hadara 0.1.0-rc.0 → 0.2.0-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.
Files changed (106) hide show
  1. package/README.md +246 -52
  2. package/dist/agent/evidence.js +1 -1
  3. package/dist/cli/actor.js +17 -0
  4. package/dist/cli/dashboard.js +85 -14
  5. package/dist/cli/dev.js +43 -0
  6. package/dist/cli/evidence.js +65 -1
  7. package/dist/cli/handoff.js +17 -0
  8. package/dist/cli/init.js +1050 -60
  9. package/dist/cli/main.js +126 -51
  10. package/dist/cli/package-smoke.js +2 -0
  11. package/dist/cli/protocol.js +103 -0
  12. package/dist/cli/release-artifact.js +2 -1
  13. package/dist/cli/task.js +156 -5
  14. package/dist/cli/tui.js +6 -1
  15. package/dist/cli/version.js +30 -0
  16. package/dist/core/actor-context.js +69 -0
  17. package/dist/core/next-action.js +15 -0
  18. package/dist/core/plan-context.js +23 -0
  19. package/dist/core/schema.js +46 -0
  20. package/dist/dev/docker-check.js +288 -0
  21. package/dist/evidence/evidence.js +123 -8
  22. package/dist/evidence/normalizer.js +171 -0
  23. package/dist/evidence/semantics.js +230 -0
  24. package/dist/handoff/handoff-suggestion.js +170 -0
  25. package/dist/harness/validate.js +199 -25
  26. package/dist/mcp/server.js +17 -1
  27. package/dist/schemas/actor-context.schema.json +15 -0
  28. package/dist/schemas/dashboard-bootstrap.schema.json +103 -0
  29. package/dist/schemas/dashboard-core.schema.json +101 -0
  30. package/dist/schemas/dashboard-task-detail.schema.json +85 -0
  31. package/dist/schemas/dashboard-timeline.schema.json +82 -0
  32. package/dist/schemas/dev-docker-check.schema.json +116 -0
  33. package/dist/schemas/evidence-lint.schema.json +67 -0
  34. package/dist/schemas/evidence-list.schema.json +58 -14
  35. package/dist/schemas/evidence-migration-preview.schema.json +113 -0
  36. package/dist/schemas/handoff-suggestion.schema.json +75 -0
  37. package/dist/schemas/next-action.schema.json +47 -0
  38. package/dist/schemas/package-smoke.schema.json +26 -0
  39. package/dist/schemas/plan-context.schema.json +20 -0
  40. package/dist/schemas/protocol-consistency.schema.json +127 -0
  41. package/dist/schemas/protocol-remediation.schema.json +73 -0
  42. package/dist/schemas/release-dry-run.schema.json +195 -1
  43. package/dist/schemas/runtime-version.schema.json +58 -0
  44. package/dist/schemas/schema-index.json +161 -0
  45. package/dist/schemas/task-audit-close.schema.json +67 -0
  46. package/dist/schemas/task-close.schema.json +141 -0
  47. package/dist/schemas/task-complete-flow.schema.json +81 -0
  48. package/dist/schemas/task-create.schema.json +37 -0
  49. package/dist/schemas/task-finish.schema.json +35 -0
  50. package/dist/schemas/task-next.schema.json +34 -0
  51. package/dist/schemas/task-ready.schema.json +50 -0
  52. package/dist/schemas/task-upgrade-scaffold.schema.json +70 -0
  53. package/dist/schemas/task-workbench.schema.json +122 -0
  54. package/dist/services/capability-registry.js +19 -2
  55. package/dist/services/dashboard-bootstrap.js +138 -0
  56. package/dist/services/dashboard-cache.js +129 -0
  57. package/dist/services/dashboard-core.js +209 -0
  58. package/dist/services/dashboard-heavy-projection.js +149 -0
  59. package/dist/services/dashboard-projection-store.js +140 -0
  60. package/dist/services/dashboard-refresh.js +332 -0
  61. package/dist/services/dashboard-task-detail.js +361 -0
  62. package/dist/services/dashboard-task-projection.js +259 -0
  63. package/dist/services/dashboard-timeline.js +243 -0
  64. package/dist/services/evidence-lint.js +321 -0
  65. package/dist/services/evidence-list.js +74 -0
  66. package/dist/services/evidence-migration.js +274 -0
  67. package/dist/services/feature-smoke.js +1 -1
  68. package/dist/services/handoff-summary-parser.js +89 -0
  69. package/dist/services/markdown-table.js +72 -0
  70. package/dist/services/operational-debt.js +38 -85
  71. package/dist/services/operations-status-service.js +19 -33
  72. package/dist/services/package-smoke.js +464 -19
  73. package/dist/services/project-read-model.js +2 -9
  74. package/dist/services/protocol-consistency.js +972 -0
  75. package/dist/services/protocol-profile.js +295 -0
  76. package/dist/services/protocol-remediation.js +390 -0
  77. package/dist/services/release-artifact-evidence.js +8 -31
  78. package/dist/services/release-artifact.js +84 -5
  79. package/dist/services/release-diagnostics.js +55 -0
  80. package/dist/services/release-dry-run.js +36 -147
  81. package/dist/services/release-evidence-validation.js +134 -0
  82. package/dist/services/release-evidence.js +170 -19
  83. package/dist/services/release-provider-advisories.js +43 -0
  84. package/dist/services/release-publish.js +2 -2
  85. package/dist/services/release-readiness-summary.js +66 -0
  86. package/dist/services/release-target-configuration.js +77 -0
  87. package/dist/services/release-targets.js +240 -0
  88. package/dist/services/runtime-version.js +114 -0
  89. package/dist/services/smoke-evidence.js +11 -33
  90. package/dist/services/task-workbench.js +252 -0
  91. package/dist/services/workbench-next-actions.js +185 -0
  92. package/dist/task/lifecycle-next-actions.js +27 -0
  93. package/dist/task/task-capsule.js +103 -40
  94. package/dist/task/task-close.js +699 -0
  95. package/dist/task/task-complete-flow.js +201 -0
  96. package/dist/task/task-create.js +85 -0
  97. package/dist/task/task-finish.js +456 -0
  98. package/dist/task/task-next.js +197 -0
  99. package/dist/task/task-ready.js +84 -0
  100. package/dist/task/task-templates.js +98 -0
  101. package/dist/task/task-upgrade-scaffold.js +288 -0
  102. package/dist/tui/cache.js +7 -96
  103. package/dist/tui/markdown.js +107 -26
  104. package/dist/tui/read-model.js +287 -31
  105. package/dist/tui/snapshot.js +17 -3
  106. package/package.json +1 -1
