Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
100 commits
Select commit Hold shift + click to select a range
dc1a416
Add Stack Bench benchmarking system
bradleyshep Aug 31, 2026
4de24d4
Harden Stack Bench run boundaries
bradleyshep Aug 31, 2026
916c24a
Rebind qualified Stack Bench runtime
bradleyshep Aug 31, 2026
bbaa862
Bind qualification to clean source
bradleyshep Aug 31, 2026
71044db
Clean Stack Bench structure and graph docs
bradleyshep Aug 31, 2026
9236066
Clean up Stack Bench runtime paths
bradleyshep Aug 31, 2026
e1fa367
Count unchanged dependency repairs as strikes
bradleyshep Aug 31, 2026
a250472
Require the appliance for paid Stack Bench runs
bradleyshep Aug 31, 2026
e03c265
Move Stack Bench policy to its owning modules
bradleyshep Aug 31, 2026
c0dd216
Allow qualified adapter metadata updates
bradleyshep Aug 31, 2026
6d25778
Separate app and backend lifecycle controls
bradleyshep Aug 31, 2026
c81f3b6
Type Stack Bench runtime control input
bradleyshep Aug 31, 2026
8eb656a
Handle dependency symlinks in source snapshots
bradleyshep Aug 31, 2026
0517ca5
Preserve dependency level evidence across regressions
bradleyshep Aug 31, 2026
097ddd6
Refresh Stack Bench qualification scope
bradleyshep Aug 31, 2026
8203ecf
Simplify Stack Bench lifecycle control
bradleyshep Aug 31, 2026
5a7a356
Clean up Stack Bench comments
bradleyshep Aug 31, 2026
fcd5623
Simplify coding session retry control
bradleyshep Aug 31, 2026
01a46b5
Make agent contracts explicit
bradleyshep Aug 31, 2026
9256cfb
Simplify Stack Bench argument parsing
bradleyshep Aug 31, 2026
94da26a
Harden agent result and cost recovery
bradleyshep Aug 31, 2026
3e83f68
harden stack bench track boundaries
bradleyshep Sep 1, 2026
24e2e2f
cleanup
bradleyshep Sep 1, 2026
c9287ae
updates
bradleyshep Sep 1, 2026
a0b42e2
docs(stack-bench): update current behavior
bradleyshep Sep 1, 2026
a2b32f7
updates
bradleyshep Sep 1, 2026
0520d4c
harden stack bench input boundaries
bradleyshep Sep 1, 2026
2b6e8c4
updates
bradleyshep Sep 1, 2026
cc8e919
updates
bradleyshep Sep 1, 2026
21cf0c6
zod
bradleyshep Sep 1, 2026
b41abc9
Update recipe-release.ts
bradleyshep Sep 1, 2026
a8c470b
clarify stack bench system control model
bradleyshep Sep 1, 2026
b6ec6da
share campaign inspection across operator views
bradleyshep Sep 1, 2026
d106f06
replace stack capability dispatch with typed methods
bradleyshep Sep 1, 2026
206f905
prevent benchmark details in agent prompts
bradleyshep Sep 1, 2026
a4c2555
trust completed grading evidence
bradleyshep Sep 1, 2026
36c66f4
fail closed on inconclusive grading
bradleyshep Sep 1, 2026
066a5a7
trust completed dependency grade evidence
bradleyshep Sep 1, 2026
7f5b56e
Harden campaign evidence trust
bradleyshep Sep 1, 2026
ceedb90
Prepare fresh depth-3 qualification
bradleyshep Sep 1, 2026
e9435ef
Fix qualification startup contracts
bradleyshep Sep 1, 2026
4f77d2a
Parallelize null qualification
bradleyshep Sep 1, 2026
c659950
fix(stack-bench): let null control reach assertions
bradleyshep Sep 1, 2026
8e16de7
fix(stack-bench): share appliance workspace ownership
bradleyshep Sep 1, 2026
20e79a6
fix(stack-bench): honor shared workspace access
bradleyshep Sep 1, 2026
727ecdc
fix(stack-bench): hand off generated workspaces
bradleyshep Sep 1, 2026
3cbdb0e
fix(stack-bench): make references restartable
bradleyshep Sep 1, 2026
3ffafaa
updates
bradleyshep Sep 1, 2026
f9d3e5e
updates
bradleyshep Sep 1, 2026
dd992dc
fixes
bradleyshep Sep 1, 2026
7bebbe5
fix(stack-bench): bind clean reference sources
bradleyshep Sep 1, 2026
c14f9a9
docs(stack-bench): organize documentation
bradleyshep Sep 1, 2026
f63cdc4
fix(stack-bench): preserve reference workspace ownership
bradleyshep Sep 1, 2026
b50e0d0
fix(stack-bench): preserve dependencies during materialization
bradleyshep Sep 1, 2026
0733529
fix(stack-bench): hand off materialized source before launch
bradleyshep Sep 1, 2026
7edf626
fix(stack-bench): distinguish transition and refusal checks
bradleyshep Sep 1, 2026
5bddc06
feat(stack-bench): target reference checks
bradleyshep Sep 1, 2026
f314368
fix(stack-bench): correct low-stock transition order
bradleyshep Sep 1, 2026
b609e2d
fix(stack-bench): separate runs from grading qualification
bradleyshep Sep 1, 2026
d3f2fc2
fix(stack-bench): separate campaign identity from grading
bradleyshep Sep 1, 2026
22d46c7
docs(stack-bench): limit verification to changed risks
bradleyshep Sep 1, 2026
209f570
fix(stack-bench): hand off transcripts to controller
bradleyshep Sep 1, 2026
08e2507
fix(stack-bench): preserve repair handoff
bradleyshep Sep 1, 2026
4411c98
fix stack bench spacetime grading proof
bradleyshep Sep 1, 2026
cf91533
fix stack bench grading isolation
bradleyshep Sep 1, 2026
636b91e
cover dependency prompts in static checks
bradleyshep Sep 1, 2026
bc5cc4e
label dependency repairs by feature
bradleyshep Sep 1, 2026
bfdc58a
fix stack bench grading setup
bradleyshep Sep 1, 2026
e146dcf
fix stack bench spacetime ownership
bradleyshep Sep 1, 2026
e033af6
drizzle, event source parser
bradleyshep Sep 1, 2026
d5603bc
Fix progression scenarios and repair diagnostics
bradleyshep Sep 1, 2026
102ed3b
test(stack-bench): separate test tiers
bradleyshep Sep 2, 2026
279b161
updates
bradleyshep Sep 2, 2026
ef7a219
fix(stack-bench): restore support reference grading
bradleyshep Sep 2, 2026
3da62bf
fix(stack-bench): label dependency depth in dashboard
bradleyshep Sep 2, 2026
758769b
fix(stack-bench): keep active dashboard attempts valid
bradleyshep Sep 2, 2026
7f40b56
Fix dashboard polling performance
bradleyshep Sep 2, 2026
7f6f1a0
Add exportable stack dependency graphs
bradleyshep Sep 2, 2026
64cb0df
Fix Stack Bench prompt fairness and result integrity
bradleyshep Sep 2, 2026
1dcb829
Fix Stack Bench dependency grading contracts
bradleyshep Sep 2, 2026
c4a3ac3
Refresh Stack Bench progression calibration identity
bradleyshep Sep 2, 2026
0734503
Align Stack Bench prompt and calibration identities
bradleyshep Sep 2, 2026
d04430d
Fix dependency repair and failure preservation
bradleyshep Sep 2, 2026
696dc1c
Harden dependency campaigns and add progression controls
bradleyshep Sep 2, 2026
9701c7b
Handle browser dialogs during grading
bradleyshep Sep 2, 2026
173481a
Measure Stack Bench container memory
bradleyshep Sep 2, 2026
7a22f88
Harden Stack Bench grading and campaign setup
bradleyshep Sep 2, 2026
c3f9b36
Serve the dashboard as per-view routes with change events
bradleyshep Sep 2, 2026
aeb5435
Rebuild the Stack Bench dashboard client as pages
bradleyshep Sep 2, 2026
0606dd7
Fix named replay contract failures
bradleyshep Sep 2, 2026
371cb27
Add the dashboard plans page, run controls, and appliance smoke fixes
bradleyshep Sep 2, 2026
a5782ef
Fix application interface grading
bradleyshep Sep 2, 2026
f2b44b0
Fix dependency grading and repair feedback
bradleyshep Sep 2, 2026
187156a
Fix neutral benchmark prompt ownership
bradleyshep Sep 3, 2026
1284c2f
docs(stack-bench): explain prompt composition
bradleyshep Sep 3, 2026
fa08536
fix(stack-bench): allocate free campaign run slots
bradleyshep Sep 3, 2026
09604c4
Fix dependency repair progression finalization
bradleyshep Sep 3, 2026
3555968
Prevent dependency repairs from trading away passes
bradleyshep Sep 3, 2026
4127079
Harden dependency repair rollback recovery
bradleyshep Sep 3, 2026
2ed75a6
Remove retired dependency definitions
bradleyshep Sep 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@
**/ModuleBindings/** linguist-generated=true eol=lf
/docs/llms/** linguist-generated=true
/docs/llms/*-details.json linguist-generated=false
/tools/stack-bench/** text eol=lf
/tools/stack-bench/**/*.woff2 -text -diff
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Generated bindings convert snake_case names to camelCase, including row fields:
## React: main.tsx

