@ornexus/neocortex 4.59.1 → 4.59.4

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 (30) hide show
  1. package/dist/sbom.cdx.json +19 -19
  2. package/install.ps1 +1 -1
  3. package/install.sh +1 -1
  4. package/package.json +2 -2
  5. package/packages/client/dist/commands/invoke.d.ts +47 -0
  6. package/packages/client/dist/commands/invoke.js +30 -28
  7. package/packages/client/dist/continuity/invoke-hooks.d.ts +1 -0
  8. package/packages/client/dist/continuity/invoke-hooks.js +1 -1
  9. package/packages/client/dist/continuity/runner-bootstrap-policy.d.ts +50 -0
  10. package/packages/client/dist/continuity/runner-bootstrap-policy.js +1 -0
  11. package/packages/client/dist/continuity/sqlite-store.d.ts +5 -2
  12. package/packages/client/dist/continuity/sqlite-store.js +16 -16
  13. package/packages/client/dist/runner/binary.d.ts +68 -0
  14. package/packages/client/dist/runner/binary.js +1 -0
  15. package/packages/client/dist/runner/cli.d.ts +2 -13
  16. package/packages/client/dist/runner/cli.js +10 -10
  17. package/packages/client/dist/runner/scheduler.d.ts +70 -0
  18. package/packages/client/dist/runner/scheduler.js +7 -6
  19. package/packages/client/dist/state/state-json-repair.js +3 -3
  20. package/targets-stubs/antigravity/gemini.md +1 -1
  21. package/targets-stubs/antigravity/skill/SKILL.md +1 -1
  22. package/targets-stubs/claude-code/neocortex-root.agent.yaml +1 -1
  23. package/targets-stubs/claude-code/neocortex-root.md +2 -2
  24. package/targets-stubs/claude-code/neocortex.agent.yaml +1 -1
  25. package/targets-stubs/claude-code/neocortex.md +2 -2
  26. package/targets-stubs/codex/AGENTS.md +1 -1
  27. package/targets-stubs/cursor/agent.md +2 -2
  28. package/targets-stubs/gemini-cli/agent.md +2 -2
  29. package/targets-stubs/opencode/neocortex-root.md +1 -1
  30. package/targets-stubs/vscode/neocortex.agent.md +2 -2