package/README.md CHANGED
@@ -1,54 +1,253 @@
1
1
  # HADARA
2
2
 
3
- **HADARA** is a portable agentic development workbench.
3
+ <p align="center">
4
+ <img src="https://raw.githubusercontent.com/ictseoyoungmin/HADARA-dev/main/docs/assets/hadara_sub_right_name.png" alt="HADARA" width="720">
5
+ </p>
6
+
7
+ <p align="center">
8
+ <img alt="Release candidate" src="https://img.shields.io/badge/release-0.2.0--rc.0-blue">
9
+ <img alt="Node.js" src="https://img.shields.io/badge/node-%3E%3D22-brightgreen">
10
+ <img alt="License" src="https://img.shields.io/badge/license-MIT-lightgrey">
11
+ </p>
12
+
13
+ **HADARA** is a portable agentic development workbench for keeping long-running AI-assisted software work inspectable, resumable, and evidence-backed.
4
14
 
5
15
  > Unbroken Context, Verified Development.
6
16
 
7
17
  HADARA is named from **Harness + Dara**. A harness safely binds and controls complex systems; Dara carries layered associations of holding, wisdom, durability, and continuity. HADARA binds non-deterministic LLM agent work into a production-oriented workflow through Task Capsules, Session Continuity, Policy Layers, Evidence Logs, and Handoff Protocols.
8
18
 
9
- This repository is a **bootstrap skeleton** for developing HADARA using the HADARA protocol itself.
19
+ This repository is both the HADARA source checkout and the HADARA protocol workspace used to build it.
20
+
21
+ ## Release Status
22
+
23
+ The current source checkout targets:
24
+
25
+ ```text
26
+ hadara@0.2.0-rc.0
27
+ ```
28
+
29
+ T-0268 refreshed package smoke, clean-checkout smoke, release artifact, release dry-run, and publish dry-run evidence for `0.2.0-rc.0`. T-0269 is the approval-gated publish capsule for this RC.
30
+
31
+ Current publish boundaries:
32
+
33
+ | Surface | Status |
34
+ |---|---|
35
+ | npm package | Primary release target. |
36
+ | `hadara@0.1.0-rc.0` | Published first RC. |
37
+ | `hadara@0.2.0-rc.0` | Current source and publish-candidate version. |
38
+ | GitHub Release | Secondary target, still approval-gated. |
39
+ | Docker image | Deferred. |
40
+ | PyPI/Python package | Advisory preview only. |
41
+ | Installer scripts / USB launchers | Deferred. |
42
+
43
+ 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.
44
+
45
+ ## Install
46
+
47
+ Requires Node.js 22.
48
+
49
+ Install the current RC:
50
+
51
+ ```bash
52
+ npm install -g hadara@0.2.0-rc.0
53
+ hadara doctor --json
54
+ hadara task list --json
55
+ hadara tools list --json
56
+ ```
57
+
58
+ Run without a global install:
59
+
60
+ ```bash
61
+ npx hadara@0.2.0-rc.0 doctor --json
62
+ npx hadara@0.2.0-rc.0 tools list --json
63
+ ```
64
+
65
+ Previous RC: `hadara@0.1.0-rc.0` remains available on npm for comparison or rollback, but new installs should use the current RC once it is published.
66
+
67
+ ## What HADARA Gives You
68
+
69
+ | Capability | Purpose |
70
+ |---|---|
71
+ | Task Capsules | Keep each unit of work scoped, evidenced, and resumable. |
72
+ | Evidence Logs | Record public, reduced proof of validation without raw private logs. |
73
+ | Handoff Protocol | Preserve current state for the next operator or agent. |
74
+ | Policy Surfaces | Inspect command risk and release boundaries before mutation. |
75
+ | CLI JSON Reports | Give agents and automation stable read models. |
76
+ | Read-only MCP Bridge | Expose project/task/evidence state without default write tools. |
77
+ | Dashboard and TUI | Provide local operator observation surfaces over existing read models. |
78
+ | Release Gates | Check release readiness through evidence-backed dry-run reports. |
10
79
 
