@assethub/cli 0.1.7 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -65
- package/dist/index.js +1 -13
- package/package.json +15 -12
- package/dist/autopilot.d.ts +0 -13
- package/dist/autopilot.d.ts.map +0 -1
- package/dist/autopilot.js +0 -158
package/README.md
CHANGED
|
@@ -201,8 +201,8 @@ IDs/version/hash are recorded on the run. Retry an uncertain generation with
|
|
|
201
201
|
`userNote`. `update <board-id> --input-json @file` creates a new immutable revision;
|
|
202
202
|
`get`, `list`, and `archive` manage existing boards. Analysis uses the existing
|
|
203
203
|
8-credit vision plan for a new attempt, resumes an active job, and reuses a ready
|
|
204
|
-
revision. The combined generation limit is **6 content and style images**:
|
|
205
|
-
|
|
204
|
+
revision. The combined generation limit is **6 content and style images**: five identity/storyboard references leave room
|
|
205
|
+
for one style representative.
|
|
206
206
|
|
|
207
207
|
Image import persists upload identity before registration and recovers the same
|
|
208
208
|
asset after an uncertain response; `--upload-id` resumes a known completed upload.
|
|
@@ -250,69 +250,9 @@ For example, create `layout.json` with those IDs:
|
|
|
250
250
|
assethub canvas layout --canvas "$CANVAS_ID" --input-json @layout.json
|
|
251
251
|
```
|
|
252
252
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
infisical run --env=prod -- node --import tsx packages/assethub-cli/src/index.ts \
|
|
257
|
-
workspace prepare --internal --manifest ./workspace.json --state ./workspace-state.json
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
`workspace.json` provides `orgId`, `actorId`, `actorEmail`, `projectName`,
|
|
261
|
-
`boardName`, `userNote`, and `references` / optional `inputs` and `outputs` arrays containing
|
|
262
|
-
`path`, `name`, optional `section`, and optional `representative` (up to three
|
|
263
|
-
references). An output can set `sourcePath` to an imported input path to retain a
|
|
264
|
-
native canvas connection from storyboard to result. The internal actor must
|
|
265
|
-
already belong to the selected workspace.
|
|
266
|
-
This creates a native workflow canvas, owned image assets, and a native moodboard
|
|
267
|
-
revision. `workspace sync` appends new images from the manifest; the original
|
|
268
|
-
moodboard reference revision stays frozen. Preserve the state file for resuming.
|
|
269
|
-
`workspace analyze` uses the native analysis model, prompt and parser with the
|
|
270
|
-
existing OpenRouter environment, saving provider usage beside the state file.
|
|
271
|
-
It uses only the saved revision's frozen references, checks the original owned
|
|
272
|
-
assets again, and claims one analysis attempt before calling the provider.
|
|
273
|
-
Resumed order and image identities, storage paths and source hashes are checked
|
|
274
|
-
against owned records before reading storage or changing the canvas.
|
|
275
|
-
`workspace verify` checks persisted native schema, ownership and uploaded hashes.
|
|
276
|
-
Optional `contextNote` (up to 24,000 characters) adds a readable native text node
|
|
277
|
-
beside the image groups. The full project context is saved separately below.
|
|
278
|
-
`workspace self-check --internal` checks native schema, context roundtrips and
|
|
279
|
-
conflict rejection without credentials.
|
|
280
|
-
|
|
281
|
-
Save and recover a project's instructions without the local manifest/state:
|
|
282
|
-
|
|
283
|
-
```sh
|
|
284
|
-
assethub workspace context put --internal --org <workspace-uuid> --actor <internal-user-uuid> \
|
|
285
|
-
--canvas <canvas-id> --file ./project-context.json
|
|
286
|
-
assethub workspace context get --internal --org <workspace-uuid> --actor <internal-user-uuid> \
|
|
287
|
-
--canvas <canvas-id> --out ./recovered-context.json
|
|
288
|
-
# To replace changed content, use the version returned by the latest get:
|
|
289
|
-
assethub workspace context put --internal --org <workspace-uuid> --actor <internal-user-uuid> \
|
|
290
|
-
--canvas <canvas-id> --file ./edited-context.json --if-version <current-version>
|
|
291
|
-
```
|
|
292
|
-
|
|
293
|
-
The document is a JSON object of at most 256 KiB, with `schemaVersion: 1`, a
|
|
294
|
-
nonempty `title`, `instructions: {must: string[], avoid: string[]}` (at least one
|
|
295
|
-
required instruction), and a nonempty `sources` object array. Other JSON fields
|
|
296
|
-
are retained. Source entries can use `remoteAssetId: <uuid> | null`; every
|
|
297
|
-
explicit `assetId` / `*AssetId` / `*AssetIds` reference must belong to the workspace.
|
|
298
|
-
An unuploaded source may retain a null ID and its provenance.
|
|
299
|
-
|
|
300
|
-
The native order's `metadata.projectContext` holds the document, version, content
|
|
301
|
-
SHA-256, timestamp and actor. Other metadata is preserved. A changed existing
|
|
302
|
-
document requires `--if-version`; identical-content retries do not create a new
|
|
303
|
-
version. The write also compares the order's `updated_at`, which the native
|
|
304
|
-
`model_workflow_update_updated_at` trigger advances on every update, refusing
|
|
305
|
-
concurrent changes to any order metadata. Documents stay in the request body,
|
|
306
|
-
so large contexts do not exceed URI limits. If multiple active orders belong to
|
|
307
|
-
a canvas, supply `--order`.
|
|
308
|
-
The actor must be an internal user with a writable workspace membership; both
|
|
309
|
-
project and order ownership are checked. `get --out` writes the original document
|
|
310
|
-
and stdout includes its stored envelope. It does not require local CLI state.
|
|
311
|
-
|
|
312
|
-
These commands require the existing internal Supabase service environment and
|
|
313
|
-
reuse native workspace, moodboard and context contracts separately from the
|
|
314
|
-
public API commands. This internal command is unavailable in a standalone
|
|
315
|
-
published CLI installation.
|
|
253
|
+
Legacy `workspace --internal` commands and the experimental autopilot demo are
|
|
254
|
+
not available in the standalone distribution. Use the authenticated public
|
|
255
|
+
`canvas`, `moodboard`, and `canvas context` commands described above.
|
|
316
256
|
|
|
317
257
|
```sh
|
|
318
258
|
export ASSETHUB_API_KEY=ah_live_xxx
|
package/dist/index.js
CHANGED
|
@@ -3010,20 +3010,8 @@ const run = async () => {
|
|
|
3010
3010
|
await commandAuth(subcommand, parsed.flags);
|
|
3011
3011
|
return;
|
|
3012
3012
|
}
|
|
3013
|
-
// The experimental demo uses an unpublished workspace development dependency.
|
|
3014
|
-
// Resolve it only for this command so standalone project commands can load.
|
|
3015
3013
|
if (command === 'autopilot') {
|
|
3016
|
-
|
|
3017
|
-
if (error instanceof Error &&
|
|
3018
|
-
'code' in error &&
|
|
3019
|
-
error.code === 'ERR_MODULE_NOT_FOUND' &&
|
|
3020
|
-
error.message.includes('@assethub/autopilot-core')) {
|
|
3021
|
-
throw new Error('The experimental autopilot demo requires the AssetHub monorepo with @assethub/autopilot-core installed. Standalone project workflow commands are available without it.');
|
|
3022
|
-
}
|
|
3023
|
-
throw error;
|
|
3024
|
-
});
|
|
3025
|
-
await commandAutopilot(parsed.positionals, parsed.flags);
|
|
3026
|
-
return;
|
|
3014
|
+
throw new Error('The experimental autopilot demo requires the AssetHub monorepo with @assethub/autopilot-core installed. Standalone project workflow commands are available without it.');
|
|
3027
3015
|
}
|
|
3028
3016
|
const ctx = await createContext(parsed.flags, argv.slice(2));
|
|
3029
3017
|
switch (command) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@assethub/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"description": "Command line interface for AssetHub.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -20,22 +20,25 @@
|
|
|
20
20
|
"README.md",
|
|
21
21
|
"LICENSE"
|
|
22
22
|
],
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "tsc -p tsconfig.json && chmod +x dist/index.js",
|
|
25
|
+
"test": "vitest run",
|
|
26
|
+
"typecheck": "tsc -p tsconfig.typecheck.json --noEmit"
|
|
27
|
+
},
|
|
23
28
|
"license": "MIT",
|
|
24
29
|
"publishConfig": {
|
|
25
30
|
"access": "public"
|
|
26
31
|
},
|
|
27
32
|
"dependencies": {
|
|
28
|
-
"@assethub/api-client": "^0.1.
|
|
33
|
+
"@assethub/api-client": "^0.1.3"
|
|
29
34
|
},
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"@assethub/autopilot-core": "0.0.1"
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "git+https://github.com/AssetHub-inc/assethub-cli.git",
|
|
38
|
+
"directory": "packages/assethub-cli"
|
|
35
39
|
},
|
|
36
|
-
"
|
|
37
|
-
|
|
38
|
-
"
|
|
39
|
-
"typecheck": "tsc -p tsconfig.typecheck.json --noEmit"
|
|
40
|
+
"homepage": "https://github.com/AssetHub-inc/assethub-cli#readme",
|
|
41
|
+
"bugs": {
|
|
42
|
+
"url": "https://github.com/AssetHub-inc/assethub-cli/issues"
|
|
40
43
|
}
|
|
41
|
-
}
|
|
44
|
+
}
|
package/dist/autopilot.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `assethub autopilot` — drives the auto-split autopilot from the terminal,
|
|
3
|
-
* rendering the shared event stream coding-agent style.
|
|
4
|
-
*
|
|
5
|
-
* The CLI is the primary frontend for the autopilot brain; the in-app chat
|
|
6
|
-
* window is the same engine + event stream rendered inside the app. This
|
|
7
|
-
* command currently runs against the deterministic MockBackend (`--demo`); the
|
|
8
|
-
* real backend (AssetHub API / trigger.dev) is a drop-in AutopilotBackend.
|
|
9
|
-
*/
|
|
10
|
-
type Flags = Record<string, string | boolean | string[]>;
|
|
11
|
-
export declare const commandAutopilot: (positionals: string[], flags: Flags) => Promise<void>;
|
|
12
|
-
export {};
|
|
13
|
-
//# sourceMappingURL=autopilot.d.ts.map
|
package/dist/autopilot.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"autopilot.d.ts","sourceRoot":"","sources":["../src/autopilot.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAiBH,KAAK,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,EAAE,CAAC,CAAA;AAmHxD,eAAO,MAAM,gBAAgB,GAC3B,aAAa,MAAM,EAAE,EACrB,OAAO,KAAK,KACX,OAAO,CAAC,IAAI,CAgDd,CAAA"}
|
package/dist/autopilot.js
DELETED
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `assethub autopilot` — drives the auto-split autopilot from the terminal,
|
|
3
|
-
* rendering the shared event stream coding-agent style.
|
|
4
|
-
*
|
|
5
|
-
* The CLI is the primary frontend for the autopilot brain; the in-app chat
|
|
6
|
-
* window is the same engine + event stream rendered inside the app. This
|
|
7
|
-
* command currently runs against the deterministic MockBackend (`--demo`); the
|
|
8
|
-
* real backend (AssetHub API / trigger.dev) is a drop-in AutopilotBackend.
|
|
9
|
-
*/
|
|
10
|
-
import { createInterface } from 'node:readline/promises';
|
|
11
|
-
import { stdin, stdout } from 'node:process';
|
|
12
|
-
import { AutopilotEngine, MockBackend, demoConfig, formatEventLine, } from '@assethub/autopilot-core';
|
|
13
|
-
// --- tiny ANSI helpers (no dependency) ---
|
|
14
|
-
const useColor = stdout.isTTY === true;
|
|
15
|
-
const paint = (code, s) => (useColor ? `[${code}m${s}[0m` : s);
|
|
16
|
-
const dim = (s) => paint('2', s);
|
|
17
|
-
const bold = (s) => paint('1', s);
|
|
18
|
-
const green = (s) => paint('32', s);
|
|
19
|
-
const yellow = (s) => paint('33', s);
|
|
20
|
-
const red = (s) => paint('31', s);
|
|
21
|
-
const cyan = (s) => paint('36', s);
|
|
22
|
-
const flagStr = (flags, name) => {
|
|
23
|
-
const v = flags[name];
|
|
24
|
-
return typeof v === 'string' ? v : Array.isArray(v) ? v[0] : undefined;
|
|
25
|
-
};
|
|
26
|
-
const flagBool = (flags, name) => flags[name] != null;
|
|
27
|
-
const flagNum = (flags, name) => {
|
|
28
|
-
const s = flagStr(flags, name);
|
|
29
|
-
if (s == null)
|
|
30
|
-
return undefined;
|
|
31
|
-
const n = Number(s);
|
|
32
|
-
return Number.isFinite(n) ? n : undefined;
|
|
33
|
-
};
|
|
34
|
-
/** Colorize the shared narration line for the terminal. */
|
|
35
|
-
const colorize = (event, line) => {
|
|
36
|
-
switch (event.type) {
|
|
37
|
-
case 'run_started':
|
|
38
|
-
return bold(cyan(line));
|
|
39
|
-
case 'phase_changed':
|
|
40
|
-
return bold(line);
|
|
41
|
-
case 'log':
|
|
42
|
-
if (event.level === 'success')
|
|
43
|
-
return green(line);
|
|
44
|
-
if (event.level === 'warn')
|
|
45
|
-
return yellow(line);
|
|
46
|
-
if (event.level === 'error')
|
|
47
|
-
return red(line);
|
|
48
|
-
return dim(line);
|
|
49
|
-
case 'human_review_requested':
|
|
50
|
-
return yellow(line);
|
|
51
|
-
case 'human_review_resolved':
|
|
52
|
-
return cyan(line);
|
|
53
|
-
case 'credit_estimate':
|
|
54
|
-
return dim(line);
|
|
55
|
-
case 'run_finished':
|
|
56
|
-
return event.status === 'complete' ? bold(green(line)) : bold(red(line));
|
|
57
|
-
default:
|
|
58
|
-
return line;
|
|
59
|
-
}
|
|
60
|
-
};
|
|
61
|
-
const PLAN_GLYPH = {
|
|
62
|
-
pending: '○',
|
|
63
|
-
active: '◐',
|
|
64
|
-
done: '●',
|
|
65
|
-
skipped: '⊘',
|
|
66
|
-
failed: '✗',
|
|
67
|
-
};
|
|
68
|
-
const renderPlan = (plan, indent = 0) => {
|
|
69
|
-
const pad = ' '.repeat(indent);
|
|
70
|
-
return plan
|
|
71
|
-
.map((step) => {
|
|
72
|
-
const head = `${pad}${PLAN_GLYPH[step.status]} ${step.label}${step.detail ? dim(` — ${step.detail}`) : ''}`;
|
|
73
|
-
const kids = step.children?.length ? '\n' + renderPlan(step.children, indent + 1) : '';
|
|
74
|
-
return head + kids;
|
|
75
|
-
})
|
|
76
|
-
.join('\n');
|
|
77
|
-
};
|
|
78
|
-
/** Interactive resolver reading a choice from the TTY; falls back to a policy when not a TTY. */
|
|
79
|
-
const makeResolver = (opts) => {
|
|
80
|
-
return async (request) => {
|
|
81
|
-
const autoChoice = autoPolicy(request);
|
|
82
|
-
if (opts.yolo || !opts.interactive) {
|
|
83
|
-
if (!opts.quiet)
|
|
84
|
-
stdout.write(dim(` → auto: ${autoChoice}\n`));
|
|
85
|
-
return { requestId: request.requestId, choice: autoChoice };
|
|
86
|
-
}
|
|
87
|
-
const rl = createInterface({ input: stdin, output: stdout });
|
|
88
|
-
try {
|
|
89
|
-
const answer = (await rl.question(cyan(' choose [1..] (enter = auto): '))).trim();
|
|
90
|
-
const idx = Number(answer);
|
|
91
|
-
if (Number.isInteger(idx) && idx >= 1 && idx <= request.options.length) {
|
|
92
|
-
return { requestId: request.requestId, choice: request.options[idx - 1].id };
|
|
93
|
-
}
|
|
94
|
-
return { requestId: request.requestId, choice: autoChoice };
|
|
95
|
-
}
|
|
96
|
-
finally {
|
|
97
|
-
rl.close();
|
|
98
|
-
}
|
|
99
|
-
};
|
|
100
|
-
};
|
|
101
|
-
/** Default non-interactive policy: accept fail parts, pick the first (top-scored) tie candidate. */
|
|
102
|
-
const autoPolicy = (request) => {
|
|
103
|
-
if (request.kind === 'fail_part')
|
|
104
|
-
return 'accept';
|
|
105
|
-
return request.options[0].id;
|
|
106
|
-
};
|
|
107
|
-
const buildConfig = (flags) => {
|
|
108
|
-
const base = demoConfig();
|
|
109
|
-
return {
|
|
110
|
-
...base,
|
|
111
|
-
maxRegenAttempts: flagNum(flags, 'max-regen') ?? base.maxRegenAttempts,
|
|
112
|
-
regenStallRounds: flagNum(flags, 'stall-rounds') ?? base.regenStallRounds,
|
|
113
|
-
tieEpsilon: flagNum(flags, 'tie-epsilon') ?? base.tieEpsilon,
|
|
114
|
-
multiviewGoalId: flagStr(flags, 'multiview') ?? base.multiviewGoalId,
|
|
115
|
-
abMode: flagStr(flags, 'ab-mode') === 'cross' ? 'cross' : base.abMode,
|
|
116
|
-
creditBudget: flagNum(flags, 'credit-budget') ?? base.creditBudget,
|
|
117
|
-
};
|
|
118
|
-
};
|
|
119
|
-
export const commandAutopilot = async (positionals, flags) => {
|
|
120
|
-
const sourceImage = positionals[1] ?? flagStr(flags, 'file') ?? flagStr(flags, 'source-url') ?? 'mock://demo-source.png';
|
|
121
|
-
const isDemo = flagBool(flags, 'demo');
|
|
122
|
-
const asJson = flagBool(flags, 'json');
|
|
123
|
-
if (!isDemo) {
|
|
124
|
-
stdout.write(yellow('autopilot: only --demo (deterministic MockBackend) is wired up in this build.\n' +
|
|
125
|
-
'The real backend (AssetHub API / trigger.dev) is a drop-in AutopilotBackend — pass --demo to run the mock end-to-end.\n'));
|
|
126
|
-
return;
|
|
127
|
-
}
|
|
128
|
-
const config = buildConfig(flags);
|
|
129
|
-
const events = [];
|
|
130
|
-
let lastPlan = [];
|
|
131
|
-
const emit = (event) => {
|
|
132
|
-
events.push(event);
|
|
133
|
-
if (asJson)
|
|
134
|
-
return; // collect only; print JSON at the end
|
|
135
|
-
if (event.type === 'plan_updated') {
|
|
136
|
-
lastPlan = event.plan;
|
|
137
|
-
return;
|
|
138
|
-
}
|
|
139
|
-
const line = formatEventLine(event);
|
|
140
|
-
if (line != null)
|
|
141
|
-
stdout.write(colorize(event, line) + '\n');
|
|
142
|
-
};
|
|
143
|
-
const engine = new AutopilotEngine(new MockBackend(), config, {
|
|
144
|
-
emit,
|
|
145
|
-
resolveHumanReview: makeResolver({
|
|
146
|
-
yolo: flagBool(flags, 'yolo'),
|
|
147
|
-
interactive: stdin.isTTY === true && !asJson,
|
|
148
|
-
quiet: asJson,
|
|
149
|
-
}),
|
|
150
|
-
runId: 'demo-run',
|
|
151
|
-
});
|
|
152
|
-
const summary = await engine.run(sourceImage);
|
|
153
|
-
if (asJson) {
|
|
154
|
-
stdout.write(`${JSON.stringify({ summary, events }, null, 2)}\n`);
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
157
|
-
stdout.write('\n' + bold('Plan') + '\n' + renderPlan(lastPlan) + '\n');
|
|
158
|
-
};
|