@@ -1,52 +1,52 @@
1
- import{createHash as T}from"node:crypto";import{chmodSync as b,existsSync as C,mkdirSync as N}from"node:fs";import{join as y}from"node:path";import{INITIAL_CONTINUITY_SQLITE_MIGRATION as O}from"./migrations/001-initial-schema.js";const f=".neocortex/continuity",A="continuity.sqlite",K=1,j=5e3,I="Install the optional Enterprise continuity SQLite adapter with `npm install --workspace packages/client better-sqlite3 --include=optional` or reinstall Neocortex with optional dependencies enabled.";class i extends Error{code;reasonCode;guidance;mutationBlocked;cause;constructor(e,t,a={}){super(t),this.name="ContinuitySqliteStoreError",this.code=e,this.reasonCode=e,this.guidance=a.guidance,this.cause=a.cause,this.mutationBlocked=a.mutationBlocked??e==="sqlite-integrity-failed"}}const R=[O],L=Object.freeze(["continuity_migrations","jobs","job_leases","job_events","job_receipts","goal_campaigns","goal_ledger_items","goal_verifiers","goal_review_gates","loop_jobs","artifacts","state_snapshots","runner_config","outbox"]),w=/(raw[_-]?logs?|prompt(?:[_-]?(?:body|text))?|private[_-]?urls?|secret|token|password|protected(?:[_-]?(?:field|body|internals))?|workflow(?:[_-]?body)?|step(?:[_-]?body)?|customer(?:[_-]?(?:pii|data))?|authorization|api[_-]?key|license[_-]?key)/i,S=/(https?:\/\/\S+|ghp_[A-Za-z0-9_]+|sk-[A-Za-z0-9_-]+|-----BEGIN [A-Z ]*PRIVATE KEY-----|authorization\s*:|password\s*=|token\s*=|api[_-]?key\s*=|license[_-]?key\s*=|raw[_-]?log|transcript|stack trace|stderr:|stdout:|system prompt|workflow body|step body|PROTECTED_|PRIVATE_INTERNALS|CUSTOMER_PII|VENDOR_CORPUS|P180[_-]?SYNTHETIC[_-]?CONTINUITY)/i,k=/(corrupt|malformed|not a database|file is not a database|database disk image is malformed)/i,x=/(foreign key constraint failed|SQLITE_CONSTRAINT_FOREIGNKEY)/i;function M(r){return new Function("specifier","return import(specifier)")(r)}function v(r){return`sha256:${T("sha256").update(r).digest("hex")}`}function _(r){return typeof r=="object"&&r!==null&&!Array.isArray(r)}function U(r){return r instanceof Error?r.message:String(r)}function q(r){return _(r)&&typeof r.code=="string"?r.code:void 0}function n(r,e){if(r instanceof i)return r;const t=U(r),a=q(r);return a==="SQLITE_CORRUPT"||a==="SQLITE_NOTADB"||k.test(t)?new i("sqlite-integrity-failed","Continuity SQLite integrity check failed; durable mutation is blocked until the store is repaired or rebuilt.",{cause:r,mutationBlocked:!0}):a==="SQLITE_CONSTRAINT_FOREIGNKEY"||x.test(t)?new i("sqlite-foreign-key-failed","Continuity SQLite foreign-key validation failed; mutation was rejected.",{cause:r}):new i(e,t,{cause:r})}function g(r,e){if(typeof r=="string"){if(S.test(r))throw new i("sqlite-public-safety-rejected",`Continuity SQLite metadata rejected unsafe value at ${e}.`);return}if(!(r===null||typeof r=="number"||typeof r=="boolean")){if(Array.isArray(r)){r.forEach((t,a)=>g(t,`${e}[${a}]`));return}if(_(r)){for(const[t,a]of Object.entries(r)){if(w.test(t))throw new i("sqlite-public-safety-rejected",`Continuity SQLite metadata rejected unsafe key at ${e}.${t}.`);g(a,`${e}.${t}`)}return}throw new i("sqlite-public-safety-rejected",`Continuity SQLite metadata rejected unsupported value at ${e}.`)}}function c(r,e){if(r!==void 0&&S.test(r))throw new i("sqlite-public-safety-rejected",`Continuity SQLite text rejected unsafe value at ${e}.`)}function l(r){return r?(g(r,"metadata"),JSON.stringify(r)):null}function p(r){if(Array.isArray(r)){const e=r[0];return _(e)?Object.values(e)[0]:e}return _(r)?Object.values(r)[0]:r}function D(r){return L.includes(r)}function F(r){return Array.from(new Set(r))}function W(r){const e=_(r)&&"default"in r?r.default:r;if(typeof e!="function")throw new i("sqlite-adapter-unavailable","Optional better-sqlite3 adapter did not export a database constructor.",{guidance:I});const t=e;return{adapterName:"better-sqlite3",open(a,s){return new t(a,s)}}}async function P(r=M){try{const e=await r("better-sqlite3");return{ok:!0,adapter:W(e)}}catch(e){return e instanceof i?{ok:!1,error:e}:{ok:!1,error:new i("sqlite-adapter-unavailable","Optional Enterprise continuity SQLite adapter better-sqlite3 is unavailable.",{cause:e,guidance:I})}}}function H(r){return y(r,f,A)}function B(r){const e=y(r,f);N(e,{recursive:!0,mode:448});try{b(e,448)}catch{}return e}async function z(r){const e=r.adapter??await J(r.adapterLoader);B(r.projectRoot);const t=H(r.projectRoot);let a;try{a=e.open(t)}catch(o){throw n(o,"sqlite-integrity-failed")}const s=new Q({db:a,filePath:t,adapterName:e.adapterName,busyTimeoutMs:r.busyTimeoutMs??j,integrityCheck:r.integrityCheck??!0,now:r.now??(()=>new Date().toISOString())});try{if(s.initialize(),C(t))try{b(t,384)}catch{}return s}catch(o){try{a.close()}catch{}throw o}}async function J(r){const e=r?await r():await P();if(!e.ok)throw e.error;return e.adapter}class Q{filePath;adapterName;db;busyTimeoutMs;integrityCheck;now;mutationBlocked=!1;constructor(e){this.db=e.db,this.filePath=e.filePath,this.adapterName=e.adapterName,this.busyTimeoutMs=e.busyTimeoutMs,this.integrityCheck=e.integrityCheck,this.now=e.now}initialize(){try{this.configureConnection(),this.integrityCheck&&this.runIntegrityCheck(),this.ensureMigrationTable(),this.applyMigrations(),this.integrityCheck&&this.runIntegrityCheck()}catch(e){throw n(e,"sqlite-migration-failed")}}close(){this.db.close()}pragmaValue(e){return p(this.db.pragma(e,{simple:!0}))}runIntegrityCheck(){try{if(String(p(this.db.pragma("integrity_check",{simple:!0}))??"").toLowerCase()!=="ok")throw this.mutationBlocked=!0,new i("sqlite-integrity-failed","Continuity SQLite integrity check failed; durable mutation is blocked until the store is repaired or rebuilt.",{mutationBlocked:!0})}catch(e){throw this.mutationBlocked=!0,n(e,"sqlite-integrity-failed")}}getSchemaVersion(){const e=this.db.prepare("SELECT COALESCE(MAX(version), 0) AS version FROM continuity_migrations").get();return _(e)&&typeof e.version=="number"?e.version:0}countRows(e){if(!D(e))throw new i("sqlite-public-safety-rejected","Unknown continuity table name.");const t=this.db.prepare(`SELECT COUNT(*) AS count FROM ${e}`).get();return _(t)&&typeof t.count=="number"?t.count:0}recordJob(e){this.assertCanMutate(),c(e.summary,"jobs.summary");const t=l(e.metadata);try{const a=this.db.prepare(`
1
+ import{createHash as T}from"node:crypto";import{chmodSync as y,existsSync as C,mkdirSync as N}from"node:fs";import{join as g}from"node:path";import{INITIAL_CONTINUITY_SQLITE_MIGRATION as O}from"./migrations/001-initial-schema.js";const f=".neocortex/continuity",A="continuity.sqlite",K=1,j=5e3,I="Install the optional Enterprise continuity SQLite adapter with `npm install --workspace packages/client better-sqlite3 --include=optional` or reinstall Neocortex with optional dependencies enabled.";class i extends Error{code;reasonCode;guidance;mutationBlocked;cause;constructor(e,t,a={}){super(t),this.name="ContinuitySqliteStoreError",this.code=e,this.reasonCode=e,this.guidance=a.guidance,this.cause=a.cause,this.mutationBlocked=a.mutationBlocked??e==="sqlite-integrity-failed"}}const R=[O],L=Object.freeze(["continuity_migrations","jobs","job_leases","job_events","job_receipts","goal_campaigns","goal_ledger_items","goal_verifiers","goal_review_gates","loop_jobs","artifacts","state_snapshots","runner_config","outbox"]),w=/(raw[_-]?logs?|prompt(?:[_-]?(?:body|text))?|private[_-]?urls?|secret|token|password|protected(?:[_-]?(?:field|body|internals))?|workflow(?:[_-]?body)?|step(?:[_-]?body)?|customer(?:[_-]?(?:pii|data))?|authorization|api[_-]?key|license[_-]?key)/i,S=/(https?:\/\/\S+|ghp_[A-Za-z0-9_]+|sk-[A-Za-z0-9_-]+|-----BEGIN [A-Z ]*PRIVATE KEY-----|authorization\s*:|password\s*=|token\s*=|api[_-]?key\s*=|license[_-]?key\s*=|raw[_-]?log|transcript|stack trace|stderr:|stdout:|system prompt|workflow body|step body|PROTECTED_|PRIVATE_INTERNALS|CUSTOMER_PII|VENDOR_CORPUS|P180[_-]?SYNTHETIC[_-]?CONTINUITY)/i,k=/(corrupt|malformed|not a database|file is not a database|database disk image is malformed)/i,x=/(foreign key constraint failed|SQLITE_CONSTRAINT_FOREIGNKEY)/i;function M(r){return new Function("specifier","return import(specifier)")(r)}function v(r){return`sha256:${T("sha256").update(r).digest("hex")}`}function _(r){return typeof r=="object"&&r!==null&&!Array.isArray(r)}function U(r){return r instanceof Error?r.message:String(r)}function q(r){return _(r)&&typeof r.code=="string"?r.code:void 0}function n(r,e){if(r instanceof i)return r;const t=U(r),a=q(r);return a==="SQLITE_CORRUPT"||a==="SQLITE_NOTADB"||k.test(t)?new i("sqlite-integrity-failed","Continuity SQLite integrity check failed; durable mutation is blocked until the store is repaired or rebuilt.",{cause:r,mutationBlocked:!0}):a==="SQLITE_CONSTRAINT_FOREIGNKEY"||x.test(t)?new i("sqlite-foreign-key-failed","Continuity SQLite foreign-key validation failed; mutation was rejected.",{cause:r}):new i(e,t,{cause:r})}function b(r,e){if(typeof r=="string"){if(S.test(r))throw new i("sqlite-public-safety-rejected",`Continuity SQLite metadata rejected unsafe value at ${e}.`);return}if(!(r===null||typeof r=="number"||typeof r=="boolean")){if(Array.isArray(r)){r.forEach((t,a)=>b(t,`${e}[${a}]`));return}if(_(r)){for(const[t,a]of Object.entries(r)){if(w.test(t))throw new i("sqlite-public-safety-rejected",`Continuity SQLite metadata rejected unsafe key at ${e}.${t}.`);b(a,`${e}.${t}`)}return}throw new i("sqlite-public-safety-rejected",`Continuity SQLite metadata rejected unsupported value at ${e}.`)}}function c(r,e){if(r!==void 0&&S.test(r))throw new i("sqlite-public-safety-rejected",`Continuity SQLite text rejected unsafe value at ${e}.`)}function l(r){return r?(b(r,"metadata"),JSON.stringify(r)):null}function p(r){if(Array.isArray(r)){const e=r[0];return _(e)?Object.values(e)[0]:e}return _(r)?Object.values(r)[0]:r}function D(r){return L.includes(r)}function F(r){return Array.from(new Set(r))}function W(r){const e=_(r)&&"default"in r?r.default:r;if(typeof e!="function")throw new i("sqlite-adapter-unavailable","Optional better-sqlite3 adapter did not export a database constructor.",{guidance:I});const t=e;return{adapterName:"better-sqlite3",open(a,s){return new t(a,s)}}}async function P(r=M){try{const e=await r("better-sqlite3");return{ok:!0,adapter:W(e)}}catch(e){return e instanceof i?{ok:!1,error:e}:{ok:!1,error:new i("sqlite-adapter-unavailable","Optional Enterprise continuity SQLite adapter better-sqlite3 is unavailable.",{cause:e,guidance:I})}}}function H(r){return g(r,f,A)}function B(r){const e=g(r,f);N(e,{recursive:!0,mode:448});try{y(e,448)}catch{}return e}async function z(r){const e=r.adapter??await J(r.adapterLoader);B(r.projectRoot);const t=H(r.projectRoot);let a;try{a=e.open(t)}catch(o){throw n(o,"sqlite-integrity-failed")}const s=new Q({db:a,filePath:t,adapterName:e.adapterName,busyTimeoutMs:r.busyTimeoutMs??j,integrityCheck:r.integrityCheck??!0,now:r.now??(()=>new Date().toISOString())});try{if(s.initialize(),C(t))try{y(t,384)}catch{}return s}catch(o){try{a.close()}catch{}throw o}}async function J(r){const e=r?await r():await P();if(!e.ok)throw e.error;return e.adapter}class Q{filePath;adapterName;db;busyTimeoutMs;integrityCheck;now;mutationBlocked=!1;constructor(e){this.db=e.db,this.filePath=e.filePath,this.adapterName=e.adapterName,this.busyTimeoutMs=e.busyTimeoutMs,this.integrityCheck=e.integrityCheck,this.now=e.now}initialize(){try{this.configureConnection(),this.integrityCheck&&this.runIntegrityCheck(),this.ensureMigrationTable(),this.applyMigrations(),this.integrityCheck&&this.runIntegrityCheck()}catch(e){throw n(e,"sqlite-migration-failed")}}close(){this.db.close()}pragmaValue(e){return p(this.db.pragma(e,{simple:!0}))}runIntegrityCheck(){try{if(String(p(this.db.pragma("integrity_check",{simple:!0}))??"").toLowerCase()!=="ok")throw this.mutationBlocked=!0,new i("sqlite-integrity-failed","Continuity SQLite integrity check failed; durable mutation is blocked until the store is repaired or rebuilt.",{mutationBlocked:!0})}catch(e){throw this.mutationBlocked=!0,n(e,"sqlite-integrity-failed")}}getSchemaVersion(){const e=this.db.prepare("SELECT COALESCE(MAX(version), 0) AS version FROM continuity_migrations").get();return _(e)&&typeof e.version=="number"?e.version:0}countRows(e){if(!D(e))throw new i("sqlite-public-safety-rejected","Unknown continuity table name.");const t=this.db.prepare(`SELECT COUNT(*) AS count FROM ${e}`).get();return _(t)&&typeof t.count=="number"?t.count:0}recordJob(e){this.assertCanMutate(),c(e.summary,"jobs.summary");const t=l(e.metadata);try{const a=this.db.prepare(`
2
2
  INSERT OR IGNORE INTO jobs (
3
3
  job_id, kind, status, summary, reason_code, created_at, updated_at,
4
4
  next_run_at, goal_id, loop_id, campaign_id, operation_id,
5
5
  idempotency_key, metadata_json
6
6
  ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
7
- `).run(e.jobId,e.kind,e.status,e.summary??null,e.reasonCode??null,e.createdAt,e.updatedAt,e.nextRunAt??null,e.goalId??null,e.loopId??null,e.campaignId??null,e.operationId??null,e.idempotencyKey??null,t);return this.toWriteResult(a)}catch(a){throw n(a,"sqlite-migration-failed")}}appendEvent(e){this.assertCanMutate(),c(e.summary,"job_events.summary");const t=l(e.metadata);try{const a=this.db.prepare(`
7
+ `).run(e.jobId,e.kind,e.status,e.summary??null,e.reasonCode??null,e.createdAt,e.updatedAt,e.nextRunAt??null,e.goalId??null,e.loopId??null,e.campaignId??null,e.operationId??null,e.idempotencyKey??null,t);return this.toWriteResult(a)}catch(a){throw n(a,"sqlite-mutation-failed")}}appendEvent(e){this.assertCanMutate(),c(e.summary,"job_events.summary");const t=l(e.metadata);try{const a=this.db.prepare(`
8
8
  INSERT OR IGNORE INTO job_events (
9
9
  event_id, job_id, operation_id, idempotency_key, event_sequence,
10
10
  type, summary, reason_code, created_at, metadata_json
11
11
  ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
12
- `).run(e.eventId,e.jobId,e.operationId,e.idempotencyKey??null,e.sequence??null,e.type,e.summary,e.reasonCode??null,e.createdAt,t);return this.toWriteResult(a)}catch(a){throw n(a,"sqlite-migration-failed")}}appendReceipt(e){this.assertCanMutate();const t=l(e.metadata);try{const a=this.db.prepare(`
12
+ `).run(e.eventId,e.jobId,e.operationId,e.idempotencyKey??null,e.sequence??null,e.type,e.summary,e.reasonCode??null,e.createdAt,t);return this.toWriteResult(a)}catch(a){throw n(a,"sqlite-mutation-failed")}}appendReceipt(e){this.assertCanMutate();const t=l(e.metadata);try{const a=this.db.prepare(`
13
13
  INSERT OR IGNORE INTO job_receipts (
14
14
  receipt_id, job_id, operation_id, idempotency_key, status, reason_code,
15
15
  applied_operation_ids_json, ignored_operation_ids_json, created_at, metadata_json
16
16
  ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
17
- `).run(e.receiptId,e.jobId,e.operationId??null,e.idempotencyKey??null,e.status,e.reasonCode??null,e.appliedOperationIds?JSON.stringify(e.appliedOperationIds):null,e.ignoredOperationIds?JSON.stringify(e.ignoredOperationIds):null,e.createdAt,t);return this.toWriteResult(a)}catch(a){throw n(a,"sqlite-migration-failed")}}updateJobStatus(e){this.assertCanMutate();try{const t=this.db.prepare(`
17
+ `).run(e.receiptId,e.jobId,e.operationId??null,e.idempotencyKey??null,e.status,e.reasonCode??null,e.appliedOperationIds?JSON.stringify(e.appliedOperationIds):null,e.ignoredOperationIds?JSON.stringify(e.ignoredOperationIds):null,e.createdAt,t);return this.toWriteResult(a)}catch(a){throw n(a,"sqlite-mutation-failed")}}updateJobStatus(e){this.assertCanMutate();try{const t=this.db.prepare(`
18
18
  UPDATE jobs
19
19
  SET status = ?,
20
20
  reason_code = COALESCE(?, reason_code),
21
21
  updated_at = ?,
22
22
  next_run_at = COALESCE(?, next_run_at)
23
23
  WHERE job_id = ?
24
- `).run(e.status,e.reasonCode??null,e.updatedAt,e.nextRunAt??null,e.jobId);if(t.changes===0)throw new i("sqlite-foreign-key-failed",`Continuity SQLite job ${e.jobId} was not found for status update.`);return this.toWriteResult(t)}catch(t){throw n(t,"sqlite-migration-failed")}}scheduleNextTick(e){return this.updateJobStatus({jobId:e.jobId,status:"active",updatedAt:e.updatedAt,reasonCode:e.reasonCode,nextRunAt:e.scheduledAt})}acquireLease(e){this.assertCanMutate();const t=l(e.metadata);try{const a=this.db.prepare(`
24
+ `).run(e.status,e.reasonCode??null,e.updatedAt,e.nextRunAt??null,e.jobId);if(t.changes===0)throw new i("sqlite-foreign-key-failed",`Continuity SQLite job ${e.jobId} was not found for status update.`);return this.toWriteResult(t)}catch(t){throw n(t,"sqlite-mutation-failed")}}scheduleNextTick(e){return this.updateJobStatus({jobId:e.jobId,status:"active",updatedAt:e.updatedAt,reasonCode:e.reasonCode,nextRunAt:e.scheduledAt})}acquireLease(e){this.assertCanMutate();const t=l(e.metadata);try{const a=this.db.prepare(`
25
25
  INSERT OR IGNORE INTO job_leases (
26
26
  lease_id, job_id, runner_id, status, acquired_at, expires_at,
27
27
  operation_id, idempotency_key, metadata_json
28
28
  ) VALUES (?, ?, ?, 'acquired', ?, ?, ?, ?, ?)
29
- `).run(e.leaseId,e.jobId,e.runnerId,e.acquiredAt,e.expiresAt,e.operationId??null,e.idempotencyKey??null,t);return this.toWriteResult(a)}catch(a){throw n(a,"sqlite-migration-failed")}}releaseLease(e){this.assertCanMutate();try{const t=this.db.prepare(`
29
+ `).run(e.leaseId,e.jobId,e.runnerId,e.acquiredAt,e.expiresAt,e.operationId??null,e.idempotencyKey??null,t);return this.toWriteResult(a)}catch(a){throw n(a,"sqlite-mutation-failed")}}releaseLease(e){this.assertCanMutate();try{const t=this.db.prepare(`
30
30
  UPDATE job_leases
31
31
  SET status = 'released', released_at = ?
32
32
  WHERE lease_id = ? AND released_at IS NULL
33
- `).run(e.releasedAt,e.leaseId);if(t.changes===0)throw new i("sqlite-foreign-key-failed",`Continuity SQLite lease ${e.leaseId} was not found for release.`);return this.toWriteResult(t)}catch(t){throw n(t,"sqlite-migration-failed")}}recordStateSnapshot(e){this.assertCanMutate(),c(e.summary,"state_snapshots.summary"),c(e.relativePath,"state_snapshots.relative_path");const t=l(e.metadata);try{const a=this.db.prepare(`
33
+ `).run(e.releasedAt,e.leaseId);if(t.changes===0)throw new i("sqlite-foreign-key-failed",`Continuity SQLite lease ${e.leaseId} was not found for release.`);return this.toWriteResult(t)}catch(t){throw n(t,"sqlite-mutation-failed")}}recordStateSnapshot(e){this.assertCanMutate(),c(e.summary,"state_snapshots.summary"),c(e.relativePath,"state_snapshots.relative_path");const t=l(e.metadata);try{const a=this.db.prepare(`
34
34
  INSERT OR IGNORE INTO state_snapshots (
35
35
  snapshot_id, job_id, kind, relative_path, sha256, summary, captured_at,
36
36
  operation_id, idempotency_key, metadata_json
37
37
  ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
38
- `).run(e.snapshotId,e.jobId??null,e.kind,e.relativePath??null,e.sha256??null,e.summary??null,e.capturedAt,e.operationId??null,e.idempotencyKey??null,t);return this.toWriteResult(a)}catch(a){throw n(a,"sqlite-migration-failed")}}recordArtifact(e){this.assertCanMutate(),c(e.kind,"artifacts.kind"),c(e.relativePath,"artifacts.relative_path"),c(e.summary,"artifacts.summary");const t=l(e.metadata);try{const a=this.db.prepare(`
38
+ `).run(e.snapshotId,e.jobId??null,e.kind,e.relativePath??null,e.sha256??null,e.summary??null,e.capturedAt,e.operationId??null,e.idempotencyKey??null,t);return this.toWriteResult(a)}catch(a){throw n(a,"sqlite-mutation-failed")}}recordArtifact(e){this.assertCanMutate(),c(e.kind,"artifacts.kind"),c(e.relativePath,"artifacts.relative_path"),c(e.summary,"artifacts.summary");const t=l(e.metadata);try{const a=this.db.prepare(`
39
39
  INSERT OR IGNORE INTO artifacts (
40
40
  artifact_id, job_id, kind, relative_path, sha256, summary,
41
41
  operation_id, idempotency_key, created_at, metadata_json
42
42
  ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
43
- `).run(e.artifactId,e.jobId??null,e.kind,e.relativePath,e.sha256??null,e.summary??null,e.operationId??null,e.idempotencyKey??null,e.createdAt,t);return this.toWriteResult(a)}catch(a){throw n(a,"sqlite-migration-failed")}}enqueueOutbox(e){this.assertCanMutate();const t=l(e.payload);try{const a=this.db.prepare(`
43
+ `).run(e.artifactId,e.jobId??null,e.kind,e.relativePath,e.sha256??null,e.summary??null,e.operationId??null,e.idempotencyKey??null,e.createdAt,t);return this.toWriteResult(a)}catch(a){throw n(a,"sqlite-mutation-failed")}}enqueueOutbox(e){this.assertCanMutate();const t=l(e.payload);try{const a=this.db.prepare(`
44
44
  INSERT OR IGNORE INTO outbox (
45
45
  outbox_id, job_id, operation_id, idempotency_key, type, status,
46
46
  payload_json, retry_count, next_attempt_at, last_error_code,
47
47
  created_at, updated_at
48
48
  ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
49
- `).run(e.outboxId,e.jobId??null,e.operationId,e.idempotencyKey??null,e.type,e.status??"pending",t??"{}",e.retryCount??0,e.nextAttemptAt??null,e.lastErrorCode??null,e.createdAt,e.updatedAt);return this.toWriteResult(a)}catch(a){throw n(a,"sqlite-migration-failed")}}retryOutboxEntries(e){this.assertCanMutate();const t=Math.max(1,Math.min(100,Math.floor(e.limit))),a=F(e.statuses?.length?e.statuses:["failed","dead_letter"]),s=e.reasonCode??"backoff-scheduled";c(s,"outbox.last_error_code"),c(e.nextAttemptAt,"outbox.next_attempt_at");try{return this.runInTransaction(()=>{const o=a.map(()=>"?").join(", "),d=this.db.prepare(`
49
+ `).run(e.outboxId,e.jobId??null,e.operationId,e.idempotencyKey??null,e.type,e.status??"pending",t??"{}",e.retryCount??0,e.nextAttemptAt??null,e.lastErrorCode??null,e.createdAt,e.updatedAt);return this.toWriteResult(a)}catch(a){throw n(a,"sqlite-mutation-failed")}}retryOutboxEntries(e){this.assertCanMutate();const t=Math.max(1,Math.min(100,Math.floor(e.limit))),a=F(e.statuses?.length?e.statuses:["failed","dead_letter"]),s=e.reasonCode??"backoff-scheduled";c(s,"outbox.last_error_code"),c(e.nextAttemptAt,"outbox.next_attempt_at");try{return this.runInTransaction(()=>{const o=a.map(()=>"?").join(", "),d=this.db.prepare(`
50
50
  SELECT outbox_id
51
51
  FROM outbox
52
52
  WHERE status IN (${o})
@@ -60,7 +60,7 @@ import{createHash as T}from"node:crypto";import{chmodSync as b,existsSync as C,m
60
60
  last_error_code = ?,
61
61
  updated_at = ?
62
62
  WHERE outbox_id IN (${h})
63
- `).run(e.nextAttemptAt??e.nowIso,s,e.nowIso,...d);return{retriedOutboxIds:d,changes:E.changes,reasonCode:s,publicSafe:!0}})}catch(o){throw n(o,"sqlite-migration-failed")}}upsertGoalCampaign(e){this.assertCanMutate(),c(e.title,"goal_campaigns.title"),c(e.publicSummary,"goal_campaigns.public_summary");const t=l(e.metadata);try{const a=this.db.prepare(`
63
+ `).run(e.nextAttemptAt??e.nowIso,s,e.nowIso,...d);return{retriedOutboxIds:d,changes:E.changes,reasonCode:s,publicSafe:!0}})}catch(o){throw n(o,"sqlite-mutation-failed")}}upsertGoalCampaign(e){this.assertCanMutate(),c(e.title,"goal_campaigns.title"),c(e.publicSummary,"goal_campaigns.public_summary");const t=l(e.metadata);try{const a=this.db.prepare(`
64
64
  INSERT INTO goal_campaigns (
65
65
  campaign_id, job_id, status, title, public_summary, reason_code,
66
66
  created_at, updated_at, operation_id, idempotency_key, metadata_json
@@ -74,7 +74,7 @@ import{createHash as T}from"node:crypto";import{chmodSync as b,existsSync as C,m
74
74
  operation_id = excluded.operation_id,
75
75
  idempotency_key = excluded.idempotency_key,
76
76
  metadata_json = excluded.metadata_json
77
- `).run(e.campaignId,e.jobId,e.status,e.title??null,e.publicSummary??null,e.reasonCode??null,e.createdAt,e.updatedAt,e.operationId??null,e.idempotencyKey??null,t);return this.toWriteResult(a)}catch(a){throw n(a,"sqlite-migration-failed")}}upsertGoalLedgerItem(e){this.assertCanMutate(),c(e.summary,"goal_ledger_items.summary");const t=l(e.metadata);try{this.ensureGoalCampaign(e.campaignId,e.jobId,e.createdAt,e.updatedAt);const a=this.db.prepare(`
77
+ `).run(e.campaignId,e.jobId,e.status,e.title??null,e.publicSummary??null,e.reasonCode??null,e.createdAt,e.updatedAt,e.operationId??null,e.idempotencyKey??null,t);return this.toWriteResult(a)}catch(a){throw n(a,"sqlite-mutation-failed")}}upsertGoalLedgerItem(e){this.assertCanMutate(),c(e.summary,"goal_ledger_items.summary");const t=l(e.metadata);try{this.ensureGoalCampaign(e.campaignId,e.jobId,e.createdAt,e.updatedAt);const a=this.db.prepare(`
78
78
  INSERT INTO goal_ledger_items (
79
79
  item_id, campaign_id, operation_id, idempotency_key, item_type, status,
80
80
  summary, reason_code, created_at, updated_at, metadata_json
@@ -85,7 +85,7 @@ import{createHash as T}from"node:crypto";import{chmodSync as b,existsSync as C,m
85
85
  reason_code = excluded.reason_code,
86
86
  updated_at = excluded.updated_at,
87
87
  metadata_json = excluded.metadata_json
88
- `).run(e.itemId,e.campaignId,e.operationId??null,e.idempotencyKey??null,e.itemType,e.status,e.summary,e.reasonCode??null,e.createdAt,e.updatedAt,t);return this.toWriteResult(a)}catch(a){throw n(a,"sqlite-migration-failed")}}upsertGoalVerifier(e){this.assertCanMutate(),c(e.summary,"goal_verifiers.summary");const t=l(e.metadata);try{const a=e.lastCheckedAt??this.now();this.ensureGoalCampaign(e.campaignId,e.jobId,a,a);const s=this.db.prepare(`
88
+ `).run(e.itemId,e.campaignId,e.operationId??null,e.idempotencyKey??null,e.itemType,e.status,e.summary,e.reasonCode??null,e.createdAt,e.updatedAt,t);return this.toWriteResult(a)}catch(a){throw n(a,"sqlite-mutation-failed")}}upsertGoalVerifier(e){this.assertCanMutate(),c(e.summary,"goal_verifiers.summary");const t=l(e.metadata);try{const a=e.lastCheckedAt??this.now();this.ensureGoalCampaign(e.campaignId,e.jobId,a,a);const s=this.db.prepare(`
89
89
  INSERT INTO goal_verifiers (
90
90
  verifier_id, campaign_id, kind, status, summary, reason_code,
91
91
  last_checked_at, operation_id, idempotency_key, metadata_json
@@ -96,7 +96,7 @@ import{createHash as T}from"node:crypto";import{chmodSync as b,existsSync as C,m
96
96
  reason_code = excluded.reason_code,
97
97
  last_checked_at = excluded.last_checked_at,
98
98
  metadata_json = excluded.metadata_json
99
- `).run(e.verifierId,e.campaignId,e.kind,e.status,e.summary??null,e.reasonCode??null,e.lastCheckedAt??null,e.operationId??null,e.idempotencyKey??null,t);return this.toWriteResult(s)}catch(a){throw n(a,"sqlite-migration-failed")}}upsertGoalReviewGate(e){this.assertCanMutate(),c(e.summary,"goal_review_gates.summary");const t=l(e.metadata);try{const a=this.now();this.ensureGoalCampaign(e.campaignId,e.jobId,a,a);const s=this.db.prepare(`
99
+ `).run(e.verifierId,e.campaignId,e.kind,e.status,e.summary??null,e.reasonCode??null,e.lastCheckedAt??null,e.operationId??null,e.idempotencyKey??null,t);return this.toWriteResult(s)}catch(a){throw n(a,"sqlite-mutation-failed")}}upsertGoalReviewGate(e){this.assertCanMutate(),c(e.summary,"goal_review_gates.summary");const t=l(e.metadata);try{const a=this.now();this.ensureGoalCampaign(e.campaignId,e.jobId,a,a);const s=this.db.prepare(`
100
100
  INSERT INTO goal_review_gates (
101
101
  gate_id, campaign_id, status, summary, required, reason_code,
102
102
  operation_id, idempotency_key, metadata_json
@@ -107,7 +107,7 @@ import{createHash as T}from"node:crypto";import{chmodSync as b,existsSync as C,m
107
107
  required = excluded.required,
108
108
  reason_code = excluded.reason_code,
109
109
  metadata_json = excluded.metadata_json
110
- `).run(e.gateId,e.campaignId,e.status,e.summary??null,e.required?1:0,e.reasonCode??null,e.operationId??null,e.idempotencyKey??null,t);return this.toWriteResult(s)}catch(a){throw n(a,"sqlite-migration-failed")}}recordOperationAudit(e){return this.appendReceipt(e)}hasOperationRef(e,t){this.assertCanMutate();const a=["jobs","job_leases","job_events","job_receipts","goal_campaigns","goal_ledger_items","goal_verifiers","goal_review_gates","loop_jobs","artifacts","state_snapshots","runner_config","outbox"],s=a.map(d=>`SELECT 1 AS found FROM ${d} WHERE operation_id = ?${t?" OR idempotency_key = ?":""}`),o=a.flatMap(()=>t?[e,t]:[e]);return!!this.db.prepare(`${s.join(" UNION ALL ")} LIMIT 1`).get(...o)}jobExists(e){return!!this.db.prepare("SELECT 1 AS found FROM jobs WHERE job_id = ? LIMIT 1").get(e)}runInTransaction(e){this.assertCanMutate();const t=this.db.transaction(e);try{return t()}catch(a){throw n(a,"sqlite-migration-failed")}}collectSnapshotRows(e){const t=(o,...m)=>{const d=this.db.prepare(o).get(...m);return _(d)&&typeof d.count=="number"?d.count:0},a=this.db.prepare(`
110
+ `).run(e.gateId,e.campaignId,e.status,e.summary??null,e.required?1:0,e.reasonCode??null,e.operationId??null,e.idempotencyKey??null,t);return this.toWriteResult(s)}catch(a){throw n(a,"sqlite-mutation-failed")}}recordOperationAudit(e){return this.appendReceipt(e)}hasOperationRef(e,t){this.assertCanMutate();const a=["jobs","job_leases","job_events","job_receipts","goal_campaigns","goal_ledger_items","goal_verifiers","goal_review_gates","loop_jobs","artifacts","state_snapshots","runner_config","outbox"],s=a.map(d=>`SELECT 1 AS found FROM ${d} WHERE operation_id = ?${t?" OR idempotency_key = ?":""}`),o=a.flatMap(()=>t?[e,t]:[e]);return!!this.db.prepare(`${s.join(" UNION ALL ")} LIMIT 1`).get(...o)}jobExists(e){return!!this.db.prepare("SELECT 1 AS found FROM jobs WHERE job_id = ? LIMIT 1").get(e)}runInTransaction(e){this.assertCanMutate();const t=this.db.transaction(e);try{return typeof t.immediate=="function"?t.immediate():t()}catch(a){throw n(a,"sqlite-mutation-failed")}}collectSnapshotRows(e){const t=(o,...m)=>{const d=this.db.prepare(o).get(...m);return _(d)&&typeof d.count=="number"?d.count:0},a=this.db.prepare(`
111
111
  SELECT status, COUNT(*) AS count FROM outbox GROUP BY status
112
112
  `).all(),s={};for(const o of a)typeof o.status=="string"&&typeof o.count=="number"&&(s[o.status]=o.count);return{schemaVersion:this.getSchemaVersion(),jobs:this.db.prepare(`
113
113
  SELECT job_id, kind, status, summary, reason_code, created_at, updated_at,
@@ -212,7 +212,7 @@ import{createHash as T}from"node:crypto";import{chmodSync as b,existsSync as C,m
212
212
  SET status = 'expired', released_at = ?
213
213
  WHERE released_at IS NULL
214
214
  AND lease_id IN (${h})
215
- `).run(e.nowIso,...d);return{recoveredLeaseIds:d,safeExpiredAtOrBefore:o,changes:E.changes}})}catch(m){throw n(m,"sqlite-migration-failed")}}ensureGoalCampaign(e,t,a,s){this.db.prepare(`
215
+ `).run(e.nowIso,...d);return{recoveredLeaseIds:d,safeExpiredAtOrBefore:o,changes:E.changes}})}catch(m){throw n(m,"sqlite-mutation-failed")}}ensureGoalCampaign(e,t,a,s){this.db.prepare(`
216
216
  INSERT OR IGNORE INTO goal_campaigns (
217
217
  campaign_id, job_id, status, public_summary, created_at, updated_at
218
218
  ) VALUES (?, ?, 'active', 'Public goal campaign summary unavailable', ?, ?)
@@ -0,0 +1,68 @@
1
+ /**
2
+ * @license FSL-1.1
3
+ * Copyright (c) 2026 OrNexus AI
4
+ *
5
+ * P181.02 -- shared trusted neocortex-runner binary resolution.
6
+ */
7
+ export declare const RUNNER_BINARY_REASON_CODES: Readonly<{
8
+ readonly OK: "continuity-ok";
9
+ readonly MISSING: "runner-binary-missing";
10
+ readonly AMBIGUOUS: "runner-binary-ambiguous";
11
+ readonly NON_EXECUTABLE: "runner-binary-non-executable";
12
+ readonly VERSION_MISMATCHED: "runner-binary-version-mismatched";
13
+ readonly UNTRUSTED: "runner-binary-untrusted";
14
+ }>;
15
+ export type RunnerBinaryReasonCode = (typeof RUNNER_BINARY_REASON_CODES)[keyof typeof RUNNER_BINARY_REASON_CODES] | string;
16
+ export type RunnerBinaryProvenance = 'published-root-package' | 'published-client-package' | 'development-workspace';
17
+ export interface RunnerBinaryResolveOptions {
18
+ readonly from?: string;
19
+ readonly packageRoot?: string;
20
+ readonly platform?: NodeJS.Platform;
21
+ readonly requireExecutable?: boolean;
22
+ }
23
+ export interface TrustedRunnerBinaryResolution {
24
+ readonly ok: true;
25
+ readonly trusted: true;
26
+ readonly command: string;
27
+ readonly args: readonly string[];
28
+ readonly executablePath: string;
29
+ readonly packageName: string;
30
+ readonly packageVersion: string;
31
+ readonly packageRoot: string;
32
+ readonly expectedRelativePath: string;
33
+ readonly provenance: RunnerBinaryProvenance;
34
+ readonly reasonCodes: readonly RunnerBinaryReasonCode[];
35
+ readonly publicSummary: string;
36
+ readonly publicSafe: true;
37
+ }
38
+ export interface FailedRunnerBinaryResolution {
39
+ readonly ok: false;
40
+ readonly trusted: false;
41
+ readonly reasonCode: RunnerBinaryReasonCode;
42
+ readonly reasonCodes: readonly RunnerBinaryReasonCode[];
43
+ readonly packageName?: string;
44
+ readonly packageVersion?: string;
45
+ readonly packageRoot?: string;
46
+ readonly executablePath?: string;
47
+ readonly expectedRelativePath?: string;
48
+ readonly provenance?: RunnerBinaryProvenance;
49
+ readonly publicSummary: string;
50
+ readonly publicSafe: true;
51
+ }
52
+ export type RunnerBinaryResolution = TrustedRunnerBinaryResolution | FailedRunnerBinaryResolution;
53
+ export interface RunnerBinaryTrustResult {
54
+ readonly trusted: boolean;
55
+ readonly reasonCode?: RunnerBinaryReasonCode;
56
+ readonly reasonCodes?: readonly RunnerBinaryReasonCode[];
57
+ readonly packageName?: string;
58
+ readonly packageVersion?: string;
59
+ readonly packageRoot?: string;
60
+ readonly executablePath?: string;
61
+ readonly expectedRelativePath?: string;
62
+ readonly provenance?: RunnerBinaryProvenance;
63
+ readonly publicSummary?: string;
64
+ readonly publicSafe: true;
65
+ }
66
+ export declare function resolveTrustedRunnerBinary(options?: RunnerBinaryResolveOptions): RunnerBinaryResolution;
67
+ export declare function checkRunnerBinaryTrust(executablePath: string | undefined, options?: Omit<RunnerBinaryResolveOptions, 'from' | 'packageRoot'>): RunnerBinaryTrustResult;
68
+ export declare function runnerTrustRelativePath(packageRoot: string, executablePath: string): string;
@@ -0,0 +1 @@
1
+ import{existsSync as h,readFileSync as _,realpathSync as V,statSync as x}from"node:fs";import{dirname as d,isAbsolute as I,join as y,relative as j,resolve as N,sep as $,win32 as H}from"node:path";const c=Object.freeze({OK:"continuity-ok",MISSING:"runner-binary-missing",AMBIGUOUS:"runner-binary-ambiguous",NON_EXECUTABLE:"runner-binary-non-executable",VERSION_MISMATCHED:"runner-binary-version-mismatched",UNTRUSTED:"runner-binary-untrusted"}),m=new Set(["@ornexus/neocortex","@neocortex/client"]),E=/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/;function q(e={}){const t=z(e);if(!t)return g(c.MISSING,"Runner binary resolution did not receive a usable start path.");const r=v(t);if(!r)return g(c.AMBIGUOUS,"Runner binary was not inside an accepted Neocortex package.");const{packageRoot:n,pkg:l}=r,a=typeof l.name=="string"?l.name:void 0,i=typeof l.version=="string"?l.version:void 0,o=U(n,a);if(!a||!m.has(a))return g(c.AMBIGUOUS,"Runner package identity was not accepted.",{packageName:a,packageVersion:i,packageRoot:n,provenance:o});if(!i||!E.test(i))return g(c.VERSION_MISMATCHED,"Runner package version was missing or invalid.",{packageName:a,packageVersion:i,packageRoot:n,provenance:o});const u=P(l,a);if(!u)return g(c.MISSING,"Runner package did not declare an accepted runner bin target.",{packageName:a,packageVersion:i,packageRoot:n,provenance:o});const p=O(n,u),s=k(p);if(!s||!h(s))return g(c.MISSING,"Runner package bin target was not present.",{packageName:a,packageVersion:i,packageRoot:n,expectedRelativePath:u,provenance:o});const b=T(s,e.platform,e.requireExecutable);return b?g(b,B(b),{packageName:a,packageVersion:i,packageRoot:n,executablePath:s,expectedRelativePath:u,provenance:o}):w(n,a,i)?g(c.VERSION_MISMATCHED,"Runner package version did not match the development workspace root.",{packageName:a,packageVersion:i,packageRoot:n,executablePath:s,expectedRelativePath:u,provenance:o}):{ok:!0,trusted:!0,command:s,args:[],executablePath:s,packageName:a,packageVersion:i,packageRoot:n,expectedRelativePath:u,provenance:o,reasonCodes:[c.OK],publicSummary:`Resolved trusted ${o} runner for ${a}.`,publicSafe:!0}}function J(e,t={}){const r=R(e);if(!r)return f(c.MISSING,"Runner executable path was missing.");const n=k(r);if(!n||!h(n))return f(c.MISSING,"Runner executable was not present.",{executablePath:r});const l=v(d(n));if(!l)return f(c.AMBIGUOUS,"Runner executable was not inside an accepted Neocortex package.",{executablePath:n});const{packageRoot:a,pkg:i}=l,o=typeof i.name=="string"?i.name:void 0,u=typeof i.version=="string"?i.version:void 0,p=U(a,o);if(!o||!m.has(o))return f(c.AMBIGUOUS,"Runner package identity was not accepted.",{executablePath:n,packageName:o,packageVersion:u,packageRoot:a,provenance:p});if(!u||!E.test(u))return f(c.VERSION_MISMATCHED,"Runner package version was missing or invalid.",{executablePath:n,packageName:o,packageVersion:u,packageRoot:a,provenance:p});const s=P(i,o);if(!s)return f(c.MISSING,"Runner package did not declare an accepted runner bin target.",{executablePath:n,packageName:o,packageVersion:u,packageRoot:a,provenance:p});const b=k(O(a,s));if(!b||!h(b))return f(c.MISSING,"Runner package bin target was not present.",{executablePath:n,packageName:o,packageVersion:u,packageRoot:a,expectedRelativePath:s,provenance:p});if(b!==n)return f(c.AMBIGUOUS,"Runner executable did not match the package-declared bin target.",{executablePath:n,packageName:o,packageVersion:u,packageRoot:a,expectedRelativePath:s,provenance:p});const S=T(n,t.platform,t.requireExecutable);return S?f(S,B(S),{executablePath:n,packageName:o,packageVersion:u,packageRoot:a,expectedRelativePath:s,provenance:p}):w(a,o,u)?f(c.VERSION_MISMATCHED,"Runner package version did not match the development workspace root.",{executablePath:n,packageName:o,packageVersion:u,packageRoot:a,expectedRelativePath:s,provenance:p}):{trusted:!0,packageName:o,packageVersion:u,packageRoot:a,executablePath:n,expectedRelativePath:s,provenance:p,reasonCodes:[c.OK],publicSummary:`Trusted ${p} runner for ${o}.`,publicSafe:!0}}function Z(e,t){return D(e)||D(t)?H.relative(e,t).split("\\").join("/"):j(e,t).split("\\").join("/")}function z(e){if(e.packageRoot)return R(e.packageRoot);const t=R(e.from??process.argv[1]);if(!t)return null;const r=k(t);if(r)try{return x(r).isDirectory()?r:d(r)}catch{return d(r)}return d(t)}function R(e){if(!e||/[\r\n\0]/.test(e))return null;const t=I(e)?e:N(e);return I(t)?t:null}function k(e){try{return V(e)}catch{return null}}function v(e){let t=e;for(let r=0;r<10;r++){const n=A(y(t,"package.json"));if(n&&typeof n.name=="string"&&m.has(n.name))return{packageRoot:t,pkg:n};const l=d(t);if(l===t)break;t=l}return null}function M(e){let t=e;for(let r=0;r<10;r++){const n=A(y(t,"package.json"));if(n?.name==="@ornexus/neocortex")return{packageRoot:t,pkg:n};const l=d(t);if(l===t)break;t=l}return null}function A(e){try{return JSON.parse(_(e,"utf8"))}catch{return null}}function P(e,t){const r=K(e.bin)?e.bin["neocortex-runner"]:void 0;if(typeof r!="string"||r.length===0)return null;const n=F(r);return t==="@ornexus/neocortex"&&n!=="packages/client/dist/runner-cli.js"||t==="@neocortex/client"&&n!=="dist/runner-cli.js"?null:n}function F(e){return e.replace(/\\/g,"/").replace(/^\.\//,"").replace(/^\/+/,"")}function O(e,t){return N(e,...t.split("/").filter(Boolean))}function U(e,t){return t==="@ornexus/neocortex"?"published-root-package":t!=="@neocortex/client"?"published-client-package":M(d(e))?"development-workspace":"published-client-package"}function w(e,t,r){if(t!=="@neocortex/client")return!1;const n=M(d(e));return!!(n&&n.pkg.version!==r)}function T(e,t=process.platform,r=!0){try{const n=x(e);return n.isFile()?r&&t!=="win32"&&(n.mode&73)===0?c.NON_EXECUTABLE:null:c.AMBIGUOUS}catch{return c.MISSING}}function g(e,t,r={}){const n=G(r);return{ok:!1,trusted:!1,reasonCode:e,reasonCodes:[e],publicSummary:C(t),publicSafe:!0,...n}}function f(e,t,r={}){const n=G(r);return{trusted:!1,reasonCode:e,reasonCodes:[e],publicSummary:C(t),publicSafe:!0,...n}}function G(e){return{...e.packageName?{packageName:e.packageName}:{},...e.packageVersion?{packageVersion:e.packageVersion}:{},...e.expectedRelativePath?{expectedRelativePath:e.expectedRelativePath}:{},...e.provenance?{provenance:e.provenance}:{}}}function B(e){switch(e){case c.MISSING:return"Runner package bin target was not present.";case c.AMBIGUOUS:return"Runner binary candidate was ambiguous.";case c.NON_EXECUTABLE:return"Runner package bin target was not executable.";case c.VERSION_MISMATCHED:return"Runner package version did not match the development workspace root.";default:return"Runner binary trust check failed."}}function C(e){return e.length<=180?e:`${e.slice(0,180)}\u2026[TRUNCATED:${e.length-180}]`}function D(e){return/^[A-Za-z]:[\\/]/.test(e)||e.includes("\\")||$==="\\"}function K(e){return!!(e&&typeof e=="object"&&!Array.isArray(e))}export{c as RUNNER_BINARY_REASON_CODES,J as checkRunnerBinaryTrust,q as resolveTrustedRunnerBinary,Z as runnerTrustRelativePath};
@@ -6,6 +6,8 @@
6
6
  */
7
7
  import { type ContinuitySqliteAdapter, type ContinuitySqliteAdapterLoadResult } from '../continuity/sqlite-store.js';
8
8
  import { type RunnerSchedulerCommandOptions } from './scheduler.js';
9
+ export { RUNNER_BINARY_REASON_CODES, checkRunnerBinaryTrust, runnerTrustRelativePath } from './binary.js';
10
+ export type { RunnerBinaryTrustResult } from './binary.js';
9
11
  export declare const RUNNER_REASON_CODES: Readonly<{
10
12
  readonly OK: "continuity-ok";
11
13
  readonly LEASE_CONFLICT: "lease-conflict";
@@ -95,16 +97,6 @@ export interface RunnerDoctorSummary {
95
97
  readonly reasonCodes: readonly RunnerReasonCode[];
96
98
  readonly publicSafe: true;
97
99
  }
98
- export interface RunnerBinaryTrustResult {
99
- readonly trusted: boolean;
100
- readonly reasonCode?: typeof RUNNER_REASON_CODES.RUNNER_BINARY_UNTRUSTED;
101
- readonly packageName?: string;
102
- readonly packageVersion?: string;
103
- readonly packageRoot?: string;
104
- readonly executablePath?: string;
105
- readonly expectedRelativePath?: string;
106
- readonly publicSafe: true;
107
- }
108
100
  interface RunnerDirective extends Record<string, unknown> {
109
101
  readonly kind: string;
110
102
  readonly commandClass?: string;
@@ -113,9 +105,6 @@ interface RunnerDirective extends Record<string, unknown> {
113
105
  export declare function defaultRunnerServerInvoker(input: RunnerServerInvokeInput): Promise<RunnerServerInvokeResult>;
114
106
  export declare function runRunnerTick(options?: RunnerTickOptions): Promise<RunnerTickSummary>;
115
107
  export declare function runRunnerDoctor(options?: RunnerCliOptions): Promise<RunnerDoctorSummary>;
116
- export declare function checkRunnerBinaryTrust(executablePath: string | undefined): RunnerBinaryTrustResult;
117
108
  export declare function extractRunnerDirectives(metadata: Record<string, unknown> | undefined): readonly RunnerDirective[];
118
109
  export declare function assertRunnerDirectiveTrusted(directive: unknown, jobId: string): asserts directive is RunnerDirective;
119
110
  export declare function runRunnerCli(argv: readonly string[], options?: RunnerCliOptions): Promise<number>;
120
- export declare function runnerTrustRelativePath(packageRoot: string, executablePath: string): string;
121
- export {};
@@ -1,13 +1,13 @@
1
- import{createHash as ee,randomBytes as te}from"node:crypto";import{existsSync as re,readFileSync as ne,realpathSync as oe}from"node:fs";import{dirname as x,join as J,relative as ae,resolve as N}from"node:path";import{openContinuitySqliteStore as B}from"../continuity/sqlite-store.js";import{invoke as se}from"../commands/invoke.js";import{runRunnerSchedulerCommand as V}from"./scheduler.js";const d=Object.freeze({OK:"continuity-ok",LEASE_CONFLICT:"lease-conflict",LEASE_EXPIRED:"lease-expired",RUNNER_BINARY_UNTRUSTED:"runner-binary-untrusted",RUNNER_DIRECTIVE_UNTRUSTED:"runner-directive-untrusted",RUNNER_SERVER_INVOKE_FAILED:"runner-server-invoke-failed",SQLITE_ADAPTER_UNAVAILABLE:"sqlite-adapter-unavailable",SQLITE_INTEGRITY_FAILED:"sqlite-integrity-failed",BACKOFF_SCHEDULED:"backoff-scheduled",MISSED_RUN_CATCHUP:"missed-run-catchup"}),ce=300*1e3,de=30*1e3,ie=30*1e3,ue=1,le=10,q=new Set(["@ornexus/neocortex","@neocortex/client"]),fe=new Set(["append_event","append_receipt","update_job_status","schedule_next_tick","release_lease","noop"]),pe=new Set(["goal-tick","loop-tick","jobs","runner"]),me=new Set(["accepted","applied","ignored","failed","deferred"]),ye=new Set(["draft","planned","active","running","waiting_external","waiting_human","backoff","paused","blocked","completed","aborted","cancelled"]),be=/(raw[_-]?logs?|prompt(?:[_-]?(?:body|text))?|private[_-]?urls?|secret|token|password|protected(?:[_-]?(?:field|body|internals))?|workflow(?:[_-]?body)?|step(?:[_-]?body)?|customer(?:[_-]?(?:pii|data))?|authorization|api[_-]?key|license[_-]?key)/i,O=/(https?:\/\/\S+|ghp_[A-Za-z0-9_]+|sk-[A-Za-z0-9_-]+|-----BEGIN [A-Z ]*PRIVATE KEY-----|authorization\s*:|password\s*=|token\s*=|api[_-]?key\s*=|license[_-]?key\s*=|raw[_-]?log|transcript|stack trace|stderr:|stdout:|system prompt|workflow body|step body|PROTECTED_|PRIVATE_INTERNALS|CUSTOMER_PII|VENDOR_CORPUS|P180[_-]?SYNTHETIC[_-]?CONTINUITY)/i,he=/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/;async function Ie(e){const t=await se({args:e.args,projectRoot:e.projectRoot,format:"json",platformTarget:"runner",serverUrl:e.serverUrl});return{success:t.success,instructions:t.instructions,metadata:t.metadata,error:t.error,exitCode:t.exitCode}}async function ke(e={}){const t=N(e.projectRoot??process.cwd()),r=U(e.runnerId??Le(t)),n=e.now??(()=>new Date().toISOString()),o=$(e.dueJobLimit??ue,1,le),u=$(e.leaseMs??ce,1e3,3600*1e3),l=$(e.staleLeaseAfterMs??de,0,1440*60*1e3),a=e.idFactory??Ne,p=[],y=[];if(e.trustCheck!==!1&&!w(e.executablePath??process.argv[1]).trusted)return{ok:!1,runnerId:r,processedJobCount:0,dueJobCount:0,recoveredLeaseIds:[],receipts:[],reasonCodes:[d.RUNNER_BINARY_UNTRUSTED],publicSafe:!0};const i=await B({projectRoot:t,adapter:e.adapter,adapterLoader:e.adapterLoader,now:n});try{const s=i.recoverStaleLeases({nowIso:n(),staleAfterMs:l,limit:o*2});if(s.recoveredLeaseIds.length>0){p.push(d.LEASE_EXPIRED);for(const c of s.recoveredLeaseIds);}const f=i.listDueJobs({nowIso:n(),limit:o});if(f.length===0)return{ok:!0,runnerId:r,processedJobCount:0,dueJobCount:0,recoveredLeaseIds:s.recoveredLeaseIds,receipts:y,reasonCodes:j(p.length>0?p:[d.OK]),publicSafe:!0};for(const c of f){const b=await Se({store:i,job:c,projectRoot:t,runnerId:r,leaseMs:u,now:n,idFactory:a,serverUrl:e.serverUrl,serverInvoker:e.serverInvoker??Ie});y.push(b),p.push(b.reasonCode)}return{ok:y.every(c=>c.outcome!=="failed"),runnerId:r,processedJobCount:y.length,dueJobCount:f.length,recoveredLeaseIds:s.recoveredLeaseIds,receipts:y,reasonCodes:j(p.length>0?p:[d.OK]),publicSafe:!0}}finally{i.close()}}async function ge(e={}){const t=N(e.projectRoot??process.cwd()),r=e.now??(()=>new Date().toISOString()),n=r(),o={};let u=null,l=null;try{l=await B({projectRoot:t,adapter:e.adapter,adapterLoader:e.adapterLoader,now:r}),u=l.collectSnapshotRows({nowIso:n,jobLimit:10,staleLeaseLimit:10,receiptLimit:10,eventLimit:10,snapshotLimit:5});const c=String(l.pragmaValue("journal_mode")??"").toLowerCase();o["db-integrity"]=I("db-integrity","DB integrity","ok",[d.OK],"Continuity SQLite integrity check completed.",{jobs:g(u.counts,"jobs"),receipts:g(u.counts,"receipts"),events:g(u.counts,"events")}),o["sqlite-wal"]=I("sqlite-wal","SQLite WAL",c==="wal"?"ok":"blocked",c==="wal"?[d.OK]:[d.SQLITE_INTEGRITY_FAILED],c==="wal"?"SQLite journal mode is WAL.":"SQLite journal mode is not WAL."),o.migrations=I("migrations","Migrations",u.schemaVersion>=1?"ok":"blocked",u.schemaVersion>=1?[d.OK]:[d.SQLITE_INTEGRITY_FAILED],`Continuity schema version ${u.schemaVersion} is readable.`)}catch(c){const b=Y(c);o["db-integrity"]=I("db-integrity","DB integrity","blocked",[b],"Continuity SQLite could not be opened safely."),o["sqlite-wal"]=I("sqlite-wal","SQLite WAL","blocked",[b],"SQLite WAL could not be verified."),o.migrations=I("migrations","Migrations","blocked",[b],"Continuity migrations could not be verified.")}finally{if(l)try{l.close()}catch{}}const a=u?g(u.counts,"staleLeases"):0;o.leases=I("leases","Lease health",a>0?"degraded":"ok",a>0?[d.LEASE_EXPIRED]:[d.OK],a>0?"Stale leases are eligible for bounded recovery.":"No stale leases reported.",{staleLeases:a});const p=u?.outboxCounts??{},y=g(p,"failed")+g(p,"dead_letter");o.outbox=I("outbox","Outbox state",y>0?"degraded":"ok",y>0?[d.BACKOFF_SCHEDULED]:[d.OK],y>0?"Failed/dead-letter outbox entries can be retried with dedupe.":"Outbox has no failed/dead-letter entries.",{pending:g(p,"pending"),failed:g(p,"failed"),deadLetter:g(p,"dead_letter")}),o.metering=I("metering","Metering receipts","ok",[d.OK],"Metering evidence is represented by public job receipts and counts only.",{receipts:u?g(u.counts,"receipts"):0}),o["portal-sync"]=I("portal-sync","Portal sync",y>0?"degraded":"ok",y>0?[d.BACKOFF_SCHEDULED]:[d.OK],y>0?"Portal sync has retryable outbox debt.":"Portal sync outbox has no failed/dead-letter entries.");const i=e.trustCheck===!1?{trusted:!0,publicSafe:!0}:w(e.executablePath??process.argv[1]);o.runner=I("runner","Runner health",i.trusted?"ok":"blocked",i.trusted?[d.OK]:[d.RUNNER_BINARY_UNTRUSTED],i.trusted?"Runner binary trust check passed.":"Runner binary trust check failed.");try{const c=await V({command:"doctor",projectRoot:t,executablePath:e.scheduler?.executablePath??e.executablePath??process.argv[1],platform:e.scheduler?.platform,env:e.scheduler?.env,dryRun:!0,intervalSeconds:e.scheduler?.intervalSeconds,strategy:e.scheduler?.strategy,allowCronFallback:e.scheduler?.allowCronFallback,trustCheck:e.scheduler?.trustCheck??e.trustCheck,uid:e.scheduler?.uid,commandAvailable:e.scheduler?.commandAvailable,commandRunner:e.scheduler?.commandRunner,trustChecker:e.scheduler?.trustChecker??w}),b=c.reasonCodes.includes(d.RUNNER_BINARY_UNTRUSTED)||c.reasonCodes.includes("scheduler-install-unsafe");o.scheduler=I("scheduler","Scheduler install",b?"blocked":c.ok?"ok":"degraded",c.reasonCodes,c.ok?"Scheduler doctor selected a user-scope strategy.":"Scheduler doctor found public guidance or degraded capability.",{manifests:c.manifestPaths.length,controlCommands:c.controlCommands.length})}catch(c){o.scheduler=I("scheduler","Scheduler install","degraded",["scheduler-command-failed"],T(c))}const s=o,f=j(Object.values(s).flatMap(c=>c.reasonCodes));return{ok:Object.values(s).every(c=>c.status!=="blocked"),generatedAt:n,checks:s,reasonCodes:f,publicSafe:!0}}function w(e){if(!e)return S();const t=H(N(e));if(!t||!re(t))return S({executablePath:e});const r=$e(x(t));if(!r)return S({executablePath:t});const{packageRoot:n,pkg:o}=r,u=typeof o.name=="string"?o.name:void 0,l=typeof o.version=="string"?o.version:void 0;if(!u||!q.has(u)||!l||!he.test(l))return S({executablePath:t,packageName:u,packageVersion:l,packageRoot:n});const a=Fe(o,u);if(!a)return S({executablePath:t,packageName:u,packageVersion:l,packageRoot:n});const p=H(N(n,a));if(!p||p!==t)return S({executablePath:t,packageName:u,packageVersion:l,packageRoot:n,expectedRelativePath:a});const y=Pe(n);return u==="@neocortex/client"&&y&&y.pkg.version!==l?S({executablePath:t,packageName:u,packageVersion:l,packageRoot:n,expectedRelativePath:a}):{trusted:!0,packageName:u,packageVersion:l,packageRoot:n,executablePath:t,expectedRelativePath:a,publicSafe:!0}}function Ee(e){if(!e)return[];const t=[e.continuityRunnerDirectives,e.runnerDirectives,e.continuityDirectives];for(const r of t)if(Array.isArray(r))return r.filter(E).map(Te).filter(je);return[]}function Re(e,t){if(!E(e))throw new k("Directive is not a public record.");if(e.publicSafe!==!0)throw new k("Directive is not marked public-safe.");const r=typeof e.kind=="string"?e.kind:typeof e.type=="string"?e.type:"";if(!fe.has(r))throw new k("Directive kind is not allowlisted.");const n=typeof e.commandClass=="string"?e.commandClass:"runner";if(!pe.has(n))throw new k("Directive command class is not allowlisted.");if((typeof e.jobId=="string"?e.jobId:t)!==t)throw new k("Directive job ID does not match the leased job.");P(e,"directive")}async function Ye(e,t={}){const r=ve(e);if(r.command==="help")return process.stdout.write(`${Ce}
2
- `),0;if(r.command==="version"){const n=w(t.executablePath??process.argv[1]);return process.stdout.write(`${n.packageVersion??"0.0.0"}
3
- `),n.trusted?0:1}if(r.command==="doctor")try{const n=await ge({...t,projectRoot:r.projectRoot??t.projectRoot,executablePath:t.executablePath??process.argv[1],scheduler:{...t.scheduler,strategy:r.strategy??t.scheduler?.strategy,allowCronFallback:r.allowCronFallback??t.scheduler?.allowCronFallback,executablePath:t.scheduler?.executablePath??t.executablePath??process.argv[1]}});return process.stdout.write(JSON.stringify(n)+`
4
- `),n.ok?0:1}catch(n){return process.stderr.write(JSON.stringify({error_code:"runner-doctor-failed",message:T(n)})+`
5
- `),1}if(Q(r.command))try{const n=await V({command:r.command,projectRoot:r.projectRoot??t.projectRoot,executablePath:t.scheduler?.executablePath??t.executablePath??process.argv[1],platform:t.scheduler?.platform,env:t.scheduler?.env,dryRun:r.dryRun??t.scheduler?.dryRun,intervalSeconds:r.intervalSeconds??t.scheduler?.intervalSeconds,strategy:r.strategy??t.scheduler?.strategy,allowCronFallback:r.allowCronFallback??t.scheduler?.allowCronFallback,trustCheck:t.scheduler?.trustCheck,uid:t.scheduler?.uid,commandAvailable:t.scheduler?.commandAvailable,commandRunner:t.scheduler?.commandRunner,trustChecker:t.scheduler?.trustChecker??w});return process.stdout.write(JSON.stringify(n)+`
6
- `),n.ok?0:1}catch(n){return process.stderr.write(JSON.stringify({error_code:"scheduler-command-failed",message:T(n)})+`
1
+ import{createHash as z,randomBytes as H}from"node:crypto";import{resolve as K}from"node:path";import{openContinuitySqliteStore as P}from"../continuity/sqlite-store.js";import{invoke as W}from"../commands/invoke.js";import{checkRunnerBinaryTrust as v}from"./binary.js";import{runRunnerSchedulerCommand as M}from"./scheduler.js";import{RUNNER_BINARY_REASON_CODES as xe,checkRunnerBinaryTrust as Fe,runnerTrustRelativePath as Ke}from"./binary.js";const i=Object.freeze({OK:"continuity-ok",LEASE_CONFLICT:"lease-conflict",LEASE_EXPIRED:"lease-expired",RUNNER_BINARY_UNTRUSTED:"runner-binary-untrusted",RUNNER_DIRECTIVE_UNTRUSTED:"runner-directive-untrusted",RUNNER_SERVER_INVOKE_FAILED:"runner-server-invoke-failed",SQLITE_ADAPTER_UNAVAILABLE:"sqlite-adapter-unavailable",SQLITE_INTEGRITY_FAILED:"sqlite-integrity-failed",BACKOFF_SCHEDULED:"backoff-scheduled",MISSED_RUN_CATCHUP:"missed-run-catchup"}),G=300*1e3,X=30*1e3,Z=30*1e3,ee=1,te=10,re=new Set(["append_event","append_receipt","update_job_status","schedule_next_tick","release_lease","noop"]),ne=new Set(["goal-tick","loop-tick","jobs","runner"]),oe=new Set(["accepted","applied","ignored","failed","deferred"]),ae=new Set(["draft","planned","active","running","waiting_external","waiting_human","backoff","paused","blocked","completed","aborted","cancelled"]),se=/(raw[_-]?logs?|prompt(?:[_-]?(?:body|text))?|private[_-]?urls?|secret|token|password|protected(?:[_-]?(?:field|body|internals))?|workflow(?:[_-]?body)?|step(?:[_-]?body)?|customer(?:[_-]?(?:pii|data))?|authorization|api[_-]?key|license[_-]?key)/i,j=/(https?:\/\/\S+|ghp_[A-Za-z0-9_]+|sk-[A-Za-z0-9_-]+|-----BEGIN [A-Z ]*PRIVATE KEY-----|authorization\s*:|password\s*=|token\s*=|api[_-]?key\s*=|license[_-]?key\s*=|raw[_-]?log|transcript|stack trace|stderr:|stdout:|system prompt|workflow body|step body|PROTECTED_|PRIVATE_INTERNALS|CUSTOMER_PII|VENDOR_CORPUS|P180[_-]?SYNTHETIC[_-]?CONTINUITY)/i;async function de(e){const t=await W({args:e.args,projectRoot:e.projectRoot,format:"json",platformTarget:"runner",serverUrl:e.serverUrl});return{success:t.success,instructions:t.instructions,metadata:t.metadata,error:t.error,exitCode:t.exitCode}}async function ce(e={}){const t=K(e.projectRoot??process.cwd()),r=O(e.runnerId??ke(t)),n=e.now??(()=>new Date().toISOString()),o=U(e.dueJobLimit??ee,1,te),l=U(e.leaseMs??G,1e3,3600*1e3),f=U(e.staleLeaseAfterMs??X,0,1440*60*1e3),d=e.idFactory??Ee,m=[],b=[];if(e.trustCheck!==!1){const a=v(e.executablePath??process.argv[1]);if(!a.trusted)return{ok:!1,runnerId:r,processedJobCount:0,dueJobCount:0,recoveredLeaseIds:[],receipts:[],reasonCodes:[a.reasonCode??i.RUNNER_BINARY_UNTRUSTED],publicSafe:!0}}const c=await P({projectRoot:t,adapter:e.adapter,adapterLoader:e.adapterLoader,now:n});try{const a=c.recoverStaleLeases({nowIso:n(),staleAfterMs:f,limit:o*2});if(a.recoveredLeaseIds.length>0){m.push(i.LEASE_EXPIRED);for(const s of a.recoveredLeaseIds);}const u=c.listDueJobs({nowIso:n(),limit:o});if(u.length===0)return{ok:!0,runnerId:r,processedJobCount:0,dueJobCount:0,recoveredLeaseIds:a.recoveredLeaseIds,receipts:b,reasonCodes:T(m.length>0?m:[i.OK]),publicSafe:!0};for(const s of u){const y=await fe({store:c,job:s,projectRoot:t,runnerId:r,leaseMs:l,now:n,idFactory:d,serverUrl:e.serverUrl,serverInvoker:e.serverInvoker??de});b.push(y),m.push(y.reasonCode)}return{ok:b.every(s=>s.outcome!=="failed"),runnerId:r,processedJobCount:b.length,dueJobCount:u.length,recoveredLeaseIds:a.recoveredLeaseIds,receipts:b,reasonCodes:T(m.length>0?m:[i.OK]),publicSafe:!0}}finally{c.close()}}async function ie(e={}){const t=K(e.projectRoot??process.cwd()),r=e.now??(()=>new Date().toISOString()),n=r(),o={};let l=null,f=null;try{f=await P({projectRoot:t,adapter:e.adapter,adapterLoader:e.adapterLoader,now:r}),l=f.collectSnapshotRows({nowIso:n,jobLimit:10,staleLeaseLimit:10,receiptLimit:10,eventLimit:10,snapshotLimit:5});const s=String(f.pragmaValue("journal_mode")??"").toLowerCase();o["db-integrity"]=I("db-integrity","DB integrity","ok",[i.OK],"Continuity SQLite integrity check completed.",{jobs:E(l.counts,"jobs"),receipts:E(l.counts,"receipts"),events:E(l.counts,"events")}),o["sqlite-wal"]=I("sqlite-wal","SQLite WAL",s==="wal"?"ok":"blocked",s==="wal"?[i.OK]:[i.SQLITE_INTEGRITY_FAILED],s==="wal"?"SQLite journal mode is WAL.":"SQLite journal mode is not WAL."),o.migrations=I("migrations","Migrations",l.schemaVersion>=1?"ok":"blocked",l.schemaVersion>=1?[i.OK]:[i.SQLITE_INTEGRITY_FAILED],`Continuity schema version ${l.schemaVersion} is readable.`)}catch(s){const y=B(s);o["db-integrity"]=I("db-integrity","DB integrity","blocked",[y],"Continuity SQLite could not be opened safely."),o["sqlite-wal"]=I("sqlite-wal","SQLite WAL","blocked",[y],"SQLite WAL could not be verified."),o.migrations=I("migrations","Migrations","blocked",[y],"Continuity migrations could not be verified.")}finally{if(f)try{f.close()}catch{}}const d=l?E(l.counts,"staleLeases"):0;o.leases=I("leases","Lease health",d>0?"degraded":"ok",d>0?[i.LEASE_EXPIRED]:[i.OK],d>0?"Stale leases are eligible for bounded recovery.":"No stale leases reported.",{staleLeases:d});const m=l?.outboxCounts??{},b=E(m,"failed")+E(m,"dead_letter");o.outbox=I("outbox","Outbox state",b>0?"degraded":"ok",b>0?[i.BACKOFF_SCHEDULED]:[i.OK],b>0?"Failed/dead-letter outbox entries can be retried with dedupe.":"Outbox has no failed/dead-letter entries.",{pending:E(m,"pending"),failed:E(m,"failed"),deadLetter:E(m,"dead_letter")}),o.metering=I("metering","Metering receipts","ok",[i.OK],"Metering evidence is represented by public job receipts and counts only.",{receipts:l?E(l.counts,"receipts"):0}),o["portal-sync"]=I("portal-sync","Portal sync",b>0?"degraded":"ok",b>0?[i.BACKOFF_SCHEDULED]:[i.OK],b>0?"Portal sync has retryable outbox debt.":"Portal sync outbox has no failed/dead-letter entries.");const c=e.trustCheck===!1?{trusted:!0,publicSafe:!0}:v(e.executablePath??process.argv[1]);o.runner=I("runner","Runner health",c.trusted?"ok":"blocked",c.trusted?[i.OK]:[c.reasonCode??i.RUNNER_BINARY_UNTRUSTED],c.trusted?"Runner binary trust check passed.":"Runner binary trust check failed.");try{const s=await M({command:"doctor",projectRoot:t,executablePath:e.scheduler?.executablePath??e.executablePath??process.argv[1],platform:e.scheduler?.platform,env:e.scheduler?.env,dryRun:!0,intervalSeconds:e.scheduler?.intervalSeconds,strategy:e.scheduler?.strategy,allowCronFallback:e.scheduler?.allowCronFallback,trustCheck:e.scheduler?.trustCheck??e.trustCheck,uid:e.scheduler?.uid,commandAvailable:e.scheduler?.commandAvailable,commandRunner:e.scheduler?.commandRunner,trustChecker:e.scheduler?.trustChecker??v}),y=s.reasonCodes.includes(i.RUNNER_BINARY_UNTRUSTED)||s.reasonCodes.some(w=>w.startsWith("runner-binary-"))||s.reasonCodes.includes("scheduler-install-unsafe");o.scheduler=I("scheduler","Scheduler install",y?"blocked":s.ok?"ok":"degraded",s.reasonCodes,s.ok?"Scheduler doctor selected a user-scope strategy.":"Scheduler doctor found public guidance or degraded capability.",{manifests:s.manifestPaths.length,controlCommands:s.controlCommands.length,legacyEntries:s.legacyEntries.length})}catch(s){o.scheduler=I("scheduler","Scheduler install","degraded",["scheduler-command-failed"],N(s))}const a=o,u=T(Object.values(a).flatMap(s=>s.reasonCodes));return{ok:Object.values(a).every(s=>s.status!=="blocked"),generatedAt:n,checks:a,reasonCodes:u,publicSafe:!0}}function ue(e){if(!e)return[];const t=[e.continuityRunnerDirectives,e.runnerDirectives,e.continuityDirectives];for(const r of t)if(Array.isArray(r))return r.filter(R).map(Re).filter(Se);return[]}function le(e,t){if(!R(e))throw new k("Directive is not a public record.");if(e.publicSafe!==!0)throw new k("Directive is not marked public-safe.");const r=typeof e.kind=="string"?e.kind:typeof e.type=="string"?e.type:"";if(!re.has(r))throw new k("Directive kind is not allowlisted.");const n=typeof e.commandClass=="string"?e.commandClass:"runner";if(!ne.has(n))throw new k("Directive command class is not allowlisted.");if((typeof e.jobId=="string"?e.jobId:t)!==t)throw new k("Directive job ID does not match the leased job.");$(e,"directive")}async function Oe(e,t={}){const r=ye(e);if(r.command==="help")return process.stdout.write(`${be}
2
+ `),0;if(r.command==="version"){const n=v(t.executablePath??process.argv[1]);return process.stdout.write(`${n.packageVersion??"0.0.0"}
3
+ `),n.trusted?0:1}if(r.command==="doctor")try{const n=await ie({...t,projectRoot:r.projectRoot??t.projectRoot,executablePath:t.executablePath??process.argv[1],scheduler:{...t.scheduler,strategy:r.strategy??t.scheduler?.strategy,allowCronFallback:r.allowCronFallback??t.scheduler?.allowCronFallback,executablePath:t.scheduler?.executablePath??t.executablePath??process.argv[1]}});return process.stdout.write(JSON.stringify(n)+`
4
+ `),n.ok?0:1}catch(n){return process.stderr.write(JSON.stringify({error_code:"runner-doctor-failed",message:N(n)})+`
5
+ `),1}if(J(r.command))try{const n=await M({command:r.command,projectRoot:r.projectRoot??t.projectRoot,executablePath:t.scheduler?.executablePath??t.executablePath??process.argv[1],platform:t.scheduler?.platform,env:t.scheduler?.env,dryRun:r.dryRun??t.scheduler?.dryRun,intervalSeconds:r.intervalSeconds??t.scheduler?.intervalSeconds,strategy:r.strategy??t.scheduler?.strategy,allowCronFallback:r.allowCronFallback??t.scheduler?.allowCronFallback,trustCheck:t.scheduler?.trustCheck,uid:t.scheduler?.uid,commandAvailable:t.scheduler?.commandAvailable,commandRunner:t.scheduler?.commandRunner,trustChecker:t.scheduler?.trustChecker??v});return process.stdout.write(JSON.stringify(Ie(n))+`
6
+ `),n.ok?0:1}catch(n){return process.stderr.write(JSON.stringify({error_code:"scheduler-command-failed",message:N(n)})+`
7
7
  `),1}if(r.command!=="tick")return process.stderr.write(JSON.stringify({error_code:"runner-command-unknown",message:"Unknown neocortex-runner command."})+`
8
- `),1;try{const n=await ke({...t,projectRoot:r.projectRoot??t.projectRoot,runnerId:r.runnerId??t.runnerId,dueJobLimit:r.limit??t.dueJobLimit,leaseMs:r.leaseMs??t.leaseMs,staleLeaseAfterMs:r.staleLeaseAfterMs??t.staleLeaseAfterMs,serverUrl:r.serverUrl??t.serverUrl});return process.stdout.write(JSON.stringify(n)+`
9
- `),n.ok?0:1}catch(n){const o=Y(n);return process.stderr.write(JSON.stringify({error_code:o,message:T(n)})+`
10
- `),1}}async function Se(e){const{store:t,job:r,projectRoot:n,runnerId:o,leaseMs:u,now:l,idFactory:a,serverUrl:p,serverInvoker:y}=e,i=r.job_id,s=a("tick",i),f=a("lease",i),c=l(),b=new Date(Date.parse(c)+u).toISOString();let K=!1,M=!1,h=d.OK,v="applied",R=[];if(!t.acquireLease({leaseId:f,jobId:i,runnerId:o,acquiredAt:c,expiresAt:b,operationId:`${s}:acquire`,idempotencyKey:`${s}:acquire`,metadata:A({jobId:i,operationId:s,runnerId:o,leaseId:f,status:"running",reasonCode:d.OK})}).inserted)return D(t,{jobId:i,tickId:s,leaseId:f,status:"ignored",reasonCode:d.LEASE_CONFLICT,createdAt:l(),redactionSummary:R});K=!0;try{t.appendEvent({eventId:`${s}:started`,jobId:i,operationId:`${s}:event:started`,idempotencyKey:`${s}:event:started`,type:"runner_tick_started",summary:`Runner tick started for ${i}.`,reasonCode:d.OK,createdAt:c,metadata:A({jobId:i,operationId:s,runnerId:o,leaseId:f,status:"running",reasonCode:d.OK})});const W=r.kind==="loop"?`*loop tick @${i} --tick-id ${s} --lease-id ${f} --runner-id ${o}`:r.kind==="goal"?`*goal tick @${i} --tick-id ${s} --lease-id ${f} --runner-id ${o}`:`*runner tick --job-id ${i} --tick-id ${s} --lease-id ${f} --runner-id ${o}`,L=await y({projectRoot:n,args:W,jobId:i,tickId:s,leaseId:f,runnerId:o,serverUrl:p});if(!L.success){h=d.RUNNER_SERVER_INVOKE_FAILED,v="failed";const _=l();return t.updateJobStatus({jobId:i,status:"backoff",updatedAt:_,reasonCode:d.BACKOFF_SCHEDULED,nextRunAt:De(_,ie)}),t.appendEvent({eventId:`${s}:server-failed`,jobId:i,operationId:`${s}:event:server-failed`,idempotencyKey:`${s}:event:server-failed`,type:"runner_tick_failed",summary:"Runner server tick invocation failed with public reason code.",reasonCode:h,createdAt:_,metadata:A({jobId:i,operationId:s,runnerId:o,leaseId:f,status:"failed",reasonCode:h})}),D(t,{jobId:i,tickId:s,leaseId:f,status:v,reasonCode:h,createdAt:l(),redactionSummary:R})}const X=Ee(L.metadata);let C={appliedCount:0,releasedLease:!1,changedStatus:!1,redactionSummary:[]};try{C=_e(t,X,{jobId:i,tickId:s,leaseId:f,runnerId:o,now:l}),M=C.releasedLease,R=[...C.redactionSummary],h=Ae(L.metadata)??h}catch(_){return h=d.RUNNER_DIRECTIVE_UNTRUSTED,v="failed",R=[_ instanceof Error?_.message:"Directive rejected."],t.updateJobStatus({jobId:i,status:"blocked",updatedAt:l(),reasonCode:h}),t.appendEvent({eventId:`${s}:directive-rejected`,jobId:i,operationId:`${s}:event:directive-rejected`,idempotencyKey:`${s}:event:directive-rejected`,type:"runner_directive_rejected",summary:"Runner rejected an untrusted continuity directive.",reasonCode:h,createdAt:l(),metadata:A({jobId:i,operationId:s,runnerId:o,leaseId:f,status:"failed",reasonCode:h,redactionSummary:R})}),D(t,{jobId:i,tickId:s,leaseId:f,status:v,reasonCode:h,createdAt:l(),redactionSummary:R})}const Z=!!L.metadata?.continuityStateUpdate;return!C.changedStatus&&!Z&&t.updateJobStatus({jobId:i,status:"active",updatedAt:l(),reasonCode:d.OK}),t.appendEvent({eventId:`${s}:completed`,jobId:i,operationId:`${s}:event:completed`,idempotencyKey:`${s}:event:completed`,type:"runner_tick_completed",summary:`Runner tick completed with ${C.appliedCount} public directive(s).`,reasonCode:h,createdAt:l(),metadata:A({jobId:i,operationId:s,runnerId:o,leaseId:f,status:"applied",reasonCode:h})}),D(t,{jobId:i,tickId:s,leaseId:f,status:v,reasonCode:h,createdAt:l(),redactionSummary:R})}finally{if(K&&!M)try{t.releaseLease({leaseId:f,releasedAt:l(),reasonCode:h})}catch{}}}function _e(e,t,r){let n=0,o=!1,u=!1;const l=[];for(const a of t){switch(Re(a,r.jobId),a.kind){case"noop":n+=1;break;case"append_event":e.appendEvent({eventId:m(a,"eventId")??`${r.tickId}:directive:${n}:event`,jobId:r.jobId,operationId:m(a,"operationId")??`${r.tickId}:directive:${n}:event`,idempotencyKey:m(a,"idempotencyKey")??`${r.tickId}:directive:${n}:event`,type:m(a,"eventType")??"runner_directive_event",summary:m(a,"summary")??"Runner applied public continuity event directive.",reasonCode:m(a,"reasonCode")??d.OK,createdAt:m(a,"createdAt")??r.now(),metadata:z(a)}),n+=1;break;case"append_receipt":e.appendReceipt({receiptId:m(a,"receiptId")??`${r.tickId}:directive:${n}:receipt`,jobId:r.jobId,operationId:m(a,"operationId")??`${r.tickId}:directive:${n}:receipt`,idempotencyKey:m(a,"idempotencyKey")??`${r.tickId}:directive:${n}:receipt`,status:Oe(m(a,"status")),reasonCode:m(a,"reasonCode")??d.OK,createdAt:m(a,"createdAt")??r.now(),metadata:z(a)}),n+=1;break;case"update_job_status":e.updateJobStatus({jobId:r.jobId,status:Ue(m(a,"status")),updatedAt:m(a,"updatedAt")??r.now(),reasonCode:m(a,"reasonCode")??d.OK,nextRunAt:m(a,"nextRunAt")}),n+=1,u=!0;break;case"schedule_next_tick":e.scheduleNextTick({jobId:r.jobId,scheduledAt:xe(a,"scheduledAt"),updatedAt:m(a,"updatedAt")??r.now(),reasonCode:m(a,"reasonCode")??d.OK}),n+=1,u=!0;break;case"release_lease":e.releaseLease({leaseId:m(a,"leaseId")??r.leaseId,releasedAt:m(a,"releasedAt")??r.now(),reasonCode:m(a,"reasonCode")??d.OK}),n+=1,o=!0;break}const p=a.redactionSummary;Array.isArray(p)&&l.push(...p.filter(y=>typeof y=="string").slice(0,5))}return{appliedCount:n,releasedLease:o,changedStatus:u,redactionSummary:l}}function D(e,t){const r={receiptId:`receipt-${U(t.tickId)}`,jobId:t.jobId,operationId:t.tickId,idempotencyKey:t.tickId,status:t.status,reasonCode:t.reasonCode,appliedOperationIds:t.status==="applied"?[t.tickId]:void 0,ignoredOperationIds:t.status==="ignored"?[t.tickId]:void 0,createdAt:t.createdAt,metadata:A({jobId:t.jobId,operationId:t.tickId,leaseId:t.leaseId,status:t.status,reasonCode:t.reasonCode,redactionSummary:t.redactionSummary})};return e.appendReceipt(r),{jobId:t.jobId,tickId:t.tickId,leaseId:t.leaseId,outcome:t.status,reasonCode:t.reasonCode,timestamp:t.createdAt,redactionSummary:t.redactionSummary,publicSafe:!0}}function A(e){return{schemaVersion:1,contractVersion:"continuity-v1",jobId:e.jobId,operationId:e.operationId,...e.runnerId?{runnerId:e.runnerId}:{},...e.leaseId?{leaseId:e.leaseId}:{},status:e.status,reasonCode:e.reasonCode,redactionEvidence:(e.redactionSummary??[]).slice(0,20).map(t=>({field:F(t,80),reason:"unsafe_key",evidence:"operation-denied",publicSafe:!0}))}}function Ae(e){if(!e)return null;const t=E(e.continuity)?e.continuity:void 0,n=[(t&&E(t.loop)?t.loop:void 0)?.reasonCode,t?.reasonCode];for(const o of n)if(typeof o=="string"&&/^[a-z0-9][a-z0-9-]{0,79}$/.test(o)&&!O.test(o))return o;return null}function ve(e){const t=e[0];if(!t||t==="--help"||t==="-h"||t==="help")return{command:"help"};if(t==="--version"||t==="-v"||t==="version")return{command:"version"};if(t!=="tick"&&!Q(t))return{command:"unknown"};let r,n,o,u,l,a,p,y,i,s;for(let f=1;f<e.length;f++){const c=e[f],b=e[f+1];if(c==="--project-root"){r=b,f+=1;continue}if(c==="--runner-id"){n=b,f+=1;continue}if(c==="--server-url"){o=b,f+=1;continue}if(c==="--limit"){u=Number(b),f+=1;continue}if(c==="--lease-ms"){l=Number(b),f+=1;continue}if(c==="--stale-lease-after-ms"){a=Number(b),f+=1;continue}if(c==="--dry-run"){p=!0;continue}if(c==="--interval-seconds"){y=Number(b),f+=1;continue}if(c==="--strategy"&&we(b)){i=b,f+=1;continue}if(c==="--allow-cron-fallback"){s=!0;continue}if(c==="--no-cron-fallback"){s=!1;continue}}return{command:t,projectRoot:r,runnerId:n,serverUrl:o,limit:u,leaseMs:l,staleLeaseAfterMs:a,dryRun:p,intervalSeconds:y,strategy:i,allowCronFallback:s}}const Ce=`
8
+ `),1;try{const n=await ce({...t,projectRoot:r.projectRoot??t.projectRoot,runnerId:r.runnerId??t.runnerId,dueJobLimit:r.limit??t.dueJobLimit,leaseMs:r.leaseMs??t.leaseMs,staleLeaseAfterMs:r.staleLeaseAfterMs??t.staleLeaseAfterMs,serverUrl:r.serverUrl??t.serverUrl});return process.stdout.write(JSON.stringify(n)+`
9
+ `),n.ok?0:1}catch(n){const o=B(n);return process.stderr.write(JSON.stringify({error_code:o,message:N(n)})+`
10
+ `),1}}async function fe(e){const{store:t,job:r,projectRoot:n,runnerId:o,leaseMs:l,now:f,idFactory:d,serverUrl:m,serverInvoker:b}=e,c=r.job_id,a=d("tick",c),u=d("lease",c),s=f(),y=new Date(Date.parse(s)+l).toISOString();let w=!1,F=!1,h=i.OK,C="applied",g=[];if(!t.acquireLease({leaseId:u,jobId:c,runnerId:o,acquiredAt:s,expiresAt:y,operationId:`${a}:acquire`,idempotencyKey:`${a}:acquire`,metadata:_({jobId:c,operationId:a,runnerId:o,leaseId:u,status:"running",reasonCode:i.OK})}).inserted)return D(t,{jobId:c,tickId:a,leaseId:u,status:"ignored",reasonCode:i.LEASE_CONFLICT,createdAt:f(),redactionSummary:g});w=!0;try{t.appendEvent({eventId:`${a}:started`,jobId:c,operationId:`${a}:event:started`,idempotencyKey:`${a}:event:started`,type:"runner_tick_started",summary:`Runner tick started for ${c}.`,reasonCode:i.OK,createdAt:s,metadata:_({jobId:c,operationId:a,runnerId:o,leaseId:u,status:"running",reasonCode:i.OK})});const q=r.kind==="loop"?`*loop tick @${c} --tick-id ${a} --lease-id ${u} --runner-id ${o}`:r.kind==="goal"?`*goal tick @${c} --tick-id ${a} --lease-id ${u} --runner-id ${o}`:`*runner tick --job-id ${c} --tick-id ${a} --lease-id ${u} --runner-id ${o}`,L=await b({projectRoot:n,args:q,jobId:c,tickId:a,leaseId:u,runnerId:o,serverUrl:m});if(!L.success){h=i.RUNNER_SERVER_INVOKE_FAILED,C="failed";const S=f();return t.updateJobStatus({jobId:c,status:"backoff",updatedAt:S,reasonCode:i.BACKOFF_SCHEDULED,nextRunAt:ge(S,Z)}),t.appendEvent({eventId:`${a}:server-failed`,jobId:c,operationId:`${a}:event:server-failed`,idempotencyKey:`${a}:event:server-failed`,type:"runner_tick_failed",summary:"Runner server tick invocation failed with public reason code.",reasonCode:h,createdAt:S,metadata:_({jobId:c,operationId:a,runnerId:o,leaseId:u,status:"failed",reasonCode:h})}),D(t,{jobId:c,tickId:a,leaseId:u,status:C,reasonCode:h,createdAt:f(),redactionSummary:g})}const Q=ue(L.metadata);let A={appliedCount:0,releasedLease:!1,changedStatus:!1,redactionSummary:[]};try{A=pe(t,Q,{jobId:c,tickId:a,leaseId:u,runnerId:o,now:f}),F=A.releasedLease,g=[...A.redactionSummary],h=me(L.metadata)??h}catch(S){return h=i.RUNNER_DIRECTIVE_UNTRUSTED,C="failed",g=[S instanceof Error?S.message:"Directive rejected."],t.updateJobStatus({jobId:c,status:"blocked",updatedAt:f(),reasonCode:h}),t.appendEvent({eventId:`${a}:directive-rejected`,jobId:c,operationId:`${a}:event:directive-rejected`,idempotencyKey:`${a}:event:directive-rejected`,type:"runner_directive_rejected",summary:"Runner rejected an untrusted continuity directive.",reasonCode:h,createdAt:f(),metadata:_({jobId:c,operationId:a,runnerId:o,leaseId:u,status:"failed",reasonCode:h,redactionSummary:g})}),D(t,{jobId:c,tickId:a,leaseId:u,status:C,reasonCode:h,createdAt:f(),redactionSummary:g})}const Y=!!L.metadata?.continuityStateUpdate;return!A.changedStatus&&!Y&&t.updateJobStatus({jobId:c,status:"active",updatedAt:f(),reasonCode:i.OK}),t.appendEvent({eventId:`${a}:completed`,jobId:c,operationId:`${a}:event:completed`,idempotencyKey:`${a}:event:completed`,type:"runner_tick_completed",summary:`Runner tick completed with ${A.appliedCount} public directive(s).`,reasonCode:h,createdAt:f(),metadata:_({jobId:c,operationId:a,runnerId:o,leaseId:u,status:"applied",reasonCode:h})}),D(t,{jobId:c,tickId:a,leaseId:u,status:C,reasonCode:h,createdAt:f(),redactionSummary:g})}finally{if(w&&!F)try{t.releaseLease({leaseId:u,releasedAt:f(),reasonCode:h})}catch{}}}function pe(e,t,r){let n=0,o=!1,l=!1;const f=[];for(const d of t){switch(le(d,r.jobId),d.kind){case"noop":n+=1;break;case"append_event":e.appendEvent({eventId:p(d,"eventId")??`${r.tickId}:directive:${n}:event`,jobId:r.jobId,operationId:p(d,"operationId")??`${r.tickId}:directive:${n}:event`,idempotencyKey:p(d,"idempotencyKey")??`${r.tickId}:directive:${n}:event`,type:p(d,"eventType")??"runner_directive_event",summary:p(d,"summary")??"Runner applied public continuity event directive.",reasonCode:p(d,"reasonCode")??i.OK,createdAt:p(d,"createdAt")??r.now(),metadata:V(d)}),n+=1;break;case"append_receipt":e.appendReceipt({receiptId:p(d,"receiptId")??`${r.tickId}:directive:${n}:receipt`,jobId:r.jobId,operationId:p(d,"operationId")??`${r.tickId}:directive:${n}:receipt`,idempotencyKey:p(d,"idempotencyKey")??`${r.tickId}:directive:${n}:receipt`,status:Ce(p(d,"status")),reasonCode:p(d,"reasonCode")??i.OK,createdAt:p(d,"createdAt")??r.now(),metadata:V(d)}),n+=1;break;case"update_job_status":e.updateJobStatus({jobId:r.jobId,status:Ae(p(d,"status")),updatedAt:p(d,"updatedAt")??r.now(),reasonCode:p(d,"reasonCode")??i.OK,nextRunAt:p(d,"nextRunAt")}),n+=1,l=!0;break;case"schedule_next_tick":e.scheduleNextTick({jobId:r.jobId,scheduledAt:_e(d,"scheduledAt"),updatedAt:p(d,"updatedAt")??r.now(),reasonCode:p(d,"reasonCode")??i.OK}),n+=1,l=!0;break;case"release_lease":e.releaseLease({leaseId:p(d,"leaseId")??r.leaseId,releasedAt:p(d,"releasedAt")??r.now(),reasonCode:p(d,"reasonCode")??i.OK}),n+=1,o=!0;break}const m=d.redactionSummary;Array.isArray(m)&&f.push(...m.filter(b=>typeof b=="string").slice(0,5))}return{appliedCount:n,releasedLease:o,changedStatus:l,redactionSummary:f}}function D(e,t){const r={receiptId:`receipt-${O(t.tickId)}`,jobId:t.jobId,operationId:t.tickId,idempotencyKey:t.tickId,status:t.status,reasonCode:t.reasonCode,appliedOperationIds:t.status==="applied"?[t.tickId]:void 0,ignoredOperationIds:t.status==="ignored"?[t.tickId]:void 0,createdAt:t.createdAt,metadata:_({jobId:t.jobId,operationId:t.tickId,leaseId:t.leaseId,status:t.status,reasonCode:t.reasonCode,redactionSummary:t.redactionSummary})};return e.appendReceipt(r),{jobId:t.jobId,tickId:t.tickId,leaseId:t.leaseId,outcome:t.status,reasonCode:t.reasonCode,timestamp:t.createdAt,redactionSummary:t.redactionSummary,publicSafe:!0}}function _(e){return{schemaVersion:1,contractVersion:"continuity-v1",jobId:e.jobId,operationId:e.operationId,...e.runnerId?{runnerId:e.runnerId}:{},...e.leaseId?{leaseId:e.leaseId}:{},status:e.status,reasonCode:e.reasonCode,redactionEvidence:(e.redactionSummary??[]).slice(0,20).map(t=>({field:x(t,80),reason:"unsafe_key",evidence:"operation-denied",publicSafe:!0}))}}function me(e){if(!e)return null;const t=R(e.continuity)?e.continuity:void 0,n=[(t&&R(t.loop)?t.loop:void 0)?.reasonCode,t?.reasonCode];for(const o of n)if(typeof o=="string"&&/^[a-z0-9][a-z0-9-]{0,79}$/.test(o)&&!j.test(o))return o;return null}function ye(e){const t=e[0];if(!t||t==="--help"||t==="-h"||t==="help")return{command:"help"};if(t==="--version"||t==="-v"||t==="version")return{command:"version"};if(t!=="tick"&&!J(t))return{command:"unknown"};let r,n,o,l,f,d,m,b,c,a;for(let u=1;u<e.length;u++){const s=e[u],y=e[u+1];if(s==="--project-root"){r=y,u+=1;continue}if(s==="--runner-id"){n=y,u+=1;continue}if(s==="--server-url"){o=y,u+=1;continue}if(s==="--limit"){l=Number(y),u+=1;continue}if(s==="--lease-ms"){f=Number(y),u+=1;continue}if(s==="--stale-lease-after-ms"){d=Number(y),u+=1;continue}if(s==="--dry-run"){m=!0;continue}if(s==="--interval-seconds"){b=Number(y),u+=1;continue}if(s==="--strategy"&&he(y)){c=y,u+=1;continue}if(s==="--allow-cron-fallback"){a=!0;continue}if(s==="--no-cron-fallback"){a=!1;continue}}return{command:t,projectRoot:r,runnerId:n,serverUrl:o,limit:l,leaseMs:f,staleLeaseAfterMs:d,dryRun:m,intervalSeconds:b,strategy:c,allowCronFallback:a}}const be=`
11
11
  neocortex-runner - Enterprise continuity local runner
12
12
 
13
13
  Usage:
@@ -17,4 +17,4 @@ Usage:
17
17
  neocortex-runner tick [--project-root <path>] [--limit <n>] [--lease-ms <ms>] [--stale-lease-after-ms <ms>]
18
18
  neocortex-runner --version
19
19
  neocortex-runner --help
20
- `.trim();function Q(e){return e==="install"||e==="start"||e==="stop"||e==="status"||e==="doctor"}function we(e){return e==="systemd-user"||e==="launchd-user"||e==="windows-task-scheduler"||e==="cron-fallback"}class k extends Error{constructor(t){super(t),this.name="RunnerDirectiveError"}}function Y(e){if(E(e)){const r=typeof e.reasonCode=="string"?e.reasonCode:typeof e.code=="string"?e.code:void 0;if(r===d.SQLITE_ADAPTER_UNAVAILABLE||r===d.SQLITE_INTEGRITY_FAILED)return r}const t=e instanceof Error?e.message:String(e);return/sqlite-adapter-unavailable/i.test(t)?d.SQLITE_ADAPTER_UNAVAILABLE:/sqlite-integrity-failed|not a database|file is not a database|database disk image is malformed|malformed/i.test(t)?d.SQLITE_INTEGRITY_FAILED:"runner-tick-failed"}function T(e){return F(e instanceof Error?e.message:String(e),240)}function Le(e){return`runner-${ee("sha256").update(e).update(process.pid.toString()).digest("hex").slice(0,12)}`}function Ne(e,t){const r=te(4).toString("hex");return`${e}-${U(t)}-${Date.now()}-${r}`}function U(e){return e.replace(/[^a-z0-9_.:-]+/gi,"-").slice(0,120)}function $(e,t,r){return Number.isFinite(e)?Math.max(t,Math.min(r,Math.floor(e))):t}function De(e,t){const r=Date.parse(e);return new Date((Number.isFinite(r)?r:Date.now())+t).toISOString()}function Te(e){return typeof e.kind=="string"?e:{...e,kind:e.type}}function je(e){return typeof e.kind=="string"&&e.publicSafe===!0}function P(e,t){if(typeof e=="string"){if(O.test(e))throw new k(`Unsafe directive value at ${t}.`);return}if(!(e===null||typeof e=="number"||typeof e=="boolean")){if(Array.isArray(e)){e.forEach((r,n)=>P(r,`${t}[${n}]`));return}if(E(e)){for(const[r,n]of Object.entries(e)){if(be.test(r))throw new k(`Unsafe directive key at ${t}.${r}.`);P(n,`${t}.${r}`)}return}throw new k(`Unsupported directive value at ${t}.`)}}function m(e,t){const r=e[t];return typeof r=="string"&&r.length>0?r:void 0}function xe(e,t){const r=m(e,t);if(!r)throw new k(`Directive missing ${t}.`);return r}function z(e){const t=e.metadata;return E(t)?t:void 0}function Oe(e){return e&&me.has(e)?e:"applied"}function Ue(e){if(!e||!ye.has(e))throw new k("Directive status is not allowlisted.");return e}function E(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function j(e){return Array.from(new Set(e))}function g(e,t){return typeof e[t]=="number"?e[t]:0}function I(e,t,r,n,o,u){return{id:e,label:t,status:r,reasonCodes:j(n.length>0?n:[d.OK]),summary:F(o,180),...u?{counts:u}:{},publicSafe:!0}}function F(e,t){const r=O.test(e)?"[REDACTED]":e;return r.length<=t?r:`${r.slice(0,t)}\u2026[TRUNCATED:${r.length-t}]`}function H(e){try{return oe(e)}catch{return null}}function $e(e){let t=e;for(let r=0;r<8;r++){const n=G(J(t,"package.json"));if(n&&typeof n.name=="string"&&q.has(n.name))return{packageRoot:t,pkg:n};const o=x(t);if(o===t)break;t=o}return null}function Pe(e){let t=e;for(let r=0;r<8;r++){const n=G(J(t,"package.json"));if(n?.name==="@ornexus/neocortex")return{packageRoot:t,pkg:n};const o=x(t);if(o===t)break;t=o}return null}function G(e){try{return JSON.parse(ne(e,"utf8"))}catch{return null}}function Fe(e,t){const r=E(e.bin)?e.bin["neocortex-runner"]:void 0;if(typeof r!="string"||r.length===0)return null;const n=r.replace(/^\.\//,"");return t==="@ornexus/neocortex"&&n!=="packages/client/dist/runner-cli.js"||t==="@neocortex/client"&&n!=="dist/runner-cli.js"?null:n}function S(e={}){return{trusted:!1,reasonCode:d.RUNNER_BINARY_UNTRUSTED,publicSafe:!0,...e}}function ze(e,t){return ae(e,t).split("\\").join("/")}export{ue as DEFAULT_DUE_JOB_LIMIT,ie as DEFAULT_RUNNER_BACKOFF_MS,ce as DEFAULT_RUNNER_LEASE_MS,de as DEFAULT_STALE_LEASE_AFTER_MS,le as MAX_DUE_JOB_LIMIT,d as RUNNER_REASON_CODES,Re as assertRunnerDirectiveTrusted,w as checkRunnerBinaryTrust,Ie as defaultRunnerServerInvoker,Ee as extractRunnerDirectives,Ye as runRunnerCli,ge as runRunnerDoctor,ke as runRunnerTick,ze as runnerTrustRelativePath};
20
+ `.trim();function J(e){return e==="install"||e==="start"||e==="stop"||e==="status"||e==="doctor"}function he(e){return e==="systemd-user"||e==="launchd-user"||e==="windows-task-scheduler"||e==="cron-fallback"}class k extends Error{constructor(t){super(t),this.name="RunnerDirectiveError"}}function B(e){if(R(e)){const r=typeof e.reasonCode=="string"?e.reasonCode:typeof e.code=="string"?e.code:void 0;if(r===i.SQLITE_ADAPTER_UNAVAILABLE||r===i.SQLITE_INTEGRITY_FAILED)return r}const t=e instanceof Error?e.message:String(e);return/sqlite-adapter-unavailable/i.test(t)?i.SQLITE_ADAPTER_UNAVAILABLE:/sqlite-integrity-failed|not a database|file is not a database|database disk image is malformed|malformed/i.test(t)?i.SQLITE_INTEGRITY_FAILED:"runner-tick-failed"}function N(e){return x(e instanceof Error?e.message:String(e),240)}function Ie(e){return e.manifests.length===0?e:{...e,manifests:e.manifests.map(t=>({...t,content:`[redacted ${t.kind} for project ${e.identity.projectKey}]`}))}}function ke(e){return`runner-${z("sha256").update(e).update(process.pid.toString()).digest("hex").slice(0,12)}`}function Ee(e,t){const r=H(4).toString("hex");return`${e}-${O(t)}-${Date.now()}-${r}`}function O(e){return e.replace(/[^a-z0-9_.:-]+/gi,"-").slice(0,120)}function U(e,t,r){return Number.isFinite(e)?Math.max(t,Math.min(r,Math.floor(e))):t}function ge(e,t){const r=Date.parse(e);return new Date((Number.isFinite(r)?r:Date.now())+t).toISOString()}function Re(e){return typeof e.kind=="string"?e:{...e,kind:e.type}}function Se(e){return typeof e.kind=="string"&&e.publicSafe===!0}function $(e,t){if(typeof e=="string"){if(j.test(e))throw new k(`Unsafe directive value at ${t}.`);return}if(!(e===null||typeof e=="number"||typeof e=="boolean")){if(Array.isArray(e)){e.forEach((r,n)=>$(r,`${t}[${n}]`));return}if(R(e)){for(const[r,n]of Object.entries(e)){if(se.test(r))throw new k(`Unsafe directive key at ${t}.${r}.`);$(n,`${t}.${r}`)}return}throw new k(`Unsupported directive value at ${t}.`)}}function p(e,t){const r=e[t];return typeof r=="string"&&r.length>0?r:void 0}function _e(e,t){const r=p(e,t);if(!r)throw new k(`Directive missing ${t}.`);return r}function V(e){const t=e.metadata;return R(t)?t:void 0}function Ce(e){return e&&oe.has(e)?e:"applied"}function Ae(e){if(!e||!ae.has(e))throw new k("Directive status is not allowlisted.");return e}function R(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function T(e){return Array.from(new Set(e))}function E(e,t){return typeof e[t]=="number"?e[t]:0}function I(e,t,r,n,o,l){return{id:e,label:t,status:r,reasonCodes:T(n.length>0?n:[i.OK]),summary:x(o,180),...l?{counts:l}:{},publicSafe:!0}}function x(e,t){const r=j.test(e)?"[REDACTED]":e;return r.length<=t?r:`${r.slice(0,t)}\u2026[TRUNCATED:${r.length-t}]`}export{ee as DEFAULT_DUE_JOB_LIMIT,Z as DEFAULT_RUNNER_BACKOFF_MS,G as DEFAULT_RUNNER_LEASE_MS,X as DEFAULT_STALE_LEASE_AFTER_MS,te as MAX_DUE_JOB_LIMIT,xe as RUNNER_BINARY_REASON_CODES,i as RUNNER_REASON_CODES,le as assertRunnerDirectiveTrusted,Fe as checkRunnerBinaryTrust,de as defaultRunnerServerInvoker,ue as extractRunnerDirectives,Oe as runRunnerCli,ie as runRunnerDoctor,ce as runRunnerTick,Ke as runnerTrustRelativePath};
@@ -5,6 +5,7 @@
5
5
  * P180.07 -- user-scope scheduler install/start/stop/status/doctor for
6
6
  * `neocortex-runner`.
7
7
  */
8
+ import { type RunnerBinaryResolveOptions, type RunnerBinaryResolution } from './binary.js';
8
9
  export declare const SCHEDULER_REASON_CODES: Readonly<{
9
10
  readonly OK: "continuity-ok";
10
11
  readonly SCHEDULER_INSTALL_UNSAFE: "scheduler-install-unsafe";
@@ -14,17 +15,39 @@ export declare const SCHEDULER_REASON_CODES: Readonly<{
14
15
  readonly SCHEDULER_UNAVAILABLE: "scheduler-unavailable";
15
16
  readonly SCHEDULER_COMMAND_FAILED: "scheduler-command-failed";
16
17
  readonly RUNNER_BINARY_UNTRUSTED: "runner-binary-untrusted";
18
+ readonly LEGACY_GLOBAL_SCHEDULER_DETECTED: "legacy-global-scheduler-detected";
19
+ readonly LEGACY_GLOBAL_SCHEDULER_AMBIGUOUS: "legacy-global-scheduler-ambiguous";
20
+ readonly LEGACY_GLOBAL_SCHEDULER_OTHER_PROJECT: "legacy-global-scheduler-other-project";
21
+ }>;
22
+ export declare const RUNNER_SCHEDULER_BOOTSTRAP_REASON_CODES: Readonly<{
23
+ readonly OK: "runner-bootstrap-ok";
24
+ readonly ALREADY_ACTIVE: "runner-bootstrap-already-active";
25
+ readonly BINARY_UNAVAILABLE: "runner-bootstrap-binary-unavailable";
26
+ readonly INSTALL_FAILED: "runner-bootstrap-install-failed";
27
+ readonly START_FAILED: "runner-bootstrap-start-failed";
28
+ readonly UNEXPECTED_ERROR: "runner-bootstrap-unexpected-error";
17
29
  }>;
18
30
  export type SchedulerReasonCode = (typeof SCHEDULER_REASON_CODES)[keyof typeof SCHEDULER_REASON_CODES] | string;
31
+ export type RunnerSchedulerBootstrapReasonCode = (typeof RUNNER_SCHEDULER_BOOTSTRAP_REASON_CODES)[keyof typeof RUNNER_SCHEDULER_BOOTSTRAP_REASON_CODES] | SchedulerReasonCode;
19
32
  export type SchedulerCommand = 'install' | 'start' | 'stop' | 'status' | 'doctor';
20
33
  export type SchedulerStrategy = 'systemd-user' | 'launchd-user' | 'windows-task-scheduler' | 'cron-fallback';
21
34
  export interface SchedulerBinaryTrustResult {
22
35
  readonly trusted: boolean;
23
36
  readonly reasonCode?: string;
37
+ readonly reasonCodes?: readonly string[];
24
38
  readonly packageName?: string;
25
39
  readonly packageVersion?: string;
40
+ readonly packageRoot?: string;
26
41
  readonly executablePath?: string;
27
42
  readonly expectedRelativePath?: string;
43
+ readonly provenance?: string;
44
+ readonly publicSafe: true;
45
+ }
46
+ export interface SchedulerRunnerCommand {
47
+ readonly command: string;
48
+ readonly args: readonly string[];
49
+ readonly executablePath: string;
50
+ readonly provenance?: string;
28
51
  readonly publicSafe: true;
29
52
  }
30
53
  export interface SchedulerManifest {
@@ -40,6 +63,32 @@ export interface SchedulerControlCommand {
40
63
  readonly safeUserScope: true;
41
64
  readonly manualOnly?: boolean;
42
65
  }
66
+ export interface SchedulerProjectIdentity {
67
+ readonly projectKey: string;
68
+ readonly projectBasename: string;
69
+ readonly systemdServiceName: string;
70
+ readonly systemdTimerName: string;
71
+ readonly systemdServiceFile: string;
72
+ readonly systemdTimerFile: string;
73
+ readonly launchdLabel: string;
74
+ readonly launchdFile: string;
75
+ readonly windowsTaskName: string;
76
+ readonly windowsXmlFile: string;
77
+ readonly cronFile: string;
78
+ readonly cronMarkerStart: string;
79
+ readonly cronMarkerEnd: string;
80
+ readonly publicSafe: true;
81
+ }
82
+ export type SchedulerLegacyRelation = 'current-project' | 'ambiguous' | 'other-project';
83
+ export interface SchedulerLegacyEntry {
84
+ readonly strategy: SchedulerStrategy;
85
+ readonly kind: SchedulerManifest['kind'];
86
+ readonly name: string;
87
+ readonly relation: SchedulerLegacyRelation;
88
+ readonly reasonCodes: readonly SchedulerReasonCode[];
89
+ readonly remediation: 'stop-safe' | 'manual-review-only' | 'report-only';
90
+ readonly publicSafe: true;
91
+ }
43
92
  export interface SchedulerCommandRunResult {
44
93
  readonly ok: boolean;
45
94
  readonly code?: number | null;
@@ -73,6 +122,7 @@ export interface RunnerSchedulerCommandOptions {
73
122
  readonly commandAvailable?: (command: string) => boolean;
74
123
  readonly commandRunner?: (command: SchedulerControlCommand) => SchedulerCommandRunResult;
75
124
  readonly trustChecker?: (executablePath: string | undefined) => SchedulerBinaryTrustResult;
125
+ readonly binaryResolver?: (options: RunnerBinaryResolveOptions) => RunnerBinaryResolution;
76
126
  readonly now?: () => string;
77
127
  }
78
128
  export interface RunnerSchedulerCommandResult {
@@ -83,6 +133,8 @@ export interface RunnerSchedulerCommandResult {
83
133
  readonly dryRun: boolean;
84
134
  readonly manifestPaths: readonly string[];
85
135
  readonly manifests: readonly SchedulerManifest[];
136
+ readonly identity: SchedulerProjectIdentity;
137
+ readonly legacyEntries: readonly SchedulerLegacyEntry[];
86
138
  readonly controlCommands: readonly SchedulerControlCommand[];
87
139
  readonly uninstallGuidance: readonly string[];
88
140
  readonly capability: SchedulerCapabilityReport;
@@ -90,6 +142,22 @@ export interface RunnerSchedulerCommandResult {
90
142
  readonly applied: boolean;
91
143
  readonly publicSafe: true;
92
144
  }
145
+ export type RunnerSchedulerBootstrapOptions = Omit<RunnerSchedulerCommandOptions, 'command'>;
146
+ export interface RunnerSchedulerBootstrapResult {
147
+ readonly ok: boolean;
148
+ readonly attempted: boolean;
149
+ readonly installed: boolean;
150
+ readonly started: boolean;
151
+ readonly cached: boolean;
152
+ readonly projectKey: string;
153
+ readonly strategy?: SchedulerStrategy;
154
+ readonly reasonCodes: readonly RunnerSchedulerBootstrapReasonCode[];
155
+ readonly publicSummary: string;
156
+ readonly publicSafe: true;
157
+ }
158
+ export declare function createRunnerSchedulerIdentity(canonicalProjectRoot: string): SchedulerProjectIdentity;
159
+ export declare function __resetRunnerSchedulerBootstrapCacheForTests(): void;
160
+ export declare function ensureRunnerSchedulerBootstrap(options?: RunnerSchedulerBootstrapOptions): Promise<RunnerSchedulerBootstrapResult>;
93
161
  export declare function runRunnerSchedulerCommand(options: RunnerSchedulerCommandOptions): Promise<RunnerSchedulerCommandResult>;
94
162
  export declare function detectSchedulerCapability(input?: {
95
163
  readonly platform?: NodeJS.Platform;
@@ -104,7 +172,9 @@ export declare function renderSchedulerManifests(input: {
104
172
  readonly paths: SchedulerPaths;
105
173
  readonly projectRoot: string;
106
174
  readonly executablePath: string;
175
+ readonly runnerCommand?: SchedulerRunnerCommand;
107
176
  readonly intervalSeconds: number;
177
+ readonly identity?: SchedulerProjectIdentity;
108
178
  }): readonly SchedulerManifest[];
109
179
  interface SchedulerPaths {
110
180
  readonly systemdServicePath: string;