11
- ## Quick Start
80
+ HADARA is deliberately conservative. Read surfaces are broad; write and release surfaces are narrow, explicit, and evidence-oriented.
81
+
82
+ ## Common Commands
83
+
84
+ Project and protocol health:
85
+
86
+ ```bash
87
+ hadara doctor --json
88
+ hadara status --json
89
+ hadara ops status --json
90
+ hadara tools list --json
91
+ hadara protocol doctor --json
92
+ hadara protocol doctor --scope docs --json
93
+ ```
94
+
95
+ Task workflow:
96
+
97
+ ```bash
98
+ hadara task next --json
99
+ hadara task create "implement a focused change" --json
100
+ hadara task status --task T-0001 --json
101
+ hadara task ready --task T-0001 --level done --json
102
+ hadara task finish --task T-0001 --json
103
+ hadara task finish --task T-0001 --execute --json
104
+ hadara task close --task T-0001 --json
105
+ hadara task close --task T-0001 --execute --json
106
+ hadara task audit-close --task T-0001 --json
107
+ ```
108
+
109
+ Evidence and handoff:
110
+
111
+ ```bash
112
+ hadara evidence collect --task T-0001 --json
113
+ hadara evidence add-command --task T-0001 --summary "Focused validation passed." --result passed --json
114
+ hadara evidence list --task T-0001 --json
115
+ hadara handoff suggest --task T-0001 --json
116
+ ```
117
+
118
+ Release and package readiness:
119
+
120
+ ```bash
121
+ hadara package smoke --dry-run --json
122
+ hadara package smoke --execute --attach-evidence --task T-0001 --json
123
+ hadara smoke clean-checkout --execute --attach-evidence --task T-0001 --json
124
+ hadara release artifact --execute --json --output dist-release --attach-evidence --task T-0001
125
+ hadara release gate --mode strict --json
126
+ hadara release dry-run --json
127
+ hadara release publish --mode dry-run --json
128
+ ```
129
+
130
+ `package smoke --execute`, `smoke clean-checkout --execute`, and `release artifact --execute` create local validation artifacts and reduced public evidence only. They must not publish packages, create GitHub Releases, build Docker images, push images, or load publish token values.
131
+
132
+ `release publish --mode dry-run` reports readiness, token presence by name, approval requirements, and mutation privacy flags without running `npm publish`. Any publish execution must happen only in a separate approval-gated release capsule with explicit operator confirmation.
133
+
134
+ ## Task Capsule Lifecycle
135
+
136
+ HADARA task workflow commands have distinct read/write boundaries. The full command semantics live in `docs/TASK_WORKFLOW_COMMANDS.md`.
137
+
138
+ Phase 6 reports support optional actor/run metadata for future multi-agent-compatible workflows. Commands such as `task complete`, `task finish`, `task ready`, `task close`, `task audit-close`, `handoff suggest`, and `dev docker-check` may accept metadata such as `--agent-id`, `--run-id`, `--actor-role`, and `--parent-run-id`. These fields improve provenance but do not enable a scheduler or full multi-agent runtime.
139
+
140
+ ```bash
141
+ hadara task next --json
142
+
143
+ # If a matching capsule already exists:
144
+ hadara task status --task T-XXXX --json
145
+
146
+ # If no matching capsule exists, create one first:
147
+ hadara task create "implement a focused change" --json
148
+ hadara task status --task T-XXXX --json
149
+
150
+ # Do the scoped work.
151
+
152
+ hadara evidence add-command --task T-XXXX --summary "..." --result passed --json
153
+ hadara task ready --task T-XXXX --level done --json
154
+
155
+ # Optional workflow compression / next action preview:
156
+ hadara task complete --task T-XXXX --json
157
+
158
+ hadara task finish --task T-XXXX --json
159
+ hadara task finish --task T-XXXX --execute --json
160
+
161
+ hadara task close --task T-XXXX --json
162
+ hadara task close --task T-XXXX --execute --json
163
+
164
+ hadara task audit-close --task T-XXXX --json
165
+ ```
166
+
167
+ Important distinctions:
168
+
169
+ | Command | Boundary |
170
+ |---|---|
171
+ | `task status` | Read-only operator console. `ok:true` means the report was generated, not that the task is ready. |
172
+ | `task complete` | Read-only workflow compressor. It reports the current stage and next action. |
173
+ | `task finish --execute` | Writes only bounded status bookkeeping in `TASK.md` and `docs/TASK_BOARD.md`. |
174
+ | `task close --execute` | Appends close evidence only. |
175
+ | `task audit-close` | Read-only close proof audit. |
176
+
177
+ ## Initialize a Project
178
+
179
+ ```bash
180
+ hadara init # default: standard
181
+ hadara init --profile basic
182
+ hadara init --profile standard
183
+ hadara init --profile governed
184
+ ```
185
+
186
+ | Profile | Use When |
187
+ |---|---|
188
+ | `basic` | Small project, only task/handoff discipline needed. |
189
+ | `standard` | Default multi-session project with planning and validation docs. |
190
+ | `governed` | Long-lived project with security, refactor, roadmap, or operational governance needs. |
191
+
192
+ Init maintenance commands dry-run by default unless `--execute` is supplied:
193
+
194
+ ```bash
195
+ hadara init doctor --json
196
+ hadara init upgrade --profile governed --json
197
+ hadara init register-doc --path docs/specs/LOCAL.md --when "Local work" --purpose "Local spec" --json
198
+ hadara init enable-integration --integration mcp --json
199
+ ```
200
+
201
+ `register-doc` can use `--require-exists` when missing referenced docs should be treated as an error. `enable-integration` registers project guidance docs only; it does not enable Hermes/MCP runtime behavior or change capability gates. `upgrade` creates missing scaffold docs and updates known generated profile metadata; it does not rewrite unrelated user-authored content.
202
+
203
+ ## Develop from Source
204
+
205
+ Use Node.js 22.
12
206
 
