@deftai/directive-core 0.94.0 → 0.96.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 +485 -0
- package/dist/cache/archive.d.ts +134 -0
- package/dist/cache/archive.js +630 -0
- package/dist/cache/index.d.ts +1 -0
- package/dist/cache/index.js +1 -0
- package/dist/cache/main.js +298 -1
- package/dist/content-contracts/skills/helpers.d.ts +1 -1
- package/dist/content-contracts/skills/helpers.js +1 -0
- package/dist/doctor/main.js +41 -9
- package/dist/doctor/types.d.ts +2 -2
- package/dist/freshness/bind.d.ts +67 -0
- package/dist/freshness/bind.js +201 -0
- package/dist/freshness/cli.d.ts +30 -0
- package/dist/freshness/cli.js +180 -0
- package/dist/freshness/compare.d.ts +14 -0
- package/dist/freshness/compare.js +134 -0
- package/dist/freshness/generation.d.ts +44 -0
- package/dist/freshness/generation.js +172 -0
- package/dist/freshness/index.d.ts +13 -0
- package/dist/freshness/index.js +13 -0
- package/dist/freshness/report.d.ts +43 -0
- package/dist/freshness/report.js +139 -0
- package/dist/freshness/types.d.ts +70 -0
- package/dist/freshness/types.js +30 -0
- package/dist/handoff-evidence/index.d.ts +8 -0
- package/dist/handoff-evidence/index.js +7 -0
- package/dist/handoff-evidence/validate.d.ts +105 -0
- package/dist/handoff-evidence/validate.js +423 -0
- package/dist/hooks/dispatcher.d.ts +3 -0
- package/dist/hooks/dispatcher.js +12 -3
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/init-deposit/agent-hooks.d.ts +1 -1
- package/dist/init-deposit/agent-hooks.js +5 -2
- package/dist/init-deposit/hygiene.d.ts +1 -1
- package/dist/init-deposit/hygiene.js +16 -4
- package/dist/init-deposit/init-deposit.d.ts +7 -1
- package/dist/init-deposit/init-deposit.js +24 -4
- package/dist/init-deposit/refresh.d.ts +9 -1
- package/dist/init-deposit/refresh.js +48 -5
- package/dist/init-deposit/scaffold.js +6 -5
- package/dist/parent-turn-shape/evaluate.d.ts +84 -0
- package/dist/parent-turn-shape/evaluate.js +353 -0
- package/dist/parent-turn-shape/index.d.ts +8 -0
- package/dist/parent-turn-shape/index.js +8 -0
- package/dist/policy/index.d.ts +3 -0
- package/dist/policy/index.js +35 -0
- package/dist/release-e2e/greenfield-python-free-smoke.js +7 -3
- package/dist/review-monitor/constants.js +3 -2
- package/dist/review-monitor/tier-detection.d.ts +7 -3
- package/dist/review-monitor/tier-detection.js +18 -1
- package/dist/review-monitor/verify.js +18 -0
- package/dist/scope/index.d.ts +2 -0
- package/dist/scope/index.js +2 -0
- package/dist/scope/main.d.ts +10 -0
- package/dist/scope/main.js +109 -24
- package/dist/scope/promote-from-issue.d.ts +49 -0
- package/dist/scope/promote-from-issue.js +367 -0
- package/dist/scope/promote-path.d.ts +39 -0
- package/dist/scope/promote-path.js +105 -0
- package/dist/session/ritual-entrypoint.d.ts +6 -2
- package/dist/session/ritual-entrypoint.js +15 -2
- package/dist/session/session-ready.js +31 -14
- package/dist/session/session-start.d.ts +2 -1
- package/dist/session/session-start.js +66 -3
- package/dist/session/verify-session-ritual.d.ts +4 -2
- package/dist/session/verify-session-ritual.js +11 -11
- package/dist/slash/product-set.js +4 -1
- package/dist/swarm/routing.d.ts +4 -2
- package/dist/swarm/routing.js +26 -4
- package/dist/swarm/verify-review-clean.d.ts +4 -3
- package/dist/swarm/verify-review-clean.js +28 -73
- package/dist/triage/actions/index.js +62 -2
- package/dist/triage/actions/types.d.ts +8 -1
- package/dist/triage/author-filter.d.ts +51 -0
- package/dist/triage/author-filter.js +152 -0
- package/dist/triage/classify/index.d.ts +9 -0
- package/dist/triage/classify/index.js +34 -2
- package/dist/triage/classify/label-mirror.d.ts +206 -0
- package/dist/triage/classify/label-mirror.js +914 -0
- package/dist/triage/help/registry-data.d.ts +49 -38
- package/dist/triage/help/registry-data.js +134 -39
- package/dist/triage/index.d.ts +1 -0
- package/dist/triage/index.js +1 -0
- package/dist/triage/queue/index.d.ts +1 -0
- package/dist/triage/queue/index.js +1 -0
- package/dist/triage/queue/render.d.ts +2 -0
- package/dist/triage/queue/render.js +6 -0
- package/dist/triage/queue/show.d.ts +1 -1
- package/dist/triage/queue/show.js +4 -2
- package/dist/vbrief-validate/project-definition.js +1 -1
- package/dist/verify-env/agent-hook-readiness.d.ts +42 -0
- package/dist/verify-env/agent-hook-readiness.js +150 -0
- package/dist/verify-env/agent-hooks-live-probe.d.ts +16 -4
- package/dist/verify-env/agent-hooks-live-probe.js +120 -107
- package/dist/verify-env/agent-hooks.js +11 -3
- package/dist/verify-env/index.d.ts +1 -0
- package/dist/verify-env/index.js +1 -0
- package/package.json +11 -3
package/dist/cache/main.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from "node:fs";
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
|
+
import { latestDecisions, readAuditLog } from "../triage/actions/candidates-log.js";
|
|
4
|
+
import { resolveCandidatesLogPath } from "../triage/cache-path.js";
|
|
5
|
+
import { archiveClosedEntries, DEFAULT_ARCHIVE_OLDER_THAN_DAYS, listArchivedEntries, restoreFromArchive, } from "./archive.js";
|
|
3
6
|
import { ALLOWED_SOURCES, DEFAULT_BATCH_SIZE, DEFAULT_DELAY_MS, DEFAULT_PRUNE_OLDER_THAN_DAYS, } from "./constants.js";
|
|
4
7
|
import { CacheCapBreachedError, CacheError, CacheFetchError, CacheNotFoundError, CacheValidationError, } from "./errors.js";
|
|
5
8
|
import { cacheFetchAll, cacheRefreshClosed } from "./fetch.js";
|
|
@@ -8,7 +11,7 @@ import { cacheGet, cacheInvalidate, cachePrune, cachePruneToCap, cachePut } from
|
|
|
8
11
|
import { resolveCaps } from "./quota.js";
|
|
9
12
|
import { clearTaskCache } from "./task-cache/store.js";
|
|
10
13
|
function usage() {
|
|
11
|
-
process.stderr.write("usage: cache [-h] {put,get,invalidate,fetch-all,prune,clear} ...\n");
|
|
14
|
+
process.stderr.write("usage: cache [-h] {put,get,invalidate,fetch-all,prune,clear,archive-closed,archive-list,restore-from-archive} ...\n");
|
|
12
15
|
}
|
|
13
16
|
function normaliseLabelFilter(raw) {
|
|
14
17
|
if (!raw || raw.length === 0)
|
|
@@ -309,6 +312,293 @@ function cmdPrune(args) {
|
|
|
309
312
|
process.stdout.write(`${pythonJsonPretty(payload)}\n`);
|
|
310
313
|
return 0;
|
|
311
314
|
}
|
|
315
|
+
/**
|
|
316
|
+
* Reversible closed-entry archive (#1137). Operator-only; not TTL prune.
|
|
317
|
+
* Distinct from `cache prune` (hard-delete by expires_at).
|
|
318
|
+
*/
|
|
319
|
+
function cmdArchiveClosed(args) {
|
|
320
|
+
let olderThanDays = DEFAULT_ARCHIVE_OLDER_THAN_DAYS;
|
|
321
|
+
let source = "github-issue";
|
|
322
|
+
let repo;
|
|
323
|
+
let dryRun = false;
|
|
324
|
+
let json = false;
|
|
325
|
+
let terminalDecisionOnly = false;
|
|
326
|
+
let projectRoot;
|
|
327
|
+
let cacheRoot;
|
|
328
|
+
let reason;
|
|
329
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
330
|
+
const arg = args[i];
|
|
331
|
+
if (arg === "--older-than-days") {
|
|
332
|
+
olderThanDays = Number.parseInt(args[i + 1] ?? "", 10);
|
|
333
|
+
i += 1;
|
|
334
|
+
}
|
|
335
|
+
else if (arg === "--source") {
|
|
336
|
+
source = args[i + 1] ?? "github-issue";
|
|
337
|
+
i += 1;
|
|
338
|
+
}
|
|
339
|
+
else if (arg === "--repo") {
|
|
340
|
+
repo = args[i + 1];
|
|
341
|
+
i += 1;
|
|
342
|
+
}
|
|
343
|
+
else if (arg === "--dry-run") {
|
|
344
|
+
dryRun = true;
|
|
345
|
+
}
|
|
346
|
+
else if (arg === "--json") {
|
|
347
|
+
json = true;
|
|
348
|
+
}
|
|
349
|
+
else if (arg === "--terminal-decision-only") {
|
|
350
|
+
terminalDecisionOnly = true;
|
|
351
|
+
}
|
|
352
|
+
else if (arg === "--project-root") {
|
|
353
|
+
projectRoot = args[i + 1];
|
|
354
|
+
i += 1;
|
|
355
|
+
}
|
|
356
|
+
else if (arg === "--cache-root") {
|
|
357
|
+
cacheRoot = args[i + 1];
|
|
358
|
+
i += 1;
|
|
359
|
+
}
|
|
360
|
+
else if (arg === "--reason") {
|
|
361
|
+
reason = args[i + 1];
|
|
362
|
+
i += 1;
|
|
363
|
+
}
|
|
364
|
+
else if (arg === "-h" || arg === "--help") {
|
|
365
|
+
process.stdout.write("usage: cache archive-closed [--dry-run] [--older-than-days 30] [--repo OWNER/NAME]\n" +
|
|
366
|
+
" [--source github-issue] [--json] [--terminal-decision-only]\n" +
|
|
367
|
+
" [--project-root PATH] [--cache-root PATH] [--reason TEXT]\n" +
|
|
368
|
+
"\n" +
|
|
369
|
+
"Reversible archive of closed github-issue cache entries (not TTL cache:prune).\n" +
|
|
370
|
+
"Skips issues still referenced by xbrief/{proposed,pending,active}.\n" +
|
|
371
|
+
"Also available as: task triage:cache-archive\n");
|
|
372
|
+
return 0;
|
|
373
|
+
}
|
|
374
|
+
else {
|
|
375
|
+
throw new CacheError(`unexpected argument: ${arg}`);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
const resolvedProjectRoot = projectRoot ?? process.cwd();
|
|
379
|
+
const resolvedCacheRoot = cacheRoot ?? (projectRoot !== undefined ? resolve(projectRoot, ".deft-cache") : undefined);
|
|
380
|
+
let latestDecisionMap = null;
|
|
381
|
+
if (terminalDecisionOnly) {
|
|
382
|
+
try {
|
|
383
|
+
const logPath = resolveCandidatesLogPath(resolvedProjectRoot);
|
|
384
|
+
latestDecisionMap = latestDecisions(readAuditLog(logPath, repo ?? null));
|
|
385
|
+
}
|
|
386
|
+
catch {
|
|
387
|
+
latestDecisionMap = new Map();
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
const result = archiveClosedEntries({
|
|
391
|
+
olderThanDays,
|
|
392
|
+
source,
|
|
393
|
+
repo: repo ?? null,
|
|
394
|
+
dryRun,
|
|
395
|
+
terminalDecisionOnly,
|
|
396
|
+
latestDecisions: latestDecisionMap,
|
|
397
|
+
projectRoot: resolvedProjectRoot,
|
|
398
|
+
cacheRoot: resolvedCacheRoot,
|
|
399
|
+
reason,
|
|
400
|
+
});
|
|
401
|
+
const payload = {
|
|
402
|
+
mode: "archive-closed",
|
|
403
|
+
note: "Reversible closed-entry archive; distinct from cache:prune (TTL hard-delete).",
|
|
404
|
+
dry_run: result.dryRun,
|
|
405
|
+
older_than_days: result.olderThanDays,
|
|
406
|
+
source: result.source,
|
|
407
|
+
repo: result.repo,
|
|
408
|
+
terminal_decision_only: terminalDecisionOnly,
|
|
409
|
+
archived_count: result.archivedCount,
|
|
410
|
+
skipped_count: result.skippedCount,
|
|
411
|
+
archived: result.archived.map((c) => ({
|
|
412
|
+
key: c.key,
|
|
413
|
+
live_dir: c.liveDir,
|
|
414
|
+
archive_dir: c.archiveDir,
|
|
415
|
+
age_basis: c.ageBasis,
|
|
416
|
+
closed_at: c.closedAt,
|
|
417
|
+
pre_archive_decision: c.preArchiveDecision,
|
|
418
|
+
})),
|
|
419
|
+
skipped: result.skipped.map((s) => ({
|
|
420
|
+
key: s.key,
|
|
421
|
+
reason: s.reason,
|
|
422
|
+
detail: s.detail ?? null,
|
|
423
|
+
})),
|
|
424
|
+
};
|
|
425
|
+
if (json) {
|
|
426
|
+
process.stdout.write(`${pythonJsonPretty(payload)}\n`);
|
|
427
|
+
}
|
|
428
|
+
else {
|
|
429
|
+
process.stdout.write(`cache:archive-closed dry_run=${pythonBool(result.dryRun)} archived=${result.archivedCount} skipped=${result.skippedCount} older_than_days=${result.olderThanDays}\n`);
|
|
430
|
+
for (const c of result.archived) {
|
|
431
|
+
process.stdout.write(` archived ${c.key} -> ${c.archiveDir}\n`);
|
|
432
|
+
}
|
|
433
|
+
for (const s of result.skipped) {
|
|
434
|
+
process.stdout.write(` skipped ${s.key} (${s.reason}${s.detail ? `: ${s.detail}` : ""})\n`);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
return 0;
|
|
438
|
+
}
|
|
439
|
+
function cmdArchiveList(args) {
|
|
440
|
+
let source = "github-issue";
|
|
441
|
+
let repo;
|
|
442
|
+
let since;
|
|
443
|
+
let limit;
|
|
444
|
+
let format = "text";
|
|
445
|
+
let cacheRoot;
|
|
446
|
+
let projectRoot;
|
|
447
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
448
|
+
const arg = args[i];
|
|
449
|
+
if (arg === "--source") {
|
|
450
|
+
source = args[i + 1] ?? "github-issue";
|
|
451
|
+
i += 1;
|
|
452
|
+
}
|
|
453
|
+
else if (arg === "--repo") {
|
|
454
|
+
repo = args[i + 1];
|
|
455
|
+
i += 1;
|
|
456
|
+
}
|
|
457
|
+
else if (arg === "--since") {
|
|
458
|
+
since = args[i + 1];
|
|
459
|
+
i += 1;
|
|
460
|
+
}
|
|
461
|
+
else if (arg === "--limit") {
|
|
462
|
+
limit = Number.parseInt(args[i + 1] ?? "", 10);
|
|
463
|
+
i += 1;
|
|
464
|
+
}
|
|
465
|
+
else if (arg === "--format") {
|
|
466
|
+
format = args[i + 1] ?? "text";
|
|
467
|
+
i += 1;
|
|
468
|
+
}
|
|
469
|
+
else if (arg === "--format=json" || arg === "--json") {
|
|
470
|
+
format = "json";
|
|
471
|
+
}
|
|
472
|
+
else if (arg?.startsWith("--format=")) {
|
|
473
|
+
format = arg.slice("--format=".length);
|
|
474
|
+
}
|
|
475
|
+
else if (arg === "--cache-root") {
|
|
476
|
+
cacheRoot = args[i + 1];
|
|
477
|
+
i += 1;
|
|
478
|
+
}
|
|
479
|
+
else if (arg === "--project-root") {
|
|
480
|
+
projectRoot = args[i + 1];
|
|
481
|
+
i += 1;
|
|
482
|
+
}
|
|
483
|
+
else if (arg === "-h" || arg === "--help") {
|
|
484
|
+
process.stdout.write("usage: cache archive-list [--repo OWNER/NAME] [--since ISO] [--limit N]\n" +
|
|
485
|
+
" [--format=json|text] [--source github-issue] [--cache-root PATH]\n" +
|
|
486
|
+
"Also available as: task triage:archive-list\n");
|
|
487
|
+
return 0;
|
|
488
|
+
}
|
|
489
|
+
else {
|
|
490
|
+
throw new CacheError(`unexpected argument: ${arg}`);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
const resolvedCacheRoot = cacheRoot ?? (projectRoot !== undefined ? resolve(projectRoot, ".deft-cache") : undefined);
|
|
494
|
+
const result = listArchivedEntries({
|
|
495
|
+
source,
|
|
496
|
+
repo: repo ?? null,
|
|
497
|
+
since: since ?? null,
|
|
498
|
+
limit: limit ?? null,
|
|
499
|
+
cacheRoot: resolvedCacheRoot,
|
|
500
|
+
});
|
|
501
|
+
if (format === "json") {
|
|
502
|
+
process.stdout.write(`${pythonJsonPretty({
|
|
503
|
+
source: result.source,
|
|
504
|
+
repo: result.repo,
|
|
505
|
+
count: result.count,
|
|
506
|
+
entries: result.entries.map((e) => ({
|
|
507
|
+
key: e.key,
|
|
508
|
+
archived_at: e.archivedAt,
|
|
509
|
+
archive_dir: e.archiveDir,
|
|
510
|
+
meta: e.meta,
|
|
511
|
+
})),
|
|
512
|
+
})}\n`);
|
|
513
|
+
}
|
|
514
|
+
else {
|
|
515
|
+
process.stdout.write(`cache:archive-list count=${result.count}\n`);
|
|
516
|
+
for (const e of result.entries) {
|
|
517
|
+
process.stdout.write(` ${e.key} archived_at=${e.archivedAt}\n`);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
return 0;
|
|
521
|
+
}
|
|
522
|
+
function cmdRestoreFromArchive(args) {
|
|
523
|
+
let source = "github-issue";
|
|
524
|
+
let key;
|
|
525
|
+
let issue;
|
|
526
|
+
let repo;
|
|
527
|
+
let force = false;
|
|
528
|
+
let cacheRoot;
|
|
529
|
+
let projectRoot;
|
|
530
|
+
let json = false;
|
|
531
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
532
|
+
const arg = args[i];
|
|
533
|
+
if (arg === "--source") {
|
|
534
|
+
source = args[i + 1] ?? "github-issue";
|
|
535
|
+
i += 1;
|
|
536
|
+
}
|
|
537
|
+
else if (arg === "--key") {
|
|
538
|
+
key = args[i + 1];
|
|
539
|
+
i += 1;
|
|
540
|
+
}
|
|
541
|
+
else if (arg === "--issue") {
|
|
542
|
+
const rawIssue = args[i + 1] ?? "";
|
|
543
|
+
if (!/^[1-9]\d*$/.test(rawIssue)) {
|
|
544
|
+
throw new CacheError(`--issue must be a positive integer (got ${JSON.stringify(rawIssue)})`);
|
|
545
|
+
}
|
|
546
|
+
issue = Number.parseInt(rawIssue, 10);
|
|
547
|
+
i += 1;
|
|
548
|
+
}
|
|
549
|
+
else if (arg === "--repo") {
|
|
550
|
+
repo = args[i + 1];
|
|
551
|
+
i += 1;
|
|
552
|
+
}
|
|
553
|
+
else if (arg === "--force") {
|
|
554
|
+
force = true;
|
|
555
|
+
}
|
|
556
|
+
else if (arg === "--json") {
|
|
557
|
+
json = true;
|
|
558
|
+
}
|
|
559
|
+
else if (arg === "--cache-root") {
|
|
560
|
+
cacheRoot = args[i + 1];
|
|
561
|
+
i += 1;
|
|
562
|
+
}
|
|
563
|
+
else if (arg === "--project-root") {
|
|
564
|
+
projectRoot = args[i + 1];
|
|
565
|
+
i += 1;
|
|
566
|
+
}
|
|
567
|
+
else if (arg === "-h" || arg === "--help") {
|
|
568
|
+
process.stdout.write("usage: cache restore-from-archive -- --issue N --repo OWNER/NAME [--force]\n" +
|
|
569
|
+
" [--key owner/repo/N] [--source github-issue] [--json]\n" +
|
|
570
|
+
"Also available as: task triage:restore-from-archive\n");
|
|
571
|
+
return 0;
|
|
572
|
+
}
|
|
573
|
+
else if (!key && arg && !arg.startsWith("-") && arg.includes("/")) {
|
|
574
|
+
key = arg;
|
|
575
|
+
}
|
|
576
|
+
else {
|
|
577
|
+
throw new CacheError(`unexpected argument: ${arg}`);
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
const resolvedCacheRoot = cacheRoot ?? (projectRoot !== undefined ? resolve(projectRoot, ".deft-cache") : undefined);
|
|
581
|
+
const result = restoreFromArchive({
|
|
582
|
+
source,
|
|
583
|
+
key,
|
|
584
|
+
issue,
|
|
585
|
+
repo: repo ?? null,
|
|
586
|
+
force,
|
|
587
|
+
cacheRoot: resolvedCacheRoot,
|
|
588
|
+
});
|
|
589
|
+
if (json) {
|
|
590
|
+
process.stdout.write(`${pythonJsonPretty(result)}\n`);
|
|
591
|
+
}
|
|
592
|
+
else {
|
|
593
|
+
process.stdout.write(`cache:restore-from-archive status=${result.status} key=${result.key} live=${result.liveDir}\n`);
|
|
594
|
+
if (result.detail) {
|
|
595
|
+
process.stdout.write(` detail: ${result.detail}\n`);
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
if (result.status === "missing" || result.status === "conflict")
|
|
599
|
+
return 1;
|
|
600
|
+
return 0;
|
|
601
|
+
}
|
|
312
602
|
/** CLI entry point (mirrors `scripts/cache.py::main`). */
|
|
313
603
|
export function main(argv) {
|
|
314
604
|
if (argv.length === 0) {
|
|
@@ -332,6 +622,13 @@ export function main(argv) {
|
|
|
332
622
|
return cmdPrune(rest);
|
|
333
623
|
case "clear":
|
|
334
624
|
return cmdClear(rest);
|
|
625
|
+
case "archive-closed":
|
|
626
|
+
case "cache-archive":
|
|
627
|
+
return cmdArchiveClosed(rest);
|
|
628
|
+
case "archive-list":
|
|
629
|
+
return cmdArchiveList(rest);
|
|
630
|
+
case "restore-from-archive":
|
|
631
|
+
return cmdRestoreFromArchive(rest);
|
|
335
632
|
default:
|
|
336
633
|
usage();
|
|
337
634
|
process.stderr.write(`cache: error: argument cmd: invalid choice: '${cmd}'\n`);
|
|
@@ -21,7 +21,7 @@ export declare function readSkill(relPath: string): string;
|
|
|
21
21
|
*/
|
|
22
22
|
export declare const SWARM_SKILL_REL = "skills/deft-directive-swarm/SKILL.md";
|
|
23
23
|
/** Stable load order: core phases, then host launch adapters, then ops. */
|
|
24
|
-
export declare const SWARM_REFERENCE_ORDER: readonly ["core-phase-0.md", "core-phase-1-2.md", "core-phase-3.md", "host-warp.md", "host-generic.md", "host-grok-build.md", "host-cursor.md", "host-openclaw.md", "core-phase-4.md", "core-phase-5-6.md", "core-ops.md"];
|
|
24
|
+
export declare const SWARM_REFERENCE_ORDER: readonly ["core-phase-0.md", "core-phase-1-2.md", "core-phase-3.md", "host-warp.md", "host-generic.md", "host-grok-build.md", "host-cursor.md", "host-claude-code.md", "host-openclaw.md", "core-phase-4.md", "core-phase-5-6.md", "core-ops.md"];
|
|
25
25
|
export declare function readSwarmSkillSurface(): string;
|
|
26
26
|
export declare function readAgentsMd(): string;
|
|
27
27
|
/** Slice the first `## Returning Sessions` section body out of AGENTS.md. */
|
package/dist/doctor/main.js
CHANGED
|
@@ -517,8 +517,11 @@ export function runAgentHooksHealthCheck(projectRoot, consumerContext, sink, add
|
|
|
517
517
|
});
|
|
518
518
|
return false;
|
|
519
519
|
}
|
|
520
|
-
const
|
|
521
|
-
|
|
520
|
+
const codexEnabled = result.registrations.some((entry) => entry.host === "codex" && entry.status !== "disabled");
|
|
521
|
+
const message = `${checkName}: registered and structurally valid` +
|
|
522
|
+
(codexEnabled
|
|
523
|
+
? "; Codex trust is manual-review-required — open `/hooks` to review the project commands"
|
|
524
|
+
: "");
|
|
522
525
|
sink.success(message);
|
|
523
526
|
addFinding({
|
|
524
527
|
severity: "skip",
|
|
@@ -526,8 +529,11 @@ export function runAgentHooksHealthCheck(projectRoot, consumerContext, sink, add
|
|
|
526
529
|
check: checkName,
|
|
527
530
|
status: "registered",
|
|
528
531
|
registrations: result.registrations,
|
|
529
|
-
trust_status: "not-
|
|
530
|
-
trust_review:
|
|
532
|
+
trust_status: codexEnabled ? "manual-review-required" : "not-applicable",
|
|
533
|
+
trust_review: codexEnabled
|
|
534
|
+
? "Open `/hooks` in Codex and review the exact project hook commands."
|
|
535
|
+
: null,
|
|
536
|
+
interception_status: "not-directly-verified",
|
|
531
537
|
});
|
|
532
538
|
return true;
|
|
533
539
|
}
|
|
@@ -543,7 +549,25 @@ export function runAgentHooksLiveProbeCheck(projectRoot, sink, addFinding, seams
|
|
|
543
549
|
const liveCheckName = "agent-hooks-live-probe";
|
|
544
550
|
try {
|
|
545
551
|
const result = (seams.evaluateAgentHooks ?? evaluateAgentHooks)(projectRoot);
|
|
546
|
-
|
|
552
|
+
if (result.code !== 0) {
|
|
553
|
+
const message = `${checkName}: ${result.message.replace(/\s+/g, " ").trim()}`;
|
|
554
|
+
sink.warn(message);
|
|
555
|
+
addFinding({
|
|
556
|
+
severity: "warning",
|
|
557
|
+
message,
|
|
558
|
+
check: checkName,
|
|
559
|
+
status: result.code === 2 ? "unavailable" : "incomplete",
|
|
560
|
+
registrations: result.registrations,
|
|
561
|
+
suggestion: "deft update",
|
|
562
|
+
});
|
|
563
|
+
return;
|
|
564
|
+
}
|
|
565
|
+
const enabledHosts = result.registrations
|
|
566
|
+
.filter((entry) => entry.status !== "disabled")
|
|
567
|
+
.map((entry) => entry.host);
|
|
568
|
+
const liveResult = (seams.probeAgentHooksLive ?? probeAgentHooksLive)(projectRoot, {
|
|
569
|
+
hosts: enabledHosts,
|
|
570
|
+
});
|
|
547
571
|
if (liveResult.code !== 0) {
|
|
548
572
|
const message = `${liveCheckName}: ${liveResult.message.replace(/\s+/g, " ").trim()}`;
|
|
549
573
|
sink.warn(message);
|
|
@@ -557,8 +581,12 @@ export function runAgentHooksLiveProbeCheck(projectRoot, sink, addFinding, seams
|
|
|
557
581
|
});
|
|
558
582
|
return;
|
|
559
583
|
}
|
|
560
|
-
const
|
|
561
|
-
|
|
584
|
+
const codexEnabled = result.registrations.some((entry) => entry.host === "codex" && entry.status !== "disabled");
|
|
585
|
+
const message = `${checkName}: registered, structurally valid, and live probe passed` +
|
|
586
|
+
(codexEnabled
|
|
587
|
+
? "; Codex trust is manual-review-required — open `/hooks` to review the project commands"
|
|
588
|
+
: "") +
|
|
589
|
+
"; direct shim invocation does not verify host interception";
|
|
562
590
|
sink.success(message);
|
|
563
591
|
addFinding({
|
|
564
592
|
severity: "skip",
|
|
@@ -566,9 +594,13 @@ export function runAgentHooksLiveProbeCheck(projectRoot, sink, addFinding, seams
|
|
|
566
594
|
check: liveCheckName,
|
|
567
595
|
status: "registered-and-functional",
|
|
568
596
|
registrations: result.registrations,
|
|
569
|
-
trust_status: "not-
|
|
570
|
-
trust_review:
|
|
597
|
+
trust_status: codexEnabled ? "manual-review-required" : "not-applicable",
|
|
598
|
+
trust_review: codexEnabled
|
|
599
|
+
? "Open `/hooks` in Codex and review the exact project hook commands."
|
|
600
|
+
: null,
|
|
601
|
+
interception_status: "not-directly-verified",
|
|
571
602
|
live_probe: "passed",
|
|
603
|
+
live_probe_duration_ms: liveResult.durationMs,
|
|
572
604
|
});
|
|
573
605
|
}
|
|
574
606
|
catch (cause) {
|
package/dist/doctor/types.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import type { EngineProbeResult } from "../resolution/classify.js";
|
|
|
4
4
|
import type { ResolutionMode } from "../resolution/index.js";
|
|
5
5
|
import type { ResolveUserMdResult } from "../user-config/resolve-user-md.js";
|
|
6
6
|
import type { AgentHookHealthResult } from "../verify-env/agent-hooks.js";
|
|
7
|
-
import type { AgentHookLiveProbeResult } from "../verify-env/agent-hooks-live-probe.js";
|
|
7
|
+
import type { AgentHookLiveProbeResult, AgentHookLiveProbeSeams } from "../verify-env/agent-hooks-live-probe.js";
|
|
8
8
|
export declare const EXIT_CLEAN = 0;
|
|
9
9
|
export declare const EXIT_DRIFT = 1;
|
|
10
10
|
export declare const EXIT_CONFIG_ERROR = 2;
|
|
@@ -153,7 +153,7 @@ export interface DoctorSeams {
|
|
|
153
153
|
/** Read-only agent-host hook registration probe (#2438). */
|
|
154
154
|
readonly evaluateAgentHooks?: (projectRoot: string) => AgentHookHealthResult;
|
|
155
155
|
/** Live hook spawn probe for doctor --full (#2852). */
|
|
156
|
-
readonly probeAgentHooksLive?: (projectRoot: string) => AgentHookLiveProbeResult;
|
|
156
|
+
readonly probeAgentHooksLive?: (projectRoot: string, seams?: AgentHookLiveProbeSeams) => AgentHookLiveProbeResult;
|
|
157
157
|
/**
|
|
158
158
|
* xBRIEF project-envelope staleness probe (#2971). Injected so doctor can
|
|
159
159
|
* fail closed on 0.6 project JSON under an xbrief/ layout without re-deriving
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session bind of live deposit generation (#3117).
|
|
3
|
+
*
|
|
4
|
+
* Host-agnostic storage:
|
|
5
|
+
* - Default (no sessionId): `.deft/session-bind.json` — single-operator convenience.
|
|
6
|
+
* - With sessionId: `.deft/session-binds/<safeId>.json` — isolated multi-session binds.
|
|
7
|
+
*
|
|
8
|
+
* Multi-agent hosts MUST pass a stable host session identity when binding and
|
|
9
|
+
* reporting so one session cannot certify another as current.
|
|
10
|
+
*/
|
|
11
|
+
import { type BoundGeneration, type LiveGeneration } from "./types.js";
|
|
12
|
+
/** Relative path for the default (no-sessionId) bind record. */
|
|
13
|
+
export declare const SESSION_BIND_REL: string;
|
|
14
|
+
/** Directory for per-session bind records. */
|
|
15
|
+
export declare const SESSION_BINDS_DIR_REL: string;
|
|
16
|
+
export declare function sessionBindPath(projectRoot: string, sessionId?: string | null): string;
|
|
17
|
+
/**
|
|
18
|
+
* Stable filesystem-safe file name for a host session id.
|
|
19
|
+
* Keeps a short prefix for debug, hashes the rest to avoid path injection.
|
|
20
|
+
* Character filter is O(n) (no regex) — CodeQL poly-redos on uncontrolled ids.
|
|
21
|
+
*/
|
|
22
|
+
export declare function safeSessionFileName(sessionId: string): string;
|
|
23
|
+
export interface BindSessionOptions {
|
|
24
|
+
readonly sessionId?: string | null;
|
|
25
|
+
readonly nowIso?: string;
|
|
26
|
+
/**
|
|
27
|
+
* When live generation is missing (legacy deposit), stamp generation 1 from
|
|
28
|
+
* contentVersion before binding. Default true.
|
|
29
|
+
*/
|
|
30
|
+
readonly ensureLive?: boolean;
|
|
31
|
+
/** Used only when ensuring a missing live token. */
|
|
32
|
+
readonly contentVersion?: string;
|
|
33
|
+
readonly stampedBy?: string;
|
|
34
|
+
/**
|
|
35
|
+
* When binding with a sessionId, also write the default bind path.
|
|
36
|
+
* Default **false** — multi-agent isolation requires hosts to report with
|
|
37
|
+
* `--session-id`. Enabling this reopens cross-session false-current (Greptile).
|
|
38
|
+
*/
|
|
39
|
+
readonly alsoWriteDefault?: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Host attests that payload surfaces for the live generation were reloaded
|
|
42
|
+
* into the session. Required for trusted readiness. Default false.
|
|
43
|
+
*/
|
|
44
|
+
readonly payloadLoaded?: boolean;
|
|
45
|
+
}
|
|
46
|
+
export interface ReadBoundOptions {
|
|
47
|
+
/** When set, read only that session's bind (never the default). */
|
|
48
|
+
readonly sessionId?: string | null;
|
|
49
|
+
}
|
|
50
|
+
/** Parse a bound generation record (null if invalid). */
|
|
51
|
+
export declare function parseBoundGeneration(raw: unknown): BoundGeneration | null;
|
|
52
|
+
/** Read the session bind record (null when absent/unreadable). */
|
|
53
|
+
export declare function readBoundGeneration(projectRoot: string, options?: ReadBoundOptions): BoundGeneration | null;
|
|
54
|
+
/**
|
|
55
|
+
* Bind the current live generation into session context.
|
|
56
|
+
*
|
|
57
|
+
* Does not require restarting a shared host runtime — callers re-load payload
|
|
58
|
+
* surfaces into the session and call this (or `freshness:bind`) to rebind.
|
|
59
|
+
*
|
|
60
|
+
* Multi-agent hosts MUST supply `sessionId` so binds do not overwrite each other.
|
|
61
|
+
*/
|
|
62
|
+
export declare function bindSessionGeneration(projectRoot: string, options?: BindSessionOptions): {
|
|
63
|
+
bound: BoundGeneration;
|
|
64
|
+
live: LiveGeneration;
|
|
65
|
+
path: string;
|
|
66
|
+
};
|
|
67
|
+
//# sourceMappingURL=bind.d.ts.map
|