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
@@ -27,15 +27,60 @@ import { TreeGenerator } from '../knowledge/TreeGenerator.js';
27
27
  import { HTTP_HOOK_TEMPLATES, buildHttpHookSettings } from '../data/http-hook-templates.js';
28
28
  import { getMigrationDefaults, applyDefaults } from '../config/ConfigDefaults.js';
29
29
  import { installBuiltinSkills } from '../commands/init.js';
30
+ import { installBuiltinJobs } from '../scheduler/InstallBuiltinJobs.js';
31
+ import { jobsMigrate } from '../commands/jobMigrate.js';
32
+ import { snapshotUserNamespace, verifyMigrationInvariants } from '../scheduler/MigrationInvariants.js';
33
+ import { appendMigrationEvent, normalizePerEntryAction } from '../scheduler/MigrationLedger.js';
34
+ import { randomUUID } from 'node:crypto';
30
35
  import { ELIGIBILITY_SCHEMA_SQL, ELIGIBILITY_SCHEMA_SQL_SHA256, PUSH_GATE_SH, PUSH_GATE_SH_SHA256, INSTAR_PR_GATE_WORKFLOW_YML, INSTAR_PR_GATE_WORKFLOW_YML_SHA256, PR_GATE_SETUP_MD, PR_GATE_SETUP_MD_SHA256, } from '../data/pr-gate-artifacts.js';
31
36
  import { SafeFsExecutor } from './SafeFsExecutor.js';
32
37
  import { DegradationReporter } from '../monitoring/DegradationReporter.js';
