instar 0.28.102 → 0.28.103

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 (247) hide show
  1. package/.claude/hooks/instar/before-prompt-recall.js +90 -0
  2. package/dist/cli.js +28 -0
  3. package/dist/cli.js.map +1 -1
  4. package/dist/commands/init.d.ts +1 -0
  5. package/dist/commands/init.d.ts.map +1 -1
  6. package/dist/commands/init.js +14 -1
  7. package/dist/commands/init.js.map +1 -1
  8. package/dist/commands/jobMigrate.d.ts +46 -0
  9. package/dist/commands/jobMigrate.d.ts.map +1 -0
  10. package/dist/commands/jobMigrate.js +292 -0
  11. package/dist/commands/jobMigrate.js.map +1 -0
  12. package/dist/commands/server.d.ts.map +1 -1
  13. package/dist/commands/server.js +88 -42
  14. package/dist/commands/server.js.map +1 -1
  15. package/dist/core/BackupManager.d.ts +27 -1
  16. package/dist/core/BackupManager.d.ts.map +1 -1
  17. package/dist/core/BackupManager.js +56 -1
  18. package/dist/core/BackupManager.js.map +1 -1
  19. package/dist/core/GitStateManager.d.ts +8 -0
  20. package/dist/core/GitStateManager.d.ts.map +1 -1
  21. package/dist/core/GitStateManager.js +31 -1
  22. package/dist/core/GitStateManager.js.map +1 -1
  23. package/dist/core/MigratorStepEngine.d.ts +170 -0
  24. package/dist/core/MigratorStepEngine.d.ts.map +1 -0
  25. package/dist/core/MigratorStepEngine.js +352 -0
  26. package/dist/core/MigratorStepEngine.js.map +1 -0
  27. package/dist/core/PostUpdateMigrator.d.ts +76 -0
  28. package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
  29. package/dist/core/PostUpdateMigrator.js +252 -1
  30. package/dist/core/PostUpdateMigrator.js.map +1 -1
  31. package/dist/core/PreCompactionFlush.d.ts +101 -0
  32. package/dist/core/PreCompactionFlush.d.ts.map +1 -0
  33. package/dist/core/PreCompactionFlush.js +282 -0
  34. package/dist/core/PreCompactionFlush.js.map +1 -0
  35. package/dist/core/PromptBuildRecall.d.ts +97 -0
  36. package/dist/core/PromptBuildRecall.d.ts.map +1 -0
  37. package/dist/core/PromptBuildRecall.js +152 -0
  38. package/dist/core/PromptBuildRecall.js.map +1 -0
  39. package/dist/core/selectIntelligenceProvider.d.ts +41 -0
  40. package/dist/core/selectIntelligenceProvider.d.ts.map +1 -0
  41. package/dist/core/selectIntelligenceProvider.js +89 -0
  42. package/dist/core/selectIntelligenceProvider.js.map +1 -0
  43. package/dist/lifeline/ServerSupervisor.d.ts +183 -0
  44. package/dist/lifeline/ServerSupervisor.d.ts.map +1 -1
  45. package/dist/lifeline/ServerSupervisor.js +443 -0
  46. package/dist/lifeline/ServerSupervisor.js.map +1 -1
  47. package/dist/memory/NativeModuleHealer.d.ts +89 -0
  48. package/dist/memory/NativeModuleHealer.d.ts.map +1 -1
  49. package/dist/memory/NativeModuleHealer.js +371 -1
  50. package/dist/memory/NativeModuleHealer.js.map +1 -1
  51. package/dist/memory/SemanticMemory.d.ts +131 -0
  52. package/dist/memory/SemanticMemory.d.ts.map +1 -1
  53. package/dist/memory/SemanticMemory.js +315 -0
  54. package/dist/memory/SemanticMemory.js.map +1 -1
  55. package/dist/messaging/DeliveryRetryManager.d.ts +60 -0
  56. package/dist/messaging/DeliveryRetryManager.d.ts.map +1 -1
  57. package/dist/messaging/DeliveryRetryManager.js +104 -0
  58. package/dist/messaging/DeliveryRetryManager.js.map +1 -1
  59. package/dist/monitoring/DegradationReporter.d.ts +164 -0
  60. package/dist/monitoring/DegradationReporter.d.ts.map +1 -1
  61. package/dist/monitoring/DegradationReporter.js +309 -1
  62. package/dist/monitoring/DegradationReporter.js.map +1 -1
  63. package/dist/monitoring/ErrorCodeExtractor.d.ts +69 -0
  64. package/dist/monitoring/ErrorCodeExtractor.d.ts.map +1 -0
  65. package/dist/monitoring/ErrorCodeExtractor.js +131 -0
  66. package/dist/monitoring/ErrorCodeExtractor.js.map +1 -0
  67. package/dist/monitoring/PromptGate.d.ts +34 -0
  68. package/dist/monitoring/PromptGate.d.ts.map +1 -1
  69. package/dist/monitoring/PromptGate.js +81 -1
  70. package/dist/monitoring/PromptGate.js.map +1 -1
  71. package/dist/monitoring/Redactor.d.ts +58 -0
  72. package/dist/monitoring/Redactor.d.ts.map +1 -0
  73. package/dist/monitoring/Redactor.js +143 -0
  74. package/dist/monitoring/Redactor.js.map +1 -0
  75. package/dist/monitoring/probes/LifelineProbe.d.ts +7 -0
  76. package/dist/monitoring/probes/LifelineProbe.d.ts.map +1 -1
  77. package/dist/monitoring/probes/LifelineProbe.js +7 -0
  78. package/dist/monitoring/probes/LifelineProbe.js.map +1 -1
  79. package/dist/monitoring/probes/__shared.d.ts +50 -0
  80. package/dist/monitoring/probes/__shared.d.ts.map +1 -0
  81. package/dist/monitoring/probes/__shared.js +51 -0
  82. package/dist/monitoring/probes/__shared.js.map +1 -0
  83. package/dist/remediation/IntentJournal.d.ts +64 -0
  84. package/dist/remediation/IntentJournal.d.ts.map +1 -0
  85. package/dist/remediation/IntentJournal.js +118 -0
  86. package/dist/remediation/IntentJournal.js.map +1 -0
  87. package/dist/remediation/MachineLock.d.ts +137 -0
  88. package/dist/remediation/MachineLock.d.ts.map +1 -0
  89. package/dist/remediation/MachineLock.js +314 -0
  90. package/dist/remediation/MachineLock.js.map +1 -0
  91. package/dist/remediation/PrimaryAggregatorLease.d.ts +205 -0
  92. package/dist/remediation/PrimaryAggregatorLease.d.ts.map +1 -0
  93. package/dist/remediation/PrimaryAggregatorLease.js +450 -0
  94. package/dist/remediation/PrimaryAggregatorLease.js.map +1 -0
  95. package/dist/remediation/RemediationContext.d.ts +63 -0
  96. package/dist/remediation/RemediationContext.d.ts.map +1 -0
  97. package/dist/remediation/RemediationContext.js +109 -0
  98. package/dist/remediation/RemediationContext.js.map +1 -0
  99. package/dist/remediation/RemediationKeyVault.d.ts +123 -0
  100. package/dist/remediation/RemediationKeyVault.d.ts.map +1 -0
  101. package/dist/remediation/RemediationKeyVault.js +564 -0
  102. package/dist/remediation/RemediationKeyVault.js.map +1 -0
  103. package/dist/remediation/Remediator.d.ts +288 -0
  104. package/dist/remediation/Remediator.d.ts.map +1 -0
  105. package/dist/remediation/Remediator.js +520 -0
  106. package/dist/remediation/Remediator.js.map +1 -0
  107. package/dist/remediation/RemediatorBootstrap.d.ts +141 -0
  108. package/dist/remediation/RemediatorBootstrap.d.ts.map +1 -0
  109. package/dist/remediation/RemediatorBootstrap.js +255 -0
  110. package/dist/remediation/RemediatorBootstrap.js.map +1 -0
  111. package/dist/remediation/TrustElevationSource.d.ts +153 -0
  112. package/dist/remediation/TrustElevationSource.d.ts.map +1 -0
  113. package/dist/remediation/TrustElevationSource.js +208 -0
  114. package/dist/remediation/TrustElevationSource.js.map +1 -0
  115. package/dist/remediation/audit/AuditProjection.d.ts +37 -0
  116. package/dist/remediation/audit/AuditProjection.d.ts.map +1 -0
  117. package/dist/remediation/audit/AuditProjection.js +118 -0
  118. package/dist/remediation/audit/AuditProjection.js.map +1 -0
  119. package/dist/remediation/audit/AuditWriter.d.ts +79 -0
  120. package/dist/remediation/audit/AuditWriter.d.ts.map +1 -0
  121. package/dist/remediation/audit/AuditWriter.js +132 -0
  122. package/dist/remediation/audit/AuditWriter.js.map +1 -0
  123. package/dist/remediation/channels/CliApprovalChannel.d.ts +37 -0
  124. package/dist/remediation/channels/CliApprovalChannel.d.ts.map +1 -0
  125. package/dist/remediation/channels/CliApprovalChannel.js +45 -0
  126. package/dist/remediation/channels/CliApprovalChannel.js.map +1 -0
  127. package/dist/remediation/channels/TelegramApprovalChannel.d.ts +37 -0
  128. package/dist/remediation/channels/TelegramApprovalChannel.d.ts.map +1 -0
  129. package/dist/remediation/channels/TelegramApprovalChannel.js +45 -0
  130. package/dist/remediation/channels/TelegramApprovalChannel.js.map +1 -0
  131. package/dist/remediation/runbooks/db-corruption.d.ts +86 -0
  132. package/dist/remediation/runbooks/db-corruption.d.ts.map +1 -0
  133. package/dist/remediation/runbooks/db-corruption.js +190 -0
  134. package/dist/remediation/runbooks/db-corruption.js.map +1 -0
  135. package/dist/remediation/runbooks/messaging-delivery-failed.d.ts +108 -0
  136. package/dist/remediation/runbooks/messaging-delivery-failed.d.ts.map +1 -0
  137. package/dist/remediation/runbooks/messaging-delivery-failed.js +172 -0
  138. package/dist/remediation/runbooks/messaging-delivery-failed.js.map +1 -0
  139. package/dist/remediation/runbooks/node-abi-mismatch.d.ts +70 -0
  140. package/dist/remediation/runbooks/node-abi-mismatch.d.ts.map +1 -0
  141. package/dist/remediation/runbooks/node-abi-mismatch.js +216 -0
  142. package/dist/remediation/runbooks/node-abi-mismatch.js.map +1 -0
  143. package/dist/remediation/runbooks/supervisor-preflight.d.ts +114 -0
  144. package/dist/remediation/runbooks/supervisor-preflight.d.ts.map +1 -0
  145. package/dist/remediation/runbooks/supervisor-preflight.js +299 -0
  146. package/dist/remediation/runbooks/supervisor-preflight.js.map +1 -0
  147. package/dist/scheduler/AgentMdAtomicSave.d.ts +85 -0
  148. package/dist/scheduler/AgentMdAtomicSave.d.ts.map +1 -0
  149. package/dist/scheduler/AgentMdAtomicSave.js +169 -0
  150. package/dist/scheduler/AgentMdAtomicSave.js.map +1 -0
  151. package/dist/scheduler/AgentMdReconcile.d.ts +62 -0
  152. package/dist/scheduler/AgentMdReconcile.d.ts.map +1 -0
  153. package/dist/scheduler/AgentMdReconcile.js +212 -0
  154. package/dist/scheduler/AgentMdReconcile.js.map +1 -0
  155. package/dist/scheduler/DisabledBodyDrift.d.ts +70 -0
  156. package/dist/scheduler/DisabledBodyDrift.d.ts.map +1 -0
  157. package/dist/scheduler/DisabledBodyDrift.js +149 -0
  158. package/dist/scheduler/DisabledBodyDrift.js.map +1 -0
  159. package/dist/scheduler/InstallBuiltinJobs.d.ts +53 -0
  160. package/dist/scheduler/InstallBuiltinJobs.d.ts.map +1 -0
  161. package/dist/scheduler/InstallBuiltinJobs.js +212 -0
  162. package/dist/scheduler/InstallBuiltinJobs.js.map +1 -0
  163. package/dist/scheduler/JobLoader.d.ts.map +1 -1
  164. package/dist/scheduler/JobLoader.js +48 -0
  165. package/dist/scheduler/JobLoader.js.map +1 -1
  166. package/dist/scheduler/MigrationInvariants.d.ts +62 -0
  167. package/dist/scheduler/MigrationInvariants.d.ts.map +1 -0
  168. package/dist/scheduler/MigrationInvariants.js +215 -0
  169. package/dist/scheduler/MigrationInvariants.js.map +1 -0
  170. package/dist/scheduler/MigrationLedger.d.ts +84 -0
  171. package/dist/scheduler/MigrationLedger.d.ts.map +1 -0
  172. package/dist/scheduler/MigrationLedger.js +114 -0
  173. package/dist/scheduler/MigrationLedger.js.map +1 -0
  174. package/dist/server/fileRoutes.d.ts.map +1 -1
  175. package/dist/server/fileRoutes.js +7 -0
  176. package/dist/server/fileRoutes.js.map +1 -1
  177. package/dist/server/routes.d.ts.map +1 -1
  178. package/dist/server/routes.js +141 -0
  179. package/dist/server/routes.js.map +1 -1
  180. package/package.json +3 -2
  181. package/scripts/classify-default-drift.mjs +238 -0
  182. package/scripts/eli16-overview-check.mjs +85 -0
  183. package/scripts/instar-dev-precommit.js +60 -1
  184. package/scripts/lint-degradation-emit-sites.js +116 -0
  185. package/scripts/lint-no-direct-destructive.js +12 -0
  186. package/scripts/protect-migration-guarantee.js +61 -0
  187. package/scripts/regen-default-job-templates.mjs +111 -0
  188. package/scripts/verify-runbook-pr-signature.js +366 -0
  189. package/src/data/builtin-manifest.json +93 -93
  190. package/src/scaffold/bootstrap.ts +138 -0
  191. package/src/scaffold/keys/instar-release-pub.pem +3 -0
  192. package/src/scaffold/templates/jobs/instar/.gitkeep +0 -0
  193. package/src/scaffold/templates/jobs/instar/commitment-detection.md +28 -0
  194. package/src/scaffold/templates/jobs/instar/evolution-overdue-check.md +28 -0
  195. package/src/scaffold/templates/jobs/instar/evolution-proposal-evaluate.md +30 -0
  196. package/src/scaffold/templates/jobs/instar/evolution-proposal-implement.md +25 -0
  197. package/src/scaffold/templates/jobs/instar/health-check.md +14 -0
  198. package/src/scaffold/templates/jobs/instar/identity-review.md +42 -0
  199. package/src/scaffold/templates/jobs/instar/insight-harvest.md +31 -0
  200. package/src/scaffold/templates/jobs/instar/overseer-development.md +23 -0
  201. package/src/scaffold/templates/jobs/instar/overseer-guardian.md +28 -0
  202. package/src/scaffold/templates/jobs/instar/overseer-infrastructure.md +26 -0
  203. package/src/scaffold/templates/jobs/instar/overseer-learning.md +28 -0
  204. package/src/scaffold/templates/jobs/instar/overseer-maintenance.md +27 -0
  205. package/src/scaffold/templates/jobs/instar/reflection-trigger.md +40 -0
  206. package/src/scaffold/templates/jobs/instar/relationship-maintenance.md +16 -0
  207. package/src/scaffold/templates.ts +1616 -0
  208. package/upgrades/0.28.102.md +6 -7
  209. package/upgrades/0.28.103.md +471 -0
  210. package/upgrades/side-effects/a47-primary-aggregator-lease.md +82 -0
  211. package/upgrades/side-effects/agentmd-atomic-save.md +66 -0
  212. package/upgrades/side-effects/agentmd-loader-200jobs-perf-benchmark.md +50 -0
  213. package/upgrades/side-effects/agentmd-reconcile-boot-lifecycle.md +66 -0
  214. package/upgrades/side-effects/api-safety-guard.md +80 -0
  215. package/upgrades/side-effects/c1-runbook-pr-gate.md +83 -0
  216. package/upgrades/side-effects/disabled-body-drift-detection.md +59 -0
  217. package/upgrades/side-effects/drift-classifier-release-time.md +71 -0
  218. package/upgrades/side-effects/eli16-overview-required-gate.md +77 -0
  219. package/upgrades/side-effects/f1-remediation-key-vault.md +195 -0
  220. package/upgrades/side-effects/f2-redactor-errorcode-extractor.md +130 -0
  221. package/upgrades/side-effects/f3-degradation-reporter-shim.md +105 -0
  222. package/upgrades/side-effects/f4-machine-locks-intent-journal-audit.md +117 -0
  223. package/upgrades/side-effects/f5-trust-elevation-source.md +258 -0
  224. package/upgrades/side-effects/f6-supervisor-handshake.md +234 -0
  225. package/upgrades/side-effects/f7-post-update-migrator-atomic-step.md +129 -0
  226. package/upgrades/side-effects/f8-remediator-skeleton.md +153 -0
  227. package/upgrades/side-effects/f8-rest-enforcement.md +72 -0
  228. package/upgrades/side-effects/file-viewer-jobs-instar-never-editable.md +41 -0
  229. package/upgrades/side-effects/frontmatter-interpolation-breakout-test.md +48 -0
  230. package/upgrades/side-effects/jobs-as-agentmd-phase-2.md +78 -0
  231. package/upgrades/side-effects/jobs-as-agentmd-phase-3.md +76 -0
  232. package/upgrades/side-effects/jobs-as-agentmd-phase-4-endpoints.md +62 -0
  233. package/upgrades/side-effects/jobs-as-agentmd-phase-5.md +67 -0
  234. package/upgrades/side-effects/jobs-as-agentmd-phase-6.md +53 -0
  235. package/upgrades/side-effects/jobs-endpoints-auth-verification.md +52 -0
  236. package/upgrades/side-effects/migration-guarantee-suite.md +61 -0
  237. package/upgrades/side-effects/migration-runtime-invariant-gate.md +59 -0
  238. package/upgrades/side-effects/migration-telemetry-invariant-8.md +68 -0
  239. package/upgrades/side-effects/npm-pack-templates-smoke.md +51 -0
  240. package/upgrades/side-effects/openclaw-import-before-prompt-build.md +84 -0
  241. package/upgrades/side-effects/openclaw-import-pre-compaction-flush.md +85 -0
  242. package/upgrades/side-effects/prompt-gate-no-prompt-cache.md +258 -0
  243. package/upgrades/side-effects/tier2-degradation-reporter-live-wire.md +146 -0
  244. package/upgrades/side-effects/w1-node-abi-mismatch-runbook.md +154 -0
  245. package/upgrades/side-effects/w2-supervisor-preflight-runbook.md +176 -0
  246. package/upgrades/side-effects/w3-messaging-delivery-failed-runbook.md +185 -0
  247. package/upgrades/side-effects/w4-db-corruption-runbook.md +114 -0
