@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.
- package/dist/sbom.cdx.json +19 -19
- package/install.ps1 +1 -1
- package/install.sh +1 -1
- package/package.json +2 -2
- package/packages/client/dist/commands/invoke.d.ts +47 -0
- package/packages/client/dist/commands/invoke.js +30 -28
- package/packages/client/dist/continuity/invoke-hooks.d.ts +1 -0
- package/packages/client/dist/continuity/invoke-hooks.js +1 -1
- package/packages/client/dist/continuity/runner-bootstrap-policy.d.ts +50 -0
- package/packages/client/dist/continuity/runner-bootstrap-policy.js +1 -0
- package/packages/client/dist/continuity/sqlite-store.d.ts +5 -2
- package/packages/client/dist/continuity/sqlite-store.js +16 -16
- package/packages/client/dist/runner/binary.d.ts +68 -0
- package/packages/client/dist/runner/binary.js +1 -0
- package/packages/client/dist/runner/cli.d.ts +2 -13
- package/packages/client/dist/runner/cli.js +10 -10
- package/packages/client/dist/runner/scheduler.d.ts +70 -0
- package/packages/client/dist/runner/scheduler.js +7 -6
- package/packages/client/dist/state/state-json-repair.js +3 -3
- package/targets-stubs/antigravity/gemini.md +1 -1
- package/targets-stubs/antigravity/skill/SKILL.md +1 -1
- package/targets-stubs/claude-code/neocortex-root.agent.yaml +1 -1
- package/targets-stubs/claude-code/neocortex-root.md +2 -2
- package/targets-stubs/claude-code/neocortex.agent.yaml +1 -1
- package/targets-stubs/claude-code/neocortex.md +2 -2
- package/targets-stubs/codex/AGENTS.md +1 -1
- package/targets-stubs/cursor/agent.md +2 -2
- package/targets-stubs/gemini-cli/agent.md +2 -2
- package/targets-stubs/opencode/neocortex-root.md +1 -1
- package/targets-stubs/vscode/neocortex.agent.md +2 -2
|
@@ -1,52 +1,52 @@
|
|
|
1
|
-
import{createHash as T}from"node:crypto";import{chmodSync as
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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
|
|
2
|
-
`),0;if(r.command==="version"){const n=
|
|
3
|
-
`),n.trusted?0:1}if(r.command==="doctor")try{const n=await
|
|
4
|
-
`),n.ok?0:1}catch(n){return process.stderr.write(JSON.stringify({error_code:"runner-doctor-failed",message:
|
|
5
|
-
`),1}if(
|
|
6
|
-
`),n.ok?0:1}catch(n){return process.stderr.write(JSON.stringify({error_code:"scheduler-command-failed",message:
|
|
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
|
|
9
|
-
`),n.ok?0:1}catch(n){const o=
|
|
10
|
-
`),1}}async function
|
|
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
|
|
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;
|