instar 0.28.102 → 0.28.104

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 (255) 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 +109 -1
  48. package/dist/memory/NativeModuleHealer.d.ts.map +1 -1
  49. package/dist/memory/NativeModuleHealer.js +418 -2
  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/TokenLedger.d.ts.map +1 -1
  76. package/dist/monitoring/TokenLedger.js +11 -1
  77. package/dist/monitoring/TokenLedger.js.map +1 -1
  78. package/dist/monitoring/probes/LifelineProbe.d.ts +7 -0
  79. package/dist/monitoring/probes/LifelineProbe.d.ts.map +1 -1
  80. package/dist/monitoring/probes/LifelineProbe.js +7 -0
  81. package/dist/monitoring/probes/LifelineProbe.js.map +1 -1
  82. package/dist/monitoring/probes/__shared.d.ts +50 -0
  83. package/dist/monitoring/probes/__shared.d.ts.map +1 -0
  84. package/dist/monitoring/probes/__shared.js +51 -0
  85. package/dist/monitoring/probes/__shared.js.map +1 -0
  86. package/dist/remediation/IntentJournal.d.ts +64 -0
  87. package/dist/remediation/IntentJournal.d.ts.map +1 -0
  88. package/dist/remediation/IntentJournal.js +118 -0
  89. package/dist/remediation/IntentJournal.js.map +1 -0
  90. package/dist/remediation/MachineLock.d.ts +137 -0
  91. package/dist/remediation/MachineLock.d.ts.map +1 -0
  92. package/dist/remediation/MachineLock.js +314 -0
  93. package/dist/remediation/MachineLock.js.map +1 -0
  94. package/dist/remediation/PrimaryAggregatorLease.d.ts +205 -0
  95. package/dist/remediation/PrimaryAggregatorLease.d.ts.map +1 -0
  96. package/dist/remediation/PrimaryAggregatorLease.js +450 -0
  97. package/dist/remediation/PrimaryAggregatorLease.js.map +1 -0
  98. package/dist/remediation/RemediationContext.d.ts +63 -0
  99. package/dist/remediation/RemediationContext.d.ts.map +1 -0
  100. package/dist/remediation/RemediationContext.js +109 -0
  101. package/dist/remediation/RemediationContext.js.map +1 -0
  102. package/dist/remediation/RemediationKeyVault.d.ts +123 -0
  103. package/dist/remediation/RemediationKeyVault.d.ts.map +1 -0
  104. package/dist/remediation/RemediationKeyVault.js +564 -0
  105. package/dist/remediation/RemediationKeyVault.js.map +1 -0
  106. package/dist/remediation/Remediator.d.ts +288 -0
  107. package/dist/remediation/Remediator.d.ts.map +1 -0
  108. package/dist/remediation/Remediator.js +520 -0
  109. package/dist/remediation/Remediator.js.map +1 -0
  110. package/dist/remediation/RemediatorBootstrap.d.ts +141 -0
  111. package/dist/remediation/RemediatorBootstrap.d.ts.map +1 -0
  112. package/dist/remediation/RemediatorBootstrap.js +255 -0
  113. package/dist/remediation/RemediatorBootstrap.js.map +1 -0
  114. package/dist/remediation/TrustElevationSource.d.ts +153 -0
  115. package/dist/remediation/TrustElevationSource.d.ts.map +1 -0
  116. package/dist/remediation/TrustElevationSource.js +208 -0
  117. package/dist/remediation/TrustElevationSource.js.map +1 -0
  118. package/dist/remediation/audit/AuditProjection.d.ts +37 -0
  119. package/dist/remediation/audit/AuditProjection.d.ts.map +1 -0
  120. package/dist/remediation/audit/AuditProjection.js +118 -0
  121. package/dist/remediation/audit/AuditProjection.js.map +1 -0
  122. package/dist/remediation/audit/AuditWriter.d.ts +79 -0
  123. package/dist/remediation/audit/AuditWriter.d.ts.map +1 -0
  124. package/dist/remediation/audit/AuditWriter.js +132 -0
  125. package/dist/remediation/audit/AuditWriter.js.map +1 -0
  126. package/dist/remediation/channels/CliApprovalChannel.d.ts +37 -0
  127. package/dist/remediation/channels/CliApprovalChannel.d.ts.map +1 -0
  128. package/dist/remediation/channels/CliApprovalChannel.js +45 -0
  129. package/dist/remediation/channels/CliApprovalChannel.js.map +1 -0
  130. package/dist/remediation/channels/TelegramApprovalChannel.d.ts +37 -0
  131. package/dist/remediation/channels/TelegramApprovalChannel.d.ts.map +1 -0
  132. package/dist/remediation/channels/TelegramApprovalChannel.js +45 -0
  133. package/dist/remediation/channels/TelegramApprovalChannel.js.map +1 -0
  134. package/dist/remediation/runbooks/db-corruption.d.ts +86 -0
  135. package/dist/remediation/runbooks/db-corruption.d.ts.map +1 -0
  136. package/dist/remediation/runbooks/db-corruption.js +190 -0
  137. package/dist/remediation/runbooks/db-corruption.js.map +1 -0
  138. package/dist/remediation/runbooks/messaging-delivery-failed.d.ts +108 -0
  139. package/dist/remediation/runbooks/messaging-delivery-failed.d.ts.map +1 -0
  140. package/dist/remediation/runbooks/messaging-delivery-failed.js +172 -0
  141. package/dist/remediation/runbooks/messaging-delivery-failed.js.map +1 -0
  142. package/dist/remediation/runbooks/node-abi-mismatch.d.ts +70 -0
  143. package/dist/remediation/runbooks/node-abi-mismatch.d.ts.map +1 -0
  144. package/dist/remediation/runbooks/node-abi-mismatch.js +216 -0
  145. package/dist/remediation/runbooks/node-abi-mismatch.js.map +1 -0
  146. package/dist/remediation/runbooks/supervisor-preflight.d.ts +114 -0
  147. package/dist/remediation/runbooks/supervisor-preflight.d.ts.map +1 -0
  148. package/dist/remediation/runbooks/supervisor-preflight.js +299 -0
  149. package/dist/remediation/runbooks/supervisor-preflight.js.map +1 -0
  150. package/dist/scheduler/AgentMdAtomicSave.d.ts +85 -0
  151. package/dist/scheduler/AgentMdAtomicSave.d.ts.map +1 -0
  152. package/dist/scheduler/AgentMdAtomicSave.js +169 -0
  153. package/dist/scheduler/AgentMdAtomicSave.js.map +1 -0
  154. package/dist/scheduler/AgentMdReconcile.d.ts +62 -0
  155. package/dist/scheduler/AgentMdReconcile.d.ts.map +1 -0
  156. package/dist/scheduler/AgentMdReconcile.js +212 -0
  157. package/dist/scheduler/AgentMdReconcile.js.map +1 -0
  158. package/dist/scheduler/DisabledBodyDrift.d.ts +70 -0
  159. package/dist/scheduler/DisabledBodyDrift.d.ts.map +1 -0
  160. package/dist/scheduler/DisabledBodyDrift.js +149 -0
  161. package/dist/scheduler/DisabledBodyDrift.js.map +1 -0
  162. package/dist/scheduler/InstallBuiltinJobs.d.ts +53 -0
  163. package/dist/scheduler/InstallBuiltinJobs.d.ts.map +1 -0
  164. package/dist/scheduler/InstallBuiltinJobs.js +212 -0
  165. package/dist/scheduler/InstallBuiltinJobs.js.map +1 -0
  166. package/dist/scheduler/JobLoader.d.ts.map +1 -1
  167. package/dist/scheduler/JobLoader.js +48 -0
  168. package/dist/scheduler/JobLoader.js.map +1 -1
  169. package/dist/scheduler/MigrationInvariants.d.ts +62 -0
  170. package/dist/scheduler/MigrationInvariants.d.ts.map +1 -0
  171. package/dist/scheduler/MigrationInvariants.js +215 -0
  172. package/dist/scheduler/MigrationInvariants.js.map +1 -0
  173. package/dist/scheduler/MigrationLedger.d.ts +84 -0
  174. package/dist/scheduler/MigrationLedger.d.ts.map +1 -0
  175. package/dist/scheduler/MigrationLedger.js +114 -0
  176. package/dist/scheduler/MigrationLedger.js.map +1 -0
  177. package/dist/server/AgentServer.d.ts.map +1 -1
  178. package/dist/server/AgentServer.js +8 -0
  179. package/dist/server/AgentServer.js.map +1 -1
  180. package/dist/server/fileRoutes.d.ts.map +1 -1
  181. package/dist/server/fileRoutes.js +7 -0
  182. package/dist/server/fileRoutes.js.map +1 -1
  183. package/dist/server/routes.d.ts.map +1 -1
  184. package/dist/server/routes.js +141 -0
  185. package/dist/server/routes.js.map +1 -1
  186. package/package.json +3 -2
  187. package/scripts/classify-default-drift.mjs +238 -0
  188. package/scripts/eli16-overview-check.mjs +85 -0
  189. package/scripts/instar-dev-precommit.js +60 -1
  190. package/scripts/lint-degradation-emit-sites.js +116 -0
  191. package/scripts/lint-no-direct-destructive.js +12 -0
  192. package/scripts/protect-migration-guarantee.js +61 -0
  193. package/scripts/regen-default-job-templates.mjs +111 -0
  194. package/scripts/verify-runbook-pr-signature.js +366 -0
  195. package/src/data/builtin-manifest.json +94 -94
  196. package/src/scaffold/bootstrap.ts +138 -0
  197. package/src/scaffold/keys/instar-release-pub.pem +3 -0
  198. package/src/scaffold/templates/jobs/instar/.gitkeep +0 -0
  199. package/src/scaffold/templates/jobs/instar/commitment-detection.md +28 -0
  200. package/src/scaffold/templates/jobs/instar/evolution-overdue-check.md +28 -0
  201. package/src/scaffold/templates/jobs/instar/evolution-proposal-evaluate.md +30 -0
  202. package/src/scaffold/templates/jobs/instar/evolution-proposal-implement.md +25 -0
  203. package/src/scaffold/templates/jobs/instar/health-check.md +14 -0
  204. package/src/scaffold/templates/jobs/instar/identity-review.md +42 -0
  205. package/src/scaffold/templates/jobs/instar/insight-harvest.md +31 -0
  206. package/src/scaffold/templates/jobs/instar/overseer-development.md +23 -0
  207. package/src/scaffold/templates/jobs/instar/overseer-guardian.md +28 -0
  208. package/src/scaffold/templates/jobs/instar/overseer-infrastructure.md +26 -0
  209. package/src/scaffold/templates/jobs/instar/overseer-learning.md +28 -0
  210. package/src/scaffold/templates/jobs/instar/overseer-maintenance.md +27 -0
  211. package/src/scaffold/templates/jobs/instar/reflection-trigger.md +40 -0
  212. package/src/scaffold/templates/jobs/instar/relationship-maintenance.md +16 -0
  213. package/src/scaffold/templates.ts +1616 -0
  214. package/upgrades/0.28.102.md +6 -7
  215. package/upgrades/0.28.103.md +471 -0
  216. package/upgrades/0.28.104.md +77 -0
  217. package/upgrades/side-effects/a47-primary-aggregator-lease.md +82 -0
  218. package/upgrades/side-effects/agentmd-atomic-save.md +66 -0
  219. package/upgrades/side-effects/agentmd-loader-200jobs-perf-benchmark.md +50 -0
  220. package/upgrades/side-effects/agentmd-reconcile-boot-lifecycle.md +66 -0
  221. package/upgrades/side-effects/api-safety-guard.md +80 -0
  222. package/upgrades/side-effects/c1-runbook-pr-gate.md +83 -0
  223. package/upgrades/side-effects/disabled-body-drift-detection.md +59 -0
  224. package/upgrades/side-effects/drift-classifier-release-time.md +71 -0
  225. package/upgrades/side-effects/eli16-overview-required-gate.md +77 -0
  226. package/upgrades/side-effects/f1-remediation-key-vault.md +195 -0
  227. package/upgrades/side-effects/f2-redactor-errorcode-extractor.md +130 -0
  228. package/upgrades/side-effects/f3-degradation-reporter-shim.md +105 -0
  229. package/upgrades/side-effects/f4-machine-locks-intent-journal-audit.md +117 -0
  230. package/upgrades/side-effects/f5-trust-elevation-source.md +258 -0
  231. package/upgrades/side-effects/f6-supervisor-handshake.md +234 -0
  232. package/upgrades/side-effects/f7-post-update-migrator-atomic-step.md +129 -0
  233. package/upgrades/side-effects/f8-remediator-skeleton.md +153 -0
  234. package/upgrades/side-effects/f8-rest-enforcement.md +72 -0
  235. package/upgrades/side-effects/file-viewer-jobs-instar-never-editable.md +41 -0
  236. package/upgrades/side-effects/frontmatter-interpolation-breakout-test.md +48 -0
  237. package/upgrades/side-effects/jobs-as-agentmd-phase-2.md +78 -0
  238. package/upgrades/side-effects/jobs-as-agentmd-phase-3.md +76 -0
  239. package/upgrades/side-effects/jobs-as-agentmd-phase-4-endpoints.md +62 -0
  240. package/upgrades/side-effects/jobs-as-agentmd-phase-5.md +67 -0
  241. package/upgrades/side-effects/jobs-as-agentmd-phase-6.md +53 -0
  242. package/upgrades/side-effects/jobs-endpoints-auth-verification.md +52 -0
  243. package/upgrades/side-effects/migration-guarantee-suite.md +61 -0
  244. package/upgrades/side-effects/migration-runtime-invariant-gate.md +59 -0
  245. package/upgrades/side-effects/migration-telemetry-invariant-8.md +68 -0
  246. package/upgrades/side-effects/npm-pack-templates-smoke.md +51 -0
  247. package/upgrades/side-effects/openclaw-import-before-prompt-build.md +84 -0
  248. package/upgrades/side-effects/openclaw-import-pre-compaction-flush.md +85 -0
  249. package/upgrades/side-effects/prompt-gate-no-prompt-cache.md +258 -0
  250. package/upgrades/side-effects/tier2-degradation-reporter-live-wire.md +146 -0
  251. package/upgrades/side-effects/token-ledger-native-heal.md +136 -0
  252. package/upgrades/side-effects/w1-node-abi-mismatch-runbook.md +154 -0
  253. package/upgrades/side-effects/w2-supervisor-preflight-runbook.md +176 -0
  254. package/upgrades/side-effects/w3-messaging-delivery-failed-runbook.md +185 -0
  255. package/upgrades/side-effects/w4-db-corruption-runbook.md +114 -0
