@deftai/directive-core 0.105.0 → 0.106.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/authz/classify.js +591 -34
- package/dist/check/named-cause.js +1 -1
- package/dist/forward-coverage/diff-coverage.d.ts +39 -0
- package/dist/forward-coverage/diff-coverage.js +112 -0
- package/dist/forward-coverage/diff-lines.d.ts +19 -0
- package/dist/forward-coverage/diff-lines.js +173 -0
- package/dist/forward-coverage/evaluate.d.ts +24 -9
- package/dist/forward-coverage/evaluate.js +125 -19
- package/dist/init-deposit/agent-hooks.d.ts +1 -1
- package/dist/init-deposit/agent-hooks.js +1 -1
- package/dist/intake/clause-derivation.d.ts +9 -0
- package/dist/intake/clause-derivation.js +30 -3
- package/dist/lifecycle-visible/evaluate.d.ts +98 -0
- package/dist/lifecycle-visible/evaluate.js +710 -0
- package/dist/lifecycle-visible/index.d.ts +2 -0
- package/dist/lifecycle-visible/index.js +2 -0
- package/dist/literal-acceptance/capture.js +3 -3
- package/dist/orchestration/judgment-policy.d.ts +13 -0
- package/dist/orchestration/judgment-policy.js +15 -0
- package/dist/orchestration/probe-session.js +13 -8
- package/dist/orchestration/verify-judgment-gates.d.ts +4 -0
- package/dist/orchestration/verify-judgment-gates.js +43 -11
- package/dist/policy/ceremony-dial.js +7 -7
- package/dist/policy/host-hooks.d.ts +20 -0
- package/dist/policy/host-hooks.js +121 -2
- package/dist/policy/org-force-on-migration.js +2 -1
- package/dist/policy/plan-extensions.d.ts +1 -1
- package/dist/policy/plan-extensions.js +2 -0
- package/dist/policy/product-signal.js +6 -7
- package/dist/policy/require-human-merge.js +8 -6
- package/dist/policy/resolve.d.ts +7 -2
- package/dist/policy/resolve.js +25 -8
- package/dist/policy/value-feedback.js +7 -8
- package/dist/preflight-cache/evaluate.d.ts +12 -0
- package/dist/preflight-cache/evaluate.js +15 -1
- package/dist/preflight-cache/index.d.ts +1 -1
- package/dist/preflight-cache/index.js +1 -1
- package/dist/product-first-done-gate/evaluate.d.ts +4 -0
- package/dist/product-first-done-gate/evaluate.js +46 -5
- package/dist/release/closed-verb-gate.d.ts +12 -0
- package/dist/release/closed-verb-gate.js +51 -0
- package/dist/release/index.d.ts +1 -0
- package/dist/release/index.js +1 -0
- package/dist/release/pipeline.js +7 -0
- package/dist/release/types.d.ts +12 -0
- package/dist/render/constants.d.ts +2 -1
- package/dist/render/constants.js +2 -1
- package/dist/render/framework-commands.js +4 -0
- package/dist/render/spec-validate.js +23 -12
- package/dist/run-summary/types.d.ts +4 -0
- package/dist/scope/main.js +15 -5
- package/dist/scope/promote-from-issue.js +5 -5
- package/dist/scope-provenance/evaluate.js +3 -3
- package/dist/session/ac-pass-banking.d.ts +5 -0
- package/dist/session/ac-pass-banking.js +3 -2
- package/dist/session/process-cost.d.ts +32 -10
- package/dist/session/process-cost.js +189 -1
- package/dist/session/product-state-hash.js +41 -24
- package/dist/session/ritual-entrypoint.js +16 -1
- package/dist/session/session-start.d.ts +6 -0
- package/dist/session/session-start.js +32 -2
- package/dist/session/verify-session-ritual.d.ts +24 -1
- package/dist/session/verify-session-ritual.js +89 -6
- package/dist/swarm/finalize-cohort-cli.d.ts +7 -2
- package/dist/swarm/finalize-cohort-cli.js +165 -35
- package/dist/swarm/finalize-cohort.d.ts +1 -0
- package/dist/swarm/finalize-cohort.js +14 -2
- package/dist/swarm/routing-set-cli.js +2 -0
- package/dist/swarm/routing-verify.d.ts +1 -1
- package/dist/swarm/routing-verify.js +2 -2
- package/dist/triage/bootstrap/index.js +6 -6
- package/dist/triage/help/registry-data.d.ts +1 -1
- package/dist/triage/help/registry-data.js +1 -1
- package/dist/triage/welcome/writers.d.ts +1 -1
- package/dist/triage/welcome/writers.js +10 -5
- package/dist/value/readback.d.ts +4 -1
- package/dist/value/readback.js +51 -12
- package/dist/vbrief-validate/schema.d.ts +4 -0
- package/dist/vbrief-validate/schema.js +1 -1
- package/dist/verify-env/agent-hook-readiness.d.ts +2 -2
- package/dist/verify-env/agent-hook-readiness.js +12 -8
- package/dist/verify-env/agent-hooks-live-probe.d.ts +5 -1
- package/dist/verify-env/agent-hooks-live-probe.js +26 -5
- package/dist/verify-env/agent-hooks.js +3 -4
- package/package.json +7 -3
|
@@ -4,6 +4,7 @@ import { containedWrite } from "../../fs/contained-write.js";
|
|
|
4
4
|
import { assertWriteTargetSafe } from "../../fs/projection-containment.js";
|
|
5
5
|
import { hasArtifactSuffix, resolveLifecycleFolder, resolveProjectDefinitionPath, } from "../../layout/resolve.js";
|
|
6
6
|
import { migrateLegacyPolicyKey, PLAN_ONBOARDING_KEY, PLAN_POLICY_KEY, } from "../../policy/plan-extensions.js";
|
|
7
|
+
import { stampChangedToken } from "../../policy/resolve.js";
|
|
7
8
|
import { projectDefinitionMutationLock } from "../../vbrief-build/project-definition-io.js";
|
|
8
9
|
import { AUDIT_LOG_REL_PATH, DEFAULT_RELIEF_AGE_DAYS, DEFAULT_WIP_CAP, SUBSCRIPTION_PRESETS, WELCOME_AUDIT_TAG, } from "./constants.js";
|
|
9
10
|
function projectDefinitionPath(projectRoot) {
|
|
@@ -12,9 +13,13 @@ function projectDefinitionPath(projectRoot) {
|
|
|
12
13
|
function utcIso() {
|
|
13
14
|
return new Date().toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
14
15
|
}
|
|
15
|
-
export function appendAuditEntry(projectRoot, entry) {
|
|
16
|
+
export function appendAuditEntry(projectRoot, entry, changed = true) {
|
|
16
17
|
const root = resolve(projectRoot);
|
|
17
18
|
const logPath = join(root, AUDIT_LOG_REL_PATH);
|
|
19
|
+
const stamped = stampChangedToken(entry, changed);
|
|
20
|
+
if (!changed) {
|
|
21
|
+
return logPath;
|
|
22
|
+
}
|
|
18
23
|
// #2980 wave D: product write sink routes through containedWrite.
|
|
19
24
|
mkdirSync(root, { recursive: true });
|
|
20
25
|
if (!existsSync(logPath)) {
|
|
@@ -28,7 +33,7 @@ export function appendAuditEntry(projectRoot, entry) {
|
|
|
28
33
|
containedWrite({
|
|
29
34
|
root,
|
|
30
35
|
target: AUDIT_LOG_REL_PATH,
|
|
31
|
-
data: `${utcIso()} ${
|
|
36
|
+
data: `${utcIso()} ${stamped}\n`,
|
|
32
37
|
mode: "append",
|
|
33
38
|
});
|
|
34
39
|
return logPath;
|
|
@@ -102,7 +107,7 @@ export function writeTriageScope(projectRoot, rules, options = { presetLabel: "c
|
|
|
102
107
|
`rule_count=${rules.length}`,
|
|
103
108
|
`changed=${changed ? "true" : "false"}`,
|
|
104
109
|
].join(" ");
|
|
105
|
-
appendAuditEntry(projectRoot, auditEntry);
|
|
110
|
+
appendAuditEntry(projectRoot, auditEntry, changed);
|
|
106
111
|
return [changed, auditEntry];
|
|
107
112
|
});
|
|
108
113
|
}
|
|
@@ -153,7 +158,7 @@ export function writeWipCapDecision(projectRoot, options = {}) {
|
|
|
153
158
|
`acceptedDefault=${acceptedDefault ? "true" : "false"}`,
|
|
154
159
|
`changed=${changed ? "true" : "false"}`,
|
|
155
160
|
].join(" ");
|
|
156
|
-
appendAuditEntry(projectRoot, auditEntry);
|
|
161
|
+
appendAuditEntry(projectRoot, auditEntry, changed);
|
|
157
162
|
return [changed, auditEntry];
|
|
158
163
|
});
|
|
159
164
|
}
|
|
@@ -220,7 +225,7 @@ export function writeWipCap(projectRoot, wipCap, options = {}) {
|
|
|
220
225
|
const changed = previous !== wipCap;
|
|
221
226
|
const auditEntry = `actor=${actor} field=plan.policy.wipCap value=${wipCap} previous=${JSON.stringify(previous)} ` +
|
|
222
227
|
`changed=${changed ? "true" : "false"}`;
|
|
223
|
-
appendAuditEntry(projectRoot, auditEntry);
|
|
228
|
+
appendAuditEntry(projectRoot, auditEntry, changed);
|
|
224
229
|
return [changed, auditEntry];
|
|
225
230
|
});
|
|
226
231
|
}
|
package/dist/value/readback.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type BehavioralEventRecord } from "../lifecycle/events.js";
|
|
2
2
|
import { type ValueFeedbackResolved } from "../policy/value-feedback.js";
|
|
3
|
+
import { type CeremonyCostRollup } from "../session/process-cost.js";
|
|
3
4
|
/** Repeat-suppression window for the budgeted session readback (#1709 / #1279 parity). */
|
|
4
5
|
export declare const VALUE_READBACK_SUPPRESSION_HOURS = 4;
|
|
5
6
|
export declare const VALUE_READBACK_HISTORY_REL: string;
|
|
@@ -24,6 +25,8 @@ export interface ValueShowResult {
|
|
|
24
25
|
readonly empty: boolean;
|
|
25
26
|
readonly text: string;
|
|
26
27
|
readonly trend: ValueShowTrend | null;
|
|
28
|
+
/** Composed #3508 ceremony-cost rollup (CLI process time, not turn clock). */
|
|
29
|
+
readonly ceremonyCost: CeremonyCostRollup | null;
|
|
27
30
|
}
|
|
28
31
|
export interface SessionReadbackResult {
|
|
29
32
|
readonly line: string | null;
|
|
@@ -64,7 +67,7 @@ export declare function computeValueShowTrend(projectRoot: string, options?: {
|
|
|
64
67
|
now?: Date;
|
|
65
68
|
}): ValueShowTrend;
|
|
66
69
|
export declare function formatValueShowReport(trend: ValueShowTrend): string;
|
|
67
|
-
/** Pull-based value:show CLI core (#1709). */
|
|
70
|
+
/** Pull-based value:show CLI core (#1709) with composed ceremony-cost reader (#3508). */
|
|
68
71
|
export declare function runValueShow(options: {
|
|
69
72
|
projectRoot?: string | null;
|
|
70
73
|
window?: string;
|
package/dist/value/readback.js
CHANGED
|
@@ -8,6 +8,7 @@ import { DEFAULT_EVENT_LOG, readEvents } from "../lifecycle/events.js";
|
|
|
8
8
|
import { policyColonInvocation } from "../policy/policy-invocation.js";
|
|
9
9
|
import { isValueFeedbackPathAllowed, resolveValueFeedback, } from "../policy/value-feedback.js";
|
|
10
10
|
import { resolveProjectRoot } from "../scope/project-context.js";
|
|
11
|
+
import { computeCeremonyCostRollup, formatCeremonyCostReport, PROCESS_COST_EVENT_NAMES, } from "../session/process-cost.js";
|
|
11
12
|
import { MAX_LINE_CHARS } from "../triage/welcome/constants.js";
|
|
12
13
|
import { probeAdoptionAtWorkBoundary } from "./adoption-emit.js";
|
|
13
14
|
import { probeFrictionAtWorkBoundary } from "./friction-emit.js";
|
|
@@ -391,7 +392,36 @@ export function formatValueShowReport(trend) {
|
|
|
391
392
|
];
|
|
392
393
|
return `${lines.join("\n")}\n`;
|
|
393
394
|
}
|
|
394
|
-
|
|
395
|
+
function attachCeremonyCost(result, ceremonyCost, format) {
|
|
396
|
+
if (format === "json") {
|
|
397
|
+
const payload = result.trend !== null
|
|
398
|
+
? {
|
|
399
|
+
...result.trend,
|
|
400
|
+
ceremonyCost,
|
|
401
|
+
process_cost_events: PROCESS_COST_EVENT_NAMES,
|
|
402
|
+
gated: result.gated,
|
|
403
|
+
attribution_gated: result.gated,
|
|
404
|
+
}
|
|
405
|
+
: {
|
|
406
|
+
ceremonyCost,
|
|
407
|
+
process_cost_events: PROCESS_COST_EVENT_NAMES,
|
|
408
|
+
gated: result.gated,
|
|
409
|
+
attribution_gated: result.gated,
|
|
410
|
+
empty: result.empty,
|
|
411
|
+
};
|
|
412
|
+
return {
|
|
413
|
+
...result,
|
|
414
|
+
ceremonyCost,
|
|
415
|
+
text: `${JSON.stringify(payload, null, 2)}\n`,
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
return {
|
|
419
|
+
...result,
|
|
420
|
+
ceremonyCost,
|
|
421
|
+
text: `${result.text}${formatCeremonyCostReport(ceremonyCost)}`,
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
/** Pull-based value:show CLI core (#1709) with composed ceremony-cost reader (#3508). */
|
|
395
425
|
export function runValueShow(options) {
|
|
396
426
|
const rootRaw = resolveProjectRoot(options.projectRoot ?? undefined);
|
|
397
427
|
if (rootRaw === null) {
|
|
@@ -401,30 +431,39 @@ export function runValueShow(options) {
|
|
|
401
431
|
empty: true,
|
|
402
432
|
text: "Error: could not resolve project root.\n",
|
|
403
433
|
trend: null,
|
|
434
|
+
ceremonyCost: null,
|
|
404
435
|
};
|
|
405
436
|
}
|
|
406
437
|
const root = resolve(rootRaw);
|
|
438
|
+
const windowMs = parseWindowMs(options.window);
|
|
439
|
+
const ceremonyCost = computeCeremonyCostRollup({
|
|
440
|
+
projectRoot: root,
|
|
441
|
+
logPath: options.logPath,
|
|
442
|
+
windowMs,
|
|
443
|
+
now: options.now,
|
|
444
|
+
windowLabel: formatWindowLabel(windowMs),
|
|
445
|
+
});
|
|
407
446
|
if (maintainerReadbackDisabled(root)) {
|
|
408
|
-
return {
|
|
447
|
+
return attachCeremonyCost({
|
|
409
448
|
exitCode: 0,
|
|
410
|
-
gated:
|
|
449
|
+
gated: false,
|
|
411
450
|
empty: true,
|
|
412
|
-
text: "[value]
|
|
451
|
+
text: "[value] Attribution skipped: maintainer framework repo " +
|
|
452
|
+
"(set DEFT_VALUE_SELF_DOGFOOD=1 to dogfood).\n",
|
|
413
453
|
trend: null,
|
|
414
|
-
};
|
|
454
|
+
}, ceremonyCost, options.format);
|
|
415
455
|
}
|
|
416
456
|
const policy = options.policyOverride ?? resolveValueFeedback(root);
|
|
417
457
|
if (!policy.enabled) {
|
|
418
|
-
return {
|
|
458
|
+
return attachCeremonyCost({
|
|
419
459
|
exitCode: 1,
|
|
420
460
|
gated: true,
|
|
421
461
|
empty: true,
|
|
422
462
|
text: "[value] Blocked: plan.policy.valueFeedback is OFF. " +
|
|
423
463
|
`Enable with \`${policyColonInvocation("enable-value-feedback", " -- --confirm")}\`.\n`,
|
|
424
464
|
trend: null,
|
|
425
|
-
};
|
|
465
|
+
}, ceremonyCost, options.format);
|
|
426
466
|
}
|
|
427
|
-
const windowMs = parseWindowMs(options.window);
|
|
428
467
|
const trend = computeValueShowTrend(root, {
|
|
429
468
|
windowMs,
|
|
430
469
|
logPath: options.logPath,
|
|
@@ -432,21 +471,21 @@ export function runValueShow(options) {
|
|
|
432
471
|
});
|
|
433
472
|
const empty = trend.total === 0;
|
|
434
473
|
if (options.format === "json") {
|
|
435
|
-
return {
|
|
474
|
+
return attachCeremonyCost({
|
|
436
475
|
exitCode: 0,
|
|
437
476
|
gated: false,
|
|
438
477
|
empty,
|
|
439
478
|
text: `${JSON.stringify(trend, null, 2)}\n`,
|
|
440
479
|
trend,
|
|
441
|
-
};
|
|
480
|
+
}, ceremonyCost, "json");
|
|
442
481
|
}
|
|
443
|
-
return {
|
|
482
|
+
return attachCeremonyCost({
|
|
444
483
|
exitCode: 0,
|
|
445
484
|
gated: false,
|
|
446
485
|
empty,
|
|
447
486
|
text: formatValueShowReport(trend),
|
|
448
487
|
trend,
|
|
449
|
-
};
|
|
488
|
+
}, ceremonyCost, "text");
|
|
450
489
|
}
|
|
451
490
|
export function parseValueShowArgs(argv) {
|
|
452
491
|
const out = {};
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
export type JsonObject = Record<string, unknown>;
|
|
2
|
+
export declare function resolveInfoBlock(data: JsonObject): {
|
|
3
|
+
key: "vBRIEFInfo" | "xBRIEFInfo";
|
|
4
|
+
info: JsonObject;
|
|
5
|
+
} | null;
|
|
2
6
|
/** Validate vBRIEF/xBRIEF structural requirements (v0.6 + v0.8 additive). */
|
|
3
7
|
export declare function validateVbriefSchema(data: JsonObject, filepath: string): string[];
|
|
4
8
|
/** Normalize a narrative key for D3 comparison. */
|
|
@@ -5,10 +5,10 @@ import { type AgentHookHealthResult } from "./agent-hooks.js";
|
|
|
5
5
|
import { type AgentHookLiveProbeResult, type AgentHookLiveProbeSeams } from "./agent-hooks-live-probe.js";
|
|
6
6
|
import type { OutputStream } from "./verify-hooks-installed.js";
|
|
7
7
|
export type AgentHookReadinessRegistration = "registered" | "disabled" | "missing" | "drifted" | "not-applicable";
|
|
8
|
-
export type AgentHookReadinessFunctionality = "functional" | "non-functional" | "unavailable" | "not-run" | "disabled" | "not-applicable";
|
|
8
|
+
export type AgentHookReadinessFunctionality = "functional" | "non-functional" | "unavailable" | "timed-out" | "not-run" | "disabled" | "not-applicable";
|
|
9
9
|
export type AgentHookReadinessTrust = "manual-review-required" | "not-applicable" | "disabled";
|
|
10
10
|
export type AgentHookReadinessInterception = "not-directly-verified" | "not-applicable" | "disabled";
|
|
11
|
-
export type AgentHookReadinessLiveStatus = "functional" | "non-functional" | "unavailable" | "not-run" | "disabled" | "skipped";
|
|
11
|
+
export type AgentHookReadinessLiveStatus = "functional" | "non-functional" | "unavailable" | "timed-out" | "not-run" | "disabled" | "skipped";
|
|
12
12
|
export interface AgentHookReadinessHostResult {
|
|
13
13
|
readonly host: HookHost;
|
|
14
14
|
readonly registration: AgentHookReadinessRegistration;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { resolve } from "node:path";
|
|
2
2
|
import { resolveFrameworkRootForProject } from "../doctor/paths.js";
|
|
3
|
-
import { loadHostHooksPolicyFromProject } from "../policy/host-hooks.js";
|
|
3
|
+
import { loadHostHooksPolicyFromProject, UNUSED_HOST_HOOKS_RECOVERY, } from "../policy/host-hooks.js";
|
|
4
4
|
import { evaluateAgentHooks } from "./agent-hooks.js";
|
|
5
5
|
import { probeAgentHooksLive, } from "./agent-hooks-live-probe.js";
|
|
6
6
|
/** Stable CLI JSON projection; keep the four readiness dimensions orthogonal. */
|
|
@@ -114,31 +114,35 @@ export function evaluateAgentHookReadiness(projectRoot, options = {}) {
|
|
|
114
114
|
? "functional"
|
|
115
115
|
: liveStatus === "unavailable"
|
|
116
116
|
? "unavailable"
|
|
117
|
-
: liveStatus === "
|
|
118
|
-
? "
|
|
119
|
-
: "
|
|
117
|
+
: liveStatus === "timed-out"
|
|
118
|
+
? "timed-out"
|
|
119
|
+
: liveStatus === "non-functional"
|
|
120
|
+
? "non-functional"
|
|
121
|
+
: "not-run",
|
|
120
122
|
};
|
|
121
123
|
});
|
|
122
124
|
const allDisabled = enabledHosts.length === 0;
|
|
125
|
+
const timeoutOnly = liveProbe.cases.length > 0 && liveProbe.cases.every((entry) => entry.issue === "timed-out");
|
|
123
126
|
const liveStatus = allDisabled
|
|
124
127
|
? "disabled"
|
|
125
128
|
: liveProbe.code === 0
|
|
126
129
|
? "functional"
|
|
127
130
|
: liveProbe.code === 2
|
|
128
131
|
? "unavailable"
|
|
129
|
-
:
|
|
132
|
+
: timeoutOnly
|
|
133
|
+
? "timed-out"
|
|
134
|
+
: "non-functional";
|
|
130
135
|
const trustReview = policy.codex
|
|
131
136
|
? "\n Codex trust: manual-review-required. Open `/hooks` and approve the exact project hook commands. " +
|
|
132
137
|
"The live probe validates the shim and codec, not host interception."
|
|
133
138
|
: "";
|
|
139
|
+
const unusedHostRecovery = liveProbe.code === 0 || timeoutOnly ? "" : `\n ${UNUSED_HOST_HOOKS_RECOVERY}`;
|
|
134
140
|
return {
|
|
135
141
|
code: liveProbe.code,
|
|
136
142
|
message: `${liveProbe.code === 0 ? "✓" : "❌"} deft agent hook readiness: ${liveProbe.message}\n` +
|
|
137
143
|
renderHosts(evaluatedHosts) +
|
|
138
144
|
trustReview +
|
|
139
|
-
|
|
140
|
-
? ""
|
|
141
|
-
: "\n If an affected host is unused, inspect `deft policy:show --field=hostHooks`, set `plan.policy.hostHooks.<host> = false`, and run `deft update`."),
|
|
145
|
+
unusedHostRecovery,
|
|
142
146
|
stream: liveProbe.code === 0 ? "stdout" : "stderr",
|
|
143
147
|
skipped: false,
|
|
144
148
|
liveStatus,
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { type HookEvent, type HookHost } from "../hooks/dispatcher.js";
|
|
2
2
|
export declare const LIVE_PROBE_CASE_TIMEOUT_MS = 1500;
|
|
3
|
+
/** Extra attempts after a timeout. One retry keeps 4×2×1.5s×2 = 24s under Cursor 30s (#3570). */
|
|
4
|
+
export declare const LIVE_PROBE_CASE_RETRY_COUNT = 1;
|
|
5
|
+
export declare const LIVE_PROBE_TIMEOUT_RECOVERY = "Recovery: retry the gated ritual when load is lower. Do not reinstall @deftai/directive or disable hostHooks for a timeout.";
|
|
6
|
+
export declare const LIVE_PROBE_BROKEN_RECOVERY = "Recovery: reinstall @deftai/directive and run `deft update`.";
|
|
3
7
|
export type AgentHookLiveProbeIssue = "hook-command-missing" | "spawn-failed" | "timed-out" | "empty-stdout" | "unparseable-json" | "missing-allow" | "missing-deny";
|
|
4
8
|
export interface AgentHookLiveProbeCase {
|
|
5
9
|
readonly host: HookHost;
|
|
@@ -8,7 +12,7 @@ export interface AgentHookLiveProbeCase {
|
|
|
8
12
|
readonly issue: AgentHookLiveProbeIssue;
|
|
9
13
|
readonly detail: string;
|
|
10
14
|
}
|
|
11
|
-
export type AgentHookLiveProbeHostStatus = "functional" | "non-functional" | "unavailable";
|
|
15
|
+
export type AgentHookLiveProbeHostStatus = "functional" | "non-functional" | "unavailable" | "timed-out";
|
|
12
16
|
export interface AgentHookLiveProbeHostResult {
|
|
13
17
|
readonly host: HookHost;
|
|
14
18
|
readonly status: AgentHookLiveProbeHostStatus;
|
|
@@ -6,6 +6,10 @@ import { DEFT_HOOK_COMMAND_MARKER } from "../init-deposit/agent-hooks.js";
|
|
|
6
6
|
import { SUBPROCESS_MAX_BUFFER } from "../subprocess/max-buffer.js";
|
|
7
7
|
import { quoteWin32CommandForShell, resolveCommandOnPath, shouldUseShellForCommand, } from "./command-spawn.js";
|
|
8
8
|
export const LIVE_PROBE_CASE_TIMEOUT_MS = 1_500;
|
|
9
|
+
/** Extra attempts after a timeout. One retry keeps 4×2×1.5s×2 = 24s under Cursor 30s (#3570). */
|
|
10
|
+
export const LIVE_PROBE_CASE_RETRY_COUNT = 1;
|
|
11
|
+
export const LIVE_PROBE_TIMEOUT_RECOVERY = "Recovery: retry the gated ritual when load is lower. Do not reinstall @deftai/directive or disable hostHooks for a timeout.";
|
|
12
|
+
export const LIVE_PROBE_BROKEN_RECOVERY = "Recovery: reinstall @deftai/directive and run `deft update`.";
|
|
9
13
|
const LIVE_PROBE_EVENT = "tool.before";
|
|
10
14
|
function elapsedMs(started) {
|
|
11
15
|
return Math.max(0, Math.round(performance.now() - started));
|
|
@@ -122,21 +126,38 @@ function validateFixtureOutput(host, fixture, stdout) {
|
|
|
122
126
|
? { ok: true }
|
|
123
127
|
: { ok: false, issue: "missing-deny", detail: `expected ${host} deny envelope` };
|
|
124
128
|
}
|
|
129
|
+
function liveProbeRecovery(cases) {
|
|
130
|
+
if (cases.length > 0 && cases.every((entry) => entry.issue === "timed-out")) {
|
|
131
|
+
return LIVE_PROBE_TIMEOUT_RECOVERY;
|
|
132
|
+
}
|
|
133
|
+
return LIVE_PROBE_BROKEN_RECOVERY;
|
|
134
|
+
}
|
|
135
|
+
function hostStatusFromFailure(hostFailure) {
|
|
136
|
+
if (hostFailure === null)
|
|
137
|
+
return "functional";
|
|
138
|
+
if (hostFailure.issue === "timed-out")
|
|
139
|
+
return "timed-out";
|
|
140
|
+
return "non-functional";
|
|
141
|
+
}
|
|
125
142
|
function runFixtureProbe(command, host, projectRoot, fixture, spawnHook) {
|
|
126
|
-
const
|
|
143
|
+
const input = {
|
|
127
144
|
command,
|
|
128
145
|
args: ["--host", host, "--event", LIVE_PROBE_EVENT, "--project-root", projectRoot],
|
|
129
146
|
stdin: fixture === "allow" ? allowFixture(projectRoot) : denyFixture(projectRoot),
|
|
130
147
|
cwd: projectRoot,
|
|
131
148
|
env: fixture === "allow" ? process.env : denyProbeEnv(),
|
|
132
|
-
}
|
|
149
|
+
};
|
|
150
|
+
let spawned = spawnHook(input);
|
|
151
|
+
for (let retry = 0; retry < LIVE_PROBE_CASE_RETRY_COUNT && spawned.timedOut === true; retry += 1) {
|
|
152
|
+
spawned = spawnHook(input);
|
|
153
|
+
}
|
|
133
154
|
if (spawned.timedOut === true) {
|
|
134
155
|
return {
|
|
135
156
|
host,
|
|
136
157
|
event: LIVE_PROBE_EVENT,
|
|
137
158
|
fixture,
|
|
138
159
|
issue: "timed-out",
|
|
139
|
-
detail: `hook command exceeded ${LIVE_PROBE_CASE_TIMEOUT_MS}ms`,
|
|
160
|
+
detail: `hook command exceeded ${LIVE_PROBE_CASE_TIMEOUT_MS}ms after ${LIVE_PROBE_CASE_RETRY_COUNT + 1} attempts`,
|
|
140
161
|
};
|
|
141
162
|
}
|
|
142
163
|
if (spawned.status !== 0) {
|
|
@@ -204,7 +225,7 @@ export function probeAgentHooksLive(projectRoot, seams = {}) {
|
|
|
204
225
|
break;
|
|
205
226
|
}
|
|
206
227
|
}
|
|
207
|
-
hostResults.push({ host, status: hostFailure
|
|
228
|
+
hostResults.push({ host, status: hostStatusFromFailure(hostFailure) });
|
|
208
229
|
}
|
|
209
230
|
if (failures.length === 0) {
|
|
210
231
|
return {
|
|
@@ -220,7 +241,7 @@ export function probeAgentHooksLive(projectRoot, seams = {}) {
|
|
|
220
241
|
.join("; ");
|
|
221
242
|
return {
|
|
222
243
|
code: 1,
|
|
223
|
-
message: `deft agent hooks live probe FAILED: ${summary}.
|
|
244
|
+
message: `deft agent hooks live probe FAILED: ${summary}. ${liveProbeRecovery(failures)}`,
|
|
224
245
|
cases: failures,
|
|
225
246
|
hosts: hostResults,
|
|
226
247
|
durationMs: elapsedMs(started),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { statSync } from "node:fs";
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
3
|
import { inspectAgentHookDeposit } from "../init-deposit/agent-hooks.js";
|
|
4
|
-
import { loadHostHooksPolicyFromProject } from "../policy/host-hooks.js";
|
|
4
|
+
import { loadHostHooksPolicyFromProject, UNUSED_HOST_HOOKS_RECOVERY, } from "../policy/host-hooks.js";
|
|
5
5
|
function isDirectory(path) {
|
|
6
6
|
try {
|
|
7
7
|
return statSync(path).isDirectory();
|
|
@@ -30,9 +30,8 @@ export function evaluateAgentHooks(projectRoot, hostHooksPolicy = loadHostHooksP
|
|
|
30
30
|
unhealthy
|
|
31
31
|
.map((entry) => ` - ${entry.host}: ${entry.status} at ${entry.path} — ${entry.detail}`)
|
|
32
32
|
.join("\n") +
|
|
33
|
-
"\n Recovery: run `deft update` (or `directive init`) to refresh project hooks." +
|
|
34
|
-
|
|
35
|
-
"set `plan.policy.hostHooks.<host> = false`, and run `deft update` again.",
|
|
33
|
+
"\n Recovery: run `deft update` (or `directive init`) to refresh project hooks. " +
|
|
34
|
+
UNUSED_HOST_HOOKS_RECOVERY,
|
|
36
35
|
stream: "stderr",
|
|
37
36
|
registrations,
|
|
38
37
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deftai/directive-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.106.0",
|
|
4
4
|
"description": "TypeScript engine core for the Directive framework.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -283,6 +283,10 @@
|
|
|
283
283
|
"types": "./dist/lifecycle/index.d.ts",
|
|
284
284
|
"default": "./dist/lifecycle/index.js"
|
|
285
285
|
},
|
|
286
|
+
"./lifecycle-visible": {
|
|
287
|
+
"types": "./dist/lifecycle-visible/index.d.ts",
|
|
288
|
+
"default": "./dist/lifecycle-visible/index.js"
|
|
289
|
+
},
|
|
286
290
|
"./literal-acceptance": {
|
|
287
291
|
"types": "./dist/literal-acceptance/index.d.ts",
|
|
288
292
|
"default": "./dist/literal-acceptance/index.js"
|
|
@@ -382,8 +386,8 @@
|
|
|
382
386
|
"provenance": true
|
|
383
387
|
},
|
|
384
388
|
"dependencies": {
|
|
385
|
-
"@deftai/directive-content": "^0.
|
|
386
|
-
"@deftai/directive-types": "^0.
|
|
389
|
+
"@deftai/directive-content": "^0.106.0",
|
|
390
|
+
"@deftai/directive-types": "^0.106.0",
|
|
387
391
|
"archiver": "^8.0.0"
|
|
388
392
|
},
|
|
389
393
|
"scripts": {
|