@ouro.bot/cli 0.1.0-alpha.664 → 0.1.0-alpha.666

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.
Files changed (32) hide show
  1. package/changelog.json +12 -0
  2. package/dist/arc/flight-recorder.js +267 -4
  3. package/dist/heart/context-loss-sentinel.js +55 -9
  4. package/dist/heart/core.js +167 -4
  5. package/dist/heart/cross-chat-delivery.js +3 -2
  6. package/dist/heart/daemon/cli-exec.js +50 -1
  7. package/dist/heart/daemon/cli-help.js +1 -1
  8. package/dist/heart/daemon/cli-parse.js +36 -2
  9. package/dist/heart/daemon/daemon-entry.js +24 -5
  10. package/dist/heart/daemon/daemon.js +10 -1
  11. package/dist/heart/habits/habit-scheduler.js +24 -5
  12. package/dist/heart/habits/habit-session.js +563 -0
  13. package/dist/heart/mailbox/mailbox-http-hooks.js +2 -0
  14. package/dist/heart/mailbox/mailbox-http-routes.js +40 -0
  15. package/dist/heart/mailbox/mailbox-read.js +3 -1
  16. package/dist/heart/mailbox/readers/runtime-readers.js +56 -0
  17. package/dist/mailbox-ui/assets/index-CaTIFDmv.js +1 -0
  18. package/dist/mailbox-ui/assets/index-Du_9G9WO.css +1 -0
  19. package/dist/mailbox-ui/assets/vendor-CcN1XpQ9.js +61 -0
  20. package/dist/mailbox-ui/index.html +3 -2
  21. package/dist/repertoire/tools-notes.js +50 -0
  22. package/dist/repertoire/tools-record.js +13 -0
  23. package/dist/repertoire/tools-session.js +14 -0
  24. package/dist/repertoire/tools-surface.js +11 -0
  25. package/dist/repertoire/tools.js +7 -0
  26. package/dist/senses/inner-dialog-worker.js +153 -69
  27. package/dist/senses/inner-dialog.js +5 -3
  28. package/dist/senses/pipeline.js +0 -9
  29. package/dist/senses/surface-tool.js +2 -1
  30. package/package.json +1 -1
  31. package/dist/mailbox-ui/assets/index-BZ60na8O.js +0 -61
  32. package/dist/mailbox-ui/assets/index-DG6Xf5uL.css +0 -1