13
207
  ```bash
14
208
  npm install
15
- npm run dev -- doctor
16
- npm run dev -- task create "implement ProviderClient contract"
17
- npm run dev -- task list
18
- npm test
209
+ npm run build
210
+ node dist/cli/main.js doctor --json
211
+ npm run check
19
212
  ```
20
213
 
21
- Linux/macOS portable launcher:
214
+ For HADARA-dev itself, Docker is the preferred validation path because host `node_modules` on mounted workspaces can be unreliable:
22
215
 
23
216
  ```bash
24
- chmod +x ./start.sh
25
- ./start.sh doctor
217
+ npm run dev:docker-check
218
+ npm run dev:docker-sync-build
26
219
  ```
27
220
 
28
- Windows launcher:
221
+ Focused validation:
29
222
 
30
- ```bat
31
- START.bat doctor
223
+ ```bash
224
+ npm run test:focused -- tests/unit/release-dry-run.test.ts
32
225
  ```
33
226
 
34
- ## Development Principle
227
+ ## Release Discipline
35
228
 
36
- HADARA development must dogfood the HADARA workflow:
229
+ HADARA release work is evidence-first.
37
230
 
38
- 1. Read `docs/PROJECT_STATE.md`
39
- 2. Read `docs/AGENT_HANDOFF.md`
40
- 3. Read `docs/TASK_BOARD.md`
41
- 4. Work inside a Task Capsule
42
- 5. Attach evidence before marking work complete
43
- 6. Update handoff before stopping
231
+ Before any npm publish:
44
232
 
45
- ## Store Separation
233
+ 1. Confirm the git worktree is clean.
234
+ 2. Run `hadara release dry-run --json`.
235
+ 3. Run `hadara release publish --mode dry-run --json`.
236
+ 4. Confirm `NPM_TOKEN` presence without printing the token value.
237
+ 5. Confirm the exact package version is not already on npm.
238
+ 6. Generate fresh package, clean-checkout, and release-artifact evidence for the active release capsule.
239
+ 7. Publish only after explicit operator approval.
240
+ 8. Verify with `npm view hadara@<version> version`.
241
+ 9. Attach reduced publish evidence.
242
+ 10. Update release notes, Project State, Agent Handoff, and the active Task Capsule.
243
+
244
+ Never write token values, private logs, raw npm output, private paths, or local machine state into committed evidence.
46
245
 
47
- HADARA separates **portable runtime state** from **project-owned development state**.
246
+ ## Store Separation
48
247
 
49
- ### Portable / USB Store
248
+ HADARA separates portable runtime state from project-owned development state.
50
249
 
51
- Located under the HADARA installation root:
250
+ Portable/local runtime state:
52
251
 
53
252
  ```text
54
253
  data/
@@ -61,49 +260,44 @@ data/
61
260
  exports/
62
261
  ```
63
262
 
64
- This is **not committed**. It is local, portable, and may live on a USB drive.
65
-
66
- ### Project Repo Store
67
-
68
- Located inside each project repository:
263
+ Project-owned reproducible state:
69
264
 
70
265
  ```text
71
266
  docs/
72
267
  tasks/
73
268
  .hadara/
74
269
  AGENTS.md
75
- .hermes.md
76
- HERMES.md
77
270
  ```
78
271
 
79
- This is committed when it represents reproducible project state, conventions, or agent context.
272
+ Portable/local state is not committed. Project docs, Task Capsules, and reduced public evidence are committed when they represent reproducible context.
80
273
 
81
- ## Initial CLI Commands
274
+ ## Optional / Deferred Integrations
275
+
276
+ Hermes and MCP surfaces exist for compatibility experiments and read-only bridge work. They are not generated by `hadara init` and are not part of the default scaffold. Use them only when a project explicitly opts into integration guidance.
82
277
 
83
278
  ```bash
