harnery 0.41.0 → 0.42.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 +3 -0
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/agents.js +9 -1
- package/dist/commands/artifacts.d.ts.map +1 -1
- package/dist/commands/artifacts.js +113 -12
- package/dist/commands/browse.d.ts +164 -0
- package/dist/commands/browse.d.ts.map +1 -1
- package/dist/commands/browse.js +263 -51
- package/dist/commands/claude-desktop.d.ts.map +1 -1
- package/dist/commands/claude-desktop.js +52 -0
- package/dist/commands/disk.d.ts +6 -0
- package/dist/commands/disk.d.ts.map +1 -0
- package/dist/commands/disk.js +80 -0
- package/dist/commands/doctor.d.ts +8 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +48 -1
- package/dist/commands/files.d.ts +16 -0
- package/dist/commands/files.d.ts.map +1 -1
- package/dist/commands/files.js +54 -2
- package/dist/commands/init.d.ts +2 -2
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +43 -9
- package/dist/commands/rm.d.ts +4 -0
- package/dist/commands/rm.d.ts.map +1 -0
- package/dist/commands/rm.js +87 -0
- package/dist/commands/servers.d.ts +7 -0
- package/dist/commands/servers.d.ts.map +1 -0
- package/dist/commands/servers.js +394 -0
- package/dist/commands/tunnel.d.ts.map +1 -1
- package/dist/commands/tunnel.js +82 -2
- package/dist/core/adapters/profiles.d.ts +9 -0
- package/dist/core/adapters/profiles.d.ts.map +1 -1
- package/dist/core/adapters/profiles.js +22 -1
- package/dist/core/adapters/types.d.ts +9 -0
- package/dist/core/adapters/types.d.ts.map +1 -1
- package/dist/core/agents/cli.js +13 -6
- package/dist/core/agents/render/session-context.d.ts.map +1 -1
- package/dist/core/agents/render/session-context.js +2 -0
- package/dist/core/agents/state/live-coordination-view.d.ts +20 -0
- package/dist/core/agents/state/live-coordination-view.d.ts.map +1 -1
- package/dist/core/agents/state/live-coordination-view.js +60 -0
- package/dist/core/artifacts/delivery-card.js +9 -2
- package/dist/core/artifacts/index.d.ts +140 -4
- package/dist/core/artifacts/index.d.ts.map +1 -1
- package/dist/core/artifacts/index.js +522 -49
- package/dist/core/config.d.ts +68 -11
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +128 -3
- package/dist/core/diagnostics/bundle.d.ts.map +1 -1
- package/dist/core/diagnostics/bundle.js +2 -2
- package/dist/core/events/v3/producers/recorder.d.ts.map +1 -1
- package/dist/core/events/v3/producers/recorder.js +16 -0
- package/dist/core/events/v3/projection.js +9 -1
- package/dist/core/hooks/adapter/events.d.ts +17 -0
- package/dist/core/hooks/adapter/events.d.ts.map +1 -1
- package/dist/core/hooks/adapter/events.js +5 -0
- package/dist/core/hooks/adapter/runtime-telemetry.js +3 -1
- package/dist/core/hooks/adapter/wiring.d.ts +37 -7
- package/dist/core/hooks/adapter/wiring.d.ts.map +1 -1
- package/dist/core/hooks/adapter/wiring.js +62 -4
- package/dist/core/hooks/cli.js +45 -6
- package/dist/core/hooks/run-markers.d.ts +37 -0
- package/dist/core/hooks/run-markers.d.ts.map +1 -0
- package/dist/core/hooks/run-markers.js +109 -0
- package/dist/core/servers/index.d.ts +211 -0
- package/dist/core/servers/index.d.ts.map +1 -0
- package/dist/core/servers/index.js +560 -0
- package/dist/core/servers/net.d.ts +58 -0
- package/dist/core/servers/net.d.ts.map +1 -0
- package/dist/core/servers/net.js +270 -0
- package/dist/core/servers/tunnels.d.ts +14 -0
- package/dist/core/servers/tunnels.d.ts.map +1 -0
- package/dist/core/servers/tunnels.js +33 -0
- package/dist/core/storage/builtins.js +1 -0
- package/dist/core/workflow/engine.d.ts.map +1 -1
- package/dist/core/workflow/engine.js +30 -1
- package/dist/core/workflow/sandbox-projection.d.ts +13 -2
- package/dist/core/workflow/sandbox-projection.d.ts.map +1 -1
- package/dist/core/workflow/sandbox-projection.js +23 -0
- package/dist/core/workflow/spawn-claude.d.ts.map +1 -1
- package/dist/core/workflow/spawn-claude.js +6 -1
- package/dist/core/workflow/spawn-codex.d.ts +2 -0
- package/dist/core/workflow/spawn-codex.d.ts.map +1 -1
- package/dist/core/workflow/spawn-codex.js +20 -1
- package/dist/core/workflow/spawn-cursor.d.ts.map +1 -1
- package/dist/core/workflow/spawn-cursor.js +6 -1
- package/dist/core/workflow/spawn-opencode.d.ts.map +1 -1
- package/dist/core/workflow/spawn-opencode.js +4 -1
- package/dist/core/workflow/types.d.ts +47 -2
- package/dist/core/workflow/types.d.ts.map +1 -1
- package/dist/core/workflow/worker-access.d.ts +92 -0
- package/dist/core/workflow/worker-access.d.ts.map +1 -0
- package/dist/core/workflow/worker-access.js +450 -0
- package/dist/lib/browser/batch-steps.d.ts +18 -0
- package/dist/lib/browser/batch-steps.d.ts.map +1 -0
- package/dist/lib/browser/batch-steps.js +82 -0
- package/dist/lib/browser/collect/collector.d.ts +99 -0
- package/dist/lib/browser/collect/collector.d.ts.map +1 -0
- package/dist/lib/browser/collect/collector.js +202 -0
- package/dist/lib/browser/collect/fields.d.ts +31 -0
- package/dist/lib/browser/collect/fields.d.ts.map +1 -0
- package/dist/lib/browser/collect/fields.js +75 -0
- package/dist/lib/browser/collect/index.d.ts +6 -0
- package/dist/lib/browser/collect/index.d.ts.map +1 -0
- package/dist/lib/browser/collect/index.js +5 -0
- package/dist/lib/browser/collect/page-driver.d.ts +14 -0
- package/dist/lib/browser/collect/page-driver.d.ts.map +1 -0
- package/dist/lib/browser/collect/page-driver.js +306 -0
- package/dist/lib/browser/collect/presets.d.ts +52 -0
- package/dist/lib/browser/collect/presets.d.ts.map +1 -0
- package/dist/lib/browser/collect/presets.js +176 -0
- package/dist/lib/browser/collect/scroll-plan.d.ts +85 -0
- package/dist/lib/browser/collect/scroll-plan.d.ts.map +1 -0
- package/dist/lib/browser/collect/scroll-plan.js +118 -0
- package/dist/lib/browser/index.d.ts +1 -1
- package/dist/lib/browser/index.d.ts.map +1 -1
- package/dist/lib/browser/page-review-judge.d.ts +2 -0
- package/dist/lib/browser/page-review-judge.d.ts.map +1 -1
- package/dist/lib/browser/page-review-judge.js +13 -0
- package/dist/lib/browser/qa-run-contracts.d.ts +10 -0
- package/dist/lib/browser/qa-run-contracts.d.ts.map +1 -1
- package/dist/lib/browser/qa-run.d.ts.map +1 -1
- package/dist/lib/browser/qa-run.js +1 -0
- package/dist/lib/browser/windows-chrome.d.ts +59 -0
- package/dist/lib/browser/windows-chrome.d.ts.map +1 -0
- package/dist/lib/browser/windows-chrome.js +179 -0
- package/dist/lib/claude-desktop-share.d.ts +136 -0
- package/dist/lib/claude-desktop-share.d.ts.map +1 -0
- package/dist/lib/claude-desktop-share.js +394 -0
- package/dist/lib/disk-usage.d.ts +50 -0
- package/dist/lib/disk-usage.d.ts.map +1 -0
- package/dist/lib/disk-usage.js +303 -0
- package/dist/lib/docs-lint.d.ts +6 -0
- package/dist/lib/docs-lint.d.ts.map +1 -1
- package/dist/lib/docs-lint.js +8 -3
- package/dist/lib/guarded-remove.d.ts +34 -0
- package/dist/lib/guarded-remove.d.ts.map +1 -0
- package/dist/lib/guarded-remove.js +310 -0
- package/dist/lib/instructions/templates.js +8 -8
- package/dist/lib/tunnel/error-page.d.ts +1 -1
- package/dist/lib/tunnel/error-page.d.ts.map +1 -1
- package/dist/lib/tunnel/error-page.js +19 -8
- package/dist/lib/tunnel/gate.js +20 -1
- package/dist/lib/tunnel/path-scope.d.ts +22 -0
- package/dist/lib/tunnel/path-scope.d.ts.map +1 -0
- package/dist/lib/tunnel/path-scope.js +62 -0
- package/dist/lib/tunnel/state.d.ts +5 -0
- package/dist/lib/tunnel/state.d.ts.map +1 -1
- package/dist/lib/tunnel/state.js +17 -3
- package/package.json +6 -1
- package/schemas/config.schema.json +91 -0
- package/src/commander.ts +19 -0
- package/src/commands/agents.ts +14 -0
- package/src/commands/artifacts.ts +171 -19
- package/src/commands/browse.ts +400 -57
- package/src/commands/claude-desktop.ts +61 -0
- package/src/commands/disk.ts +114 -0
- package/src/commands/doctor.ts +52 -1
- package/src/commands/files.ts +93 -2
- package/src/commands/init.ts +55 -5
- package/src/commands/rm.ts +115 -0
- package/src/commands/servers.ts +506 -0
- package/src/commands/tunnel.ts +102 -2
- package/src/core/adapters/profiles.ts +22 -1
- package/src/core/adapters/types.ts +10 -0
- package/src/core/agents/cli.ts +14 -6
- package/src/core/agents/render/session-context.ts +1 -0
- package/src/core/agents/state/live-coordination-view.ts +73 -0
- package/src/core/artifacts/delivery-card.ts +10 -2
- package/src/core/artifacts/index.ts +697 -44
- package/src/core/config.ts +183 -4
- package/src/core/diagnostics/bundle.ts +2 -1
- package/src/core/events/v3/producers/recorder.ts +16 -0
- package/src/core/events/v3/projection.ts +11 -1
- package/src/core/hooks/adapter/events.ts +19 -0
- package/src/core/hooks/adapter/runtime-telemetry.ts +3 -1
- package/src/core/hooks/adapter/wiring.ts +116 -8
- package/src/core/hooks/cli.ts +47 -6
- package/src/core/hooks/run-markers.ts +132 -0
- package/src/core/servers/index.ts +712 -0
- package/src/core/servers/net.ts +283 -0
- package/src/core/servers/tunnels.ts +39 -0
- package/src/core/storage/builtins.ts +1 -0
- package/src/core/workflow/engine.ts +38 -1
- package/src/core/workflow/sandbox-projection.ts +38 -2
- package/src/core/workflow/spawn-claude.ts +5 -1
- package/src/core/workflow/spawn-codex.ts +18 -1
- package/src/core/workflow/spawn-cursor.ts +5 -1
- package/src/core/workflow/spawn-opencode.ts +4 -1
- package/src/core/workflow/types.ts +62 -2
- package/src/core/workflow/worker-access.ts +525 -0
- package/src/lib/browser/batch-steps.ts +79 -0
- package/src/lib/browser/collect/collector.ts +306 -0
- package/src/lib/browser/collect/fields.ts +87 -0
- package/src/lib/browser/collect/index.ts +47 -0
- package/src/lib/browser/collect/page-driver.ts +327 -0
- package/src/lib/browser/collect/presets.ts +237 -0
- package/src/lib/browser/collect/scroll-plan.ts +179 -0
- package/src/lib/browser/index.ts +1 -0
- package/src/lib/browser/page-review-judge.ts +16 -0
- package/src/lib/browser/qa-run-contracts.ts +11 -0
- package/src/lib/browser/qa-run.ts +1 -0
- package/src/lib/browser/windows-chrome.ts +227 -0
- package/src/lib/claude-desktop-share.ts +511 -0
- package/src/lib/disk-usage.ts +347 -0
- package/src/lib/docs-lint.ts +8 -3
- package/src/lib/guarded-remove.ts +376 -0
- package/src/lib/instructions/templates.ts +8 -8
- package/src/lib/tunnel/error-page.ts +25 -9
- package/src/lib/tunnel/gate.ts +22 -1
- package/src/lib/tunnel/path-scope.ts +73 -0
- package/src/lib/tunnel/state.ts +20 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "harnery",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.42.0",
|
|
4
4
|
"description": "Multi-agent coordination for AI coding agents - Claude Code, Cursor, and Codex.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Ryan Kelly",
|
|
@@ -137,6 +137,11 @@
|
|
|
137
137
|
"types": "./dist/core/supervisor/index.d.ts",
|
|
138
138
|
"import": "./dist/core/supervisor/index.js"
|
|
139
139
|
},
|
|
140
|
+
"./core/servers": {
|
|
141
|
+
"bun": "./src/core/servers/index.ts",
|
|
142
|
+
"types": "./dist/core/servers/index.d.ts",
|
|
143
|
+
"import": "./dist/core/servers/index.js"
|
|
144
|
+
},
|
|
140
145
|
"./core/diagnostics": {
|
|
141
146
|
"bun": "./src/core/diagnostics/index.ts",
|
|
142
147
|
"types": "./dist/core/diagnostics/index.d.ts",
|
|
@@ -240,6 +240,53 @@
|
|
|
240
240
|
"maximum": 3650,
|
|
241
241
|
"default": 3,
|
|
242
242
|
"description": "Retention for `harn artifacts create` when --days is absent. Env override: HARNERY_ARTIFACT_RETENTION_DAYS."
|
|
243
|
+
},
|
|
244
|
+
"auto_clean": {
|
|
245
|
+
"type": "boolean",
|
|
246
|
+
"default": true,
|
|
247
|
+
"description": "Run the throttled artifact cleanup at session start and before new artifact work. Env override: HARNERY_ARTIFACT_AUTO_CLEAN."
|
|
248
|
+
},
|
|
249
|
+
"max_bytes": {
|
|
250
|
+
"type": "integer",
|
|
251
|
+
"minimum": 67108864,
|
|
252
|
+
"maximum": 1099511627776,
|
|
253
|
+
"default": 21474836480,
|
|
254
|
+
"description": "Soft repository budget in bytes of disk use for unheld managed workspaces. Env override: HARNERY_ARTIFACT_MAX_BYTES."
|
|
255
|
+
},
|
|
256
|
+
"max_unit_bytes": {
|
|
257
|
+
"type": "integer",
|
|
258
|
+
"minimum": 16777216,
|
|
259
|
+
"maximum": 1099511627776,
|
|
260
|
+
"default": 1073741824,
|
|
261
|
+
"description": "Per-workspace ceiling in bytes of disk use; a workspace created with --big is exempt. Env override: HARNERY_ARTIFACT_MAX_UNIT_BYTES."
|
|
262
|
+
},
|
|
263
|
+
"idle_grace_hours": {
|
|
264
|
+
"type": "integer",
|
|
265
|
+
"minimum": 1,
|
|
266
|
+
"maximum": 8760,
|
|
267
|
+
"default": 24,
|
|
268
|
+
"description": "Hours an unexpired workspace must be idle (no file change, no owner heartbeat) before a size rule may delete it. Env override: HARNERY_ARTIFACT_IDLE_GRACE_HOURS."
|
|
269
|
+
},
|
|
270
|
+
"hold_days": {
|
|
271
|
+
"type": "integer",
|
|
272
|
+
"minimum": 1,
|
|
273
|
+
"maximum": 365,
|
|
274
|
+
"default": 14,
|
|
275
|
+
"description": "Days a hold protects a workspace before it lapses unless renewed with `harn artifacts hold` (same id and reason). Env override: HARNERY_ARTIFACT_HOLD_DAYS."
|
|
276
|
+
},
|
|
277
|
+
"max_held_bytes": {
|
|
278
|
+
"type": "integer",
|
|
279
|
+
"minimum": 67108864,
|
|
280
|
+
"maximum": 1099511627776,
|
|
281
|
+
"default": 21474836480,
|
|
282
|
+
"description": "Advisory budget in bytes of disk use for held workspaces. Exceeding it produces warnings; held work is never deleted. Env override: HARNERY_ARTIFACT_MAX_HELD_BYTES."
|
|
283
|
+
},
|
|
284
|
+
"min_free_bytes": {
|
|
285
|
+
"type": "integer",
|
|
286
|
+
"minimum": 0,
|
|
287
|
+
"maximum": 1125899906842624,
|
|
288
|
+
"default": 21474836480,
|
|
289
|
+
"description": "Free-disk floor for the artifact store. Below it, artifact commands warn and `artifacts create --big` refuses without --allow-low-disk. 0 disables the floor. Env override: HARNERY_ARTIFACT_MIN_FREE_BYTES."
|
|
243
290
|
}
|
|
244
291
|
}
|
|
245
292
|
},
|
|
@@ -306,6 +353,37 @@
|
|
|
306
353
|
"type": "boolean",
|
|
307
354
|
"default": false,
|
|
308
355
|
"description": "Pin `workflow run` to subscription billing: API-key vars are scrubbed from every child env. Stamped true by `harn init` when the key is absent. Env override: HARNERY_WORKFLOW_SUBSCRIPTION_ONLY=1|0."
|
|
356
|
+
},
|
|
357
|
+
"workerFullAccess": {
|
|
358
|
+
"type": "object",
|
|
359
|
+
"additionalProperties": false,
|
|
360
|
+
"description": "Let qualifying workflow workers launch without their vendor sandbox (ADR 0192). A launch qualifies only when this is enabled, the launching session itself can be shown to run with full access, and the worker's exact model and effort meet a floor listed here. Anything else keeps the ordinary sandboxed projection. Project config only; a user-global file cannot grant it. HARNERY_WORKFLOW_WORKER_FULL_ACCESS=0 turns it off for one process. An invalid value disables it entirely.",
|
|
361
|
+
"properties": {
|
|
362
|
+
"enabled": { "type": "boolean", "default": false },
|
|
363
|
+
"floors": {
|
|
364
|
+
"type": "object",
|
|
365
|
+
"description": "Per-adapter list of models a worker may run unsandboxed on. Keys are adapter ids.",
|
|
366
|
+
"additionalProperties": {
|
|
367
|
+
"type": "array",
|
|
368
|
+
"items": {
|
|
369
|
+
"type": "object",
|
|
370
|
+
"additionalProperties": false,
|
|
371
|
+
"required": ["model"],
|
|
372
|
+
"properties": {
|
|
373
|
+
"model": {
|
|
374
|
+
"type": "string",
|
|
375
|
+
"minLength": 1,
|
|
376
|
+
"description": "Exact model id the worker must name. Aliases and the adapter's default model never match."
|
|
377
|
+
},
|
|
378
|
+
"minEffort": {
|
|
379
|
+
"type": "string",
|
|
380
|
+
"description": "Lowest qualifying effort on the adapter's declared effort scale. Required for an adapter with an effort scale; not allowed for one that encodes effort in the model id."
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
309
387
|
}
|
|
310
388
|
}
|
|
311
389
|
},
|
|
@@ -349,6 +427,19 @@
|
|
|
349
427
|
"default": 65536
|
|
350
428
|
}
|
|
351
429
|
}
|
|
430
|
+
},
|
|
431
|
+
"codexWindowsBridge": {
|
|
432
|
+
"type": "object",
|
|
433
|
+
"additionalProperties": false,
|
|
434
|
+
"required": ["entryPoint"],
|
|
435
|
+
"description": "Route Windows-native Codex hooks through a resident WSL bridge (decision record 0197). init writes a commandWindows on each Codex hook that calls entryPoint when it is on PATH and the working directory is a WSL path, and otherwise runs the usual command. Project config only.",
|
|
436
|
+
"properties": {
|
|
437
|
+
"entryPoint": {
|
|
438
|
+
"type": "string",
|
|
439
|
+
"pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$",
|
|
440
|
+
"description": "Windows command name the bridge installs, for example codex-wsl-hook. Only a bridge that implements the decision record 0197 contract should install it."
|
|
441
|
+
}
|
|
442
|
+
}
|
|
352
443
|
}
|
|
353
444
|
}
|
|
354
445
|
},
|
package/src/commander.ts
CHANGED
|
@@ -320,6 +320,12 @@ function harneryCommandBundles({
|
|
|
320
320
|
binName,
|
|
321
321
|
}: CommandBundleContext): LazyCommandBundle[] {
|
|
322
322
|
return [
|
|
323
|
+
lazy(
|
|
324
|
+
"disk [path]",
|
|
325
|
+
"Measure checkout disk usage, including nested repositories and ignored files",
|
|
326
|
+
async (program) => (await import("./commands/disk.ts")).registerDiskCommand(program, emit),
|
|
327
|
+
{ hasOptions: true },
|
|
328
|
+
),
|
|
323
329
|
lazy(
|
|
324
330
|
"tokens <files...>",
|
|
325
331
|
"Count tokens in text/markdown files (offline, uses o200k_base as Claude proxy)",
|
|
@@ -596,6 +602,13 @@ function harneryCommandBundles({
|
|
|
596
602
|
async (program) =>
|
|
597
603
|
(await import("./commands/storage.ts")).registerStorageCommand(program, emit, context),
|
|
598
604
|
),
|
|
605
|
+
lazy(
|
|
606
|
+
"rm <paths...>",
|
|
607
|
+
"Preview guarded removal of untracked files; --yes applies permanent deletion",
|
|
608
|
+
async (program) =>
|
|
609
|
+
(await import("./commands/rm.ts")).registerRmCommand(program, emit, context),
|
|
610
|
+
{ hasOptions: true },
|
|
611
|
+
),
|
|
599
612
|
lazy("logs", "List and query bounded Harnery log families", async (program) =>
|
|
600
613
|
(await import("./commands/logs.ts")).registerLogsCommand(program, emit, context),
|
|
601
614
|
),
|
|
@@ -661,6 +674,12 @@ function harneryCommandBundles({
|
|
|
661
674
|
async (program) =>
|
|
662
675
|
(await import("./commands/tunnel.ts")).registerTunnelCommand(program, emit, context),
|
|
663
676
|
),
|
|
677
|
+
lazy(
|
|
678
|
+
"servers",
|
|
679
|
+
"Every local server started in this project: list, stop, clean up idle session servers, read logs",
|
|
680
|
+
async (program) =>
|
|
681
|
+
(await import("./commands/servers.ts")).registerServersCommand(program, emit, context),
|
|
682
|
+
),
|
|
664
683
|
lazy(
|
|
665
684
|
"docs",
|
|
666
685
|
"Documentation tooling: freshness report, metadata, lint, sweep, index",
|
package/src/commands/agents.ts
CHANGED
|
@@ -78,6 +78,9 @@ import {
|
|
|
78
78
|
readHeartbeat as readHeartbeatCache,
|
|
79
79
|
} from "../core/agents/state/heartbeat-writer.ts";
|
|
80
80
|
import {
|
|
81
|
+
describeLiveAuthorityBlockV3,
|
|
82
|
+
liveAuthorityBlockHintV3,
|
|
83
|
+
liveAuthorityBlockV3,
|
|
81
84
|
readLiveCoordinationRow,
|
|
82
85
|
readLiveCoordinationRows,
|
|
83
86
|
} from "../core/agents/state/live-coordination-view.ts";
|
|
@@ -1486,6 +1489,10 @@ function normalizeKind(kind: string | undefined | null): string {
|
|
|
1486
1489
|
* command refuses in turn and the caller has no way to guess the path back.
|
|
1487
1490
|
*/
|
|
1488
1491
|
function noLiveGenerationMessage(root: string, owner: string): string {
|
|
1492
|
+
const block = liveAuthorityBlockV3(root, owner);
|
|
1493
|
+
if (block) {
|
|
1494
|
+
return `resolved owner=${owner}; ${describeLiveAuthorityBlockV3(block)}; ${liveAuthorityBlockHintV3(resolveBinName(root))}`;
|
|
1495
|
+
}
|
|
1489
1496
|
return `resolved owner=${owner} but no authority-safe live V3 generation exists for it; ${lifecycleReopenHint(root)}`;
|
|
1490
1497
|
}
|
|
1491
1498
|
|
|
@@ -5230,6 +5237,13 @@ function runHeal(opts: {
|
|
|
5230
5237
|
}
|
|
5231
5238
|
|
|
5232
5239
|
if (proc.status !== 0) {
|
|
5240
|
+
const block = liveAuthorityBlockV3(root, owner);
|
|
5241
|
+
if (block) {
|
|
5242
|
+
emitHealFailure(
|
|
5243
|
+
"authority_blocked",
|
|
5244
|
+
`${describeLiveAuthorityBlockV3(block)}; a cache rebuild cannot restore authority the ledger withholds; ${liveAuthorityBlockHintV3(resolveBinName(root))}`,
|
|
5245
|
+
);
|
|
5246
|
+
}
|
|
5233
5247
|
emitHealFailure(
|
|
5234
5248
|
healFailureReason(root, owner, sessionId, healAdapter),
|
|
5235
5249
|
spawnFailureMessage(proc, `agent-coord ${action}`),
|
|
@@ -6,9 +6,13 @@ import {
|
|
|
6
6
|
type ArtifactActor,
|
|
7
7
|
type ArtifactDeliveryManifest,
|
|
8
8
|
adoptUnmanagedArtifactFiles,
|
|
9
|
+
allowBigArtifact,
|
|
9
10
|
artifactCapabilities,
|
|
11
|
+
artifactQuickUsage,
|
|
10
12
|
artifactReviewGuidance,
|
|
11
13
|
artifactsRoot,
|
|
14
|
+
artifactUsageReport,
|
|
15
|
+
assertArtifactDiskFloor,
|
|
12
16
|
autoCleanArtifacts,
|
|
13
17
|
cleanArtifacts,
|
|
14
18
|
createArtifact,
|
|
@@ -17,7 +21,9 @@ import {
|
|
|
17
21
|
inventoryArtifacts,
|
|
18
22
|
migrateArtifacts,
|
|
19
23
|
parseArtifactDeliverySpec,
|
|
24
|
+
readArtifactDeletions,
|
|
20
25
|
releaseArtifact,
|
|
26
|
+
removeArtifact,
|
|
21
27
|
renderArtifactDeliveryCard,
|
|
22
28
|
renewArtifact,
|
|
23
29
|
repairArtifactActivity,
|
|
@@ -28,7 +34,10 @@ import {
|
|
|
28
34
|
} from "../core/artifacts/index.ts";
|
|
29
35
|
import {
|
|
30
36
|
artifactDefaultRetentionDays,
|
|
37
|
+
artifactIdleGraceHours,
|
|
38
|
+
artifactMaxUnitBytes,
|
|
31
39
|
coordFreshnessSeconds,
|
|
40
|
+
resolveBinName,
|
|
32
41
|
reviewPackAutoCleanEnabled,
|
|
33
42
|
} from "../core/config.ts";
|
|
34
43
|
import { deleteExpiredPacks } from "../lib/browser/page-review-pack.ts";
|
|
@@ -50,8 +59,16 @@ export function registerArtifactsCommand(
|
|
|
50
59
|
.option("--days <n>", "Retention in days (default from artifacts.default_retention_days)")
|
|
51
60
|
.option("--minutes <n>", "Retention in minutes; cannot be combined with --days")
|
|
52
61
|
.option("--big", "Acknowledge that this workspace may exceed the per-bundle size ceiling")
|
|
62
|
+
.option(
|
|
63
|
+
"--allow-low-disk",
|
|
64
|
+
"Create a --big workspace even though free disk is below artifacts.min_free_bytes",
|
|
65
|
+
)
|
|
53
66
|
.option("--hold <id>", "Create the workspace with this hold already present")
|
|
54
67
|
.option("--hold-reason <text>", "Why the initial hold is required")
|
|
68
|
+
.option(
|
|
69
|
+
"--hold-persistent",
|
|
70
|
+
"Make the initial hold persistent: it never lapses and counts toward the held budget. Only for a hold that mirrors an external lease, such as an open checkout with unsynchronized work",
|
|
71
|
+
)
|
|
55
72
|
.option("--actor <instance-id>", "Stable owner identity for the initial hold")
|
|
56
73
|
.action(
|
|
57
74
|
(
|
|
@@ -61,8 +78,10 @@ export function registerArtifactsCommand(
|
|
|
61
78
|
days?: string;
|
|
62
79
|
minutes?: string;
|
|
63
80
|
big?: boolean;
|
|
81
|
+
allowLowDisk?: boolean;
|
|
64
82
|
hold?: string;
|
|
65
83
|
holdReason?: string;
|
|
84
|
+
holdPersistent?: boolean;
|
|
66
85
|
actor?: string;
|
|
67
86
|
},
|
|
68
87
|
) => {
|
|
@@ -73,6 +92,8 @@ export function registerArtifactsCommand(
|
|
|
73
92
|
const actor = opts.actor ? { instance_id: opts.actor } : currentActor(repoRoot);
|
|
74
93
|
if (!!opts.hold !== !!opts.holdReason)
|
|
75
94
|
throw new Error("--hold and --hold-reason must be used together");
|
|
95
|
+
if (opts.holdPersistent && !opts.hold)
|
|
96
|
+
throw new Error("--hold-persistent requires --hold");
|
|
76
97
|
const retentionDays = opts.days
|
|
77
98
|
? parseDays(opts.days)
|
|
78
99
|
: artifactDefaultRetentionDays(repoRoot);
|
|
@@ -86,6 +107,7 @@ export function registerArtifactsCommand(
|
|
|
86
107
|
"warn",
|
|
87
108
|
);
|
|
88
109
|
}
|
|
110
|
+
if (opts.big && !opts.allowLowDisk) assertArtifactDiskFloor(repoRoot);
|
|
89
111
|
const created = createArtifact(repoRoot, {
|
|
90
112
|
slug,
|
|
91
113
|
purpose: opts.purpose,
|
|
@@ -93,7 +115,15 @@ export function registerArtifactsCommand(
|
|
|
93
115
|
retentionMinutes,
|
|
94
116
|
actor,
|
|
95
117
|
big: opts.big,
|
|
96
|
-
holds: opts.hold
|
|
118
|
+
holds: opts.hold
|
|
119
|
+
? [
|
|
120
|
+
{
|
|
121
|
+
id: opts.hold,
|
|
122
|
+
reason: opts.holdReason!,
|
|
123
|
+
...(opts.holdPersistent ? { persistent: true } : {}),
|
|
124
|
+
},
|
|
125
|
+
]
|
|
126
|
+
: [],
|
|
97
127
|
});
|
|
98
128
|
emit.data({
|
|
99
129
|
path: created.path,
|
|
@@ -101,6 +131,13 @@ export function registerArtifactsCommand(
|
|
|
101
131
|
expires_at: created.manifest.retention.expires_at,
|
|
102
132
|
owner_instance_id: actor?.instance_id ?? null,
|
|
103
133
|
holds: created.manifest.holds,
|
|
134
|
+
...usageFields(emit, repoRoot),
|
|
135
|
+
...(opts.big
|
|
136
|
+
? {}
|
|
137
|
+
: {
|
|
138
|
+
size_ceiling_bytes: artifactMaxUnitBytes(repoRoot),
|
|
139
|
+
size_note: `Cleanup deletes this workspace before it expires if it grows past ${artifactMaxUnitBytes(repoRoot)} bytes on disk and then sits idle for ${artifactIdleGraceHours(repoRoot)}h. Create it with --big, or run ${resolveBinName(repoRoot)} artifacts allow-big later, if it will grow that large.`,
|
|
140
|
+
}),
|
|
104
141
|
after_review: artifactReviewGuidance(repoRoot, created.manifest.artifact_id),
|
|
105
142
|
});
|
|
106
143
|
});
|
|
@@ -144,7 +181,14 @@ export function registerArtifactsCommand(
|
|
|
144
181
|
const rows = inventoryArtifacts(repoRoot, {
|
|
145
182
|
freshnessSeconds: coordFreshnessSeconds(repoRoot),
|
|
146
183
|
});
|
|
147
|
-
|
|
184
|
+
const recentDeletions = readArtifactDeletions(repoRoot, {
|
|
185
|
+
since: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000),
|
|
186
|
+
});
|
|
187
|
+
emit.data({
|
|
188
|
+
rows,
|
|
189
|
+
meta: inventoryMeta(emit, repoRoot, rows),
|
|
190
|
+
recent_deletions: recentDeletions,
|
|
191
|
+
});
|
|
148
192
|
});
|
|
149
193
|
});
|
|
150
194
|
|
|
@@ -154,11 +198,21 @@ export function registerArtifactsCommand(
|
|
|
154
198
|
.action((ref: string) => {
|
|
155
199
|
run(emit, () => {
|
|
156
200
|
const repoRoot = requireRepoRoot(context);
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
201
|
+
try {
|
|
202
|
+
emit.data(
|
|
203
|
+
showArtifact(repoRoot, ref, {
|
|
204
|
+
freshnessSeconds: coordFreshnessSeconds(repoRoot),
|
|
205
|
+
}),
|
|
206
|
+
);
|
|
207
|
+
} catch (error) {
|
|
208
|
+
const deleted = readArtifactDeletions(repoRoot)
|
|
209
|
+
.reverse()
|
|
210
|
+
.find((record) => [record.artifact_id, record.name].includes(ref));
|
|
211
|
+
if (!deleted) throw error;
|
|
212
|
+
throw new Error(
|
|
213
|
+
`artifact "${ref}" was deleted by cleanup at ${deleted.deleted_at} as ${deleted.classification}: ${deleted.reason}`,
|
|
214
|
+
);
|
|
215
|
+
}
|
|
162
216
|
});
|
|
163
217
|
});
|
|
164
218
|
|
|
@@ -221,6 +275,18 @@ export function registerArtifactsCommand(
|
|
|
221
275
|
});
|
|
222
276
|
});
|
|
223
277
|
|
|
278
|
+
root
|
|
279
|
+
.command("allow-big <ref>")
|
|
280
|
+
.description(
|
|
281
|
+
"Exempt an existing workspace from the per-bundle size ceiling, as create --big would; expiry still applies.",
|
|
282
|
+
)
|
|
283
|
+
.action((ref: string) => {
|
|
284
|
+
run(emit, () => {
|
|
285
|
+
const repoRoot = requireRepoRoot(context);
|
|
286
|
+
emit.data(allowBigArtifact(repoRoot, ref, { actor: currentActor(repoRoot) }));
|
|
287
|
+
});
|
|
288
|
+
});
|
|
289
|
+
|
|
224
290
|
root
|
|
225
291
|
.command("release <ref>")
|
|
226
292
|
.description("Release active-owner protection without shortening retention.")
|
|
@@ -251,6 +317,20 @@ export function registerArtifactsCommand(
|
|
|
251
317
|
});
|
|
252
318
|
});
|
|
253
319
|
|
|
320
|
+
root
|
|
321
|
+
.command("remove <ref>")
|
|
322
|
+
.description("Preview immediate removal of one owned artifact; --yes permanently deletes it.")
|
|
323
|
+
.requiredOption("--reason <text>", "Why these reviewed files are no longer needed")
|
|
324
|
+
.option("--yes", "Permanently delete this one workspace after safety checks")
|
|
325
|
+
.action((ref: string, opts: { reason: string; yes?: boolean }) => {
|
|
326
|
+
run(emit, () => {
|
|
327
|
+
const repoRoot = requireRepoRoot(context);
|
|
328
|
+
emit.data(
|
|
329
|
+
removeArtifact(repoRoot, ref, opts.reason, { ...opts, actor: currentActor(repoRoot) }),
|
|
330
|
+
);
|
|
331
|
+
});
|
|
332
|
+
});
|
|
333
|
+
|
|
254
334
|
root
|
|
255
335
|
.command("capabilities")
|
|
256
336
|
.description("Report artifact schema and hold capabilities for embedding clients.")
|
|
@@ -278,21 +358,46 @@ export function registerArtifactsCommand(
|
|
|
278
358
|
|
|
279
359
|
root
|
|
280
360
|
.command("hold <ref>")
|
|
281
|
-
.description(
|
|
361
|
+
.description(
|
|
362
|
+
"Protect an artifact from cleanup until the hold lapses or its owner removes it; repeating the same id and reason renews it.",
|
|
363
|
+
)
|
|
282
364
|
.requiredOption("--id <id>", "Unique hold id within this artifact")
|
|
283
365
|
.requiredOption("--reason <text>", "Why cleanup must retain these files")
|
|
284
366
|
.option("--actor <instance-id>", "Stable hold owner; defaults to the current agent")
|
|
285
|
-
.
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
367
|
+
.option("--days <n>", "Hold lifetime in days, 1 to 365 (default from artifacts.hold_days)")
|
|
368
|
+
.option("--minutes <n>", "Hold lifetime in minutes; cannot be combined with --days")
|
|
369
|
+
.option(
|
|
370
|
+
"--persistent",
|
|
371
|
+
"Never lapse; counts toward the held budget. Only for a hold that mirrors an external lease, such as an open checkout with unsynchronized work",
|
|
372
|
+
)
|
|
373
|
+
.action(
|
|
374
|
+
(
|
|
375
|
+
ref: string,
|
|
376
|
+
opts: {
|
|
377
|
+
id: string;
|
|
378
|
+
reason: string;
|
|
379
|
+
actor?: string;
|
|
380
|
+
days?: string;
|
|
381
|
+
minutes?: string;
|
|
382
|
+
persistent?: boolean;
|
|
383
|
+
},
|
|
384
|
+
) =>
|
|
385
|
+
run(emit, () => {
|
|
386
|
+
const repoRoot = requireRepoRoot(context);
|
|
387
|
+
if (opts.days !== undefined && opts.minutes !== undefined)
|
|
388
|
+
throw new Error("choose either --days or --minutes");
|
|
389
|
+
if (opts.persistent && (opts.days !== undefined || opts.minutes !== undefined))
|
|
390
|
+
throw new Error("--persistent cannot be combined with --days or --minutes");
|
|
391
|
+
const manifest = holdArtifact(repoRoot, ref, {
|
|
290
392
|
id: opts.id,
|
|
291
393
|
reason: opts.reason,
|
|
292
394
|
actor: requireHoldActor(repoRoot, opts.actor),
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
395
|
+
...(opts.days !== undefined ? { days: parseHoldDays(opts.days) } : {}),
|
|
396
|
+
...(opts.minutes !== undefined ? { minutes: parseHoldMinutes(opts.minutes) } : {}),
|
|
397
|
+
...(opts.persistent ? { persistent: true } : {}),
|
|
398
|
+
});
|
|
399
|
+
emit.data({ ...manifest, ...usageFields(emit, repoRoot) });
|
|
400
|
+
}),
|
|
296
401
|
);
|
|
297
402
|
|
|
298
403
|
root
|
|
@@ -325,7 +430,7 @@ export function registerArtifactsCommand(
|
|
|
325
430
|
: undefined;
|
|
326
431
|
emit.data({
|
|
327
432
|
rows,
|
|
328
|
-
meta:
|
|
433
|
+
meta: inventoryMeta(emit, repoRoot, rows),
|
|
329
434
|
...(reviewPacks ? { review_packs: reviewPacks } : {}),
|
|
330
435
|
});
|
|
331
436
|
});
|
|
@@ -370,20 +475,67 @@ function parseMinutes(value: string): number {
|
|
|
370
475
|
return parsed;
|
|
371
476
|
}
|
|
372
477
|
|
|
478
|
+
function parseHoldDays(value: string): number {
|
|
479
|
+
const parsed = Number(value);
|
|
480
|
+
if (!Number.isInteger(parsed) || parsed <= 0 || parsed > 365)
|
|
481
|
+
throw new Error("--days must be between 1 and 365 for a hold");
|
|
482
|
+
return parsed;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
function parseHoldMinutes(value: string): number {
|
|
486
|
+
const parsed = Number(value);
|
|
487
|
+
if (!Number.isInteger(parsed) || parsed < 1 || parsed > 525600)
|
|
488
|
+
throw new Error("--minutes must be between 1 and 525600 for a hold");
|
|
489
|
+
return parsed;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/** Cheap usage for create and hold: cached held bytes plus live free disk. */
|
|
493
|
+
function usageFields(
|
|
494
|
+
emit: EmitContext,
|
|
495
|
+
repoRoot: string,
|
|
496
|
+
): { usage: ReturnType<typeof artifactQuickUsage>["usage"]; warnings: string[] } {
|
|
497
|
+
const quick = artifactQuickUsage(repoRoot);
|
|
498
|
+
for (const warning of quick.warnings) emit.log(warning, "warn");
|
|
499
|
+
return { usage: quick.usage, warnings: quick.warnings };
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/** Summary plus held budget and free disk for a full inventory; warnings also go to stderr. */
|
|
503
|
+
function inventoryMeta(
|
|
504
|
+
emit: EmitContext,
|
|
505
|
+
repoRoot: string,
|
|
506
|
+
rows: Parameters<typeof artifactUsageReport>[1],
|
|
507
|
+
): Record<string, unknown> {
|
|
508
|
+
const report = artifactUsageReport(repoRoot, rows);
|
|
509
|
+
for (const warning of report.warnings) emit.log(warning, "warn");
|
|
510
|
+
return { ...summarize(rows), ...report };
|
|
511
|
+
}
|
|
512
|
+
|
|
373
513
|
function collect(value: string, previous: string[]): string[] {
|
|
374
514
|
return [...previous, value];
|
|
375
515
|
}
|
|
376
516
|
|
|
377
517
|
function summarize(
|
|
378
|
-
rows: {
|
|
518
|
+
rows: {
|
|
519
|
+
classification: string;
|
|
520
|
+
action: string;
|
|
521
|
+
bytes?: number | null;
|
|
522
|
+
apparent_bytes?: number | null;
|
|
523
|
+
warning?: string | null;
|
|
524
|
+
}[],
|
|
379
525
|
): Record<string, unknown> {
|
|
380
526
|
const classifications: Record<string, number> = {};
|
|
381
527
|
for (const row of rows) {
|
|
382
528
|
classifications[row.classification] = (classifications[row.classification] ?? 0) + 1;
|
|
383
529
|
}
|
|
530
|
+
const bytes = rows.reduce((sum, row) => sum + (row.bytes ?? 0), 0);
|
|
384
531
|
return {
|
|
385
532
|
total: rows.length,
|
|
386
|
-
|
|
533
|
+
// Disk use. `apparent_bytes` is the sum of file lengths; a large gap
|
|
534
|
+
// between the two means sparse or hard-linked files.
|
|
535
|
+
bytes,
|
|
536
|
+
apparent_bytes: rows.reduce((sum, row) => sum + (row.apparent_bytes ?? 0), 0),
|
|
537
|
+
// Rows carrying a per-row `warning`; `warnings` holds store-level sentences.
|
|
538
|
+
row_warnings: rows.filter((row) => row.warning).length,
|
|
387
539
|
classifications,
|
|
388
540
|
would_delete: rows.filter((row) => row.action === "would-delete").length,
|
|
389
541
|
deleted: rows.filter((row) => row.action === "deleted").length,
|