harnery 0.37.0 → 0.38.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.d.ts +9 -0
- package/dist/commander.d.ts.map +1 -1
- package/dist/commander.js +7 -2
- package/dist/commands/admission.d.ts +21 -0
- package/dist/commands/admission.d.ts.map +1 -0
- package/dist/commands/admission.js +565 -0
- package/dist/commands/agents.d.ts +7 -0
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/agents.js +61 -1
- package/dist/commands/artifacts.d.ts.map +1 -1
- package/dist/commands/artifacts.js +48 -2
- package/dist/commands/browse-ai.d.ts +2 -2
- package/dist/commands/browse-ai.d.ts.map +1 -1
- package/dist/commands/browse-ai.js +6 -4
- package/dist/commands/browse.d.ts.map +1 -1
- package/dist/commands/browse.js +349 -21
- package/dist/commands/fetch.js +1 -0
- package/dist/commands/qa-record.d.ts +144 -0
- package/dist/commands/qa-record.d.ts.map +1 -0
- package/dist/commands/qa-record.js +0 -0
- package/dist/commands/qa-run.d.ts +7 -3
- package/dist/commands/qa-run.d.ts.map +1 -1
- package/dist/commands/qa-run.js +268 -13
- package/dist/commands/qa-status.d.ts +71 -0
- package/dist/commands/qa-status.d.ts.map +1 -0
- package/dist/commands/qa-status.js +490 -0
- package/dist/commands/qa-verify.d.ts +40 -0
- package/dist/commands/qa-verify.d.ts.map +1 -0
- package/dist/commands/qa-verify.js +180 -0
- package/dist/commands/review-pack.d.ts +4 -0
- package/dist/commands/review-pack.d.ts.map +1 -0
- package/dist/commands/review-pack.js +1001 -0
- package/dist/core/agents/qa-signal.d.ts +111 -0
- package/dist/core/agents/qa-signal.d.ts.map +1 -0
- package/dist/core/agents/qa-signal.js +231 -0
- package/dist/core/agents/session-name-display.d.ts +20 -5
- package/dist/core/agents/session-name-display.d.ts.map +1 -1
- package/dist/core/agents/session-name-display.js +67 -7
- package/dist/core/agents/state/heartbeat-reader.d.ts +7 -0
- package/dist/core/agents/state/heartbeat-reader.d.ts.map +1 -1
- package/dist/core/agents/state/heartbeat-writer.d.ts +11 -0
- package/dist/core/agents/state/heartbeat-writer.d.ts.map +1 -1
- package/dist/core/agents/state/heartbeat-writer.js +17 -0
- package/dist/core/agents/state/live-coordination-view.d.ts.map +1 -1
- package/dist/core/agents/state/live-coordination-view.js +1 -0
- package/dist/core/agents/state/live-coordination-writer.js +5 -0
- package/dist/core/artifacts/constants.d.ts +1 -1
- package/dist/core/artifacts/constants.js +1 -1
- package/dist/core/artifacts/index.d.ts +57 -6
- package/dist/core/artifacts/index.d.ts.map +1 -1
- package/dist/core/artifacts/index.js +265 -10
- package/dist/core/config.d.ts +8 -0
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +16 -0
- package/dist/core/diagnostics/bundle.d.ts +16 -0
- package/dist/core/diagnostics/bundle.d.ts.map +1 -1
- package/dist/core/diagnostics/bundle.js +101 -7
- package/dist/core/events/v3/bootstrap.d.ts.map +1 -1
- package/dist/core/events/v3/bootstrap.js +10 -0
- package/dist/core/events/v3/coordination-view.d.ts +3 -0
- package/dist/core/events/v3/coordination-view.d.ts.map +1 -1
- package/dist/core/events/v3/coordination-view.js +69 -8
- package/dist/core/events/v3/producers/intake.d.ts.map +1 -1
- package/dist/core/events/v3/producers/intake.js +9 -2
- package/dist/core/events/v3/producers/recorder.d.ts +23 -0
- package/dist/core/events/v3/producers/recorder.d.ts.map +1 -1
- package/dist/core/events/v3/producers/recorder.js +264 -18
- package/dist/core/hooks/cli.js +120 -27
- package/dist/core/hooks/resolve/transcript.d.ts.map +1 -1
- package/dist/core/hooks/resolve/transcript.js +10 -3
- package/dist/core/hooks/session-name-presence.d.ts.map +1 -1
- package/dist/core/hooks/session-name-presence.js +4 -1
- package/dist/core/qa-artifacts.d.ts +20 -0
- package/dist/core/qa-artifacts.d.ts.map +1 -0
- package/dist/core/qa-artifacts.js +110 -0
- package/dist/core/resources/contract.d.ts +6 -0
- package/dist/core/resources/contract.d.ts.map +1 -1
- package/dist/core/resources/sampler.d.ts +7 -0
- package/dist/core/resources/sampler.d.ts.map +1 -1
- package/dist/core/resources/sampler.js +106 -5
- package/dist/lib/admission.d.ts +71 -0
- package/dist/lib/admission.d.ts.map +1 -0
- package/dist/lib/admission.js +264 -0
- package/dist/lib/agent-browser/client.d.ts +1 -1
- package/dist/lib/agent-browser/client.d.ts.map +1 -1
- package/dist/lib/agent-browser/client.js +1 -5
- package/dist/lib/browser/capture-fidelity.d.ts +39 -0
- package/dist/lib/browser/capture-fidelity.d.ts.map +1 -0
- package/dist/lib/browser/capture-fidelity.js +84 -0
- package/dist/lib/browser/client.d.ts +41 -1
- package/dist/lib/browser/client.d.ts.map +1 -1
- package/dist/lib/browser/client.js +167 -9
- package/dist/lib/browser/critique.d.ts +38 -1
- package/dist/lib/browser/critique.d.ts.map +1 -1
- package/dist/lib/browser/critique.js +34 -6
- package/dist/lib/browser/index.d.ts +4 -2
- package/dist/lib/browser/index.d.ts.map +1 -1
- package/dist/lib/browser/index.js +2 -0
- package/dist/lib/browser/page-review-judge.d.ts +64 -0
- package/dist/lib/browser/page-review-judge.d.ts.map +1 -0
- package/dist/lib/browser/page-review-judge.js +270 -0
- package/dist/lib/browser/page-review-pack.d.ts +613 -0
- package/dist/lib/browser/page-review-pack.d.ts.map +1 -0
- package/dist/lib/browser/page-review-pack.js +1751 -0
- package/dist/lib/browser/qa-run-contracts.d.ts +214 -10
- package/dist/lib/browser/qa-run-contracts.d.ts.map +1 -1
- package/dist/lib/browser/qa-run-contracts.js +136 -1
- package/dist/lib/browser/qa-run.d.ts +100 -10
- package/dist/lib/browser/qa-run.d.ts.map +1 -1
- package/dist/lib/browser/qa-run.js +768 -169
- package/dist/lib/browser/request-diagnostics.d.ts +13 -0
- package/dist/lib/browser/request-diagnostics.d.ts.map +1 -0
- package/dist/lib/browser/request-diagnostics.js +18 -0
- package/dist/lib/browser/tiling.d.ts +19 -0
- package/dist/lib/browser/tiling.d.ts.map +1 -1
- package/dist/lib/browser/tiling.js +28 -0
- package/dist/lib/cookies/client.d.ts +9 -0
- package/dist/lib/cookies/client.d.ts.map +1 -1
- package/dist/lib/cookies/client.js +197 -44
- package/dist/lib/cookies/extra.d.ts +18 -0
- package/dist/lib/cookies/extra.d.ts.map +1 -0
- package/dist/lib/cookies/extra.js +14 -0
- package/dist/lib/cookies/index.d.ts +2 -1
- package/dist/lib/cookies/index.d.ts.map +1 -1
- package/dist/lib/cookies/index.js +2 -1
- package/dist/lib/durable-job.d.ts +124 -0
- package/dist/lib/durable-job.d.ts.map +1 -0
- package/dist/lib/durable-job.js +296 -0
- package/dist/lib/http/client.d.ts +7 -1
- package/dist/lib/http/client.d.ts.map +1 -1
- package/dist/lib/http/client.js +2 -0
- package/dist/lib/instructions/templates.d.ts.map +1 -1
- package/dist/lib/instructions/templates.js +5 -2
- package/package.json +8 -2
- package/src/commander.ts +50 -2
- package/src/commands/admission.ts +699 -0
- package/src/commands/agents.ts +87 -1
- package/src/commands/artifacts.ts +97 -21
- package/src/commands/browse-ai.ts +10 -5
- package/src/commands/browse.ts +481 -20
- package/src/commands/fetch.ts +1 -0
- package/src/commands/qa-record.ts +682 -0
- package/src/commands/qa-run.ts +335 -16
- package/src/commands/qa-status.ts +608 -0
- package/src/commands/qa-verify.ts +238 -0
- package/src/commands/review-pack.ts +1281 -0
- package/src/core/agents/qa-signal.ts +261 -0
- package/src/core/agents/session-name-display.ts +78 -7
- package/src/core/agents/state/heartbeat-reader.ts +7 -0
- package/src/core/agents/state/heartbeat-writer.ts +23 -0
- package/src/core/agents/state/live-coordination-view.ts +1 -0
- package/src/core/agents/state/live-coordination-writer.ts +5 -0
- package/src/core/artifacts/constants.ts +1 -1
- package/src/core/artifacts/index.ts +370 -21
- package/src/core/config.ts +23 -0
- package/src/core/diagnostics/bundle.ts +119 -11
- package/src/core/events/v3/bootstrap.ts +10 -0
- package/src/core/events/v3/coordination-view.ts +100 -11
- package/src/core/events/v3/producers/intake.ts +9 -2
- package/src/core/events/v3/producers/recorder.ts +312 -18
- package/src/core/hooks/cli.ts +140 -32
- package/src/core/hooks/resolve/transcript.ts +10 -3
- package/src/core/hooks/session-name-presence.ts +6 -1
- package/src/core/qa-artifacts.ts +126 -0
- package/src/core/resources/contract.ts +7 -0
- package/src/core/resources/sampler.ts +138 -6
- package/src/lib/admission.ts +347 -0
- package/src/lib/agent-browser/client.ts +2 -10
- package/src/lib/browser/capture-fidelity.ts +98 -0
- package/src/lib/browser/client.ts +206 -10
- package/src/lib/browser/critique.ts +62 -7
- package/src/lib/browser/index.ts +36 -0
- package/src/lib/browser/page-review-judge.ts +360 -0
- package/src/lib/browser/page-review-pack.ts +2384 -0
- package/src/lib/browser/qa-run-contracts.ts +366 -3
- package/src/lib/browser/qa-run.ts +868 -190
- package/src/lib/browser/request-diagnostics.ts +27 -0
- package/src/lib/browser/tiling.ts +32 -0
- package/src/lib/cookies/client.ts +228 -42
- package/src/lib/cookies/extra.ts +28 -0
- package/src/lib/cookies/index.ts +2 -0
- package/src/lib/durable-job.ts +407 -0
- package/src/lib/http/client.ts +13 -1
- package/src/lib/instructions/templates.ts +5 -2
package/src/commands/agents.ts
CHANGED
|
@@ -56,6 +56,7 @@ import {
|
|
|
56
56
|
queueMailboxMessage,
|
|
57
57
|
suggestNames,
|
|
58
58
|
} from "../core/agents/mailbox.ts";
|
|
59
|
+
import { qaSignalStatusRow } from "../core/agents/qa-signal.ts";
|
|
59
60
|
import { reconcileCoordinationV3 } from "../core/agents/reconcile-coordination-v3.ts";
|
|
60
61
|
import {
|
|
61
62
|
listSessionFinalizationRequestsV3,
|
|
@@ -91,7 +92,10 @@ import {
|
|
|
91
92
|
} from "../core/config.ts";
|
|
92
93
|
import type { EventTypeV3 } from "../core/events/v3/contract.ts";
|
|
93
94
|
import { readEventV3ControlState } from "../core/events/v3/control.ts";
|
|
94
|
-
import {
|
|
95
|
+
import {
|
|
96
|
+
projectCoordinationViewV3,
|
|
97
|
+
readCoordinationViewV3,
|
|
98
|
+
} from "../core/events/v3/coordination-view.ts";
|
|
95
99
|
import { liveInstanceIdV3 } from "../core/events/v3/live-routing.ts";
|
|
96
100
|
import {
|
|
97
101
|
countSummarizedSinceV3,
|
|
@@ -2399,6 +2403,12 @@ function runStatus(opts: {
|
|
|
2399
2403
|
/* non-fatal: status box should not fail on council errors */
|
|
2400
2404
|
}
|
|
2401
2405
|
|
|
2406
|
+
// Latest page-QA verdict for this session, with the RUNNER's clock. Session
|
|
2407
|
+
// age is not QA time; without this row an operator reads "session 58m" as if
|
|
2408
|
+
// the QA run took 58 minutes. Best-effort by contract — no pointer, a
|
|
2409
|
+
// malformed one, or any read failure renders no row.
|
|
2410
|
+
const qaSignal = qaSignalStatusRow({ coordRoot: root, instanceId: hb.instance_id });
|
|
2411
|
+
|
|
2402
2412
|
const data = {
|
|
2403
2413
|
name: displayName,
|
|
2404
2414
|
instance_id: hb.instance_id,
|
|
@@ -2436,6 +2446,7 @@ function runStatus(opts: {
|
|
|
2436
2446
|
timestamp_iso: new Date().toISOString(),
|
|
2437
2447
|
timestamp_local: timeStr,
|
|
2438
2448
|
...(quality ? { quality } : {}),
|
|
2449
|
+
...(qaSignal ? { qa: qaSignal.pointer } : {}),
|
|
2439
2450
|
...(finalization ? { finalization } : {}),
|
|
2440
2451
|
...(sessionEnd ? { session_end: sessionEnd } : {}),
|
|
2441
2452
|
};
|
|
@@ -2474,6 +2485,10 @@ function runStatus(opts: {
|
|
|
2474
2485
|
const idx = rows.findIndex((row) => row[0] === "time");
|
|
2475
2486
|
rows.splice(idx, 0, ["quality", formatRunQuality(quality.status, quality.signal_ids)]);
|
|
2476
2487
|
}
|
|
2488
|
+
if (qaSignal) {
|
|
2489
|
+
const idx = rows.findIndex((row) => row[0] === "time");
|
|
2490
|
+
rows.splice(idx, 0, ["qa", qaSignal.value]);
|
|
2491
|
+
}
|
|
2477
2492
|
if (sessionEnd) {
|
|
2478
2493
|
const idx = rows.findIndex((row) => row[0] === "time");
|
|
2479
2494
|
rows.splice(idx, 0, [
|
|
@@ -3101,6 +3116,13 @@ export type EventLedgerHealthV3 =
|
|
|
3101
3116
|
/** Times the summary gate failed open (loose write proceeded). */
|
|
3102
3117
|
mitigation_fail_open: number;
|
|
3103
3118
|
};
|
|
3119
|
+
coordination_authority: {
|
|
3120
|
+
safe: boolean;
|
|
3121
|
+
global_diagnostics: number;
|
|
3122
|
+
isolated_diagnostics: number;
|
|
3123
|
+
affected_generations: string[];
|
|
3124
|
+
codes: string[];
|
|
3125
|
+
};
|
|
3104
3126
|
span_pressure: Array<{ instance_id: string; generation_id: string; span_count: number }>;
|
|
3105
3127
|
collection_errors: string[];
|
|
3106
3128
|
};
|
|
@@ -3280,6 +3302,57 @@ export function collectEventLedgerHealthV3(root: string, nowMs = Date.now()): Ev
|
|
|
3280
3302
|
collectionErrors.push(`diagnostic summaries unreadable: ${errorText(error)}`);
|
|
3281
3303
|
}
|
|
3282
3304
|
|
|
3305
|
+
let coordinationAuthority: Extract<
|
|
3306
|
+
EventLedgerHealthV3,
|
|
3307
|
+
{ state: "live" }
|
|
3308
|
+
>["coordination_authority"] = {
|
|
3309
|
+
safe: false,
|
|
3310
|
+
global_diagnostics: 0,
|
|
3311
|
+
isolated_diagnostics: 0,
|
|
3312
|
+
affected_generations: [],
|
|
3313
|
+
codes: [],
|
|
3314
|
+
};
|
|
3315
|
+
try {
|
|
3316
|
+
const view = readCoordinationViewV3(root);
|
|
3317
|
+
const globalDiagnostics = view.global_diagnostics.filter(
|
|
3318
|
+
(diagnostic) => diagnostic.authority_blocking,
|
|
3319
|
+
);
|
|
3320
|
+
const isolatedDiagnostics = new Map<string, (typeof globalDiagnostics)[number]>();
|
|
3321
|
+
const affectedGenerations: string[] = [];
|
|
3322
|
+
for (const [generationId, diagnostics] of Object.entries(view.diagnostics_by_generation)) {
|
|
3323
|
+
const blocking = diagnostics.filter((diagnostic) => diagnostic.authority_blocking);
|
|
3324
|
+
if (blocking.length === 0) continue;
|
|
3325
|
+
affectedGenerations.push(generationId);
|
|
3326
|
+
for (const diagnostic of blocking) {
|
|
3327
|
+
isolatedDiagnostics.set(
|
|
3328
|
+
[
|
|
3329
|
+
diagnostic.code,
|
|
3330
|
+
diagnostic.source_code ?? "",
|
|
3331
|
+
diagnostic.event_id ?? "",
|
|
3332
|
+
diagnostic.generation_id ?? "",
|
|
3333
|
+
diagnostic.subject_instance_id ?? "",
|
|
3334
|
+
].join("\0"),
|
|
3335
|
+
diagnostic,
|
|
3336
|
+
);
|
|
3337
|
+
}
|
|
3338
|
+
}
|
|
3339
|
+
coordinationAuthority = {
|
|
3340
|
+
safe: view.authority_safe,
|
|
3341
|
+
global_diagnostics: globalDiagnostics.length,
|
|
3342
|
+
isolated_diagnostics: isolatedDiagnostics.size,
|
|
3343
|
+
affected_generations: affectedGenerations.sort(),
|
|
3344
|
+
codes: [
|
|
3345
|
+
...new Set(
|
|
3346
|
+
[...globalDiagnostics, ...isolatedDiagnostics.values()].map(
|
|
3347
|
+
(diagnostic) => diagnostic.source_code ?? diagnostic.code,
|
|
3348
|
+
),
|
|
3349
|
+
),
|
|
3350
|
+
].sort(),
|
|
3351
|
+
};
|
|
3352
|
+
} catch (error) {
|
|
3353
|
+
collectionErrors.push(`coordination authority unreadable: ${errorText(error)}`);
|
|
3354
|
+
}
|
|
3355
|
+
|
|
3283
3356
|
return {
|
|
3284
3357
|
state: "live",
|
|
3285
3358
|
mode: control.state,
|
|
@@ -3303,6 +3376,7 @@ export function collectEventLedgerHealthV3(root: string, nowMs = Date.now()): Ev
|
|
|
3303
3376
|
recent_by_category: recentByCategory,
|
|
3304
3377
|
mitigation_fail_open: mitigationFailOpen,
|
|
3305
3378
|
},
|
|
3379
|
+
coordination_authority: coordinationAuthority,
|
|
3306
3380
|
span_pressure: spanPressure,
|
|
3307
3381
|
collection_errors: collectionErrors,
|
|
3308
3382
|
};
|
|
@@ -4058,6 +4132,17 @@ function runHealth(opts: { since: string; json?: boolean }): void {
|
|
|
4058
4132
|
);
|
|
4059
4133
|
}
|
|
4060
4134
|
if (eventLedger.state === "live") {
|
|
4135
|
+
const authority = eventLedger.coordination_authority;
|
|
4136
|
+
if (authority.global_diagnostics > 0) {
|
|
4137
|
+
findings.push(
|
|
4138
|
+
`${authority.global_diagnostics} global coordination authority diagnostic(s): ${authority.codes.join(", ")}`,
|
|
4139
|
+
);
|
|
4140
|
+
}
|
|
4141
|
+
if (authority.isolated_diagnostics > 0) {
|
|
4142
|
+
findings.push(
|
|
4143
|
+
`${authority.isolated_diagnostics} coordination authority diagnostic(s) isolated to ${authority.affected_generations.length} generation(s): ${authority.codes.join(", ")}`,
|
|
4144
|
+
);
|
|
4145
|
+
}
|
|
4061
4146
|
// Open spans whose generation has no open turn: the turn ended without its
|
|
4062
4147
|
// tool spans closing, so an explicit end can only queue, never finalize.
|
|
4063
4148
|
const orphanGenerations = eventLedger.open_spans.generations.filter(
|
|
@@ -4198,6 +4283,7 @@ function renderHealthBox(report: HealthReport): void {
|
|
|
4198
4283
|
)
|
|
4199
4284
|
.join(", ");
|
|
4200
4285
|
ledgerStr = [
|
|
4286
|
+
`authority ${ledger.coordination_authority.safe ? "safe" : "unsafe"}${ledger.coordination_authority.isolated_diagnostics > 0 ? ` (${ledger.coordination_authority.isolated_diagnostics} isolated)` : ""}`,
|
|
4201
4287
|
`open spans ${ledger.open_spans.total}${orphanGenerations > 0 ? ` (${orphanGenerations} gen turn-closed)` : ""}`,
|
|
4202
4288
|
`pending ends ${ledger.pending_finalizations.length}${pendingAges ? ` (${pendingAges})` : ""}`,
|
|
4203
4289
|
`intake ${ledger.intake_spool.total}`,
|
|
@@ -5,12 +5,16 @@ import { readLiveCoordinationRow } from "../core/agents/state/live-coordination-
|
|
|
5
5
|
import {
|
|
6
6
|
type ArtifactActor,
|
|
7
7
|
adoptUnmanagedArtifactFiles,
|
|
8
|
+
artifactCapabilities,
|
|
8
9
|
cleanArtifacts,
|
|
9
10
|
createArtifact,
|
|
11
|
+
holdArtifact,
|
|
10
12
|
inventoryArtifacts,
|
|
13
|
+
migrateArtifacts,
|
|
11
14
|
releaseArtifact,
|
|
12
15
|
renewArtifact,
|
|
13
16
|
showArtifact,
|
|
17
|
+
unholdArtifact,
|
|
14
18
|
} from "../core/artifacts/index.ts";
|
|
15
19
|
import { artifactDefaultRetentionDays, coordFreshnessSeconds } from "../core/config.ts";
|
|
16
20
|
|
|
@@ -30,28 +34,47 @@ export function registerArtifactsCommand(
|
|
|
30
34
|
.requiredOption("--purpose <text>", "What the files are for")
|
|
31
35
|
.option("--days <n>", "Retention in days (default from artifacts.default_retention_days)")
|
|
32
36
|
.option("--big", "Acknowledge that this workspace may exceed the per-bundle size ceiling")
|
|
33
|
-
.
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
37
|
+
.option("--hold <id>", "Create the workspace with this hold already present")
|
|
38
|
+
.option("--hold-reason <text>", "Why the initial hold is required")
|
|
39
|
+
.option("--actor <instance-id>", "Stable owner identity for the initial hold")
|
|
40
|
+
.action(
|
|
41
|
+
(
|
|
42
|
+
slug: string,
|
|
43
|
+
opts: {
|
|
44
|
+
purpose: string;
|
|
45
|
+
days?: string;
|
|
46
|
+
big?: boolean;
|
|
47
|
+
hold?: string;
|
|
48
|
+
holdReason?: string;
|
|
49
|
+
actor?: string;
|
|
50
|
+
},
|
|
51
|
+
) => {
|
|
52
|
+
run(emit, () => {
|
|
53
|
+
const repoRoot = requireRepoRoot(context);
|
|
54
|
+
const actor = opts.actor ? { instance_id: opts.actor } : currentActor(repoRoot);
|
|
55
|
+
if (!!opts.hold !== !!opts.holdReason)
|
|
56
|
+
throw new Error("--hold and --hold-reason must be used together");
|
|
57
|
+
const retentionDays = opts.days
|
|
58
|
+
? parseDays(opts.days)
|
|
59
|
+
: artifactDefaultRetentionDays(repoRoot);
|
|
60
|
+
const created = createArtifact(repoRoot, {
|
|
61
|
+
slug,
|
|
62
|
+
purpose: opts.purpose,
|
|
63
|
+
retentionDays,
|
|
64
|
+
actor,
|
|
65
|
+
big: opts.big,
|
|
66
|
+
holds: opts.hold ? [{ id: opts.hold, reason: opts.holdReason! }] : [],
|
|
67
|
+
});
|
|
68
|
+
emit.data({
|
|
69
|
+
path: created.path,
|
|
70
|
+
artifact_id: created.manifest.artifact_id,
|
|
71
|
+
expires_at: created.manifest.retention.expires_at,
|
|
72
|
+
owner_instance_id: actor?.instance_id ?? null,
|
|
73
|
+
holds: created.manifest.holds,
|
|
74
|
+
});
|
|
52
75
|
});
|
|
53
|
-
}
|
|
54
|
-
|
|
76
|
+
},
|
|
77
|
+
);
|
|
55
78
|
|
|
56
79
|
root
|
|
57
80
|
.command("adopt-unmanaged")
|
|
@@ -133,6 +156,53 @@ export function registerArtifactsCommand(
|
|
|
133
156
|
});
|
|
134
157
|
});
|
|
135
158
|
|
|
159
|
+
root
|
|
160
|
+
.command("capabilities")
|
|
161
|
+
.description("Report artifact schema and hold capabilities for embedding clients.")
|
|
162
|
+
.option("--json", "Emit the capability document as JSON")
|
|
163
|
+
.action(() => emit.data(artifactCapabilities()));
|
|
164
|
+
|
|
165
|
+
root
|
|
166
|
+
.command("migrate")
|
|
167
|
+
.description("Preview the explicit v1 to v2 manifest migration, preserving preimages.")
|
|
168
|
+
.option("--yes", "Apply the migration to valid v1 manifests")
|
|
169
|
+
.action((opts: { yes?: boolean }) =>
|
|
170
|
+
run(emit, () => emit.data({ rows: migrateArtifacts(requireRepoRoot(context), opts) })),
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
root
|
|
174
|
+
.command("hold <ref>")
|
|
175
|
+
.description("Protect an artifact from cleanup until its owner removes this exact hold.")
|
|
176
|
+
.requiredOption("--id <id>", "Unique hold id within this artifact")
|
|
177
|
+
.requiredOption("--reason <text>", "Why cleanup must retain these files")
|
|
178
|
+
.option("--actor <instance-id>", "Stable hold owner; defaults to the current agent")
|
|
179
|
+
.action((ref: string, opts: { id: string; reason: string; actor?: string }) =>
|
|
180
|
+
run(emit, () => {
|
|
181
|
+
const repoRoot = requireRepoRoot(context);
|
|
182
|
+
emit.data(
|
|
183
|
+
holdArtifact(repoRoot, ref, {
|
|
184
|
+
id: opts.id,
|
|
185
|
+
reason: opts.reason,
|
|
186
|
+
actor: requireHoldActor(repoRoot, opts.actor),
|
|
187
|
+
}),
|
|
188
|
+
);
|
|
189
|
+
}),
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
root
|
|
193
|
+
.command("unhold <ref>")
|
|
194
|
+
.description("Remove one exact hold belonging to the supplied owner.")
|
|
195
|
+
.requiredOption("--id <id>", "Exact hold id to remove")
|
|
196
|
+
.option("--actor <instance-id>", "Stable hold owner; defaults to the current agent")
|
|
197
|
+
.action((ref: string, opts: { id: string; actor?: string }) =>
|
|
198
|
+
run(emit, () => {
|
|
199
|
+
const repoRoot = requireRepoRoot(context);
|
|
200
|
+
emit.data(
|
|
201
|
+
unholdArtifact(repoRoot, ref, opts.id, { actor: requireHoldActor(repoRoot, opts.actor) }),
|
|
202
|
+
);
|
|
203
|
+
}),
|
|
204
|
+
);
|
|
205
|
+
|
|
136
206
|
root
|
|
137
207
|
.command("clean")
|
|
138
208
|
.description("Preview expired artifact deletion; pass --yes to delete.")
|
|
@@ -149,6 +219,12 @@ export function registerArtifactsCommand(
|
|
|
149
219
|
});
|
|
150
220
|
}
|
|
151
221
|
|
|
222
|
+
function requireHoldActor(repoRoot: string, explicit?: string): ArtifactActor {
|
|
223
|
+
const actor = explicit ? { instance_id: explicit } : currentActor(repoRoot);
|
|
224
|
+
if (!actor) throw new Error("hold operations require --actor or a current agent identity");
|
|
225
|
+
return actor;
|
|
226
|
+
}
|
|
227
|
+
|
|
152
228
|
function currentActor(repoRoot: string): ArtifactActor | undefined {
|
|
153
229
|
const instanceId = resolveOwner();
|
|
154
230
|
if (!instanceId) return undefined;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { homedir } from "node:os";
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
3
|
import type { Command } from "commander";
|
|
4
|
-
import type { EmitContext } from "../commander.ts";
|
|
4
|
+
import type { EmitContext, HarneryProgramContext } from "../commander.ts";
|
|
5
5
|
import { AgentBrowser, type ExecResult } from "../lib/agent-browser/index.ts";
|
|
6
|
-
import { CookieJar } from "../lib/cookies/index.ts";
|
|
6
|
+
import { applyExtraCookies, CookieJar } from "../lib/cookies/index.ts";
|
|
7
7
|
|
|
8
8
|
// Module-scoped emit assigned by registerBrowseAiCommand. Same pattern as
|
|
9
9
|
// cookies/read/browse: helper functions close over `emit` so action
|
|
@@ -50,7 +50,11 @@ interface BrowseAiOpts {
|
|
|
50
50
|
timeout: string;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
export function registerBrowseAiCommand(
|
|
53
|
+
export function registerBrowseAiCommand(
|
|
54
|
+
program: Command,
|
|
55
|
+
emitParam: EmitContext,
|
|
56
|
+
context?: HarneryProgramContext,
|
|
57
|
+
): void {
|
|
54
58
|
emit = emitParam;
|
|
55
59
|
program
|
|
56
60
|
.command("browse-ai <url>")
|
|
@@ -86,7 +90,7 @@ export function registerBrowseAiCommand(program: Command, emitParam: EmitContext
|
|
|
86
90
|
.option("--timeout <ms>", "Per-step timeout in ms", "60000")
|
|
87
91
|
.action((url: string, opts: BrowseAiOpts) => {
|
|
88
92
|
try {
|
|
89
|
-
runBrowseAi(url, opts);
|
|
93
|
+
runBrowseAi(url, opts, context);
|
|
90
94
|
} catch (err: unknown) {
|
|
91
95
|
const msg = err instanceof Error ? err.message : String(err);
|
|
92
96
|
emit.error({ code: "browse_ai_error", message: msg });
|
|
@@ -95,11 +99,12 @@ export function registerBrowseAiCommand(program: Command, emitParam: EmitContext
|
|
|
95
99
|
});
|
|
96
100
|
}
|
|
97
101
|
|
|
98
|
-
function runBrowseAi(url: string, opts: BrowseAiOpts): void {
|
|
102
|
+
function runBrowseAi(url: string, opts: BrowseAiOpts, context?: HarneryProgramContext): void {
|
|
99
103
|
const jar =
|
|
100
104
|
opts.cookies === false
|
|
101
105
|
? null
|
|
102
106
|
: new CookieJar({ path: opts.store ?? DEFAULT_STORE, source: "harn-browse-ai" });
|
|
107
|
+
if (jar) applyExtraCookies(url, jar, context?.extraCookies);
|
|
103
108
|
const ab = new AgentBrowser({
|
|
104
109
|
jar,
|
|
105
110
|
timeoutMs: Number.parseInt(opts.timeout, 10),
|