@@ -1084,6 +1084,25 @@ export function createRoutes(ctx) {
1084
1084
  // Compaction-resume trigger #3 — called by .instar/hooks/instar/compaction-recovery.sh
1085
1085
  // immediately after a compaction event, independent of HookEventReceiver and Watchdog.
1086
1086
  // This is the most reliable path: the hook only runs when compaction actually happened.
1087
+ // Pre-prompt memory recall (OpenClaw import T2.2). Invoked by a Claude Code
1088
+ // UserPromptSubmit hook to inject bounded memory context before each reply.
1089
+ // Synchronous from the caller's perspective; bounded by recallTimeoutMs in
1090
+ // PromptBuildRecallConfig.
1091
+ router.post('/internal/prompt-recall', async (req, res) => {
1092
+ const userMessage = (req.body?.userMessage ?? '').toString();
1093
+ const sessionId = req.body?.sessionId ? String(req.body.sessionId) : undefined;
1094
+ if (!userMessage) {
1095
+ res.status(400).json({ error: 'userMessage required' });
1096
+ return;
1097
+ }
1098
+ const recall = globalThis.__instarPromptBuildRecall;
1099
+ if (!recall) {
1100
+ res.json({ contextText: '', source: 'no-recall', elapsedMs: 0, resultsCount: 0, cacheKey: '' });
1101
+ return;
1102
+ }
1103
+ const result = recall.recall({ userMessage, sessionId });
1104
+ res.json(result);
1105
+ });
1087
1106
  router.post('/internal/compaction-resume', async (req, res) => {
1088
1107
  const sessionName = (req.body?.sessionName || req.body?.tmuxSession || '').toString();
1089
1108
  if (!sessionName) {
@@ -3896,6 +3915,128 @@ export function createRoutes(ctx) {
3896
3915
  jobs: jobReports,
3897
3916
  });
3898
3917
  });
3918
+ /**
3919
+ * GET /jobs/migration-status
3920
+ * Phase 4 — surface the jobs-as-agentmd migration state so the Dashboard
3921
+ * can render the "Confirm migration complete" / "Roll back" buttons.
3922
+ *
3923
+ * Returns:
3924
+ * - hasLegacyJobsJson: boolean (whether .instar/jobs.json exists)
3925
+ * - hasMigrationComplete: boolean
3926
+ * - hasMigrationAbandoned: boolean
3927
+ * - canConfirm: boolean (legacy + schedule/ exist, no marker)
3928
+ * - canAbandon: boolean (schedule/ exists, no completion marker)
3929
+ * - scheduleEntryCount: number
3930
+ */
3931
+ /**
3932
+ * GET /jobs/reconcile
3933
+ *
3934
+ * Boot-time consistency check for the agentmd job tree. Surfaces
3935
+ * orphan manifests, shadow .md files, missing-from-jobs.json entries,
3936
+ * staged .new files from interrupted saves, and case-collisions per
3937
+ * INSTAR-JOBS-AS-AGENTMD spec §Runtime "Load lifecycle (boot)".
3938
+ *
3939
+ * Dashboard Issues-card consumes the returned `findings` array.
3940
+ */
3941
+ router.get('/jobs/reconcile', async (_req, res) => {
3942
+ try {
3943
+ const stateDir = ctx.config.stateDir;
3944
+ if (!stateDir) {
3945
+ res.status(503).json({ error: 'state dir not configured' });
3946
+ return;
3947
+ }
3948
+ const { reconcileAgentMdTree } = await import('../scheduler/AgentMdReconcile.js');
3949
+ const report = reconcileAgentMdTree({ stateDir });
3950
+ res.json(report);
3951
+ }
3952
+ catch (err) {
3953
+ res.status(500).json({ error: err instanceof Error ? err.message : String(err) });
3954
+ }
3955
+ });
3956
+ router.get('/jobs/migration-status', (_req, res) => {
3957
+ try {
3958
+ const stateDir = ctx.config.stateDir;
3959
+ if (!stateDir) {
3960
+ res.status(503).json({ error: 'state dir not configured' });
3961
+ return;
3962
+ }
3963
+ const jobsJson = path.join(stateDir, 'jobs.json');
3964
+ const jobsRoot = path.join(stateDir, 'jobs');
3965
+ const scheduleDir = path.join(jobsRoot, 'schedule');
3966
+ const completed = path.join(jobsRoot, '.migration-complete.json');
3967
+ const abandoned = path.join(jobsRoot, '.migration-abandoned.json');
3968
+ const hasLegacyJobsJson = fs.existsSync(jobsJson);
3969
+ const hasMigrationComplete = fs.existsSync(completed);
3970
+ const hasMigrationAbandoned = fs.existsSync(abandoned);
3971
+ let scheduleEntryCount = 0;
3972
+ if (fs.existsSync(scheduleDir)) {
3973
+ scheduleEntryCount = fs.readdirSync(scheduleDir).filter((f) => f.endsWith('.json')).length;
3974
+ }
3975
+ res.json({
3976
+ hasLegacyJobsJson,
3977
+ hasMigrationComplete,
3978
+ hasMigrationAbandoned,
3979
+ canConfirm: hasLegacyJobsJson && scheduleEntryCount > 0 && !hasMigrationComplete && !hasMigrationAbandoned,
3980
+ canAbandon: scheduleEntryCount > 0 && !hasMigrationComplete && !hasMigrationAbandoned,
3981
+ scheduleEntryCount,
3982
+ });
3983
+ }
3984
+ catch (err) {
3985
+ res.status(500).json({ error: err instanceof Error ? err.message : String(err) });
3986
+ }
3987
+ });
3988
+ /**
3989
+ * POST /jobs/migration-confirm
3990
+ * Phase 4 — operator confirms migration is complete. Writes
3991
+ * .instar/jobs/.migration-complete.json which the release-cut gate
3992
+ * consumes to allow jobs.json deletion.
3993
+ *
3994
+ * Idempotent — re-confirming is a no-op.
3995
+ */
3996
+ router.post('/jobs/migration-confirm', (_req, res) => {
3997
+ try {
3998
+ const stateDir = ctx.config.stateDir;
3999
+ if (!stateDir) {
4000
+ res.status(503).json({ error: 'state dir not configured' });
4001
+ return;
4002
+ }
4003
+ const jobsRoot = path.join(stateDir, 'jobs');
4004
+ const completed = path.join(jobsRoot, '.migration-complete.json');
4005
+ const abandoned = path.join(jobsRoot, '.migration-abandoned.json');
4006
+ if (fs.existsSync(abandoned)) {
4007
+ res.status(409).json({ error: 'Migration has been abandoned; cannot confirm. Run `instar job migrate` first.' });
4008
+ return;
4009
+ }
4010
+ fs.mkdirSync(jobsRoot, { recursive: true });
4011
+ fs.writeFileSync(completed, JSON.stringify({ confirmedAt: new Date().toISOString(), confirmedBy: 'dashboard' }, null, 2), 'utf-8');
4012
+ res.json({ ok: true, marker: completed });
4013
+ }
4014
+ catch (err) {
4015
+ res.status(500).json({ error: err instanceof Error ? err.message : String(err) });
4016
+ }
4017
+ });
4018
+ /**
4019
+ * POST /jobs/migration-abandon
4020
+ * Phase 4 — operator rolls back migration. Invokes
4021
+ * `jobsMigrate({ abandon: true })` to remove `.instar/jobs/schedule/`,
4022
+ * write `.migration-abandoned.json`, and leave `jobs.json` intact.
4023
+ */
4024
+ router.post('/jobs/migration-abandon', async (_req, res) => {
4025
+ try {
4026
+ const stateDir = ctx.config.stateDir;
4027
+ if (!stateDir) {
4028
+ res.status(503).json({ error: 'state dir not configured' });
4029
+ return;
4030
+ }
4031
+ const { jobsMigrate } = await import('../commands/jobMigrate.js');
4032
+ const packageRoot = path.resolve(__dirname, '..', '..');
4033
+ const outcome = jobsMigrate({ agentStateDir: stateDir, packageRoot, abandon: true });
4034
+ res.json(outcome);
4035
+ }
4036
+ catch (err) {
4037
+ res.status(500).json({ error: err instanceof Error ? err.message : String(err) });
4038
+ }
4039
+ });
3899
4040
  router.post('/jobs/:slug/trigger', async (req, res) => {
3900
4041
  if (!JOB_SLUG_RE.test(req.params.slug)) {
3901
4042
  res.status(400).json({ error: 'Invalid job slug' });