blun-king-cli 9.1.561 → 9.1.563
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/LIESMICH.txt +2 -2
- package/README.md +1 -1
- package/agent-spine-plugin/.claude-plugin/marketplace.json +1 -1
- package/agent-spine-plugin/.claude-plugin/plugin.json +1 -1
- package/agent-spine-plugin/.codex-plugin/plugin.json +1 -1
- package/agent-spine-plugin/blun.plugin.json +3 -3
- package/agent-spine-plugin/hooks/codex.json +2 -2
- package/agent-spine-plugin/hooks/hooks.json +1 -1
- package/agent-spine-plugin/hooks/version.json +1 -1
- package/agent-spine-plugin/package.json +1 -1
- package/agent-spine-plugin/scripts/check-hosts.js +199 -0
- package/agent-spine-plugin/skills/agent-spine/SKILL.md +1 -1
- package/agent-spine-plugin/src/cli.js +390 -7
- package/agent-spine-plugin/src/hook.js +80 -10
- package/agent-spine-plugin/src/index.js +4 -2
- package/agent-spine-plugin/src/lib/audit.js +19 -1
- package/agent-spine-plugin/src/lib/filesystem-retry.js +5 -0
- package/agent-spine-plugin/src/lib/learning.js +5575 -128
- package/agent-spine-plugin/src/lib/owned-file-lock.js +143 -0
- package/agent-spine-plugin/src/version.js +1 -1
- package/package.json +2 -1
|
@@ -8,9 +8,12 @@ import {
|
|
|
8
8
|
recordActivity, resolveAttention, upsertAttention
|
|
9
9
|
} from "./lib/attention.js";
|
|
10
10
|
import {
|
|
11
|
-
addLearningEvidence, configureLearning, deleteLearning, evaluateLearning,
|
|
11
|
+
addLearningEvidence, beginLearningRevalidation, configureLearning, deleteLearning, evaluateLearning,
|
|
12
12
|
learningContext, learningOutcomeStatus, loadLearning, proposeLearning,
|
|
13
|
-
|
|
13
|
+
purgeStaleLearningApplications, purgeStaleLearningMeasurements, recordLearningMeasurement,
|
|
14
|
+
recordLearningOutcome, registerLearningEvaluation, registerLearningEvaluator, renewLearningValidation, revokeLearningEvaluator,
|
|
15
|
+
reviewLearning, revokeLearningApplication, revokeLearningDelivery, revokeLearningEvaluation, revokeLearningEvidence, revokeLearningMeasurement, revokeLearningOutcome, revokeLearningTrialFailure, revokeLearningValidation,
|
|
16
|
+
rollbackLearning
|
|
14
17
|
} from "./lib/learning.js";
|
|
15
18
|
import { configureContinuity, loadContinuity, purgeContinuity } from "./lib/continuity.js";
|
|
16
19
|
import {
|
|
@@ -109,6 +112,14 @@ function hasLearningScope(flags) {
|
|
|
109
112
|
return ["persona", "user", "tenant", "project", "group", "task"].some((name) => flags[name] !== undefined);
|
|
110
113
|
}
|
|
111
114
|
|
|
115
|
+
function evaluatorRootsFlag(value) {
|
|
116
|
+
return String(value || "").split(",").filter(Boolean).map((entry) => {
|
|
117
|
+
const separator = entry.lastIndexOf("=");
|
|
118
|
+
if (separator <= 0) throw new Error("evaluator roots must use evaluator-id=sha256 entries");
|
|
119
|
+
return { evaluatorId: entry.slice(0, separator), principalDigest: entry.slice(separator + 1) };
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
112
123
|
function help() {
|
|
113
124
|
return `AgentSpine ${VERSION}
|
|
114
125
|
|
|
@@ -134,11 +145,27 @@ Usage:
|
|
|
134
145
|
agentspine attention-config [root] [--enabled true|false] [--quiet-start 22 --quiet-end 7 --utc-offset 120]
|
|
135
146
|
agentspine learn-propose [id] --kind preference|behavior --claim text --evidence text [--persona id --user id --tenant id --project id --group id --task id]
|
|
136
147
|
agentspine learn-evidence <id> --summary text [--type interaction] [--source path.md]
|
|
148
|
+
agentspine learn-evidence-revoke <learning-id> --evidence-id id --reason-code retracted|source-invalid|measurement-invalid|duplicate|other --reason text --confirm-local-evidence
|
|
137
149
|
agentspine learn-review <id> --decision accept|reject --reason text [--confirmed-by-user]
|
|
138
150
|
agentspine learn-context [root] [--group id] [--include-private] [--kind preference,goal]
|
|
139
151
|
agentspine learn-evaluate [root]
|
|
140
|
-
agentspine learn-
|
|
152
|
+
agentspine learn-evaluator-register <id> --principal-digest sha256 --confirm-local-evaluator
|
|
153
|
+
agentspine learn-evaluator-revoke <id> --reason text --confirm-local-evaluator
|
|
154
|
+
agentspine learn-evaluation <id> --learning id --metric name --direction higher|lower --task-digest sha256 --dataset-digest sha256 --protocol-digest sha256 --min-cases n --evaluators id,id --evaluator-roots id=sha256,id=sha256 [--expires-at date] [--retry-trial-failure id --confirm-local-trial-retry] --confirm-local-evaluation
|
|
155
|
+
agentspine learn-evaluation-revoke <evaluation-id> --reason-code benchmark-invalid|protocol-invalid|scope-invalid|threshold-invalid|duplicate|other --reason text --confirm-local-evaluation-revocation
|
|
156
|
+
agentspine learn-validation-revoke <validation-lease-id> --reason-code decision-invalid|cohort-invalid|binding-invalid|scope-invalid|duplicate|other --reason text --confirm-local-validation-revocation
|
|
157
|
+
agentspine learn-trial-failure-revoke <trial-failure-id> --reason-code clock-invalid|host-invalid|receipt-invalid|scope-invalid|duplicate|other --reason text --confirm-local-trial-failure-revocation
|
|
158
|
+
agentspine learn-revalidation-start <learning-id> --confirm-local-validation
|
|
159
|
+
agentspine learn-revalidate <learning-id> --measurements id,id --applications id,id --deliveries id,id --confirm-local-validation
|
|
160
|
+
agentspine learn-measurement <id> --learning id --evaluation id --phase before|after --metric name --direction higher|lower --value 0..1 --measurement objective|user-feedback|model-suggestion --evaluator id --run id --source-digest sha256 --dataset-digest sha256 --case-count n --confirm-local-measurement
|
|
161
|
+
agentspine learn-measurement-revoke <measurement-id> --reason-code source-invalid|evaluator-invalid|protocol-invalid|duplicate|other --reason text --confirm-local-measurement-revocation
|
|
162
|
+
agentspine learn-application-revoke <application-id> --reason-code preflight-invalid|scope-invalid|projection-invalid|duplicate|other --reason text --confirm-local-application-revocation
|
|
163
|
+
agentspine learn-delivery-revoke <delivery-id> --reason-code host-invalid|session-invalid|hook-invalid|duplicate|other --reason text --confirm-local-delivery-revocation
|
|
164
|
+
agentspine learn-outcome-revoke <outcome-id> --reason-code binding-invalid|phase-invalid|scope-invalid|duplicate|other --reason text --confirm-local-outcome-revocation
|
|
165
|
+
agentspine learn-outcome <learning-id> --id id --evaluation id --measurement-receipt id [--application id --delivery id]
|
|
141
166
|
agentspine learn-status [root] [--persona id --user id --tenant id --project id --group id --task id]
|
|
167
|
+
agentspine learn-delivery-purge [root] --confirm-local-purge
|
|
168
|
+
agentspine learn-measurement-purge [root] --confirm-local-purge
|
|
142
169
|
agentspine learn-rollback <id> --reason text
|
|
143
170
|
agentspine learn-delete <id>
|
|
144
171
|
agentspine learn-config [root] [--auto-promote true|false] [--min-confidence 0.85] [--min-outcomes 2 --min-improvement 0.05 --canary-receipts 2 --canary-ttl-days 14]
|
|
@@ -429,6 +456,15 @@ export async function run(argv = process.argv.slice(2)) {
|
|
|
429
456
|
}), json);
|
|
430
457
|
}
|
|
431
458
|
|
|
459
|
+
if (command === "learn-evidence-revoke") {
|
|
460
|
+
return output(await revokeLearningEvidence({
|
|
461
|
+
root: flags.root || process.cwd(), learningId: positional[0], evidenceId: flags["evidence-id"],
|
|
462
|
+
reasonCode: flags["reason-code"], reason: flags.reason,
|
|
463
|
+
confirmation: booleanFlag(flags["confirm-local-evidence"])
|
|
464
|
+
? "local-evidence-revocation-confirmed" : null
|
|
465
|
+
}), json);
|
|
466
|
+
}
|
|
467
|
+
|
|
432
468
|
if (command === "learn-review") {
|
|
433
469
|
return output(await reviewLearning({
|
|
434
470
|
root: flags.root || process.cwd(), id: positional[0], decision: flags.decision,
|
|
@@ -451,11 +487,147 @@ export async function run(argv = process.argv.slice(2)) {
|
|
|
451
487
|
return output(await evaluateLearning({ root: positional[0] || process.cwd() }), json);
|
|
452
488
|
}
|
|
453
489
|
|
|
490
|
+
if (command === "learn-evaluator-register") {
|
|
491
|
+
return output(await registerLearningEvaluator({
|
|
492
|
+
root: flags.root || process.cwd(), id: positional[0], principalDigest: flags["principal-digest"],
|
|
493
|
+
confirmLocalEvaluator: booleanFlag(flags["confirm-local-evaluator"])
|
|
494
|
+
}), json);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
if (command === "learn-evaluator-revoke") {
|
|
498
|
+
return output(await revokeLearningEvaluator({
|
|
499
|
+
root: flags.root || process.cwd(), id: positional[0], reason: flags.reason,
|
|
500
|
+
confirmLocalEvaluator: booleanFlag(flags["confirm-local-evaluator"])
|
|
501
|
+
}), json);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
if (command === "learn-evaluation") {
|
|
505
|
+
return output(await registerLearningEvaluation({
|
|
506
|
+
root: flags.root || process.cwd(), id: positional[0], learningId: flags.learning,
|
|
507
|
+
scope: learningScope(flags), metric: { name: flags.metric, direction: flags.direction },
|
|
508
|
+
benchmark: {
|
|
509
|
+
taskDigest: flags["task-digest"], datasetDigest: flags["dataset-digest"],
|
|
510
|
+
protocolDigest: flags["protocol-digest"], minCases: Number(flags["min-cases"])
|
|
511
|
+
},
|
|
512
|
+
evaluatorIds: String(flags.evaluators || "").split(",").filter(Boolean),
|
|
513
|
+
evaluatorRoots: evaluatorRootsFlag(flags["evaluator-roots"]),
|
|
514
|
+
expiresAt: flags["expires-at"] || null,
|
|
515
|
+
retryTrialFailureId: flags["retry-trial-failure"] || null,
|
|
516
|
+
confirmLocalTrialRetry: booleanFlag(flags["confirm-local-trial-retry"]),
|
|
517
|
+
confirmLocalEvaluation: booleanFlag(flags["confirm-local-evaluation"])
|
|
518
|
+
}), json);
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
if (command === "learn-revalidation-start") {
|
|
522
|
+
return output(await beginLearningRevalidation({
|
|
523
|
+
root: flags.root || process.cwd(), learningId: positional[0],
|
|
524
|
+
confirmLocalValidation: booleanFlag(flags["confirm-local-validation"])
|
|
525
|
+
}), json);
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
if (command === "learn-revalidate") {
|
|
529
|
+
const measurements = String(flags.measurements || "").split(",").filter(Boolean);
|
|
530
|
+
const applications = String(flags.applications || "").split(",").filter(Boolean);
|
|
531
|
+
const deliveries = String(flags.deliveries || "").split(",").filter(Boolean);
|
|
532
|
+
if (!measurements.length || measurements.length !== applications.length || measurements.length !== deliveries.length) {
|
|
533
|
+
throw new Error("revalidation requires equally sized measurement, application, and delivery lists");
|
|
534
|
+
}
|
|
535
|
+
return output(await renewLearningValidation({
|
|
536
|
+
root: flags.root || process.cwd(), learningId: positional[0],
|
|
537
|
+
evidence: measurements.map((measurementId, index) => ({ measurementId,
|
|
538
|
+
applicationId: applications[index], deliveryId: deliveries[index] })),
|
|
539
|
+
confirmLocalValidation: booleanFlag(flags["confirm-local-validation"])
|
|
540
|
+
}), json);
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
if (command === "learn-measurement") {
|
|
544
|
+
return output(await recordLearningMeasurement({
|
|
545
|
+
root: flags.root || process.cwd(), id: positional[0], learningId: flags.learning,
|
|
546
|
+
evaluationId: flags.evaluation, phase: flags.phase, scope: learningScope(flags),
|
|
547
|
+
metric: {
|
|
548
|
+
name: flags.metric, direction: flags.direction, value: Number(flags.value),
|
|
549
|
+
blockingDefects: Number(flags["blocking-defects"] ?? 0)
|
|
550
|
+
},
|
|
551
|
+
measurement: {
|
|
552
|
+
kind: flags.measurement || "objective", evaluatorId: flags.evaluator,
|
|
553
|
+
runId: flags.run, sourceDigest: flags["source-digest"]
|
|
554
|
+
},
|
|
555
|
+
coverage: { datasetDigest: flags["dataset-digest"], caseCount: Number(flags["case-count"]) },
|
|
556
|
+
measuredAt: flags.at,
|
|
557
|
+
confirmLocalMeasurement: booleanFlag(flags["confirm-local-measurement"])
|
|
558
|
+
}), json);
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
if (command === "learn-measurement-revoke") {
|
|
562
|
+
return output(await revokeLearningMeasurement({
|
|
563
|
+
root: flags.root || process.cwd(), measurementId: positional[0], reasonCode: flags["reason-code"],
|
|
564
|
+
reason: flags.reason,
|
|
565
|
+
confirmation: booleanFlag(flags["confirm-local-measurement-revocation"])
|
|
566
|
+
? "local-measurement-revocation-confirmed" : null
|
|
567
|
+
}), json);
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
if (command === "learn-evaluation-revoke") {
|
|
571
|
+
return output(await revokeLearningEvaluation({
|
|
572
|
+
root: flags.root || process.cwd(), evaluationId: positional[0], reasonCode: flags["reason-code"],
|
|
573
|
+
reason: flags.reason,
|
|
574
|
+
confirmation: booleanFlag(flags["confirm-local-evaluation-revocation"])
|
|
575
|
+
? "local-evaluation-revocation-confirmed" : null
|
|
576
|
+
}), json);
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
if (command === "learn-validation-revoke") {
|
|
580
|
+
return output(await revokeLearningValidation({
|
|
581
|
+
root: flags.root || process.cwd(), validationLeaseId: positional[0], reasonCode: flags["reason-code"],
|
|
582
|
+
reason: flags.reason,
|
|
583
|
+
confirmation: booleanFlag(flags["confirm-local-validation-revocation"])
|
|
584
|
+
? "local-validation-revocation-confirmed" : null
|
|
585
|
+
}), json);
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
if (command === "learn-trial-failure-revoke") {
|
|
589
|
+
return output(await revokeLearningTrialFailure({
|
|
590
|
+
root: flags.root || process.cwd(), trialFailureId: positional[0], reasonCode: flags["reason-code"],
|
|
591
|
+
reason: flags.reason,
|
|
592
|
+
confirmation: booleanFlag(flags["confirm-local-trial-failure-revocation"])
|
|
593
|
+
? "local-trial-failure-revocation-confirmed" : null
|
|
594
|
+
}), json);
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
if (command === "learn-application-revoke") {
|
|
598
|
+
return output(await revokeLearningApplication({
|
|
599
|
+
root: flags.root || process.cwd(), applicationId: positional[0], reasonCode: flags["reason-code"],
|
|
600
|
+
reason: flags.reason,
|
|
601
|
+
confirmation: booleanFlag(flags["confirm-local-application-revocation"])
|
|
602
|
+
? "local-application-revocation-confirmed" : null
|
|
603
|
+
}), json);
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
if (command === "learn-delivery-revoke") {
|
|
607
|
+
return output(await revokeLearningDelivery({
|
|
608
|
+
root: flags.root || process.cwd(), deliveryId: positional[0], reasonCode: flags["reason-code"],
|
|
609
|
+
reason: flags.reason,
|
|
610
|
+
confirmation: booleanFlag(flags["confirm-local-delivery-revocation"])
|
|
611
|
+
? "local-delivery-revocation-confirmed" : null
|
|
612
|
+
}), json);
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
if (command === "learn-outcome-revoke") {
|
|
616
|
+
return output(await revokeLearningOutcome({
|
|
617
|
+
root: flags.root || process.cwd(), outcomeId: positional[0], reasonCode: flags["reason-code"],
|
|
618
|
+
reason: flags.reason,
|
|
619
|
+
confirmation: booleanFlag(flags["confirm-local-outcome-revocation"])
|
|
620
|
+
? "local-outcome-revocation-confirmed" : null
|
|
621
|
+
}), json);
|
|
622
|
+
}
|
|
623
|
+
|
|
454
624
|
if (command === "learn-outcome") {
|
|
625
|
+
const lineage = flags["measurement-receipt"] || null;
|
|
455
626
|
return output(await recordLearningOutcome({
|
|
456
627
|
root: flags.root || process.cwd(), learningId: positional[0], id: flags.id,
|
|
457
|
-
|
|
458
|
-
|
|
628
|
+
evaluationId: flags.evaluation, measurementReceiptId: lineage,
|
|
629
|
+
applicationId: flags.application || null, deliveryId: flags.delivery || null,
|
|
630
|
+
...(lineage ? {} : { phase: flags.phase, scope: learningScope(flags), metric: {
|
|
459
631
|
name: flags.metric, direction: flags.direction, value: Number(flags.value),
|
|
460
632
|
blockingDefects: Number(flags["blocking-defects"] ?? 0)
|
|
461
633
|
},
|
|
@@ -463,7 +635,11 @@ export async function run(argv = process.argv.slice(2)) {
|
|
|
463
635
|
kind: flags.measurement || "objective", evaluatorId: flags.evaluator,
|
|
464
636
|
sourceDigest: flags["source-digest"] || null
|
|
465
637
|
},
|
|
466
|
-
|
|
638
|
+
coverage: {
|
|
639
|
+
datasetDigest: flags["dataset-digest"],
|
|
640
|
+
caseCount: Number(flags["case-count"])
|
|
641
|
+
},
|
|
642
|
+
measuredAt: flags.at })
|
|
467
643
|
}), json);
|
|
468
644
|
}
|
|
469
645
|
|
|
@@ -473,6 +649,20 @@ export async function run(argv = process.argv.slice(2)) {
|
|
|
473
649
|
}), json);
|
|
474
650
|
}
|
|
475
651
|
|
|
652
|
+
if (command === "learn-delivery-purge") {
|
|
653
|
+
return output(await purgeStaleLearningApplications({
|
|
654
|
+
root: positional[0] || process.cwd(),
|
|
655
|
+
confirmation: booleanFlag(flags["confirm-local-purge"]) ? "local-user-purge-confirmed" : null
|
|
656
|
+
}), json);
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
if (command === "learn-measurement-purge") {
|
|
660
|
+
return output(await purgeStaleLearningMeasurements({
|
|
661
|
+
root: positional[0] || process.cwd(),
|
|
662
|
+
confirmation: booleanFlag(flags["confirm-local-purge"]) ? "local-user-purge-confirmed" : null
|
|
663
|
+
}), json);
|
|
664
|
+
}
|
|
665
|
+
|
|
476
666
|
if (command === "learn-rollback") {
|
|
477
667
|
return output(await rollbackLearning({
|
|
478
668
|
root: flags.root || process.cwd(), id: positional[0], reason: flags.reason
|
|
@@ -496,6 +686,9 @@ export async function run(argv = process.argv.slice(2)) {
|
|
|
496
686
|
if (flags["outcome-max-age-days"] !== undefined) config.outcomeMaxAgeDays = Number(flags["outcome-max-age-days"]);
|
|
497
687
|
if (flags["canary-receipts"] !== undefined) config.canaryReceipts = Number(flags["canary-receipts"]);
|
|
498
688
|
if (flags["canary-ttl-days"] !== undefined) config.canaryTtlDays = Number(flags["canary-ttl-days"]);
|
|
689
|
+
if (flags["initial-trial-outcome-timeout-minutes"] !== undefined) {
|
|
690
|
+
config.initialTrialOutcomeTimeoutMinutes = Number(flags["initial-trial-outcome-timeout-minutes"]);
|
|
691
|
+
}
|
|
499
692
|
if (!Object.keys(config).length) return output((await loadLearning(root)).learning.config, json);
|
|
500
693
|
return output(await configureLearning({ root, config }), json);
|
|
501
694
|
}
|
|
@@ -1005,12 +1198,202 @@ export async function run(argv = process.argv.slice(2)) {
|
|
|
1005
1198
|
let learningOutcomes;
|
|
1006
1199
|
try {
|
|
1007
1200
|
const status = await learningOutcomeStatus({ root: positional[0] || process.cwd() });
|
|
1201
|
+
const unboundAfterReceipts = status.records.reduce((sum, item) => sum + item.afterReceipts - item.boundAfterReceipts, 0);
|
|
1202
|
+
const undeliveredAfterReceipts = status.records.reduce((sum, item) => sum + item.afterReceipts - item.deliveredAfterReceipts, 0);
|
|
1203
|
+
const stalePendingApplications = status.records.reduce((sum, item) => sum + item.stalePendingApplications, 0);
|
|
1204
|
+
const totalOutcomeReceipts = status.records.reduce((sum, item) => sum + item.beforeReceipts + item.afterReceipts, 0);
|
|
1205
|
+
const plannedOutcomeReceipts = status.records.reduce((sum, item) => sum + item.plannedOutcomeReceipts, 0);
|
|
1206
|
+
const coverageBoundReceipts = status.records.reduce((sum, item) => sum + item.coverageBoundReceipts, 0);
|
|
1207
|
+
const legacyCoverageReceipts = status.records.reduce((sum, item) => sum + item.legacyCoverageReceipts, 0);
|
|
1208
|
+
const provenanceBoundReceipts = status.records.reduce((sum, item) => sum + item.provenanceBoundReceipts, 0);
|
|
1209
|
+
const legacyProvenanceReceipts = status.records.reduce((sum, item) => sum + item.legacyProvenanceReceipts, 0);
|
|
1210
|
+
const measurementReceipts = status.records.reduce((sum, item) => sum + item.measurementReceipts, 0);
|
|
1211
|
+
const measurementLineageReceipts = status.records.reduce((sum, item) => sum + item.measurementLineageReceipts, 0);
|
|
1212
|
+
const consumedMeasurementReceipts = status.records.reduce((sum, item) => sum + item.consumedMeasurementReceipts, 0);
|
|
1213
|
+
const staleUnconsumedMeasurements = status.records.reduce((sum, item) => sum + item.staleUnconsumedMeasurements, 0);
|
|
1214
|
+
const lineageBoundReceipts = status.records.reduce((sum, item) => sum + item.lineageBoundReceipts, 0);
|
|
1215
|
+
const pairedOutcomeReceipts = status.records.reduce((sum, item) => sum + item.pairedOutcomeReceipts, 0);
|
|
1216
|
+
const pairedEvaluatorPairs = status.records.reduce((sum, item) => sum + item.pairedEvaluatorPairs, 0);
|
|
1217
|
+
const evaluatorRootBoundReceipts = status.records.reduce((sum, item) => sum + item.evaluatorRootBoundReceipts, 0);
|
|
1218
|
+
const independentEvaluatorRoots = status.records.reduce((sum, item) => sum + item.independentEvaluatorRoots, 0);
|
|
1219
|
+
const evaluatorRegistryContracts = status.records.reduce((sum, item) => sum + item.evaluatorRegistryContracts, 0);
|
|
1220
|
+
const inactiveEvaluatorRegistryContracts = status.records.reduce((sum, item) => sum + item.inactiveEvaluatorRegistryContracts, 0);
|
|
1221
|
+
const currentValidatedLessons = status.records.filter((item) => item.validationLeaseStatus === "current-validated").length;
|
|
1222
|
+
const staleValidatedLessons = status.records.filter((item) => item.validationLeaseStatus === "stale-validated").length;
|
|
1223
|
+
const unprovenValidatedLessons = status.records.filter((item) => item.validationLeaseStatus === "unproven-validated").length;
|
|
1224
|
+
const revokedValidatedLessons = status.records.filter((item) => item.validationLeaseStatus === "revoked-validated").length;
|
|
1225
|
+
const renewedValidationLeases = status.records.filter((item) =>
|
|
1226
|
+
["agentspine.learning-validation/v2", "agentspine.learning-validation/v3",
|
|
1227
|
+
"agentspine.learning-validation/v4", "agentspine.learning-validation/v5"].includes(item.validationLeaseSchema)).length;
|
|
1228
|
+
const fixedCohortValidationLeases = status.records.filter((item) =>
|
|
1229
|
+
["agentspine.learning-validation/v3", "agentspine.learning-validation/v4",
|
|
1230
|
+
"agentspine.learning-validation/v5"]
|
|
1231
|
+
.includes(item.validationLeaseSchema)).length;
|
|
1232
|
+
const admissionBoundValidationLeases = status.records.filter((item) =>
|
|
1233
|
+
["agentspine.learning-validation/v4", "agentspine.learning-validation/v5"]
|
|
1234
|
+
.includes(item.validationLeaseSchema)).length;
|
|
1235
|
+
const trialBoundValidationLeases = status.records.filter((item) =>
|
|
1236
|
+
item.validationLeaseSchema === "agentspine.learning-validation/v5").length;
|
|
1237
|
+
const activeRevalidations = status.records.filter((item) => item.revalidationStatus === "active").length;
|
|
1238
|
+
const staleRevalidations = status.records.filter((item) => item.revalidationStatus === "stale").length;
|
|
1239
|
+
const fixedCohortRevalidations = status.records.filter((item) =>
|
|
1240
|
+
item.revalidationStatus === "active"
|
|
1241
|
+
&& ["first-completed-turns", "first-admitted-turns",
|
|
1242
|
+
"first-admitted-trials"].includes(item.revalidationSelectionMode)).length;
|
|
1243
|
+
const admissionBoundRevalidations = status.records.filter((item) =>
|
|
1244
|
+
item.revalidationStatus === "active" && ["first-admitted-turns", "first-admitted-trials"]
|
|
1245
|
+
.includes(item.revalidationSelectionMode)).length;
|
|
1246
|
+
const trialBoundRevalidations = status.records.filter((item) =>
|
|
1247
|
+
item.revalidationStatus === "active" && item.revalidationSelectionMode === "first-admitted-trials").length;
|
|
1248
|
+
const requiredRevalidationDeliveries = status.records.reduce((sum, item) =>
|
|
1249
|
+
sum + item.revalidationRequiredDeliveries, 0);
|
|
1250
|
+
const completedRevalidationDeliveries = status.records.reduce((sum, item) =>
|
|
1251
|
+
sum + item.revalidationCompletedDeliveries, 0);
|
|
1252
|
+
const admittedRevalidationApplications = status.records.reduce((sum, item) =>
|
|
1253
|
+
sum + item.revalidationAdmittedApplications, 0);
|
|
1254
|
+
const initialTrialContracts = status.records.filter((item) => item.initialTrialMode === "first-admitted-trials").length;
|
|
1255
|
+
const requiredInitialTrials = status.records.reduce((sum, item) => sum + item.initialTrialSlots, 0);
|
|
1256
|
+
const admittedInitialApplications = status.records.reduce((sum, item) =>
|
|
1257
|
+
sum + item.initialAdmittedApplications, 0);
|
|
1258
|
+
const completedInitialDeliveries = status.records.reduce((sum, item) =>
|
|
1259
|
+
sum + item.initialCompletedDeliveries, 0);
|
|
1260
|
+
const incompleteInitialAdmissions = status.records.reduce((sum, item) =>
|
|
1261
|
+
sum + item.incompleteInitialAdmissions, 0);
|
|
1262
|
+
const targetBoundEvaluationContracts = status.records.reduce((sum, item) =>
|
|
1263
|
+
sum + item.targetBoundEvaluationContracts, 0);
|
|
1264
|
+
const targetBoundApplications = status.records.reduce((sum, item) =>
|
|
1265
|
+
sum + item.targetBoundApplications, 0);
|
|
1266
|
+
const deadlineBoundEvaluationContracts = status.records.reduce((sum, item) =>
|
|
1267
|
+
sum + item.deadlineBoundEvaluationContracts, 0);
|
|
1268
|
+
const stalenessBoundEvaluationContracts = status.records.reduce((sum, item) =>
|
|
1269
|
+
sum + item.stalenessBoundEvaluationContracts, 0);
|
|
1270
|
+
const promotionBoundEvaluationContracts = status.records.reduce((sum, item) =>
|
|
1271
|
+
sum + item.promotionBoundEvaluationContracts, 0);
|
|
1272
|
+
const candidateAdmissionEvaluationContracts = status.records.reduce((sum, item) =>
|
|
1273
|
+
sum + item.candidateAdmissionEvaluationContracts, 0);
|
|
1274
|
+
const candidateEvidenceCohortEvaluationContracts = status.records.reduce((sum, item) =>
|
|
1275
|
+
sum + item.candidateEvidenceCohortEvaluationContracts, 0);
|
|
1276
|
+
const blockingDefectBoundEvaluationContracts = status.records.reduce((sum, item) =>
|
|
1277
|
+
sum + item.blockingDefectBoundEvaluationContracts, 0);
|
|
1278
|
+
const evidenceSourceBoundEvaluationContracts = status.records.reduce((sum, item) =>
|
|
1279
|
+
sum + item.evidenceSourceBoundEvaluationContracts, 0);
|
|
1280
|
+
const blockingDefectOutcomeReceipts = status.records.reduce((sum, item) =>
|
|
1281
|
+
sum + item.blockingDefectOutcomeReceipts, 0);
|
|
1282
|
+
const deadlineBoundApplications = status.records.reduce((sum, item) =>
|
|
1283
|
+
sum + item.deadlineBoundApplications, 0);
|
|
1284
|
+
const trialRetryEvaluationContracts = status.records.reduce((sum, item) =>
|
|
1285
|
+
sum + item.trialRetryEvaluationContracts, 0);
|
|
1286
|
+
const comparableTrialRetryEvaluationContracts = status.records.reduce((sum, item) =>
|
|
1287
|
+
sum + item.comparableTrialRetryEvaluationContracts, 0);
|
|
1288
|
+
const boundedTrialRetryEvaluationContracts = status.records.reduce((sum, item) =>
|
|
1289
|
+
sum + item.boundedTrialRetryEvaluationContracts, 0);
|
|
1290
|
+
const trialRetryExhaustionReceipts = status.records.reduce((sum, item) =>
|
|
1291
|
+
sum + item.trialRetryExhaustionReceipts, 0);
|
|
1292
|
+
const trialFailureReceipts = status.records.reduce((sum, item) => sum + item.trialFailureReceipts, 0);
|
|
1293
|
+
const trialFailureRevocationReceipts = status.records.reduce((sum, item) =>
|
|
1294
|
+
sum + item.trialFailureRevocationReceipts, 0);
|
|
1295
|
+
const evaluationRevocationReceipts = status.records.reduce((sum, item) => sum + item.evaluationRevocationReceipts, 0);
|
|
1296
|
+
const validationRevocationReceipts = status.records.reduce((sum, item) => sum + item.validationRevocationReceipts, 0);
|
|
1297
|
+
const evidenceRevocationReceipts = status.records.reduce((sum, item) => sum + item.evidenceRevocationReceipts, 0);
|
|
1298
|
+
const measurementRevocationReceipts = status.records.reduce((sum, item) => sum + item.measurementRevocationReceipts, 0);
|
|
1299
|
+
const applicationRevocationReceipts = status.records.reduce((sum, item) => sum + item.applicationRevocationReceipts, 0);
|
|
1300
|
+
const deliveryRevocationReceipts = status.records.reduce((sum, item) => sum + item.deliveryRevocationReceipts, 0);
|
|
1301
|
+
const outcomeRevocationReceipts = status.records.reduce((sum, item) => sum + item.outcomeRevocationReceipts, 0);
|
|
1302
|
+
const deliveryTimeoutFailures = status.records.reduce((sum, item) => sum + item.deliveryTimeoutFailures, 0);
|
|
1303
|
+
const outcomeTimeoutFailures = status.records.reduce((sum, item) => sum + item.outcomeTimeoutFailures, 0);
|
|
1304
|
+
const pendingInitialOutcomes = status.records.reduce((sum, item) => sum + item.pendingInitialOutcomes, 0);
|
|
1305
|
+
const staleInitialOutcomes = status.records.reduce((sum, item) => sum + item.staleInitialOutcomes, 0);
|
|
1306
|
+
const unplannedOutcomeReceipts = totalOutcomeReceipts - plannedOutcomeReceipts;
|
|
1008
1307
|
learningOutcomes = {
|
|
1009
|
-
status: status.records.some((item) =>
|
|
1308
|
+
status: status.records.some((item) => ["stale", "revoked", "revoked-evaluation", "revoked-validation", "revoked-evidence", "revoked-measurement", "revoked-application", "revoked-delivery", "revoked-outcome", "unproven", "failed-trial"].includes(item.canaryStatus))
|
|
1309
|
+
|| unboundAfterReceipts > 0 || undeliveredAfterReceipts > 0 || unplannedOutcomeReceipts > 0
|
|
1310
|
+
|| stalePendingApplications > 0 || staleUnconsumedMeasurements > 0
|
|
1311
|
+
|| inactiveEvaluatorRegistryContracts > 0 || staleRevalidations > 0
|
|
1312
|
+
|| staleInitialOutcomes > 0 || trialFailureRevocationReceipts > 0 ? "degraded" : "healthy",
|
|
1010
1313
|
candidates: status.records.length,
|
|
1011
1314
|
activeCanaries: status.records.filter((item) => item.canaryStatus === "active").length,
|
|
1012
1315
|
validatedCanaries: status.records.filter((item) => item.canaryStatus === "validated").length,
|
|
1013
1316
|
staleCanaries: status.records.filter((item) => item.canaryStatus === "stale").length,
|
|
1317
|
+
awaitingApplication: status.records.filter((item) => item.canaryStatus === "active" && item.applicationReceipts === 0).length,
|
|
1318
|
+
applicationReceipts: status.records.reduce((sum, item) => sum + item.applicationReceipts, 0),
|
|
1319
|
+
deliveryReceipts: status.records.reduce((sum, item) => sum + item.deliveryReceipts, 0),
|
|
1320
|
+
pendingApplications: status.records.reduce((sum, item) => sum + item.pendingApplications, 0),
|
|
1321
|
+
stalePendingApplications,
|
|
1322
|
+
evaluationContracts: status.records.reduce((sum, item) => sum + item.evaluationContracts, 0),
|
|
1323
|
+
targetBoundEvaluationContracts,
|
|
1324
|
+
targetBoundApplications,
|
|
1325
|
+
deadlineBoundEvaluationContracts,
|
|
1326
|
+
stalenessBoundEvaluationContracts,
|
|
1327
|
+
promotionBoundEvaluationContracts,
|
|
1328
|
+
candidateAdmissionEvaluationContracts,
|
|
1329
|
+
candidateEvidenceCohortEvaluationContracts,
|
|
1330
|
+
blockingDefectBoundEvaluationContracts,
|
|
1331
|
+
evidenceSourceBoundEvaluationContracts,
|
|
1332
|
+
blockingDefectOutcomeReceipts,
|
|
1333
|
+
deadlineBoundApplications,
|
|
1334
|
+
trialRetryEvaluationContracts,
|
|
1335
|
+
comparableTrialRetryEvaluationContracts,
|
|
1336
|
+
boundedTrialRetryEvaluationContracts,
|
|
1337
|
+
trialRetryExhaustionReceipts,
|
|
1338
|
+
trialFailureReceipts,
|
|
1339
|
+
trialFailureRevocationReceipts,
|
|
1340
|
+
evaluationRevocationReceipts,
|
|
1341
|
+
validationRevocationReceipts,
|
|
1342
|
+
evidenceRevocationReceipts,
|
|
1343
|
+
measurementRevocationReceipts,
|
|
1344
|
+
applicationRevocationReceipts,
|
|
1345
|
+
deliveryRevocationReceipts,
|
|
1346
|
+
outcomeRevocationReceipts,
|
|
1347
|
+
deliveryTimeoutFailures,
|
|
1348
|
+
outcomeTimeoutFailures,
|
|
1349
|
+
pendingInitialOutcomes,
|
|
1350
|
+
staleInitialOutcomes,
|
|
1351
|
+
plannedOutcomeReceipts,
|
|
1352
|
+
coverageBoundReceipts,
|
|
1353
|
+
legacyCoverageReceipts,
|
|
1354
|
+
provenanceBoundReceipts,
|
|
1355
|
+
legacyProvenanceReceipts,
|
|
1356
|
+
measurementReceipts,
|
|
1357
|
+
measurementLineageReceipts,
|
|
1358
|
+
consumedMeasurementReceipts,
|
|
1359
|
+
staleUnconsumedMeasurements,
|
|
1360
|
+
lineageBoundReceipts,
|
|
1361
|
+
pairedOutcomeReceipts,
|
|
1362
|
+
pairedEvaluatorPairs,
|
|
1363
|
+
evaluatorRootBoundReceipts,
|
|
1364
|
+
independentEvaluatorRoots,
|
|
1365
|
+
activeEvaluatorRoots: status.evaluatorRegistry.active,
|
|
1366
|
+
revokedEvaluatorRoots: status.evaluatorRegistry.revoked,
|
|
1367
|
+
evaluatorRegistryBindings: status.evaluatorRegistry.bindings,
|
|
1368
|
+
validationLeases: status.evaluatorRegistry.validationLeases,
|
|
1369
|
+
renewedValidationLeases,
|
|
1370
|
+
fixedCohortValidationLeases,
|
|
1371
|
+
admissionBoundValidationLeases,
|
|
1372
|
+
trialBoundValidationLeases,
|
|
1373
|
+
initialTrialContracts,
|
|
1374
|
+
requiredInitialTrials,
|
|
1375
|
+
admittedInitialApplications,
|
|
1376
|
+
completedInitialDeliveries,
|
|
1377
|
+
incompleteInitialAdmissions,
|
|
1378
|
+
activeRevalidations,
|
|
1379
|
+
staleRevalidations,
|
|
1380
|
+
fixedCohortRevalidations,
|
|
1381
|
+
admissionBoundRevalidations,
|
|
1382
|
+
trialBoundRevalidations,
|
|
1383
|
+
requiredRevalidationDeliveries,
|
|
1384
|
+
admittedRevalidationApplications,
|
|
1385
|
+
completedRevalidationDeliveries,
|
|
1386
|
+
currentValidatedLessons,
|
|
1387
|
+
staleValidatedLessons,
|
|
1388
|
+
unprovenValidatedLessons,
|
|
1389
|
+
revokedValidatedLessons,
|
|
1390
|
+
evaluatorRegistryContracts,
|
|
1391
|
+
inactiveEvaluatorRegistryContracts,
|
|
1392
|
+
unplannedOutcomeReceipts,
|
|
1393
|
+
boundAfterReceipts: status.records.reduce((sum, item) => sum + item.boundAfterReceipts, 0),
|
|
1394
|
+
unboundAfterReceipts,
|
|
1395
|
+
deliveredAfterReceipts: status.records.reduce((sum, item) => sum + item.deliveredAfterReceipts, 0),
|
|
1396
|
+
undeliveredAfterReceipts,
|
|
1014
1397
|
contradictions: status.records.filter((item) => item.conflictsWith.length > 0).length,
|
|
1015
1398
|
authority: "context-only"
|
|
1016
1399
|
};
|
|
@@ -8,6 +8,7 @@ import { canonicalPath } from "./lib/paths.js";
|
|
|
8
8
|
import { resolveHostSourceCatalog } from "./lib/source-roots.js";
|
|
9
9
|
import { sessionBriefing } from "./lib/briefing.js";
|
|
10
10
|
import { captureContinuityPrompt, loadContinuity } from "./lib/continuity.js";
|
|
11
|
+
import { recordLearningApplications, recordLearningDeliveries } from "./lib/learning.js";
|
|
11
12
|
import {
|
|
12
13
|
authorizeJobEffect, checkpointJobEffect, closeJobLease, resolveSessionJob, startOrResumeJob
|
|
13
14
|
} from "./lib/selfstarter.js";
|
|
@@ -26,15 +27,25 @@ const KNOWN_EVENTS = new Set([
|
|
|
26
27
|
const ID_RE = /^[A-Za-z0-9][A-Za-z0-9:_.@/-]{0,127}$/;
|
|
27
28
|
const ATTENTION_WRITE_EVENTS = new Set(["UserPromptSubmit", "PostToolUse", "Stop", "SubagentStop"]);
|
|
28
29
|
const SELFSTART_EVENTS = new Set(["SessionStart", "PostCompact"]);
|
|
30
|
+
const SILENT_OVERSIZE_POST_TOOL_USE = Symbol("silent-oversize-post-tool-use");
|
|
31
|
+
const SILENT_OVERSIZE_POST_TOOL_USE_ARG = "--silent-oversize-post-tool-use";
|
|
29
32
|
|
|
30
|
-
async function readStdin() {
|
|
31
|
-
|
|
33
|
+
async function readStdin({ silentOversizePostToolUse = false } = {}) {
|
|
34
|
+
const chunks = [];
|
|
32
35
|
let bytes = 0;
|
|
36
|
+
let oversized = false;
|
|
33
37
|
for await (const chunk of process.stdin) {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
38
|
+
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
39
|
+
const remaining = Math.max(0, MAX_STDIN_BYTES - bytes);
|
|
40
|
+
if (remaining) chunks.push(buffer.subarray(0, remaining));
|
|
41
|
+
bytes += buffer.length;
|
|
42
|
+
if (bytes > MAX_STDIN_BYTES) oversized = true;
|
|
37
43
|
}
|
|
44
|
+
if (oversized) {
|
|
45
|
+
if (silentOversizePostToolUse) return SILENT_OVERSIZE_POST_TOOL_USE;
|
|
46
|
+
throw new Error("hook input exceeds the 64 KiB limit");
|
|
47
|
+
}
|
|
48
|
+
const value = Buffer.concat(chunks, bytes).toString("utf8");
|
|
38
49
|
const parsed = value.trim() ? JSON.parse(value) : {};
|
|
39
50
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("hook input must be one JSON object");
|
|
40
51
|
return parsed;
|
|
@@ -196,6 +207,7 @@ function renderContext(event, catalog, briefing, signal = null, attentionEvent =
|
|
|
196
207
|
createdAt: preflight.receipt.createdAt,
|
|
197
208
|
expiresAt: preflight.receipt.expiresAt,
|
|
198
209
|
policy: preflight.policy,
|
|
210
|
+
learningApplications: preflight.learningApplications || null,
|
|
199
211
|
pendingMustRemember: preflight.pendingMustRemember ? {
|
|
200
212
|
id: preflight.pendingMustRemember.candidate?.id || null,
|
|
201
213
|
status: preflight.pendingMustRemember.candidate?.status || (preflight.pendingMustRemember.rejected ? "rejected" : null),
|
|
@@ -501,8 +513,9 @@ function blockPrompt(reason) {
|
|
|
501
513
|
})}\n`);
|
|
502
514
|
}
|
|
503
515
|
|
|
504
|
-
export async function runHook(payload = null) {
|
|
505
|
-
const input = payload || await readStdin();
|
|
516
|
+
export async function runHook(payload = null, options = {}) {
|
|
517
|
+
const input = payload || await readStdin(options);
|
|
518
|
+
if (input === SILENT_OVERSIZE_POST_TOOL_USE) return;
|
|
506
519
|
if (!input || typeof input !== "object" || Array.isArray(input)) throw new Error("hook input must be one JSON object");
|
|
507
520
|
const event = input.hook_event_name || input.event_name || "";
|
|
508
521
|
if (!KNOWN_EVENTS.has(event)) throw new Error(`unsupported hook event: ${event || "missing"}`);
|
|
@@ -560,6 +573,7 @@ export async function runHook(payload = null) {
|
|
|
560
573
|
let scope = null;
|
|
561
574
|
let selfstarter = null;
|
|
562
575
|
let channelEvent = null;
|
|
576
|
+
let learningDelivery = null;
|
|
563
577
|
|
|
564
578
|
if (event === "PreToolUse" && isMutationTool(input.tool_name)) {
|
|
565
579
|
const { graph } = await loadGraph(root, catalog);
|
|
@@ -637,6 +651,19 @@ export async function runHook(payload = null) {
|
|
|
637
651
|
if (["Stop", "SubagentStop"].includes(event)) {
|
|
638
652
|
scope ||= await runtimeScope(input, root, resolvedSources.userStateRoot, catalog);
|
|
639
653
|
const exact = await selfstarterScope(input, scope, root, "resume");
|
|
654
|
+
if (exact && !scope.currentTaskId) scope.currentTaskId = exact.taskId;
|
|
655
|
+
try {
|
|
656
|
+
learningDelivery = await recordLearningDeliveries({
|
|
657
|
+
root, sessionId: sessionId(input), hookEvent: event,
|
|
658
|
+
scope: {
|
|
659
|
+
personaId: scope.entityId, userId: scope.userId, tenantId: scope.tenantId,
|
|
660
|
+
projectId: scope.projectId, groupId: scope.groupId, taskId: scope.currentTaskId
|
|
661
|
+
},
|
|
662
|
+
completedAt: input.timestamp || new Date()
|
|
663
|
+
});
|
|
664
|
+
} catch (error) {
|
|
665
|
+
learningDelivery = { status: "degraded", receipts: [], reason: error.message, authority: "context-only" };
|
|
666
|
+
}
|
|
640
667
|
const requested = selfstarterInput(input);
|
|
641
668
|
if (exact) {
|
|
642
669
|
selfstarter = await closeJobLease({
|
|
@@ -694,7 +721,7 @@ export async function runHook(payload = null) {
|
|
|
694
721
|
catalog, userStateRoot: resolvedSources.userStateRoot, sourceDiagnostics: resolvedSources.diagnostics,
|
|
695
722
|
prompt: event === "UserPromptSubmit" ? promptFromInput(input) : null
|
|
696
723
|
});
|
|
697
|
-
|
|
724
|
+
let context = renderContext(event, catalog, briefing, signal, attentionEvent, selfstarter, channelEvent, resolvedSources.diagnostics, preflight);
|
|
698
725
|
if (event === "UserPromptSubmit" && Buffer.byteLength(context) > hostContextLimit(preflight)) {
|
|
699
726
|
throw new Error("mandatory preflight context exceeds the host hook injection limit");
|
|
700
727
|
}
|
|
@@ -702,6 +729,45 @@ export async function runHook(payload = null) {
|
|
|
702
729
|
receipt: preflight.receipt, input, scope, resolvedSources, prompt: promptFromInput(input),
|
|
703
730
|
now: input.timestamp || new Date(), env: process.env, consume: true
|
|
704
731
|
})) throw new Error("preflight receipt could not be consumed atomically for this exact turn");
|
|
732
|
+
if (event === "UserPromptSubmit") {
|
|
733
|
+
const activeCanaries = briefing.learning.filter((item) => ["active", "revalidating"].includes(item.outcomeStatus));
|
|
734
|
+
if (!activeCanaries.length) {
|
|
735
|
+
preflight.learningApplications = {
|
|
736
|
+
status: "not-applicable", receipts: [], authority: "context-only"
|
|
737
|
+
};
|
|
738
|
+
} else try {
|
|
739
|
+
const application = await recordLearningApplications({
|
|
740
|
+
root, items: briefing.learning,
|
|
741
|
+
scope: {
|
|
742
|
+
personaId: scope.entityId, userId: scope.userId, tenantId: scope.tenantId,
|
|
743
|
+
projectId: scope.projectId, groupId: scope.groupId, taskId: scope.currentTaskId
|
|
744
|
+
},
|
|
745
|
+
preflightReceipt: preflight.receipt,
|
|
746
|
+
sessionBriefingDigest: createHash("sha256").update(JSON.stringify(briefing)).digest("hex"),
|
|
747
|
+
projectedAt: input.timestamp || new Date()
|
|
748
|
+
});
|
|
749
|
+
preflight.learningApplications = {
|
|
750
|
+
status: application.receipts.length ? "recorded" : "not-applicable",
|
|
751
|
+
receipts: application.receipts.map((item) => ({
|
|
752
|
+
id: item.id, learningId: item.learningId, projectedAt: item.projectedAt, expiresAt: item.expiresAt
|
|
753
|
+
})),
|
|
754
|
+
authority: "context-only"
|
|
755
|
+
};
|
|
756
|
+
} catch (error) {
|
|
757
|
+
briefing.learning = briefing.learning.filter((item) => !["active", "revalidating"].includes(item.outcomeStatus));
|
|
758
|
+
preflight.learningApplications = {
|
|
759
|
+
status: "degraded", receipts: [], reason: error.message, authority: "context-only"
|
|
760
|
+
};
|
|
761
|
+
}
|
|
762
|
+
const enriched = renderContext(event, catalog, briefing, signal, attentionEvent, selfstarter, channelEvent,
|
|
763
|
+
resolvedSources.diagnostics, preflight);
|
|
764
|
+
if (Buffer.byteLength(enriched) <= hostContextLimit(preflight)) context = enriched;
|
|
765
|
+
else if (preflight.learningApplications.status === "degraded") {
|
|
766
|
+
preflight.learningApplications = null;
|
|
767
|
+
context = renderContext(event, catalog, briefing, signal, attentionEvent, selfstarter, channelEvent,
|
|
768
|
+
resolvedSources.diagnostics, preflight);
|
|
769
|
+
}
|
|
770
|
+
}
|
|
705
771
|
if (payload) return { blocked: false, context, briefing, preflight, signal, attentionEvent, channelEvent, catalogPath };
|
|
706
772
|
process.stdout.write(`${JSON.stringify(hookOutput(event, context))}\n`);
|
|
707
773
|
return;
|
|
@@ -728,12 +794,16 @@ export async function runHook(payload = null) {
|
|
|
728
794
|
}
|
|
729
795
|
}
|
|
730
796
|
|
|
731
|
-
if (payload) return { blocked: false, attentionEvent, selfstarter };
|
|
797
|
+
if (payload) return { blocked: false, attentionEvent, selfstarter, learningDelivery };
|
|
732
798
|
process.stdout.write("{}\n");
|
|
733
799
|
}
|
|
734
800
|
|
|
735
801
|
if (isMainModule(import.meta.url)) {
|
|
736
|
-
|
|
802
|
+
const args = process.argv.slice(2);
|
|
803
|
+
const silentOversizePostToolUse = args.length === 1 && args[0] === SILENT_OVERSIZE_POST_TOOL_USE_ARG;
|
|
804
|
+
const argumentError = args.length && !silentOversizePostToolUse
|
|
805
|
+
? new Error(`unsupported hook argument: ${args[0]}`) : null;
|
|
806
|
+
(argumentError ? Promise.reject(argumentError) : runHook(null, { silentOversizePostToolUse })).catch((error) => {
|
|
737
807
|
process.stderr.write(`AgentSpine hook: ${String(error.message).slice(0, 2048)}\n`);
|
|
738
808
|
// Claude command hooks treat exit 2 as a blocking failure. Exit 1 is
|
|
739
809
|
// fail-open, which is unsafe for malformed pre-answer payloads.
|
|
@@ -12,9 +12,11 @@ export {
|
|
|
12
12
|
recordActivity, recordAttentionEvent, resolveAttention, upsertAttention
|
|
13
13
|
} from "./lib/attention.js";
|
|
14
14
|
export {
|
|
15
|
-
acceptContinuityLearning, addLearningEvidence, configureLearning, deleteLearning, evaluateLearning,
|
|
15
|
+
acceptContinuityLearning, addLearningEvidence, beginLearningRevalidation, configureLearning, deleteLearning, evaluateLearning,
|
|
16
16
|
learningContext, learningOutcomeStatus, loadLearning, proposeLearning, purgeLearningBySubject,
|
|
17
|
-
recordLearningOutcome,
|
|
17
|
+
purgeStaleLearningApplications, recordLearningOutcome, registerLearningEvaluation, renewLearningValidation,
|
|
18
|
+
reviewLearning, revokeLearningApplication, revokeLearningDelivery, revokeLearningEvaluation, revokeLearningEvidence, revokeLearningMeasurement, revokeLearningOutcome, revokeLearningTrialFailure, revokeLearningValidation,
|
|
19
|
+
rollbackLearning
|
|
18
20
|
} from "./lib/learning.js";
|
|
19
21
|
export {
|
|
20
22
|
captureContinuityPrompt, configureContinuity, continuityFindings,
|