harnery 0.36.0 → 0.37.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/dist/commander.js +4 -0
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/agents.js +87 -46
- package/dist/commands/artifacts.d.ts.map +1 -1
- package/dist/commands/artifacts.js +26 -1
- package/dist/commands/browse.d.ts.map +1 -1
- package/dist/commands/browse.js +11 -0
- package/dist/commands/diagnostics.d.ts +4 -0
- package/dist/commands/diagnostics.d.ts.map +1 -0
- package/dist/commands/diagnostics.js +229 -0
- package/dist/commands/files.d.ts +12 -0
- package/dist/commands/files.d.ts.map +1 -1
- package/dist/commands/files.js +54 -1
- package/dist/commands/governor.d.ts.map +1 -1
- package/dist/commands/governor.js +4 -0
- package/dist/commands/ledger-v3.d.ts.map +1 -1
- package/dist/commands/ledger-v3.js +71 -2
- package/dist/commands/qa-run.d.ts +4 -0
- package/dist/commands/qa-run.d.ts.map +1 -0
- package/dist/commands/qa-run.js +141 -0
- package/dist/commands/resources.d.ts +4 -0
- package/dist/commands/resources.d.ts.map +1 -0
- package/dist/commands/resources.js +29 -0
- package/dist/commands/supervisor.d.ts +4 -0
- package/dist/commands/supervisor.d.ts.map +1 -0
- package/dist/commands/supervisor.js +101 -0
- package/dist/commands/web.d.ts.map +1 -1
- package/dist/commands/web.js +17 -0
- package/dist/commands/workflow.d.ts.map +1 -1
- package/dist/commands/workflow.js +4 -0
- package/dist/core/agents/cli.js +7 -3
- package/dist/core/agents/health.d.ts +17 -0
- package/dist/core/agents/health.d.ts.map +1 -0
- package/dist/core/agents/health.js +109 -0
- package/dist/core/agents/mailbox.d.ts +92 -0
- package/dist/core/agents/mailbox.d.ts.map +1 -0
- package/dist/core/agents/mailbox.js +325 -0
- package/dist/core/agents/reconcile-coordination-v3.d.ts +44 -0
- package/dist/core/agents/reconcile-coordination-v3.d.ts.map +1 -0
- package/dist/core/agents/reconcile-coordination-v3.js +58 -0
- package/dist/core/agents/render/prompt-context.d.ts +5 -0
- package/dist/core/agents/render/prompt-context.d.ts.map +1 -1
- package/dist/core/agents/render/prompt-context.js +34 -13
- package/dist/core/agents/render/session-context.d.ts +8 -0
- package/dist/core/agents/render/session-context.d.ts.map +1 -1
- package/dist/core/agents/render/session-context.js +34 -3
- package/dist/core/agents/rules/commit-conflict.d.ts.map +1 -1
- package/dist/core/agents/rules/commit-conflict.js +50 -1
- package/dist/core/agents/rules/stop-hook.d.ts.map +1 -1
- package/dist/core/agents/rules/stop-hook.js +6 -10
- package/dist/core/agents/session-finalizer-v3.js +4 -1
- package/dist/core/artifacts/index.d.ts +26 -1
- package/dist/core/artifacts/index.d.ts.map +1 -1
- package/dist/core/artifacts/index.js +146 -6
- package/dist/core/config.d.ts +12 -0
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +43 -0
- package/dist/core/diagnostics/advice.d.ts +9 -0
- package/dist/core/diagnostics/advice.d.ts.map +1 -0
- package/dist/core/diagnostics/advice.js +112 -0
- package/dist/core/diagnostics/bundle.d.ts +35 -0
- package/dist/core/diagnostics/bundle.d.ts.map +1 -0
- package/dist/core/diagnostics/bundle.js +874 -0
- package/dist/core/diagnostics/comparison.d.ts +5 -0
- package/dist/core/diagnostics/comparison.d.ts.map +1 -0
- package/dist/core/diagnostics/comparison.js +444 -0
- package/dist/core/diagnostics/contract.d.ts +245 -0
- package/dist/core/diagnostics/contract.d.ts.map +1 -0
- package/dist/core/diagnostics/contract.js +18 -0
- package/dist/core/diagnostics/identity.d.ts +3 -0
- package/dist/core/diagnostics/identity.d.ts.map +1 -0
- package/dist/core/diagnostics/identity.js +10 -0
- package/dist/core/diagnostics/index.d.ts +8 -0
- package/dist/core/diagnostics/index.d.ts.map +1 -0
- package/dist/core/diagnostics/index.js +7 -0
- package/dist/core/diagnostics/replay.d.ts +8 -0
- package/dist/core/diagnostics/replay.d.ts.map +1 -0
- package/dist/core/diagnostics/replay.js +213 -0
- package/dist/core/diagnostics/sanitize.d.ts +9 -0
- package/dist/core/diagnostics/sanitize.d.ts.map +1 -0
- package/dist/core/diagnostics/sanitize.js +84 -0
- package/dist/core/events/legacy-storage/compression.d.ts +13 -0
- package/dist/core/events/legacy-storage/compression.d.ts.map +1 -0
- package/dist/core/events/legacy-storage/compression.js +107 -0
- package/dist/core/events/legacy-storage/index.d.ts +1 -0
- package/dist/core/events/legacy-storage/index.d.ts.map +1 -1
- package/dist/core/events/legacy-storage/index.js +1 -0
- package/dist/core/events/v3/archive-retention.d.ts +33 -0
- package/dist/core/events/v3/archive-retention.d.ts.map +1 -0
- package/dist/core/events/v3/archive-retention.js +195 -0
- package/dist/core/events/v3/capabilities.d.ts +1 -1
- package/dist/core/events/v3/capabilities.d.ts.map +1 -1
- package/dist/core/events/v3/capabilities.js +1 -0
- package/dist/core/events/v3/index.d.ts +1 -0
- package/dist/core/events/v3/index.d.ts.map +1 -1
- package/dist/core/events/v3/index.js +1 -0
- package/dist/core/events/v3/live-routing.d.ts.map +1 -1
- package/dist/core/events/v3/live-routing.js +1 -0
- package/dist/core/events/v3/producers/hook-base.d.ts +1 -1
- package/dist/core/events/v3/producers/hook-base.d.ts.map +1 -1
- package/dist/core/events/v3/producers/hook-base.js +13 -2
- package/dist/core/events/v3/producers/intake.d.ts.map +1 -1
- package/dist/core/events/v3/producers/intake.js +1 -0
- package/dist/core/events/v3/producers/recorder.d.ts +16 -0
- package/dist/core/events/v3/producers/recorder.d.ts.map +1 -1
- package/dist/core/events/v3/producers/recorder.js +88 -1
- package/dist/core/hooks/adapter/output.d.ts +8 -0
- package/dist/core/hooks/adapter/output.d.ts.map +1 -1
- package/dist/core/hooks/adapter/output.js +11 -1
- package/dist/core/hooks/cli.js +183 -192
- package/dist/core/hooks/health.d.ts +59 -0
- package/dist/core/hooks/health.d.ts.map +1 -0
- package/dist/core/hooks/health.js +84 -0
- package/dist/core/resources/contract.d.ts +90 -0
- package/dist/core/resources/contract.d.ts.map +1 -0
- package/dist/core/resources/contract.js +2 -0
- package/dist/core/resources/index.d.ts +6 -0
- package/dist/core/resources/index.d.ts.map +1 -0
- package/dist/core/resources/index.js +5 -0
- package/dist/core/resources/sampler.d.ts +27 -0
- package/dist/core/resources/sampler.d.ts.map +1 -0
- package/dist/core/resources/sampler.js +357 -0
- package/dist/core/resources/service-status.d.ts +3 -0
- package/dist/core/resources/service-status.d.ts.map +1 -0
- package/dist/core/resources/service-status.js +48 -0
- package/dist/core/resources/service.d.ts +26 -0
- package/dist/core/resources/service.d.ts.map +1 -0
- package/dist/core/resources/service.js +292 -0
- package/dist/core/resources/storage.d.ts +13 -0
- package/dist/core/resources/storage.d.ts.map +1 -0
- package/dist/core/resources/storage.js +30 -0
- package/dist/core/storage/atomic-json.d.ts +3 -0
- package/dist/core/storage/atomic-json.d.ts.map +1 -0
- package/dist/core/storage/atomic-json.js +15 -0
- package/dist/core/storage/builtins.d.ts.map +1 -1
- package/dist/core/storage/builtins.js +45 -6
- package/dist/core/storage/logger.d.ts +2 -0
- package/dist/core/storage/logger.d.ts.map +1 -1
- package/dist/core/storage/logger.js +2 -0
- package/dist/core/storage/query.d.ts +14 -0
- package/dist/core/storage/query.d.ts.map +1 -1
- package/dist/core/storage/query.js +51 -0
- package/dist/core/supervisor/activity.d.ts +4 -0
- package/dist/core/supervisor/activity.d.ts.map +1 -0
- package/dist/core/supervisor/activity.js +141 -0
- package/dist/core/supervisor/contract.d.ts +268 -0
- package/dist/core/supervisor/contract.d.ts.map +1 -0
- package/dist/core/supervisor/contract.js +35 -0
- package/dist/core/supervisor/explanations.d.ts +4 -0
- package/dist/core/supervisor/explanations.d.ts.map +1 -0
- package/dist/core/supervisor/explanations.js +71 -0
- package/dist/core/supervisor/findings.d.ts +20 -0
- package/dist/core/supervisor/findings.d.ts.map +1 -0
- package/dist/core/supervisor/findings.js +399 -0
- package/dist/core/supervisor/history.d.ts +9 -0
- package/dist/core/supervisor/history.d.ts.map +1 -0
- package/dist/core/supervisor/history.js +46 -0
- package/dist/core/supervisor/hook-health-alerts.d.ts +14 -0
- package/dist/core/supervisor/hook-health-alerts.d.ts.map +1 -0
- package/dist/core/supervisor/hook-health-alerts.js +70 -0
- package/dist/core/supervisor/hook-health-storage.d.ts +5 -0
- package/dist/core/supervisor/hook-health-storage.d.ts.map +1 -0
- package/dist/core/supervisor/hook-health-storage.js +24 -0
- package/dist/core/supervisor/hook-health.d.ts +72 -0
- package/dist/core/supervisor/hook-health.d.ts.map +1 -0
- package/dist/core/supervisor/hook-health.js +203 -0
- package/dist/core/supervisor/hooks.d.ts +10 -0
- package/dist/core/supervisor/hooks.d.ts.map +1 -0
- package/dist/core/supervisor/hooks.js +28 -0
- package/dist/core/supervisor/index.d.ts +15 -0
- package/dist/core/supervisor/index.d.ts.map +1 -0
- package/dist/core/supervisor/index.js +14 -0
- package/dist/core/supervisor/log-feed.d.ts +9 -0
- package/dist/core/supervisor/log-feed.d.ts.map +1 -0
- package/dist/core/supervisor/log-feed.js +103 -0
- package/dist/core/supervisor/service.d.ts +29 -0
- package/dist/core/supervisor/service.d.ts.map +1 -0
- package/dist/core/supervisor/service.js +450 -0
- package/dist/core/supervisor/services.d.ts +11 -0
- package/dist/core/supervisor/services.d.ts.map +1 -0
- package/dist/core/supervisor/services.js +155 -0
- package/dist/core/supervisor/status.d.ts +3 -0
- package/dist/core/supervisor/status.d.ts.map +1 -0
- package/dist/core/supervisor/status.js +48 -0
- package/dist/core/supervisor/storage.d.ts +30 -0
- package/dist/core/supervisor/storage.d.ts.map +1 -0
- package/dist/core/supervisor/storage.js +73 -0
- package/dist/core/supervisor/timeline.d.ts +3 -0
- package/dist/core/supervisor/timeline.d.ts.map +1 -0
- package/dist/core/supervisor/timeline.js +87 -0
- package/dist/core/workflow/admission.d.ts +23 -0
- package/dist/core/workflow/admission.d.ts.map +1 -0
- package/dist/core/workflow/admission.js +136 -0
- package/dist/core/workflow/engine.d.ts.map +1 -1
- package/dist/core/workflow/engine.js +77 -2
- package/dist/core/workflow/index.d.ts +3 -2
- package/dist/core/workflow/index.d.ts.map +1 -1
- package/dist/core/workflow/index.js +2 -1
- package/dist/core/workflow/proof.d.ts +2 -1
- package/dist/core/workflow/proof.d.ts.map +1 -1
- package/dist/core/workflow/proof.js +39 -1
- package/dist/core/workflow/run-state.d.ts +3 -2
- package/dist/core/workflow/run-state.d.ts.map +1 -1
- package/dist/core/workflow/run-state.js +8 -1
- package/dist/core/workflow/types.d.ts +33 -1
- package/dist/core/workflow/types.d.ts.map +1 -1
- package/dist/core/workflow/types.js +2 -1
- package/dist/lib/browser/client.d.ts +5 -0
- package/dist/lib/browser/client.d.ts.map +1 -1
- package/dist/lib/browser/client.js +1 -0
- package/dist/lib/browser/index.d.ts +2 -0
- package/dist/lib/browser/index.d.ts.map +1 -1
- package/dist/lib/browser/index.js +2 -0
- package/dist/lib/browser/qa-run-contracts.d.ts +173 -0
- package/dist/lib/browser/qa-run-contracts.d.ts.map +1 -0
- package/dist/lib/browser/qa-run-contracts.js +226 -0
- package/dist/lib/browser/qa-run.d.ts +51 -0
- package/dist/lib/browser/qa-run.d.ts.map +1 -0
- package/dist/lib/browser/qa-run.js +684 -0
- package/dist/lib/coord-root-id.d.ts +9 -0
- package/dist/lib/coord-root-id.d.ts.map +1 -0
- package/dist/lib/coord-root-id.js +17 -0
- package/dist/lib/instructions/apply.d.ts +3 -1
- package/dist/lib/instructions/apply.d.ts.map +1 -1
- package/dist/lib/instructions/apply.js +74 -3
- package/dist/lib/instructions/templates.d.ts.map +1 -1
- package/dist/lib/instructions/templates.js +6 -0
- package/package.json +12 -1
- package/src/commander.ts +26 -0
- package/src/commands/agents.ts +102 -49
- package/src/commands/artifacts.ts +40 -2
- package/src/commands/browse.ts +15 -0
- package/src/commands/diagnostics.ts +271 -0
- package/src/commands/files.ts +102 -2
- package/src/commands/governor.ts +8 -0
- package/src/commands/ledger-v3.ts +82 -0
- package/src/commands/qa-run.ts +184 -0
- package/src/commands/resources.ts +38 -0
- package/src/commands/supervisor.ts +141 -0
- package/src/commands/web.ts +19 -0
- package/src/commands/workflow.ts +8 -0
- package/src/core/agents/cli.ts +7 -3
- package/src/core/agents/health.ts +142 -0
- package/src/core/agents/mailbox.ts +373 -0
- package/src/core/agents/reconcile-coordination-v3.ts +77 -0
- package/src/core/agents/render/prompt-context.ts +42 -12
- package/src/core/agents/render/session-context.ts +37 -3
- package/src/core/agents/rules/commit-conflict.ts +58 -1
- package/src/core/agents/rules/stop-hook.ts +6 -12
- package/src/core/agents/session-finalizer-v3.ts +4 -1
- package/src/core/artifacts/index.ts +196 -10
- package/src/core/config.ts +111 -2
- package/src/core/diagnostics/advice.ts +147 -0
- package/src/core/diagnostics/bundle.ts +1142 -0
- package/src/core/diagnostics/comparison.ts +565 -0
- package/src/core/diagnostics/contract.ts +311 -0
- package/src/core/diagnostics/identity.ts +11 -0
- package/src/core/diagnostics/index.ts +7 -0
- package/src/core/diagnostics/replay.ts +314 -0
- package/src/core/diagnostics/sanitize.ts +97 -0
- package/src/core/events/legacy-storage/compression.ts +130 -0
- package/src/core/events/legacy-storage/index.ts +1 -0
- package/src/core/events/v3/archive-retention.ts +251 -0
- package/src/core/events/v3/capabilities.ts +2 -0
- package/src/core/events/v3/index.ts +9 -0
- package/src/core/events/v3/live-routing.ts +1 -0
- package/src/core/events/v3/producers/hook-base.ts +14 -2
- package/src/core/events/v3/producers/intake.ts +1 -0
- package/src/core/events/v3/producers/recorder.ts +110 -1
- package/src/core/hooks/adapter/output.ts +12 -1
- package/src/core/hooks/cli.ts +192 -215
- package/src/core/hooks/health.ts +146 -0
- package/src/core/resources/contract.ts +98 -0
- package/src/core/resources/index.ts +5 -0
- package/src/core/resources/sampler.ts +458 -0
- package/src/core/resources/service-status.ts +62 -0
- package/src/core/resources/service.ts +337 -0
- package/src/core/resources/storage.ts +44 -0
- package/src/core/storage/atomic-json.ts +15 -0
- package/src/core/storage/builtins.ts +62 -6
- package/src/core/storage/logger.ts +2 -0
- package/src/core/storage/query.ts +58 -0
- package/src/core/supervisor/activity.ts +193 -0
- package/src/core/supervisor/contract.ts +312 -0
- package/src/core/supervisor/explanations.ts +104 -0
- package/src/core/supervisor/findings.ts +788 -0
- package/src/core/supervisor/history.ts +61 -0
- package/src/core/supervisor/hook-health-alerts.ts +108 -0
- package/src/core/supervisor/hook-health-storage.ts +25 -0
- package/src/core/supervisor/hook-health.ts +301 -0
- package/src/core/supervisor/hooks.ts +35 -0
- package/src/core/supervisor/index.ts +14 -0
- package/src/core/supervisor/log-feed.ts +131 -0
- package/src/core/supervisor/service.ts +511 -0
- package/src/core/supervisor/services.ts +203 -0
- package/src/core/supervisor/status.ts +59 -0
- package/src/core/supervisor/storage.ts +126 -0
- package/src/core/supervisor/timeline.ts +133 -0
- package/src/core/workflow/admission.ts +215 -0
- package/src/core/workflow/engine.ts +93 -1
- package/src/core/workflow/index.ts +10 -0
- package/src/core/workflow/proof.ts +54 -1
- package/src/core/workflow/run-state.ts +13 -1
- package/src/core/workflow/types.ts +39 -1
- package/src/lib/browser/client.ts +6 -0
- package/src/lib/browser/index.ts +29 -0
- package/src/lib/browser/qa-run-contracts.ts +380 -0
- package/src/lib/browser/qa-run.ts +784 -0
- package/src/lib/coord-root-id.ts +23 -0
- package/src/lib/instructions/apply.ts +81 -2
- package/src/lib/instructions/templates.ts +6 -0
|
@@ -4,6 +4,7 @@ import { monorepoRoot, resolveOwner } from "../core/agents/index.ts";
|
|
|
4
4
|
import { readLiveCoordinationRow } from "../core/agents/state/live-coordination-view.ts";
|
|
5
5
|
import {
|
|
6
6
|
type ArtifactActor,
|
|
7
|
+
adoptUnmanagedArtifactFiles,
|
|
7
8
|
cleanArtifacts,
|
|
8
9
|
createArtifact,
|
|
9
10
|
inventoryArtifacts,
|
|
@@ -28,7 +29,8 @@ export function registerArtifactsCommand(
|
|
|
28
29
|
.description("Create one managed artifact workspace and print its path.")
|
|
29
30
|
.requiredOption("--purpose <text>", "What the files are for")
|
|
30
31
|
.option("--days <n>", "Retention in days (default from artifacts.default_retention_days)")
|
|
31
|
-
.
|
|
32
|
+
.option("--big", "Acknowledge that this workspace may exceed the per-bundle size ceiling")
|
|
33
|
+
.action((slug: string, opts: { purpose: string; days?: string; big?: boolean }) => {
|
|
32
34
|
run(emit, () => {
|
|
33
35
|
const repoRoot = requireRepoRoot(context);
|
|
34
36
|
const actor = currentActor(repoRoot);
|
|
@@ -40,6 +42,7 @@ export function registerArtifactsCommand(
|
|
|
40
42
|
purpose: opts.purpose,
|
|
41
43
|
retentionDays,
|
|
42
44
|
actor,
|
|
45
|
+
big: opts.big,
|
|
43
46
|
});
|
|
44
47
|
emit.data({
|
|
45
48
|
path: created.path,
|
|
@@ -50,6 +53,34 @@ export function registerArtifactsCommand(
|
|
|
50
53
|
});
|
|
51
54
|
});
|
|
52
55
|
|
|
56
|
+
root
|
|
57
|
+
.command("adopt-unmanaged")
|
|
58
|
+
.description("Preview loose direct-child files, or move them into one managed workspace.")
|
|
59
|
+
.option(
|
|
60
|
+
"--purpose <text>",
|
|
61
|
+
"Why the adopted files are being retained",
|
|
62
|
+
"Adopt legacy loose artifact files",
|
|
63
|
+
)
|
|
64
|
+
.option("--days <n>", "Retention in days (default from artifacts.default_retention_days)")
|
|
65
|
+
.option("--big", "Acknowledge an adopted bundle above the per-bundle size ceiling")
|
|
66
|
+
.option("--yes", "Move the exact previewed regular files into a managed workspace")
|
|
67
|
+
.action((opts: { purpose: string; days?: string; big?: boolean; yes?: boolean }) => {
|
|
68
|
+
run(emit, () => {
|
|
69
|
+
const repoRoot = requireRepoRoot(context);
|
|
70
|
+
emit.data(
|
|
71
|
+
adoptUnmanagedArtifactFiles(repoRoot, {
|
|
72
|
+
yes: opts.yes,
|
|
73
|
+
big: opts.big,
|
|
74
|
+
purpose: opts.purpose,
|
|
75
|
+
retentionDays: opts.days
|
|
76
|
+
? parseDays(opts.days)
|
|
77
|
+
: artifactDefaultRetentionDays(repoRoot),
|
|
78
|
+
actor: currentActor(repoRoot),
|
|
79
|
+
}),
|
|
80
|
+
);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
|
|
53
84
|
root
|
|
54
85
|
.command("list")
|
|
55
86
|
.description("Inventory every artifact workspace with its cleanup classification.")
|
|
@@ -143,16 +174,23 @@ function parseDays(value: string): number {
|
|
|
143
174
|
return parsed;
|
|
144
175
|
}
|
|
145
176
|
|
|
146
|
-
function summarize(
|
|
177
|
+
function summarize(
|
|
178
|
+
rows: { classification: string; action: string; bytes?: number | null }[],
|
|
179
|
+
): Record<string, unknown> {
|
|
147
180
|
const classifications: Record<string, number> = {};
|
|
148
181
|
for (const row of rows) {
|
|
149
182
|
classifications[row.classification] = (classifications[row.classification] ?? 0) + 1;
|
|
150
183
|
}
|
|
151
184
|
return {
|
|
152
185
|
total: rows.length,
|
|
186
|
+
bytes: rows.reduce((sum, row) => sum + (row.bytes ?? 0), 0),
|
|
153
187
|
classifications,
|
|
154
188
|
would_delete: rows.filter((row) => row.action === "would-delete").length,
|
|
155
189
|
deleted: rows.filter((row) => row.action === "deleted").length,
|
|
190
|
+
would_delete_bytes: rows.reduce(
|
|
191
|
+
(sum, row) => sum + (row.action === "would-delete" ? (row.bytes ?? 0) : 0),
|
|
192
|
+
0,
|
|
193
|
+
),
|
|
156
194
|
};
|
|
157
195
|
}
|
|
158
196
|
|
package/src/commands/browse.ts
CHANGED
|
@@ -117,6 +117,7 @@ interface BrowseOpts {
|
|
|
117
117
|
store?: string;
|
|
118
118
|
profile?: string;
|
|
119
119
|
viewport?: string;
|
|
120
|
+
colorScheme?: string;
|
|
120
121
|
waitUntil: string;
|
|
121
122
|
timeout: string;
|
|
122
123
|
json?: boolean;
|
|
@@ -275,6 +276,12 @@ export function registerBrowseCommand(
|
|
|
275
276
|
"Viewport: mobile (390x844), tablet (820x1180), desktop (1280x800), hd (1920x1080), or explicit '1920x1080'",
|
|
276
277
|
"desktop",
|
|
277
278
|
)
|
|
279
|
+
.option(
|
|
280
|
+
"--color-scheme <scheme>",
|
|
281
|
+
"Emulate prefers-color-scheme for the whole session: light | dark. " +
|
|
282
|
+
"Renders theme-aware pages in that scheme without page-specific toggles. " +
|
|
283
|
+
"Absent = browser default (unchanged behavior).",
|
|
284
|
+
)
|
|
278
285
|
.option("--login", "Headed mode for one-time auth flow (cookies persist in profile)")
|
|
279
286
|
.option(
|
|
280
287
|
"--login-close-file <path>",
|
|
@@ -734,6 +741,13 @@ async function runBrowse(
|
|
|
734
741
|
: new CookieJar({ path: opts.store ?? DEFAULT_STORE, source: "harn-browse" });
|
|
735
742
|
const headed = opts.login || opts.headed;
|
|
736
743
|
const viewport = parseViewport(opts.viewport ?? "desktop");
|
|
744
|
+
let colorScheme: "light" | "dark" | undefined;
|
|
745
|
+
if (opts.colorScheme !== undefined) {
|
|
746
|
+
if (opts.colorScheme !== "light" && opts.colorScheme !== "dark") {
|
|
747
|
+
throw new Error(`--color-scheme must be light or dark (got: ${opts.colorScheme}).`);
|
|
748
|
+
}
|
|
749
|
+
colorScheme = opts.colorScheme;
|
|
750
|
+
}
|
|
737
751
|
const proxy = opts.proxyFromEnv ? browserProxyFromEnv() : undefined;
|
|
738
752
|
const proxyGate = opts.proxyFromEnv ? browserProxyGateFromEnv() : null;
|
|
739
753
|
if (opts.loginCloseFile && !opts.login) {
|
|
@@ -754,6 +768,7 @@ async function runBrowse(
|
|
|
754
768
|
headed,
|
|
755
769
|
jar,
|
|
756
770
|
viewport,
|
|
771
|
+
...(colorScheme ? { colorScheme } : {}),
|
|
757
772
|
navigationTimeout: Number.parseInt(opts.timeout, 10),
|
|
758
773
|
waitUntil: opts.waitUntil as BrowseOpts["waitUntil"] as never,
|
|
759
774
|
recordHarPath: opts.networkHar ? resolve(opts.networkHar) : undefined,
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import type { Command } from "commander";
|
|
2
|
+
import type { EmitContext, HarneryProgramContext } from "../commander.ts";
|
|
3
|
+
import { monorepoRoot, resolveOwner } from "../core/agents/index.ts";
|
|
4
|
+
import { readLiveCoordinationRow } from "../core/agents/state/live-coordination-view.ts";
|
|
5
|
+
import type { ArtifactActor } from "../core/artifacts/index.ts";
|
|
6
|
+
import {
|
|
7
|
+
buildDiagnosticAdvice,
|
|
8
|
+
captureDiagnosticBundle,
|
|
9
|
+
compareDiagnosticBundles,
|
|
10
|
+
DIAGNOSTIC_COMMAND_SCHEMA_VERSION,
|
|
11
|
+
listDiagnosticBundles,
|
|
12
|
+
renderDiagnosticBundleComparison,
|
|
13
|
+
replayDiagnosticBundle,
|
|
14
|
+
showDiagnosticBundle,
|
|
15
|
+
} from "../core/diagnostics/index.ts";
|
|
16
|
+
import {
|
|
17
|
+
buildSupervisorTimeline,
|
|
18
|
+
explainSupervisorFinding,
|
|
19
|
+
readSupervisorExplanation,
|
|
20
|
+
readSupervisorFindings,
|
|
21
|
+
readSupervisorStatus,
|
|
22
|
+
readSupervisorTimeline,
|
|
23
|
+
type SupervisorCapability,
|
|
24
|
+
type SupervisorFinding,
|
|
25
|
+
} from "../core/supervisor/index.ts";
|
|
26
|
+
|
|
27
|
+
export function registerDiagnosticsCommand(
|
|
28
|
+
program: Command,
|
|
29
|
+
emit: EmitContext,
|
|
30
|
+
context?: HarneryProgramContext,
|
|
31
|
+
): void {
|
|
32
|
+
const root = program
|
|
33
|
+
.command("diagnostics")
|
|
34
|
+
.description("Capture, inspect, and replay sanitized local diagnostic bundles.");
|
|
35
|
+
|
|
36
|
+
root
|
|
37
|
+
.command("list")
|
|
38
|
+
.description("List live findings and managed diagnostic bundles.")
|
|
39
|
+
.action(() => {
|
|
40
|
+
run(emit, () => {
|
|
41
|
+
const repoRoot = requireRepoRoot(context);
|
|
42
|
+
const report = readSupervisorFindings(repoRoot);
|
|
43
|
+
const findings = mergeFindings(report?.active ?? [], report?.transitions ?? []);
|
|
44
|
+
const bundles = listDiagnosticBundles(repoRoot);
|
|
45
|
+
const capability = liveFindingsCapability(repoRoot, report !== undefined);
|
|
46
|
+
emit.data({
|
|
47
|
+
schema_version: DIAGNOSTIC_COMMAND_SCHEMA_VERSION,
|
|
48
|
+
kind: "diagnostic_list",
|
|
49
|
+
findings,
|
|
50
|
+
bundles,
|
|
51
|
+
capability,
|
|
52
|
+
total_findings: findings.length,
|
|
53
|
+
total_bundles: bundles.length,
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
root
|
|
59
|
+
.command("show <ref>")
|
|
60
|
+
.description("Show one finding or validate one diagnostic bundle.")
|
|
61
|
+
.action((ref: string) => {
|
|
62
|
+
run(emit, () => {
|
|
63
|
+
const repoRoot = requireRepoRoot(context);
|
|
64
|
+
const finding = findFinding(repoRoot, ref);
|
|
65
|
+
if (finding) {
|
|
66
|
+
emit.data({
|
|
67
|
+
schema_version: DIAGNOSTIC_COMMAND_SCHEMA_VERSION,
|
|
68
|
+
kind: "diagnostic_finding",
|
|
69
|
+
finding,
|
|
70
|
+
timeline:
|
|
71
|
+
readSupervisorTimeline(repoRoot, finding.id) ?? buildSupervisorTimeline(finding),
|
|
72
|
+
explanation:
|
|
73
|
+
readSupervisorExplanation(repoRoot, finding.id) ?? explainSupervisorFinding(finding),
|
|
74
|
+
});
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const bundle = showDiagnosticBundle(repoRoot, ref);
|
|
78
|
+
emit.data({
|
|
79
|
+
schema_version: DIAGNOSTIC_COMMAND_SCHEMA_VERSION,
|
|
80
|
+
kind: "diagnostic_bundle",
|
|
81
|
+
bundle: {
|
|
82
|
+
path: bundle.path,
|
|
83
|
+
manifest: bundle.manifest,
|
|
84
|
+
summary: bundle.summary,
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
root
|
|
91
|
+
.command("explain")
|
|
92
|
+
.description("Report bounded local pressure advice without taking action.")
|
|
93
|
+
.option("--bundle <artifact-ref>", "Use a frozen diagnostic bundle instead of live state")
|
|
94
|
+
.option("--json", "Emit structured JSON")
|
|
95
|
+
.action((opts: { bundle?: string; json?: boolean }) => {
|
|
96
|
+
run(emit, () => {
|
|
97
|
+
if (opts.json) emit.config({ format: "json" });
|
|
98
|
+
const repoRoot = requireRepoRoot(context);
|
|
99
|
+
if (opts.bundle) {
|
|
100
|
+
const bundle = showDiagnosticBundle(repoRoot, opts.bundle);
|
|
101
|
+
emit.data({
|
|
102
|
+
schema_version: DIAGNOSTIC_COMMAND_SCHEMA_VERSION,
|
|
103
|
+
kind: "diagnostic_advice",
|
|
104
|
+
source: {
|
|
105
|
+
mode: "frozen",
|
|
106
|
+
artifact_id: bundle.manifest.artifact_id,
|
|
107
|
+
captured_at: bundle.manifest.captured_at,
|
|
108
|
+
},
|
|
109
|
+
advice: bundle.expected.advice,
|
|
110
|
+
});
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
const report = readSupervisorFindings(repoRoot);
|
|
114
|
+
const findings = mergeFindings(report?.active ?? [], report?.transitions ?? []);
|
|
115
|
+
const sourceCapability = liveFindingsCapability(repoRoot, report !== undefined);
|
|
116
|
+
emit.data({
|
|
117
|
+
schema_version: DIAGNOSTIC_COMMAND_SCHEMA_VERSION,
|
|
118
|
+
kind: "diagnostic_advice",
|
|
119
|
+
source: { mode: "live" },
|
|
120
|
+
advice: buildDiagnosticAdvice({
|
|
121
|
+
findings,
|
|
122
|
+
sourceCapability,
|
|
123
|
+
evaluatedAt: new Date().toISOString(),
|
|
124
|
+
}),
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
root
|
|
130
|
+
.command("capture")
|
|
131
|
+
.description("Capture sanitized supervisor inputs into a frozen managed bundle.")
|
|
132
|
+
.option("--finding <id>", "Capture the time range for one finding")
|
|
133
|
+
.option("--from <timestamp>", "Capture observations from this ISO timestamp")
|
|
134
|
+
.option("--to <timestamp>", "Capture observations through this ISO timestamp")
|
|
135
|
+
.option("--days <n>", "Managed artifact retention in days")
|
|
136
|
+
.action((opts: { finding?: string; from?: string; to?: string; days?: string }) => {
|
|
137
|
+
run(emit, () => {
|
|
138
|
+
const repoRoot = requireRepoRoot(context);
|
|
139
|
+
const captured = captureDiagnosticBundle(repoRoot, {
|
|
140
|
+
findingId: opts.finding,
|
|
141
|
+
startAt: opts.from,
|
|
142
|
+
endAt: opts.to,
|
|
143
|
+
retentionDays: opts.days === undefined ? undefined : parseDays(opts.days),
|
|
144
|
+
actor: currentActor(repoRoot),
|
|
145
|
+
});
|
|
146
|
+
emit.data({
|
|
147
|
+
schema_version: DIAGNOSTIC_COMMAND_SCHEMA_VERSION,
|
|
148
|
+
kind: "diagnostic_bundle_capture",
|
|
149
|
+
bundle: {
|
|
150
|
+
path: captured.path,
|
|
151
|
+
artifact_id: captured.manifest.artifact_id,
|
|
152
|
+
captured_at: captured.manifest.captured_at,
|
|
153
|
+
finding_id: captured.manifest.finding_id,
|
|
154
|
+
summary: captured.summary,
|
|
155
|
+
},
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
root
|
|
161
|
+
.command("replay <artifact-ref>")
|
|
162
|
+
.description("Replay a frozen bundle without reading live supervisor state.")
|
|
163
|
+
.action((ref: string) => {
|
|
164
|
+
run(emit, () => {
|
|
165
|
+
emit.data({
|
|
166
|
+
schema_version: DIAGNOSTIC_COMMAND_SCHEMA_VERSION,
|
|
167
|
+
kind: "diagnostic_bundle_replay",
|
|
168
|
+
replay: replayDiagnosticBundle(requireRepoRoot(context), ref),
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
root
|
|
174
|
+
.command("compare <before> <after>")
|
|
175
|
+
.description("Compare two frozen bundles without reading live supervisor state.")
|
|
176
|
+
.option("--json", "Emit structured JSON")
|
|
177
|
+
.action((before: string, after: string, opts: { json?: boolean }) => {
|
|
178
|
+
run(emit, () => {
|
|
179
|
+
const comparison = compareDiagnosticBundles(requireRepoRoot(context), before, after);
|
|
180
|
+
if (opts.json) {
|
|
181
|
+
emit.config({ format: "json" });
|
|
182
|
+
emit.data({
|
|
183
|
+
schema_version: DIAGNOSTIC_COMMAND_SCHEMA_VERSION,
|
|
184
|
+
kind: "diagnostic_bundle_comparison",
|
|
185
|
+
comparison,
|
|
186
|
+
});
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
emit.text(renderDiagnosticBundleComparison(comparison));
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function liveFindingsCapability(repoRoot: string, reportPresent: boolean): SupervisorCapability {
|
|
195
|
+
if (!reportPresent) {
|
|
196
|
+
return {
|
|
197
|
+
source_kind: "supervisor.findings",
|
|
198
|
+
state: "unsupported",
|
|
199
|
+
reason_code: "source_missing",
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
const status = readSupervisorStatus(repoRoot);
|
|
203
|
+
if (status.running) return { source_kind: "supervisor.findings", state: "supported" };
|
|
204
|
+
return {
|
|
205
|
+
source_kind: "supervisor.findings",
|
|
206
|
+
state: "expired",
|
|
207
|
+
reason_code: status.stale
|
|
208
|
+
? "supervisor_status_stale"
|
|
209
|
+
: status.record
|
|
210
|
+
? "supervisor_not_running"
|
|
211
|
+
: "supervisor_status_missing",
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function findFinding(repoRoot: string, id: string): SupervisorFinding | undefined {
|
|
216
|
+
const report = readSupervisorFindings(repoRoot);
|
|
217
|
+
return mergeFindings(report?.active ?? [], report?.transitions ?? []).find(
|
|
218
|
+
(finding) => finding.id === id,
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function mergeFindings(
|
|
223
|
+
active: readonly SupervisorFinding[],
|
|
224
|
+
transitions: readonly SupervisorFinding[],
|
|
225
|
+
): SupervisorFinding[] {
|
|
226
|
+
const byId = new Map<string, SupervisorFinding>();
|
|
227
|
+
for (const finding of transitions) byId.set(finding.id, finding);
|
|
228
|
+
for (const finding of active) byId.set(finding.id, finding);
|
|
229
|
+
return [...byId.values()].sort(
|
|
230
|
+
(left, right) =>
|
|
231
|
+
Date.parse(right.observed_at) - Date.parse(left.observed_at) ||
|
|
232
|
+
left.id.localeCompare(right.id),
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function currentActor(repoRoot: string): ArtifactActor | undefined {
|
|
237
|
+
const instanceId = resolveOwner();
|
|
238
|
+
if (!instanceId) return undefined;
|
|
239
|
+
const heartbeat = readLiveCoordinationRow(repoRoot, instanceId);
|
|
240
|
+
return {
|
|
241
|
+
instance_id: instanceId,
|
|
242
|
+
session_id: heartbeat?.session_id,
|
|
243
|
+
name: heartbeat?.name,
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function requireRepoRoot(context?: HarneryProgramContext): string {
|
|
248
|
+
const root = context?.repoRoot ?? monorepoRoot();
|
|
249
|
+
if (!root) throw new Error("not inside a Git repository");
|
|
250
|
+
return root;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
function parseDays(value: string): number {
|
|
254
|
+
const parsed = Number(value);
|
|
255
|
+
if (!Number.isInteger(parsed) || parsed < 1 || parsed > 3_650) {
|
|
256
|
+
throw new Error("--days must be between 1 and 3650");
|
|
257
|
+
}
|
|
258
|
+
return parsed;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function run(emit: EmitContext, fn: () => void): void {
|
|
262
|
+
try {
|
|
263
|
+
fn();
|
|
264
|
+
} catch (error) {
|
|
265
|
+
emit.error({
|
|
266
|
+
code: "diagnostics_failed",
|
|
267
|
+
message: error instanceof Error ? error.message : String(error),
|
|
268
|
+
});
|
|
269
|
+
emit.setExitCode(1);
|
|
270
|
+
}
|
|
271
|
+
}
|
package/src/commands/files.ts
CHANGED
|
@@ -4,6 +4,7 @@ import type { Command } from "commander";
|
|
|
4
4
|
import type { EmitContext, HarneryProgramContext } from "../commander.ts";
|
|
5
5
|
import { resolveCoordRoot } from "../core/agents/coord-client.ts";
|
|
6
6
|
import { DEFAULT_WEB_PORT, resolveWebPort } from "../core/config.ts";
|
|
7
|
+
import { coordRootId, localCoordRootIdUrl } from "../lib/coord-root-id.ts";
|
|
7
8
|
import { localFilesOriginUrl, localFileViewerUrl } from "../lib/local-file-url.ts";
|
|
8
9
|
|
|
9
10
|
export { FILES_ORIGIN_HOST } from "../lib/local-file-url.ts";
|
|
@@ -22,6 +23,92 @@ export interface LocalFileUrl {
|
|
|
22
23
|
mode: Exclude<LocalFileUrlMode, "auto">;
|
|
23
24
|
}
|
|
24
25
|
|
|
26
|
+
export type DashboardRootErrorCode =
|
|
27
|
+
| "dashboard_unreachable"
|
|
28
|
+
| "dashboard_identity_unavailable"
|
|
29
|
+
| "dashboard_root_mismatch";
|
|
30
|
+
|
|
31
|
+
export class DashboardRootError extends Error {
|
|
32
|
+
constructor(
|
|
33
|
+
readonly code: DashboardRootErrorCode,
|
|
34
|
+
message: string,
|
|
35
|
+
readonly hint: string,
|
|
36
|
+
) {
|
|
37
|
+
super(message);
|
|
38
|
+
this.name = "DashboardRootError";
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
interface DashboardRootPayload {
|
|
43
|
+
root_id?: unknown;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export type DashboardRootFetch = (
|
|
47
|
+
input: string | URL | Request,
|
|
48
|
+
init?: RequestInit,
|
|
49
|
+
) => Promise<Response>;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Prove that the dashboard on the selected port serves the same canonical
|
|
53
|
+
* coordination root used to mint the file URL.
|
|
54
|
+
*/
|
|
55
|
+
export async function verifyDashboardRoot(
|
|
56
|
+
coordRoot: string,
|
|
57
|
+
port: number,
|
|
58
|
+
fetchImpl: DashboardRootFetch = fetch,
|
|
59
|
+
): Promise<void> {
|
|
60
|
+
const url = localCoordRootIdUrl(port);
|
|
61
|
+
let response: Response;
|
|
62
|
+
try {
|
|
63
|
+
response = await fetchImpl(url, {
|
|
64
|
+
headers: { accept: "application/json" },
|
|
65
|
+
signal: AbortSignal.timeout(5_000),
|
|
66
|
+
});
|
|
67
|
+
} catch {
|
|
68
|
+
throw new DashboardRootError(
|
|
69
|
+
"dashboard_unreachable",
|
|
70
|
+
`dashboard is not reachable at http://localhost:${port}`,
|
|
71
|
+
"Start the dashboard for this repository, then retry.",
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (!response.ok) {
|
|
76
|
+
throw new DashboardRootError(
|
|
77
|
+
"dashboard_identity_unavailable",
|
|
78
|
+
`dashboard at http://localhost:${port} cannot report its repository identity (HTTP ${response.status})`,
|
|
79
|
+
"Update and restart the dashboard, then retry.",
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
let payload: DashboardRootPayload;
|
|
84
|
+
try {
|
|
85
|
+
payload = (await response.json()) as DashboardRootPayload;
|
|
86
|
+
} catch {
|
|
87
|
+
throw new DashboardRootError(
|
|
88
|
+
"dashboard_identity_unavailable",
|
|
89
|
+
`dashboard at http://localhost:${port} returned an invalid repository identity`,
|
|
90
|
+
"Update and restart the dashboard, then retry.",
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (typeof payload.root_id !== "string") {
|
|
95
|
+
throw new DashboardRootError(
|
|
96
|
+
"dashboard_identity_unavailable",
|
|
97
|
+
`dashboard at http://localhost:${port} returned an invalid repository identity`,
|
|
98
|
+
"Update and restart the dashboard, then retry.",
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const expected = coordRootId(coordRoot);
|
|
103
|
+
if (payload.root_id !== expected) {
|
|
104
|
+
throw new DashboardRootError(
|
|
105
|
+
"dashboard_root_mismatch",
|
|
106
|
+
`dashboard at http://localhost:${port} serves a different repository`,
|
|
107
|
+
"Stop that dashboard and start this repository's dashboard, then retry.",
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
25
112
|
function isOutsideRoot(relPath: string): boolean {
|
|
26
113
|
return relPath === "" || relPath === ".." || relPath.startsWith(`..${path.sep}`);
|
|
27
114
|
}
|
|
@@ -92,10 +179,17 @@ export function registerFilesCommand(
|
|
|
92
179
|
.option("--coord-root <dir>", "Override the coord root")
|
|
93
180
|
.option("--raw", "Use the isolated files origin, regardless of extension")
|
|
94
181
|
.option("--viewer", "Use the dashboard file viewer, regardless of extension")
|
|
182
|
+
.option("--no-verify", "Mint without checking the running dashboard's repository identity")
|
|
95
183
|
.action(
|
|
96
|
-
(
|
|
184
|
+
async (
|
|
97
185
|
filePath: string,
|
|
98
|
-
opts: {
|
|
186
|
+
opts: {
|
|
187
|
+
port?: string;
|
|
188
|
+
coordRoot?: string;
|
|
189
|
+
raw?: boolean;
|
|
190
|
+
viewer?: boolean;
|
|
191
|
+
verify?: boolean;
|
|
192
|
+
},
|
|
99
193
|
) => {
|
|
100
194
|
if (opts.raw && opts.viewer) {
|
|
101
195
|
emit.error({
|
|
@@ -129,8 +223,14 @@ export function registerFilesCommand(
|
|
|
129
223
|
port,
|
|
130
224
|
mode: opts.raw ? "raw" : opts.viewer ? "viewer" : "auto",
|
|
131
225
|
});
|
|
226
|
+
if (opts.verify !== false) await verifyDashboardRoot(coordRoot, port);
|
|
132
227
|
emit.text(`${result.url}\n`);
|
|
133
228
|
} catch (error) {
|
|
229
|
+
if (error instanceof DashboardRootError) {
|
|
230
|
+
emit.error({ code: error.code, message: error.message, hint: error.hint });
|
|
231
|
+
emit.setExitCode(1);
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
134
234
|
emit.error({
|
|
135
235
|
code: "invalid_local_file",
|
|
136
236
|
message: error instanceof Error ? error.message : "invalid local file path",
|
package/src/commands/governor.ts
CHANGED
|
@@ -62,6 +62,7 @@ interface CreateOpts {
|
|
|
62
62
|
interface RunOpts {
|
|
63
63
|
adapter?: string;
|
|
64
64
|
cwd?: string;
|
|
65
|
+
observePressure?: boolean;
|
|
65
66
|
subscriptionOnly?: boolean;
|
|
66
67
|
allowApiBilling?: boolean;
|
|
67
68
|
policy?: string;
|
|
@@ -438,6 +439,10 @@ function addServiceOptions(command: Command): Command {
|
|
|
438
439
|
.option("--error-backoff-max-ms <n>", "Maximum service-error backoff (default 300000)")
|
|
439
440
|
.option("--adapter <name>", "Fallback adapter for agent calls without a specialist")
|
|
440
441
|
.option("--cwd <dir>", "Working directory for child agents")
|
|
442
|
+
.option(
|
|
443
|
+
"--observe-pressure",
|
|
444
|
+
"Record observer-only local pressure before each workflow's first real child dispatch",
|
|
445
|
+
)
|
|
441
446
|
.option("--subscription-only", "Require stored adapter-login billing")
|
|
442
447
|
.option("--allow-api-billing", "Permit API-key override billing")
|
|
443
448
|
.option("--policy <file>", "Host policy JSON/JSONC")
|
|
@@ -596,6 +601,9 @@ function registerRunCommand(
|
|
|
596
601
|
spawners: registry.spawners(),
|
|
597
602
|
defaultAdapter: opts.adapter,
|
|
598
603
|
cwd: opts.cwd,
|
|
604
|
+
diagnosticAdmission: opts.observePressure
|
|
605
|
+
? { schema_version: 1, mode: "shadow" }
|
|
606
|
+
: undefined,
|
|
599
607
|
subscriptionOnly:
|
|
600
608
|
opts.subscriptionOnly === true ? true : workflowSubscriptionOnly(coordRoot),
|
|
601
609
|
allowApiBilling: opts.allowApiBilling,
|
|
@@ -5,13 +5,16 @@ import { resolve } from "node:path";
|
|
|
5
5
|
import type { Command } from "commander";
|
|
6
6
|
import type { EmitContext, HarneryProgramContext } from "../commander.ts";
|
|
7
7
|
import {
|
|
8
|
+
compressSealedLegacyV1Segments,
|
|
8
9
|
inventoryLegacyV1Segments,
|
|
9
10
|
streamLegacyV1Rows,
|
|
10
11
|
verifyLegacyV1HardFence,
|
|
11
12
|
writeLegacyV1Canary,
|
|
12
13
|
} from "../core/events/legacy-storage/index.ts";
|
|
13
14
|
import {
|
|
15
|
+
cleanEventV3Archives,
|
|
14
16
|
initializeEventLedgerV3,
|
|
17
|
+
inventoryEventV3Archives,
|
|
15
18
|
readEventV3ControlState,
|
|
16
19
|
recoverInvalidEventLedgerV3,
|
|
17
20
|
sha256V3,
|
|
@@ -59,6 +62,39 @@ export function registerLedgerV3Command(
|
|
|
59
62
|
}
|
|
60
63
|
});
|
|
61
64
|
|
|
65
|
+
const archives = command
|
|
66
|
+
.command("archives")
|
|
67
|
+
.description("Inventory and enforce bounded retention for complete closed V3 epochs");
|
|
68
|
+
|
|
69
|
+
archives
|
|
70
|
+
.command("list")
|
|
71
|
+
.description("Show closed epochs, retention classifications, and planned actions")
|
|
72
|
+
.option("--root <path>", "Explicit coordination root")
|
|
73
|
+
.action((options: { root?: string }) => {
|
|
74
|
+
try {
|
|
75
|
+
const rows = inventoryEventV3Archives(resolve(options.root ?? coordRoot(context)));
|
|
76
|
+
emit.data({ rows, meta: summarizeArchiveRows(rows) });
|
|
77
|
+
} catch (error) {
|
|
78
|
+
emitFailure(emit, "ledger_v3_archive_inventory_failed", error);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
archives
|
|
83
|
+
.command("clean")
|
|
84
|
+
.description("Preview closed-epoch deletion; pass --yes to execute the exact current plan")
|
|
85
|
+
.option("--root <path>", "Explicit coordination root")
|
|
86
|
+
.option("--yes", "Delete only epochs still classified expired or over-budget")
|
|
87
|
+
.action((options: { root?: string; yes?: boolean }) => {
|
|
88
|
+
try {
|
|
89
|
+
const rows = cleanEventV3Archives(resolve(options.root ?? coordRoot(context)), {
|
|
90
|
+
yes: options.yes,
|
|
91
|
+
});
|
|
92
|
+
emit.data({ rows, meta: summarizeArchiveRows(rows) });
|
|
93
|
+
} catch (error) {
|
|
94
|
+
emitFailure(emit, "ledger_v3_archive_cleanup_failed", error);
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
|
|
62
98
|
command
|
|
63
99
|
.command("initialize")
|
|
64
100
|
.description("Create V3 control state, or archive and replace the current V3 epoch")
|
|
@@ -355,6 +391,32 @@ export function registerLedgerV3Command(
|
|
|
355
391
|
}
|
|
356
392
|
});
|
|
357
393
|
|
|
394
|
+
command
|
|
395
|
+
.command("legacy-compress")
|
|
396
|
+
.description("Preview verified gzip replacement of sealed non-terminal V1 shards")
|
|
397
|
+
.option("--root <path>", "Explicit coordination root")
|
|
398
|
+
.option("--yes", "Replace only unchanged shards after exact logical-row parity")
|
|
399
|
+
.action(async (options: { root?: string; yes?: boolean }) => {
|
|
400
|
+
try {
|
|
401
|
+
const rows = await compressSealedLegacyV1Segments(
|
|
402
|
+
resolve(options.root ?? coordRoot(context)),
|
|
403
|
+
{ yes: options.yes },
|
|
404
|
+
);
|
|
405
|
+
emit.data({
|
|
406
|
+
rows,
|
|
407
|
+
meta: {
|
|
408
|
+
total: rows.length,
|
|
409
|
+
would_compress: rows.filter((row) => row.action === "would-compress").length,
|
|
410
|
+
compressed: rows.filter((row) => row.action === "compressed").length,
|
|
411
|
+
bytes_before: rows.reduce((sum, row) => sum + row.bytes_before, 0),
|
|
412
|
+
bytes_after: rows.reduce((sum, row) => sum + (row.bytes_after ?? row.bytes_before), 0),
|
|
413
|
+
},
|
|
414
|
+
});
|
|
415
|
+
} catch (error) {
|
|
416
|
+
emitFailure(emit, "ledger_v1_compression_failed", error);
|
|
417
|
+
}
|
|
418
|
+
});
|
|
419
|
+
|
|
358
420
|
command
|
|
359
421
|
.command("verify-legacy")
|
|
360
422
|
.description("Stream and validate one loose or manifest-bound gzip legacy segment")
|
|
@@ -525,6 +587,26 @@ function sameSortedStrings(left: string[], right: string[]): boolean {
|
|
|
525
587
|
);
|
|
526
588
|
}
|
|
527
589
|
|
|
590
|
+
function summarizeArchiveRows(
|
|
591
|
+
rows: Array<{ classification: string; action: string; bytes: number | null }>,
|
|
592
|
+
): Record<string, unknown> {
|
|
593
|
+
const classifications: Record<string, number> = {};
|
|
594
|
+
for (const row of rows) {
|
|
595
|
+
classifications[row.classification] = (classifications[row.classification] ?? 0) + 1;
|
|
596
|
+
}
|
|
597
|
+
return {
|
|
598
|
+
total: rows.length,
|
|
599
|
+
bytes: rows.reduce((sum, row) => sum + (row.bytes ?? 0), 0),
|
|
600
|
+
classifications,
|
|
601
|
+
would_delete: rows.filter((row) => row.action === "would-delete").length,
|
|
602
|
+
would_delete_bytes: rows.reduce(
|
|
603
|
+
(sum, row) => sum + (row.action === "would-delete" ? (row.bytes ?? 0) : 0),
|
|
604
|
+
0,
|
|
605
|
+
),
|
|
606
|
+
deleted: rows.filter((row) => row.action === "deleted").length,
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
|
|
528
610
|
function emitFailure(emit: EmitContext, code: string, error: unknown): never {
|
|
529
611
|
emit.error({ code, message: error instanceof Error ? error.message : String(error) });
|
|
530
612
|
throw error;
|