axstack 0.9.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/LICENSE +21 -0
- package/README.md +132 -0
- package/bin/axstack.js +396 -0
- package/docs/installation.md +239 -0
- package/docs/workflows.md +220 -0
- package/package.json +40 -0
- package/profiles/presets/claude-only.json +194 -0
- package/profiles/presets/codex-only.json +194 -0
- package/profiles/presets/mixed.json +194 -0
- package/skills/axstack/SKILL.md +81 -0
- package/skills/axstack/references/automations.md +368 -0
- package/skills/axstack/references/candidate-publication.md +45 -0
- package/skills/axstack/references/contracts.md +102 -0
- package/skills/axstack/references/lifecycle.md +137 -0
- package/skills/axstack/references/orca-runtime.md +109 -0
- package/skills/axstack/references/pr-shape.md +39 -0
- package/skills/axstack/references/routing.md +129 -0
- package/skills/axstack/references/run-record.md +109 -0
- package/skills/axstack-align/SKILL.md +121 -0
- package/skills/axstack-audit/SKILL.md +137 -0
- package/skills/axstack-audit/references/record.md +28 -0
- package/skills/axstack-debug/SKILL.md +157 -0
- package/skills/axstack-debug/references/packet.md +80 -0
- package/skills/axstack-explain/SKILL.md +66 -0
- package/skills/axstack-explain/references/visual-qa.md +15 -0
- package/skills/axstack-implement/SKILL.md +164 -0
- package/skills/axstack-improve/SKILL.md +69 -0
- package/skills/axstack-relay/SKILL.md +102 -0
- package/skills/axstack-research/SKILL.md +57 -0
- package/skills/axstack-research/references/checklist.md +25 -0
- package/skills/axstack-review/SKILL.md +343 -0
- package/skills/axstack-spec/SKILL.md +67 -0
- package/skills/axstack-tickets/SKILL.md +86 -0
- package/skills/axstack-watch/SKILL.md +160 -0
- package/skills/axstack-watch/references/repair-publication.md +69 -0
- package/skills/axstack-watch/references/watch-runtime.md +60 -0
- package/src/capabilities.js +138 -0
- package/src/claude-settings.js +230 -0
- package/src/installer.js +980 -0
- package/src/instructions.js +100 -0
- package/src/locations.js +43 -0
- package/src/manifest.js +251 -0
- package/src/posixpath.js +108 -0
- package/src/roles.js +142 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: axstack-tickets
|
|
3
|
+
description: When an approved capability needs executable tasks, use axstack-tickets to map work and track lifecycle state.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Tickets
|
|
7
|
+
|
|
8
|
+
Produce an executable capability map tied to the exact approved spec revision.
|
|
9
|
+
Keep user-visible capabilities in the selected store, keep implementation detail
|
|
10
|
+
in the repository, reconcile lifecycle state, and stop before implementation.
|
|
11
|
+
|
|
12
|
+
Before mapping, load [Standing contracts](../axstack/references/contracts.md).
|
|
13
|
+
Follow its required edge to [Shared lifecycle](../axstack/references/lifecycle.md),
|
|
14
|
+
including the lifecycle audit hook. Read the
|
|
15
|
+
[PR-shape policy](../axstack/references/pr-shape.md) before sizing tasks. Read the
|
|
16
|
+
[Orca runtime boundary](../axstack/references/orca-runtime.md) immediately before
|
|
17
|
+
an actual checker dispatch, not for ordinary mapping or state reconciliation.
|
|
18
|
+
|
|
19
|
+
## Procedure
|
|
20
|
+
|
|
21
|
+
1. **Pin scope and storage.** Confirm the approved spec identity before mapping.
|
|
22
|
+
Hold on unapproved or materially changed scope; a still-valid approval is
|
|
23
|
+
never repeated. Use the explicitly selected Markdown or Linear store. Record
|
|
24
|
+
the exact approved spec revision and selected store.
|
|
25
|
+
|
|
26
|
+
2. **Preflight the selected store.** Markdown mode works independently. In
|
|
27
|
+
Linear mode, check the actual session's required MCP tools and document
|
|
28
|
+
access. Missing access is an actionable setup gap: preserve the selected
|
|
29
|
+
store, record the gap, and stop affected work. Proceed only with verified
|
|
30
|
+
access; a recorded gap never switches stores.
|
|
31
|
+
|
|
32
|
+
3. **Map capabilities to execution.** In Linear, issues represent user-visible
|
|
33
|
+
capabilities; one capability may span several tasks and PRs. Keep detailed
|
|
34
|
+
execution breakdowns in the repository. For every capability, derive
|
|
35
|
+
acceptance checks from the pinned spec and identify internal tasks,
|
|
36
|
+
dependencies, PR ownership, and worktrees. For each task the driver records
|
|
37
|
+
one theme and a coarse size estimate from the ownership, interface, and
|
|
38
|
+
dependency map. A task estimated in the exception band is assessed for a
|
|
39
|
+
split at mapping time and split where a green, atomic, reviewable split
|
|
40
|
+
exists. If the driver judges it inseparable, record the coarse planning
|
|
41
|
+
rationale with the task; actual measurement and exception evidence follow in
|
|
42
|
+
the implement receipt. Mapping time requires no actual SHAs or line counts.
|
|
43
|
+
Every capability ends with the fields below and an explicit dependency list.
|
|
44
|
+
These routine mapping and split choices are autonomous driver decisions
|
|
45
|
+
within the approved spec; size alone never requires user approval.
|
|
46
|
+
|
|
47
|
+
The driver performs every Linear mutation. Other roles return proposed
|
|
48
|
+
changes and evidence to the driver.
|
|
49
|
+
|
|
50
|
+
## Template: capability to task map
|
|
51
|
+
|
|
52
|
+
```text
|
|
53
|
+
Spec: <approved revision>
|
|
54
|
+
Capability: <Markdown ref or Linear issue URL> <title>
|
|
55
|
+
Internal task: <task> -> <PR owner> -> <worktree>
|
|
56
|
+
Theme: <one behavior or component>
|
|
57
|
+
Size est: <coarse band estimate>
|
|
58
|
+
Acceptance: <checks from approved spec rev>
|
|
59
|
+
Depends: <task IDs or none>
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
4. **Reconcile lifecycle state.** Compare each run capability with its required
|
|
63
|
+
PR merge evidence and acceptance outputs. A reviewed but unmerged capability
|
|
64
|
+
stays **In Review**; mark Done only after all required PRs merge and the
|
|
65
|
+
capability's acceptance checks pass. Resolve each observed mismatch with
|
|
66
|
+
either a verified driver-owned update or a drift report.
|
|
67
|
+
|
|
68
|
+
The checker reports run-scoped discrepancies with evidence and never mutates
|
|
69
|
+
Linear. The driver independently verifies that evidence before applying an
|
|
70
|
+
update. Spec or acceptance changes and conflicting state are decisions, not
|
|
71
|
+
routine sync repairs. With no configured `axstack-checker` profile, hold
|
|
72
|
+
checker dispatch; the driver checks directly or records the gap. Never launch
|
|
73
|
+
a provider default.
|
|
74
|
+
|
|
75
|
+
### Template: drift report
|
|
76
|
+
|
|
77
|
+
```text
|
|
78
|
+
Capability: <issue>
|
|
79
|
+
Observed: <Linear state> vs <PR merge SHAs/URLs + acceptance outputs>
|
|
80
|
+
Recommendation: <move to In Review | other> (driver verifies first)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
5. **Return the mapping.** Report the pinned spec revision, selected store, map
|
|
84
|
+
references, mutations performed by the driver, recorded gaps, and unresolved
|
|
85
|
+
decisions. Stop with a map ready for lifecycle continuation; implementation
|
|
86
|
+
has not started.
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: axstack-watch
|
|
3
|
+
description: When babysitting an existing PR, use axstack-watch to monitor or maintain it within bounded authority.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Watch
|
|
7
|
+
|
|
8
|
+
Leave each adopted PR with one accountable owner, current readiness evidence,
|
|
9
|
+
and a bounded watch that ends cleanly or preserves enough state to resume.
|
|
10
|
+
|
|
11
|
+
Before acting, load [Standing contracts](../axstack/references/contracts.md).
|
|
12
|
+
Its required edge loads [Shared lifecycle](../axstack/references/lifecycle.md),
|
|
13
|
+
including the end-of-run audit hook. Reach other references only at the steps
|
|
14
|
+
that name them.
|
|
15
|
+
|
|
16
|
+
Preserve any explicitly named PR, repository, or peer scope. For broad
|
|
17
|
+
discovery of the user's own PRs (such as “my” or “our” PRs), run
|
|
18
|
+
`gh api user --jq .login` on the execution host, then select open PRs authored
|
|
19
|
+
by that login in the named or current repository. Never hardcode or guess the
|
|
20
|
+
username; a missing or failed authenticated-login lookup is a concrete blocker.
|
|
21
|
+
The authenticated human login selects PRs. Runtime session IDs coordinate work
|
|
22
|
+
only and establish neither human identity nor write, reply, or merge authority.
|
|
23
|
+
When the session is the Orca driver automation, also load
|
|
24
|
+
[Automation sessions](../axstack/references/automations.md): it is the owner
|
|
25
|
+
for every PR it handles, and its gate and allowlist bound every mutation.
|
|
26
|
+
|
|
27
|
+
## 1. Adopt and reconcile
|
|
28
|
+
|
|
29
|
+
Start from actual state. Reconcile the PR's remote head and base, ownership,
|
|
30
|
+
existing Orca Tasks, Dispatches, sessions, private run record, and watch registrations. Reuse the
|
|
31
|
+
live owner and watch; uncertain state holds new registrations until resolved.
|
|
32
|
+
|
|
33
|
+
For an existing own PR, read the
|
|
34
|
+
[proportional scope identities](../axstack/references/routing.md#proportional-scope-identity),
|
|
35
|
+
verify writable ownership and user maintenance authority, then snapshot the
|
|
36
|
+
accepted maintenance intent once: authorized scope, actual head and base,
|
|
37
|
+
current owner, actual author provenance, and watch state. Check authoring
|
|
38
|
+
session evidence; the orchestrator identity is not author evidence, and never
|
|
39
|
+
assume an author for an imported own PR. It needs no new spec, ticket, or repeated
|
|
40
|
+
approval. Monitoring-only adoption grants no repair or reply authority.
|
|
41
|
+
|
|
42
|
+
Adoption is settled when the record names one persistent owner, one watch, the
|
|
43
|
+
exact PR revision and base, and the applicable authority snapshot. If write
|
|
44
|
+
authority is unverified, record the hold and continue read-only.
|
|
45
|
+
|
|
46
|
+
## 2. Fix the operating mode
|
|
47
|
+
|
|
48
|
+
Choose one mode from the user's authority and record it before dispatch:
|
|
49
|
+
|
|
50
|
+
- **Observation-only:** reconcile and report CI, reviews, and PR state. It
|
|
51
|
+
dispatches no author and sends no reply. This restriction dominates every
|
|
52
|
+
repair path, including obvious fixes after changed heads or feedback.
|
|
53
|
+
- **Peer:** observe and report a colleague's PR. Peer mode never repairs.
|
|
54
|
+
- **Authorized maintenance:** repair an adopted own PR only within the accepted
|
|
55
|
+
maintenance snapshot and publication authority.
|
|
56
|
+
|
|
57
|
+
Every later wake must be classifiable from this recorded mode without inferring
|
|
58
|
+
new authority.
|
|
59
|
+
|
|
60
|
+
## 3. Start the bounded watch
|
|
61
|
+
|
|
62
|
+
Read-only checks and updates to the already-owned local record need no runtime
|
|
63
|
+
load. When the watch needs a new owner or automated observation, first read
|
|
64
|
+
[Watch runtime](references/watch-runtime.md) and then
|
|
65
|
+
[Orca runtime](../axstack/references/orca-runtime.md). Reconcile before creating
|
|
66
|
+
anything. The user lifted the native-watch hold by user decision: the 5 min driver
|
|
67
|
+
automation is a mutating owner for the PRs it handles and the hourly watchdog
|
|
68
|
+
stays independent and read-only. The driver is the automation session itself,
|
|
69
|
+
with no `axstack-monitor` or `axstack-owner` role row; `axstack-monitor` stays
|
|
70
|
+
an optional read-only observer that never sends. One read-only PR observation
|
|
71
|
+
needs neither.
|
|
72
|
+
|
|
73
|
+
For standalone adoption, materialize `axstack-owner` only when no live owner
|
|
74
|
+
exists. Once it exists, the current chat is not a competing coordinator. Only
|
|
75
|
+
the owner launches the writer, reviewers, monitor, and watchdog. Workers create
|
|
76
|
+
no children or recursive teams, and the adoption watcher is never the writer.
|
|
77
|
+
|
|
78
|
+
A live watch has verified role and timer receipts, handshakes, watched scope,
|
|
79
|
+
wake ownership, and a common expiry. A missing runtime capability is a setup gap,
|
|
80
|
+
not a reason to invent a call or create a duplicate registration. Wait through
|
|
81
|
+
native wake-ups; no model remains active between events.
|
|
82
|
+
|
|
83
|
+
## 4. Route each wake
|
|
84
|
+
|
|
85
|
+
Re-read the remote head and base, then reconcile the event against acknowledged
|
|
86
|
+
IDs and the recorded mode. A changed head, CI result, or review comment is an
|
|
87
|
+
event, not repair authority. Stale or ambiguous observations authorize nothing.
|
|
88
|
+
|
|
89
|
+
Observation-only and peer wakes produce a read-only report and stop. For an
|
|
90
|
+
authorized maintenance wake that may require a repair or public reply, read and
|
|
91
|
+
follow [Repair and publication](references/repair-publication.md). An
|
|
92
|
+
automation session repairs in a per-PR child worktree created through
|
|
93
|
+
`orca-cli`; its driver worktree never checks out a PR branch.
|
|
94
|
+
|
|
95
|
+
### Feedback routing
|
|
96
|
+
|
|
97
|
+
New work routes only under its confirmed scope identity: an approved spec and
|
|
98
|
+
matching ticket map for substantial work, or a snapshotted **small-change
|
|
99
|
+
intent** for small work. An adopted own PR instead uses its accepted maintenance
|
|
100
|
+
snapshot. Missing, stale, or materially changed identity holds repair routing
|
|
101
|
+
while monitoring continues. Accepted fixes return to the same original author
|
|
102
|
+
session only when the run itself launched that session and evidence allows,
|
|
103
|
+
then receive refreshed review under the authored mode rule before publication.
|
|
104
|
+
For an adopted own PR under the automation, the original authoring session is
|
|
105
|
+
not a run-launched session: the repair author is the automation session
|
|
106
|
+
(Claude/Opus) or a dispatched `axstack-author` (Sol), and the authored-review
|
|
107
|
+
pairing follows the recorded actual provenance of that repair, not the PR's
|
|
108
|
+
historical author. Unknown, mixed, or unsupported author provenance
|
|
109
|
+
that cannot establish the eligible configured reviewer is an exact gap to
|
|
110
|
+
report to the user, not permission to invent a pairing or model fallback.
|
|
111
|
+
|
|
112
|
+
A handled wake has an acknowledged event ID, an observation or action bound to
|
|
113
|
+
the current revision, and a recorded hold or next owner where work remains.
|
|
114
|
+
|
|
115
|
+
When a new actionable event is eligible under a recorded `Notification policy`,
|
|
116
|
+
the owner may use the optional [axstack-relay](../axstack-relay/SKILL.md).
|
|
117
|
+
The monitor never sends, and `axstack-watchdog` never mutates GitHub and
|
|
118
|
+
performs exactly one kind of send, a gate-authorized automation-health
|
|
119
|
+
escalation recorded in `watchdog.json`; absent policy or failed relay uses the
|
|
120
|
+
current Orca conversation and leaves every existing hold open.
|
|
121
|
+
|
|
122
|
+
## 5. State readiness precisely
|
|
123
|
+
|
|
124
|
+
The owner checks current required checks, all feedback, approvals, mergeability,
|
|
125
|
+
and exact-revision receipts before any merge-ready statement. API errors leave
|
|
126
|
+
readiness `UNKNOWN`; review approval alone is not merge-ready. Merge-ready is an
|
|
127
|
+
observed state distinct from merged, and the human merges by default.
|
|
128
|
+
|
|
129
|
+
## 6. End and preserve continuity
|
|
130
|
+
|
|
131
|
+
End early when all required PRs merge, or at cancel or the shared default 24h
|
|
132
|
+
deadline. In every case, stop and verify all owned registrations. The deadline
|
|
133
|
+
also stops timers for open PRs; never silently renew them.
|
|
134
|
+
|
|
135
|
+
At every end condition, leave the compact state below in the private run record
|
|
136
|
+
and report it in the current chat, even when work remains. Expiry grants neither
|
|
137
|
+
silent renewal nor ownership-transfer authority. Under an automation, expiry
|
|
138
|
+
marks the PR `expired` in the record and sidecar; an `expired` PR is never
|
|
139
|
+
silently re-adopted and is skipped until the user re-arms it.
|
|
140
|
+
|
|
141
|
+
Transfer ownership through the runtime-owned Orca handoff route only when the
|
|
142
|
+
user explicitly requests it. Before transfer, follow the lifecycle-owned
|
|
143
|
+
preflight for native capability availability, the configured role, and explicit
|
|
144
|
+
recipient acceptance. A failed or incomplete preflight preserves the current
|
|
145
|
+
owner and reports the gap; never invent a native command or infer acceptance.
|
|
146
|
+
|
|
147
|
+
```text
|
|
148
|
+
Record: <progress.md path>
|
|
149
|
+
PR: <URL> rev <sha> base <sha>
|
|
150
|
+
Owner: <profile + session> Worktree: <path>
|
|
151
|
+
Scope: <approved rev, small-change intent, or maintenance snapshot>
|
|
152
|
+
Capability: <issue + lifecycle state>
|
|
153
|
+
CI/review: <current states + evidence refs>
|
|
154
|
+
Watch: <automation ids or stopped registration receipts + expiry>
|
|
155
|
+
Remaining: <next actions + owner>
|
|
156
|
+
Resume: <known commands or verified refs needed to reconcile from this revision>
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
The watch ends only when registrations are stopped, receipts are recorded, and
|
|
160
|
+
the PR is either merged or represented by this resumable state.
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Repair and publication
|
|
2
|
+
|
|
3
|
+
Read this only for authorized maintenance of an adopted own PR. Observation-only
|
|
4
|
+
and peer modes stop with a report before this branch.
|
|
5
|
+
|
|
6
|
+
## 1. Confirm the repair boundary
|
|
7
|
+
|
|
8
|
+
Re-read the accepted maintenance snapshot, writable ownership, publication
|
|
9
|
+
authority, remote head and base, and current feedback. Route an accepted fix to
|
|
10
|
+
the original author session only when the run itself launched that session and
|
|
11
|
+
evidence permits. For an adopted own PR under the automation, the repair
|
|
12
|
+
author is the automation session (Claude/Opus) or a dispatched
|
|
13
|
+
`axstack-author` (Sol); record that repair's actual provenance before
|
|
14
|
+
selecting the reviewer, because the authored-review pairing follows the actual
|
|
15
|
+
provenance of the repair, never the PR's historical author. A missing,
|
|
16
|
+
stale, or materially changed boundary holds the repair while read-only
|
|
17
|
+
monitoring continues.
|
|
18
|
+
|
|
19
|
+
Record the exact defect, allowed files and actions, current revision, feedback
|
|
20
|
+
IDs, and actual author without expanding scope. If actual author information is
|
|
21
|
+
unknown, mixed, or unsupported and cannot establish an eligible configured
|
|
22
|
+
reviewer, report that exact gap and ask the user; do not assume an author from
|
|
23
|
+
the importing owner or orchestrator.
|
|
24
|
+
|
|
25
|
+
## 2. Produce a reviewable candidate
|
|
26
|
+
|
|
27
|
+
The author prepares the smallest in-scope repair and the exact public reply
|
|
28
|
+
bodies, each keyed to its feedback ID and bound to the candidate revision. The
|
|
29
|
+
candidate is committed locally in the per-PR child worktree and reviewed in
|
|
30
|
+
authored mode at its local SHA; nothing is pushed for review. Both code and
|
|
31
|
+
reply bodies receive the one complete eligible non-author/non-owner review
|
|
32
|
+
required by the authored review rule in `axstack-review`.
|
|
33
|
+
|
|
34
|
+
Publication stays held until the current authored review receipt covers the
|
|
35
|
+
exact new revision and base, all six angles, applicable acceptance, the reply
|
|
36
|
+
body identities, and every affected boundary, with no unresolved material
|
|
37
|
+
finding or urgent hold. Under an automation the escalation gate of
|
|
38
|
+
[Automation sessions](../../axstack/references/automations.md) also runs on
|
|
39
|
+
the local SHA: publication additionally requires the gate to return `proceed`
|
|
40
|
+
with no unresolved validated blocking finding, and a push before the gate
|
|
41
|
+
settles is forbidden.
|
|
42
|
+
|
|
43
|
+
## 3. Revalidate immediately before publication
|
|
44
|
+
|
|
45
|
+
Confirm fresh remote head and base, feedback freshness, reply body identity,
|
|
46
|
+
and the exact revision covered by the mode-required review receipt. Before a history
|
|
47
|
+
rewrite, confirm the expected-old SHA; a mismatch holds publication.
|
|
48
|
+
|
|
49
|
+
All publication inputs must still match their reviewed values at the final
|
|
50
|
+
readback.
|
|
51
|
+
|
|
52
|
+
## 4. Publish idempotently
|
|
53
|
+
|
|
54
|
+
Use `gh stack` for the adopted PR only, preserving unrelated stack entries.
|
|
55
|
+
Bind the operation to the exact reviewed revision, then verify the submission
|
|
56
|
+
receipt and remote state.
|
|
57
|
+
|
|
58
|
+
An automation session pushes fast-forward only: run the section 3 publication
|
|
59
|
+
readback immediately before the push, then `git push` to the PR branch with no
|
|
60
|
+
lease or force, and no `gh stack` sync or restack from an automation. A
|
|
61
|
+
non-fast-forward remote is a recorded hold, never a rewrite.
|
|
62
|
+
|
|
63
|
+
If the send outcome is unknown, inspect remote IDs, bodies, and actor before any
|
|
64
|
+
retry. Remain blocked while the outcome is ambiguous; retry only after
|
|
65
|
+
confirming the intended operation is absent.
|
|
66
|
+
|
|
67
|
+
Publication ends with a remote receipt proving that the reviewed revision and
|
|
68
|
+
exact replies landed once, or a recorded hold naming the unmatched input and
|
|
69
|
+
next owner.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Watch runtime
|
|
2
|
+
|
|
3
|
+
Read this before starting, resuming, or stopping automated PR observation.
|
|
4
|
+
|
|
5
|
+
## Accepted policy
|
|
6
|
+
|
|
7
|
+
The PR owner remains accountable throughout one shared default 24-hour window.
|
|
8
|
+
`axstack-monitor` and `axstack-watchdog` are independent, read-only roles, not
|
|
9
|
+
authors, reviewers, repliers, or owners.
|
|
10
|
+
|
|
11
|
+
- **Monitor:** `axstack-monitor` is an optional read-only observer that reads
|
|
12
|
+
GitHub, all PR feedback, and latest checks every five minutes, persists event
|
|
13
|
+
IDs, wakes the owner only for a new actionable event, and never sends.
|
|
14
|
+
- **Watchdog:** `axstack-watchdog` reads only automation health, handshake
|
|
15
|
+
state, and snapshot freshness hourly and never mutates GitHub; it may perform
|
|
16
|
+
exactly one kind of send, a gate-authorized automation-health escalation
|
|
17
|
+
recorded in `watchdog.json`, and otherwise reports a verified health failure
|
|
18
|
+
to the owner.
|
|
19
|
+
|
|
20
|
+
Healthy observations are snapshot-only and update quietly; they wake neither owner nor
|
|
21
|
+
driver. Both roles deduplicate event IDs. Uncertain delivery is reconciled
|
|
22
|
+
before retry. Restart reuses prior watch identity rather than registering a
|
|
23
|
+
duplicate. The shared deadline ends earlier on completion or cancellation and
|
|
24
|
+
is never silently renewed.
|
|
25
|
+
|
|
26
|
+
## Native Orca automations
|
|
27
|
+
|
|
28
|
+
Load the version-matched Orca automation guidance through the shared
|
|
29
|
+
[runtime boundary](../../axstack/references/orca-runtime.md). The verified
|
|
30
|
+
native automation schema supports provider selection, but model, effort, and
|
|
31
|
+
permission pinning are unsupported, and its schedule parser cannot preserve
|
|
32
|
+
the accepted bounded expiry by itself. Requested role values or a post-launch
|
|
33
|
+
self-report are not effective launch evidence.
|
|
34
|
+
|
|
35
|
+
The user lifted the native-watch hold by user decision on 2026-09-16. The accepted
|
|
36
|
+
contract now has a new shape: the driver automation is a mutating owner for the
|
|
37
|
+
PRs it handles, not an independent read-only monitor, and the watchdog keeps
|
|
38
|
+
the independent read-only health contract. The driver is the automation
|
|
39
|
+
session itself, with no `axstack-monitor` or `axstack-owner` role row
|
|
40
|
+
materialized for it. The driver records its own model
|
|
41
|
+
identity on every tick and the watchdog compares it with the expected model; a
|
|
42
|
+
mismatch is a safety hold, never a silent substitution. The bounded expiry is
|
|
43
|
+
enforced by the run record's watch deadline, not by the schedule parser. Still
|
|
44
|
+
introduce no custom scheduler or polling loop and use no legacy runtime
|
|
45
|
+
fallback. The session-level contract lives in
|
|
46
|
+
[Automation sessions](../../axstack/references/automations.md).
|
|
47
|
+
|
|
48
|
+
## Preserve the contract under automation
|
|
49
|
+
|
|
50
|
+
An automation session preserves the roles, five-minute/hourly cadences, quiet
|
|
51
|
+
healthy behavior, deduplication, handshake, watched scope, wake owner, and
|
|
52
|
+
shared expiry. Test active expiry, missed final ticks, restart, duplicate
|
|
53
|
+
ticks, cancellation, session-reuse fallback, and final cleanup before enabling.
|
|
54
|
+
A firing timestamp proves neither delivery nor work advancement. An unrequested
|
|
55
|
+
fallback session reconciles ownership and never becomes owner silently.
|
|
56
|
+
|
|
57
|
+
At every end condition, stop all task-owned registrations, verify runtime
|
|
58
|
+
cleanup receipts, and capture remaining work as resumable state. Removing watch
|
|
59
|
+
coverage, weakening role discipline, or changing the deadline requires a
|
|
60
|
+
material specification revision; it is not an implementation workaround.
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
// Host capability checks. `exec` is injected so tests never touch a live
|
|
2
|
+
// runtime. Resolve Orca exactly once and reuse it: a failed choice never
|
|
3
|
+
// triggers a fallback to another binary.
|
|
4
|
+
export const BUN_FLOOR = '1.3.14';
|
|
5
|
+
|
|
6
|
+
export const PROBE_LIMITATIONS = [
|
|
7
|
+
'A host binary probe cannot prove each agent session\'s Linear MCP access; skill prompts perform a session preflight instead.',
|
|
8
|
+
'A host binary probe cannot prove model availability or quotas; an unavailable or exhausted model pauses affected work until the user decides.',
|
|
9
|
+
'Stored role model, effort, and permission intent does not prove Orca launch parity or a successful agent execution.',
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
const CHECK_LABELS = {
|
|
13
|
+
bun: 'bun >= 1.3.14 runtime',
|
|
14
|
+
git: 'git CLI',
|
|
15
|
+
gh: 'gh CLI',
|
|
16
|
+
'gh-stack': 'gh stack extension',
|
|
17
|
+
'orca-binary': 'resolved Orca CLI',
|
|
18
|
+
'orca-runtime': 'Orca runtime connection',
|
|
19
|
+
'orca-orchestration-guide': 'Orca orchestration guide capability',
|
|
20
|
+
'orca-cli-guide': 'Orca CLI guide capability',
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
// The real commands behind each probe. gh-stack runs the actual
|
|
24
|
+
// `gh stack --help`: a "stack" substring in `gh extension list` output is not
|
|
25
|
+
// proof the extension command works.
|
|
26
|
+
export const PROBE_COMMANDS = {
|
|
27
|
+
git: ['git', ['--version']],
|
|
28
|
+
gh: ['gh', ['--version']],
|
|
29
|
+
'gh-stack': ['gh', ['stack', '--help']],
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export function resolveOrcaExecutable({ env = Bun.env, platform = process.platform } = {}) {
|
|
33
|
+
if (typeof env.ORCA_CLI_COMMAND === 'string' && env.ORCA_CLI_COMMAND.trim() !== '') {
|
|
34
|
+
return env.ORCA_CLI_COMMAND.trim();
|
|
35
|
+
}
|
|
36
|
+
if (typeof env.ORCA_DEV_REPO_ROOT === 'string' && env.ORCA_DEV_REPO_ROOT.trim() !== '') {
|
|
37
|
+
return 'orca-dev';
|
|
38
|
+
}
|
|
39
|
+
const managed = Boolean(env.ORCA_TERMINAL_HANDLE || env.ORCA_WORKTREE_ID);
|
|
40
|
+
if (platform === 'linux' && !managed) return 'orca-ide';
|
|
41
|
+
return 'orca';
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function orcaCommand(name, executable) {
|
|
45
|
+
if (name === 'orca-binary') return [executable, ['--version']];
|
|
46
|
+
if (name === 'orca-runtime') return [executable, ['status', '--json']];
|
|
47
|
+
if (name === 'orca-orchestration-guide') {
|
|
48
|
+
return [executable, ['skills', 'get', 'orchestration', '--json']];
|
|
49
|
+
}
|
|
50
|
+
if (name === 'orca-cli-guide') return [executable, ['skills', 'get', 'orca-cli', '--json']];
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function validateOrcaOutput(name, stdout) {
|
|
55
|
+
if (name === 'orca-binary') return { ok: true, stdout };
|
|
56
|
+
let parsed;
|
|
57
|
+
try {
|
|
58
|
+
parsed = JSON.parse(stdout);
|
|
59
|
+
} catch {
|
|
60
|
+
return { ok: false, stdout: 'invalid JSON response' };
|
|
61
|
+
}
|
|
62
|
+
if (name === 'orca-runtime') {
|
|
63
|
+
const runtime = parsed?.result?.runtime;
|
|
64
|
+
const ready = parsed?.ok === true && runtime?.state === 'ready' &&
|
|
65
|
+
runtime?.reachable === true && runtime?.connectionState === 'connected';
|
|
66
|
+
return { ok: ready, stdout: ready ? 'ready and connected' : 'runtime is not ready and connected' };
|
|
67
|
+
}
|
|
68
|
+
const expected = name === 'orca-cli-guide' ? 'orca-cli' : 'orchestration';
|
|
69
|
+
const ready = parsed?.name === expected && typeof parsed?.markdown === 'string' && parsed.markdown.length > 0;
|
|
70
|
+
return { ok: ready, stdout: ready ? `${expected} guide available` : `${expected} guide unavailable` };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Pure semver-floor comparison over numeric prefix segments ("1.3.14" style;
|
|
74
|
+
// trailing build metadata is ignored).
|
|
75
|
+
export function meetsFloor(version, floor = BUN_FLOOR) {
|
|
76
|
+
const nums = (s) => String(s).split('.').map((n) => Number.parseInt(n, 10));
|
|
77
|
+
const [v, f] = [nums(version), nums(floor)];
|
|
78
|
+
for (let i = 0; i < Math.max(v.length, f.length); i++) {
|
|
79
|
+
const a = Number.isInteger(v[i]) ? v[i] : 0;
|
|
80
|
+
const b = Number.isInteger(f[i]) ? f[i] : 0;
|
|
81
|
+
if (a !== b) return a > b;
|
|
82
|
+
}
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export async function runRealCheck(name, { orcaExecutable = resolveOrcaExecutable() } = {}) {
|
|
87
|
+
if (name === 'bun') {
|
|
88
|
+
const version = Bun.version;
|
|
89
|
+
return { ok: meetsFloor(version), stdout: `v${version}` };
|
|
90
|
+
}
|
|
91
|
+
const [cmd, args] = orcaCommand(name, orcaExecutable) ?? PROBE_COMMANDS[name];
|
|
92
|
+
try {
|
|
93
|
+
const result = Bun.spawnSync([cmd, ...args], {
|
|
94
|
+
stdout: 'pipe',
|
|
95
|
+
stderr: 'pipe',
|
|
96
|
+
timeout: 10000,
|
|
97
|
+
});
|
|
98
|
+
if (result.exitCode === 0) {
|
|
99
|
+
const stdout = result.stdout.toString().trim();
|
|
100
|
+
return name.startsWith('orca-') ? validateOrcaOutput(name, stdout) : { ok: true, stdout };
|
|
101
|
+
}
|
|
102
|
+
const detail = (result.stderr.toString().trim() || result.stdout.toString().trim()).slice(0, 120);
|
|
103
|
+
return { ok: false, stdout: detail || `exit ${result.exitCode}` };
|
|
104
|
+
} catch (err) {
|
|
105
|
+
return { ok: false, stdout: err?.code ?? 'not found' };
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export async function checkCapabilities(exec, resolution = {}) {
|
|
110
|
+
const orcaExecutable = resolveOrcaExecutable(resolution);
|
|
111
|
+
const names = [
|
|
112
|
+
'bun', 'git', 'gh', 'gh-stack', 'orca-binary', 'orca-runtime',
|
|
113
|
+
'orca-orchestration-guide', 'orca-cli-guide',
|
|
114
|
+
];
|
|
115
|
+
const checks = [];
|
|
116
|
+
for (const name of names) {
|
|
117
|
+
let result;
|
|
118
|
+
try {
|
|
119
|
+
result = await exec(name, { orcaExecutable });
|
|
120
|
+
} catch (err) {
|
|
121
|
+
result = { ok: false, stdout: err?.message ?? 'error' };
|
|
122
|
+
}
|
|
123
|
+
const ok = !!result?.ok;
|
|
124
|
+
const baseLabel = CHECK_LABELS[name] ?? name;
|
|
125
|
+
checks.push({
|
|
126
|
+
name,
|
|
127
|
+
label: !ok && name.startsWith('orca-')
|
|
128
|
+
? `${baseLabel} via ${orcaExecutable}`
|
|
129
|
+
: baseLabel,
|
|
130
|
+
ok,
|
|
131
|
+
detail: ok
|
|
132
|
+
? String(result?.stdout ?? '').trim().slice(0, 120) || 'found'
|
|
133
|
+
: String(result?.stdout ?? result?.detail ?? '').trim().slice(0, 120) || 'not found',
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
const gaps = checks.filter((c) => !c.ok).map((c) => `missing ${c.label}`);
|
|
137
|
+
return { checks, gaps, limitations: [...PROBE_LIMITATIONS] };
|
|
138
|
+
}
|