84
- hadara init
85
- hadara doctor
86
- hadara task create "..."
87
- hadara task list
88
- hadara task show T-0001
89
- hadara evidence collect --task T-0001
90
- hadara handoff update --task T-0001
91
- hadara hermes detect
92
- hadara hermes export-context
279
+ hadara init enable-integration --integration hermes --execute --json
280
+ hadara init enable-integration --integration mcp --execute --json
281
+ hadara hermes detect --json
282
+ hadara hermes export-context --json
93
283
  hadara mcp serve
94
284
  ```
95
285
 
96
- Current CLI is a seed implementation. Full agent execution, provider integration, dashboard, and MCP server runtime are intentionally stubbed for later tasks.
286
+ The default MCP server remains read-only. Evidence attach is opt-in, approval-recorded, and audited.
97
287
 
98
- ## Test Suites
288
+ ## Deferred
99
289
 
100
- ```bash
101
- npm run test:unit
102
- npm run test:contract
103
- npm run test:harness
104
- npm run check
105
- ```
290
+ These are intentionally not part of the current default runtime:
291
+
292
+ - Full multi-agent scheduler/controller.
293
+ - Broad MCP write tools.
294
+ - Shell execution through agents.
295
+ - Real provider execution as the default path.
296
+ - GitHub Release automation as a default path.
297
+ - Docker image publishing.
298
+ - Installer scripts and USB portable launchers.
299
+ - Live dashboard streaming.
106
300
 
107
301
  ## License
108
302
 
109
- TBD. Recommended candidates: Apache-2.0 or MIT.
303
+ HADARA is released under the MIT License. You can use, copy, modify, distribute, and build on it under the terms in `LICENSE`.
@@ -41,7 +41,7 @@ function toAttachment(projectRoot, appended, summary, result) {
41
41
  kind: 'command-log',
42
42
  summary,
43
43
  result,
44
- evidencePath: appended.evidence.evidencePath ?? '',
44
+ evidencePath: (0, evidence_1.persistedEvidencePath)(appended.evidence) ?? '',
45
45
  markdownPath: toPortablePath(node_path_1.default.relative(projectRoot, appended.markdownPath))
46
46
  };
47
47
  }
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getActorContextOption = getActorContextOption;
4
+ const actor_context_1 = require("../core/actor-context");
5
+ const args_1 = require("./args");
6
+ function getActorContextOption(args) {
7
+ const agentId = (0, args_1.getStringOption)(args, '--agent-id');
8
+ const runId = (0, args_1.getStringOption)(args, '--run-id');
9
+ const role = (0, args_1.getStringOption)(args, '--actor-role');
10
+ const parentRunId = (0, args_1.getStringOption)(args, '--parent-run-id');
11
+ if (agentId === undefined && runId === undefined && role === undefined && parentRunId === undefined)
12
+ return undefined;
13
+ if (role !== undefined && !(0, actor_context_1.isHadaraActorRole)(role)) {
14
+ throw new Error(`unsupported --actor-role: ${role}`);
15
+ }
16
+ return (0, actor_context_1.resolveHadaraActorContext)({ agentId, runId, role, parentRunId }).actor;
17
+ }
@@ -11,10 +11,19 @@ const node_fs_1 = __importDefault(require("node:fs"));
11
11
  const node_http_1 = __importDefault(require("node:http"));
12
12
  const node_path_1 = __importDefault(require("node:path"));
13
13
  const active_run_state_1 = require("../services/active-run-state");
14
+ const dashboard_bootstrap_1 = require("../services/dashboard-bootstrap");
15
+ const dashboard_cache_1 = require("../services/dashboard-cache");
16
+ const dashboard_core_1 = require("../services/dashboard-core");
17
+ const dashboard_refresh_1 = require("../services/dashboard-refresh");
18
+ const dashboard_task_detail_1 = require("../services/dashboard-task-detail");
19
+ const dashboard_heavy_projection_1 = require("../services/dashboard-heavy-projection");
20
+ const evidence_lint_1 = require("../services/evidence-lint");
14
21
  const evidence_list_1 = require("../services/evidence-list");
22
+ const dashboard_timeline_1 = require("../services/dashboard-timeline");
15
23
  const operational_debt_1 = require("../services/operational-debt");
16
24
  const operations_status_service_1 = require("../services/operations-status-service");
17
25
  const task_read_model_1 = require("../services/task-read-model");
26
+ const task_workbench_1 = require("../services/task-workbench");
18
27
  const args_1 = require("./args");
19
28
  const DASHBOARD_HTML = node_path_1.default.join('docs', 'design', 'dashboard', 'index.html');
20
29
  const DASHBOARD_FIXTURE = node_path_1.default.join('docs', 'design', 'fixtures', 'hadara.ops.status.sample.json');
@@ -43,6 +52,7 @@ function serveDashboard(projectRoot, options = {}) {
43
52
  server.listen(port, host, () => {
44
53
  const address = server.address();
45
54
  const actualPort = typeof address === 'object' && address ? address.port : port;
55
+ (0, dashboard_refresh_1.warmDashboardProjections)(projectRoot);
46
56
  // console.log(`[HADARA] Dashboard serving sample fixture at http://${host}:${actualPort}/dashboard/`);
