@everfir/az8-cli 0.2.0-preview.3 → 0.2.0-preview.5

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/CHANGELOG.md CHANGED
@@ -3,6 +3,29 @@
3
3
  All notable AZ8 CLI changes are recorded here. The CLI package has its own linear version sequence;
4
4
  it does not inherit the Web application or monorepo root version.
5
5
 
6
+ ## 0.2.0-preview.5 - 2026-07-22
7
+
8
+ ### Changed
9
+
10
+ - Canvas awareness names now preserve the authenticated user's Web-equivalent display name first
11
+ and append a CLI-owned parenthesized client suffix, defaulting to `(cli)`.
12
+ - `--client-name <suffix>` may override the client suffix for persistent and one-shot lifecycles,
13
+ but caller-provided parentheses are rejected so presence cannot obscure the name boundary.
14
+ - CLI attention awareness now publishes only the semantic cursor and omits selection bounds.
15
+ - `startGeneration` now carries valid Workflow execution-time estimates into the View Node's
16
+ generation history as Web-compatible median and maximum completion timestamps.
17
+
18
+ ## 0.2.0-preview.4 - 2026-07-22
19
+
20
+ ### Changed
21
+
22
+ - Persistent NDJSON stdio is now the default interaction mode for every Canvas authoring task,
23
+ including a plan containing only one write.
24
+ - One-shot is limited to isolated reads, standalone transfers, explicit caller choice, or hosts that
25
+ genuinely cannot retain a child process; fewer tool calls alone is not a valid reason to use it.
26
+ - The outer repository Skill now requires preview.4 so a newly triggered agent receives this mode
27
+ selection policy.
28
+
6
29
  ## 0.2.0-preview.3 - 2026-07-21
7
30
 
8
31
  ### Changed
package/README.md CHANGED
@@ -17,7 +17,7 @@ az8 guide
17
17
  For a supplied release artifact, install the exact immutable tarball instead:
18
18
 
19
19
  ```bash
20
- npm install --global ./everfir-az8-cli-0.2.0-preview.3.tgz
20
+ npm install --global ./everfir-az8-cli-0.2.0-preview.5.tgz
21
21
  az8 --version
22
22
  ```
23
23
 
@@ -108,6 +108,10 @@ the agent can verify identities, byte count, MIME, and SHA-256.
108
108
  One-shot commands open a real Canvas client, complete synchronization and hydration, invoke the same
109
109
  query or Operation used by the persistent client, and close after the result is authoritative:
110
110
 
111
+ Persistent stdio is the default for any Canvas authoring task, including a plan with only one write.
112
+ Use this wrapper only for an isolated read, standalone transfer, explicit one-shot request, or a host
113
+ that cannot retain a child process and write later NDJSON to stdin.
114
+
111
115
  ```bash
112
116
  az8 canvas query <project-id> canvas.summary
113
117
  az8 canvas query <project-id> canvas.detail --view-node-id <view-node-id>
@@ -120,7 +124,10 @@ az8 canvas operation <project-id> startGeneration \
120
124
  Operation input is one JSON object supplied by exactly one of `--input-stdin`, `--input-file`, or
121
125
  `--input-json`; omitted input defaults to `{}`. Input is limited to one MiB. `--timeout-ms` controls
122
126
  the same Operation acknowledgement or domain observation window as persistent stdio, and
123
- `--client-name` changes only the ephemeral awareness display name.
127
+ `--client-name` changes only the parenthesized client suffix of the ephemeral awareness name. The
128
+ authenticated display name always remains first: the default is `<current user> (cli)`, while
129
+ `--client-name codex` produces `<current user> (codex)`. Parentheses are owned by the CLI and are
130
+ rejected in caller-provided suffixes.
124
131
 
125
132
  Success writes one `az8.canvas.one-shot.v1` JSON document to stdout and exits `0`. A definitive
126
133
  input, validation, permission, or business failure writes structured JSON to stderr and exits `1`.
@@ -207,8 +214,12 @@ retried. After any non-success, the agent must decide whether a new invocation i
207
214
 
208
215
  ## Persistent Canvas client
209
216
 
217
+ This is the default mode whenever a task may perform any Canvas write. Open it before the first
218
+ Canvas query, keep capability discovery and all ordered Operations in the same lifecycle, and shut
219
+ it down only after the authoring task is complete.
220
+
210
221
  ```bash
