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.
- package/README.md +246 -52
- package/dist/agent/evidence.js +1 -1
- package/dist/cli/actor.js +17 -0
- package/dist/cli/dashboard.js +85 -14
- package/dist/cli/dev.js +43 -0
- package/dist/cli/evidence.js +65 -1
- package/dist/cli/handoff.js +17 -0
- package/dist/cli/init.js +1050 -60
- package/dist/cli/main.js +126 -51
- package/dist/cli/package-smoke.js +2 -0
- package/dist/cli/protocol.js +103 -0
- package/dist/cli/release-artifact.js +2 -1
- package/dist/cli/task.js +156 -5
- package/dist/cli/tui.js +6 -1
- package/dist/cli/version.js +30 -0
- package/dist/core/actor-context.js +69 -0
- package/dist/core/next-action.js +15 -0
- package/dist/core/plan-context.js +23 -0
- package/dist/core/schema.js +46 -0
- package/dist/dev/docker-check.js +288 -0
- package/dist/evidence/evidence.js +123 -8
- package/dist/evidence/normalizer.js +171 -0
- package/dist/evidence/semantics.js +230 -0
- package/dist/handoff/handoff-suggestion.js +170 -0
- package/dist/harness/validate.js +199 -25
- package/dist/mcp/server.js +17 -1
- package/dist/schemas/actor-context.schema.json +15 -0
- package/dist/schemas/dashboard-bootstrap.schema.json +103 -0
- package/dist/schemas/dashboard-core.schema.json +101 -0
- package/dist/schemas/dashboard-task-detail.schema.json +85 -0
- package/dist/schemas/dashboard-timeline.schema.json +82 -0
- package/dist/schemas/dev-docker-check.schema.json +116 -0
- package/dist/schemas/evidence-lint.schema.json +67 -0
- package/dist/schemas/evidence-list.schema.json +58 -14
- package/dist/schemas/evidence-migration-preview.schema.json +113 -0
- package/dist/schemas/handoff-suggestion.schema.json +75 -0
- package/dist/schemas/next-action.schema.json +47 -0
- package/dist/schemas/package-smoke.schema.json +26 -0
- package/dist/schemas/plan-context.schema.json +20 -0
- package/dist/schemas/protocol-consistency.schema.json +127 -0
- package/dist/schemas/protocol-remediation.schema.json +73 -0
- package/dist/schemas/release-dry-run.schema.json +195 -1
- package/dist/schemas/runtime-version.schema.json +58 -0
- package/dist/schemas/schema-index.json +161 -0
- package/dist/schemas/task-audit-close.schema.json +67 -0
- package/dist/schemas/task-close.schema.json +141 -0
- package/dist/schemas/task-complete-flow.schema.json +81 -0
- package/dist/schemas/task-create.schema.json +37 -0
- package/dist/schemas/task-finish.schema.json +35 -0
- package/dist/schemas/task-next.schema.json +34 -0
- package/dist/schemas/task-ready.schema.json +50 -0
- package/dist/schemas/task-upgrade-scaffold.schema.json +70 -0
- package/dist/schemas/task-workbench.schema.json +122 -0
- package/dist/services/capability-registry.js +19 -2
- package/dist/services/dashboard-bootstrap.js +138 -0
- package/dist/services/dashboard-cache.js +129 -0
- package/dist/services/dashboard-core.js +209 -0
- package/dist/services/dashboard-heavy-projection.js +149 -0
- package/dist/services/dashboard-projection-store.js +140 -0
- package/dist/services/dashboard-refresh.js +332 -0
- package/dist/services/dashboard-task-detail.js +361 -0
- package/dist/services/dashboard-task-projection.js +259 -0
- package/dist/services/dashboard-timeline.js +243 -0
- package/dist/services/evidence-lint.js +321 -0
- package/dist/services/evidence-list.js +74 -0
- package/dist/services/evidence-migration.js +274 -0
- package/dist/services/feature-smoke.js +1 -1
- package/dist/services/handoff-summary-parser.js +89 -0
- package/dist/services/markdown-table.js +72 -0
- package/dist/services/operational-debt.js +38 -85
- package/dist/services/operations-status-service.js +19 -33
- package/dist/services/package-smoke.js +464 -19
- package/dist/services/project-read-model.js +2 -9
- package/dist/services/protocol-consistency.js +972 -0
- package/dist/services/protocol-profile.js +295 -0
- package/dist/services/protocol-remediation.js +390 -0
- package/dist/services/release-artifact-evidence.js +8 -31
- package/dist/services/release-artifact.js +84 -5
- package/dist/services/release-diagnostics.js +55 -0
- package/dist/services/release-dry-run.js +36 -147
- package/dist/services/release-evidence-validation.js +134 -0
- package/dist/services/release-evidence.js +170 -19
- package/dist/services/release-provider-advisories.js +43 -0
- package/dist/services/release-publish.js +2 -2
- package/dist/services/release-readiness-summary.js +66 -0
- package/dist/services/release-target-configuration.js +77 -0
- package/dist/services/release-targets.js +240 -0
- package/dist/services/runtime-version.js +114 -0
- package/dist/services/smoke-evidence.js +11 -33
- package/dist/services/task-workbench.js +252 -0
- package/dist/services/workbench-next-actions.js +185 -0
- package/dist/task/lifecycle-next-actions.js +27 -0
- package/dist/task/task-capsule.js +103 -40
- package/dist/task/task-close.js +699 -0
- package/dist/task/task-complete-flow.js +201 -0
- package/dist/task/task-create.js +85 -0
- package/dist/task/task-finish.js +456 -0
- package/dist/task/task-next.js +197 -0
- package/dist/task/task-ready.js +84 -0
- package/dist/task/task-templates.js +98 -0
- package/dist/task/task-upgrade-scaffold.js +288 -0
- package/dist/tui/cache.js +7 -96
- package/dist/tui/markdown.js +107 -26
- package/dist/tui/read-model.js +287 -31
- package/dist/tui/snapshot.js +17 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,54 +1,253 @@
|
|
|
1
1
|
# HADARA
|
|
2
2
|
|
|
3
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
16
|
-
|
|
17
|
-
npm run
|
|
18
|
-
npm test
|
|
209
|
+
npm run build
|
|
210
|
+
node dist/cli/main.js doctor --json
|
|
211
|
+
npm run check
|
|
19
212
|
```
|
|
20
213
|
|
|
21
|
-
|
|
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
|
-
|
|
25
|
-
|
|
217
|
+
npm run dev:docker-check
|
|
218
|
+
npm run dev:docker-sync-build
|
|
26
219
|
```
|
|
27
220
|
|
|
28
|
-
|
|
221
|
+
Focused validation:
|
|
29
222
|
|
|
30
|
-
```
|
|
31
|
-
|
|
223
|
+
```bash
|
|
224
|
+
npm run test:focused -- tests/unit/release-dry-run.test.ts
|
|
32
225
|
```
|
|
33
226
|
|
|
34
|
-
##
|
|
227
|
+
## Release Discipline
|
|
35
228
|
|
|
36
|
-
HADARA
|
|
229
|
+
HADARA release work is evidence-first.
|
|
37
230
|
|
|
38
|
-
|
|
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
|
-
|
|
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
|
-
|
|
246
|
+
## Store Separation
|
|
48
247
|
|
|
49
|
-
|
|
248
|
+
HADARA separates portable runtime state from project-owned development state.
|
|
50
249
|
|
|
51
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
##
|
|
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
|
|
86
|
-
hadara
|
|
87
|
-
hadara
|
|
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
|
-
|
|
286
|
+
The default MCP server remains read-only. Evidence attach is opt-in, approval-recorded, and audited.
|
|
97
287
|
|
|
98
|
-
##
|
|
288
|
+
## Deferred
|
|
99
289
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
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
|
-
|
|
303
|
+
HADARA is released under the MIT License. You can use, copy, modify, distribute, and build on it under the terms in `LICENSE`.
|
package/dist/agent/evidence.js
CHANGED
|
@@ -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
|
|
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
|
+
}
|
package/dist/cli/dashboard.js
CHANGED
|
@@ -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
|
|
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;
|
package/dist/cli/dev.js
ADDED
|
@@ -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
|
+
}
|
package/dist/cli/evidence.js
CHANGED
|
@@ -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
|
|
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');
|