38
+ import { MigratorStepEngine, } from './MigratorStepEngine.js';
33
39
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
34
40
  export class PostUpdateMigrator {
35
41
  config;
42
+ /**
43
+ * F-7 atomic-step engine. Lazily constructed on first access via
44
+ * `getStepEngine()` so existing callers that never touch atomic steps
45
+ * pay zero cost. See `src/core/MigratorStepEngine.ts` for the primitive
46
+ * docs; see `docs/specs/SELF-HEALING-REMEDIATOR-V2-SPEC.md` §A35/§A50
47
+ * for the spec.
48
+ */
49
+ stepEngine;
36
50
  constructor(config) {
37
51
  this.config = config;
38
52
  }
53
+ /**
54
+ * F-7 atomic-step primitive: register a step that will run once on
55
+ * the release boundary where `step.version <= toVersion`. Idempotent
56
+ * across runs — the engine records every step's outcome in
57
+ * `<stateDir>/migrator-steps-completed.json` keyed by
58
+ * `<version>:<step-name>`.
59
+ *
60
+ * Steps are atomic and self-contained: a failure in one step does not
61
+ * roll back prior steps and does not block subsequent steps.
62
+ *
63
+ * See `docs/specs/SELF-HEALING-REMEDIATOR-V2-SPEC.md` §A35 + §A50.
64
+ */
65
+ registerStep(step) {
66
+ this.getStepEngine().registerStep(step);
67
+ }
68
+ /**
69
+ * F-7 atomic-step primitive: execute every pending step. Pending =
70
+ * step.version <= toVersion AND no ledger entry recorded yet.
71
+ *
72
+ * Steps run in registration order. Failures are recorded (never
73
+ * thrown) and do not stop subsequent steps.
74
+ */
75
+ async runPendingSteps(fromVersion, toVersion) {
76
+ return this.getStepEngine().runPendingSteps(fromVersion, toVersion);
77
+ }
78
+ getStepEngine() {
79
+ if (!this.stepEngine) {
80
+ this.stepEngine = new MigratorStepEngine(this.config.stateDir);
81
+ }
82
+ return this.stepEngine;
83
+ }
39
84
  /**
40
85
  * Run all post-update migrations. Safe to call multiple times —
41
86
  * each migration is idempotent.
@@ -55,6 +100,8 @@ export class PostUpdateMigrator {
55
100
  this.migrateBackupManifest(result);
56
101
  this.migrateGitignore(result);
57
102
  this.migrateBuiltinSkills(result);
103
+ this.migrateBuiltinJobs(result);
104
+ this.autoMigrateLegacyJobsJson(result);
58
105
  this.migrateSkillPortHardcoding(result);
59
106
  this.migrateSelfKnowledgeTree(result);
60
107
  this.migrateSoulMd(result);
@@ -235,6 +282,210 @@ export class PostUpdateMigrator {
235
282
  result.errors.push(`built-in skills: ${err}`);
236
283
  }
237
284
  }
285
+ /**
286
+ * Phase 2 — install/refresh built-in agentmd jobs. Copies the shipped
287
+ * markdown templates into `.instar/jobs/instar/` and writes their
288
+ * per-slug manifests. Honors operator-disabled state (preserves
289
+ * `enabled: false` + `disabledAtBodyHash` across updates). Retires
290
+ * jobs that are no longer shipped.
291
+ *
292
+ * The `.instar/jobs/user/` namespace is structurally untouched (Seamless
293
+ * Migration Guarantee invariant 4).
294
+ */
295
+ migrateBuiltinJobs(result) {
296
+ try {
297
+ // The package root is two levels up from this compiled module (dist/core/),
298
+ // which puts us at the installed npm package root in production or the
299
+ // repo root in dev.
300
+ const packageRoot = path.resolve(__dirname, '..', '..');
301
+ const report = installBuiltinJobs({
302
+ agentStateDir: this.config.stateDir,
303
+ packageRoot,
304
+ port: this.config.port,
305
+ });
306
+ if (report.installed.length > 0) {
307
+ result.upgraded.push(`built-in agentmd jobs: ${report.installed.length} installed/refreshed`);
308
+ }
309
+ else if (report.errors.length === 0) {
310
+ result.skipped.push('built-in agentmd jobs: nothing to install');
311
+ }
312
+ for (const slug of report.retired) {
313
+ result.upgraded.push(`built-in agentmd jobs: retired "${slug}"`);
314
+ }
315
+ for (const e of report.errors) {
316
+ result.errors.push(`built-in agentmd jobs${e.slug ? ` [${e.slug}]` : ''}: ${e.reason}`);
317
+ }
318
+ }
319
+ catch (err) {
320
+ result.errors.push(`built-in agentmd jobs: ${err instanceof Error ? err.message : String(err)}`);
321
+ }
322
+ }
323
+ /**
324
+ * Phase 5 — auto-run `instar jobs migrate` for pre-spec agents on update.
325
+ *
326
+ * Behavior:
327
+ * - SKIP entirely if `.instar/jobs/.migration-complete.json` exists
328
+ * (operator already confirmed completion via Dashboard).
329
+ * - SKIP entirely if `.instar/jobs/.migration-abandoned.json` exists
330
+ * (operator explicitly chose to roll back).
331
+ * - SKIP if `.instar/jobs.json` is absent (nothing to migrate).
332
+ * - Otherwise, invoke `jobsMigrate({ defaultAction: 'fork' })` —
333
+ * fork policy preserves the operator's customized body in user/
334
+ * namespace, never silently drops content. This is the
335
+ * spec-mandated default for the auto-run path.
336
+ * - Emit a Dashboard banner event via the migration result so the
337
+ * operator sees "migration ran on update — confirm in Dashboard."
338
+ *
339
+ * Seamless Migration Guarantee invariants enforced at this layer
340
+ * (PR #180 §Seamless Migration Guarantee):
341
+ * #6 in-flight protection — JobScheduler.activeRuns() check is
342
+ * currently a defensive no-op until Phase 4 wires the scheduler
343
+ * back-reference; the migration runs at update time, before the
344
+ * new scheduler instance comes up, so by construction nothing is
345
+ * in flight.
346
+ * #7 transactional safety on interrupt — `jobsMigrate` is structurally
347
+ * safe (backup-first, idempotent, rollback via --abandon).
348
+ * #8 telemetry — outcome is appended to result.upgraded/errors.
349
+ */
350
+ autoMigrateLegacyJobsJson(result) {
351
+ const runId = randomUUID();
352
+ const startedAt = new Date().toISOString();
353
+ try {
354
+ const stateDir = this.config.stateDir;
355
+ const jobsJsonPath = path.join(stateDir, 'jobs.json');
356
+ const jobsRoot = path.join(stateDir, 'jobs');
357
+ const completedMarker = path.join(jobsRoot, '.migration-complete.json');
358
+ const abandonedMarker = path.join(jobsRoot, '.migration-abandoned.json');
359
+ if (!fs.existsSync(jobsJsonPath)) {
360
+ return; // nothing to migrate
361
+ }
362
+ if (fs.existsSync(completedMarker)) {
363
+ result.skipped.push('legacy jobs.json migration: already complete (operator-confirmed)');
364
+ return;
365
+ }
366
+ if (fs.existsSync(abandonedMarker)) {
367
+ result.skipped.push('legacy jobs.json migration: explicitly abandoned by operator');
368
+ return;
369
+ }
370
+ // Snapshot pre-migration state so the runtime invariant gate has
371
+ // ground truth to compare against. Per spec §Gate wiring:
372
+ // "Before performing any destructive write, the migrator re-verifies
373
+ // invariants 1, 2, 4, and 6 against the staged state. Failure aborts
374
+ // to fail-closed (invariant 9)."
375
+ let preMigrationJobs = [];
376
+ try {
377
+ preMigrationJobs = JSON.parse(fs.readFileSync(jobsJsonPath, 'utf-8'));
378
+ if (!Array.isArray(preMigrationJobs))
379
+ preMigrationJobs = [];
380
+ }
381
+ catch {
382
+ preMigrationJobs = [];
383
+ }
384
+ const preMigrationUserSnapshot = snapshotUserNamespace(stateDir);
385
+ const packageRoot = path.resolve(__dirname, '..', '..');
386
+ const instarVersion = this.readBundledInstarVersion(packageRoot);
387
+ const outcome = jobsMigrate({
388
+ agentStateDir: stateDir,
389
+ packageRoot,
390
+ defaultAction: 'fork',
391
+ });
392
+ if (outcome.status === 'completed') {
393
+ // Runtime invariant gate. Spec §Seamless Migration Guarantee #1, #2, #4.
394
+ // Invariant 6 (in-flight) is structurally satisfied at update-apply
395
+ // time because no jobs run mid-update.
396
+ const verification = verifyMigrationInvariants({
397
+ agentStateDir: stateDir,
398
+ preMigrationJobs,
399
+ preMigrationUserSnapshot,
400
+ });
401
+ if (!verification.ok) {
402
+ // Fail-closed (invariant 9): roll back via abandon.
403
+ try {
404
+ jobsMigrate({ agentStateDir: stateDir, packageRoot, abandon: true });
405
+ }
406
+ catch (rollbackErr) {
407
+ result.errors.push(`legacy jobs.json migration: invariant verification failed AND rollback errored — ` +
408
+ `${rollbackErr instanceof Error ? rollbackErr.message : String(rollbackErr)}`);
409
+ }
410
+ result.errors.push(`legacy jobs.json migration: ${verification.summary} — rolled back to pre-migration state`);
411
+ return;
412
+ }
413
+ const migratedCount = outcome.perEntry.filter((e) => e.action === 'migrated-instar').length;
414
+ const forkedCount = outcome.perEntry.filter((e) => e.action === 'forked-user' || e.action === 'kept-user').length;
415
+ const renamedCount = outcome.perEntry.filter((e) => e.action === 'renamed-user').length;
416
+ result.upgraded.push(`legacy jobs.json migration: auto-ran on update — ${migratedCount} migrated to instar, ${forkedCount} preserved in user namespace, ${renamedCount} renamed. Invariants verified. Confirm via Dashboard to allow jobs.json removal.`);
417
+ if (outcome.backupPath) {
418
+ result.upgraded.push(`legacy jobs.json migration: backup at ${path.basename(outcome.backupPath)}`);
419
+ }
420
+ // Spec invariant 8: telemetry write is the LAST action of a
421
+ // successful migration. Append the migration.completed event.
422
+ this.appendMigrationTelemetry({
423
+ kind: 'migration.completed',
424
+ runId,
425
+ startedAt,
426
+ completedAt: new Date().toISOString(),
427
+ trigger: 'post-update',
428
+ perEntry: outcome.perEntry.map((e) => ({
429
+ slug: e.slug,
430
+ action: normalizePerEntryAction(e.action),
431
+ reason: e.reason,
432
+ })),
433
+ backupPath: outcome.backupPath,
434
+ instarVersion,
435
+ });
436
+ }
437
+ else if (outcome.status === 'aborted') {
438
+ result.errors.push(`legacy jobs.json migration: aborted — ${outcome.errors.join('; ')}`);
439
+ this.appendMigrationTelemetry({
440
+ kind: 'migration.aborted',
441
+ runId,
442
+ startedAt,
443
+ completedAt: new Date().toISOString(),
444
+ trigger: 'post-update',
445
+ perEntry: outcome.perEntry.map((e) => ({
446
+ slug: e.slug,
447
+ action: normalizePerEntryAction(e.action),
448
+ reason: e.reason,
449
+ })),
450
+ abortReason: outcome.errors.join('; '),
451
+ instarVersion,
452
+ });
453
+ }
454
+ }
455
+ catch (err) {
456
+ result.errors.push(`legacy jobs.json migration: ${err instanceof Error ? err.message : String(err)}`);
457
+ this.appendMigrationTelemetry({
458
+ kind: 'migration.aborted',
459
+ runId,
460
+ startedAt,
461
+ completedAt: new Date().toISOString(),
462
+ trigger: 'post-update',
463
+ perEntry: [],
464
+ abortReason: err instanceof Error ? err.message : String(err),
465
+ });
466
+ }
467
+ }
468
+ /** Read the installed package's version, for the migration event's
469
+ * `instarVersion` field. Best-effort — returns undefined on failure. */
470
+ readBundledInstarVersion(packageRoot) {
471
+ try {
472
+ const pkg = JSON.parse(fs.readFileSync(path.join(packageRoot, 'package.json'), 'utf-8'));
473
+ return typeof pkg.version === 'string' ? pkg.version : undefined;
474
+ }
475
+ catch {
476
+ return undefined;
477
+ }
478
+ }
479
+ /** Best-effort telemetry write. Missing telemetry is degradation, not a
480
+ * release-blocker, so failures are swallowed. */
481
+ appendMigrationTelemetry(event) {
482
+ try {
483
+ appendMigrationEvent(this.config.stateDir, event);
484
+ }
485
+ catch {
486
+ // @silent-fallback-ok — telemetry is non-load-bearing
487
+ }
488
+ }
238
489
  /**
239
490
  * Re-install hooks with the latest templates.
240
491
  * Built-in hooks in instar/ are always overwritten.
@@ -1256,7 +1507,7 @@ The user has been talking to you (possibly for days). A generic greeting like "H
1256
1507
  - **Generate a file link**: \`curl -H "Authorization: Bearer $AUTH" "http://localhost:${port}/api/files/link?path=.claude/CLAUDE.md"\`
1257
1508
  - **Download a file**: \`curl -H "Authorization: Bearer $AUTH" "http://localhost:${port}/api/files/download?path=.claude/CLAUDE.md" -O\`
1258
1509
  - **Default config**: Browsing and editing enabled for the entire project directory (\`./\`) by default.
1259
- - **Never editable**: \`.claude/hooks/\`, \`.claude/scripts/\`, \`node_modules/\` are always read-only regardless of config.
1510
+ - **Never editable**: \`.claude/hooks/\`, \`.claude/scripts/\`, \`node_modules/\`, \`.instar/jobs/instar/\` are always read-only regardless of config.
1260
1511
  `;
1261
1512
  // Insert after Dashboard section
1262
1513
  const dashboardIdx = content.indexOf('**Dashboard**');