@@ -0,0 +1,212 @@
1
+ /**
2
+ * AgentMdReconcile — boot-time consistency check for the agentmd job tree.
3
+ *
4
+ * Per INSTAR-JOBS-AS-AGENTMD spec §Runtime "Load lifecycle (boot)":
5
+ *
6
+ * reconcile() runs at boot, surfaces orphan/shadow/missing on boot.
7
+ * Output goes to Dashboard Issues card.
8
+ *
9
+ * Categories surfaced:
10
+ *
11
+ * - ORPHAN-MANIFEST: A `<slug>.json` per-slug manifest exists but the
12
+ * `.md` it references does NOT. Scheduler cannot resolve the body;
13
+ * entry is excluded from jobs[] and surfaced as Issues-card row.
14
+ *
15
+ * - SHADOW-MD: A `<slug>.md` exists in either `instar/` or `user/` but
16
+ * has no per-slug manifest. The body is on disk but the scheduler
17
+ * has no schedule for it — Issues-card "Add to schedule (disabled)"
18
+ * or "Delete file" actions apply.
19
+ *
20
+ * - MISSING-FROM-JOBS-JSON: A legacy `jobs.json` entry has no
21
+ * corresponding per-slug manifest AND no `.md` under user/ or
22
+ * instar/. Mid-migration state; not yet copied over.
23
+ *
24
+ * - STAGED-NEW: A `.md.new` or `.json.new` left over from a crashed
25
+ * atomic save (see AgentMdAtomicSave). Issues-card "Apply" /
26
+ * "Discard" actions apply.
27
+ *
28
+ * - CASE-COLLISION: Two slug files differ only by case (NFC normalized)
29
+ * in the same directory. Both are excluded from jobs[] by the
30
+ * loader; this row surfaces them together.
31
+ *
32
+ * Pure function — reads the file system, returns a structured report.
33
+ * The caller (boot lifecycle in JobLoader; Phase 4 Dashboard read
34
+ * endpoint) decides how to present the rows.
35
+ */
36
+ import fs from 'node:fs';
37
+ import path from 'node:path';
38
+ /** Local scanner for `.new` staged files. Will be replaced with the
39
+ * shared `listStagedNewFiles()` export from `AgentMdAtomicSave.ts`
40
+ * once that PR merges (echo/two-rename-atomicity). */
41
+ function scanStagedFiles(jobsRoot) {
42
+ const found = [];
43
+ const walk = (dir) => {
44
+ if (!fs.existsSync(dir))
45
+ return;
46
+ let entries;
47
+ try {
48
+ entries = fs.readdirSync(dir, { withFileTypes: true });
49
+ }
50
+ catch {
51
+ return;
52
+ }
53
+ for (const e of entries) {
54
+ const p = path.join(dir, e.name);
55
+ if (e.isDirectory())
56
+ walk(p);
57
+ else if (e.isFile() && (p.endsWith('.md.new') || p.endsWith('.json.new'))) {
58
+ found.push(p);
59
+ }
60
+ }
61
+ };
62
+ walk(jobsRoot);
63
+ return found;
64
+ }
65
+ const EMPTY_BY_KIND = {
66
+ 'orphan-manifest': 0,
67
+ 'shadow-md': 0,
68
+ 'missing-from-jobs-json': 0,
69
+ 'staged-new': 0,
70
+ 'case-collision': 0,
71
+ };
72
+ export function reconcileAgentMdTree(opts) {
73
+ const { stateDir } = opts;
74
+ const jobsRoot = path.join(stateDir, 'jobs');
75
+ const scheduleDir = path.join(jobsRoot, 'schedule');
76
+ const instarDir = path.join(jobsRoot, 'instar');
77
+ const userDir = path.join(jobsRoot, 'user');
78
+ const jobsJsonPath = path.join(stateDir, 'jobs.json');
79
+ const findings = [];
80
+ const byKind = { ...EMPTY_BY_KIND };
81
+ // ── Index the per-slug manifests ─────────────────────────────────
82
+ const manifestSlugs = new Map();
83
+ if (fs.existsSync(scheduleDir)) {
84
+ for (const f of fs.readdirSync(scheduleDir)) {
85
+ if (!f.endsWith('.json'))
86
+ continue;
87
+ const slug = path.basename(f, '.json');
88
+ const p = path.join(scheduleDir, f);
89
+ let origin;
90
+ try {
91
+ const parsed = JSON.parse(fs.readFileSync(p, 'utf-8'));
92
+ origin = typeof parsed?.origin === 'string' ? parsed.origin : undefined;
93
+ }
94
+ catch {
95
+ // Surface as orphan + add to find later.
96
+ }
97
+ manifestSlugs.set(slug, { path: p, origin });
98
+ }
99
+ }
100
+ // ── Index the .md files under instar/ and user/ ──────────────────
101
+ const mdSlugs = new Map();
102
+ for (const [dir, ns] of [
103
+ [instarDir, 'instar'],
104
+ [userDir, 'user'],
105
+ ]) {
106
+ if (!fs.existsSync(dir))
107
+ continue;
108
+ for (const f of fs.readdirSync(dir)) {
109
+ if (!f.endsWith('.md') || f.startsWith('.'))
110
+ continue;
111
+ const slug = path.basename(f, '.md');
112
+ const p = path.join(dir, f);
113
+ mdSlugs.set(slug, { path: p, namespace: ns });
114
+ }
115
+ }
116
+ // ── Orphan manifests: manifest exists, no .md ────────────────────
117
+ for (const [slug, info] of manifestSlugs.entries()) {
118
+ if (!mdSlugs.has(slug)) {
119
+ findings.push({
120
+ kind: 'orphan-manifest',
121
+ slug,
122
+ filePath: info.path,
123
+ summary: `Manifest "${slug}.json" exists but no matching .md under ${info.origin === 'instar' ? 'instar/' : info.origin === 'user' ? 'user/' : 'instar/ or user/'}.`,
124
+ severity: 'error',
125
+ });
126
+ byKind['orphan-manifest']++;
127
+ }
128
+ }
129
+ // ── Shadow .md: .md exists, no manifest ───────────────────────────
130
+ for (const [slug, info] of mdSlugs.entries()) {
131
+ if (!manifestSlugs.has(slug)) {
132
+ findings.push({
133
+ kind: 'shadow-md',
134
+ slug,
135
+ filePath: info.path,
136
+ summary: `Body file "${slug}.md" exists under ${info.namespace}/ but no per-slug manifest at schedule/${slug}.json.`,
137
+ severity: 'warning',
138
+ });
139
+ byKind['shadow-md']++;
140
+ }
141
+ }
142
+ // ── Missing from jobs.json: legacy entry not yet copied ──────────
143
+ if (fs.existsSync(jobsJsonPath)) {
144
+ try {
145
+ const entries = JSON.parse(fs.readFileSync(jobsJsonPath, 'utf-8'));
146
+ if (Array.isArray(entries)) {
147
+ for (const e of entries) {
148
+ if (!e || typeof e !== 'object' || typeof e.slug !== 'string')
149
+ continue;
150
+ if (e.execute?.type !== 'prompt')
151
+ continue;
152
+ if (!manifestSlugs.has(e.slug) && !mdSlugs.has(e.slug)) {
153
+ findings.push({
154
+ kind: 'missing-from-jobs-json',
155
+ slug: e.slug,
156
+ summary: `Legacy jobs.json entry "${e.slug}" has no per-slug manifest and no body file. Migration may have partially run.`,
157
+ severity: 'warning',
158
+ });
159
+ byKind['missing-from-jobs-json']++;
160
+ }
161
+ }
162
+ }
163
+ }
164
+ catch {
165
+ // jobs.json malformed — separate concern, not surfaced here.
166
+ }
167
+ }
168
+ // ── Staged .new files from interrupted atomic save ───────────────
169
+ for (const staged of scanStagedFiles(jobsRoot)) {
170
+ findings.push({
171
+ kind: 'staged-new',
172
+ filePath: staged,
173
+ summary: `Staged file from interrupted save: ${path.relative(stateDir, staged)}. Operator can apply or discard via Dashboard.`,
174
+ severity: 'info',
175
+ });
176
+ byKind['staged-new']++;
177
+ }
178
+ // ── Case collisions: two .md or .json files differ only by case ──
179
+ detectCaseCollisions(instarDir, '.md', findings, byKind);
180
+ detectCaseCollisions(userDir, '.md', findings, byKind);
181
+ detectCaseCollisions(scheduleDir, '.json', findings, byKind);
182
+ return {
183
+ findings,
184
+ summary: { total: findings.length, byKind },
185
+ };
186
+ }
187
+ function detectCaseCollisions(dir, ext, findings, byKind) {
188
+ if (!fs.existsSync(dir))
189
+ return;
190
+ const seen = new Map();
191
+ for (const f of fs.readdirSync(dir)) {
192
+ if (!f.endsWith(ext) || f.startsWith('.'))
193
+ continue;
194
+ const slug = path.basename(f, ext);
195
+ const normalized = slug.normalize('NFC').toLowerCase();
196
+ if (!seen.has(normalized))
197
+ seen.set(normalized, []);
198
+ seen.get(normalized).push(path.join(dir, f));
199
+ }
200
+ for (const [, paths] of seen) {
201
+ if (paths.length > 1) {
202
+ findings.push({
203
+ kind: 'case-collision',
204
+ conflictingPaths: paths,
205
+ summary: `Case-only filename collision in ${path.basename(dir)}/: ${paths.map((p) => path.basename(p)).join(' vs ')}. Both excluded from jobs[]; manual resolution required.`,
206
+ severity: 'error',
207
+ });
208
+ byKind['case-collision']++;
209
+ }
210
+ }
211
+ }
212
+ //# sourceMappingURL=AgentMdReconcile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AgentMdReconcile.js","sourceRoot":"","sources":["../../src/scheduler/AgentMdReconcile.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * DisabledBodyDrift — detect whether an operator-disabled default has had
3
+ * its body change since the operator disabled it.
4
+ *
5
+ * Per INSTAR-JOBS-AS-AGENTMD spec §Dashboard UX:
6
+ * row per job: status dot, name + description, schedule, last run + bodyHash link,
7
+ * enabled toggle (records disabledAtBodyHash), namespace badge
8
+ *
9
+ * The manifest field `disabledAtBodyHash` is captured by the Dashboard
10
+ * when the operator flips the enabled toggle to false. It records the
11
+ * normalized SHA-256 of the body at disable-time. On every subsequent
12
+ * `instar update`, the body may change; `bodyDriftedSinceDisable(...)`
13
+ * returns true when the current body hash no longer matches what was
14
+ * captured. The Dashboard surfaces a "default has changed since you
15
+ * disabled it — consider reviewing" badge in response.
16
+ *
17
+ * Pure function — reads the manifest + the .md file. No state, no
18
+ * side-effects.
19
+ */
20
+ import { normalize } from './AgentMdLockFile.js';
21
+ export interface BodyDriftCheckOptions {
22
+ /** Agent state directory root (e.g., `<projectDir>/.instar/`). */
23
+ stateDir: string;
24
+ /** Job slug to check. */
25
+ slug: string;
26
+ }
27
+ export type BodyDriftStatus = {
28
+ kind: 'no-drift';
29
+ } | {
30
+ kind: 'drifted';
31
+ disabledAtBodyHash: string;
32
+ currentBodyHash: string;
33
+ } | {
34
+ kind: 'manifest-missing';
35
+ } | {
36
+ kind: 'body-missing';
37
+ expectedPath: string;
38
+ } | {
39
+ kind: 'not-disabled';
40
+ note: string;
41
+ } | {
42
+ kind: 'no-disable-record';
43
+ note: string;
44
+ };
45
+ export declare function bodyDriftedSinceDisable(opts: BodyDriftCheckOptions): BodyDriftStatus;
46
+ /**
47
+ * Convenience helper: list every slug whose disabled-state has drifted
48
+ * since the operator disabled it. Used by the Dashboard's status feed and
49
+ * by the drift digest.
50
+ */
51
+ export declare function listDriftedDisabledSlugs(stateDir: string): Array<{
52
+ slug: string;
53
+ status: BodyDriftStatus;
54
+ }>;
55
+ /**
56
+ * Stamp the disabledAtBodyHash field on a manifest. Used by the Dashboard
57
+ * "disable" action and by the future CLI `instar job disable <slug>`
58
+ * command. Idempotent: re-stamping with the same body produces the same
59
+ * hash. Re-disabling after a body change produces a fresh hash.
60
+ *
61
+ * Returns the captured hash or null if the body cannot be read.
62
+ */
63
+ export declare function stampDisabledAtBodyHash(stateDir: string, slug: string): string | null;
64
+ /**
65
+ * Clear the disabledAtBodyHash when an operator re-enables a job.
66
+ * Idempotent.
67
+ */
68
+ export declare function clearDisabledAtBodyHash(stateDir: string, slug: string): void;
69
+ export { normalize };
70
+ //# sourceMappingURL=DisabledBodyDrift.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DisabledBodyDrift.d.ts","sourceRoot":"","sources":["../../src/scheduler/DisabledBodyDrift.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAIH,OAAO,EAAY,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAE3D,MAAM,WAAW,qBAAqB;IACpC,kEAAkE;IAClE,QAAQ,EAAE,MAAM,CAAC;IACjB,yBAAyB;IACzB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,eAAe,GACvB;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,GACpB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,kBAAkB,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAA;CAAE,GACxE;IAAE,IAAI,EAAE,kBAAkB,CAAA;CAAE,GAC5B;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAC9C;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACtC;IAAE,IAAI,EAAE,mBAAmB,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEhD,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,qBAAqB,GAAG,eAAe,CAgDpF;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,eAAe,CAAA;CAAE,CAAC,CAa3G;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA6BrF;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAY5E;AAKD,OAAO,EAAE,SAAS,EAAE,CAAC"}
@@ -0,0 +1,149 @@
1
+ /**
2
+ * DisabledBodyDrift — detect whether an operator-disabled default has had
3
+ * its body change since the operator disabled it.
4
+ *
5
+ * Per INSTAR-JOBS-AS-AGENTMD spec §Dashboard UX:
6
+ * row per job: status dot, name + description, schedule, last run + bodyHash link,
7
+ * enabled toggle (records disabledAtBodyHash), namespace badge
8
+ *
9
+ * The manifest field `disabledAtBodyHash` is captured by the Dashboard
10
+ * when the operator flips the enabled toggle to false. It records the
11
+ * normalized SHA-256 of the body at disable-time. On every subsequent
12
+ * `instar update`, the body may change; `bodyDriftedSinceDisable(...)`
13
+ * returns true when the current body hash no longer matches what was
14
+ * captured. The Dashboard surfaces a "default has changed since you
15
+ * disabled it — consider reviewing" badge in response.
16
+ *
17
+ * Pure function — reads the manifest + the .md file. No state, no
18
+ * side-effects.
19
+ */
20
+ import fs from 'node:fs';
21
+ import path from 'node:path';
22
+ import { hashBody, normalize } from './AgentMdLockFile.js';
23
+ export function bodyDriftedSinceDisable(opts) {
24
+ const { stateDir, slug } = opts;
25
+ const manifestPath = path.join(stateDir, 'jobs', 'schedule', `${slug}.json`);
26
+ if (!fs.existsSync(manifestPath)) {
27
+ return { kind: 'manifest-missing' };
28
+ }
29
+ let manifest;
30
+ try {
31
+ manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));
32
+ }
33
+ catch {
34
+ return { kind: 'manifest-missing' };
35
+ }
36
+ if (manifest.enabled !== false) {
37
+ return { kind: 'not-disabled', note: `Slug "${slug}" is enabled; drift check applies only to operator-disabled defaults.` };
38
+ }
39
+ if (typeof manifest.disabledAtBodyHash !== 'string' || !manifest.disabledAtBodyHash.startsWith('sha256:')) {
40
+ return { kind: 'no-disable-record', note: `Slug "${slug}" is disabled but has no disabledAtBodyHash captured. Pre-spec disable, or manifest manually edited.` };
41
+ }
42
+ // Resolve the body file — try instar/ first (origin:instar) then user/.
43
+ const namespace = manifest.origin === 'instar' ? 'instar' : 'user';
44
+ const expectedPath = path.join(stateDir, 'jobs', namespace, `${slug}.md`);
45
+ if (!fs.existsSync(expectedPath)) {
46
+ return { kind: 'body-missing', expectedPath };
47
+ }
48
+ let bodyText;
49
+ try {
50
+ const raw = fs.readFileSync(expectedPath, 'utf-8');
51
+ const match = raw.match(/^---\n[\s\S]*?\n---\n([\s\S]*)$/);
52
+ bodyText = match ? match[1] : raw;
53
+ }
54
+ catch {
55
+ return { kind: 'body-missing', expectedPath };
56
+ }
57
+ const currentBodyHash = hashBody(bodyText);
58
+ if (currentBodyHash === manifest.disabledAtBodyHash) {
59
+ return { kind: 'no-drift' };
60
+ }
61
+ return {
62
+ kind: 'drifted',
63
+ disabledAtBodyHash: manifest.disabledAtBodyHash,
64
+ currentBodyHash,
65
+ };
66
+ }
67
+ /**
68
+ * Convenience helper: list every slug whose disabled-state has drifted
69
+ * since the operator disabled it. Used by the Dashboard's status feed and
70
+ * by the drift digest.
71
+ */
72
+ export function listDriftedDisabledSlugs(stateDir) {
73
+ const scheduleDir = path.join(stateDir, 'jobs', 'schedule');
74
+ if (!fs.existsSync(scheduleDir))
75
+ return [];
76
+ const results = [];
77
+ for (const f of fs.readdirSync(scheduleDir)) {
78
+ if (!f.endsWith('.json') || f.startsWith('.'))
79
+ continue;
80
+ const slug = path.basename(f, '.json');
81
+ const status = bodyDriftedSinceDisable({ stateDir, slug });
82
+ if (status.kind === 'drifted') {
83
+ results.push({ slug, status });
84
+ }
85
+ }
86
+ return results;
87
+ }
88
+ /**
89
+ * Stamp the disabledAtBodyHash field on a manifest. Used by the Dashboard
90
+ * "disable" action and by the future CLI `instar job disable <slug>`
91
+ * command. Idempotent: re-stamping with the same body produces the same
92
+ * hash. Re-disabling after a body change produces a fresh hash.
93
+ *
94
+ * Returns the captured hash or null if the body cannot be read.
95
+ */
96
+ export function stampDisabledAtBodyHash(stateDir, slug) {
97
+ const manifestPath = path.join(stateDir, 'jobs', 'schedule', `${slug}.json`);
98
+ if (!fs.existsSync(manifestPath))
99
+ return null;
100
+ let manifest;
101
+ try {
102
+ manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));
103
+ }
104
+ catch {
105
+ return null;
106
+ }
107
+ const namespace = manifest.origin === 'instar' ? 'instar' : 'user';
108
+ const bodyPath = path.join(stateDir, 'jobs', namespace, `${slug}.md`);
109
+ if (!fs.existsSync(bodyPath))
110
+ return null;
111
+ let bodyText;
112
+ try {
113
+ const raw = fs.readFileSync(bodyPath, 'utf-8');
114
+ const match = raw.match(/^---\n[\s\S]*?\n---\n([\s\S]*)$/);
115
+ bodyText = match ? match[1] : raw;
116
+ }
117
+ catch {
118
+ return null;
119
+ }
120
+ const hash = hashBody(bodyText);
121
+ manifest.disabledAtBodyHash = hash;
122
+ manifest.enabled = false;
123
+ fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + '\n', 'utf-8');
124
+ return hash;
125
+ }
126
+ /**
127
+ * Clear the disabledAtBodyHash when an operator re-enables a job.
128
+ * Idempotent.
129
+ */
130
+ export function clearDisabledAtBodyHash(stateDir, slug) {
131
+ const manifestPath = path.join(stateDir, 'jobs', 'schedule', `${slug}.json`);
132
+ if (!fs.existsSync(manifestPath))
133
+ return;
134
+ let manifest;
135
+ try {
136
+ manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));
137
+ }
138
+ catch {
139
+ return;
140
+ }
141
+ delete manifest.disabledAtBodyHash;
142
+ manifest.enabled = true;
143
+ fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + '\n', 'utf-8');
144
+ }
145
+ // Re-export the canonical normalize from AgentMdLockFile so callers can
146
+ // inspect what the hash is computed over without having to know which
147
+ // module owns it.
148
+ export { normalize };
149
+ //# sourceMappingURL=DisabledBodyDrift.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DisabledBodyDrift.js","sourceRoot":"","sources":["../../src/scheduler/DisabledBodyDrift.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * InstallBuiltinJobs — Phase 2 installer for instar-default jobs.
3
+ *
4
+ * Copies the shipped agentmd templates from the installed npm package into
5
+ * the agent's `.instar/jobs/instar/` directory and creates the corresponding
6
+ * per-slug manifest under `.instar/jobs/schedule/`. Idempotent. Safe to call
7
+ * on init and on every update.
8
+ *
9
+ * Sources (in this order; first existing wins):
10
+ * 1. <packageRoot>/dist/scaffold/templates/jobs/instar/ (npm-installed)
11
+ * 2. <packageRoot>/src/scaffold/templates/jobs/instar/ (in-tree dev)
12
+ *
13
+ * Targets:
14
+ * .instar/jobs/instar/<slug>.md
15
+ * .instar/jobs/schedule/<slug>.json
16
+ * .instar/jobs/instar.lock.json (copied from <packageRoot>/dist/jobs/)
17
+ * .instar/keys/instar-release-pub.pem (copied from <packageRoot>/dist/keys/)
18
+ *
19
+ * Per the Seamless Migration Guarantee (spec §Seamless Migration Guarantee):
20
+ *
21
+ * - This function NEVER touches `.instar/jobs/user/` (invariant 4).
22
+ * - This function NEVER deletes or overwrites a user-edited body
23
+ * (`.instar/jobs/instar/<slug>.md` is overwritten on update — that's
24
+ * the contract; users who edited a default should fork via Phase 4
25
+ * Dashboard "Unfork" before updating).
26
+ * - When a slug is no longer in the templates dir, its `.instar/jobs/instar/<slug>.md`
27
+ * is removed; the per-slug schedule manifest is moved to retired-defaults
28
+ * (Phase 4-Dashboard surface) and its `enabled` flipped to false.
29
+ *
30
+ * Spec: docs/specs/INSTAR-JOBS-AS-AGENTMD-SPEC.md §Concrete Paths + §PostUpdateMigrator.
31
+ */
32
+ export interface InstallBuiltinJobsOptions {
33
+ /** Agent state directory root (typically `<projectDir>/.instar`). */
34
+ agentStateDir: string;
35
+ /** Installed npm package root (typically `node_modules/instar` or the
36
+ * repo root in dev). The installer searches `dist/scaffold/...` first,
37
+ * then `src/scaffold/...` as a dev-mode fallback. */
38
+ packageRoot: string;
39
+ /** Agent's HTTP server port. Replaces the `PORT_SENTINEL` token (4042)
40
+ * baked into the shipped templates so the on-disk content matches what
41
+ * `getDefaultJobs()` produces today. */
42
+ port: number;
43
+ }
44
+ export interface InstallReport {
45
+ installed: string[];
46
+ retired: string[];
47
+ errors: Array<{
48
+ slug?: string;
49
+ reason: string;
50
+ }>;
51
+ }
52
+ export declare function installBuiltinJobs(opts: InstallBuiltinJobsOptions): InstallReport;
53
+ //# sourceMappingURL=InstallBuiltinJobs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InstallBuiltinJobs.d.ts","sourceRoot":"","sources":["../../src/scheduler/InstallBuiltinJobs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAOH,MAAM,WAAW,yBAAyB;IACxC,qEAAqE;IACrE,aAAa,EAAE,MAAM,CAAC;IACtB;;0DAEsD;IACtD,WAAW,EAAE,MAAM,CAAC;IACpB;;6CAEyC;IACzC,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAClD;AAID,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,yBAAyB,GAAG,aAAa,CAyKjF"}