@everfir/az8-cli 0.2.0-preview.4 → 0.2.0
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 +33 -0
- package/README.md +22 -13
- package/RELEASE.md +31 -12
- package/dist/main.js +100 -21
- package/package.json +6 -5
- package/skills/az8-cli/SKILL.md +40 -9
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,39 @@
|
|
|
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 - 2026-07-22
|
|
7
|
+
|
|
8
|
+
First stable semantic Project Canvas client for agents.
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Project management, persistent NDJSON Canvas collaboration, one-shot compatibility wrappers,
|
|
13
|
+
semantic note and hierarchy authoring, Core Node generation, Workflow observation, and safe local
|
|
14
|
+
media upload/download.
|
|
15
|
+
- A runtime-discoverable built-in agent Skill covering platform concepts, capability discovery,
|
|
16
|
+
persistent request/process lifecycle, generation sequencing, recovery, and prohibited bypasses.
|
|
17
|
+
|
|
18
|
+
### Stability contract
|
|
19
|
+
|
|
20
|
+
- Public Canvas writes remain available only through semantic Operations and internal Commands;
|
|
21
|
+
callers cannot write raw backend, Yjs, Core Node, or Project Content data.
|
|
22
|
+
- Protocol `1.0`, ordered request/Receipt behavior, authenticated presence, no automatic write retry,
|
|
23
|
+
and explicit deferred scopes form the initial stable compatibility boundary.
|
|
24
|
+
- 3D World, Asset aggregate management, automatic layout, media replacement, and batch upload remain
|
|
25
|
+
intentionally deferred rather than partially exposed.
|
|
26
|
+
|
|
27
|
+
## 0.2.0-preview.5 - 2026-07-22
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
|
|
31
|
+
- Canvas awareness names now preserve the authenticated user's Web-equivalent display name first
|
|
32
|
+
and append a CLI-owned parenthesized client suffix, defaulting to `(cli)`.
|
|
33
|
+
- `--client-name <suffix>` may override the client suffix for persistent and one-shot lifecycles,
|
|
34
|
+
but caller-provided parentheses are rejected so presence cannot obscure the name boundary.
|
|
35
|
+
- CLI attention awareness now publishes only the semantic cursor and omits selection bounds.
|
|
36
|
+
- `startGeneration` now carries valid Workflow execution-time estimates into the View Node's
|
|
37
|
+
generation history as Web-compatible median and maximum completion timestamps.
|
|
38
|
+
|
|
6
39
|
## 0.2.0-preview.4 - 2026-07-22
|
|
7
40
|
|
|
8
41
|
### Changed
|
package/README.md
CHANGED
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
AZ8 CLI is a semantic Project Canvas client for agents. It does not import Web implementation code
|
|
4
4
|
and does not expose raw backend, Yjs, or document mutation commands.
|
|
5
5
|
|
|
6
|
-
## Install
|
|
6
|
+
## Install
|
|
7
7
|
|
|
8
|
-
AZ8 CLI requires Node.js 20 or newer. Install the
|
|
8
|
+
AZ8 CLI requires Node.js 20 or newer. Install the stable channel from the configured npm registry:
|
|
9
9
|
|
|
10
10
|
```bash
|
|
11
|
-
npm install --global @everfir/az8-cli
|
|
11
|
+
npm install --global @everfir/az8-cli
|
|
12
12
|
az8 --version
|
|
13
13
|
az8 help
|
|
14
14
|
az8 guide
|
|
@@ -17,12 +17,12 @@ 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
|
|
20
|
+
npm install --global ./everfir-az8-cli-0.2.0.tgz
|
|
21
21
|
az8 --version
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
`az8 --version` must report the version selected for the agent environment.
|
|
25
|
-
|
|
24
|
+
`az8 --version` must report the version selected for the agent environment. Pin an exact version or
|
|
25
|
+
tarball for reproducible agent runs.
|
|
26
26
|
|
|
27
27
|
## Built-in agent Skill
|
|
28
28
|
|
|
@@ -124,7 +124,10 @@ az8 canvas operation <project-id> startGeneration \
|
|
|
124
124
|
Operation input is one JSON object supplied by exactly one of `--input-stdin`, `--input-file`, or
|
|
125
125
|
`--input-json`; omitted input defaults to `{}`. Input is limited to one MiB. `--timeout-ms` controls
|
|
126
126
|
the same Operation acknowledgement or domain observation window as persistent stdio, and
|
|
127
|
-
`--client-name` changes only the ephemeral awareness
|
|
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.
|
|
128
131
|
|
|
129
132
|
Success writes one `az8.canvas.one-shot.v1` JSON document to stdout and exits `0`. A definitive
|
|
130
133
|
input, validation, permission, or business failure writes structured JSON to stderr and exits `1`.
|
|
@@ -216,7 +219,7 @@ Canvas query, keep capability discovery and all ordered Operations in the same l
|
|
|
216
219
|
it down only after the authoring task is complete.
|
|
217
220
|
|
|
218
221
|
```bash
|
|
219
|
-
az8 canvas open <project-id> --write --format ndjson
|
|
222
|
+
az8 canvas open <project-id> --write --format ndjson [--client-name codex]
|
|
220
223
|
```
|
|
221
224
|
|
|
222
225
|
The process writes one `hello` frame, then waits for an `initialize` request on stdin:
|
|
@@ -226,9 +229,12 @@ The process writes one `hello` frame, then waits for an `initialize` request on
|
|
|
226
229
|
```
|
|
227
230
|
|
|
228
231
|
Before readiness the client hydrates the current authenticated account profile. Canvas Operations use
|
|
229
|
-
that immutable account id and display name for persisted creator data.
|
|
230
|
-
|
|
231
|
-
|
|
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.
|
|
232
238
|
|
|
233
239
|
After `ready`, requests use `query`, `configureObservations`, `operation`, `reconnect`, or `shutdown`.
|
|
234
240
|
The public authoring surface includes the note lifecycle, non-World View Node hierarchy operations,
|
|
@@ -311,6 +317,9 @@ explicitly submitting the same input. An uncertain backend or collaboration outc
|
|
|
311
317
|
are acknowledged. It first estimates the exact current Draft inputs, then materializes literal Core
|
|
312
318
|
Nodes and starts with the estimate's cost and Definition version. This estimate is internal: there is
|
|
313
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.
|
|
314
323
|
Waiting for a terminal result is deliberately a separate operation. Generation is a non-undoable
|
|
315
324
|
Canvas History barrier. The CLI does not expose Assets, arbitrary Core Node creation, or 3D World
|
|
316
325
|
operations.
|
|
@@ -340,9 +349,9 @@ Every output frame has `protocolVersion`, monotonic `streamSeq`, `type`, `payloa
|
|
|
340
349
|
after collaboration-server acknowledgement. A timeout or lost acknowledgement is indeterminate,
|
|
341
350
|
moves the Canvas context offline, and requires explicit reconnect and inspection before any retry.
|
|
342
351
|
|
|
343
|
-
##
|
|
352
|
+
## Release acceptance checklist
|
|
344
353
|
|
|
345
|
-
Before distributing a
|
|
354
|
+
Before distributing a release tarball, verify all of the following from its clean installation, not
|
|
346
355
|
from TypeScript source:
|
|
347
356
|
|
|
348
357
|
1. `az8 --version` matches the immutable package version; `az8 help` lists the built-in guide,
|
package/RELEASE.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
# AZ8 CLI
|
|
1
|
+
# AZ8 CLI release
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
`latest` is the stable release channel. Preview versions remain immutable historical artifacts and
|
|
4
|
+
must not be republished or renamed into a stable version.
|
|
5
5
|
|
|
6
6
|
## Release gate
|
|
7
7
|
|
|
@@ -12,9 +12,11 @@ pnpm release:az8-cli
|
|
|
12
12
|
pnpm release:pack:az8-cli
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
The first command
|
|
16
|
-
a
|
|
17
|
-
|
|
15
|
+
The first command rebuilds the CLI's classified workspace dependencies, runs CLI tests and type
|
|
16
|
+
checking, builds a real npm tarball, installs that tarball in a clean temporary directory, and
|
|
17
|
+
verifies the installed `az8` executable. The second repeats the dependency-aware prepack and
|
|
18
|
+
preserves the verified tarball and clean installation under `tmp/az8-cli-release/` for live
|
|
19
|
+
acceptance. Never bundle against pre-existing workspace `dist/` output.
|
|
18
20
|
|
|
19
21
|
Run the live smoke only against the test environment. It creates one Project unless `--project-id`
|
|
20
22
|
reuses an explicit test Project, starts one image generation, and uploads one tiny PNG:
|
|
@@ -28,28 +30,45 @@ node apps/az8-cli/scripts/smoke-test.js \
|
|
|
28
30
|
The smoke report must show authenticated persistent stdio, ordered shutdown, a completed Workflow
|
|
29
31
|
Run whose target resolves its output Core Node, upload replay without another transfer, and matching
|
|
30
32
|
download SHA-256. `--skip-generation` is only for diagnosing unrelated media or transport checks;
|
|
31
|
-
it cannot satisfy full release acceptance.
|
|
33
|
+
it cannot satisfy full release acceptance. When the release changes generation-time projection,
|
|
34
|
+
select a timing-enabled test Definition and require its persisted Web estimate:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
node apps/az8-cli/scripts/smoke-test.js \
|
|
38
|
+
--bin ./tmp/az8-cli-release/install/node_modules/.bin/az8 \
|
|
39
|
+
--env-file ./.env.local \
|
|
40
|
+
--generation-definition-id <timing-enabled-test-definition-id> \
|
|
41
|
+
--require-generation-estimate
|
|
42
|
+
```
|
|
32
43
|
|
|
33
44
|
Before publishing, also run the test-environment acceptance checklist in the packaged README and the
|
|
34
45
|
repository-wide `pnpm verify`. Publishing is an external action and requires explicit operator
|
|
35
46
|
authorization:
|
|
36
47
|
|
|
37
48
|
```bash
|
|
38
|
-
npm publish ./tmp/az8-cli-release/everfir-az8-cli-0.2.0
|
|
49
|
+
npm publish ./tmp/az8-cli-release/everfir-az8-cli-0.2.0.tgz --tag latest
|
|
39
50
|
npm view @everfir/az8-cli dist-tags versions --json
|
|
40
51
|
```
|
|
41
52
|
|
|
42
|
-
|
|
53
|
+
Publish only the exact retained tarball whose SHA-512 appears in the stable release verification
|
|
54
|
+
record. Do not publish from an unverified source directory. If the obsolete misspelled `prewview`
|
|
55
|
+
tag still exists after stable publication, remove that tag without unpublishing its immutable
|
|
56
|
+
version:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
npm dist-tag rm @everfir/az8-cli prewview
|
|
60
|
+
npm view @everfir/az8-cli dist-tags --json
|
|
61
|
+
```
|
|
43
62
|
|
|
44
63
|
## Rollback
|
|
45
64
|
|
|
46
|
-
Published versions are immutable. Rollback moves
|
|
65
|
+
Published versions are immutable. Rollback moves `latest` to a previously verified stable version
|
|
47
66
|
instead of unpublishing or overwriting a package:
|
|
48
67
|
|
|
49
68
|
```bash
|
|
50
|
-
npm dist-tag add @everfir/az8-cli@<previous-version>
|
|
69
|
+
npm dist-tag add @everfir/az8-cli@<previous-stable-version> latest
|
|
51
70
|
npm view @everfir/az8-cli dist-tags --json
|
|
52
|
-
npm install --global @everfir/az8-cli
|
|
71
|
+
npm install --global @everfir/az8-cli
|
|
53
72
|
az8 --version
|
|
54
73
|
```
|
|
55
74
|
|
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;
|
|
@@ -13579,10 +13600,7 @@ var HocuspocusProjectCanvasDocumentImplementation = class {
|
|
|
13579
13600
|
this.setAwarenessFields({
|
|
13580
13601
|
cursor: input.cursor,
|
|
13581
13602
|
updatedAt: Date.now(),
|
|
13582
|
-
view: {
|
|
13583
|
-
kind: "canvas",
|
|
13584
|
-
...input.selection ? { selection: input.selection } : {}
|
|
13585
|
-
}
|
|
13603
|
+
view: { kind: "canvas" }
|
|
13586
13604
|
});
|
|
13587
13605
|
}
|
|
13588
13606
|
getAwareness() {
|
|
@@ -15916,6 +15934,7 @@ var CoreNodeCreativeLoop = class {
|
|
|
15916
15934
|
prepared,
|
|
15917
15935
|
timeoutMs
|
|
15918
15936
|
});
|
|
15937
|
+
const submittedAt = this.context.now();
|
|
15919
15938
|
const run = await this.systems.workflowRuntime.startRun({
|
|
15920
15939
|
definitionId: definition.id,
|
|
15921
15940
|
expectedCost: estimate.estimatedCost,
|
|
@@ -15933,11 +15952,13 @@ var CoreNodeCreativeLoop = class {
|
|
|
15933
15952
|
runtime: {
|
|
15934
15953
|
expectedCost: estimate.estimatedCost,
|
|
15935
15954
|
expectedDefinitionVersion: estimate.definitionVersion,
|
|
15955
|
+
...createEstimatedCompletionTimes(estimate, submittedAt),
|
|
15936
15956
|
instanceIds: [run.id],
|
|
15937
15957
|
materializedInputs: materialized.materializedInputs,
|
|
15938
15958
|
originClientId: this.context.clientInstanceId,
|
|
15939
|
-
submittedAt
|
|
15940
|
-
}
|
|
15959
|
+
submittedAt
|
|
15960
|
+
},
|
|
15961
|
+
updatedAt: timestamp
|
|
15941
15962
|
};
|
|
15942
15963
|
const { creationIntent: _creationIntent, ...data } = asRecord3(target.data);
|
|
15943
15964
|
const after = {
|
|
@@ -16224,6 +16245,28 @@ var CoreNodeCreativeLoop = class {
|
|
|
16224
16245
|
};
|
|
16225
16246
|
}
|
|
16226
16247
|
};
|
|
16248
|
+
function createEstimatedCompletionTimes(estimate, submittedAt) {
|
|
16249
|
+
const ranges = estimate.executionTimeRanges;
|
|
16250
|
+
if (!ranges?.length)
|
|
16251
|
+
return {};
|
|
16252
|
+
let medianSeconds = 0;
|
|
16253
|
+
let maxSeconds = 0;
|
|
16254
|
+
let validRangeCount = 0;
|
|
16255
|
+
for (const range of ranges) {
|
|
16256
|
+
if (!Number.isFinite(range.medianSeconds) || range.medianSeconds < 0 || !Number.isFinite(range.maxSeconds) || range.maxSeconds < 0) {
|
|
16257
|
+
continue;
|
|
16258
|
+
}
|
|
16259
|
+
medianSeconds += range.medianSeconds;
|
|
16260
|
+
maxSeconds += range.maxSeconds;
|
|
16261
|
+
validRangeCount += 1;
|
|
16262
|
+
}
|
|
16263
|
+
if (validRangeCount === 0)
|
|
16264
|
+
return {};
|
|
16265
|
+
return {
|
|
16266
|
+
estimatedMaxCompletionAt: submittedAt + maxSeconds * 1e3,
|
|
16267
|
+
estimatedMedianCompletionAt: submittedAt + medianSeconds * 1e3
|
|
16268
|
+
};
|
|
16269
|
+
}
|
|
16227
16270
|
function attention(viewNodeId, result3) {
|
|
16228
16271
|
return { attention: { kind: "view-nodes", viewNodeIds: [viewNodeId] }, result: result3 };
|
|
16229
16272
|
}
|
|
@@ -22727,9 +22770,26 @@ function mapWorkflowRunEstimate(value, definitionId) {
|
|
|
22727
22770
|
canAfford: value.can_afford,
|
|
22728
22771
|
definitionId: value.definition_id,
|
|
22729
22772
|
definitionVersion: value.definition_version,
|
|
22730
|
-
estimatedCost: value.estimated_cost
|
|
22773
|
+
estimatedCost: value.estimated_cost,
|
|
22774
|
+
executionTimeRanges: (value.execution_time_ranges ?? []).flatMap((item) => {
|
|
22775
|
+
const range = item.range;
|
|
22776
|
+
if (!range || !isNonNegativeFinite(range.minSeconds) || !isNonNegativeFinite(range.maxSeconds) || !isNonNegativeFinite(range.medianSeconds) || !isNonNegativeFinite(range.sampleCount)) {
|
|
22777
|
+
return [];
|
|
22778
|
+
}
|
|
22779
|
+
return [
|
|
22780
|
+
{
|
|
22781
|
+
maxSeconds: range.maxSeconds,
|
|
22782
|
+
medianSeconds: range.medianSeconds,
|
|
22783
|
+
minSeconds: range.minSeconds,
|
|
22784
|
+
sampleCount: range.sampleCount
|
|
22785
|
+
}
|
|
22786
|
+
];
|
|
22787
|
+
})
|
|
22731
22788
|
};
|
|
22732
22789
|
}
|
|
22790
|
+
function isNonNegativeFinite(value) {
|
|
22791
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0;
|
|
22792
|
+
}
|
|
22733
22793
|
function mapWorkflowDefinition(value) {
|
|
22734
22794
|
if (!value.id || !value.name || typeof value.version !== "number") {
|
|
22735
22795
|
throw new Error("Workflow Runtime returned an invalid Definition.");
|
|
@@ -22903,7 +22963,8 @@ var CanvasSession = class {
|
|
|
22903
22963
|
projectionRevision = 0;
|
|
22904
22964
|
actorId = null;
|
|
22905
22965
|
health;
|
|
22906
|
-
async connect(
|
|
22966
|
+
async connect(clientName, onState) {
|
|
22967
|
+
const normalizedClientName = normalizeCanvasClientName(clientName);
|
|
22907
22968
|
this.closeContext();
|
|
22908
22969
|
this.transition("authenticating", onState);
|
|
22909
22970
|
this.health.connectionAttempts += 1;
|
|
@@ -22927,7 +22988,10 @@ var CanvasSession = class {
|
|
|
22927
22988
|
});
|
|
22928
22989
|
this.document = document2;
|
|
22929
22990
|
try {
|
|
22930
|
-
document2.setIdentity({
|
|
22991
|
+
document2.setIdentity({
|
|
22992
|
+
accountId: actor.accountId,
|
|
22993
|
+
displayName: formatCanvasAwarenessName(actor.displayName, normalizedClientName)
|
|
22994
|
+
});
|
|
22931
22995
|
this.transition("hydrating", onState);
|
|
22932
22996
|
const foundationData = this.dependencies.foundationData ?? createAz8FoundationDataSystem(this.config);
|
|
22933
22997
|
const projectContent = this.dependencies.projectContent ?? createAz8ProjectContentSystem(this.config);
|
|
@@ -23037,8 +23101,7 @@ var CanvasSession = class {
|
|
|
23037
23101
|
}
|
|
23038
23102
|
publishAttentionBounds(bounds) {
|
|
23039
23103
|
this.requireDocument().setAttention({
|
|
23040
|
-
cursor: { x: bounds.x + bounds.width + 24, y: bounds.y + bounds.height / 2 }
|
|
23041
|
-
selection: bounds
|
|
23104
|
+
cursor: { x: bounds.x + bounds.width + 24, y: bounds.y + bounds.height / 2 }
|
|
23042
23105
|
});
|
|
23043
23106
|
}
|
|
23044
23107
|
closeContext() {
|
|
@@ -23379,18 +23442,20 @@ function requirePositiveInteger(value, field) {
|
|
|
23379
23442
|
|
|
23380
23443
|
// src/canvas-protocol-server.ts
|
|
23381
23444
|
var CanvasProtocolServer = class {
|
|
23382
|
-
constructor(config, projectId, output, session) {
|
|
23445
|
+
constructor(config, projectId, output, session, options = {}) {
|
|
23383
23446
|
this.projectId = projectId;
|
|
23384
23447
|
this.output = output;
|
|
23448
|
+
this.options = options;
|
|
23385
23449
|
this.client = new CanvasClient(config, projectId, session);
|
|
23386
23450
|
}
|
|
23387
23451
|
projectId;
|
|
23388
23452
|
output;
|
|
23453
|
+
options;
|
|
23389
23454
|
client;
|
|
23390
23455
|
initialized = false;
|
|
23391
23456
|
shuttingDown = false;
|
|
23392
23457
|
shutdownFinalized = false;
|
|
23393
|
-
|
|
23458
|
+
clientName = "cli";
|
|
23394
23459
|
observationPreset = "compact";
|
|
23395
23460
|
observationInclude = /* @__PURE__ */ new Set();
|
|
23396
23461
|
recordedRequests = /* @__PURE__ */ new Map();
|
|
@@ -23533,8 +23598,11 @@ var CanvasProtocolServer = class {
|
|
|
23533
23598
|
"initialize projectId does not match canvas open."
|
|
23534
23599
|
);
|
|
23535
23600
|
}
|
|
23601
|
+
const clientName = normalizeCanvasClientName(
|
|
23602
|
+
this.options.clientName ?? request.payload.client?.name
|
|
23603
|
+
);
|
|
23536
23604
|
this.initialized = true;
|
|
23537
|
-
this.
|
|
23605
|
+
this.clientName = clientName;
|
|
23538
23606
|
this.observationPreset = request.payload.observationPreset ?? "compact";
|
|
23539
23607
|
this.unsubscribeObservation = this.session.subscribe((observation) => {
|
|
23540
23608
|
const category = observation.kind === "workflow" ? "workflow" : "canvas";
|
|
@@ -23558,7 +23626,7 @@ var CanvasProtocolServer = class {
|
|
|
23558
23626
|
}
|
|
23559
23627
|
async connect(requestId) {
|
|
23560
23628
|
try {
|
|
23561
|
-
await this.client.connect(this.
|
|
23629
|
+
await this.client.connect(this.clientName, (state) => {
|
|
23562
23630
|
void this.output.emitMandatory({ payload: { state }, requestId, type: "lifecycle" });
|
|
23563
23631
|
});
|
|
23564
23632
|
} catch (error) {
|
|
@@ -23936,7 +24004,7 @@ async function runCanvasOneShot(config, command, dependencies = {}) {
|
|
|
23936
24004
|
try {
|
|
23937
24005
|
assertProcessIndependent(command);
|
|
23938
24006
|
client = dependencies.clientFactory?.(config, command.projectId) ?? new CanvasClient(config, command.projectId);
|
|
23939
|
-
await client.connect(command.clientName
|
|
24007
|
+
await client.connect(normalizeCanvasClientName(command.clientName));
|
|
23940
24008
|
if (command.kind === "query") {
|
|
23941
24009
|
return {
|
|
23942
24010
|
exitCode: 0,
|
|
@@ -24159,7 +24227,7 @@ async function runCanvasMediaDownload(config, command, dependencies = {}) {
|
|
|
24159
24227
|
try {
|
|
24160
24228
|
client = dependencies.mediaDownloadClientFactory?.(config, command.projectId) ?? new CanvasClient(config, command.projectId);
|
|
24161
24229
|
try {
|
|
24162
|
-
await client.connect(command.clientName
|
|
24230
|
+
await client.connect(normalizeCanvasClientName(command.clientName));
|
|
24163
24231
|
} catch {
|
|
24164
24232
|
throw new MediaDownloadError(
|
|
24165
24233
|
"canvas-connection-failed",
|
|
@@ -25029,7 +25097,7 @@ function projectHelpOutput() {
|
|
|
25029
25097
|
function canvasHelpOutput() {
|
|
25030
25098
|
return [
|
|
25031
25099
|
"Canvas:",
|
|
25032
|
-
" az8 canvas open <project-id> --write --format ndjson",
|
|
25100
|
+
" az8 canvas open <project-id> --write --format ndjson [--client-name <suffix>]",
|
|
25033
25101
|
" az8 canvas inspect <project-id> Print the latest persisted snapshot as JSON",
|
|
25034
25102
|
" az8 canvas upload <project-id> --file <path> --idempotency-key <key>",
|
|
25035
25103
|
" az8 canvas download <project-id> (--view-node-id <id> | --core-node-id <id>) --output <path>",
|
|
@@ -25042,7 +25110,7 @@ function canvasHelpOutput() {
|
|
|
25042
25110
|
" --input-json <json> Read one inline JSON object",
|
|
25043
25111
|
" --request-id <id> Set the Operation Receipt request ID",
|
|
25044
25112
|
" --timeout-ms <ms> Set the operation acknowledgement timeout",
|
|
25045
|
-
" --client-name <
|
|
25113
|
+
" --client-name <suffix> Set the parenthesized awareness client suffix",
|
|
25046
25114
|
"",
|
|
25047
25115
|
"One-shot query options:",
|
|
25048
25116
|
" --view-node-id <id> Select one View Node for canvas.detail",
|
|
@@ -25235,7 +25303,15 @@ async function runPersistentCanvas(args2) {
|
|
|
25235
25303
|
});
|
|
25236
25304
|
try {
|
|
25237
25305
|
const config = await resolveCliConfig(args2, {});
|
|
25238
|
-
|
|
25306
|
+
const requestedClientName = readOption3(args2, "--client-name");
|
|
25307
|
+
const clientName = requestedClientName ? normalizeCanvasClientName(requestedClientName) : void 0;
|
|
25308
|
+
server = new CanvasProtocolServer(
|
|
25309
|
+
config,
|
|
25310
|
+
projectId,
|
|
25311
|
+
output,
|
|
25312
|
+
void 0,
|
|
25313
|
+
clientName ? { clientName } : {}
|
|
25314
|
+
);
|
|
25239
25315
|
const shutdownOnSignal = (signal) => {
|
|
25240
25316
|
void server?.shutdownFromControl(signal.toLowerCase()).finally(() => process.stdin.destroy());
|
|
25241
25317
|
};
|
|
@@ -25252,7 +25328,10 @@ async function runPersistentCanvas(args2) {
|
|
|
25252
25328
|
}
|
|
25253
25329
|
function readOption3(args2, name) {
|
|
25254
25330
|
const index = args2.indexOf(name);
|
|
25255
|
-
|
|
25331
|
+
if (index < 0) return void 0;
|
|
25332
|
+
const value = args2[index + 1];
|
|
25333
|
+
if (!value || value.startsWith("--")) throw new Error(`${name} requires a value.`);
|
|
25334
|
+
return value;
|
|
25256
25335
|
}
|
|
25257
25336
|
function safeDiagnostic(error) {
|
|
25258
25337
|
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
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Semantic Project Canvas client for AZ8 Studio agents.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|
|
@@ -16,20 +16,21 @@
|
|
|
16
16
|
"main": "./dist/main.js",
|
|
17
17
|
"publishConfig": {
|
|
18
18
|
"access": "public",
|
|
19
|
-
"tag": "
|
|
19
|
+
"tag": "latest"
|
|
20
20
|
},
|
|
21
21
|
"scripts": {
|
|
22
|
-
"build": "rm -rf dist && esbuild src/main.ts --bundle --platform=node --format=esm --target=node20 --banner:js='import { createRequire } from \"node:module\"; const require = createRequire(import.meta.url);' --outfile=dist/main.js",
|
|
22
|
+
"build": "pnpm build:dependencies && rm -rf dist && esbuild src/main.ts --bundle --platform=node --format=esm --target=node20 --banner:js='import { createRequire } from \"node:module\"; const require = createRequire(import.meta.url);' --outfile=dist/main.js",
|
|
23
|
+
"build:dependencies": "pnpm --filter @everfir/az8-cli^... build",
|
|
23
24
|
"dev": "tsx src/main.ts",
|
|
24
25
|
"start": "node dist/main.js",
|
|
25
26
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
26
27
|
"lint": "biome check .",
|
|
27
28
|
"prepack": "pnpm build",
|
|
28
29
|
"prepublishOnly": "pnpm release:check",
|
|
29
|
-
"release:check": "pnpm test && pnpm typecheck && node scripts/verify-package.js",
|
|
30
|
+
"release:check": "pnpm build:dependencies && pnpm test && pnpm typecheck && node scripts/verify-package.js",
|
|
30
31
|
"release:pack": "node scripts/verify-package.js --output-dir ../../tmp/az8-cli-release --keep-install",
|
|
31
32
|
"release:smoke": "node scripts/smoke-test.js",
|
|
32
|
-
"test": "tsx --tsconfig tsconfig.test.json --test src/**/*.test.ts"
|
|
33
|
+
"test": "tsx --tsconfig tsconfig.test.json --test src/**/*.test.ts && node --test scripts/*.test.js"
|
|
33
34
|
},
|
|
34
35
|
"devDependencies": {
|
|
35
36
|
"@types/node": "^25.5.0",
|
package/skills/az8-cli/SKILL.md
CHANGED
|
@@ -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
|
|
50
|
-
|
|
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
|
|
|
@@ -131,6 +133,10 @@ and Operations, observe concurrent changes, and shut it down only after the Canv
|
|
|
131
133
|
az8 canvas open <project-id> --write --format ndjson
|
|
132
134
|
```
|
|
133
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
|
+
|
|
134
140
|
1. Continuously drain stdout; it is an ordered NDJSON protocol stream and may apply backpressure.
|
|
135
141
|
2. Read `hello`, select protocol `1.0`, then send `initialize` for the same Project ID.
|
|
136
142
|
3. Wait for `ready` before any query or Operation.
|
|
@@ -144,6 +150,24 @@ az8 canvas open <project-id> --write --format ndjson
|
|
|
144
150
|
Protocol truth is written to stdout. stderr contains diagnostics only. Unknown optional fields are
|
|
145
151
|
additive; ignore them. Do not treat a process exit code as the result of the last persistent request.
|
|
146
152
|
|
|
153
|
+
Treat the persistent process lifetime and each request lifetime separately:
|
|
154
|
+
|
|
155
|
+
- Keep the process running between requests. Decide request completion only from the matching
|
|
156
|
+
`requestId` and its `requestCompleted` or `requestFailed` frame; never wait for process exit.
|
|
157
|
+
- Treat `requestAccepted` as admission only. For a write, wait for its terminal Receipt before
|
|
158
|
+
issuing the next query or Operation.
|
|
159
|
+
- Continuously drain and parse stdout, but do not repeatedly poll an idle process merely to make it
|
|
160
|
+
produce output. No new frame is a normal healthy state when no lifecycle, request, Canvas, or
|
|
161
|
+
Workflow fact changed.
|
|
162
|
+
- Do not interpret a shell/agent-host read window ending with no output (for example, a 30-second
|
|
163
|
+
terminal yield) as CLI latency, request timeout, or connection failure. Check request terminal
|
|
164
|
+
frames and lifecycle/health facts instead.
|
|
165
|
+
- Keep one connected client for related work. Reopening one-shot clients repeatedly pays connection,
|
|
166
|
+
synchronization, and hydration cost each time and loses local History, Receipts, and presence.
|
|
167
|
+
- Remember that the current persistent protocol processes requests serially. A long
|
|
168
|
+
`waitWorkflowRun` occupies the request lane until the Run becomes terminal or its observation
|
|
169
|
+
window ends; submit it only when no other request needs that lane.
|
|
170
|
+
|
|
147
171
|
Use one-shot only for:
|
|
148
172
|
|
|
149
173
|
- an isolated read when no Canvas write is planned;
|
|
@@ -195,10 +219,15 @@ Generation is an explicit sequence, never one transaction:
|
|
|
195
219
|
current facts. Stop after the first non-success.
|
|
196
220
|
5. `startGeneration` succeeds when the Workflow Run is accepted and immediate Canvas effects are
|
|
197
221
|
acknowledged. This completes the start interaction; it does not mean generation finished.
|
|
198
|
-
6. Retain the Workflow Run ID.
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
7.
|
|
222
|
+
6. Retain the Workflow Run ID. After the successful start Receipt, continue any work that does not
|
|
223
|
+
require the generated output. Prefer `workflowChanged` observations while the persistent client
|
|
224
|
+
is active, and use `getWorkflowRun` at a meaningful later checkpoint.
|
|
225
|
+
7. Use `waitWorkflowRun` only when the next step actually requires terminal output and the current
|
|
226
|
+
request lane can remain dedicated to waiting. Choose one intentional observation window; do not
|
|
227
|
+
emulate polling with repeated short waits. An observation-window timeout while the authoritative
|
|
228
|
+
Run remains pending/running is an ordinary read outcome and does not cancel the Run or take a
|
|
229
|
+
healthy context offline.
|
|
230
|
+
8. On terminal success, query the target detail and resolve its current output Core Node through
|
|
202
231
|
Project Content before downloading or placing it elsewhere.
|
|
203
232
|
|
|
204
233
|
Workflow Definitions change over time. Query `workflowDefinitions.summary`, then
|
|
@@ -207,7 +236,9 @@ configuration option, modality, cost, or media compatibility from its display na
|
|
|
207
236
|
|
|
208
237
|
The start Receipt may report `usage.credits.status` as `estimated`, `not-consumed`, or `unknown`.
|
|
209
238
|
Estimated cost is informational, not final charged usage. There is no second confirmation. Never
|
|
210
|
-
claim actual credit consumption from an estimate.
|
|
239
|
+
claim actual credit consumption from an estimate. When timing data is available, `startGeneration`
|
|
240
|
+
also records the same median and maximum completion timestamps Web uses to display expected duration;
|
|
241
|
+
these timestamps remain estimates and do not change the Run's completion boundary.
|
|
211
242
|
|
|
212
243
|
## Media
|
|
213
244
|
|
|
@@ -285,8 +316,8 @@ Never:
|
|
|
285
316
|
or protocol payloads;
|
|
286
317
|
- inspect, print, or edit an operator-provisioned credential source merely to check whether it
|
|
287
318
|
exists; authenticate with a bounded read instead;
|
|
288
|
-
- use awareness client
|
|
289
|
-
authority;
|
|
319
|
+
- use awareness client suffixes to impersonate persisted authors, supply parentheses to obscure the
|
|
320
|
+
authenticated-name boundary, or treat Attention Cursor position as authority;
|
|
290
321
|
- use one-shot as if it retained History, Receipts, replay state, observations, or presence;
|
|
291
322
|
- attempt Asset membership, arbitrary Core Node creation, 3D World editing, unsupported
|
|
292
323
|
Decoration, alignment, or automatic layout through lower-level access;
|