@timurproko/a1 0.1.8-dev.0b6d8cc → 0.1.8-dev.112
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 +29 -23
- package/dist/native/darwin-arm64/manifest.json +1 -1
- package/dist/native/linux-x64/manifest.json +1 -1
- package/dist/native/win32-x64/manifest.json +2 -2
- package/dist/native/win32-x64/process-guardian.exe +0 -0
- package/dist/src/cli/dispatch.js +14 -12
- package/dist/src/cli/packages.d.ts +9 -1
- package/dist/src/cli/packages.js +24 -20
- package/dist/src/cli/version-stats.js +4 -4
- package/dist/src/foundation/pi-engine-adapter/adapter.js +54 -10
- package/dist/src/foundation/pi-owned-ui-integration/session-shell.d.ts +6 -0
- package/dist/src/foundation/pi-owned-ui-integration/session-shell.js +37 -3
- package/dist/src/foundation/release/update.d.ts +1 -1
- package/dist/src/foundation/release/update.js +9 -13
- package/docs/architecture/toolchain.md +1 -1
- package/docs/ci-release-runbook.md +76 -79
- package/docs/features/launch-profiles.md +1 -1
- package/docs/manual-transparent-checkpoint.md +1 -1
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -10,13 +10,14 @@ npm install --global @timurproko/a1@latest
|
|
|
10
10
|
|
|
11
11
|
```sh
|
|
12
12
|
a1 # A1-owned UI and profile: ~/.a1/agent
|
|
13
|
-
a1 version # show Installed, Release
|
|
14
|
-
a1 update # update to
|
|
15
|
-
a1 update:
|
|
13
|
+
a1 version # show Installed, Release, and Develop versions
|
|
14
|
+
a1 update # update to the current release
|
|
15
|
+
a1 update:develop # update to the current development preview
|
|
16
|
+
a1 update:107 # install numbered development preview 107
|
|
16
17
|
a1 update --models # refresh A1's model catalogs
|
|
17
18
|
```
|
|
18
19
|
|
|
19
|
-
Prerelease builds — what `a1 update:
|
|
20
|
+
Prerelease builds — what `a1 update:develop` installs — add two development profiles
|
|
20
21
|
for comparing against pinned Pi and for experimenting against an isolated profile.
|
|
21
22
|
A release build does not carry them.
|
|
22
23
|
|
|
@@ -63,24 +64,30 @@ npm run test:full # complete non-physical suite
|
|
|
63
64
|
Two channels, both published by CI from the exact bytes it validated. Nothing is
|
|
64
65
|
ever published from a workstation.
|
|
65
66
|
|
|
66
|
-
###
|
|
67
|
+
### Development previews
|
|
67
68
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
installed preview says exactly which source produced it.
|
|
69
|
+
Ordinary pushes to `develop` do not publish. The nightly run at `03:17 UTC` always
|
|
70
|
+
performs complete verification of current `origin/develop`; it publishes only when
|
|
71
|
+
that source's preview is absent. A maintainer can request the same authoritative
|
|
72
|
+
GitHub Actions path and wait for its result:
|
|
73
73
|
|
|
74
74
|
```sh
|
|
75
|
-
|
|
76
|
-
a1 update:7eabe9e # install the preview built from that commit
|
|
75
|
+
npm run develop
|
|
77
76
|
```
|
|
78
77
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
78
|
+
A preview is `<major.minor.patch>-dev.<pull-request number>`, stamped only into the
|
|
79
|
+
package. For example, the source GitHub presents as `develop (#107)` produces
|
|
80
|
+
`0.1.8-dev.107`. Repeating a request for immutable version 107 succeeds without
|
|
81
|
+
building or publishing again.
|
|
82
|
+
|
|
83
|
+
```sh
|
|
84
|
+
a1 update:develop # install the current development preview
|
|
85
|
+
a1 update:107 # install preview 107
|
|
86
|
+
a1 update:0.1.8-dev.107 # install that exact full preview version
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
The published version list is authoritative: an unpublished number is refused
|
|
90
|
+
rather than guessed. npm's `next` dist-tag remains an internal registry detail.
|
|
84
91
|
|
|
85
92
|
### Stable — npm `latest`
|
|
86
93
|
|
|
@@ -93,12 +100,11 @@ npm run release -- major # 0.1.1 -> 1.0.0
|
|
|
93
100
|
npm run release -- 0.4.0 # an exact version
|
|
94
101
|
```
|
|
95
102
|
|
|
96
|
-
It lands the version on `develop` through a pull request that merges itself
|
|
97
|
-
|
|
98
|
-
on Windows, Linux, and macOS, publishes to npm
|
|
99
|
-
then writes the `v<version>` tag and records the
|
|
100
|
-
|
|
101
|
-
immediately.
|
|
103
|
+
It lands the version on `develop` through a pull request that merges itself, then
|
|
104
|
+
explicitly dispatches publication for that exact commit. GitHub Actions builds,
|
|
105
|
+
validates the packed release on Windows, Linux, and macOS, publishes to npm
|
|
106
|
+
`latest` with provenance, and only then writes the `v<version>` tag and records the
|
|
107
|
+
GitHub Release. The command waits for success before opening the next `-dev` line.
|
|
102
108
|
|
|
103
109
|
```sh
|
|
104
110
|
a1 update # install the newest stable release
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"platform": "darwin",
|
|
6
6
|
"architecture": "arm64",
|
|
7
7
|
"capability": "unsupported",
|
|
8
|
-
"builtAt": "2026-08-
|
|
8
|
+
"builtAt": "2026-08-25T09:42:56.359Z",
|
|
9
9
|
"artifact": {
|
|
10
10
|
"filename": "process-guardian",
|
|
11
11
|
"sha256": "7524bf568992517f50ed53196c861c5edeba0d7275633bb4735ab45bd5963a28",
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"platform": "linux",
|
|
6
6
|
"architecture": "x64",
|
|
7
7
|
"capability": "supported",
|
|
8
|
-
"builtAt": "2026-08-
|
|
8
|
+
"builtAt": "2026-08-25T09:43:23.793Z",
|
|
9
9
|
"artifact": {
|
|
10
10
|
"filename": "process-guardian",
|
|
11
11
|
"sha256": "29e22fe29de2828982bc67ef418c4adcaab1490281477b7bea592ec6fe621bcd",
|
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
"platform": "win32",
|
|
6
6
|
"architecture": "x64",
|
|
7
7
|
"capability": "supported",
|
|
8
|
-
"builtAt": "2026-08-
|
|
8
|
+
"builtAt": "2026-08-25T09:44:35.937Z",
|
|
9
9
|
"artifact": {
|
|
10
10
|
"filename": "process-guardian.exe",
|
|
11
|
-
"sha256": "
|
|
11
|
+
"sha256": "0e2919843f1cdc824ce48203dace68df43f8ebb4b24b190ff7baf6c13d4846b1",
|
|
12
12
|
"size": 172544
|
|
13
13
|
},
|
|
14
14
|
"provenance": {
|
|
Binary file
|
package/dist/src/cli/dispatch.js
CHANGED
|
@@ -6,8 +6,8 @@ export function cliUsage(capabilities) {
|
|
|
6
6
|
...(capabilities.developmentProfiles ? ["pi", "sandbox"] : []),
|
|
7
7
|
"version",
|
|
8
8
|
"update [self|--models]",
|
|
9
|
-
"update:
|
|
10
|
-
"update:<
|
|
9
|
+
"update:develop",
|
|
10
|
+
"update:<number>",
|
|
11
11
|
"pi install <source>",
|
|
12
12
|
"pi remove <source>",
|
|
13
13
|
"pi list",
|
|
@@ -58,20 +58,22 @@ export function parseCliCommand(arguments_, capabilities) {
|
|
|
58
58
|
return { kind: "error", message: PRODUCT_TEXT.diagnostic(`received an unknown command: ${command ?? ""}`) };
|
|
59
59
|
}
|
|
60
60
|
/**
|
|
61
|
-
* What follows the colon says which build to move to. `
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
* commit alone is enough to find it.
|
|
61
|
+
* What follows the colon says which development build to move to. `develop`
|
|
62
|
+
* selects the channel head; a positive decimal or a full numbered preview names
|
|
63
|
+
* one immutable publication.
|
|
65
64
|
*/
|
|
66
65
|
function parseColonUpdate(suffix, rest) {
|
|
67
66
|
if (rest.length > 0)
|
|
68
67
|
return { kind: "error", message: PRODUCT_TEXT.diagnostic("update takes what to move to after the colon, and nothing else.") };
|
|
69
|
-
if (suffix === "next")
|
|
68
|
+
if (suffix === "next") {
|
|
69
|
+
return { kind: "error", message: PRODUCT_TEXT.diagnostic(`renamed its development channel; run ${PRODUCT_TEXT.commandName} update:develop.`) };
|
|
70
|
+
}
|
|
71
|
+
if (suffix === "develop")
|
|
70
72
|
return { kind: "update", channel: "next" };
|
|
71
73
|
if (suffix.length === 0)
|
|
72
|
-
return { kind: "error", message: PRODUCT_TEXT.diagnostic(`update: needs a preview after the colon, as in ${PRODUCT_TEXT.commandName} update:
|
|
73
|
-
if (!/^[
|
|
74
|
-
return { kind: "error", message: PRODUCT_TEXT.diagnostic(`received an unusable preview: ${suffix}`) };
|
|
74
|
+
return { kind: "error", message: PRODUCT_TEXT.diagnostic(`update: needs a preview after the colon, as in ${PRODUCT_TEXT.commandName} update:develop.`) };
|
|
75
|
+
if (!/^[1-9]\d*$/.test(suffix) && !/^\d+\.\d+\.\d+-dev\.[1-9]\d*$/.test(suffix)) {
|
|
76
|
+
return { kind: "error", message: PRODUCT_TEXT.diagnostic(`received an unusable numbered preview: ${suffix}`) };
|
|
75
77
|
}
|
|
76
78
|
return { kind: "update", channel: "next", target: suffix };
|
|
77
79
|
}
|
|
@@ -94,8 +96,8 @@ function parseUpdate(rest) {
|
|
|
94
96
|
message: PRODUCT_TEXT.diagnostic(`pins the Pi version it was certified against; run ${PRODUCT_TEXT.commandName} update to move ${PRODUCT_TEXT.displayName} itself.`),
|
|
95
97
|
};
|
|
96
98
|
}
|
|
97
|
-
if (target === "next" || target === "stable") {
|
|
98
|
-
const form = target === "
|
|
99
|
+
if (target === "next" || target === "develop" || target === "stable") {
|
|
100
|
+
const form = target === "stable" ? `${PRODUCT_TEXT.commandName} update` : `${PRODUCT_TEXT.commandName} update:develop`;
|
|
99
101
|
return { kind: "error", message: PRODUCT_TEXT.diagnostic(`selects a release channel with a colon; run ${form}.`) };
|
|
100
102
|
}
|
|
101
103
|
if (target === "--models")
|
|
@@ -11,6 +11,12 @@ export interface PackageCommandRequest {
|
|
|
11
11
|
readonly verb: PackageCommandVerb;
|
|
12
12
|
readonly source: string | null;
|
|
13
13
|
}
|
|
14
|
+
export interface PackageCommandStyle {
|
|
15
|
+
readonly dim: (message: string) => string;
|
|
16
|
+
readonly bold: (message: string) => string;
|
|
17
|
+
readonly green: (message: string) => string;
|
|
18
|
+
readonly red: (message: string) => string;
|
|
19
|
+
}
|
|
14
20
|
export interface PackageCommandEnvironment {
|
|
15
21
|
readonly createPort: (input: AgentPackagesPortInput) => AgentPackagesPort;
|
|
16
22
|
readonly cwd?: string;
|
|
@@ -18,6 +24,8 @@ export interface PackageCommandEnvironment {
|
|
|
18
24
|
readonly stdout?: (message: string) => void;
|
|
19
25
|
readonly stderr?: (message: string) => void;
|
|
20
26
|
readonly initializeProfile?: typeof initializeProductProfile;
|
|
27
|
+
/** Defaults to Chalk's terminal-aware styles; injectable for transcript tests. */
|
|
28
|
+
readonly style?: PackageCommandStyle;
|
|
21
29
|
}
|
|
22
30
|
export declare function runPackageCommand(request: PackageCommandRequest, environment: PackageCommandEnvironment): Promise<number>;
|
|
23
|
-
export declare function renderPackageOutcome(outcome: AgentPackageOutcome, profileRoot: string): string;
|
|
31
|
+
export declare function renderPackageOutcome(outcome: AgentPackageOutcome, profileRoot: string, style?: PackageCommandStyle): string;
|
package/dist/src/cli/packages.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
1
2
|
import { configurationRootForProfile, initializeProductProfile, resolveLaunchProfilePaths } from "../features/launch/index.js";
|
|
2
3
|
import { PRODUCT_TEXT } from "../product-identity.js";
|
|
3
4
|
export async function runPackageCommand(request, environment) {
|
|
@@ -5,6 +6,7 @@ export async function runPackageCommand(request, environment) {
|
|
|
5
6
|
const stderr = environment.stderr ?? (message => process.stderr.write(message));
|
|
6
7
|
const cwd = environment.cwd ?? process.cwd();
|
|
7
8
|
const processEnvironment = environment.environment ?? process.env;
|
|
9
|
+
const style = environment.style ?? chalk;
|
|
8
10
|
const paths = resolveLaunchProfilePaths({ environment: processEnvironment });
|
|
9
11
|
const profileRoot = configurationRootForProfile("a1", paths);
|
|
10
12
|
if (profileRoot === null)
|
|
@@ -19,10 +21,10 @@ export async function runPackageCommand(request, environment) {
|
|
|
19
21
|
const port = environment.createPort({
|
|
20
22
|
profileRoot,
|
|
21
23
|
cwd,
|
|
22
|
-
onProgress: progress => stdout(`${progress.message}\n`),
|
|
24
|
+
onProgress: progress => stdout(`${style.dim(progress.message)}\n`),
|
|
23
25
|
});
|
|
24
26
|
const outcome = await runVerb(port, request);
|
|
25
|
-
const rendered = renderPackageOutcome(outcome, profileRoot);
|
|
27
|
+
const rendered = renderPackageOutcome(outcome, profileRoot, style);
|
|
26
28
|
(outcome.status === "completed" ? stdout : stderr)(rendered);
|
|
27
29
|
return outcome.status === "completed" ? 0 : 1;
|
|
28
30
|
}
|
|
@@ -37,38 +39,40 @@ async function runVerb(port, request) {
|
|
|
37
39
|
throw new Error(PRODUCT_TEXT.diagnostic(`requires a source for ${request.verb}`));
|
|
38
40
|
return request.verb === "install" ? await port.install(request.source) : await port.remove(request.source);
|
|
39
41
|
}
|
|
40
|
-
export function renderPackageOutcome(outcome, profileRoot) {
|
|
41
|
-
|
|
42
|
+
export function renderPackageOutcome(outcome, profileRoot, style = chalk) {
|
|
43
|
+
// Model refresh remains an A1 top-level command. The `a1 pi` compatibility
|
|
44
|
+
// transcript applies to package operations only.
|
|
45
|
+
if (outcome.operation === "refresh-models") {
|
|
46
|
+
if (outcome.status === "failed") {
|
|
47
|
+
return `${PRODUCT_TEXT.diagnostic(`could not ${describeOperation(outcome.operation)}: ${outcome.detail ?? "unknown failure"}`)}\n`;
|
|
48
|
+
}
|
|
49
|
+
return `${PRODUCT_TEXT.displayName} refreshed the model catalogs in ${profileRoot}.\n`;
|
|
50
|
+
}
|
|
42
51
|
if (outcome.status === "failed") {
|
|
43
|
-
return `${
|
|
52
|
+
return `${style.red(`Error: ${outcome.detail ?? "Unknown package command error"}`)}\n`;
|
|
44
53
|
}
|
|
45
54
|
if (outcome.status === "not-found") {
|
|
46
|
-
return `${
|
|
55
|
+
return `${style.red(`No matching package found for ${outcome.source ?? "that source"}`)}\n`;
|
|
47
56
|
}
|
|
48
57
|
switch (outcome.operation) {
|
|
49
58
|
case "install":
|
|
50
|
-
return `${
|
|
51
|
-
+ `Restart ${PRODUCT_TEXT.commandName} for a running session to load it.\n`;
|
|
59
|
+
return `${style.green(`Installed ${outcome.source}`)}\n`;
|
|
52
60
|
case "remove":
|
|
53
|
-
return `${
|
|
61
|
+
return `${style.green(`Removed ${outcome.source}`)}\n`;
|
|
54
62
|
case "update":
|
|
55
|
-
return outcome.source === null
|
|
56
|
-
? `${name} updated the packages in ${profileRoot}.\n`
|
|
57
|
-
: `${name} updated ${outcome.source}.\n`;
|
|
58
|
-
case "refresh-models":
|
|
59
|
-
return `${name} refreshed the model catalogs in ${profileRoot}.\n`;
|
|
63
|
+
return `${style.green(outcome.source === null ? "Updated packages" : `Updated ${outcome.source}`)}\n`;
|
|
60
64
|
case "list":
|
|
61
|
-
return renderPackageList(outcome,
|
|
65
|
+
return renderPackageList(outcome, style);
|
|
62
66
|
}
|
|
63
67
|
}
|
|
64
|
-
function renderPackageList(outcome,
|
|
68
|
+
function renderPackageList(outcome, style) {
|
|
65
69
|
if (outcome.packages.length === 0)
|
|
66
|
-
return `${
|
|
67
|
-
const lines = [
|
|
70
|
+
return `${style.dim("No packages installed.")}\n`;
|
|
71
|
+
const lines = [style.bold("User packages:")];
|
|
68
72
|
for (const entry of outcome.packages) {
|
|
69
|
-
lines.push(` ${entry.source}${entry.filtered ? " (
|
|
73
|
+
lines.push(` ${entry.source}${entry.filtered ? " (filtered)" : ""}`);
|
|
70
74
|
if (entry.installedPath !== null)
|
|
71
|
-
lines.push(` ${entry.installedPath}`);
|
|
75
|
+
lines.push(style.dim(` ${entry.installedPath}`));
|
|
72
76
|
}
|
|
73
77
|
return `${lines.join("\n")}\n`;
|
|
74
78
|
}
|
|
@@ -21,7 +21,7 @@ export async function runVersionStats(options) {
|
|
|
21
21
|
return 1;
|
|
22
22
|
}
|
|
23
23
|
const remote = await queryDistTags(runner);
|
|
24
|
-
output.stdout(`Installed: ${installed}\nRelease: ${remote.release ?? "unavailable"}\
|
|
24
|
+
output.stdout(`Installed: ${installed}\nRelease: ${remote.release ?? "unavailable"}\nDevelop: ${remote.develop ?? "unavailable"}\n`);
|
|
25
25
|
if (remote.error)
|
|
26
26
|
output.stderr(`${PRODUCT_TEXT.diagnostic(`could not resolve npm dist-tags: ${remote.error}`)}\n`);
|
|
27
27
|
return 0;
|
|
@@ -42,15 +42,15 @@ async function queryDistTags(runner) {
|
|
|
42
42
|
throw new TypeError("npm returned a non-object dist-tags value");
|
|
43
43
|
const tags = metadata;
|
|
44
44
|
const release = parseVersion(tags.latest, "npm latest");
|
|
45
|
-
const
|
|
46
|
-
return { release,
|
|
45
|
+
const develop = tags.next === undefined ? null : parseVersion(tags.next, "npm development channel");
|
|
46
|
+
return { release, develop, error: null };
|
|
47
47
|
}
|
|
48
48
|
catch (error) {
|
|
49
49
|
return unavailable(message(error));
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
function unavailable(error) {
|
|
53
|
-
return { release: null,
|
|
53
|
+
return { release: null, develop: null, error };
|
|
54
54
|
}
|
|
55
55
|
function createVersionProcessRunner() {
|
|
56
56
|
return async (command, arguments_) => await new Promise((resolvePromise, rejectPromise) => {
|
|
@@ -1476,14 +1476,16 @@ export class PiEngineAdapter {
|
|
|
1476
1476
|
this.#upsertMessageBlock(event.message, "live");
|
|
1477
1477
|
return;
|
|
1478
1478
|
case "message_update": {
|
|
1479
|
-
const
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1479
|
+
const delta = isRecord(event.assistantMessageEvent) && typeof event.assistantMessageEvent.delta === "string"
|
|
1480
|
+
? event.assistantMessageEvent.delta
|
|
1481
|
+
: undefined;
|
|
1482
|
+
// The delta is folded in before the block is stored, so a chunk is one update to
|
|
1483
|
+
// one block rather than a store without the delta followed by a store with it.
|
|
1484
|
+
const blocks = this.#messageBlocks(event.message, "live", this.#transcript.length);
|
|
1485
|
+
for (const [index, block] of blocks.entries()) {
|
|
1486
|
+
this.#upsertTranscriptBlock(index === 0 && delta !== undefined && !block.text.endsWith(delta)
|
|
1487
|
+
? { ...block, text: `${block.text}${delta}` }
|
|
1488
|
+
: block);
|
|
1487
1489
|
}
|
|
1488
1490
|
return;
|
|
1489
1491
|
}
|
|
@@ -1638,7 +1640,13 @@ export class PiEngineAdapter {
|
|
|
1638
1640
|
}
|
|
1639
1641
|
}
|
|
1640
1642
|
}
|
|
1641
|
-
|
|
1643
|
+
// An authoritative rebuild restates most of what is already there. Reusing the block
|
|
1644
|
+
// that already says it keeps its revision, and with it the rows the shell rendered for
|
|
1645
|
+
// it — otherwise every turn that ends re-renders the whole session.
|
|
1646
|
+
this.#setTranscript(blocks.map(block => {
|
|
1647
|
+
const existing = this.#transcriptBlock(block.id);
|
|
1648
|
+
return existing !== undefined && sameBlockContent(existing, block) ? existing : block;
|
|
1649
|
+
}));
|
|
1642
1650
|
}
|
|
1643
1651
|
#upsertMessageBlock(message, status) {
|
|
1644
1652
|
const blocks = this.#messageBlocks(message, status, this.#transcript.length);
|
|
@@ -1815,8 +1823,14 @@ export class PiEngineAdapter {
|
|
|
1815
1823
|
}
|
|
1816
1824
|
#upsertTranscriptBlock(block) {
|
|
1817
1825
|
const index = this.#transcriptIndex.get(block.id);
|
|
1818
|
-
if (index !== undefined)
|
|
1826
|
+
if (index !== undefined) {
|
|
1827
|
+
const existing = this.#transcript[index];
|
|
1828
|
+
// Nothing to tell the shell about a block that repeats itself, and keeping the
|
|
1829
|
+
// revision keeps the rows it already rendered.
|
|
1830
|
+
if (existing !== undefined && sameBlockContent(existing, block))
|
|
1831
|
+
return;
|
|
1819
1832
|
this.#transcript[index] = block;
|
|
1833
|
+
}
|
|
1820
1834
|
else {
|
|
1821
1835
|
this.#transcriptIndex.set(block.id, this.#transcript.length);
|
|
1822
1836
|
this.#transcript.push(block);
|
|
@@ -2388,6 +2402,36 @@ function compactResourceLabel(path) {
|
|
|
2388
2402
|
const segments = path.replaceAll("\\", "/").split("/").filter(Boolean);
|
|
2389
2403
|
return segments.at(-1) ?? path;
|
|
2390
2404
|
}
|
|
2405
|
+
/**
|
|
2406
|
+
* Whether two blocks say the same thing. A block that says what it already said is not a
|
|
2407
|
+
* new revision: the shell renders a block once per revision, so bumping one it did not
|
|
2408
|
+
* need re-renders it for nothing.
|
|
2409
|
+
*/
|
|
2410
|
+
function sameBlockContent(left, right) {
|
|
2411
|
+
return left.kind === right.kind
|
|
2412
|
+
&& left.status === right.status
|
|
2413
|
+
&& left.title === right.title
|
|
2414
|
+
&& left.text === right.text
|
|
2415
|
+
&& sameValue(left.payload, right.payload);
|
|
2416
|
+
}
|
|
2417
|
+
function sameValue(left, right) {
|
|
2418
|
+
if (left === right)
|
|
2419
|
+
return true;
|
|
2420
|
+
if (typeof left !== typeof right || left === null || right === null)
|
|
2421
|
+
return false;
|
|
2422
|
+
if (Array.isArray(left) || Array.isArray(right)) {
|
|
2423
|
+
if (!Array.isArray(left) || !Array.isArray(right) || left.length !== right.length)
|
|
2424
|
+
return false;
|
|
2425
|
+
return left.every((value, index) => sameValue(value, right[index]));
|
|
2426
|
+
}
|
|
2427
|
+
if (typeof left !== "object")
|
|
2428
|
+
return false;
|
|
2429
|
+
const leftKeys = Object.keys(left);
|
|
2430
|
+
const rightRecord = right;
|
|
2431
|
+
if (leftKeys.length !== Object.keys(rightRecord).length)
|
|
2432
|
+
return false;
|
|
2433
|
+
return leftKeys.every(key => Object.hasOwn(rightRecord, key) && sameValue(left[key], rightRecord[key]));
|
|
2434
|
+
}
|
|
2391
2435
|
function textFromContent(content) {
|
|
2392
2436
|
if (typeof content === "string")
|
|
2393
2437
|
return content;
|
|
@@ -39,6 +39,12 @@ export declare class OwnedUiSessionShellRoot implements PiTuiComponentPort {
|
|
|
39
39
|
readonly onDequeue?: () => void;
|
|
40
40
|
}, startup?: PiShellHeaderOptions, agentDir?: string, extensionRenderers?: PiShellExtensionRendererResolver);
|
|
41
41
|
update(view: OwnedUiSessionViewModel): void;
|
|
42
|
+
/**
|
|
43
|
+
* Applies one block: its component is created or updated in place and the order grows
|
|
44
|
+
* only when the block is new. A streamed chunk costs one component update rather than a
|
|
45
|
+
* walk of the whole transcript.
|
|
46
|
+
*/
|
|
47
|
+
applyTranscriptBlock(block: OwnedUiSessionViewModel["transcript"][number]): void;
|
|
42
48
|
render(width: number): readonly string[];
|
|
43
49
|
layoutRoot(): PiTuiLayoutNode;
|
|
44
50
|
transcriptComponent(id: string): PiShellTranscriptComponentPort | undefined;
|
|
@@ -71,6 +71,25 @@ export class OwnedUiSessionShellRoot {
|
|
|
71
71
|
this.editor.setThinkingLevel(view.thinkingLevel);
|
|
72
72
|
this.invalidate();
|
|
73
73
|
}
|
|
74
|
+
/**
|
|
75
|
+
* Applies one block: its component is created or updated in place and the order grows
|
|
76
|
+
* only when the block is new. A streamed chunk costs one component update rather than a
|
|
77
|
+
* walk of the whole transcript.
|
|
78
|
+
*/
|
|
79
|
+
applyTranscriptBlock(block) {
|
|
80
|
+
this.#blocksById.set(block.id, block);
|
|
81
|
+
const component = this.#transcript.get(block.id);
|
|
82
|
+
if (component === undefined) {
|
|
83
|
+
const created = createPiShellTranscriptComponent(block, this.#cwd, this.#extensionRenderers);
|
|
84
|
+
created.setExpanded(this.#toolsExpanded);
|
|
85
|
+
this.#transcript.set(block.id, created);
|
|
86
|
+
this.#transcriptOrder.push(block.id);
|
|
87
|
+
}
|
|
88
|
+
else if (component.revision !== block.revision) {
|
|
89
|
+
component.update(block);
|
|
90
|
+
}
|
|
91
|
+
this.invalidate();
|
|
92
|
+
}
|
|
74
93
|
render(width) {
|
|
75
94
|
const queued = this.#view.editor.queuedSubmissions.length === 0 ? [] : this.#queued.render(width);
|
|
76
95
|
return [
|
|
@@ -794,9 +813,12 @@ export class OwnedUiSessionShell {
|
|
|
794
813
|
});
|
|
795
814
|
this.root.editor.setAutocompleteCommands(this.backend.workflowAutocompleteCommands());
|
|
796
815
|
this.#unsubscribe = this.backend.onEvent(event => {
|
|
797
|
-
//
|
|
798
|
-
//
|
|
799
|
-
|
|
816
|
+
// A streamed chunk names one block, and touching only that block is what keeps the
|
|
817
|
+
// cost of a chunk the same in a long session as in a new one. Everything else
|
|
818
|
+
// resynchronizes the view, which is cheap next to re-reading the transcript.
|
|
819
|
+
const view = event.type === "transcript-block" && this.#sessionGeneration === this.backend.sessionGeneration
|
|
820
|
+
? this.#syncBlock(event.block)
|
|
821
|
+
: this.#syncView();
|
|
800
822
|
if (view.lifecycle === "ready" && this.#compactionQueue.length > 0)
|
|
801
823
|
void this.#flushCompactionQueue();
|
|
802
824
|
if (event.type === "session-lifecycle" && event.lifecycle === "stopped")
|
|
@@ -1415,6 +1437,18 @@ export class OwnedUiSessionShell {
|
|
|
1415
1437
|
this.#extensionBridge.dispose();
|
|
1416
1438
|
await this.runtime.dispose();
|
|
1417
1439
|
}
|
|
1440
|
+
/**
|
|
1441
|
+
* Applies one transcript block without re-reading the session. The listeners still hear
|
|
1442
|
+
* the view they would have heard, so nothing downstream can tell the difference.
|
|
1443
|
+
*/
|
|
1444
|
+
#syncBlock(block) {
|
|
1445
|
+
this.root.applyTranscriptBlock(block);
|
|
1446
|
+
this.runtime.requestRender();
|
|
1447
|
+
const view = this.view();
|
|
1448
|
+
for (const listener of this.#listeners)
|
|
1449
|
+
listener(view);
|
|
1450
|
+
return view;
|
|
1451
|
+
}
|
|
1418
1452
|
#syncView() {
|
|
1419
1453
|
const view = this.view();
|
|
1420
1454
|
if (this.backend.sessionGeneration !== this.#sessionGeneration) {
|
|
@@ -33,7 +33,7 @@ export interface UpdatePerformanceEvidence {
|
|
|
33
33
|
export interface SelfUpdateOptions {
|
|
34
34
|
packageRoot: string;
|
|
35
35
|
channel?: UpdateChannel;
|
|
36
|
-
/** A specific preview to install, named by its
|
|
36
|
+
/** A specific preview to install, named by its development number or full version. */
|
|
37
37
|
target?: string;
|
|
38
38
|
environment?: NodeJS.ProcessEnv;
|
|
39
39
|
fileSystem?: UpdateFileSystem;
|
|
@@ -20,7 +20,7 @@ const UPDATE_DIST_TAGS = { stable: "latest", next: "next" };
|
|
|
20
20
|
* a release, and that is the word the repository, its tags, and its GitHub
|
|
21
21
|
* releases all use.
|
|
22
22
|
*/
|
|
23
|
-
const UPDATE_CHANNEL_LABELS = { stable: "release", next: "
|
|
23
|
+
const UPDATE_CHANNEL_LABELS = { stable: "release", next: "develop" };
|
|
24
24
|
const defaultFileSystem = {
|
|
25
25
|
async readFile(path) { return await readFile(path, "utf8"); },
|
|
26
26
|
realpath,
|
|
@@ -223,12 +223,13 @@ function createUpdateProgress(output, enabled) {
|
|
|
223
223
|
}
|
|
224
224
|
/** The newest version the channel points at, which is what an unqualified update takes. */
|
|
225
225
|
async function resolveChannelHead(runner, distTag, output) {
|
|
226
|
-
const
|
|
226
|
+
const publicChannel = distTag === "next" ? "development" : "release";
|
|
227
|
+
const lookup = await runNpm(runner, ["view", `${PRODUCT_PACKAGE}@${distTag}`, "version"], true, output, `query the npm ${publicChannel} channel`);
|
|
227
228
|
if (lookup.result === null)
|
|
228
229
|
return { version: null, exitCode: lookup.exitCode };
|
|
229
230
|
const version = validSemver(lookup.result.stdout.trim());
|
|
230
231
|
if (version === null) {
|
|
231
|
-
output.stderr(`${PRODUCT_TEXT.diagnostic(`received a malformed ${
|
|
232
|
+
output.stderr(`${PRODUCT_TEXT.diagnostic(`received a malformed ${publicChannel} channel version from npm: ${JSON.stringify(lookup.result.stdout.trim())}.`)}\n`);
|
|
232
233
|
return { version: null, exitCode: 1 };
|
|
233
234
|
}
|
|
234
235
|
return { version, exitCode: 0 };
|
|
@@ -236,14 +237,10 @@ async function resolveChannelHead(runner, distTag, output) {
|
|
|
236
237
|
/**
|
|
237
238
|
* Resolve a preview the caller named.
|
|
238
239
|
*
|
|
239
|
-
* A preview is published as `<version>-dev.<
|
|
240
|
-
*
|
|
241
|
-
*
|
|
242
|
-
*
|
|
243
|
-
*
|
|
244
|
-
* The published list is the authority: naming a commit that was never published,
|
|
245
|
-
* or one published more than once under different versions, is an error rather
|
|
246
|
-
* than a guess.
|
|
240
|
+
* A preview is published as `<version>-dev.<pull-request-number>`, so its decimal
|
|
241
|
+
* development number is enough to identify it. A full version is accepted too.
|
|
242
|
+
* The published list remains authoritative: nothing is constructed from the
|
|
243
|
+
* installed package's base version.
|
|
247
244
|
*/
|
|
248
245
|
async function resolveRequestedPreview(runner, requested, output) {
|
|
249
246
|
const lookup = await runNpm(runner, ["view", PRODUCT_PACKAGE, "versions", "--json"], true, output, "list the published versions");
|
|
@@ -261,8 +258,7 @@ async function resolveRequestedPreview(runner, requested, output) {
|
|
|
261
258
|
const exact = versions.find(version => version === requested);
|
|
262
259
|
if (exact !== undefined) {
|
|
263
260
|
// Naming a release here would install it through the preview path, which is a
|
|
264
|
-
// different command with a different meaning.
|
|
265
|
-
// one, so only the fuller spelling of a preview reaches this.
|
|
261
|
+
// different command with a different meaning.
|
|
266
262
|
if (!exact.includes("-dev.")) {
|
|
267
263
|
output.stderr(`${PRODUCT_TEXT.diagnostic(`${exact} is a release, not a preview; run ${PRODUCT_TEXT.commandName} update to move to the current release.`)}\n`);
|
|
268
264
|
return { version: null, exitCode: 1 };
|
|
@@ -71,7 +71,7 @@ Presentation acceptance is the reader comparing `a1 pi` with pinned Pi. `node sc
|
|
|
71
71
|
|
|
72
72
|
## Publication
|
|
73
73
|
|
|
74
|
-
One workflow publishes both channels: `.github/workflows/release.yml
|
|
74
|
+
One workflow publishes both channels: `.github/workflows/release.yml`. Pushes do not publish. Nightly development verification runs at `03:17 UTC`; `npm run develop` explicitly requests a numbered preview and `npm run release` explicitly requests stable publication after its version pull request merges. A preview is stamped as `-dev.<merged pull-request number>` and uses npm `next` only as an internal dist-tag. New candidates pack once and are validated on Windows, Linux, and macOS; a repeated nightly verifies the exact immutable registry tarball. All publication uses provenance from the `npm-publish` environment, a preview never changes `latest`, and the stable tag, GitHub Release, and `master` are written only after npm has the package. One global non-cancelling concurrency group serializes the final registry check.
|
|
75
75
|
|
|
76
76
|
`docs/ci-release-runbook.md` is the operational reference.
|
|
77
77
|
|
|
@@ -5,107 +5,104 @@ GitHub Actions is the only automation platform. Three refs are protected:
|
|
|
5
5
|
| Ref | Protection | Produced by |
|
|
6
6
|
| --- | --- | --- |
|
|
7
7
|
| `develop` | `Development validation required` on every pull request | `.github/workflows/ci.yml` |
|
|
8
|
-
| `master` | cannot be deleted or force-updated |
|
|
9
|
-
| `refs/tags/v*` | cannot be deleted or moved |
|
|
8
|
+
| `master` | cannot be deleted or force-updated | stable publication |
|
|
9
|
+
| `refs/tags/v*` | cannot be deleted or moved | stable publication |
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
`.github/workflows/release.yml` is the only publisher. A push publishes neither
|
|
12
|
+
channel. The workflow starts at `03:17 UTC` for nightly development verification,
|
|
13
|
+
or by explicit dispatch from `npm run develop` or `npm run release`.
|
|
13
14
|
|
|
14
|
-
`develop` is where work lands. `master` records what
|
|
15
|
-
|
|
16
|
-
writes it. There is no promotion to arrange and nothing to keep in sync — `master`
|
|
17
|
-
is an effect of publishing, not a step before it.
|
|
15
|
+
`develop` is where work lands. `master` records what npm `latest` serves and is an
|
|
16
|
+
effect of stable publication, not a trigger.
|
|
18
17
|
|
|
19
|
-
##
|
|
18
|
+
## Validation by trigger
|
|
20
19
|
|
|
21
|
-
|
|
|
20
|
+
| Trigger | Validation and outcome |
|
|
22
21
|
| --- | --- |
|
|
23
|
-
|
|
|
24
|
-
|
|
|
25
|
-
|
|
|
26
|
-
|
|
|
22
|
+
| Pull request into `develop` | Fast required validation; docs/spec-only changes use strict OpenSpec validation |
|
|
23
|
+
| `npm run develop` | Preview package gates on Windows, Linux, and macOS; an existing numbered preview is an early successful no-op |
|
|
24
|
+
| Nightly at `03:17 UTC` | Complete non-physical suite on Windows, Linux, and macOS, every night |
|
|
25
|
+
| `npm run release -- ...` | Complete exact-byte stable gates, then npm `latest`, tag, GitHub Release, and `master` |
|
|
26
|
+
| `.github/workflows/full-regression.yml` | Additional on-demand complete regression without publication authority |
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
demand.
|
|
28
|
+
## Numbered development previews
|
|
30
29
|
|
|
31
|
-
|
|
30
|
+
A merge or push to `develop` does not publish by itself. To request a deliberate
|
|
31
|
+
preview from any authorized checkout:
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
```sh
|
|
34
|
+
npm run develop
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
The command fetches authoritative `origin/develop`, resolves the unique merged pull
|
|
38
|
+
request associated with that exact commit through GitHub, and derives
|
|
39
|
+
`<major.minor.patch>-dev.<pull-request number>`. Thus GitHub's `develop (#107)`
|
|
40
|
+
source produces `0.1.8-dev.107`. It first checks npm; if the immutable version
|
|
41
|
+
already exists it reports that version without dispatching package work. Otherwise
|
|
42
|
+
it dispatches GitHub Actions, waits, and reports the published version. It never
|
|
43
|
+
builds or uploads npm bytes from the workstation.
|
|
44
|
+
|
|
45
|
+
Nightly resolves the same current `origin/develop` source. It always runs complete
|
|
46
|
+
verification even if source has not changed. For a new number it packs once and
|
|
47
|
+
runs the suite against that final-version tarball before publication. For an
|
|
48
|
+
existing number it downloads the exact npm tarball and runs package/update gates
|
|
49
|
+
against those registry bytes; publication is then a successful no-op.
|
|
50
|
+
|
|
51
|
+
Manual and nightly runs share one non-cancelling concurrency group. Their final
|
|
52
|
+
registry check is serialized, so overlapping requests can produce only one publish
|
|
53
|
+
and one successful existing-version no-op. A development publication moves npm's
|
|
54
|
+
internal `next` dist-tag and never moves `latest`.
|
|
55
|
+
|
|
56
|
+
Users install previews with public `develop` terminology:
|
|
35
57
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
installed: `a1 update:<commit>` resolves it against the published list and
|
|
42
|
-
refuses a commit that was never published. `develop` therefore carries one open prerelease version between
|
|
43
|
-
releases, and no commit is ever spent on a preview.
|
|
58
|
+
```sh
|
|
59
|
+
a1 update:develop # current development channel
|
|
60
|
+
a1 update:107 # numbered preview
|
|
61
|
+
a1 update:0.1.8-dev.107 # exact full preview version
|
|
62
|
+
```
|
|
44
63
|
|
|
45
|
-
|
|
46
|
-
|
|
64
|
+
`a1 update:next` is removed and redirects to `a1 update:develop` without registry
|
|
65
|
+
or runtime work.
|
|
47
66
|
|
|
48
67
|
## Cutting a stable release
|
|
49
68
|
|
|
50
|
-
|
|
69
|
+
From a clean `develop` matching its remote:
|
|
51
70
|
|
|
52
71
|
```sh
|
|
53
72
|
npm run release -- patch # or minor, major, or an exact x.y.z
|
|
54
73
|
```
|
|
55
74
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
Landing the stable version is what publishes. The same pipeline sees a commit
|
|
61
|
-
declaring a stable version and runs its stable form: build the process guardian on
|
|
62
|
-
all three platforms, pack once, run the complete suite against those exact bytes on
|
|
63
|
-
all three platforms, publish to npm `latest` with provenance from the
|
|
64
|
-
`npm-publish` environment, and only then write the tag `vx.y.z`, record the GitHub
|
|
65
|
-
Release, and fast-forward `master`.
|
|
75
|
+
The command lands `x.y.z` through its version pull request, explicitly dispatches
|
|
76
|
+
stable publication for that exact current `origin/develop` commit, and waits. Only
|
|
77
|
+
after success does it land `x.y.(z+1)-dev`.
|
|
66
78
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
79
|
+
Stable publication builds the process guardian on all supported platforms, packs
|
|
80
|
+
once, runs the complete suite against those exact bytes on Windows, Linux, and
|
|
81
|
+
macOS, publishes to npm `latest` with provenance from the `npm-publish`
|
|
82
|
+
environment, and then writes `vx.y.z`, records the GitHub Release, and fast-forwards
|
|
83
|
+
`master`. A push of the stable version does not publish it.
|
|
70
84
|
|
|
71
85
|
Rules that do not bend:
|
|
72
86
|
|
|
73
|
-
- **Never upload locally rebuilt bytes.** The publisher uploads the artifact the
|
|
74
|
-
|
|
75
|
-
- **Never
|
|
76
|
-
job has no checkout of dependencies, no build, and no pack step.
|
|
77
|
-
- **Never move a release tag.** A wrong tag is superseded by the next version, not
|
|
78
|
-
repointed. The tag is written by the publication itself, so it exists only for
|
|
79
|
-
versions that shipped.
|
|
87
|
+
- **Never upload locally rebuilt bytes.** The publisher uploads the artifact the validation ran against and checks its digest before and after.
|
|
88
|
+
- **Never route around validation by rebuilding inside a publisher.** The publish job receives the packed artifact and does not install dependencies, build, or pack.
|
|
89
|
+
- **Never move a release tag.** A wrong tag is superseded by the next version, not repointed.
|
|
80
90
|
|
|
81
91
|
## When something fails
|
|
82
92
|
|
|
83
|
-
- **PR validation fails:** fix the code and push
|
|
84
|
-
- **
|
|
85
|
-
|
|
86
|
-
- **Stable
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
approving reviews to zero. It does not require the branch to be up to date: once a
|
|
100
|
-
PR is green it merges even if unrelated work landed first, with no re-validation
|
|
101
|
-
loop.
|
|
102
|
-
|
|
103
|
-
The `master` and tag rulesets carry no checks at all. Both only ever receive a commit
|
|
104
|
-
that has already been validated and published, so what matters about them is that
|
|
105
|
-
neither can be rewritten. Requiring a pull request on `master` would stop the release
|
|
106
|
-
from recording itself there.
|
|
107
|
-
|
|
108
|
-
Do not add a direct-push bypass as a shortcut, and never weaken the force-push or
|
|
109
|
-
deletion protection. Ruleset mutation is a separate administrative operation: run
|
|
110
|
-
`node scripts/check-github-rulesets.mjs` to see the diff, and apply only when a
|
|
111
|
-
maintainer explicitly confirms with `--apply --confirm apply-a1-ci-rulesets`.
|
|
93
|
+
- **PR validation fails:** fix the code and push; do not mark a failed tier optional.
|
|
94
|
+
- **Development publication fails:** fix the cause and rerun `npm run develop`; an npm version that already exists is never overwritten.
|
|
95
|
+
- **Stable publication fails before npm accepts bytes:** no tag, release, or moved branch exists. Fix the cause and release the next version.
|
|
96
|
+
- **Stable publication is uncertain after npm accepted bytes:** stop and inspect registry version, digest, tag, and release. Never republish immutable bytes.
|
|
97
|
+
|
|
98
|
+
## Branch protection rationale
|
|
99
|
+
|
|
100
|
+
One person maintains this repository, and a PR author cannot approve their own PR.
|
|
101
|
+
The `develop` ruleset therefore requires a pull request, a green required check,
|
|
102
|
+
and resolved review threads, but zero approving reviews. `master` and release tags
|
|
103
|
+
are written only after publication and are protected from force-push, movement, and
|
|
104
|
+
deletion.
|
|
105
|
+
|
|
106
|
+
Do not add direct-push bypasses. Ruleset mutation remains a separate administrative
|
|
107
|
+
operation: inspect with `node scripts/check-github-rulesets.mjs`, and apply only
|
|
108
|
+
with explicit maintainer confirmation.
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
| `a1 pi` | Untouched vanilla Pi fallback and comparison oracle | ordinary `~/.pi/agent` |
|
|
9
9
|
| `a1 sandbox` | Unchanged isolated vanilla Pi profile for experiments | `~/.a1/sandbox` |
|
|
10
10
|
|
|
11
|
-
`a1 pi` and `a1 sandbox` are development instruments: one compares A1 against pinned Pi, the other tries resources against an isolated profile. Prerelease builds — what `a1 update:
|
|
11
|
+
`a1 pi` and `a1 sandbox` are development instruments: one compares A1 against pinned Pi, the other tries resources against an isolated profile. Prerelease builds — what `a1 update:develop` or `a1 update:<number>` installs — expose them. A release build does not, and does not recognize the words: what it exposes is bare `a1` plus the maintenance and package commands. Working in this repository is unaffected, because `npm start:pi` and `npm run start:sandbox` prepare the profile and launch directly rather than through the command line.
|
|
12
12
|
|
|
13
13
|
There is no `a1 agent` command. The former `a1 ui` subcommand is removed. Bare `a1` is the owned agent product surface and remains the entry point when multi-agent UX is introduced.
|
|
14
14
|
|
|
@@ -50,4 +50,4 @@ Report failures with direct-versus-A1 behavior, platform/terminal versions, exac
|
|
|
50
50
|
|
|
51
51
|
For recovery, use `a1 pi`; do not use the removed `a1 ui` command. `a1 sandbox` remains profile isolation rather than a security boundary.
|
|
52
52
|
|
|
53
|
-
Manual acceptance can authorize an exact uncertified
|
|
53
|
+
Manual acceptance can authorize an exact uncertified development preview after non-desktop gates pass. It does not certify stable terminal parity or platform support.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@timurproko/a1",
|
|
3
|
-
"version": "0.1.8-dev.
|
|
3
|
+
"version": "0.1.8-dev.112",
|
|
4
4
|
"description": "Standalone terminal workspace for supervised native and managed agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "npm@11.13.0",
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
"check:deprecated": "node scripts/check-deprecated-dependencies.mjs",
|
|
34
34
|
"branches:prune": "node scripts/prune-merged-branches.mjs",
|
|
35
35
|
"check": "npm run test:fast",
|
|
36
|
+
"develop": "node scripts/develop.mjs",
|
|
36
37
|
"release": "node scripts/release.mjs",
|
|
37
38
|
"test": "npm run test:fast",
|
|
38
39
|
"test:fast": "node scripts/run-validation-tier.mjs typecheck fast",
|
|
@@ -57,6 +58,7 @@
|
|
|
57
58
|
"dependencies": {
|
|
58
59
|
"@earendil-works/pi-coding-agent": "0.84.2",
|
|
59
60
|
"@earendil-works/pi-tui": "0.84.2",
|
|
61
|
+
"chalk": "5.6.2",
|
|
60
62
|
"cross-spawn": "7.0.6",
|
|
61
63
|
"grok-mermaid": "0.2.2",
|
|
62
64
|
"semver": "7.8.5"
|