47
57
  console.log(`[HADARA] Dashboard serving at http://${host}:${actualPort}/dashboard/ with read-only APIs under /api/.`);
48
58
  });
@@ -85,32 +95,93 @@ function createDashboardApiResponse(projectRoot, requestUrl, method) {
85
95
  const headOnly = normalizedMethod === 'HEAD';
86
96
  if (url.pathname === '/api/status')
87
97
  return jsonResponse((0, operations_status_service_1.createOpsStatusReport)(projectRoot), headOnly);
98
+ if (url.pathname === '/api/dashboard/core') {
99
+ const bypassProjection = url.searchParams.get('cache') === 'bypass';
100
+ const status = bypassProjection ? null : (0, dashboard_refresh_1.createDashboardProjectionStatusReport)(projectRoot);
101
+ return jsonResponse((0, dashboard_core_1.createDashboardCoreReport)(projectRoot, {
102
+ bypassProjection,
103
+ projectionFreshness: status?.projections.core.freshness,
104
+ refreshState: status?.refresh.state,
105
+ pendingSections: status?.pendingSections,
106
+ staleSections: status?.staleSections
107
+ }), headOnly);
108
+ }
109
+ if (url.pathname === '/api/dashboard/projection/status')
110
+ return jsonResponse((0, dashboard_refresh_1.createDashboardProjectionStatusReport)(projectRoot), headOnly);
111
+ if (url.pathname === '/api/dashboard/refresh')
112
+ return jsonResponse((0, dashboard_refresh_1.triggerDashboardProjectionRefresh)(projectRoot, 'api'), headOnly);
113
+ if (url.pathname === '/api/dashboard/timeline')
114
+ return jsonResponse((0, dashboard_heavy_projection_1.createProjectedDashboardTimelineReport)(projectRoot), headOnly);
115
+ if (url.pathname === '/api/dashboard/debt')
116
+ return jsonResponse((0, dashboard_heavy_projection_1.createProjectedDashboardDebtReport)(projectRoot), headOnly);
117
+ if (url.pathname === '/api/dashboard/bootstrap') {
118
+ const selectedTaskId = url.searchParams.get('selectedTaskId')?.trim();
119
+ const tier = url.searchParams.get('tier') === 'core' ? 'core' : 'full';
120
+ const keyParts = ['bootstrap'];
121
+ if (tier === 'core')
122
+ keyParts.push('core');
123
+ if (selectedTaskId)
124
+ keyParts.push('selected', selectedTaskId);
125
+ const key = (0, dashboard_cache_1.createDashboardCacheKey)(projectRoot, ...keyParts);
126
+ const cached = (0, dashboard_cache_1.getOrCreateCachedReport)(key, { ttlMs: dashboard_cache_1.DASHBOARD_CACHE_TTLS.bootstrap, bypass: url.searchParams.get('cache') === 'bypass' }, () => (0, dashboard_bootstrap_1.createDashboardBootstrapReport)(projectRoot, { tier, ...(selectedTaskId ? { selectedTaskId } : {}) }));
127
+ return jsonResponse((0, dashboard_cache_1.withDashboardCacheMetadata)(cached.value, cached.cache), headOnly);
128
+ }
129
+ if (url.pathname === '/api/dashboard/task-detail') {
130
+ const taskId = url.searchParams.get('taskId')?.trim();
131
+ if (!taskId)
132
+ return missingTaskId(headOnly);
133
+ const key = (0, dashboard_cache_1.createDashboardCacheKey)(projectRoot, 'task-detail', taskId);
134
+ const cached = (0, dashboard_cache_1.getOrCreateCachedReport)(key, { ttlMs: dashboard_cache_1.DASHBOARD_CACHE_TTLS.taskDetail, bypass: url.searchParams.get('cache') === 'bypass' }, () => (0, dashboard_task_detail_1.createDashboardTaskDetailReport)(projectRoot, taskId));
135
+ return jsonResponse((0, dashboard_cache_1.withDashboardCacheMetadata)(cached.value, cached.cache), headOnly);
136
+ }
137
+ if (url.pathname === '/api/dashboard/cache/status')
138
+ return jsonResponse((0, dashboard_cache_1.createDashboardCacheStatusReport)(), headOnly);
88
139
  if (url.pathname === '/api/tasks')
89
140
  return jsonResponse((0, task_read_model_1.createTaskListReport)(projectRoot), headOnly);
90
141
  if (url.pathname === '/api/active-run')
91
142
  return jsonResponse((0, active_run_state_1.safeCreateActiveRunProjection)(projectRoot), headOnly);
92
143
  if (url.pathname === '/api/debt')
93
144
  return jsonResponse((0, operational_debt_1.createOperationalDebtReport)(projectRoot), headOnly);
145
+ if (url.pathname === '/api/timeline') {
146
+ const taskId = url.searchParams.get('taskId')?.trim();
147
+ const key = taskId ? (0, dashboard_cache_1.createDashboardCacheKey)(projectRoot, 'timeline', taskId) : (0, dashboard_cache_1.createDashboardCacheKey)(projectRoot, 'timeline');
148
+ const cached = (0, dashboard_cache_1.getOrCreateCachedReport)(key, { ttlMs: dashboard_cache_1.DASHBOARD_CACHE_TTLS.timeline, bypass: url.searchParams.get('cache') === 'bypass' }, () => (0, dashboard_timeline_1.createDashboardTimelineReport)(projectRoot, taskId ? { taskId } : {}));
149
+ return jsonResponse((0, dashboard_cache_1.withDashboardCacheMetadata)(cached.value, cached.cache), headOnly);
150
+ }
151
+ if (url.pathname === '/api/task-workbench') {
152
+ const taskId = url.searchParams.get('taskId')?.trim();
153
+ if (!taskId)
154
+ return missingTaskId(headOnly);
155
+ return jsonResponse((0, task_workbench_1.createTaskWorkbenchReport)(projectRoot, taskId), headOnly);
156
+ }
157
+ if (url.pathname === '/api/evidence-lint') {
158
+ const taskId = url.searchParams.get('taskId')?.trim();
159
+ if (!taskId)
160
+ return missingTaskId(headOnly);
161
+ return jsonResponse((0, evidence_lint_1.createEvidenceLintReport)(projectRoot, taskId), headOnly);
162
+ }
94
163
  if (url.pathname === '/api/evidence') {
95
164
  const taskId = url.searchParams.get('taskId')?.trim();
96
- if (!taskId) {
97
- return jsonResponse({
98
- schemaVersion: 'hadara.dashboard.api.error.v1',
99
- command: 'dashboard.api',
100
- ok: false,
101
- issues: [
102
- {
103
- severity: 'error',
104
- code: 'TASK_ID_REQUIRED',
105
- message: 'Missing required query parameter: taskId.'
106
- }
107
- ]
108
- }, headOnly, 400);
109
- }
165
+ if (!taskId)
166
+ return missingTaskId(headOnly);
110
167
  return jsonResponse((0, evidence_list_1.createEvidenceListReport)(projectRoot, { taskId }), headOnly);
111
168
  }
112
169
  return notFound();
113
170
  }