```typescript
import React, { useEffect, useMemo } from 'react';
import React, { useMemo } from 'react';
import ReactDOM from 'react-dom/client';
import { SpacetimeDBProvider } from 'spacetimedb/react';
import { DbConnection } from './module_bindings';
Expand All @@ -30,6 +30,7 @@ function Root() {
DbConnection.builder()
.withUri(SPACETIMEDB_URI)
.withDatabaseName(MODULE_NAME)
// Reuse the token issued on the previous connection.
.withToken(localStorage.getItem('auth_token') || undefined),
[]
);
Expand All @@ -46,14 +47,15 @@ ReactDOM.createRoot(document.getElementById('root')!).render(<Root />);
## React: App.tsx

```typescript
import { useEffect } from 'react';
import { useTable, useSpacetimeDB } from 'spacetimedb/react';
import { DbConnection, tables } from './module_bindings';

function App() {
const { isActive, identity: myIdentity, token, getConnection } = useSpacetimeDB();
const conn = getConnection() as DbConnection | null;

// Save auth token
// Persist the issued token for the next page load.
useEffect(() => { if (token) localStorage.setItem('auth_token', token); }, [token]);

// Subscribe when connected. Prefer typed query builders over raw SQL
Expand Down
23 changes: 21 additions & 2 deletions codex-plugin/plugins/spacetimedb/skills/typescript-server/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ Every column is a `t` builder value:

Modifiers: `.primaryKey()`, `.autoInc()`, `.unique()`, `.index('btree')`, `.default(value)`.

`.primaryKey()` and `.unique()` apply to one column. For uniqueness across
multiple columns, use a surrogate key, the multi-column index below, and a
reducer that rejects an existing index match before inserting.

Use `.default(value)` only for a newly appended migration-safe field. Do not put defaults on primary-key, unique, or auto-increment columns.

Optional columns: `nickname: t.option(t.string())`
Expand Down Expand Up @@ -130,7 +134,9 @@ export { default } from './schema'; // re-export the schema for the module ent

## Reducers

Reducers are created with `spacetimedb.reducer(...)`; the export name becomes the reducer name:
Reducers are created with `spacetimedb.reducer(...)`. An exported `signUp`
becomes `signUp` in generated clients and `sign_up` in `spacetime call` and
`describe`:

```typescript
export const createEntity = spacetimedb.reducer(
Expand Down Expand Up @@ -278,17 +284,30 @@ const Shape = t.enum('Shape', {
A client subscribing to a view receives only the rows it returns. Use a per-user view
(keyed on `ctx.sender`) for per-viewer access control: deleting a row it depends on
(e.g. a membership row) automatically drops the rows it was exposing from that client.
Use index accessors in views. Do not scan a whole table with `.iter()` when an
indexed lookup can select the required rows.

`t.row(...)` and `t.object(...)` return schema builders, not TypeScript runtime row types. Let a view callback infer its result, or annotate a separately declared structural type such as `Array<{ sku: bigint; label: string }>`. A named output type must not reuse the generated PascalCase name of its view accessor (for example, reserve `DiscountedProduct` for a `discounted_product` view).

A view context is `ViewCtx<S>` (and `AnonymousViewCtx<S>`), both exported from
`spacetimedb/server`. It carries `sender`, a read-only `db`, and `from`; it is
not a `ReducerCtx`, so a helper shared between a reducer and a view must accept
either:

```typescript
import type { ReducerCtx, ViewCtx, InferSchema } from 'spacetimedb/server';
type S = InferSchema<typeof spacetimedb>;
function stockOf(ctx: ReducerCtx<S> | ViewCtx<S>, itemId: bigint) { ... }
```

Both `spacetimedb.view(...)` and `spacetimedb.anonymousView(...)` take three arguments: view options, the declared return schema, and the callback.

```typescript
// Anonymous view (same for all clients):
export const activeUsers = spacetimedb.anonymousView(
{ name: 'active_users', public: true },
t.array(entity.rowType),
(ctx) => [...ctx.db.entity.iter()].filter(e => e.active)
(ctx) => [...ctx.db.entity.active.filter(true)] // active: t.bool().index('btree')
);

// Per-user view (varies by ctx.sender):
Expand Down
26 changes: 14 additions & 12 deletions crates/bindings-typescript/src/lib/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -248,19 +248,21 @@ export type NamespacedQueryBuilder<SchemaDef extends UntypedSchemaDef> =
* A runtime reference to a table. This materializes the RowExpr for us.
* TODO: Maybe add the full SchemaDef to the type signature depending on how joins will work.
*/
export type TableRef<TableDef extends TypedTableDef> = Readonly<{
type: 'table';
sourceName: TableDef['sourceName'];
accessorName: string;
cols: RowExpr<TableDef>;
indexedCols: IndexedRowExpr<TableDef>;
tableDef: TableDef;
// Keep this named so TypeScript diagnostics show `TableRef` instead of its
// expanded structure.
export interface TableRef<TableDef extends TypedTableDef> {
readonly type: 'table';
readonly sourceName: TableDef['sourceName'];
readonly accessorName: string;
readonly cols: RowExpr<TableDef>;
readonly indexedCols: IndexedRowExpr<TableDef>;
readonly tableDef: TableDef;
// Delegated UntypedTableDef properties for compatibility.
columns: TableDef['columns'];
indexes: TableDef['indexes'];
rowType: TableDef['rowType'];
constraints: any;
}>;
readonly columns: TableDef['columns'];
readonly indexes: TableDef['indexes'];
readonly rowType: TableDef['rowType'];
readonly constraints: any;
}

class TableRefImpl<TableDef extends TypedTableDef>
implements TableRef<TableDef>, From<TableDef>
Expand Down
18 changes: 11 additions & 7 deletions crates/bindings-typescript/src/sdk/connection_manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,9 +145,7 @@ class ConnectionManagerImpl {
clearTimeout(managed.reconnectTimer);
managed.reconnectTimer = null;
managed.reconnectAttempt = 0;
if (managed.builder) {
this.#buildManagedConnection(managed, managed.builder);
}
this.#reconnectManagedConnection(managed);
continue;
}

Expand Down Expand Up @@ -179,9 +177,7 @@ class ConnectionManagerImpl {
connection.disconnect();
this.#updateState(managed, { isActive: false });
managed.reconnectAttempt = 0;
if (managed.builder) {
this.#buildManagedConnection(managed, managed.builder);
}
this.#reconnectManagedConnection(managed);
}

/** Generates a unique key for a connection based on URI and module name. */
Expand Down Expand Up @@ -294,6 +290,14 @@ class ConnectionManagerImpl {
}
}

