axstack 0.20.30 → 0.21.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/README.md +24 -23
- package/bin/axstack.js +18 -5
- package/docs/installation.md +101 -46
- package/docs/workflows.md +179 -117
- package/package.json +3 -3
- package/profiles/presets/claude-only.json +46 -46
- package/profiles/presets/codex-only.json +50 -50
- package/profiles/presets/mixed.json +59 -59
- package/skills/axstack/references/automations.md +127 -137
- package/skills/axstack/references/autopilot.md +121 -0
- package/skills/axstack/references/candidate-publication.md +13 -8
- package/skills/axstack/references/contracts.md +10 -4
- package/skills/axstack/references/diligence.md +3 -1
- package/skills/axstack/references/evidence-archive.md +38 -33
- package/skills/axstack/references/lifecycle.md +64 -50
- package/skills/axstack/references/review-manager-prompt.md +13 -11
- package/skills/axstack/references/role-roster.md +19 -9
- package/skills/axstack/references/routing.md +33 -18
- package/skills/axstack/references/run-record.md +36 -15
- package/skills/axstack/references/t3-runtime.md +234 -0
- package/skills/axstack/references/test-audit-weekly.md +62 -0
- package/skills/axstack/references/test-value.md +120 -0
- package/skills/axstack/references/ui-verification.md +5 -1
- package/skills/axstack/references/workspace-hygiene.md +102 -156
- package/skills/axstack/scripts/pr-digest.js +120 -0
- package/skills/axstack/scripts/resolve-models.js +102 -0
- package/skills/axstack-align/SKILL.md +25 -11
- package/skills/axstack-audit/SKILL.md +22 -5
- package/skills/axstack-audit/references/record.md +1 -1
- package/skills/axstack-cleanup/SKILL.md +69 -87
- package/skills/axstack-debug/SKILL.md +1 -1
- package/skills/axstack-explain/SKILL.md +1 -1
- package/skills/axstack-explain/references/visual-qa.md +2 -0
- package/skills/axstack-implement/SKILL.md +76 -26
- package/skills/axstack-improve/SKILL.md +24 -4
- package/skills/axstack-relay/SKILL.md +16 -7
- package/skills/axstack-research/SKILL.md +11 -4
- package/skills/axstack-review/SKILL.md +42 -32
- package/skills/axstack-spec/SKILL.md +23 -14
- package/skills/axstack-tickets/SKILL.md +13 -11
- package/skills/axstack-watch/SKILL.md +117 -34
- package/skills/axstack-watch/references/watch-runtime.md +61 -69
- package/src/capabilities.js +33 -69
- package/src/installer.js +9 -1
- package/src/instructions.js +9 -4
- package/src/roles.js +38 -10
- package/skills/axstack/references/orca-runtime.md +0 -183
- package/skills/axstack/scripts/trust-path.js +0 -123
|
@@ -1,183 +0,0 @@
|
|
|
1
|
-
# Orca runtime boundary
|
|
2
|
-
|
|
3
|
-
Read this immediately before using Orca for a role dispatch, handoff, delivery,
|
|
4
|
-
settlement, or recovery. Ordinary local reading and writing do not load it.
|
|
5
|
-
Axstack owns policy, role selection, and evidence; Orca owns Run, Task,
|
|
6
|
-
Dispatch, session, worktree, messaging, settlement, and scheduling state.
|
|
7
|
-
|
|
8
|
-
## Discover the runtime-owned guides
|
|
9
|
-
|
|
10
|
-
Resolve one Orca executable for the session and reuse it. Prefer
|
|
11
|
-
`ORCA_CLI_COMMAND` when set, then the checkout's `orca-dev` when
|
|
12
|
-
`ORCA_DEV_REPO_ROOT` is set, the Linux-safe `orca-ide` outside managed
|
|
13
|
-
terminals, and otherwise `orca`. If the selected executable fails, report that
|
|
14
|
-
exact gap; never switch binaries silently.
|
|
15
|
-
|
|
16
|
-
Load only the selected executable's version-matched guides needed by the
|
|
17
|
-
operation through `skills get orchestration --json`,
|
|
18
|
-
`skills get orca-cli --json`, and `skills get orca-linear --json`.
|
|
19
|
-
`orchestration` owns Run, Task,
|
|
20
|
-
Dispatch, messaging, supervision,
|
|
21
|
-
settlement, and recovery. `orca-cli` owns worktrees, terminals, automations,
|
|
22
|
-
handoffs, and artifact publication; load its named conditional reference at
|
|
23
|
-
the matching action gate. `orca-linear` owns Linear issue reads and writes.
|
|
24
|
-
Follow returned schemas and current command help rather than copying their
|
|
25
|
-
procedures into Axstack. Guide discovery does not prove runtime support for a
|
|
26
|
-
particular operation: preflight that operation and report an advertised gap.
|
|
27
|
-
Missing discovery never authorizes legacy runtime use, a silent integration or
|
|
28
|
-
store fallback, or an Axstack dispatcher, daemon, scheduler, database, or
|
|
29
|
-
escalation engine.
|
|
30
|
-
|
|
31
|
-
Orca artifacts publish public-by-link output. They are not private evidence
|
|
32
|
-
storage and must never receive private evidence by default; sharing requires
|
|
33
|
-
explicit publication authority and the `orca-cli` publishing reference.
|
|
34
|
-
|
|
35
|
-
## Bind the configured role
|
|
36
|
-
|
|
37
|
-
Read `roles.json` from the installed shared root `skills/axstack/`. The installed
|
|
38
|
-
shape is `{ "version": 1, "preset": "<name>", "roles": [...] }`. Bundled
|
|
39
|
-
profiles are setup inputs shaped as
|
|
40
|
-
`{ "version": 1, "roles": [...] }`. A new run records the selected preset and
|
|
41
|
-
all 32 role rows once. An active run keeps the exact snapshot until the user
|
|
42
|
-
explicitly changes it.
|
|
43
|
-
|
|
44
|
-
Select the requested role by stable ID. A missing or null model holds only that role;
|
|
45
|
-
never launch a provider default. Launch-by-agent-id routes for which Orca exposes no
|
|
46
|
-
`--model` override (today: `grok`, `antigravity`) record `model: null` with an explicit note and are
|
|
47
|
-
launchable; the run record snapshots the model the TUI reports. Validate provider, model, and effort
|
|
48
|
-
against the guide and actual launch capability. Stored `modeId` and other
|
|
49
|
-
permission fields are conservative intent, not proof of effective permission
|
|
50
|
-
parity or a security boundary. Requested settings, input acceptance, effective
|
|
51
|
-
settings, and completed work are separate evidence. An unsupported or
|
|
52
|
-
unavailable value holds affected work for the user's decision without fallback.
|
|
53
|
-
The single-provider preset's null adviser and round-2 seat are intentional installation data, not
|
|
54
|
-
readiness failure; because Align and Spec require both adviser receipts, either
|
|
55
|
-
null adviser still holds those phases. The current chat is the driver and has
|
|
56
|
-
no role row in any preset.
|
|
57
|
-
|
|
58
|
-
## Materialize checkouts as worktrees of the registered repo
|
|
59
|
-
|
|
60
|
-
Every reviewer, release, or worker checkout is `ORCA worktree create --repo
|
|
61
|
-
id:<repoId> ...` under the repo Orca already registers. `ORCA repo add` is a
|
|
62
|
-
one-time import of a new repository; running it on a clone of a registered
|
|
63
|
-
repo creates a second top-level repo record, so it never materializes a
|
|
64
|
-
checkout. See [Candidate publication](candidate-publication.md) for the
|
|
65
|
-
detached immutable review checkout.
|
|
66
|
-
|
|
67
|
-
## Supervise one authoritative attempt
|
|
68
|
-
|
|
69
|
-
For supervised work, use the orchestration guide's native Run, Task, and
|
|
70
|
-
Dispatch flow. Reconcile existing attempts first. Bind the approved spec or
|
|
71
|
-
small-change intent, brief, authority, role snapshot, worktree, base, and
|
|
72
|
-
candidate to the Task; preserve the returned
|
|
73
|
-
Task, Dispatch, terminal, agent, and worktree identities. Exactly one Dispatch
|
|
74
|
-
may write a candidate at a time.
|
|
75
|
-
Put the [Safe deletion](workspace-hygiene.md#safe-deletion) rule in every
|
|
76
|
-
worker brief.
|
|
77
|
-
|
|
78
|
-
Create a worker worktree with `--parent-worktree` naming the candidate's
|
|
79
|
-
worktree when both are in the same repository; see
|
|
80
|
-
[Readable sidebar](workspace-hygiene.md#readable-sidebar) for naming, status,
|
|
81
|
-
and parentage at dispatch. `--no-parent` is for unrelated work with no parent
|
|
82
|
-
context. Where supported, correct wrong lineage in place with
|
|
83
|
-
`worktree set --parent-worktree`. Lineage is presentation, never authority: it
|
|
84
|
-
grants nothing and cannot replace Task, Dispatch, and receipt evidence.
|
|
85
|
-
`--no-parent` is never used for a review or repair checkout.
|
|
86
|
-
|
|
87
|
-
Every reviewer gets a separate Orca child worktree parented to the candidate.
|
|
88
|
-
Keep that reviewer's probes and private evidence in its separate private
|
|
89
|
-
per-Dispatch run folder under [Workspace hygiene](workspace-hygiene.md), with no
|
|
90
|
-
first-pass cross-read. Untracked files never prove a worktree disposable.
|
|
91
|
-
|
|
92
|
-
Before launching a Claude worker in a checkout, from the installed `axstack` skill directory
|
|
93
|
-
run `bun scripts/trust-path.js --path <exact checkout path>` for that
|
|
94
|
-
exact checkout path. It trusts only Orca-registered repository roots and their
|
|
95
|
-
worktrees. A failed preflight holds launch; workers never answer trust or
|
|
96
|
-
permission dialogs. A trust dialog that still appears is a hold.
|
|
97
|
-
|
|
98
|
-
An `input_accepted` stage proves only that input reached the terminal. Require
|
|
99
|
-
`turn_started` plus runtime/session inspection before treating the agent as
|
|
100
|
-
started, and verify the requested role independently before trusting its work.
|
|
101
|
-
If a worker asks to confirm its own dispatch brief, the dispatching owner
|
|
102
|
-
confirms once by typed terminal input restating the brief's authority, then
|
|
103
|
-
re-verifies `turn_started`. That confirmation never answers a trust or permission prompt;
|
|
104
|
-
it answers only the agent's own model-turn question about its brief, never a
|
|
105
|
-
harness or tool dialog, and adds no authority. A second ask is a hold.
|
|
106
|
-
A workspace trust, hook review, permission, authentication, or model prompt is
|
|
107
|
-
a visible hold. Never answer a trust or permission prompt on the worker's
|
|
108
|
-
behalf. A permission prompt or provider safety refusal is a held, incomplete
|
|
109
|
-
outcome, never consent or completion. Never bypass or retry it through another
|
|
110
|
-
model. Preserve the attempt and its evidence, then use only
|
|
111
|
-
the runtime guide's inspection and recovery procedure; reconcile before any
|
|
112
|
-
authorized retry so no duplicate writer starts.
|
|
113
|
-
|
|
114
|
-
## Reviewer workspaces and evidence
|
|
115
|
-
|
|
116
|
-
Give each reviewer a separate Orca-managed child worktree under the candidate's
|
|
117
|
-
worktree, including report-only reviews and rechecks; never share the author's
|
|
118
|
-
checkout or another reviewer's checkout. A later review gets a fresh Orca-managed
|
|
119
|
-
child worktree after the prior settled review's evidence and cleanup are
|
|
120
|
-
reconciled. Use the runtime-owned worktree guide,
|
|
121
|
-
not a raw Git worktree or temporary clone. Before dispatch, verify a detached
|
|
122
|
-
checkout of the exact candidate SHA and the pinned base in that child.
|
|
123
|
-
|
|
124
|
-
Name the private `<run dir>/evidence/<dispatch>/` folder in the brief and
|
|
125
|
-
completion receipt. Keep tracked candidate files read-only and peer folders
|
|
126
|
-
isolated. Scope `TMPDIR` to that 0700 folder for owned commands where supported.
|
|
127
|
-
Before use or temporary-file cleanup, validate that its real path equals or
|
|
128
|
-
is inside the recorded run evidence folder, is not a symbolic link, and matches the recorded
|
|
129
|
-
Dispatch owner. Worktree-local temporary paths use the same guards against
|
|
130
|
-
their recorded worktree and owner. Remove only an exact validated owned
|
|
131
|
-
path, with no glob or parent-root deletion; never wipe a general cache.
|
|
132
|
-
Uncertain temporary paths are preserved for reconciliation.
|
|
133
|
-
Before removing a reviewer worktree, read back its report and supporting
|
|
134
|
-
evidence from the private run evidence folder and record their paths. Files
|
|
135
|
-
already there need no archive step; the private evidence archive applies only
|
|
136
|
-
to legacy in-worktree evidence. Incidental caches are not evidence.
|
|
137
|
-
A settled reviewer Dispatch can be
|
|
138
|
-
cleaned before PR merge through [axstack-cleanup](../../axstack-cleanup/SKILL.md)
|
|
139
|
-
only after its classification, readback, and removal guards pass. Preserve
|
|
140
|
-
active or unknown review evidence and unique evidence whose bytes must survive;
|
|
141
|
-
uncertain ownership or evidence holds. Terminal release alone is not permission
|
|
142
|
-
to discard evidence or remove the worktree.
|
|
143
|
-
|
|
144
|
-
## Consume, settle, and recover
|
|
145
|
-
|
|
146
|
-
Process a whole delivery before acknowledgment. Accept `worker_done` only when
|
|
147
|
-
its sender, Task, and Dispatch match the expected active attempt; then verify
|
|
148
|
-
the candidate revision and evidence before advancing Axstack's derived record.
|
|
149
|
-
A valid completion for an older Dispatch never completes a newer Dispatch.
|
|
150
|
-
Duplicate messages are deduplicated by their runtime identity.
|
|
151
|
-
|
|
152
|
-
On `consumer_fenced`, stop consuming under that identity. Reconcile the active
|
|
153
|
-
coordinator and delivery through the runtime guide; never bypass the fence,
|
|
154
|
-
forge a sender, borrow a terminal identity, or partially acknowledge the
|
|
155
|
-
delivery. Settlement is also runtime-owned: reuse, retain, or release a settled
|
|
156
|
-
terminal only through the guide. A genuine `user_takeover` result requires
|
|
157
|
-
retention; do not close, release, reuse, or send commands to that terminal as
|
|
158
|
-
cleanup. Apply only the recorded
|
|
159
|
-
repair Dispatch ID exception in [Workspace hygiene](workspace-hygiene.md).
|
|
160
|
-
|
|
161
|
-
Contact loss, silence, idle state, or an absent status never proves exit or
|
|
162
|
-
transfers authority. Ordinary restart and resume reconcile the same owner,
|
|
163
|
-
author, Task, Dispatch, worktree, revisions, and pending receipts. Authorized
|
|
164
|
-
repairs return to the same author when its session and evidence remain usable;
|
|
165
|
-
uncertainty holds replacement rather than creating a second writer.
|
|
166
|
-
|
|
167
|
-
## Transfer ownership explicitly
|
|
168
|
-
|
|
169
|
-
Distinguish supervised workers from a full ownership handoff. Only the user's
|
|
170
|
-
explicit transfer request enters this branch. Record the intended recipient,
|
|
171
|
-
exact scope, revisions, authority, and pending request before following the
|
|
172
|
-
runtime-owned `orca-cli` handoff procedure.
|
|
173
|
-
|
|
174
|
-
Input acceptance or turn start is launch evidence, not ownership. Validate an
|
|
175
|
-
explicit recipient acceptance against the intended request, session, scope,
|
|
176
|
-
candidate/base, and authority before changing ownership. Until then the current
|
|
177
|
-
owner remains accountable. After a valid acceptance, record it, transfer only
|
|
178
|
-
the accepted authority, and have the prior owner stop. Ordinary resume keeps
|
|
179
|
-
the current owner and never launches a handoff.
|
|
180
|
-
|
|
181
|
-
The runtime step is complete only when its real receipts are recorded with
|
|
182
|
-
their limitations. Those receipts grant no merge, release, publication, model
|
|
183
|
-
substitution, host-configuration, or scope authority.
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bun
|
|
2
|
-
import { chmod, lstat, readFile, rename, unlink, writeFile } from 'node:fs/promises';
|
|
3
|
-
|
|
4
|
-
function fail(message) { throw new Error(message); }
|
|
5
|
-
|
|
6
|
-
function args(argv) {
|
|
7
|
-
const values = {};
|
|
8
|
-
for (let i = 0; i < argv.length; i += 2) {
|
|
9
|
-
const key = argv[i];
|
|
10
|
-
if (!['--path', '--repo-list-file', '--worktree-list-file'].includes(key) || !argv[i + 1] || values[key]) {
|
|
11
|
-
fail(`invalid argument: ${key ?? '(end)'}`);
|
|
12
|
-
}
|
|
13
|
-
values[key] = argv[i + 1];
|
|
14
|
-
}
|
|
15
|
-
const path = values['--path'];
|
|
16
|
-
if (!path || !path.startsWith('/') || path.includes('\0') || path.split('/').some((part) => part === '.' || part === '..') ||
|
|
17
|
-
(path !== '/' && (path.endsWith('/') || path.includes('//')))) fail('path must be an exact absolute path');
|
|
18
|
-
if (Boolean(values['--repo-list-file']) !== Boolean(values['--worktree-list-file'])) {
|
|
19
|
-
fail('both Orca inventory files are required together');
|
|
20
|
-
}
|
|
21
|
-
return values;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
async function inventory(file, command, key) {
|
|
25
|
-
let raw;
|
|
26
|
-
if (file) raw = await readFile(file, 'utf8');
|
|
27
|
-
else {
|
|
28
|
-
const result = Bun.spawnSync(['orca', ...command, '--json'], { stdout: 'pipe', stderr: 'pipe' });
|
|
29
|
-
if (result.exitCode !== 0) fail(`Orca ${command.join(' ')} failed: ${result.stderr.toString().trim()}`);
|
|
30
|
-
raw = result.stdout.toString();
|
|
31
|
-
}
|
|
32
|
-
const response = JSON.parse(raw);
|
|
33
|
-
if (response.ok !== true || !Array.isArray(response.result?.[key])) fail(`invalid Orca ${key} inventory`);
|
|
34
|
-
if (response.result.truncated === true) fail(`truncated Orca ${key} inventory`);
|
|
35
|
-
return response.result[key];
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
async function configStat(path) {
|
|
39
|
-
const stat = await lstat(path).catch((err) => err?.code === 'ENOENT' ? null : Promise.reject(err));
|
|
40
|
-
if (stat?.isSymbolicLink()) fail(`refusing symlinked Claude config: ${path}`);
|
|
41
|
-
if (stat && !stat.isFile()) fail(`Claude config is not a regular file: ${path}`);
|
|
42
|
-
return stat;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
async function snapshot(path) {
|
|
46
|
-
const stat = await configStat(path);
|
|
47
|
-
return { stat, raw: stat ? await readFile(path, 'utf8') : null };
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
async function withLock(path, action) {
|
|
51
|
-
// The lock serializes this helper's writers; byte checks also catch other writers.
|
|
52
|
-
const lock = `${path}.axstack-lock`;
|
|
53
|
-
for (let attempt = 0; attempt < 100; attempt += 1) {
|
|
54
|
-
try {
|
|
55
|
-
await writeFile(lock, `${process.pid}\n`, { flag: 'wx', mode: 0o600 });
|
|
56
|
-
try { return await action(); }
|
|
57
|
-
finally { await unlink(lock); }
|
|
58
|
-
} catch (err) {
|
|
59
|
-
if (err?.code !== 'EEXIST') throw err;
|
|
60
|
-
await Bun.sleep(5 + Math.floor(Math.random() * 10));
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
fail('Claude config is busy; trust preflight held');
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
async function trust(configPath, path) {
|
|
67
|
-
for (let attempt = 0; attempt < 5; attempt += 1) {
|
|
68
|
-
const { stat, raw } = await snapshot(configPath);
|
|
69
|
-
const current = raw === null ? {} : JSON.parse(raw);
|
|
70
|
-
if (!current || typeof current !== 'object' || Array.isArray(current) ||
|
|
71
|
-
(current.projects !== undefined && (!current.projects || typeof current.projects !== 'object' || Array.isArray(current.projects)))) {
|
|
72
|
-
fail('invalid Claude config shape');
|
|
73
|
-
}
|
|
74
|
-
if (current.projects?.[path]?.hasTrustDialogAccepted === true) {
|
|
75
|
-
console.log(JSON.stringify({ status: 'already-trusted', path }));
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
current.projects ??= {};
|
|
79
|
-
if (current.projects[path] !== undefined && (!current.projects[path] || typeof current.projects[path] !== 'object' || Array.isArray(current.projects[path]))) {
|
|
80
|
-
fail('invalid Claude project entry');
|
|
81
|
-
}
|
|
82
|
-
current.projects[path] ??= {};
|
|
83
|
-
current.projects[path].hasTrustDialogAccepted = true;
|
|
84
|
-
|
|
85
|
-
const temp = `${configPath}.${crypto.randomUUID()}.tmp`;
|
|
86
|
-
try {
|
|
87
|
-
await writeFile(temp, `${JSON.stringify(current, null, 2)}\n`, { flag: 'wx', mode: stat ? stat.mode & 0o777 : 0o600 });
|
|
88
|
-
if (stat) await chmod(temp, stat.mode & 0o777);
|
|
89
|
-
if ((await snapshot(configPath)).raw !== raw) {
|
|
90
|
-
await Bun.sleep(5 + Math.floor(Math.random() * 10));
|
|
91
|
-
continue;
|
|
92
|
-
}
|
|
93
|
-
await rename(temp, configPath);
|
|
94
|
-
const after = await snapshot(configPath);
|
|
95
|
-
if (JSON.parse(after.raw).projects?.[path]?.hasTrustDialogAccepted === true) {
|
|
96
|
-
console.log(JSON.stringify({ status: 'trusted', path }));
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
} finally {
|
|
100
|
-
await unlink(temp).catch((err) => { if (err?.code !== 'ENOENT') throw err; });
|
|
101
|
-
}
|
|
102
|
-
await Bun.sleep(5 + Math.floor(Math.random() * 10));
|
|
103
|
-
}
|
|
104
|
-
fail('Claude config changed during trust preflight');
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
async function main() {
|
|
108
|
-
const options = args(process.argv.slice(2));
|
|
109
|
-
const path = options['--path'];
|
|
110
|
-
const repos = await inventory(options['--repo-list-file'], ['repo', 'list'], 'repos');
|
|
111
|
-
const worktrees = await inventory(options['--worktree-list-file'], ['worktree', 'list'], 'worktrees');
|
|
112
|
-
const repoIds = new Set(repos.filter((repo) => repo.kind === 'git').map((repo) => repo.id));
|
|
113
|
-
const registered = repos.some((repo) => repo.kind === 'git' && repo.path === path) ||
|
|
114
|
-
worktrees.some((worktree) => repoIds.has(worktree.repoId) && worktree.hostId === 'local' && worktree.path === path);
|
|
115
|
-
if (!registered) fail(`path is not an Orca-registered repository or worktree: ${path}`);
|
|
116
|
-
|
|
117
|
-
const home = process.env.HOME;
|
|
118
|
-
if (!home?.startsWith('/')) fail('HOME must be absolute');
|
|
119
|
-
const configPath = `${home.replace(/\/$/, '')}/.claude.json`;
|
|
120
|
-
await withLock(configPath, () => trust(configPath, path));
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
main().catch((err) => { console.error(err.message); process.exitCode = 1; });
|