211
- az8 canvas open <project-id> --write --format ndjson
222
+ az8 canvas open <project-id> --write --format ndjson [--client-name codex]
212
223
  ```
213
224
 
214
225
  The process writes one `hello` frame, then waits for an `initialize` request on stdin:
@@ -218,9 +229,12 @@ The process writes one `hello` frame, then waits for an `initialize` request on
218
229
  ```
219
230
 
220
231
  Before readiness the client hydrates the current authenticated account profile. Canvas Operations use
221
- that immutable account id and display name for persisted creator data. The `client.name` supplied by
222
- `initialize` is awareness-only and cannot impersonate or rename the persisted author. Project owner
223
- metadata is likewise never treated as the current actor on shared Projects.
232
+ that immutable account id and display name for persisted creator data. Awareness always displays the
233
+ authenticated name first and a CLI-owned parenthesized client suffix second. The default suffix is
234
+ `cli`; startup `--client-name` overrides it, otherwise `initialize.client.name` may provide it.
235
+ Caller suffixes cannot contain parentheses. This name is awareness-only and cannot impersonate or
236
+ rename the persisted author. The CLI publishes its Attention Cursor but deliberately omits selection
237
+ bounds. Project owner metadata is likewise never treated as the current actor on shared Projects.
224
238
 
225
239
  After `ready`, requests use `query`, `configureObservations`, `operation`, `reconnect`, or `shutdown`.
226
240
  The public authoring surface includes the note lifecycle, non-World View Node hierarchy operations,
@@ -303,6 +317,9 @@ explicitly submitting the same input. An uncertain backend or collaboration outc
303
317
  are acknowledged. It first estimates the exact current Draft inputs, then materializes literal Core
304
318
  Nodes and starts with the estimate's cost and Definition version. This estimate is internal: there is
305
319
  no public estimate Operation, balance query, caller-supplied expected cost, or second confirmation.
320
+ When the estimate includes execution-time ranges, the generation history records Web-compatible
321
+ median and maximum completion timestamps from the pre-submit time so Web can render the same expected
322
+ generation duration for a CLI-started Run.
306
323
  Waiting for a terminal result is deliberately a separate operation. Generation is a non-undoable
307
324
  Canvas History barrier. The CLI does not expose Assets, arbitrary Core Node creation, or 3D World
308
325
  operations.
package/RELEASE.md CHANGED
@@ -35,7 +35,7 @@ repository-wide `pnpm verify`. Publishing is an external action and requires exp
35
35
  authorization:
36
36
 
37
37
  ```bash
38
- npm publish ./tmp/az8-cli-release/everfir-az8-cli-0.2.0-preview.3.tgz --tag preview
38
+ npm publish ./tmp/az8-cli-release/everfir-az8-cli-0.2.0-preview.5.tgz --tag preview
39
39
  npm view @everfir/az8-cli dist-tags versions --json
40
40
  ```
41
41
 
package/dist/main.js CHANGED
@@ -4527,6 +4527,27 @@ var require_src2 = __commonJS({
4527
4527
  }
4528
4528
  });
4529
4529
 
4530
+ // src/canvas-awareness.ts
4531
+ var DEFAULT_CANVAS_CLIENT_NAME = "cli";
4532
+ function normalizeCanvasClientName(value) {
4533
+ const name = (value ?? DEFAULT_CANVAS_CLIENT_NAME).trim();
4534
+ if (!name) {
4535
+ throw invalidClientName("Canvas client name must not be empty.");
4536
+ }
4537
+ if (/[()]/.test(name)) {
4538
+ throw invalidClientName(
4539
+ "Canvas client name must not contain parentheses; AZ8 adds the required (name) suffix."
4540
+ );
4541
+ }
4542
+ return name;
4543
+ }
4544
+ function formatCanvasAwarenessName(actorDisplayName, clientName) {
4545
+ return `${actorDisplayName} (${normalizeCanvasClientName(clientName)})`;
4546
+ }
4547
+ function invalidClientName(message) {
4548
+ return Object.assign(new Error(message), { code: "invalid-client-name" });
4549
+ }
4550
+
4530
4551
  // ../../node_modules/.pnpm/lib0@0.2.117/node_modules/lib0/math.js