/** Reconnect with the issued token. Explicit rebuilds use the caller's token. */
#reconnectManagedConnection(managed: ManagedConnection): void {
if (!managed.builder) return;
const token = managed.state.token;
if (token) managed.builder.withToken(token);
this.#buildManagedConnection(managed, managed.builder);
}

#buildManagedConnection<T extends DbConnectionImpl<any>>(
managed: ManagedConnection,
builder: DbConnectionBuilder<T>
Expand Down Expand Up @@ -349,7 +353,7 @@ class ConnectionManagerImpl {
return;
}

this.#buildManagedConnection(managed, managed.builder);
this.#reconnectManagedConnection(managed);
}, delay);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ type ErrorContextInterface = { isActive: boolean };
class MockConnection {
isActive = false;
identity = undefined;
token = undefined;
token: string | undefined;
connectionId = ConnectionId.random();
isDisconnectRequested = false;
disconnected = false;
Expand All @@ -28,6 +28,10 @@ class MockConnection {
(ctx: ErrorContextInterface, error: Error) => void
>();

constructor(private readonly issuedToken?: string) {
this.token = undefined;
}

get isSocketClosed(): boolean {
return this.socketClosed;
}
Expand Down Expand Up @@ -63,6 +67,7 @@ class MockConnection {

simulateConnect(): void {
this.isActive = true;
this.token = this.issuedToken;
for (const cb of this.#onConnect) cb(this);
}
simulateDisconnect(error?: Error): void {
Expand All @@ -74,7 +79,9 @@ class MockConnection {

class MockBuilder {
buildCount = 0;
presentedTokens: Array<string | undefined> = [];
connections: MockConnection[] = [];
#token: string | undefined;

#onConnect = new Set<(conn: MockConnection) => void>();
#onDisconnect = new Set<
Expand All @@ -84,9 +91,17 @@ class MockBuilder {
(ctx: ErrorContextInterface, error: Error) => void
>();

constructor(private readonly issuedToken?: string) {}

withToken(token?: string): MockBuilder {
this.#token = token;
return this;
}

build(): MockConnection {
const connection = new MockConnection();
const connection = new MockConnection(this.issuedToken);
this.buildCount += 1;
this.presentedTokens.push(this.#token);
this.connections.push(connection);
for (const cb of this.#onConnect) connection.register('connect', cb);
for (const cb of this.#onDisconnect) connection.register('disconnect', cb);
Expand Down Expand Up @@ -201,6 +216,32 @@ describe('ConnectionManager liveness recovery', () => {
ConnectionManager.release(key);
});

test('reuses the issued token when reviving a dead socket', () => {
const key = nextKey();
const builder = new MockBuilder('issued-token');
const first = retain(key, builder);
expect(builder.presentedTokens).toEqual([undefined]);

first.simulateConnect();
first.socketClosed = true;
fire('win:online');

expect(builder.presentedTokens).toEqual([undefined, 'issued-token']);
ConnectionManager.release(key);
});

test('an explicit rebuild uses the caller token', () => {
const key = nextKey();
const firstBuilder = new MockBuilder('issued-token');
retain(key, firstBuilder).simulateConnect();

const replacement = new MockBuilder().withToken('caller-token');
ConnectionManager.rebuild(key, replacement as any);

expect(replacement.presentedTokens).toEqual(['caller-token']);
ConnectionManager.release(key);
});

test('does not rebuild a healthy connection on resume', () => {
const key = nextKey();
const builder = new MockBuilder();
Expand Down
79 changes: 79 additions & 0 deletions crates/bindings-typescript/tests/table_ref_error_message.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
import { tmpdir } from 'node:os';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import * as ts from 'typescript';
import { describe, expect, it } from 'vitest';

const bindingsRoot = path.resolve(
path.dirname(fileURLToPath(import.meta.url)),
'..'
);

function runTypecheck(source: string) {
const tmpDir = mkdtempSync(path.join(tmpdir(), 'stdb-tableref-diag-'));
const reproPath = path.join(tmpDir, 'repro.ts');
writeFileSync(reproPath, source);

try {
const options: ts.CompilerOptions = {
target: ts.ScriptTarget.ESNext,
module: ts.ModuleKind.ESNext,
strict: true,
noEmit: true,
skipLibCheck: true,
forceConsistentCasingInFileNames: true,
allowImportingTsExtensions: true,
noImplicitAny: true,
moduleResolution: ts.ModuleResolutionKind.Bundler,
useDefineForClassFields: true,
verbatimModuleSyntax: true,
isolatedModules: true,
};

const host = ts.createCompilerHost(options);
const program = ts.createProgram(
[reproPath, path.join(bindingsRoot, 'src/server/sys.d.ts')],
options,
host
);
const diagnostics = ts.getPreEmitDiagnostics(program);
return diagnostics.map(d =>
ts.flattenDiagnosticMessageText(d.messageText, '\n')
);
} finally {
rmSync(tmpDir, { recursive: true, force: true });
}
}

describe('TableRef diagnostics', () => {
const source = `
import { t } from ${JSON.stringify(path.join(bindingsRoot, 'src/server/index.ts'))};
import { table } from ${JSON.stringify(path.join(bindingsRoot, 'src/lib/table.ts'))};
import { createTableRefFromDef } from ${JSON.stringify(path.join(bindingsRoot, 'src/lib/query.ts'))};
import type { AllUnique } from ${JSON.stringify(path.join(bindingsRoot, 'src/lib/constraints.ts'))};

const cartItem = table(
{ name: 'cart_item' },
{ id: t.u64().primaryKey().autoInc(), accountId: t.u64(), quantity: t.u32() }
);

const ref = createTableRefFromDef(cartItem as any, 'cartItem');
type Boom = AllUnique<typeof ref, ['accountId']>;
declare const b: Boom;
`;

it('names the type instead of dumping its structure', () => {
const messages = runTypecheck(source);
const constraintError = messages.find(m =>
m.includes("does not satisfy the constraint 'UntypedTableDef'")
);

expect(constraintError).toBeDefined();
// The name, not the shape.
expect(constraintError).toContain('TableRef<');
expect(constraintError).not.toContain('type: "table"');
expect(constraintError).not.toContain('accessorName');
expect(constraintError.length).toBeLessThan(250);
}, 15000);
});
1 change: 1 addition & 0 deletions crates/cli/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ fn generate_template_files() {

// Embed skill files from skills/*/SKILL.md
let skills_dir = repo_root.join("skills");
println!("cargo:rerun-if-changed={}", skills_dir.display());
let skill_names = discover_skill_names(&skills_dir);

generated_code.push_str("pub fn get_skill(name: &str) -> Option<&'static str> {\n");
Expand Down
9 changes: 5 additions & 4 deletions crates/cli/src/subcommands/dev.rs
Original file line number Diff line number Diff line change
Expand Up @@ -738,7 +738,7 @@ pub async fn exec(mut config: Config, args: &ArgMatches) -> Result<(), anyhow::E
let loaded_config_dir = loaded_config.as_ref().map(|lc| lc.config_dir.clone());

generate_build_and_publish(
&config,
&mut config,
&project_dir,
loaded_config_dir.as_deref(),
&spacetimedb_dir,
Expand Down Expand Up @@ -853,7 +853,7 @@ pub async fn exec(mut config: Config, args: &ArgMatches) -> Result<(), anyhow::E

println!("\n{}", "File change detected, rebuilding...".yellow());
match generate_build_and_publish(
&config,
&mut config,
&project_dir,
loaded_config_dir.as_deref(),
&spacetimedb_dir,
Expand Down Expand Up @@ -1000,7 +1000,7 @@ fn upsert_env_db_names_and_hosts(env_path: &Path, server_host_url: &str, databas

#[allow(clippy::too_many_arguments)]
async fn generate_build_and_publish(
config: &Config,
config: &mut Config,
project_dir: &Path,
config_dir: Option<&Path>,
spacetimedb_dir: &Path,
Expand Down Expand Up @@ -1146,7 +1146,8 @@ async fn generate_build_and_publish(
publish_entry.insert("break-clients".to_string(), json!(true));
}

publish::exec_from_entry(config.clone(), publish_entry, config_dir, clear_database, yes).await?;
// Preserve a token created during publish for logs and later rebuilds.
publish::exec_from_entry(config, publish_entry, config_dir, clear_database, yes).await?;
}

println!("{}", "Published successfully!".green().bold());
Expand Down
Loading
Loading