hadara 0.3.3-rc.0 → 0.3.4-rc.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 +28 -20
- package/dist/cli/dashboard.js +13 -6
- package/dist/cli/evidence.js +42 -0
- package/dist/cli/handoff.js +13 -0
- package/dist/cli/init.js +20 -2
- package/dist/cli/main.js +3 -0
- package/dist/cli/package-smoke.js +33 -1
- package/dist/cli/release-closeout.js +22 -0
- package/dist/context/context-pack.js +91 -7
- package/dist/context/session-start.js +39 -0
- package/dist/context/state-projection.js +15 -2
- package/dist/core/schema.js +8 -0
- package/dist/handoff/handoff-stale-problems.js +150 -0
- package/dist/schemas/context-pack.schema.json +23 -0
- package/dist/schemas/evidence-summary.schema.json +73 -0
- package/dist/schemas/handoff-stale-problems.schema.json +64 -0
- package/dist/schemas/package-recycle.schema.json +150 -0
- package/dist/schemas/release-closeout.schema.json +39 -0
- package/dist/schemas/schema-index.json +28 -0
- package/dist/schemas/session-start.schema.json +30 -0
- package/dist/schemas/smoke-evidence-summary.schema.json +1 -1
- package/dist/services/capability-registry.js +115 -0
- package/dist/services/dashboard-bootstrap.js +3 -3
- package/dist/services/evidence-summary.js +66 -0
- package/dist/services/package-recycle.js +709 -0
- package/dist/services/release-closeout.js +136 -0
- package/dist/services/workbench-next-actions.js +2 -0
- package/dist/task/task-finalize.js +36 -5
- package/dist/task/task-lifecycle.js +6 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
</p>
|
|
6
6
|
|
|
7
7
|
<p align="center">
|
|
8
|
-
<img alt="Stable npm release" src="https://img.shields.io/badge/npm-0.3.
|
|
9
|
-
<img alt="Source version" src="https://img.shields.io/badge/source-0.3.
|
|
8
|
+
<img alt="Stable npm release" src="https://img.shields.io/badge/npm-0.3.3-blue">
|
|
9
|
+
<img alt="Source version" src="https://img.shields.io/badge/source-0.3.4--rc.0-blue">
|
|
10
10
|
<img alt="Node.js" src="https://img.shields.io/badge/node-%3E%3D22-brightgreen">
|
|
11
11
|
<img alt="License" src="https://img.shields.io/badge/license-MIT-lightgrey">
|
|
12
12
|
</p>
|
|
@@ -24,31 +24,38 @@ This repository is both the HADARA source checkout and the HADARA protocol works
|
|
|
24
24
|
Current stable npm release:
|
|
25
25
|
|
|
26
26
|
```text
|
|
27
|
-
hadara@0.3.
|
|
27
|
+
hadara@0.3.3
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
Current release candidate:
|
|
30
|
+
Current source release candidate:
|
|
31
|
+
|
|
32
|
+
```text
|
|
33
|
+
hadara@0.3.4-rc.0
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Previous published release candidate:
|
|
31
37
|
|
|
32
38
|
```text
|
|
33
39
|
hadara@0.3.3-rc.0
|
|
34
40
|
```
|
|
35
41
|
|
|
36
|
-
The 0.3.
|
|
42
|
+
The 0.3.4 source line is an agent UX hardening release candidate after stable 0.3.3. It keeps the context-routing and finalize-first lifecycle surfaces, then improves the commands agents actually use during HADARA development: session start, context pack, evidence summary, handoff stale-problem checks, release closeout, package recycle, generated init guidance, and close/finalize diagnostics.
|
|
37
43
|
|
|
38
|
-
Phase labels are internal implementation phases, not npm release-candidate labels. The stable `0.3.
|
|
44
|
+
Phase labels are internal implementation phases, not npm release-candidate labels. The stable `0.3.3` package is the default install target; `0.3.4-rc.0` is the current source candidate and must not be treated as published until an approval-gated publish capsule completes.
|
|
39
45
|
|
|
40
46
|
| Surface | Status |
|
|
41
47
|
|---|---|
|
|
42
|
-
| Current stable | [`hadara@0.3.
|
|
43
|
-
|
|
|
44
|
-
| Previous RC | [`hadara@0.3.
|
|
48
|
+
| Current stable | [`hadara@0.3.3`](docs/RELEASE_NOTES.md#033) |
|
|
49
|
+
| Source candidate | [`hadara@0.3.4-rc.0`](docs/RELEASE_NOTES.md#034-rc0) |
|
|
50
|
+
| Previous RC | [`hadara@0.3.3-rc.0`](docs/RELEASE_NOTES.md#033-rc0) |
|
|
51
|
+
| Previous stable | [`hadara@0.3.2`](docs/RELEASE_NOTES.md#032) |
|
|
45
52
|
| Historical RCs | See [Release Notes](docs/RELEASE_NOTES.md). |
|
|
46
53
|
| GitHub Release | Secondary target, approval-gated. |
|
|
47
54
|
| Docker image | Deferred. |
|
|
48
55
|
| PyPI/Python package | `hadara==0.2.0rc1` published preview bridge. |
|
|
49
56
|
| Installer scripts / USB launchers | Deferred. |
|
|
50
57
|
|
|
51
|
-
No release command should publish, create a GitHub Release, build Docker images, upload artifacts, or load token values unless an operator explicitly approves the mutation path for the active release capsule.
|
|
58
|
+
No release command should publish, create a GitHub Release, build Docker images, upload artifacts, or load token values unless an operator explicitly approves the mutation path for the active release capsule. Stable `0.3.3` is the npm package line until the `0.3.4-rc.0` publish capsule completes; GitHub Release, Docker/PyPI publish, installer execution, and MCP release/package execution remain separate explicit mutations.
|
|
52
59
|
|
|
53
60
|
## Install
|
|
54
61
|
|
|
@@ -57,7 +64,7 @@ Requires Node.js 22.
|
|
|
57
64
|
Install the stable release:
|
|
58
65
|
|
|
59
66
|
```bash
|
|
60
|
-
npm install -g hadara@0.3.
|
|
67
|
+
npm install -g hadara@0.3.3
|
|
61
68
|
hadara help
|
|
62
69
|
hadara doctor --json
|
|
63
70
|
```
|
|
@@ -65,11 +72,11 @@ hadara doctor --json
|
|
|
65
72
|
Run without a global install:
|
|
66
73
|
|
|
67
74
|
```bash
|
|
68
|
-
npx hadara@0.3.
|
|
69
|
-
npx hadara@0.3.
|
|
75
|
+
npx hadara@0.3.3 help
|
|
76
|
+
npx hadara@0.3.3 doctor --json
|
|
70
77
|
```
|
|
71
78
|
|
|
72
|
-
Evaluate the release candidate explicitly:
|
|
79
|
+
Evaluate the previous release candidate explicitly:
|
|
73
80
|
|
|
74
81
|
```bash
|
|
75
82
|
npm install -g hadara@0.3.3-rc.0
|
|
@@ -80,11 +87,11 @@ For release or recycle evidence, prefer an isolated prefix install when PATH, gl
|
|
|
80
87
|
|
|
81
88
|
```bash
|
|
82
89
|
tmp="$(mktemp -d)"
|
|
83
|
-
npm --prefix "$tmp" install hadara@0.3.
|
|
90
|
+
npm --prefix "$tmp" install hadara@0.3.3
|
|
84
91
|
"$tmp/node_modules/.bin/hadara" version --json
|
|
85
92
|
```
|
|
86
93
|
|
|
87
|
-
`npx hadara@0.3.
|
|
94
|
+
`npx hadara@0.3.3 ...` remains convenient for normal use. The isolated installed-bin path is stronger proof that the published package installed and executed from the intended package tree.
|
|
88
95
|
|
|
89
96
|
## What HADARA Gives You
|
|
90
97
|
|
|
@@ -122,10 +129,11 @@ hadara help command task.close
|
|
|
122
129
|
|
|
123
130
|
## Primary Capsule Lifecycle
|
|
124
131
|
|
|
125
|
-
The 0.3.
|
|
132
|
+
The 0.3.4 primary path is intentionally small. Agents should start with compact context and use `task finalize` as the default lifecycle close path:
|
|
126
133
|
|
|
127
134
|
```bash
|
|
128
135
|
hadara task next --json
|
|
136
|
+
hadara session start --task T-XXXX --json
|
|
129
137
|
hadara task create "implement a focused change" --json
|
|
130
138
|
hadara task status --task T-XXXX --json
|
|
131
139
|
hadara evidence add-command --task T-XXXX --summary "..." --result passed --category validation --idempotency-key "command:T-XXXX:check" --json
|
|
@@ -260,7 +268,7 @@ Dashboard, TUI, Hermes, MCP, installer, package, release, and run commands stay
|
|
|
260
268
|
|
|
261
269
|
## Safety Boundaries
|
|
262
270
|
|
|
263
|
-
HADARA 0.3.
|
|
271
|
+
HADARA 0.3.4-rc.0 is not:
|
|
264
272
|
|
|
265
273
|
- a full agent runtime;
|
|
266
274
|
- Rack/enterprise behavior;
|
|
@@ -300,7 +308,7 @@ Portable/local state is not committed. Project docs, Task Capsules, and reduced
|
|
|
300
308
|
|
|
301
309
|
`evidence.jsonl` is the canonical Task Capsule evidence source. `EVIDENCE.md` is a non-canonical human summary that can help review validation history, but it must not be treated as the source of truth for rebuild, migration, or resolution logic.
|
|
302
310
|
|
|
303
|
-
0.3.
|
|
311
|
+
0.3.4-rc.0 does not implement `hadara evidence rebuild --json` or an execute mode. Future rebuild work must first define whether a difference is formatting regeneration, managed-section drift, or data inconsistency before reporting `wouldChange`. Any later write-capable rebuild flow must be dry-run-first, reviewed, and before-hash guarded before it rewrites derived Markdown.
|
|
304
312
|
|
|
305
313
|
## Development / Contributing
|
|
306
314
|
|
|
@@ -313,7 +321,7 @@ hadara init --profile standard
|
|
|
313
321
|
hadara init --profile governed
|
|
314
322
|
```
|
|
315
323
|
|
|
316
|
-
Every profile generates `docs/TASK_WORKFLOW_COMMANDS.md` so fresh projects get the current 0.3.
|
|
324
|
+
Every profile generates `docs/TASK_WORKFLOW_COMMANDS.md` so fresh projects get the current 0.3.4 context-aware finalize-first lifecycle loop plus low-level proof-boundary reference commands.
|
|
317
325
|
|
|
318
326
|
| Profile | Use When |
|
|
319
327
|
|---|---|
|
package/dist/cli/dashboard.js
CHANGED
|
@@ -20,7 +20,6 @@ const dashboard_heavy_projection_1 = require("../services/dashboard-heavy-projec
|
|
|
20
20
|
const evidence_lint_1 = require("../services/evidence-lint");
|
|
21
21
|
const evidence_list_1 = require("../services/evidence-list");
|
|
22
22
|
const dashboard_timeline_1 = require("../services/dashboard-timeline");
|
|
23
|
-
const operational_debt_1 = require("../services/operational-debt");
|
|
24
23
|
const operations_status_service_1 = require("../services/operations-status-service");
|
|
25
24
|
const task_read_model_1 = require("../services/task-read-model");
|
|
26
25
|
const task_workbench_1 = require("../services/task-workbench");
|
|
@@ -93,8 +92,11 @@ function createDashboardApiResponse(projectRoot, requestUrl, method) {
|
|
|
93
92
|
if (!url || !url.pathname.startsWith('/api/'))
|
|
94
93
|
return null;
|
|
95
94
|
const headOnly = normalizedMethod === 'HEAD';
|
|
96
|
-
if (url.pathname === '/api/status')
|
|
97
|
-
|
|
95
|
+
if (url.pathname === '/api/status') {
|
|
96
|
+
// Dashboard clients fetch operational debt separately; keep the status
|
|
97
|
+
// route cheap so a single slow debt scan cannot block first API paint.
|
|
98
|
+
return jsonResponse((0, operations_status_service_1.createOpsStatusReport)(projectRoot, { includeDebt: false }), headOnly);
|
|
99
|
+
}
|
|
98
100
|
if (url.pathname === '/api/dashboard/core') {
|
|
99
101
|
const bypassProjection = url.searchParams.get('cache') === 'bypass';
|
|
100
102
|
const status = bypassProjection ? null : (0, dashboard_refresh_1.createDashboardProjectionStatusReport)(projectRoot);
|
|
@@ -116,7 +118,7 @@ function createDashboardApiResponse(projectRoot, requestUrl, method) {
|
|
|
116
118
|
return jsonResponse((0, dashboard_heavy_projection_1.createProjectedDashboardDebtReport)(projectRoot), headOnly);
|
|
117
119
|
if (url.pathname === '/api/dashboard/bootstrap') {
|
|
118
120
|
const selectedTaskId = url.searchParams.get('selectedTaskId')?.trim();
|
|
119
|
-
const tier = url.searchParams.get('tier') === '
|
|
121
|
+
const tier = url.searchParams.get('tier') === 'full' ? 'full' : 'core';
|
|
120
122
|
const keyParts = ['bootstrap'];
|
|
121
123
|
if (tier === 'core')
|
|
122
124
|
keyParts.push('core');
|
|
@@ -140,8 +142,13 @@ function createDashboardApiResponse(projectRoot, requestUrl, method) {
|
|
|
140
142
|
return jsonResponse((0, task_read_model_1.createTaskListReport)(projectRoot), headOnly);
|
|
141
143
|
if (url.pathname === '/api/active-run')
|
|
142
144
|
return jsonResponse((0, active_run_state_1.safeCreateActiveRunProjection)(projectRoot), headOnly);
|
|
143
|
-
if (url.pathname === '/api/debt')
|
|
144
|
-
|
|
145
|
+
if (url.pathname === '/api/debt') {
|
|
146
|
+
// Keep the legacy dashboard debt route on the same fast aggregate path as
|
|
147
|
+
// /api/dashboard/debt. The full operational-debt read model remains
|
|
148
|
+
// available through CLI/MCP surfaces; dashboard request handlers must not
|
|
149
|
+
// perform broad capsule scans on the hot API path.
|
|
150
|
+
return jsonResponse((0, dashboard_heavy_projection_1.createProjectedDashboardDebtReport)(projectRoot), headOnly);
|
|
151
|
+
}
|
|
145
152
|
if (url.pathname === '/api/timeline') {
|
|
146
153
|
const taskId = url.searchParams.get('taskId')?.trim();
|
|
147
154
|
const key = taskId ? (0, dashboard_cache_1.createDashboardCacheKey)(projectRoot, 'timeline', taskId) : (0, dashboard_cache_1.createDashboardCacheKey)(projectRoot, 'timeline');
|
package/dist/cli/evidence.js
CHANGED
|
@@ -11,6 +11,7 @@ const evidence_json_1 = require("./evidence-json");
|
|
|
11
11
|
const evidence_lint_1 = require("../services/evidence-lint");
|
|
12
12
|
const evidence_list_1 = require("../services/evidence-list");
|
|
13
13
|
const evidence_migration_1 = require("../services/evidence-migration");
|
|
14
|
+
const evidence_summary_1 = require("../services/evidence-summary");
|
|
14
15
|
const args_1 = require("./args");
|
|
15
16
|
function handleEvidenceCommand(input) {
|
|
16
17
|
const sub = input.args[1];
|
|
@@ -52,6 +53,32 @@ function handleEvidenceCommand(input) {
|
|
|
52
53
|
process.exitCode = 6;
|
|
53
54
|
return true;
|
|
54
55
|
}
|
|
56
|
+
if (sub === 'summary') {
|
|
57
|
+
const taskId = (0, args_1.getRequiredStringOption)(input.args, '--task');
|
|
58
|
+
const report = (0, evidence_summary_1.createEvidenceSummaryReport)(input.projectRoot, {
|
|
59
|
+
taskId,
|
|
60
|
+
limit: (0, args_1.getIntegerOption)(input.args, '--limit', { min: 0, max: 500 }),
|
|
61
|
+
includePrivate: (0, args_1.getFlag)(input.args, '--include-private')
|
|
62
|
+
});
|
|
63
|
+
if (input.jsonOutput) {
|
|
64
|
+
console.log(JSON.stringify(report, null, 2));
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
console.log(`[HADARA] evidence summary ${taskId}: ${report.ok ? 'ok' : 'issues'} | records ${report.summary.count} | durable ${report.summary.durableCount}`);
|
|
68
|
+
if (report.latest)
|
|
69
|
+
console.log(`latest: ${evidenceSummaryDisplay(report.latest)}`);
|
|
70
|
+
if (report.latestCloseEvidence)
|
|
71
|
+
console.log(`latest-close: ${evidenceSummaryDisplay(report.latestCloseEvidence)}`);
|
|
72
|
+
for (const record of report.records)
|
|
73
|
+
console.log(`- ${evidenceSummaryDisplay(record)}`);
|
|
74
|
+
for (const issue of report.issues) {
|
|
75
|
+
console.log(`[${issue.severity}] ${issue.code}: ${issue.message}`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (!report.ok)
|
|
79
|
+
process.exitCode = 6;
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
55
82
|
if (sub === 'migrate') {
|
|
56
83
|
const taskId = (0, args_1.getRequiredStringOption)(input.args, '--task');
|
|
57
84
|
const report = (0, evidence_migration_1.createEvidenceMigrationPreviewReport)({
|
|
@@ -175,6 +202,21 @@ function evidenceListCategory(record) {
|
|
|
175
202
|
function evidenceListOutcome(record) {
|
|
176
203
|
return record.outcome;
|
|
177
204
|
}
|
|
205
|
+
function evidenceSummaryDisplay(record) {
|
|
206
|
+
const tags = record.tags.length > 0 ? ` | tags:${record.tags.slice(0, 3).map(compactEvidenceTag).join(',')}${record.tags.length > 3 ? ',...' : ''}` : '';
|
|
207
|
+
return `${record.id} | ${record.time} | ${record.category}/${record.outcome} | ${record.visibility} | ${truncateSummary(record.summary)}${tags}`;
|
|
208
|
+
}
|
|
209
|
+
function truncateSummary(value) {
|
|
210
|
+
const maxLength = 160;
|
|
211
|
+
if (value.length <= maxLength)
|
|
212
|
+
return value;
|
|
213
|
+
return `${value.slice(0, maxLength - 3)}...`;
|
|
214
|
+
}
|
|
215
|
+
function compactEvidenceTag(value) {
|
|
216
|
+
if (value.startsWith('idempotency:'))
|
|
217
|
+
return 'idempotency:*';
|
|
218
|
+
return truncateSummary(value);
|
|
219
|
+
}
|
|
178
220
|
function parseEvidenceKind(value) {
|
|
179
221
|
if (['test-log', 'command-log', 'diff-summary', 'screenshot', 'note'].includes(value)) {
|
|
180
222
|
return value;
|
package/dist/cli/handoff.js
CHANGED
|
@@ -2,11 +2,24 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.handleHandoffCommand = handleHandoffCommand;
|
|
4
4
|
const handoff_1 = require("../handoff/handoff");
|
|
5
|
+
const handoff_stale_problems_1 = require("../handoff/handoff-stale-problems");
|
|
5
6
|
const handoff_suggestion_1 = require("../handoff/handoff-suggestion");
|
|
6
7
|
const actor_1 = require("./actor");
|
|
7
8
|
const args_1 = require("./args");
|
|
8
9
|
function handleHandoffCommand(input) {
|
|
9
10
|
const sub = input.args[1];
|
|
11
|
+
if (sub === 'stale-problems') {
|
|
12
|
+
const report = (0, handoff_stale_problems_1.createHandoffStaleProblemsReport)(input.projectRoot);
|
|
13
|
+
if (input.jsonOutput) {
|
|
14
|
+
console.log(JSON.stringify(report, null, 2));
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
console.log((0, handoff_stale_problems_1.formatHandoffStaleProblemsReport)(report));
|
|
18
|
+
}
|
|
19
|
+
if (!report.ok)
|
|
20
|
+
process.exitCode = 6;
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
10
23
|
if (sub === 'suggest') {
|
|
11
24
|
const taskId = (0, args_1.getStringOption)(input.args, '--task') ?? input.args[2];
|
|
12
25
|
if (!taskId || taskId.startsWith('--'))
|
package/dist/cli/init.js
CHANGED
|
@@ -1104,17 +1104,19 @@ Ownership boundaries follow the lifecycle command model. \`task finalize --execu
|
|
|
1104
1104
|
|
|
1105
1105
|
## Standard Task Workflow Loop
|
|
1106
1106
|
|
|
1107
|
-
The authoritative command semantics live in \`docs/TASK_WORKFLOW_COMMANDS.md\`. From 0.3.
|
|
1107
|
+
The authoritative command semantics live in \`docs/TASK_WORKFLOW_COMMANDS.md\`. From 0.3.4 onward, agents should start from a compact task/context packet, then use lifecycle/finalize for closure instead of starting with low-level proof-boundary commands:
|
|
1108
1108
|
|
|
1109
1109
|
\`\`\`bash
|
|
1110
1110
|
hadara task next --json
|
|
1111
1111
|
|
|
1112
1112
|
# If a matching capsule already exists:
|
|
1113
1113
|
hadara task status --task T-XXXX --json
|
|
1114
|
+
hadara session start --task T-XXXX --json
|
|
1114
1115
|
|
|
1115
1116
|
# If no matching capsule exists, create one first:
|
|
1116
1117
|
hadara task create "task title" --json
|
|
1117
1118
|
hadara task status --task T-XXXX --json
|
|
1119
|
+
hadara session start --task T-XXXX --json
|
|
1118
1120
|
|
|
1119
1121
|
# Do the scoped work.
|
|
1120
1122
|
|
|
@@ -1315,17 +1317,19 @@ HADARA task workflow commands are split by responsibility. Similar-looking comma
|
|
|
1315
1317
|
|
|
1316
1318
|
## Standard Task Loop
|
|
1317
1319
|
|
|
1318
|
-
From 0.3.
|
|
1320
|
+
From 0.3.4 onward, agents should use the context-aware finalize-first loop for ordinary implementation capsules:
|
|
1319
1321
|
|
|
1320
1322
|
\`\`\`bash
|
|
1321
1323
|
hadara task next --json
|
|
1322
1324
|
|
|
1323
1325
|
# If a matching capsule already exists:
|
|
1324
1326
|
hadara task status --task T-XXXX --json
|
|
1327
|
+
hadara session start --task T-XXXX --json
|
|
1325
1328
|
|
|
1326
1329
|
# If no matching capsule exists, create one first:
|
|
1327
1330
|
hadara task create "task title" --json
|
|
1328
1331
|
hadara task status --task T-XXXX --json
|
|
1332
|
+
hadara session start --task T-XXXX --json
|
|
1329
1333
|
|
|
1330
1334
|
# Do the scoped work.
|
|
1331
1335
|
|
|
@@ -1534,6 +1538,20 @@ Use semantic tiers to keep session startup compact:
|
|
|
1534
1538
|
|
|
1535
1539
|
\`.hadara/context/HADARA_CONTEXT.md\` is the current-state entry point. It should route readers to compact state before task-work or conditional-reference docs. Full historical review of \`docs/PROJECT_STATE.md\` is not mandatory every session; use \`docs/AGENT_HANDOFF.md\` and its Historical Index when older history is needed. Historical and superseded docs are never default required reading.
|
|
1536
1540
|
|
|
1541
|
+
## Default Agent Loop
|
|
1542
|
+
|
|
1543
|
+
For ordinary implementation work, use the current context-aware loop:
|
|
1544
|
+
|
|
1545
|
+
\`\`\`bash
|
|
1546
|
+
hadara task next --json
|
|
1547
|
+
hadara session start --task T-XXXX --json
|
|
1548
|
+
hadara task lifecycle --task T-XXXX --json
|
|
1549
|
+
hadara task finalize --task T-XXXX --json
|
|
1550
|
+
hadara task finalize --task T-XXXX --execute --plan-hash sha256:... --json
|
|
1551
|
+
\`\`\`
|
|
1552
|
+
|
|
1553
|
+
Use low-level \`task finish\`, \`task ready\`, \`task close\`, and \`task audit-close\` only when debugging, repairing, or implementing those proof-boundary commands.
|
|
1554
|
+
|
|
1537
1555
|
## Rules
|
|
1538
1556
|
|
|
1539
1557
|
| Rule | Requirement | Evidence / Update Location |
|
package/dist/cli/main.js
CHANGED
|
@@ -222,6 +222,9 @@ async function main(args = process.argv.slice(2)) {
|
|
|
222
222
|
break;
|
|
223
223
|
}
|
|
224
224
|
case 'release': {
|
|
225
|
+
const { handleReleaseCloseoutCommand } = await Promise.resolve().then(() => __importStar(require('./release-closeout')));
|
|
226
|
+
if (handleReleaseCloseoutCommand({ args, projectRoot: paths.projectRoot, jsonOutput }))
|
|
227
|
+
return;
|
|
225
228
|
const { handleReleaseDryRunCommand } = await Promise.resolve().then(() => __importStar(require('./release-dry-run')));
|
|
226
229
|
if (handleReleaseDryRunCommand({ args, projectRoot: paths.projectRoot, jsonOutput }))
|
|
227
230
|
return;
|
|
@@ -1,10 +1,42 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.handlePackageCommand = handlePackageCommand;
|
|
4
|
+
const package_recycle_1 = require("../services/package-recycle");
|
|
4
5
|
const package_smoke_1 = require("../services/package-smoke");
|
|
5
6
|
const args_1 = require("./args");
|
|
6
7
|
function handlePackageCommand(input) {
|
|
7
|
-
if (input.args[0] !== 'package'
|
|
8
|
+
if (input.args[0] !== 'package')
|
|
9
|
+
return false;
|
|
10
|
+
if (input.args[1] === 'recycle') {
|
|
11
|
+
const report = (0, package_recycle_1.createPackageRecycleReport)({
|
|
12
|
+
paths: input.paths,
|
|
13
|
+
execute: (0, args_1.getFlag)(input.args, '--execute'),
|
|
14
|
+
packageSpecifier: (0, args_1.getStringOption)(input.args, '--package'),
|
|
15
|
+
expectedVersion: (0, args_1.getStringOption)(input.args, '--expected-version'),
|
|
16
|
+
workspace: (0, args_1.getStringOption)(input.args, '--workspace'),
|
|
17
|
+
taskId: (0, args_1.getStringOption)(input.args, '--task'),
|
|
18
|
+
attachEvidence: (0, args_1.getFlag)(input.args, '--attach-evidence'),
|
|
19
|
+
noEvidence: (0, args_1.getFlag)(input.args, '--no-evidence'),
|
|
20
|
+
keepTemp: (0, args_1.getFlag)(input.args, '--keep-temp'),
|
|
21
|
+
timeoutSeconds: (0, args_1.getIntegerOption)(input.args, '--timeout', { min: 1 })
|
|
22
|
+
});
|
|
23
|
+
if (input.jsonOutput) {
|
|
24
|
+
console.log(JSON.stringify(report, null, 2));
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
console.log(`${report.ok ? 'passed' : 'failed'} | package recycle | ${report.mode}`);
|
|
28
|
+
for (const step of report.steps) {
|
|
29
|
+
console.log(`${step.status} | ${step.label} | ${step.summary}`);
|
|
30
|
+
}
|
|
31
|
+
for (const issue of report.issues) {
|
|
32
|
+
console.log(`${issue.severity} | ${issue.code} | ${issue.message}`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (!report.ok)
|
|
36
|
+
process.exitCode = 6;
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
if (input.args[1] !== 'smoke')
|
|
8
40
|
return false;
|
|
9
41
|
const options = {
|
|
10
42
|
paths: input.paths,
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.handleReleaseCloseoutCommand = handleReleaseCloseoutCommand;
|
|
4
|
+
const release_closeout_1 = require("../services/release-closeout");
|
|
5
|
+
const args_1 = require("./args");
|
|
6
|
+
function handleReleaseCloseoutCommand(input) {
|
|
7
|
+
if (input.args[0] !== 'release' || input.args[1] !== 'closeout')
|
|
8
|
+
return false;
|
|
9
|
+
const report = (0, release_closeout_1.createReleaseCloseoutReport)(input.projectRoot, {
|
|
10
|
+
version: (0, args_1.getStringOption)(input.args, '--version'),
|
|
11
|
+
taskId: (0, args_1.getStringOption)(input.args, '--task')
|
|
12
|
+
});
|
|
13
|
+
if (input.jsonOutput) {
|
|
14
|
+
console.log(JSON.stringify(report, null, 2));
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
console.log((0, release_closeout_1.formatReleaseCloseoutReport)(report));
|
|
18
|
+
}
|
|
19
|
+
if (!report.ok)
|
|
20
|
+
process.exitCode = 6;
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
@@ -108,6 +108,10 @@ function buildContextPackReport(input) {
|
|
|
108
108
|
score: 0
|
|
109
109
|
}, false, input.projectRoot))
|
|
110
110
|
.sort(compareItems);
|
|
111
|
+
const validateWith = validationSuggestionsForTask(taskId, graphReport);
|
|
112
|
+
const writeBoundaries = writeBoundariesForItems([...readFirst, ...readIfNeeded], graphReport.nodes);
|
|
113
|
+
const sliceCandidates = sliceCandidatesForItems([...readFirst, ...readIfNeeded], graphReport.nodes);
|
|
114
|
+
const agentActions = agentActionsForContextPack(readFirst, sliceCandidates, validateWith, taskId);
|
|
111
115
|
const cache = input.cache ?? graphReport.cache ?? { used: false, hit: false };
|
|
112
116
|
return {
|
|
113
117
|
schemaVersion: exports.CONTEXT_PACK_SCHEMA_ID,
|
|
@@ -120,9 +124,10 @@ function buildContextPackReport(input) {
|
|
|
120
124
|
readFirst,
|
|
121
125
|
readIfNeeded,
|
|
122
126
|
doNotReadByDefault,
|
|
123
|
-
validateWith
|
|
124
|
-
writeBoundaries
|
|
125
|
-
sliceCandidates
|
|
127
|
+
validateWith,
|
|
128
|
+
writeBoundaries,
|
|
129
|
+
sliceCandidates,
|
|
130
|
+
agentActions,
|
|
126
131
|
knownProblems,
|
|
127
132
|
stateProjection: {
|
|
128
133
|
...graphReport.stateProjection.summary,
|
|
@@ -159,7 +164,7 @@ function rankContextPackNodes(nodes, edges, connectedIds, taskNode) {
|
|
|
159
164
|
if (taskNode) {
|
|
160
165
|
ranked.set(taskNode.id, {
|
|
161
166
|
node: taskNode,
|
|
162
|
-
reason: '
|
|
167
|
+
reason: 'Read the active task capsule first; it defines scope, acceptance, test expectations, and close handoff for this task.',
|
|
163
168
|
confidence: 'explicit',
|
|
164
169
|
score: 1000
|
|
165
170
|
});
|
|
@@ -174,7 +179,7 @@ function rankContextPackNodes(nodes, edges, connectedIds, taskNode) {
|
|
|
174
179
|
continue;
|
|
175
180
|
upsertRankedNode(ranked, {
|
|
176
181
|
node,
|
|
177
|
-
reason: edge.reason,
|
|
182
|
+
reason: concreteRankReason(node, edge.reason),
|
|
178
183
|
confidence: edge.confidence,
|
|
179
184
|
score: nodeScore(node, edge.confidence, connectedIds.has(node.id))
|
|
180
185
|
});
|
|
@@ -186,7 +191,7 @@ function rankContextPackNodes(nodes, edges, connectedIds, taskNode) {
|
|
|
186
191
|
if (metadataBoolean(node, 'requiredReading')) {
|
|
187
192
|
upsertRankedNode(ranked, {
|
|
188
193
|
node,
|
|
189
|
-
reason: '
|
|
194
|
+
reason: 'Required current-state document from the docs registry; read after task-local context if the task needs this surface.',
|
|
190
195
|
confidence: 'explicit',
|
|
191
196
|
score: nodeScore(node, 'explicit', false) - 25
|
|
192
197
|
});
|
|
@@ -203,6 +208,8 @@ function upsertRankedNode(ranked, candidate) {
|
|
|
203
208
|
function nodeScore(node, confidence, connected) {
|
|
204
209
|
const confidenceScore = confidence === 'explicit' ? 80 : confidence === 'derived' ? 50 : 20;
|
|
205
210
|
const connectedScore = connected ? 25 : 0;
|
|
211
|
+
const taskLocalScore = node.path?.startsWith('tasks/') ? 140 : 0;
|
|
212
|
+
const sourceScore = ['SourceFile', 'TestFile', 'Symbol'].includes(node.type) ? 40 : 0;
|
|
206
213
|
const typeScore = {
|
|
207
214
|
Task: 1000,
|
|
208
215
|
Document: 700,
|
|
@@ -218,7 +225,28 @@ function nodeScore(node, confidence, connected) {
|
|
|
218
225
|
FixtureFile: 380,
|
|
219
226
|
ConfigFile: 360
|
|
220
227
|
};
|
|
221
|
-
return typeScore[node.type] + confidenceScore + connectedScore;
|
|
228
|
+
return typeScore[node.type] + confidenceScore + connectedScore + taskLocalScore + sourceScore;
|
|
229
|
+
}
|
|
230
|
+
function concreteRankReason(node, sourceReason) {
|
|
231
|
+
if (node.path?.startsWith('tasks/')) {
|
|
232
|
+
return `Task-local file connected to the active task; read it before broad project history. ${sourceReason}`;
|
|
233
|
+
}
|
|
234
|
+
if (node.type === 'SourceFile') {
|
|
235
|
+
return `Implementation file connected to the active task; inspect it when changing code. ${sourceReason}`;
|
|
236
|
+
}
|
|
237
|
+
if (node.type === 'TestFile') {
|
|
238
|
+
return `Test file connected to the active task; inspect it when planning or verifying changes. ${sourceReason}`;
|
|
239
|
+
}
|
|
240
|
+
if (node.type === 'Symbol') {
|
|
241
|
+
return `Specific symbol connected to the active task; prefer this bounded location over opening the full file. ${sourceReason}`;
|
|
242
|
+
}
|
|
243
|
+
if (node.type === 'KnownProblem') {
|
|
244
|
+
return `Current handoff problem relevant to this task; check whether it changes implementation or validation. ${sourceReason}`;
|
|
245
|
+
}
|
|
246
|
+
if (node.type === 'Command') {
|
|
247
|
+
return `Command surface connected to this task; use it to choose dry-run/read-only validation before mutation. ${sourceReason}`;
|
|
248
|
+
}
|
|
249
|
+
return sourceReason;
|
|
222
250
|
}
|
|
223
251
|
function isReadFirstAllowed(node) {
|
|
224
252
|
if (isDoNotReadByDefault(node))
|
|
@@ -388,6 +416,62 @@ function sliceCandidatesForItems(items, nodes) {
|
|
|
388
416
|
};
|
|
389
417
|
});
|
|
390
418
|
}
|
|
419
|
+
function agentActionsForContextPack(readFirst, sliceCandidates, validateWith, taskId) {
|
|
420
|
+
const actions = [];
|
|
421
|
+
const seenCommands = new Set();
|
|
422
|
+
const firstSliceableItem = readFirst.find((item) => item.path && item.sourceAccess?.rawSlice === 'sliceable');
|
|
423
|
+
if (firstSliceableItem?.path) {
|
|
424
|
+
const args = suggestedSliceCommandArgs(firstSliceableItem.path, 'explicit-range', undefined, {
|
|
425
|
+
lineStart: firstSliceableItem.lineStart ?? 1,
|
|
426
|
+
lineEnd: firstSliceableItem.lineEnd ?? Math.max(firstSliceableItem.lineStart ?? 1, (firstSliceableItem.lineStart ?? 1) + 80)
|
|
427
|
+
});
|
|
428
|
+
pushAgentAction(actions, seenCommands, {
|
|
429
|
+
id: 'agent-action:read-first:1',
|
|
430
|
+
kind: 'read-first',
|
|
431
|
+
priority: 100,
|
|
432
|
+
sourceItemId: firstSliceableItem.id,
|
|
433
|
+
path: firstSliceableItem.path,
|
|
434
|
+
reason: `Read the top context item ${firstSliceableItem.id} as a bounded raw slice before opening broader files.`,
|
|
435
|
+
command: suggestedSliceCommand(args),
|
|
436
|
+
commandArgs: args,
|
|
437
|
+
writeBoundary: 'read-only'
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
for (const [index, candidate] of sliceCandidates.slice(0, 3).entries()) {
|
|
441
|
+
pushAgentAction(actions, seenCommands, {
|
|
442
|
+
id: `agent-action:slice:${index + 1}`,
|
|
443
|
+
kind: 'slice',
|
|
444
|
+
priority: 90 - index,
|
|
445
|
+
sliceCandidateId: candidate.id,
|
|
446
|
+
path: candidate.path,
|
|
447
|
+
reason: `Use this bounded slice candidate before reading the full file: ${candidate.reason}`,
|
|
448
|
+
command: candidate.suggestedCommand,
|
|
449
|
+
commandArgs: candidate.suggestedCommandArgs,
|
|
450
|
+
writeBoundary: 'read-only'
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
const requiredValidation = validateWith.find((suggestion) => suggestion.requiredForClose);
|
|
454
|
+
if (requiredValidation) {
|
|
455
|
+
pushAgentAction(actions, seenCommands, {
|
|
456
|
+
id: 'agent-action:validate:required-close',
|
|
457
|
+
kind: 'validate',
|
|
458
|
+
priority: 50,
|
|
459
|
+
reason: taskId
|
|
460
|
+
? `Run this read-only readiness check before planning close for ${taskId}.`
|
|
461
|
+
: 'Run this read-only readiness check before planning close.',
|
|
462
|
+
command: requiredValidation.command,
|
|
463
|
+
writeBoundary: 'read-only'
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
return actions.sort((a, b) => b.priority - a.priority || a.id.localeCompare(b.id));
|
|
467
|
+
}
|
|
468
|
+
function pushAgentAction(actions, seenCommands, action) {
|
|
469
|
+
const key = action.commandArgs ? action.commandArgs.join('\0') : action.command;
|
|
470
|
+
if (seenCommands.has(key))
|
|
471
|
+
return;
|
|
472
|
+
seenCommands.add(key);
|
|
473
|
+
actions.push(action);
|
|
474
|
+
}
|
|
391
475
|
function explicitRangeForCandidate(item, node) {
|
|
392
476
|
const lineStart = item.lineStart ?? numberMetadata(node, 'startLine') ?? node?.source.line ?? 1;
|
|
393
477
|
const metadataEnd = numberMetadata(node, 'endLine');
|
|
@@ -134,6 +134,7 @@ function buildWarmCachedContextPackReport(input) {
|
|
|
134
134
|
function lifecycleForSessionStart(taskId, contextPack) {
|
|
135
135
|
const primaryNextCommands = taskId
|
|
136
136
|
? [
|
|
137
|
+
`node dist/cli/main.js task lifecycle --task ${taskId} --json`,
|
|
137
138
|
`node dist/cli/main.js task status --task ${taskId} --json`,
|
|
138
139
|
`node dist/cli/main.js context pack --task ${taskId} --json`
|
|
139
140
|
]
|
|
@@ -175,7 +176,17 @@ function guidanceForSessionStart(input) {
|
|
|
175
176
|
? 'Session Start used explicit live context-pack discovery because --live was supplied.'
|
|
176
177
|
: 'Session Start used the bounded no-live packet and avoided broad live graph discovery.';
|
|
177
178
|
const commands = [];
|
|
179
|
+
let primaryAction;
|
|
178
180
|
if (!taskId) {
|
|
181
|
+
primaryAction = {
|
|
182
|
+
id: 'task-next',
|
|
183
|
+
label: 'Select the next task',
|
|
184
|
+
command: 'node dist/cli/main.js task next --json',
|
|
185
|
+
args: ['task', 'next', '--json'],
|
|
186
|
+
reason: 'No task id is available, so the next useful step is to select a concrete task before reading task-scoped context.',
|
|
187
|
+
writeBoundary: 'read-only',
|
|
188
|
+
recommendedActorRole: 'agent-worker'
|
|
189
|
+
};
|
|
179
190
|
commands.push({
|
|
180
191
|
id: 'task-next',
|
|
181
192
|
command: 'node dist/cli/main.js task next --json',
|
|
@@ -184,6 +195,21 @@ function guidanceForSessionStart(input) {
|
|
|
184
195
|
});
|
|
185
196
|
}
|
|
186
197
|
else {
|
|
198
|
+
primaryAction = {
|
|
199
|
+
id: 'task-lifecycle',
|
|
200
|
+
label: 'Inspect task lifecycle phase',
|
|
201
|
+
command: `node dist/cli/main.js task lifecycle --task ${taskId} --json`,
|
|
202
|
+
args: ['task', 'lifecycle', '--task', taskId, '--json'],
|
|
203
|
+
reason: 'A task id is available, so the fastest safe first step is to inspect lifecycle phase and blockers before editing files.',
|
|
204
|
+
writeBoundary: 'read-only',
|
|
205
|
+
recommendedActorRole: 'agent-worker'
|
|
206
|
+
};
|
|
207
|
+
commands.push({
|
|
208
|
+
id: 'task-lifecycle',
|
|
209
|
+
command: `node dist/cli/main.js task lifecycle --task ${taskId} --json`,
|
|
210
|
+
args: ['task', 'lifecycle', '--task', taskId, '--json'],
|
|
211
|
+
reason: 'Inspect the task phase and the one primary lifecycle next action before editing.'
|
|
212
|
+
});
|
|
187
213
|
commands.push({
|
|
188
214
|
id: 'task-status',
|
|
189
215
|
command: `node dist/cli/main.js task status --task ${taskId} --json`,
|
|
@@ -216,6 +242,18 @@ function guidanceForSessionStart(input) {
|
|
|
216
242
|
return {
|
|
217
243
|
mode,
|
|
218
244
|
primaryNextAction,
|
|
245
|
+
primaryAction,
|
|
246
|
+
whyThisNow: primaryAction.reason,
|
|
247
|
+
avoidForNow: taskId
|
|
248
|
+
? [
|
|
249
|
+
'Do not run task finalize before reviewing lifecycle blockers and required reads.',
|
|
250
|
+
'Do not opt into --live context reads unless the bounded or warm packet is insufficient.'
|
|
251
|
+
]
|
|
252
|
+
: [
|
|
253
|
+
'Do not infer a task id from broad project files.',
|
|
254
|
+
'Do not run live context discovery before selecting a task.'
|
|
255
|
+
],
|
|
256
|
+
nextCommandArgs: primaryAction.args,
|
|
219
257
|
reason,
|
|
220
258
|
taskRequired,
|
|
221
259
|
liveContextPackAvailable: true,
|
|
@@ -273,6 +311,7 @@ function buildBoundedContextPackReport(input) {
|
|
|
273
311
|
: [],
|
|
274
312
|
writeBoundaries: [],
|
|
275
313
|
sliceCandidates: [],
|
|
314
|
+
agentActions: [],
|
|
276
315
|
knownProblems: [],
|
|
277
316
|
stateProjection: {
|
|
278
317
|
...(input.taskId ? { activeTask: input.taskId } : {}),
|