4531
4552
  var floor = Math.floor;
4532
4553
  var abs = Math.abs;
@@ -22727,9 +22748,26 @@ function mapWorkflowRunEstimate(value, definitionId) {
22727
22748
  canAfford: value.can_afford,
22728
22749
  definitionId: value.definition_id,
22729
22750
  definitionVersion: value.definition_version,
22730
- estimatedCost: value.estimated_cost
22751
+ estimatedCost: value.estimated_cost,
22752
+ executionTimeRanges: (value.execution_time_ranges ?? []).flatMap((item) => {
22753
+ const range = item.range;
22754
+ if (!range || !isNonNegativeFinite(range.minSeconds) || !isNonNegativeFinite(range.maxSeconds) || !isNonNegativeFinite(range.medianSeconds) || !isNonNegativeFinite(range.sampleCount)) {
22755
+ return [];
22756
+ }
22757
+ return [
22758
+ {
22759
+ maxSeconds: range.maxSeconds,
22760
+ medianSeconds: range.medianSeconds,
22761
+ minSeconds: range.minSeconds,
22762
+ sampleCount: range.sampleCount
22763
+ }
22764
+ ];
22765
+ })
22731
22766
  };
22732
22767
  }
22768
+ function isNonNegativeFinite(value) {
22769
+ return typeof value === "number" && Number.isFinite(value) && value >= 0;
22770
+ }
22733
22771
  function mapWorkflowDefinition(value) {
22734
22772
  if (!value.id || !value.name || typeof value.version !== "number") {
22735
22773
  throw new Error("Workflow Runtime returned an invalid Definition.");
@@ -22903,7 +22941,8 @@ var CanvasSession = class {
22903
22941
  projectionRevision = 0;
22904
22942
  actorId = null;
22905
22943
  health;
22906
- async connect(displayName, onState) {
22944
+ async connect(clientName, onState) {
22945
+ const normalizedClientName = normalizeCanvasClientName(clientName);
22907
22946
  this.closeContext();
22908
22947
  this.transition("authenticating", onState);
22909
22948
  this.health.connectionAttempts += 1;
@@ -22927,7 +22966,10 @@ var CanvasSession = class {
22927
22966
  });
22928
22967
  this.document = document2;
22929
22968
  try {
22930
- document2.setIdentity({ accountId: actor.accountId, displayName });
22969
+ document2.setIdentity({
22970
+ accountId: actor.accountId,
22971
+ displayName: formatCanvasAwarenessName(actor.displayName, normalizedClientName)
22972
+ });
22931
22973
  this.transition("hydrating", onState);
22932
22974
  const foundationData = this.dependencies.foundationData ?? createAz8FoundationDataSystem(this.config);
22933
22975
  const projectContent = this.dependencies.projectContent ?? createAz8ProjectContentSystem(this.config);
@@ -23037,8 +23079,7 @@ var CanvasSession = class {
23037
23079
  }
23038
23080
  publishAttentionBounds(bounds) {
23039
23081
  this.requireDocument().setAttention({
23040
- cursor: { x: bounds.x + bounds.width + 24, y: bounds.y + bounds.height / 2 },
23041
- selection: bounds
23082
+ cursor: { x: bounds.x + bounds.width + 24, y: bounds.y + bounds.height / 2 }
23042
23083
  });
23043
23084
  }
23044
23085
  closeContext() {
@@ -23379,18 +23420,20 @@ function requirePositiveInteger(value, field) {
23379
23420
 
23380
23421
  // src/canvas-protocol-server.ts
23381
23422
  var CanvasProtocolServer = class {
23382
- constructor(config, projectId, output, session) {
23423
+ constructor(config, projectId, output, session, options = {}) {
23383
23424
  this.projectId = projectId;
23384
23425
  this.output = output;
23426
+ this.options = options;
23385
23427
  this.client = new CanvasClient(config, projectId, session);
23386
23428
  }
23387
23429
  projectId;
23388
23430
  output;
23431
+ options;
23389
23432
  client;
23390
23433
  initialized = false;
23391
23434
  shuttingDown = false;
23392
23435
  shutdownFinalized = false;
23393
- displayName = "AZ8 CLI";
23436
+ clientName = "cli";
23394
23437
  observationPreset = "compact";
23395
23438
  observationInclude = /* @__PURE__ */ new Set();
23396
23439
  recordedRequests = /* @__PURE__ */ new Map();
@@ -23533,8 +23576,11 @@ var CanvasProtocolServer = class {
23533
23576
  "initialize projectId does not match canvas open."
23534
23577
  );
23535
23578
  }
23579
+ const clientName = normalizeCanvasClientName(
23580
+ this.options.clientName ?? request.payload.client?.name
23581
+ );
23536
23582
  this.initialized = true;
23537
- this.displayName = request.payload.client?.name ?? "AZ8 CLI";
23583
+ this.clientName = clientName;
23538
23584
  this.observationPreset = request.payload.observationPreset ?? "compact";
23539
23585
  this.unsubscribeObservation = this.session.subscribe((observation) => {
23540
23586
  const category = observation.kind === "workflow" ? "workflow" : "canvas";
@@ -23558,7 +23604,7 @@ var CanvasProtocolServer = class {
23558
23604
  }
23559
23605
  async connect(requestId) {
23560
23606
  try {
23561
- await this.client.connect(this.displayName, (state) => {
23607
+ await this.client.connect(this.clientName, (state) => {
23562
23608
  void this.output.emitMandatory({ payload: { state }, requestId, type: "lifecycle" });
23563
23609
  });
23564
23610
  } catch (error) {
@@ -23936,7 +23982,7 @@ async function runCanvasOneShot(config, command, dependencies = {}) {
23936
23982
  try {
23937
23983
  assertProcessIndependent(command);
23938
23984
  client = dependencies.clientFactory?.(config, command.projectId) ?? new CanvasClient(config, command.projectId);
23939
- await client.connect(command.clientName ?? "AZ8 CLI one-shot");
23985
+ await client.connect(normalizeCanvasClientName(command.clientName));
23940
23986
  if (command.kind === "query") {
23941
23987
  return {
23942
23988
  exitCode: 0,
@@ -24159,7 +24205,7 @@ async function runCanvasMediaDownload(config, command, dependencies = {}) {
24159
24205
  try {
24160
24206
  client = dependencies.mediaDownloadClientFactory?.(config, command.projectId) ?? new CanvasClient(config, command.projectId);
24161
24207
  try {
24162
- await client.connect(command.clientName ?? "AZ8 CLI media download");
24208
+ await client.connect(normalizeCanvasClientName(command.clientName));
24163
24209
  } catch {
24164
24210
  throw new MediaDownloadError(
24165
24211
  "canvas-connection-failed",
@@ -25029,7 +25075,7 @@ function projectHelpOutput() {
25029
25075
  function canvasHelpOutput() {
25030
25076
  return [
25031
25077
  "Canvas:",
25032
- " az8 canvas open <project-id> --write --format ndjson",
25078
+ " az8 canvas open <project-id> --write --format ndjson [--client-name <suffix>]",
25033
25079
  " az8 canvas inspect <project-id> Print the latest persisted snapshot as JSON",
25034
25080
  " az8 canvas upload <project-id> --file <path> --idempotency-key <key>",
25035
25081
  " az8 canvas download <project-id> (--view-node-id <id> | --core-node-id <id>) --output <path>",
@@ -25042,7 +25088,7 @@ function canvasHelpOutput() {
25042
25088
  " --input-json <json> Read one inline JSON object",
25043
25089
  " --request-id <id> Set the Operation Receipt request ID",
25044
25090
  " --timeout-ms <ms> Set the operation acknowledgement timeout",
25045
- " --client-name <name> Set the ephemeral awareness display name",
25091
+ " --client-name <suffix> Set the parenthesized awareness client suffix",
25046
25092
  "",
25047
25093
  "One-shot query options:",
25048
25094
  " --view-node-id <id> Select one View Node for canvas.detail",
@@ -25235,7 +25281,15 @@ async function runPersistentCanvas(args2) {
25235
25281
  });
25236
25282
  try {
25237
25283
  const config = await resolveCliConfig(args2, {});
25238
- server = new CanvasProtocolServer(config, projectId, output);
25284
+ const requestedClientName = readOption3(args2, "--client-name");
25285
+ const clientName = requestedClientName ? normalizeCanvasClientName(requestedClientName) : void 0;
25286
+ server = new CanvasProtocolServer(
25287
+ config,
25288
+ projectId,
25289
+ output,
25290
+ void 0,
25291
+ clientName ? { clientName } : {}
25292
+ );
25239
25293
  const shutdownOnSignal = (signal) => {
25240
25294
  void server?.shutdownFromControl(signal.toLowerCase()).finally(() => process.stdin.destroy());
25241
25295
  };
@@ -25252,7 +25306,10 @@ async function runPersistentCanvas(args2) {
25252
25306
  }
25253
25307
  function readOption3(args2, name) {
25254
25308
  const index = args2.indexOf(name);
25255
- return index >= 0 ? args2[index + 1] : void 0;
25309
+ if (index < 0) return void 0;
25310
+ const value = args2[index + 1];
25311
+ if (!value || value.startsWith("--")) throw new Error(`${name} requires a value.`);
25312
+ return value;
25256
25313
  }
25257
25314
  function safeDiagnostic(error) {
25258
25315
  const message = error instanceof Error ? error.message : "Persistent Canvas client failed.";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@everfir/az8-cli",
3
- "version": "0.2.0-preview.3",
3
+ "version": "0.2.0-preview.5",
4
4
  "description": "Semantic Project Canvas client for AZ8 Studio agents.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
@@ -46,8 +46,10 @@ capabilities instead of guessing operation names or input shapes.
46
46
  outcome, revisions, and optional usage. It is not Canvas History.
47
47
  - **History** contains reversible local interactions. Only Operations advertised as `undoable`
48
48
  participate. A generation start is a History barrier and is not undone by `undo`.
49
- - **Awareness** is ephemeral presence, client name, and Attention Cursor information. It never
50
- grants authority, changes persisted authorship, or proves a business result.
49
+ - **Awareness** is ephemeral presence, client suffix, and Attention Cursor information. The visible
50
+ name is always `<authenticated display name> (<client suffix>)`; the default suffix is `cli`.
51
+ CLI awareness does not publish selection bounds. Awareness never grants authority, changes
52
+ persisted authorship, or proves a business result.
51
53
  - **Actor** is the authenticated account from `AZ8_TOKEN`. A client or awareness name cannot
52
54
  impersonate another author.
53
55
 
@@ -115,31 +117,26 @@ capabilities instead of guessing operation names or input shapes.
115
117
  az8 canvas query <project-id> canvas.detail --view-node-id <view-node-id>
116
118
  ```
117
119
 
118
- 6. Choose one-shot for independent tasks and persistent stdio for a collaborative session. Finish
119
- by inspecting the affected View Nodes or Workflow Run rather than trusting visual assumptions.
120
+ 6. If the task may perform any Canvas write, open one persistent stdio client before the first
121
+ Canvas read or write and retain it through the authoring session. Use one-shot only under the
122
+ explicit exceptions below. Finish by inspecting the affected View Nodes or Workflow Run rather
123
+ than trusting visual assumptions.
120
124
 
121
125
  ## Interaction modes
122
126
 
123
- Use one-shot commands for a self-contained query, write, upload, or download:
124
-
125
- ```bash
126
- printf '%s\n' '{"text":"Idea","position":{"x":160,"y":160}}' |
127
- az8 canvas operation <project-id> createNote --input-stdin --request-id create-note-1
128
- ```
129
-
130
- - Supply Operation input through exactly one of `--input-stdin`, `--input-file`, or `--input-json`.
131
- - Give every write attempt a meaningful unique `--request-id` and retain its returned Receipt.
132
- - Each invocation opens, hydrates, executes, and closes a real Canvas client.
133
- - One-shot processes do not preserve local History, Receipt Log, Awareness, or request replay.
134
- Therefore `undo`, `redo`, `receipts.summary`, and `receipt.detail` require persistent stdio.
135
-
136
- Use persistent stdio when multiple ordered interactions, live synchronization, History, Receipt
137
- lookup, observations, or human collaboration matter:
127
+ Default to persistent stdio for Canvas authoring. A one-write plan still uses persistent stdio. This
128
+ is the normal mode whenever a task may create, edit, move, organize, remove, undo, generate, import,
129
+ or upload Canvas content. Open the client once, use it for capability discovery and subsequent reads
130
+ and Operations, observe concurrent changes, and shut it down only after the Canvas task is complete:
138
131
 
139
132
  ```bash
140
133
  az8 canvas open <project-id> --write --format ndjson
141
134
  ```
142
135
 
136
+ Use `--client-name <suffix>` only when a more specific CLI presence label helps collaborators. The
137
+ CLI owns the surrounding parentheses, rejects parentheses in the supplied suffix, and always keeps
138
+ the authenticated user display name first.
139
+
143
140
  1. Continuously drain stdout; it is an ordered NDJSON protocol stream and may apply backpressure.
144
141
  2. Read `hello`, select protocol `1.0`, then send `initialize` for the same Project ID.
145
142
  3. Wait for `ready` before any query or Operation.
@@ -153,6 +150,24 @@ az8 canvas open <project-id> --write --format ndjson
153
150
  Protocol truth is written to stdout. stderr contains diagnostics only. Unknown optional fields are
154
151
  additive; ignore them. Do not treat a process exit code as the result of the last persistent request.
155
152
 
153
+ Use one-shot only for:
154
+
155
+ - an isolated read when no Canvas write is planned;
156
+ - a standalone media download;
157
+ - an explicitly standalone upload/import whose caller does not want an ongoing authoring session;
158
+ - an explicit user request for one-shot behavior; or
159
+ - a host that genuinely cannot retain a child process and write later NDJSON to its stdin.
160
+
161
+ Do not choose one-shot merely because the current plan has one write or because it requires fewer
162
+ tool calls. Codex and other hosts with retained process sessions can use persistent stdio. If a host
163
+ limitation forces fallback, disclose that the client will not preserve local History, Receipt Log,
164
+ Awareness, observations, or request replay across invocations.
165
+
166
+ For a permitted one-shot call, supply Operation input through exactly one of `--input-stdin`,
167
+ `--input-file`, or `--input-json`, give every write a meaningful unique `--request-id`, and retain its
168
+ returned Receipt. `undo`, `redo`, `receipts.summary`, and `receipt.detail` are never available across
169
+ one-shot processes.
170
+
156
171
  ## Canvas SOP
157
172
 
158
173
  1. Query `canvas.summary`; query selected details only as needed.
@@ -198,11 +213,15 @@ configuration option, modality, cost, or media compatibility from its display na
198
213
 
199
214
  The start Receipt may report `usage.credits.status` as `estimated`, `not-consumed`, or `unknown`.
200
215
  Estimated cost is informational, not final charged usage. There is no second confirmation. Never
201
- claim actual credit consumption from an estimate.
216
+ claim actual credit consumption from an estimate. When timing data is available, `startGeneration`
217
+ also records the same median and maximum completion timestamps Web uses to display expected duration;
218
+ these timestamps remain estimates and do not change the Run's completion boundary.
202
219
 
203
220
  ## Media
204
221
 
205
- For a local image, video, or audio file, use the semantic upload wrapper:
222
+ Within an active persistent authoring session, invoke the discovered `uploadMedia` Operation so the
223
+ write shares that client lifecycle. For an explicitly standalone local image, video, or audio
224
+ transfer, use the semantic one-shot upload wrapper:
206
225
 
207
226
  ```bash
208
227
  az8 canvas upload <project-id> \
@@ -274,8 +293,8 @@ Never:
274
293
  or protocol payloads;
275
294
  - inspect, print, or edit an operator-provisioned credential source merely to check whether it
276
295
  exists; authenticate with a bounded read instead;
277
- - use awareness client names to impersonate persisted authors or treat Attention Cursor position as
278
- authority;
296
+ - use awareness client suffixes to impersonate persisted authors, supply parentheses to obscure the
297
+ authenticated-name boundary, or treat Attention Cursor position as authority;
279
298
  - use one-shot as if it retained History, Receipts, replay state, observations, or presence;
280
299
  - attempt Asset membership, arbitrary Core Node creation, 3D World editing, unsupported
281
300
  Decoration, alignment, or automatic layout through lower-level access;