171
+ function missingTaskId(headOnly) {
172
+ return jsonResponse({
173
+ schemaVersion: 'hadara.dashboard.api.error.v1',
174
+ command: 'dashboard.api',
175
+ ok: false,
176
+ issues: [
177
+ {
178
+ severity: 'error',
179
+ code: 'TASK_ID_REQUIRED',
180
+ message: 'Missing required query parameter: taskId.'
181
+ }
182
+ ]
183
+ }, headOnly, 400);
184
+ }
114
185
  function safePathname(requestUrl) {
115
186
  const url = safeUrl(requestUrl);
116
187
  return url?.pathname ?? null;
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleDevCommand = handleDevCommand;
4
+ const docker_check_1 = require("../dev/docker-check");
5
+ const actor_1 = require("./actor");
6
+ const args_1 = require("./args");
7
+ function handleDevCommand(input) {
8
+ const sub = input.args[1];
9
+ if (sub !== 'docker-check')
10
+ return false;
11
+ const report = (0, docker_check_1.createDevDockerCheckReport)(input.projectRoot, {
12
+ focusedTests: getFocusedTests(input.args),
13
+ syncDist: (0, args_1.getFlag)(input.args, '--sync-dist'),
14
+ fullCheck: (0, args_1.getFlag)(input.args, '--full'),
15
+ actor: (0, actor_1.getActorContextOption)(input.args),
16
+ distBeforeHash: (0, args_1.getStringOption)(input.args, '--before-hash'),
17
+ allowMissingBeforeHash: (0, args_1.getFlag)(input.args, '--allow-missing-before-hash')
18
+ });
19
+ if (input.jsonOutput) {
20
+ console.log(JSON.stringify(report, null, 2));
21
+ }
22
+ else {
23
+ console.log((0, docker_check_1.formatDevDockerCheckReport)(report));
24
+ }
25
+ if (!report.ok)
26
+ process.exitCode = 6;
27
+ return true;
28
+ }
29
+ function getFocusedTests(args) {
30
+ const index = args.indexOf('--focused');
31
+ if (index === -1)
32
+ return [];
33
+ const values = [];
34
+ for (let i = index + 1; i < args.length; i += 1) {
35
+ const value = args[i];
36
+ if (value.startsWith('--'))
37
+ break;
38
+ values.push(value);
39
+ }
40
+ if (values.length === 0)
41
+ throw new Error('dev docker-check --focused requires at least one test path');
42
+ return values;
43
+ }
@@ -6,7 +6,9 @@ exports.parseEvidenceResult = parseEvidenceResult;
6
6
  exports.parseEvidenceVisibility = parseEvidenceVisibility;
7
7
  const evidence_1 = require("../evidence/evidence");
8
8
  const evidence_json_1 = require("./evidence-json");
9
+ const evidence_lint_1 = require("../services/evidence-lint");
9
10
  const evidence_list_1 = require("../services/evidence-list");
11
+ const evidence_migration_1 = require("../services/evidence-migration");
10
12
  const args_1 = require("./args");
11
13
  function handleEvidenceCommand(input) {
12
14
  const sub = input.args[1];
@@ -22,7 +24,7 @@ function handleEvidenceCommand(input) {
22
24
  }
23
25
  else {
24
26
  for (const record of report.records) {
25
- console.log(`${record.time} | ${record.kind} | ${record.result} | ${record.visibility} | ${record.summary}`);
27
+ console.log(`${record.time} | ${(0, evidence_1.persistedEvidenceKind)(record)} | ${(0, evidence_1.persistedEvidenceResult)(record)} | ${record.visibility} | ${record.summary}`);
26
28
  }
27
29
  for (const issue of report.issues) {
28
30
  console.log(`[${issue.severity}] ${issue.code}: ${issue.message}`);
@@ -32,6 +34,68 @@ function handleEvidenceCommand(input) {
32
34
  process.exitCode = 6;
33
35
  return true;
34
36
  }
37
+ if (sub === 'lint') {
38
+ const taskId = (0, args_1.getRequiredStringOption)(input.args, '--task');
39
+ const report = (0, evidence_lint_1.createEvidenceLintReport)(input.projectRoot, taskId);
40
+ if (input.jsonOutput) {
41
+ console.log(JSON.stringify(report, null, 2));
42
+ }
43
+ else {
44
+ console.log(`[HADARA] evidence lint ${taskId}: ${report.ok ? 'ok' : 'issues'}`);
45
+ for (const issue of report.issues) {
46
+ console.log(`[${issue.severity}] ${issue.code}: ${issue.message}`);
47
+ }
48
+ }
49
+ if (!report.ok)
50
+ process.exitCode = 6;
51
+ return true;
52
+ }
53
+ if (sub === 'migrate') {
54
+ const taskId = (0, args_1.getRequiredStringOption)(input.args, '--task');
55
+ const report = (0, evidence_migration_1.createEvidenceMigrationPreviewReport)({
56
+ projectRoot: input.projectRoot,
57
+ taskId,
58
+ toVersion: (0, args_1.getStringOption)(input.args, '--to', 'v2') ?? 'v2',
59
+ execute: (0, args_1.getFlag)(input.args, '--execute'),
60
+ beforeHash: (0, args_1.getStringOption)(input.args, '--before-hash')
61
+ });
62
+ if (input.jsonOutput) {
63
+ console.log(JSON.stringify(report, null, 2));
64
+ }
65
+ else {
66
+ const execution = report.mode === 'execute' ? ` | applied ${report.execution.applied ? 'yes' : 'no'}` : '';
67
+ console.log(`[HADARA] evidence migrate ${taskId}: ${report.ok ? 'ok' : 'issues'} | planned ${report.summary.plannedTransforms} | skipped ${report.summary.skippedRecords}${execution}`);
68
+ for (const issue of report.issues) {
69
+ console.log(`[${issue.severity}] ${issue.code}: ${issue.message}`);
70
+ }
71
+ }
72
+ if (!report.ok)
73
+ process.exitCode = 6;
74
+ return true;
75
+ }
76
+ if (sub === 'add-command') {
77
+ const taskId = (0, args_1.getRequiredStringOption)(input.args, '--task');
78
+ const summary = (0, args_1.getStringOption)(input.args, '--summary') ?? 'Command completed.';
79
+ const result = parseEvidenceResult((0, args_1.getStringOption)(input.args, '--result', 'unknown') ?? 'unknown');
80
+ const visibility = parseEvidenceVisibility((0, args_1.getStringOption)(input.args, '--visibility', 'public') ?? 'public', (0, args_1.getFlag)(input.args, '--private'));
81
+ if (input.jsonOutput) {
82
+ const report = (0, evidence_json_1.createEvidenceCollectReport)(input.projectRoot, {
83
+ taskId,
84
+ kind: 'command-log',
85
+ summary,
86
+ result,
87
+ visibility
88
+ });
89
+ console.log(JSON.stringify({ ...report, command: 'evidence.add-command' }, null, 2));
90
+ if (!report.ok)
91
+ process.exitCode = 6;
92
+ }
93
+ else {
94
+ const filePath = (0, evidence_1.appendEvidence)(input.projectRoot, { taskId, kind: 'command-log', summary, result, visibility });
95
+ console.log(`[HADARA] Command evidence updated: ${filePath}`);
96
+ }
97
+ return true;
98
+ }
35
99
  if (sub !== 'collect')
36
100
  return false;
37
101
  const taskId = (0, args_1.getRequiredStringOption)(input.args, '--task');