package/changelog.json CHANGED
@@ -1,6 +1,18 @@
1
1
  {
2
2
  "_note": "This changelog is maintained as part of the PR/version-bump workflow. Agent-curated, not auto-generated. Agents read this file directly via read_file to understand what changed between versions.",
3
3
  "versions": [
4
+ {
5
+ "version": "0.1.0-alpha.666",
6
+ "changes": [
7
+ "Close pre-merge habit session review gaps for route gating, executable risk policy, and Desk produced refs."
8
+ ]
9
+ },
10
+ {
11
+ "version": "0.1.0-alpha.665",
12
+ "changes": [
13
+ "Ignore Sentinel-owned daemon-health git dirt when computing the Sentinel bundle signal, preventing a self-sustaining health-receipt loop while keeping real bundle dirt visible."
14
+ ]
15
+ },
4
16
  {
5
17
  "version": "0.1.0-alpha.664",
6
18
  "changes": [
@@ -33,11 +33,15 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.isHabitRunTrigger = isHabitRunTrigger;
36
37
  exports.flightRecorderLatestPath = flightRecorderLatestPath;
37
38
  exports.isFlightRecorderResume = isFlightRecorderResume;
38
39
  exports.readFlightRecorderResume = readFlightRecorderResume;
39
40
  exports.writeFlightRecorderResume = writeFlightRecorderResume;
40
41
  exports.recordFlightRecorderEvent = recordFlightRecorderEvent;
42
+ exports.isSafeHabitRunId = isSafeHabitRunId;
43
+ exports.readHabitRunReceipt = readHabitRunReceipt;
44
+ exports.listHabitRunReceipts = listHabitRunReceipts;
41
45
  exports.writeHabitRunReceipt = writeHabitRunReceipt;
42
46
  exports.formatFlightRecorderResume = formatFlightRecorderResume;
43
47
  exports.createHabitRunId = createHabitRunId;
@@ -46,6 +50,13 @@ const path = __importStar(require("path"));
46
50
  const crypto_1 = require("crypto");
47
51
  const session_events_1 = require("../heart/session-events");
48
52
  const runtime_1 = require("../nerves/runtime");
53
+ function isHabitRunTrigger(value) {
54
+ return value === "cron"
55
+ || value === "launchd"
56
+ || value === "poke"
57
+ || value === "overdue"
58
+ || value === "manual";
59
+ }
49
60
  function flightRecorderDir(agentRoot) {
50
61
  return path.join(agentRoot, "arc", "flight-recorder");
51
62
  }
@@ -55,6 +66,9 @@ function eventsDir(agentRoot) {
55
66
  function receiptsDir(agentRoot) {
56
67
  return path.join(flightRecorderDir(agentRoot), "habit-receipts");
57
68
  }
69
+ function habitReceiptPath(agentRoot, runId) {
70
+ return path.join(receiptsDir(agentRoot), `${runId}.json`);
71
+ }
58
72
  function flightRecorderLatestPath(agentRoot) {
59
73
  return path.join(flightRecorderDir(agentRoot), "latest.json");
60
74
  }
@@ -311,20 +325,269 @@ function recordFlightRecorderEvent(agentRoot, input) {
311
325
  });
312
326
  return event;
313
327
  }
314
- function writeHabitRunReceipt(agentRoot, receipt) {
315
- fs.mkdirSync(receiptsDir(agentRoot), { recursive: true });
316
- const safeReceipt = {
328
+ function isSafeHabitRunId(value) {
329
+ return typeof value === "string"
330
+ && /^[A-Za-z0-9][A-Za-z0-9_.:-]*$/.test(value)
331
+ && !value.includes("..");
332
+ }
333
+ function isPlainRecord(value) {
334
+ return !!value && typeof value === "object" && !Array.isArray(value);
335
+ }
336
+ function isProducedRefArray(value) {
337
+ return Array.isArray(value)
338
+ && value.every((entry) => isPlainRecord(entry)
339
+ && (entry.kind === "arc"
340
+ || entry.kind === "desk_task"
341
+ || entry.kind === "desk_record"
342
+ || entry.kind === "claim"
343
+ || entry.kind === "surface"
344
+ || entry.kind === "none")
345
+ && typeof entry.locator === "string");
346
+ }
347
+ function isHabitSurfaceAttemptArray(value) {
348
+ return Array.isArray(value)
349
+ && value.every((entry) => isPlainRecord(entry)
350
+ && typeof entry.recipient === "string"
351
+ && typeof entry.channel === "string"
352
+ && (entry.reason === "needed_input"
353
+ || entry.reason === "status"
354
+ || entry.reason === "answer"
355
+ || entry.reason === "blocked"
356
+ || entry.reason === "other")
357
+ && (entry.result === "sent"
358
+ || entry.result === "delivered"
359
+ || entry.result === "delivered_now"
360
+ || entry.result === "queued"
361
+ || entry.result === "deferred"
362
+ || entry.result === "blocked"
363
+ || entry.result === "failed"
364
+ || entry.result === "unavailable")
365
+ && (entry.routeKind === undefined
366
+ || entry.routeKind === "family"
367
+ || entry.routeKind === "originator"
368
+ || entry.routeKind === "extra")
369
+ && (entry.rawStatus === undefined || typeof entry.rawStatus === "string")
370
+ && (entry.error === undefined || typeof entry.error === "string"));
371
+ }
372
+ function isHabitReturnRouteArray(value) {
373
+ return Array.isArray(value)
374
+ && value.every((entry) => isPlainRecord(entry)
375
+ && (entry.kind === "family" || entry.kind === "originator" || entry.kind === "extra")
376
+ && typeof entry.recipient === "string"
377
+ && (entry.status === "allowed" || entry.status === "unresolved")
378
+ && (entry.friendId === undefined || typeof entry.friendId === "string")
379
+ && (entry.channel === undefined || typeof entry.channel === "string")
380
+ && (entry.key === undefined || typeof entry.key === "string")
381
+ && (entry.reason === undefined || typeof entry.reason === "string"));
382
+ }
383
+ function isHabitPermissionEnvelope(value) {
384
+ if (!isPlainRecord(value))
385
+ return false;
386
+ return value.schemaVersion === 1
387
+ && typeof value.canMessageOutward === "boolean"
388
+ && isHabitReturnRouteArray(value.returnRoutes)
389
+ && isStringArray(value.deniedTools)
390
+ && isStringArray(value.warnings);
391
+ }
392
+ function isHabitToolPolicy(value) {
393
+ if (!isPlainRecord(value))
394
+ return false;
395
+ return (value.requestedTools === null || isStringArray(value.requestedTools))
396
+ && isStringArray(value.grantedTools)
397
+ && isStringArray(value.deniedTools)
398
+ && typeof value.outwardMessagingAllowed === "boolean";
399
+ }
400
+ function isHabitRunReceipt(value) {
401
+ if (!isPlainRecord(value))
402
+ return false;
403
+ return value.schemaVersion === 2
404
+ && isSafeHabitRunId(value.runId)
405
+ && typeof value.sessionId === "string"
406
+ && typeof value.habitName === "string"
407
+ && (value.trigger === "cron"
408
+ || value.trigger === "launchd"
409
+ || value.trigger === "poke"
410
+ || value.trigger === "overdue"
411
+ || value.trigger === "manual")
412
+ && typeof value.startedAt === "string"
413
+ && typeof value.endedAt === "string"
414
+ && (value.outcome === "no_change"
415
+ || value.outcome === "wrote_arc"
416
+ || value.outcome === "updated_desk"
417
+ || value.outcome === "wrote_record"
418
+ || value.outcome === "surfaced"
419
+ || value.outcome === "blocked"
420
+ || value.outcome === "error")
421
+ && typeof value.definitionLocator === "string"
422
+ && typeof value.sessionLocator === "string"
423
+ && typeof value.pendingLocator === "string"
424
+ && typeof value.runtimeStateLocator === "string"
425
+ && typeof value.receiptLocator === "string"
426
+ && (value.nextRunAt === null || typeof value.nextRunAt === "string")
427
+ && isHabitPermissionEnvelope(value.permissionEnvelope)
428
+ && isHabitToolPolicy(value.toolPolicy)
429
+ && isProducedRefArray(value.producedRefs)
430
+ && isHabitSurfaceAttemptArray(value.surfaceAttempts)
431
+ && isStringArray(value.errors);
432
+ }
433
+ function isLegacyHabitRunReceipt(value) {
434
+ if (!isPlainRecord(value))
435
+ return false;
436
+ return value.schemaVersion === 1
437
+ && isSafeHabitRunId(value.runId)
438
+ && typeof value.habitName === "string"
439
+ && (value.trigger === "cron"
440
+ || value.trigger === "launchd"
441
+ || value.trigger === "poke"
442
+ || value.trigger === "overdue"
443
+ || value.trigger === "manual")
444
+ && typeof value.startedAt === "string"
445
+ && typeof value.endedAt === "string"
446
+ && (value.outcome === "no_change"
447
+ || value.outcome === "wrote_arc"
448
+ || value.outcome === "updated_desk"
449
+ || value.outcome === "wrote_record"
450
+ || value.outcome === "surfaced"
451
+ || value.outcome === "blocked"
452
+ || value.outcome === "error")
453
+ && isProducedRefArray(value.producedRefs)
454
+ && isHabitSurfaceAttemptArray(value.surfaceAttempts)
455
+ && isStringArray(value.errors);
456
+ }
457
+ function warnMalformedHabitReceipt(agentRoot, runId, reason) {
458
+ (0, runtime_1.emitNervesEvent)({
459
+ level: "warn",
460
+ component: "mind",
461
+ event: "mind.flight_recorder_habit_receipt_malformed",
462
+ message: "flight recorder habit receipt malformed",
463
+ meta: { agentRoot, runId: (0, session_events_1.capStructuredRecordString)(runId), reason },
464
+ });
465
+ }
466
+ function normalizeLegacyHabitRunReceipt(receipt) {
467
+ const sawSurface = receipt.surfaceAttempts.length > 0 || receipt.producedRefs.some((ref) => ref.kind === "surface");
468
+ return {
469
+ schemaVersion: 2,
470
+ runId: receipt.runId,
471
+ sessionId: receipt.runId,
472
+ habitName: receipt.habitName,
473
+ trigger: receipt.trigger,
474
+ startedAt: receipt.startedAt,
475
+ endedAt: receipt.endedAt,
476
+ outcome: receipt.outcome,
477
+ definitionLocator: `habits/${receipt.habitName}.md`,
478
+ sessionLocator: `state/habit-sessions/${receipt.runId}/session.json`,
479
+ pendingLocator: `state/habit-sessions/${receipt.runId}/pending`,
480
+ runtimeStateLocator: `state/habits/${receipt.habitName}.json`,
481
+ receiptLocator: `arc/flight-recorder/habit-receipts/${receipt.runId}.json`,
482
+ nextRunAt: null,
483
+ permissionEnvelope: {
484
+ schemaVersion: 1,
485
+ canMessageOutward: sawSurface,
486
+ returnRoutes: [],
487
+ deniedTools: sawSurface ? [] : ["send_message", "surface"],
488
+ warnings: ["legacy receipt normalized without habit permission envelope"],
489
+ },
490
+ toolPolicy: {
491
+ requestedTools: null,
492
+ grantedTools: sawSurface ? ["surface"] : [],
493
+ deniedTools: sawSurface ? [] : ["send_message", "surface"],
494
+ outwardMessagingAllowed: sawSurface,
495
+ },
496
+ producedRefs: receipt.producedRefs,
497
+ surfaceAttempts: receipt.surfaceAttempts,
498
+ errors: receipt.errors,
499
+ };
500
+ }
501
+ function capHabitRunReceipt(receipt) {
502
+ return {
317
503
  ...receipt,
318
504
  habitName: (0, session_events_1.capStructuredRecordString)(receipt.habitName),
505
+ definitionLocator: (0, session_events_1.capStructuredRecordString)(receipt.definitionLocator),
506
+ sessionLocator: (0, session_events_1.capStructuredRecordString)(receipt.sessionLocator),
507
+ pendingLocator: (0, session_events_1.capStructuredRecordString)(receipt.pendingLocator),
508
+ runtimeStateLocator: (0, session_events_1.capStructuredRecordString)(receipt.runtimeStateLocator),
509
+ receiptLocator: (0, session_events_1.capStructuredRecordString)(receipt.receiptLocator),
510
+ permissionEnvelope: {
511
+ ...receipt.permissionEnvelope,
512
+ returnRoutes: receipt.permissionEnvelope.returnRoutes.map((route) => ({
513
+ ...route,
514
+ recipient: (0, session_events_1.capStructuredRecordString)(route.recipient),
515
+ ...(route.friendId ? { friendId: (0, session_events_1.capStructuredRecordString)(route.friendId) } : {}),
516
+ ...(route.channel ? { channel: (0, session_events_1.capStructuredRecordString)(route.channel) } : {}),
517
+ ...(route.key ? { key: (0, session_events_1.capStructuredRecordString)(route.key) } : {}),
518
+ ...(route.reason ? { reason: (0, session_events_1.capStructuredRecordString)(route.reason) } : {}),
519
+ })),
520
+ deniedTools: cappedArray(receipt.permissionEnvelope.deniedTools),
521
+ warnings: cappedArray(receipt.permissionEnvelope.warnings),
522
+ },
523
+ toolPolicy: {
524
+ requestedTools: receipt.toolPolicy.requestedTools ? cappedArray(receipt.toolPolicy.requestedTools) : null,
525
+ grantedTools: cappedArray(receipt.toolPolicy.grantedTools),
526
+ deniedTools: cappedArray(receipt.toolPolicy.deniedTools),
527
+ outwardMessagingAllowed: receipt.toolPolicy.outwardMessagingAllowed,
528
+ },
319
529
  producedRefs: receipt.producedRefs.map((ref) => ({ ...ref, locator: (0, session_events_1.capStructuredRecordString)(ref.locator) })),
320
530
  surfaceAttempts: receipt.surfaceAttempts.map((attempt) => ({
321
531
  ...attempt,
322
532
  recipient: (0, session_events_1.capStructuredRecordString)(attempt.recipient),
323
533
  channel: (0, session_events_1.capStructuredRecordString)(attempt.channel),
534
+ ...(attempt.rawStatus ? { rawStatus: (0, session_events_1.capStructuredRecordString)(attempt.rawStatus) } : {}),
535
+ ...(attempt.error ? { error: (0, session_events_1.capStructuredRecordString)(attempt.error) } : {}),
324
536
  })),
325
537
  errors: receipt.errors.map((error) => (0, session_events_1.capStructuredRecordString)(error)),
326
538
  };
327
- atomicWriteJson(path.join(receiptsDir(agentRoot), `${safeReceipt.runId}.json`), safeReceipt);
539
+ }
540
+ function normalizeHabitRunReceiptForWrite(receipt) {
541
+ return capHabitRunReceipt(receipt.schemaVersion === 1 ? normalizeLegacyHabitRunReceipt(receipt) : receipt);
542
+ }
543
+ function readHabitRunReceipt(agentRoot, runId) {
544
+ if (!isSafeHabitRunId(runId)) {
545
+ warnMalformedHabitReceipt(agentRoot, runId, "unsafe run id");
546
+ return null;
547
+ }
548
+ try {
549
+ const parsed = JSON.parse(fs.readFileSync(habitReceiptPath(agentRoot, runId), "utf-8"));
550
+ const receipt = isHabitRunReceipt(parsed)
551
+ ? parsed
552
+ : isLegacyHabitRunReceipt(parsed)
553
+ ? normalizeLegacyHabitRunReceipt(parsed)
554
+ : null;
555
+ if (!receipt) {
556
+ warnMalformedHabitReceipt(agentRoot, runId, "invalid habit receipt shape");
557
+ return null;
558
+ }
559
+ (0, runtime_1.emitNervesEvent)({
560
+ component: "mind",
561
+ event: "mind.flight_recorder_habit_receipt_read",
562
+ message: "flight recorder habit receipt read",
563
+ meta: { agentRoot, runId },
564
+ });
565
+ return receipt;
566
+ }
567
+ catch (error) {
568
+ warnMalformedHabitReceipt(agentRoot, runId, error instanceof Error ? error.message : /* v8 ignore next -- defensive: non-Error catch branch @preserve */ String(error));
569
+ return null;
570
+ }
571
+ }
572
+ function listHabitRunReceipts(agentRoot, options = {}) {
573
+ const dir = receiptsDir(agentRoot);
574
+ if (!fs.existsSync(dir))
575
+ return [];
576
+ const receipts = fs.readdirSync(dir)
577
+ .filter((fileName) => fileName.endsWith(".json"))
578
+ .map((fileName) => readHabitRunReceipt(agentRoot, path.basename(fileName, ".json")))
579
+ .filter((receipt) => receipt !== null)
580
+ .sort((left, right) => right.endedAt.localeCompare(left.endedAt) || right.runId.localeCompare(left.runId));
581
+ return typeof options.limit === "number" && options.limit >= 0 ? receipts.slice(0, options.limit) : receipts;
582
+ }
583
+ function writeHabitRunReceipt(agentRoot, receipt) {
584
+ fs.mkdirSync(receiptsDir(agentRoot), { recursive: true });
585
+ const safeReceipt = normalizeHabitRunReceiptForWrite(receipt);
586
+ if (!isSafeHabitRunId(safeReceipt.runId)) {
587
+ warnMalformedHabitReceipt(agentRoot, safeReceipt.runId, "unsafe run id");
588
+ throw new Error(`unsafe habit run id: ${safeReceipt.runId}`);
589
+ }
590
+ atomicWriteJson(habitReceiptPath(agentRoot, safeReceipt.runId), safeReceipt);
328
591
  recordFlightRecorderEvent(agentRoot, {
329
592
  kind: "habit_run",
330
593
  recordedAt: safeReceipt.endedAt,
@@ -482,7 +482,7 @@ function healthSignals(results) {
482
482
  }
483
483
  function defaultGitStatus(agentRoot) {
484
484
  try {
485
- const porcelain = (0, child_process_1.execFileSync)("git", ["status", "--porcelain"], {
485
+ const porcelain = (0, child_process_1.execFileSync)("git", ["status", "--porcelain=v1", "-uall"], {
486
486
  cwd: agentRoot,
487
487
  encoding: "utf-8",
488
488
  stdio: ["ignore", "pipe", "pipe"],
@@ -494,7 +494,50 @@ function defaultGitStatus(agentRoot) {
494
494
  return { ok: false, error: String(error) };
495
495
  }
496
496
  }
497
- function bundleSignal(status) {
497
+ function gitStatusEntries(porcelain) {
498
+ return porcelain.split(/\r?\n/).filter((line) => line.trim().length > 0);
499
+ }
500
+ function normalizeGitStatusPath(entryPath) {
501
+ return entryPath.trim().replace(/^"|"$/g, "");
502
+ }
503
+ function gitStatusPaths(entry) {
504
+ const rawPath = entry.slice(3).trim();
505
+ const paths = [];
506
+ let start = 0;
507
+ let inQuote = false;
508
+ let escaped = false;
509
+ for (let index = 0; index < rawPath.length; index += 1) {
510
+ const char = rawPath[index];
511
+ if (escaped) {
512
+ escaped = false;
513
+ continue;
514
+ }
515
+ if (inQuote && char === "\\") {
516
+ escaped = true;
517
+ continue;
518
+ }
519
+ if (char === "\"") {
520
+ inQuote = !inQuote;
521
+ continue;
522
+ }
523
+ if (!inQuote && rawPath.startsWith(" -> ", index)) {
524
+ paths.push(rawPath.slice(start, index));
525
+ start = index + 4;
526
+ index += 3;
527
+ }
528
+ }
529
+ paths.push(rawPath.slice(start));
530
+ return paths.map(normalizeGitStatusPath);
531
+ }
532
+ function isSentinelGitStatusEntry(entry) {
533
+ const sentinelRoot = relativeSentinelRoot();
534
+ return gitStatusPaths(entry).every((entryPath) => {
535
+ const normalizedPath = entryPath.replace(/\/$/, "");
536
+ return normalizedPath === sentinelRoot || normalizedPath.startsWith(`${sentinelRoot}/`);
537
+ });
538
+ }
539
+ function bundleSignal(status, options = {}) {
540
+ const gitStatusCommand = "git status --porcelain=v1 -uall";
498
541
  if (!status.ok) {
499
542
  return {
500
543
  id: "bundle:git",
@@ -503,11 +546,12 @@ function bundleSignal(status) {
503
546
  severity: "warn",
504
547
  verdictImpact: "watch",
505
548
  summary: `bundle git status unavailable: ${status.error}`,
506
- source: { kind: "git", locator: "git status --porcelain" },
507
- repair: repair("agent-runnable", "bundle-cleanup", "Inspect bundle git state before assuming the local state is clean.", "git status --porcelain"),
549
+ source: { kind: "git", locator: gitStatusCommand },
550
+ repair: repair("agent-runnable", "bundle-cleanup", "Inspect bundle git state before assuming the local state is clean.", gitStatusCommand),
508
551
  };
509
552
  }
510
- const dirtyEntries = status.porcelain.split(/\r?\n/).filter((line) => line.trim().length > 0);
553
+ const dirtyEntries = gitStatusEntries(status.porcelain)
554
+ .filter((entry) => !(options.ignoreSentinelDirtyEntries && isSentinelGitStatusEntry(entry)));
511
555
  if (dirtyEntries.length > 0) {
512
556
  return {
513
557
  id: "bundle:git",
@@ -516,8 +560,8 @@ function bundleSignal(status) {
516
560
  severity: "warn",
517
561
  verdictImpact: "watch",
518
562
  summary: `bundle has ${dirtyEntries.length} uncommitted git status entr${dirtyEntries.length === 1 ? "y" : "ies"}`,
519
- source: { kind: "git", locator: "git status --porcelain" },
520
- repair: repair("agent-runnable", "bundle-cleanup", "Resolve or intentionally preserve local bundle changes before handoff.", "git status --porcelain"),
563
+ source: { kind: "git", locator: gitStatusCommand },
564
+ repair: repair("agent-runnable", "bundle-cleanup", "Resolve or intentionally preserve local bundle changes before handoff.", gitStatusCommand),
521
565
  meta: { dirtyEntries },
522
566
  };
523
567
  }
@@ -528,7 +572,7 @@ function bundleSignal(status) {
528
572
  severity: "info",
529
573
  verdictImpact: "none",
530
574
  summary: "bundle git status clean",
531
- source: { kind: "git", locator: "git status --porcelain" },
575
+ source: { kind: "git", locator: gitStatusCommand },
532
576
  };
533
577
  }
534
578
  function sentinelVerdict(signals) {
@@ -633,7 +677,9 @@ function makeReceipt(agentName, agentRoot, options, generatedAt) {
633
677
  gauntletSignal(report),
634
678
  ...deriveContextLossSentinelProviderSignals(providerVisibility),
635
679
  ...healthSignals(options.daemonHealthResults ?? []),
636
- bundleSignal((options.gitStatus ?? (() => defaultGitStatus(agentRoot)))()),
680
+ bundleSignal((options.gitStatus ?? (() => defaultGitStatus(agentRoot)))(), {
681
+ ignoreSentinelDirtyEntries: options.trigger === "daemon_health",
682
+ }),
637
683
  ];
638
684
  const verdict = sentinelVerdict(signals);
639
685
  const latestReady = readLatestReady(agentRoot);