@sabaiway/agent-workflow-kit 12.0.0 → 12.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +74 -0
- package/README.md +2 -1
- package/SKILL.md +5 -1
- package/bridges/antigravity-cli-bridge/SKILL.md +16 -13
- package/bridges/antigravity-cli-bridge/bin/agy-review.sh +6 -5
- package/bridges/antigravity-cli-bridge/bin/agy-review.test.mjs +5 -5
- package/bridges/antigravity-cli-bridge/bin/agy.sh +4 -4
- package/bridges/antigravity-cli-bridge/bin/agy.test.mjs +2 -2
- package/bridges/antigravity-cli-bridge/capability.json +3 -3
- package/bridges/antigravity-cli-bridge/references/driving-agy.md +6 -5
- package/bridges/antigravity-cli-bridge/references/models-and-flags.md +14 -11
- package/bridges/codex-cli-bridge/SKILL.md +14 -12
- package/bridges/codex-cli-bridge/bin/codex-exec.sh +16 -15
- package/bridges/codex-cli-bridge/bin/codex-exec.test.mjs +9 -9
- package/bridges/codex-cli-bridge/bin/codex-review.sh +14 -13
- package/bridges/codex-cli-bridge/bin/codex-review.test.mjs +8 -8
- package/bridges/codex-cli-bridge/capability.json +4 -4
- package/bridges/codex-cli-bridge/references/driving-codex.md +2 -2
- package/bridges/codex-cli-bridge/references/sandbox-and-flags.md +6 -6
- package/capability.json +1 -1
- package/package.json +1 -1
- package/references/modes/bridge-settings.md +2 -2
- package/references/modes/now.md +30 -0
- package/tools/bridge-settings.mjs +1 -1
- package/tools/commands.mjs +7 -0
- package/tools/feedback-record.mjs +6 -2
- package/tools/now-cli.mjs +104 -0
- package/tools/now-facts.mjs +67 -0
- package/tools/now-plan-facts.mjs +129 -0
- package/tools/now-render.mjs +162 -0
- package/tools/now-status.mjs +145 -0
- package/tools/plan-shape-facts.mjs +1 -1
- package/tools/queue-audit-cli.mjs +17 -10
- package/tools/queue-audit-rows.mjs +98 -18
- package/tools/queue-audit.mjs +58 -12
- package/tools/queue-row-name.mjs +149 -0
|
@@ -194,10 +194,10 @@ describe('codex-exec.sh — quality-first model/effort guard (1.1)', { concurren
|
|
|
194
194
|
|
|
195
195
|
it('refuses a non-default CODEX_EFFORT', async () => {
|
|
196
196
|
const sb = makeSandbox();
|
|
197
|
-
const r = await run(sb, { env: { CODEX_EFFORT: '
|
|
197
|
+
const r = await run(sb, { env: { CODEX_EFFORT: 'xhigh' } });
|
|
198
198
|
rmSync(sb.root, { recursive: true, force: true });
|
|
199
199
|
assert.notEqual(r.status, 0);
|
|
200
|
-
assert.match(r.stderr, /not the pinned
|
|
200
|
+
assert.match(r.stderr, /not the pinned effort/);
|
|
201
201
|
});
|
|
202
202
|
|
|
203
203
|
it('CODEX_PROBE=1 allows a non-default model and warns loudly', async () => {
|
|
@@ -650,8 +650,8 @@ describe('codex-exec.sh — preflight (unchanged invariants)', { concurrency: 2
|
|
|
650
650
|
|
|
651
651
|
describe('codex-exec.sh — resume entrypoint restates every invariant (3.1)', { concurrency: 2 }, () => {
|
|
652
652
|
const RESUME_INVARIANTS = [
|
|
653
|
-
/(^|\n)resume(\n|$)/, /(^|\n)--ignore-user-config(\n|$)/, /(^|\n)gpt-
|
|
654
|
-
/model_reasoning_effort=
|
|
653
|
+
/(^|\n)resume(\n|$)/, /(^|\n)--ignore-user-config(\n|$)/, /(^|\n)gpt-6-astra(\n|$)/,
|
|
654
|
+
/model_reasoning_effort=high/, /sandbox_mode=workspace-write/,
|
|
655
655
|
/approval_policy=never/, /sandbox_workspace_write\.network_access=false/,
|
|
656
656
|
];
|
|
657
657
|
|
|
@@ -1546,7 +1546,7 @@ describe('codex-exec.sh — dispatch-posture labeling (D5, AD-061)', { concurren
|
|
|
1546
1546
|
const lines = banners(r.stderr);
|
|
1547
1547
|
assert.equal(lines.length, 1, 'EXACTLY ONE banner line per run');
|
|
1548
1548
|
assert.equal(lines[0],
|
|
1549
|
-
'exec posture: model=gpt-
|
|
1549
|
+
'exec posture: model=gpt-6-astra effort=high tier=standard sandbox=workspace-write session=fresh timeout=3600s');
|
|
1550
1550
|
});
|
|
1551
1551
|
|
|
1552
1552
|
it('an ARMED Fast tier rides the banner (tier=priority)', async () => {
|
|
@@ -1642,11 +1642,11 @@ describe('codex-exec.sh — dispatch-posture labeling (D5, AD-061)', { concurren
|
|
|
1642
1642
|
|
|
1643
1643
|
it('a banner field carrying CONTROL BYTES refuses pre-spend (model / effort / tier / timeout / DEL)', async () => {
|
|
1644
1644
|
const cases = [
|
|
1645
|
-
{ CODEX_MODEL: `gpt-
|
|
1646
|
-
{ CODEX_EFFORT: `
|
|
1645
|
+
{ CODEX_MODEL: `gpt-6-astra${String.fromCharCode(1)}` },
|
|
1646
|
+
{ CODEX_EFFORT: `high${String.fromCharCode(2)}` },
|
|
1647
1647
|
{ CODEX_SERVICE_TIER: `priority${String.fromCharCode(3)}` },
|
|
1648
1648
|
{ CODEX_HARD_TIMEOUT: `3600${String.fromCharCode(4)}` },
|
|
1649
|
-
{ CODEX_MODEL: `gpt-
|
|
1649
|
+
{ CODEX_MODEL: `gpt-6-astra${String.fromCharCode(127)}` },
|
|
1650
1650
|
];
|
|
1651
1651
|
for (const env of cases) {
|
|
1652
1652
|
const sb = makeSandbox();
|
|
@@ -2047,7 +2047,7 @@ describe('codex-exec.sh — the pre-spend reservation (D1/D8)', { concurrency: 2
|
|
|
2047
2047
|
assert.equal(r.status, 71, r.stderr);
|
|
2048
2048
|
assert.equal(held.state, 'reserved');
|
|
2049
2049
|
assert.equal(held.wrapperVersion, MANIFEST.version, 'the receipt stamps the bridge version version-sync bumps');
|
|
2050
|
-
assert.deepEqual(held.posture, { model: 'gpt-
|
|
2050
|
+
assert.deepEqual(held.posture, { model: 'gpt-6-astra', effort: 'high', tier: null });
|
|
2051
2051
|
assert.equal(held.capS, 3600);
|
|
2052
2052
|
assert.equal(held.killGraceS, 15);
|
|
2053
2053
|
assert.match(held.contractDigest, /^[0-9a-f]{64}$/);
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
# back as a validated JSON object, with a raw-text fallback.
|
|
22
22
|
#
|
|
23
23
|
# Auth/policy: subscription-only, identical to codex-exec.sh. Quality-first: the
|
|
24
|
-
# review runs on the PINNED model at
|
|
24
|
+
# review runs on the PINNED model at the pinned effort (advisory findings still bear on
|
|
25
25
|
# what ships, so the same pin-integrity guard applies; CODEX_PROBE=1 relaxes it for
|
|
26
26
|
# a throwaway probe only).
|
|
27
27
|
#
|
|
@@ -39,7 +39,7 @@ set -euo pipefail
|
|
|
39
39
|
case "${1:-}" in
|
|
40
40
|
--help|-h)
|
|
41
41
|
cat <<'HELP'
|
|
42
|
-
codex-review — read-only ADVISORY review by the OpenAI Codex CLI (subscription-only; the PINNED model at
|
|
42
|
+
codex-review — read-only ADVISORY review by the OpenAI Codex CLI (subscription-only; the PINNED model at the pinned effort).
|
|
43
43
|
|
|
44
44
|
Usage:
|
|
45
45
|
codex-review plan <plan-file> [--nonce <n>]
|
|
@@ -91,7 +91,7 @@ Receipt:
|
|
|
91
91
|
|
|
92
92
|
Settings file (KEY=VALUE, parsed never sourced; env wins over file, file wins over built-in default):
|
|
93
93
|
${XDG_CONFIG_HOME:-~/.config}/agent-workflow/bridge-settings.conf
|
|
94
|
-
CODEX_SERVICE_TIER — service tier: 'priority' (Fast —
|
|
94
|
+
CODEX_SERVICE_TIER — service tier: 'priority' (Fast — "2x speed, increased usage", the codex catalog's own words for gpt-6-astra, cache fetched 2026-09-05; it states no credit-rate figure); a consented SPEND knob, default off (standard tier)
|
|
95
95
|
CODEX_HARD_TIMEOUT — hard wall-clock cap, integer seconds 1..86400 (built-in default 1800)
|
|
96
96
|
CODEX_REVIEW_MAX_TOTAL_BYTES — inline-payload cap, integer bytes 1..100000000 (default 1500000); above it the diff rides via a git-dir temp file
|
|
97
97
|
|
|
@@ -279,15 +279,15 @@ aw_resolve_timeout_bin() {
|
|
|
279
279
|
printf '%s' "$bin"
|
|
280
280
|
}
|
|
281
281
|
|
|
282
|
-
DEFAULT_CODEX_MODEL="gpt-
|
|
283
|
-
DEFAULT_CODEX_EFFORT="
|
|
282
|
+
DEFAULT_CODEX_MODEL="gpt-6-astra"
|
|
283
|
+
DEFAULT_CODEX_EFFORT="high"
|
|
284
284
|
# Review-receipt identity (AD-038). AW_BRIDGE_VERSION mirrors this bridge's SKILL.md/capability.json
|
|
285
285
|
# version (drift-guarded by codex-review.test.mjs against capability.json).
|
|
286
286
|
AW_RECEIPT_BACKEND="codex"
|
|
287
|
-
AW_BRIDGE_VERSION="3.
|
|
287
|
+
AW_BRIDGE_VERSION="3.8.0" # aw-version-anchor
|
|
288
288
|
CODEX_MODEL="${CODEX_MODEL:-$DEFAULT_CODEX_MODEL}"
|
|
289
289
|
CODEX_EFFORT="${CODEX_EFFORT:-$DEFAULT_CODEX_EFFORT}"
|
|
290
|
-
# Generous hard cap for a slow
|
|
290
|
+
# Generous hard cap for a slow review at the pinned effort (subscription latency varies).
|
|
291
291
|
CODEX_HARD_TIMEOUT="${CODEX_HARD_TIMEOUT:-1800}"
|
|
292
292
|
# Above this assembled-payload size (bytes), the diff goes via a git-dir-local temp
|
|
293
293
|
# file instead of inline — never truncated.
|
|
@@ -298,11 +298,12 @@ CODEX_REVIEW_MAX_TOTAL_BYTES="${CODEX_REVIEW_MAX_TOTAL_BYTES:-1500000}"
|
|
|
298
298
|
# file), so the budget is pinned at the DEFAULT inline-payload cap — the map can never outgrow the
|
|
299
299
|
# whole payload, and every realistic repo's map assembles byte-unchanged.
|
|
300
300
|
AW_REVIEW_MAP_BUDGET_BYTES=1500000
|
|
301
|
-
# Codex service tier (quality-neutral speed knob
|
|
301
|
+
# Codex service tier (quality-neutral speed knob): default EMPTY ⇒ no
|
|
302
302
|
# service_tier flag (standard tier) — enabling Fast is a consented per-host SPEND act, never a
|
|
303
303
|
# silent default. The only server-catalog tier id on this subscription is 'priority' (catalog
|
|
304
|
-
# display name "Fast":
|
|
305
|
-
#
|
|
304
|
+
# display name "Fast": "2x speed, increased usage" in the catalog's own words for gpt-6-astra, cache
|
|
305
|
+
# fetched 2026-09-05; it states no credit-rate figure; quality-neutral — same model). codex itself
|
|
306
|
+
# accepts ANY -c service_tier string silently (probe-verified), so
|
|
306
307
|
# the wrapper validates the effective value: an unsupported one warns and runs on the standard
|
|
307
308
|
# tier — a typo can never silently masquerade as Fast.
|
|
308
309
|
CODEX_SERVICE_TIER="${CODEX_SERVICE_TIER:-}"
|
|
@@ -365,13 +366,13 @@ if [[ "${CODEX_PROBE:-}" == "1" ]]; then
|
|
|
365
366
|
else
|
|
366
367
|
if [[ "$CODEX_MODEL" != "$DEFAULT_CODEX_MODEL" ]]; then
|
|
367
368
|
echo "error: CODEX_MODEL='$CODEX_MODEL' is not the pinned model '$DEFAULT_CODEX_MODEL'." >&2
|
|
368
|
-
echo " A delegated review must run on the pinned model at
|
|
369
|
+
echo " A delegated review must run on the pinned model at the pinned effort (quality-first)." >&2
|
|
369
370
|
echo " For a throwaway probe whose result is effort-independent, set CODEX_PROBE=1." >&2
|
|
370
371
|
exit 2
|
|
371
372
|
fi
|
|
372
373
|
if [[ "$CODEX_EFFORT" != "$DEFAULT_CODEX_EFFORT" ]]; then
|
|
373
|
-
echo "error: CODEX_EFFORT='$CODEX_EFFORT' is not the pinned
|
|
374
|
-
echo " A delegated review must run at
|
|
374
|
+
echo "error: CODEX_EFFORT='$CODEX_EFFORT' is not the pinned effort '$DEFAULT_CODEX_EFFORT'." >&2
|
|
375
|
+
echo " A delegated review must run at the pinned reasoning effort (quality-first)." >&2
|
|
375
376
|
echo " For a throwaway probe whose result is effort-independent, set CODEX_PROBE=1." >&2
|
|
376
377
|
exit 2
|
|
377
378
|
fi
|
|
@@ -172,10 +172,10 @@ describe('codex-review.sh — quality-first model/effort guard (1.1)', { concurr
|
|
|
172
172
|
|
|
173
173
|
it('refuses a non-default CODEX_EFFORT', async () => {
|
|
174
174
|
const sb = makeSandbox();
|
|
175
|
-
const r = await run(sb, { env: { CODEX_EFFORT: '
|
|
175
|
+
const r = await run(sb, { env: { CODEX_EFFORT: 'xhigh' } });
|
|
176
176
|
rmSync(sb.root, { recursive: true, force: true });
|
|
177
177
|
assert.notEqual(r.status, 0);
|
|
178
|
-
assert.match(r.stderr, /not the pinned
|
|
178
|
+
assert.match(r.stderr, /not the pinned effort/);
|
|
179
179
|
});
|
|
180
180
|
|
|
181
181
|
it('CODEX_PROBE=1 relaxes the guard and warns', async () => {
|
|
@@ -1646,8 +1646,8 @@ describe('codex-review.sh — dispatch-posture labeling (D5)', { concurrency: 2
|
|
|
1646
1646
|
const receipts = readReceipts(sb.repo);
|
|
1647
1647
|
rmSync(sb.root, { recursive: true, force: true });
|
|
1648
1648
|
assert.equal(r.status, 0, r.stderr);
|
|
1649
|
-
assert.match(r.stderr, /review posture: model=gpt-
|
|
1650
|
-
assert.deepEqual(receipts[0].posture, { model: 'gpt-
|
|
1649
|
+
assert.match(r.stderr, /review posture: model=gpt-6-astra effort=high tier=standard/, 'the banner states the actual run posture');
|
|
1650
|
+
assert.deepEqual(receipts[0].posture, { model: 'gpt-6-astra', effort: 'high', tier: null }, 'banner ↔ receipt parity (standard tier = null)');
|
|
1651
1651
|
assert.deepEqual(Object.keys(receipts[0]), Object.keys(RECEIPT_FIXTURE), 'fixture key set + order');
|
|
1652
1652
|
});
|
|
1653
1653
|
|
|
@@ -1657,7 +1657,7 @@ describe('codex-review.sh — dispatch-posture labeling (D5)', { concurrency: 2
|
|
|
1657
1657
|
const receipts = readReceipts(sb.repo);
|
|
1658
1658
|
rmSync(sb.root, { recursive: true, force: true });
|
|
1659
1659
|
assert.equal(r.status, 0, r.stderr);
|
|
1660
|
-
assert.match(r.stderr, /review posture: model=gpt-
|
|
1660
|
+
assert.match(r.stderr, /review posture: model=gpt-6-astra effort=high tier=priority/);
|
|
1661
1661
|
assert.equal(receipts[0].posture.tier, 'priority');
|
|
1662
1662
|
});
|
|
1663
1663
|
|
|
@@ -1674,7 +1674,7 @@ describe('codex-review.sh — dispatch-posture labeling (D5)', { concurrency: 2
|
|
|
1674
1674
|
|
|
1675
1675
|
it('a posture value carrying CONTROL BYTES refuses pre-spend, BEFORE the pinned-model guard', async () => {
|
|
1676
1676
|
const sb = makeSandbox();
|
|
1677
|
-
const r = await run(sb, { env: { CODEX_MODEL: `gpt-
|
|
1677
|
+
const r = await run(sb, { env: { CODEX_MODEL: `gpt-6-astra${String.fromCharCode(1)}` } });
|
|
1678
1678
|
const receipts = readReceipts(sb.repo);
|
|
1679
1679
|
rmSync(sb.root, { recursive: true, force: true });
|
|
1680
1680
|
assert.notEqual(r.status, 0);
|
|
@@ -1689,7 +1689,7 @@ describe('codex-review.sh — dispatch-posture labeling (D5)', { concurrency: 2
|
|
|
1689
1689
|
const receipts = readReceipts(sb.repo);
|
|
1690
1690
|
rmSync(sb.root, { recursive: true, force: true });
|
|
1691
1691
|
assert.equal(r.status, 0, r.stderr);
|
|
1692
|
-
assert.match(r.stderr, /^review posture: model=gpt-
|
|
1692
|
+
assert.match(r.stderr, /^review posture: model=gpt-6-astra effort=high tier=standard timeout=1800s$/m);
|
|
1693
1693
|
assert.deepEqual(Object.keys(receipts[0].posture), ['model', 'effort', 'tier'], 'timeout never enters the receipt posture');
|
|
1694
1694
|
});
|
|
1695
1695
|
|
|
@@ -1715,7 +1715,7 @@ describe('codex-review.sh — dispatch-posture labeling (D5)', { concurrency: 2
|
|
|
1715
1715
|
|
|
1716
1716
|
it('a DEL (0x7f) byte in a banner field refuses pre-spend like the C0 range', async () => {
|
|
1717
1717
|
const sb = makeSandbox();
|
|
1718
|
-
const r = await run(sb, { env: { CODEX_MODEL: `gpt-
|
|
1718
|
+
const r = await run(sb, { env: { CODEX_MODEL: `gpt-6-astra${String.fromCharCode(127)}` } });
|
|
1719
1719
|
const receipts = readReceipts(sb.repo);
|
|
1720
1720
|
rmSync(sb.root, { recursive: true, force: true });
|
|
1721
1721
|
assert.notEqual(r.status, 0);
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
"schema": 1,
|
|
4
4
|
"name": "codex-cli-bridge",
|
|
5
5
|
"kind": "execution-backend",
|
|
6
|
-
"version": "3.
|
|
7
|
-
"posture": { "model": "gpt-
|
|
6
|
+
"version": "3.8.0",
|
|
7
|
+
"posture": { "model": "gpt-6-astra", "effort": "high", "tier": null },
|
|
8
8
|
"provides": ["execute", "review"],
|
|
9
9
|
"roles": {
|
|
10
10
|
"execute": {
|
|
@@ -141,7 +141,7 @@
|
|
|
141
141
|
],
|
|
142
142
|
"guardrails": [
|
|
143
143
|
{ "value": "read-only sandbox — codex cannot edit, create or delete a file", "enforcement": "enforced", "source": "bin/codex-review.sh" },
|
|
144
|
-
{ "value": "runs on the pinned model at
|
|
144
|
+
{ "value": "runs on the pinned model at the pinned effort", "enforcement": "enforced", "condition": "unless CODEX_PROBE=1 relaxes the guard for a throwaway probe", "source": "bin/codex-review.sh" },
|
|
145
145
|
{ "value": "a successful review appends one receipt line the review-state gate reads", "enforcement": "enforced", "condition": "a receipt write failure warns and the review still succeeds — the tree then reads un-receipted", "source": "capability.json roles.review.contract.receipt" }
|
|
146
146
|
],
|
|
147
147
|
"customHooks": ["CODEX_PROBE"]
|
|
@@ -193,7 +193,7 @@
|
|
|
193
193
|
"values": ["priority"],
|
|
194
194
|
"default": null,
|
|
195
195
|
"appliesTo": ["codex-exec", "codex-review"],
|
|
196
|
-
"effect": "codex service tier; 'priority' (catalog display name Fast) =
|
|
196
|
+
"effect": "codex service tier; 'priority' (catalog display name Fast) = \"2x speed, increased usage\" in the codex catalog's own words for gpt-6-astra (cache fetched 2026-09-05); it states no credit-rate figure — quality-neutral (same model). Unset/empty ⇒ no service_tier flag (standard tier). SPEND KNOB: enabling it is a consented per-host act, never a default. codex itself accepts any -c service_tier string silently, so the wrapper validates the value."
|
|
197
197
|
},
|
|
198
198
|
{
|
|
199
199
|
"key": "CODEX_HARD_TIMEOUT",
|
|
@@ -20,7 +20,7 @@ judgment.
|
|
|
20
20
|
|
|
21
21
|
## Quality-first: model & effort are pinned
|
|
22
22
|
|
|
23
|
-
Delegated codex work ALWAYS runs on the PINNED model at
|
|
23
|
+
Delegated codex work ALWAYS runs on the PINNED model at the pinned effort: `gpt-6-astra` / `high` are **pinned**
|
|
24
24
|
and a non-default `CODEX_MODEL`/`CODEX_EFFORT` is **refused** (exit 2). That the pinned id is still the
|
|
25
25
|
strongest selectable model is a hand-checked claim with no automated gate and no recorded date — see
|
|
26
26
|
SKILL.md. Do not try to "tune down" the
|
|
@@ -92,7 +92,7 @@ codex-exec --resume <session-id> <file|-> # explicit session id
|
|
|
92
92
|
|
|
93
93
|
Resume continues the SAME codex session, so you avoid re-sending the original context. It runs through
|
|
94
94
|
the wrapper, which **re-establishes every invariant** (subscription-only `*_API_KEY` scrub,
|
|
95
|
-
`--ignore-user-config`, the pinned `gpt-
|
|
95
|
+
`--ignore-user-config`, the pinned `gpt-6-astra`/`high`) and **restates the full posture via `-c`** —
|
|
96
96
|
because `codex exec resume` resets the sandbox/approval/network posture and rejects `-s`/`--add-dir`/`-C`,
|
|
97
97
|
the wrapper passes `-c sandbox_mode=workspace-write -c approval_policy=never -c
|
|
98
98
|
sandbox_workspace_write.network_access=false` explicitly. A resume takes no passthrough flags and an
|
|
@@ -47,7 +47,7 @@ carries the session id) into the run trace, with stderr merged into it; `--color
|
|
|
47
47
|
`--color`, which stays on the fresh lane), so the resume lane is no longer the odd one out: it used
|
|
48
48
|
to print its final message straight to stdout with the event stream nowhere, which left the very
|
|
49
49
|
mode a nested-sandbox incident fired on without a structured evidence surface. Net effect: the wrapper prints just the final answer. **Reasoning still runs at
|
|
50
|
-
|
|
50
|
+
the pinned effort** — quality is unchanged; only the *noise* is dropped. On success `codex-exec` extracts the
|
|
51
51
|
session id from the trace and records it to `${CODEX_SESSION_FILE:-./.codex-last-session}` (so
|
|
52
52
|
`--resume-last` can find it) and echoes `session: <id>` to stderr. On a missing/empty final-message
|
|
53
53
|
file it falls back to the trace tail (loud, never silent).
|
|
@@ -63,8 +63,8 @@ failure is proven.
|
|
|
63
63
|
|
|
64
64
|
## Quality-first guard (pinned model & effort)
|
|
65
65
|
|
|
66
|
-
The wrappers default `CODEX_MODEL=gpt-
|
|
67
|
-
non-default — delegated work always uses the PINNED model at
|
|
66
|
+
The wrappers default `CODEX_MODEL=gpt-6-astra` and `CODEX_EFFORT=high` and **refuse** (exit 2, loud) any
|
|
67
|
+
non-default — delegated work always uses the PINNED model at the pinned effort; quality is never traded for
|
|
68
68
|
quota. (Whether the pinned id is still the strongest selectable model is a hand-checked claim with no
|
|
69
69
|
automated gate — see SKILL.md.) `CODEX_PROBE=1` relaxes this for a throwaway, effort-independent probe only (echoed loudly), and
|
|
70
70
|
a probe still runs on the subscription, in the sandbox, with clean capture.
|
|
@@ -164,7 +164,7 @@ EVIDENCE posture as a fresh run — `-o` for the final message, `--json` into th
|
|
|
164
164
|
|
|
165
165
|
A backgrounded/hung run survives otherwise, so both wrappers wrap codex in `timeout`/`gtimeout`
|
|
166
166
|
(`--kill-after=15s`): `CODEX_HARD_TIMEOUT` defaults to **3600s (exec)** / **1800s (review)**, sized for a
|
|
167
|
-
slow
|
|
167
|
+
slow run at the pinned effort. Exit 124/137 ⇒ "exceeded the hard cap" (raise the cap or narrow the task). If neither
|
|
168
168
|
`timeout` nor `gtimeout` is on `PATH`, `codex-exec` **warns loudly and runs uncapped** — never a silent
|
|
169
169
|
no-op — while `codex-review` **refuses pre-spend** (the fail-closed hard-timeout preflight).
|
|
170
170
|
|
|
@@ -205,8 +205,8 @@ exec` over the precomputed diff instead, keeping every invariant intact.
|
|
|
205
205
|
| `-o, --output-last-message <f>` | write ONLY the final message (clean capture) |
|
|
206
206
|
| `--json` | structured event stream (`thread.started` ⇒ session id) |
|
|
207
207
|
| `--output-schema <f>` | constrain output to a JSON schema (`CODEX_REVIEW_SCHEMA=1`) |
|
|
208
|
-
| `-m <model>` | model (wrapper default `gpt-
|
|
209
|
-
| `-c model_reasoning_effort=<effort>` | reasoning effort (wrapper default `
|
|
208
|
+
| `-m <model>` | model (wrapper default `gpt-6-astra`, pinned via `CODEX_MODEL`) |
|
|
209
|
+
| `-c model_reasoning_effort=<effort>` | reasoning effort (wrapper default `high`, pinned via `CODEX_EFFORT`) |
|
|
210
210
|
| `--ignore-user-config` | do NOT load `$CODEX_HOME/config.toml`; auth still uses `CODEX_HOME` |
|
|
211
211
|
| `--color never` | disable ANSI colour in output |
|
|
212
212
|
|
package/capability.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sabaiway/agent-workflow-kit",
|
|
3
|
-
"version": "12.
|
|
3
|
+
"version": "12.2.0",
|
|
4
4
|
"description": "Portable, cross-agent memory & workflow for AI coding agents — Claude Code, Codex, Cursor, Devin Desktop. One command deploys an AGENTS.md entry point + docs/ai context with cap/archive/index enforcement into any repo.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai-agents",
|
|
@@ -8,7 +8,7 @@ The reader + consent-gated **writer** for the **host-level** bridge settings fil
|
|
|
8
8
|
|
|
9
9
|
| key | bridge | values | note |
|
|
10
10
|
|---|---|---|---|
|
|
11
|
-
| `CODEX_SERVICE_TIER` | codex | `priority` | **SPEND KNOB** — the "Fast" tier:
|
|
11
|
+
| `CODEX_SERVICE_TIER` | codex | `priority` | **SPEND KNOB** — the "Fast" tier: "2x speed, **increased usage**" in the codex catalog's own words for gpt-6-astra (cache fetched 2026-09-05); it states no credit-rate figure; quality-neutral (same model). Default unset ⇒ standard tier. |
|
|
12
12
|
| `CODEX_HARD_TIMEOUT` | codex | integer `1..86400` | hard wall-clock cap (seconds) via `timeout(1)`. |
|
|
13
13
|
| `CODEX_REVIEW_MAX_TOTAL_BYTES` | codex | integer `1..100000000` | codex-review payload size above which the diff rides a temp file (never truncated). |
|
|
14
14
|
| `AGY_HARD_TIMEOUT` | agy | duration `5m`/`30m`/`90s` (unit required, nonzero) | hard wall-clock cap via `timeout(1)`. |
|
|
@@ -25,7 +25,7 @@ The reader + consent-gated **writer** for the **host-level** bridge settings fil
|
|
|
25
25
|
|
|
26
26
|
**Refusals (the guarded contract):** an **unknown key** or an **invalid / out-of-range value** → exit `2` (nothing read of the file, nothing written). A file that already carries **duplicate keys** → exit `1`, named and left **byte-untouched** (fix the duplicates by hand first — the writer never edits blindly around them). A **symlinked / non-regular / unreadable** settings file → exit `1` (refuses to write through it). `--apply` with `--dry-run`, a duplicate op for one key, or a malformed `--set` → usage exit `2`.
|
|
27
27
|
|
|
28
|
-
**Spend consent (D4):** enabling `CODEX_SERVICE_TIER=priority` costs
|
|
28
|
+
**Spend consent (D4):** enabling `CODEX_SERVICE_TIER=priority` costs **increased usage** (the catalog states no credit-rate figure) — a per-host, consented act, never a default. The preview shows the caveat (from the manifest `effect`); confirm with the user before `--apply`. The tool also warns when an env var currently shadows the key you are writing (the env value wins for that session until unset).
|
|
29
29
|
|
|
30
30
|
Output is **English/structured** — **localize it to the user's conversational language** when you narrate.
|
|
31
31
|
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
### Mode: now
|
|
2
|
+
|
|
3
|
+
<!-- opt-in-capability: none — an inspection surface that configures nothing -->
|
|
4
|
+
|
|
5
|
+
Read-only. The single answer to where the work stands. It writes no file, cache, receipt, lock or git state; it never commits and never runs a subscription CLI.
|
|
6
|
+
|
|
7
|
+
Run `node ${CLAUDE_SKILL_DIR}/tools/now-cli.mjs --dir <project> --json`. For a direct terminal render, use `--format=plain|ansi|json`; `--json` is strict sugar for `--format=json`.
|
|
8
|
+
|
|
9
|
+
Render the returned envelope compactly in the user's conversational language. Never paste the JSON and never expose an internal field name. Preserve every fact, evidence label, annotation and withheld cause while translating only the prose around source-language commands, paths and identifiers.
|
|
10
|
+
|
|
11
|
+
The four blocks keep this order:
|
|
12
|
+
|
|
13
|
+
1. **NOW** — every plan in flight, its derived phase, current and next step, then the tree fingerprint, clean state, review verdict lines, final run and red-proof currency. No plan and several plans are rendered states; never pick one silently.
|
|
14
|
+
2. **STEPS** — every ledger row with one of `landed`, `in progress`, `pending` or `unjudged`. The rows are the steps; invent no numbering.
|
|
15
|
+
3. **QUEUE** — every work-carrying row (live, parked, ambiguous) under the full line-numbered heading path it carries, with per-class counts covering every row of the bucket, terminal and record included, and names rather than ids. Only a path through `## Pending / backlog` calls its position priority; every other bucket is archive and calls it position.
|
|
16
|
+
4. **CAMPAIGN** — source-size config state (`absent`, `authored`, `incomplete`, `minted`), caps, roots, recorded over-cap files and aggregate lines. An absent opt-in config is a rendered state.
|
|
17
|
+
|
|
18
|
+
Evidence alone sets a ledger status: the row's path and verb, then the path fact, changed set and exclusion fact. The plan's prose never sets a status. A checked box or terminal marker is only a claim; when evidence contradicts it, print the claim beside the evidence-derived status. Keep anomaly and current red-proof annotations beside the same status too. Every status line names its evidence source.
|
|
19
|
+
|
|
20
|
+
A block that cannot be derived is `WITHHELD` and prints its cause on one line. NOW has two halves, plans and tree, each independently a value or `WITHHELD`; NOW itself is `WITHHELD` only when both are. Render every other block normally.
|
|
21
|
+
|
|
22
|
+
Exit codes:
|
|
23
|
+
|
|
24
|
+
| Code | Meaning |
|
|
25
|
+
|------|---------|
|
|
26
|
+
| 0 | Anything rendered, including default states, contradictions and a WITHHELD block. |
|
|
27
|
+
| 1 | Nothing rendered: every block withheld, each cause printed on stderr; the usual cause is a `--dir` that is not a git work tree. |
|
|
28
|
+
| 2 | Usage: an unknown flag, an invalid or missing value, conflicting `--json` / `--format`, or `--help` combined with anything. |
|
|
29
|
+
|
|
30
|
+
**Invariants:** read-only · the plan's prose never sets status · evidence is shown beside every status · compact user-language render with no JSON or internal field names · `process.exitCode`, never `process.exit()`.
|
|
@@ -273,7 +273,7 @@ export const main = (argv = [], ctx = {}) => {
|
|
|
273
273
|
const body = joinLines(newLines);
|
|
274
274
|
|
|
275
275
|
// The machine surface carries the SAME spend/credit-rate caveats the human preview prints (D4) — a
|
|
276
|
-
// --json consumer must not miss the
|
|
276
|
+
// --json consumer must not miss the spend consent warning the human render shows.
|
|
277
277
|
const jsonBody = (wrote) => ({ path, wrote, noop, changes: changes.map((c) => ({ key: c.key, kind: c.kind, before: c.before, after: c.after })), envShadows, caveats });
|
|
278
278
|
|
|
279
279
|
if (!apply || noop) {
|
package/tools/commands.mjs
CHANGED
|
@@ -84,6 +84,13 @@ const CATALOG = [
|
|
|
84
84
|
kind: READ_ONLY,
|
|
85
85
|
oneLine: 'Show what is installed and at what version, your settings and backends, and what is deployed in this project.',
|
|
86
86
|
},
|
|
87
|
+
{
|
|
88
|
+
key: 'now',
|
|
89
|
+
invocation: invocationOf('now'),
|
|
90
|
+
group: 'Inspect',
|
|
91
|
+
kind: READ_ONLY,
|
|
92
|
+
oneLine: 'Show where work stands: NOW answers the plan and tree, STEPS the evidence-derived ledger state, QUEUE its named positions, and CAMPAIGN its size-practice figures; the plan’s own text never sets a status.',
|
|
93
|
+
},
|
|
87
94
|
{
|
|
88
95
|
key: 'backends',
|
|
89
96
|
invocation: invocationOf('backends'),
|
|
@@ -18,7 +18,11 @@ const NOTES_HEADING = '## Notes';
|
|
|
18
18
|
const TABLE_HEADER = '| # | Claim | Evidence | Verdict | Disposition |';
|
|
19
19
|
const OBJECT_ID = /^(?:[0-9a-f]{40}|[0-9a-f]{64})$/iu;
|
|
20
20
|
const ANCHOR = /^`([^`,\s]+):([1-9][0-9]*)(?:-([1-9][0-9]*))?`$/u;
|
|
21
|
-
|
|
21
|
+
// The row id a checked record hands over, and the ONE home of that grammar: the queue's name
|
|
22
|
+
// judge reads it back for the EXPLICITLY marked form (`— id <ID>`), so every id this writer may
|
|
23
|
+
// legally emit round-trips through the judge — including `FOO`, `TASK-123` and `1-TASK`, which
|
|
24
|
+
// the judge's own heuristic deliberately does not read unmarked.
|
|
25
|
+
export const ROW_ID = '[A-Z0-9][A-Z0-9-]*';
|
|
22
26
|
const QUEUE = new RegExp(`^queue (${ROW_ID})$`, 'u');
|
|
23
27
|
const ALREADY_QUEUED = new RegExp(`^already-queued (${ROW_ID})$`, 'u');
|
|
24
28
|
const REASONED_DISPOSITION = /^(?:declined|folded): (.+)$/u;
|
|
@@ -227,7 +231,7 @@ export const renderRows = (record, { date, recordPath }) => {
|
|
|
227
231
|
return ids.map((id) => {
|
|
228
232
|
const claims = record.claims.filter((claim) => QUEUE.exec(claim.disposition)?.[1] === id);
|
|
229
233
|
return [
|
|
230
|
-
`- [ ] ${
|
|
234
|
+
`- [ ] ${claims[0].claim} — id ${id} (${date})`,
|
|
231
235
|
...claims.map((claim) => ` - ${claim.claim}; verdict ${claim.verdict}; evidence ${claim.anchors.map(rendersAnchor).join(', ')}`),
|
|
232
236
|
` - record: ${recordPath}`,
|
|
233
237
|
` - head: ${record.head}`,
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// The CLI half of `now`: argv, the io seam and the pipeline. The rules live in now-status.mjs, the
|
|
3
|
+
// facts in now-facts.mjs, the phrases in now-render.mjs.
|
|
4
|
+
|
|
5
|
+
import { resolve } from 'node:path';
|
|
6
|
+
import { fail } from '../references/scripts/markdown-blocks.mjs';
|
|
7
|
+
import { isDirectRun } from './direct-run.mjs';
|
|
8
|
+
import { FORMATS, detectSurface } from './surface.mjs';
|
|
9
|
+
import { gatherNowFacts } from './now-facts.mjs';
|
|
10
|
+
import { isWithheld } from './now-status.mjs';
|
|
11
|
+
import { renderNow, toNowViewModel } from './now-render.mjs';
|
|
12
|
+
|
|
13
|
+
const BLOCKS = Object.freeze(['now', 'steps', 'queue', 'campaign']);
|
|
14
|
+
const SCHEMA = 1;
|
|
15
|
+
const FORMAT_FLAG = '--format=';
|
|
16
|
+
const HELP = `now — read-only: where the work stands, in four blocks.
|
|
17
|
+
|
|
18
|
+
Usage:
|
|
19
|
+
node now-cli.mjs [--dir <project>] [--format=<${FORMATS.join('|')}>] [--json]
|
|
20
|
+
|
|
21
|
+
--dir the project to read (default: the current directory).
|
|
22
|
+
--format the output surface; --json is strict sugar for --format=json, and naming both with
|
|
23
|
+
different values is usage.
|
|
24
|
+
--help answered only when it is the whole invocation.
|
|
25
|
+
|
|
26
|
+
Blocks: NOW (the plans in flight, the phase, the current and the next step, the tree), STEPS (the
|
|
27
|
+
ledger rows, one status each), QUEUE (the backlog folded under each row's heading path), CAMPAIGN
|
|
28
|
+
(the size practice). A block that cannot be derived is WITHHELD with its cause on one line.
|
|
29
|
+
|
|
30
|
+
A status is a function of the row's (path, verb) pair and the evidence at that path; the row's prose
|
|
31
|
+
is printed as a claim beside a status it never moves.
|
|
32
|
+
|
|
33
|
+
Exit codes: 0 anything rendered, a withheld block included; 1 nothing rendered at all (a --dir that
|
|
34
|
+
is not a git work tree); 2 usage.
|
|
35
|
+
|
|
36
|
+
Reads only: no store, no receipt, no cache, no lock.`;
|
|
37
|
+
|
|
38
|
+
const valueAt = (argv, index, flag) => {
|
|
39
|
+
const value = argv[index + 1];
|
|
40
|
+
if (value === undefined || value === '' || value.startsWith('-')) throw fail(2, `${flag} takes a value`);
|
|
41
|
+
return value;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export const parseArgv = (argv) => {
|
|
45
|
+
if (argv.includes('--help') || argv.includes('-h')) {
|
|
46
|
+
if (argv.length !== 1) throw fail(2, '--help is answered only when it is the whole invocation');
|
|
47
|
+
return { help: true, dir: null, formats: [] };
|
|
48
|
+
}
|
|
49
|
+
const parsed = argv.reduce((state, arg, index) => {
|
|
50
|
+
if (state.skip) return { ...state, skip: false };
|
|
51
|
+
if (arg === '--dir') return { ...state, dir: valueAt(argv, index, arg), skip: true };
|
|
52
|
+
if (arg === '--format') return { ...state, formats: [...state.formats, valueAt(argv, index, arg)], skip: true };
|
|
53
|
+
if (arg.startsWith(FORMAT_FLAG)) return { ...state, formats: [...state.formats, arg.slice(FORMAT_FLAG.length)] };
|
|
54
|
+
if (arg === '--json') return { ...state, formats: [...state.formats, 'json'], json: true };
|
|
55
|
+
throw fail(2, `unknown argument "${arg}" — run with --help`);
|
|
56
|
+
}, { help: false, dir: null, formats: [], json: false, skip: false });
|
|
57
|
+
if (parsed.json && parsed.formats.some((format) => format !== 'json')) {
|
|
58
|
+
throw fail(2, '--json is strict sugar for --format=json — naming both with different values is usage');
|
|
59
|
+
}
|
|
60
|
+
return parsed;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const resolveSurface = (formats, env, io) => detectSurface({
|
|
64
|
+
argv: formats.map((format) => `${FORMAT_FLAG}${format}`),
|
|
65
|
+
env,
|
|
66
|
+
isTTY: io.isTTY ?? Boolean(process.stdout.isTTY),
|
|
67
|
+
columns: io.columns ?? process.stdout.columns,
|
|
68
|
+
platform: io.platform ?? process.platform,
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
const toEnvelope = (dir, vm) => ({ schema: SCHEMA, command: 'now', dir, ...vm });
|
|
72
|
+
|
|
73
|
+
export const main = (argv, io = {}) => {
|
|
74
|
+
const log = io.log ?? console.log;
|
|
75
|
+
const error = io.error ?? console.error;
|
|
76
|
+
const env = io.env ?? process.env;
|
|
77
|
+
const start = (() => {
|
|
78
|
+
try {
|
|
79
|
+
const options = parseArgv(argv);
|
|
80
|
+
return options.help ? { help: true } : { options, surface: resolveSurface(options.formats, env, io) };
|
|
81
|
+
} catch (err) {
|
|
82
|
+
error(err?.message ?? String(err));
|
|
83
|
+
return { code: err?.exitCode ?? 2 };
|
|
84
|
+
}
|
|
85
|
+
})();
|
|
86
|
+
if (start.code !== undefined) return start.code;
|
|
87
|
+
if (start.help) {
|
|
88
|
+
log(HELP);
|
|
89
|
+
return 0;
|
|
90
|
+
}
|
|
91
|
+
const cwd = resolve(io.cwd ?? process.cwd(), start.options.dir ?? '.');
|
|
92
|
+
// The composed readers spawn git under process.env alone, so the flag must reach them there too.
|
|
93
|
+
process.env.GIT_OPTIONAL_LOCKS = '0';
|
|
94
|
+
const vm = toNowViewModel(gatherNowFacts({ cwd, env: { ...env, GIT_OPTIONAL_LOCKS: '0' } }));
|
|
95
|
+
const blocks = BLOCKS.map((name) => vm[name]);
|
|
96
|
+
if (blocks.every(isWithheld)) {
|
|
97
|
+
for (const cause of new Set(blocks.map(({ withheld }) => withheld))) error(cause);
|
|
98
|
+
return 1;
|
|
99
|
+
}
|
|
100
|
+
log(start.surface.mode === 'json' ? JSON.stringify(toEnvelope(cwd, vm), null, 2) : renderNow(vm, start.surface));
|
|
101
|
+
return 0;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
if (isDirectRun(import.meta.url)) process.exitCode = main(process.argv.slice(2));
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { buildSummaryState, isTreeClean } from './core-evidence.mjs';
|
|
4
|
+
import { readRegularFileNoFollow } from './fs-read-nofollow.mjs';
|
|
5
|
+
import { resolveGitLocation } from './git-env.mjs';
|
|
6
|
+
import { auditQueue } from './queue-audit.mjs';
|
|
7
|
+
import { loadSourceSizeConfig, practiceFacts } from './source-size-config.mjs';
|
|
8
|
+
import { gatherPlanFacts, readSummaryFacts } from './now-plan-facts.mjs';
|
|
9
|
+
import { isWithheld } from './now-status.mjs';
|
|
10
|
+
|
|
11
|
+
const QUEUE_REL = 'docs/plans/queue.md';
|
|
12
|
+
const BLOCKS = Object.freeze(['plans', 'tree', 'queue', 'campaign']);
|
|
13
|
+
|
|
14
|
+
const attempt = (label, read) => {
|
|
15
|
+
try {
|
|
16
|
+
return read();
|
|
17
|
+
} catch (error) {
|
|
18
|
+
return { withheld: `${label}: ${error?.message ?? error}` };
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const readQueueFacts = (cwd, deps) => {
|
|
23
|
+
const read = readRegularFileNoFollow(join(cwd, QUEUE_REL), deps.io ?? {});
|
|
24
|
+
if (read.outcome !== 'ok') throw new Error(`${QUEUE_REL} is not a readable regular file (${read.className ?? read.code ?? read.outcome})`);
|
|
25
|
+
const { rows, counts, total } = auditQueue(read.content, { label: QUEUE_REL });
|
|
26
|
+
return { path: QUEUE_REL, rows, counts, total };
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// The practice is opt-in: an absent declaration is a rendered STATE, only an unreadable one is withheld.
|
|
30
|
+
const readCampaignFacts = (cwd, deps) => {
|
|
31
|
+
const loaded = loadSourceSizeConfig(cwd, deps);
|
|
32
|
+
return loaded.state === 'absent' ? { state: loaded.state } : { state: loaded.state, ...practiceFacts(loaded.config) };
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
// A store the summary cannot trust never attests: the tree is withheld with the store's own cause.
|
|
36
|
+
const describeUntrustedStore = (summary) => {
|
|
37
|
+
if (summary.evidenceUnavailable) return `the core-evidence store is malformed or unreadable (${summary.storeReadError ?? `${summary.storeMalformed} malformed line(s)`})`;
|
|
38
|
+
if (summary.receiptsUnavailable) return `the review receipts store is malformed or unreadable (${summary.receiptsReadError ?? `${summary.receiptsMalformed} malformed line(s)`})`;
|
|
39
|
+
return null;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const toTreeFacts = (summary, clean) => {
|
|
43
|
+
const untrusted = describeUntrustedStore(summary);
|
|
44
|
+
if (untrusted) return { withheld: untrusted };
|
|
45
|
+
const { redProofs, receipts } = readSummaryFacts(summary);
|
|
46
|
+
return { fingerprint: summary.fingerprint, clean, verdicts: receipts.verdicts, finalRun: receipts.finalRun, redProofs };
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const gatherNowFacts = ({ cwd, env: given = process.env, deps = {} }) => {
|
|
50
|
+
// Every reader honouring an env argument spawns under this one: a plain `git diff` rewrites .git/index without the flag.
|
|
51
|
+
const env = { ...given, GIT_OPTIONAL_LOCKS: '0' };
|
|
52
|
+
const location = resolveGitLocation(cwd, { spawn: deps.spawn ?? spawnSync, env });
|
|
53
|
+
if (location.state !== 'work-tree') {
|
|
54
|
+
const withheld = `${cwd} is not a git work tree (${location.state}: ${location.cause})`;
|
|
55
|
+
return Object.fromEntries(BLOCKS.map((block) => [block, { withheld }]));
|
|
56
|
+
}
|
|
57
|
+
const root = location.top;
|
|
58
|
+
const summary = attempt('the evidence summary', () => deps.summary ?? buildSummaryState({ cwd: root, env }));
|
|
59
|
+
return {
|
|
60
|
+
plans: attempt('the plans in flight', () => ({
|
|
61
|
+
entries: gatherPlanFacts({ cwd: root, env, deps }).plans,
|
|
62
|
+
})),
|
|
63
|
+
tree: isWithheld(summary) ? summary : attempt('the tree state', () => toTreeFacts(summary, isTreeClean(root, { env }))),
|
|
64
|
+
queue: attempt('the queue', () => readQueueFacts(root, deps)),
|
|
65
|
+
campaign: attempt('the practice', () => readCampaignFacts(root, deps)),
|
|
66
|
+
};
|
|
67
|
+
};
|