@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 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**: Marza's
205
- 5 required identity/storyboard references leave room for 1 style representative.
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
- Internal workspace preparation (monorepo checkout only):
254
-
255
- ```sh
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
- const { commandAutopilot } = await import('./autopilot.js').catch((error) => {
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.7",
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.2"
33
+ "@assethub/api-client": "^0.1.3"
29
34
  },
30
- "devDependencies": {
31
- "@types/node": "24.10.1",
32
- "typescript": "5.9.3",
33
- "vitest": "^4.1.5",
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
- "scripts": {
37
- "build": "tsc -p tsconfig.json && chmod +x dist/index.js",
38
- "test": "vitest run",
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
+ }
@@ -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
@@ -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}` : 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
- };