@ornexus/neocortex 4.60.16

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 (235) hide show
  1. package/LICENSE +56 -0
  2. package/LICENSE-COMMERCIAL.md +70 -0
  3. package/README.md +58 -0
  4. package/dist/sbom.cdx.json +11159 -0
  5. package/docs/install/coderabbit-manual-setup.md +86 -0
  6. package/docs/install/installer-diagnostics.md +107 -0
  7. package/docs/install/linux-global-install.md +97 -0
  8. package/install.js +572 -0
  9. package/install.ps1 +2214 -0
  10. package/install.sh +2013 -0
  11. package/package.json +132 -0
  12. package/packages/client/dist/adapters/adapter-registry.d.ts +61 -0
  13. package/packages/client/dist/adapters/adapter-registry.js +1 -0
  14. package/packages/client/dist/adapters/antigravity-adapter.d.ts +18 -0
  15. package/packages/client/dist/adapters/antigravity-adapter.js +2 -0
  16. package/packages/client/dist/adapters/claude-code-adapter.d.ts +19 -0
  17. package/packages/client/dist/adapters/claude-code-adapter.js +3 -0
  18. package/packages/client/dist/adapters/codex-adapter.d.ts +19 -0
  19. package/packages/client/dist/adapters/codex-adapter.js +2 -0
  20. package/packages/client/dist/adapters/cursor-adapter.d.ts +19 -0
  21. package/packages/client/dist/adapters/cursor-adapter.js +4 -0
  22. package/packages/client/dist/adapters/gemini-adapter.d.ts +18 -0
  23. package/packages/client/dist/adapters/gemini-adapter.js +2 -0
  24. package/packages/client/dist/adapters/index.d.ts +19 -0
  25. package/packages/client/dist/adapters/index.js +1 -0
  26. package/packages/client/dist/adapters/platform-detector.d.ts +48 -0
  27. package/packages/client/dist/adapters/platform-detector.js +1 -0
  28. package/packages/client/dist/adapters/target-adapter.d.ts +70 -0
  29. package/packages/client/dist/adapters/target-adapter.js +0 -0
  30. package/packages/client/dist/adapters/vscode-adapter.d.ts +19 -0
  31. package/packages/client/dist/adapters/vscode-adapter.js +2 -0
  32. package/packages/client/dist/agent/refresh-stubs.d.ts +90 -0
  33. package/packages/client/dist/agent/refresh-stubs.js +2 -0
  34. package/packages/client/dist/agent/update-agent-yaml.d.ts +26 -0
  35. package/packages/client/dist/agent/update-agent-yaml.js +1 -0
  36. package/packages/client/dist/agent/update-description.d.ts +45 -0
  37. package/packages/client/dist/agent/update-description.js +1 -0
  38. package/packages/client/dist/cache/crypto-utils.d.ts +30 -0
  39. package/packages/client/dist/cache/crypto-utils.js +1 -0
  40. package/packages/client/dist/cache/encrypted-cache.d.ts +30 -0
  41. package/packages/client/dist/cache/encrypted-cache.js +1 -0
  42. package/packages/client/dist/cache/in-memory-asset-cache.d.ts +62 -0
  43. package/packages/client/dist/cache/in-memory-asset-cache.js +1 -0
  44. package/packages/client/dist/cache/index.d.ts +13 -0
  45. package/packages/client/dist/cache/index.js +1 -0
  46. package/packages/client/dist/cache/protected-pi-boundary.d.ts +19 -0
  47. package/packages/client/dist/cache/protected-pi-boundary.js +1 -0
  48. package/packages/client/dist/checkpoint/checkpoint-client-reader.d.ts +45 -0
  49. package/packages/client/dist/checkpoint/checkpoint-client-reader.js +2 -0
  50. package/packages/client/dist/checkpoint/index.d.ts +12 -0
  51. package/packages/client/dist/checkpoint/index.js +1 -0
  52. package/packages/client/dist/checkpoint/shared-checkpoint-types.d.ts +85 -0
  53. package/packages/client/dist/checkpoint/shared-checkpoint-types.js +1 -0
  54. package/packages/client/dist/cli.d.ts +14 -0
  55. package/packages/client/dist/cli.js +81 -0
  56. package/packages/client/dist/commands/activate.d.ts +55 -0
  57. package/packages/client/dist/commands/activate.js +8 -0
  58. package/packages/client/dist/commands/cache-status.d.ts +39 -0
  59. package/packages/client/dist/commands/cache-status.js +2 -0
  60. package/packages/client/dist/commands/invoke.d.ts +546 -0
  61. package/packages/client/dist/commands/invoke.js +140 -0
  62. package/packages/client/dist/commands/refresh-memory.d.ts +11 -0
  63. package/packages/client/dist/commands/refresh-memory.js +1 -0
  64. package/packages/client/dist/config/resolver-selection.d.ts +40 -0
  65. package/packages/client/dist/config/resolver-selection.js +1 -0
  66. package/packages/client/dist/config/secure-config.d.ts +78 -0
  67. package/packages/client/dist/config/secure-config.js +12 -0
  68. package/packages/client/dist/constants.d.ts +25 -0
  69. package/packages/client/dist/constants.js +1 -0
  70. package/packages/client/dist/context/context-collector.d.ts +28 -0
  71. package/packages/client/dist/context/context-collector.js +2 -0
  72. package/packages/client/dist/context/context-sanitizer.d.ts +28 -0
  73. package/packages/client/dist/context/context-sanitizer.js +1 -0
  74. package/packages/client/dist/continuity/autonomous-governance.d.ts +84 -0
  75. package/packages/client/dist/continuity/autonomous-governance.js +1 -0
  76. package/packages/client/dist/continuity/continuity-client-state-store.d.ts +302 -0
  77. package/packages/client/dist/continuity/continuity-client-state-store.js +1 -0
  78. package/packages/client/dist/continuity/invoke-hooks.d.ts +19 -0
  79. package/packages/client/dist/continuity/invoke-hooks.js +1 -0
  80. package/packages/client/dist/continuity/migrations/001-initial-schema.d.ts +11 -0
  81. package/packages/client/dist/continuity/migrations/001-initial-schema.js +263 -0
  82. package/packages/client/dist/continuity/migrations/002-processing-output-summary-indexes.d.ts +11 -0
  83. package/packages/client/dist/continuity/migrations/002-processing-output-summary-indexes.js +7 -0
  84. package/packages/client/dist/continuity/migrations/003-headless-execution-attempts.d.ts +11 -0
  85. package/packages/client/dist/continuity/migrations/003-headless-execution-attempts.js +62 -0
  86. package/packages/client/dist/continuity/migrations/004-outbox-delivery-state.d.ts +11 -0
  87. package/packages/client/dist/continuity/migrations/004-outbox-delivery-state.js +19 -0
  88. package/packages/client/dist/continuity/migrations/005-bounded-headless-queue.d.ts +11 -0
  89. package/packages/client/dist/continuity/migrations/005-bounded-headless-queue.js +35 -0
  90. package/packages/client/dist/continuity/outbox.d.ts +83 -0
  91. package/packages/client/dist/continuity/outbox.js +1 -0
  92. package/packages/client/dist/continuity/runner-bootstrap-policy.d.ts +50 -0
  93. package/packages/client/dist/continuity/runner-bootstrap-policy.js +1 -0
  94. package/packages/client/dist/continuity/sqlite-store.d.ts +926 -0
  95. package/packages/client/dist/continuity/sqlite-store.js +619 -0
  96. package/packages/client/dist/errors/error-messages.d.ts +40 -0
  97. package/packages/client/dist/errors/error-messages.js +2 -0
  98. package/packages/client/dist/graph-retrieval/pre-command-hook.d.ts +34 -0
  99. package/packages/client/dist/graph-retrieval/pre-command-hook.js +1 -0
  100. package/packages/client/dist/graph-retrieval/shared-graph-retrieval-contract.d.ts +99 -0
  101. package/packages/client/dist/graph-retrieval/shared-graph-retrieval-contract.js +1 -0
  102. package/packages/client/dist/i18n/first-run.d.ts +23 -0
  103. package/packages/client/dist/i18n/first-run.js +2 -0
  104. package/packages/client/dist/index.d.ts +56 -0
  105. package/packages/client/dist/index.js +1 -0
  106. package/packages/client/dist/license/index.d.ts +5 -0
  107. package/packages/client/dist/license/index.js +1 -0
  108. package/packages/client/dist/license/license-client.d.ts +79 -0
  109. package/packages/client/dist/license/license-client.js +1 -0
  110. package/packages/client/dist/machine/fingerprint.d.ts +34 -0
  111. package/packages/client/dist/machine/fingerprint.js +2 -0
  112. package/packages/client/dist/machine/index.d.ts +5 -0
  113. package/packages/client/dist/machine/index.js +1 -0
  114. package/packages/client/dist/memory/project-memory-writer.d.ts +74 -0
  115. package/packages/client/dist/memory/project-memory-writer.js +36 -0
  116. package/packages/client/dist/memory/shared-project-memory-types.d.ts +370 -0
  117. package/packages/client/dist/memory/shared-project-memory-types.js +2 -0
  118. package/packages/client/dist/policy/architecture-policy.d.ts +40 -0
  119. package/packages/client/dist/policy/architecture-policy.js +2 -0
  120. package/packages/client/dist/policy/index.d.ts +8 -0
  121. package/packages/client/dist/policy/index.js +1 -0
  122. package/packages/client/dist/policy/shared-policy-types.d.ts +89 -0
  123. package/packages/client/dist/policy/shared-policy-types.js +0 -0
  124. package/packages/client/dist/resilience/circuit-breaker.d.ts +70 -0
  125. package/packages/client/dist/resilience/circuit-breaker.js +1 -0
  126. package/packages/client/dist/resilience/degradation-manager.d.ts +67 -0
  127. package/packages/client/dist/resilience/degradation-manager.js +1 -0
  128. package/packages/client/dist/resilience/freshness-indicator.d.ts +59 -0
  129. package/packages/client/dist/resilience/freshness-indicator.js +1 -0
  130. package/packages/client/dist/resilience/index.d.ts +8 -0
  131. package/packages/client/dist/resilience/index.js +1 -0
  132. package/packages/client/dist/resilience/recovery-detector.d.ts +59 -0
  133. package/packages/client/dist/resilience/recovery-detector.js +1 -0
  134. package/packages/client/dist/resolvers/asset-resolver.d.ts +79 -0
  135. package/packages/client/dist/resolvers/asset-resolver.js +0 -0
  136. package/packages/client/dist/resolvers/local-resolver.d.ts +26 -0
  137. package/packages/client/dist/resolvers/local-resolver.js +8 -0
  138. package/packages/client/dist/resolvers/remote-resolver.d.ts +91 -0
  139. package/packages/client/dist/resolvers/remote-resolver.js +1 -0
  140. package/packages/client/dist/runner/binary.d.ts +115 -0
  141. package/packages/client/dist/runner/binary.js +1 -0
  142. package/packages/client/dist/runner/cli.d.ts +168 -0
  143. package/packages/client/dist/runner/cli.js +70 -0
  144. package/packages/client/dist/runner/headless/adapters.d.ts +20 -0
  145. package/packages/client/dist/runner/headless/adapters.js +1 -0
  146. package/packages/client/dist/runner/headless/claude-code-adapter.d.ts +8 -0
  147. package/packages/client/dist/runner/headless/claude-code-adapter.js +1 -0
  148. package/packages/client/dist/runner/headless/fake-adapter.d.ts +8 -0
  149. package/packages/client/dist/runner/headless/fake-adapter.js +1 -0
  150. package/packages/client/dist/runner/headless/opencode-adapter.d.ts +15 -0
  151. package/packages/client/dist/runner/headless/opencode-adapter.js +2 -0
  152. package/packages/client/dist/runner/headless/resolver.d.ts +68 -0
  153. package/packages/client/dist/runner/headless/resolver.js +1 -0
  154. package/packages/client/dist/runner/headless/run-yolo.d.ts +59 -0
  155. package/packages/client/dist/runner/headless/run-yolo.js +1 -0
  156. package/packages/client/dist/runner/headless/run-yoloop.d.ts +113 -0
  157. package/packages/client/dist/runner/headless/run-yoloop.js +1 -0
  158. package/packages/client/dist/runner/headless/types.d.ts +194 -0
  159. package/packages/client/dist/runner/headless/types.js +2 -0
  160. package/packages/client/dist/runner/local-console.d.ts +83 -0
  161. package/packages/client/dist/runner/local-console.js +13 -0
  162. package/packages/client/dist/runner/portal-sync-worker.d.ts +184 -0
  163. package/packages/client/dist/runner/portal-sync-worker.js +1 -0
  164. package/packages/client/dist/runner/project-identity.d.ts +19 -0
  165. package/packages/client/dist/runner/project-identity.js +1 -0
  166. package/packages/client/dist/runner/scheduler.d.ts +186 -0
  167. package/packages/client/dist/runner/scheduler.js +7 -0
  168. package/packages/client/dist/runner-cli.d.ts +9 -0
  169. package/packages/client/dist/runner-cli.js +3 -0
  170. package/packages/client/dist/state/project-state-snapshot.d.ts +24 -0
  171. package/packages/client/dist/state/project-state-snapshot.js +1 -0
  172. package/packages/client/dist/state/state-json-repair.d.ts +74 -0
  173. package/packages/client/dist/state/state-json-repair.js +3 -0
  174. package/packages/client/dist/telemetry/index.d.ts +5 -0
  175. package/packages/client/dist/telemetry/index.js +1 -0
  176. package/packages/client/dist/telemetry/offline-queue.d.ts +57 -0
  177. package/packages/client/dist/telemetry/offline-queue.js +1 -0
  178. package/packages/client/dist/tier/index.d.ts +5 -0
  179. package/packages/client/dist/tier/index.js +1 -0
  180. package/packages/client/dist/tier/tier-aware-client.d.ts +105 -0
  181. package/packages/client/dist/tier/tier-aware-client.js +1 -0
  182. package/packages/client/dist/types/index.d.ts +140 -0
  183. package/packages/client/dist/types/index.js +1 -0
  184. package/packages/client/dist/yoloop/discovery-hook.d.ts +85 -0
  185. package/packages/client/dist/yoloop/discovery-hook.js +2 -0
  186. package/packages/client/dist/yoloop/index.d.ts +10 -0
  187. package/packages/client/dist/yoloop/index.js +1 -0
  188. package/packages/client/dist/yoloop/invoke-hooks.d.ts +127 -0
  189. package/packages/client/dist/yoloop/invoke-hooks.js +5 -0
  190. package/packages/client/dist/yoloop/shared-discover-epics.d.ts +289 -0
  191. package/packages/client/dist/yoloop/shared-discover-epics.js +1 -0
  192. package/packages/client/dist/yoloop/shared-yoloop-types.d.ts +172 -0
  193. package/packages/client/dist/yoloop/shared-yoloop-types.js +1 -0
  194. package/packages/client/dist/yoloop/yoloop-client-state-store.d.ts +124 -0
  195. package/packages/client/dist/yoloop/yoloop-client-state-store.js +1 -0
  196. package/postinstall.js +754 -0
  197. package/targets-stubs/antigravity/README.md +36 -0
  198. package/targets-stubs/antigravity/gemini.md +29 -0
  199. package/targets-stubs/antigravity/install-antigravity.sh +153 -0
  200. package/targets-stubs/antigravity/mcp-config.json +30 -0
  201. package/targets-stubs/antigravity/skill/SKILL.md +166 -0
  202. package/targets-stubs/claude-code/.mcp.json +32 -0
  203. package/targets-stubs/claude-code/README.md +20 -0
  204. package/targets-stubs/claude-code/neocortex-root.agent.yaml +42 -0
  205. package/targets-stubs/claude-code/neocortex-root.md +317 -0
  206. package/targets-stubs/claude-code/neocortex.agent.yaml +42 -0
  207. package/targets-stubs/claude-code/neocortex.md +385 -0
  208. package/targets-stubs/codex/AGENTS.md +250 -0
  209. package/targets-stubs/codex/README.md +47 -0
  210. package/targets-stubs/codex/config-mcp.toml +22 -0
  211. package/targets-stubs/codex/install-codex.sh +63 -0
  212. package/targets-stubs/codex/neocortex.toml +33 -0
  213. package/targets-stubs/cursor/README.md +33 -0
  214. package/targets-stubs/cursor/agent.md +211 -0
  215. package/targets-stubs/cursor/install-cursor.sh +50 -0
  216. package/targets-stubs/cursor/mcp.json +30 -0
  217. package/targets-stubs/gemini-cli/README.md +34 -0
  218. package/targets-stubs/gemini-cli/agent.md +241 -0
  219. package/targets-stubs/gemini-cli/agents/neocortex.md +60 -0
  220. package/targets-stubs/gemini-cli/gemini.md +46 -0
  221. package/targets-stubs/gemini-cli/install-gemini.sh +70 -0
  222. package/targets-stubs/gemini-cli/settings-mcp.json +30 -0
  223. package/targets-stubs/kimi/mcp.json +33 -0
  224. package/targets-stubs/kimi/neocortex.md +60 -0
  225. package/targets-stubs/lib/mcp-merge.js +189 -0
  226. package/targets-stubs/openclaw/README.md +12 -0
  227. package/targets-stubs/openclaw/SKILL.md +92 -0
  228. package/targets-stubs/opencode/neocortex-root.md +267 -0
  229. package/targets-stubs/opencode/neocortex.md +65 -0
  230. package/targets-stubs/opencode/opencode-mcp.json +35 -0
  231. package/targets-stubs/vscode/README.md +34 -0
  232. package/targets-stubs/vscode/copilot-instructions.md +47 -0
  233. package/targets-stubs/vscode/install-vscode.sh +72 -0
  234. package/targets-stubs/vscode/mcp.json +36 -0
  235. package/targets-stubs/vscode/neocortex.agent.md +252 -0
@@ -0,0 +1,184 @@
1
+ /**
2
+ * @license FSL-1.1
3
+ * Copyright (c) 2026 OrNexus AI
4
+ *
5
+ * P192.02 -- outbound Portal sync worker for runner heartbeat, jobs sync and
6
+ * pending command acknowledgements.
7
+ */
8
+ import { type ContinuityRedactionEvidence } from '../continuity/continuity-client-state-store.js';
9
+ import { type ContinuitySqliteAdapter, type ContinuitySqliteAdapterLoadResult } from '../continuity/sqlite-store.js';
10
+ import type { ContinuityRetentionPolicyInput } from '../continuity/outbox.js';
11
+ export declare const RUNNER_PORTAL_SYNC_REASON_CODES: Readonly<{
12
+ readonly OK: "continuity-ok";
13
+ readonly AUTH_TOKEN_PERMISSION_FAILURE: "auth-token-permission-failure";
14
+ readonly BACKOFF_SCHEDULED: "backoff-scheduled";
15
+ readonly COMMAND_EXPIRED: "command-expired";
16
+ readonly IDEMPOTENCY_REPLAY: "idempotency-replay";
17
+ readonly INVALID_STATE_TRANSITION: "invalid-state-transition";
18
+ readonly JOB_CANCELLED: "job-cancelled";
19
+ readonly PORTAL_COMMAND_LOCAL_AUDIT_RECORDED: "portal-command-local-audit-recorded";
20
+ readonly PORTAL_COMMAND_PAYLOAD_REJECTED: "portal-command-payload-rejected";
21
+ readonly PORTAL_SYNC_PAYLOAD_REJECTED: "portal-sync-payload-rejected";
22
+ readonly RUNNER_DIRECTIVE_UNTRUSTED: "runner-directive-untrusted";
23
+ readonly SQLITE_ADAPTER_UNAVAILABLE: "sqlite-adapter-unavailable";
24
+ readonly SQLITE_INTEGRITY_FAILED: "sqlite-integrity-failed";
25
+ readonly UNSAFE_FIELD_REJECTED: "unsafe-field-rejected";
26
+ readonly WAITING_HUMAN: "waiting-human";
27
+ }>;
28
+ export type RunnerPortalSyncReasonCode = (typeof RUNNER_PORTAL_SYNC_REASON_CODES)[keyof typeof RUNNER_PORTAL_SYNC_REASON_CODES] | string;
29
+ export type RunnerPortalSyncMode = 'manual' | 'scheduled' | 'background';
30
+ export type RunnerPortalHttpMethod = 'GET' | 'POST';
31
+ export interface RunnerPortalHttpRequest {
32
+ readonly method: RunnerPortalHttpMethod;
33
+ readonly path: string;
34
+ readonly query?: Readonly<Record<string, string | undefined>>;
35
+ readonly body?: Readonly<Record<string, unknown>>;
36
+ readonly headers: Readonly<Record<string, string>>;
37
+ }
38
+ export interface RunnerPortalHttpResponse {
39
+ readonly ok: boolean;
40
+ readonly status: number;
41
+ readonly body?: unknown;
42
+ }
43
+ export type RunnerPortalHttpClient = (request: RunnerPortalHttpRequest) => Promise<RunnerPortalHttpResponse>;
44
+ export interface RunnerPortalSyncOptions {
45
+ readonly projectRoot?: string;
46
+ readonly runnerId?: string;
47
+ readonly sessionId?: string;
48
+ readonly workspaceId?: string;
49
+ readonly workspaceLabel?: string;
50
+ readonly projectId?: string;
51
+ readonly projectLabel?: string;
52
+ readonly serverUrl?: string;
53
+ readonly authToken?: string;
54
+ readonly licenseKey?: string;
55
+ readonly adapter?: ContinuitySqliteAdapter;
56
+ readonly adapterLoader?: () => Promise<ContinuitySqliteAdapterLoadResult>;
57
+ readonly httpClient?: RunnerPortalHttpClient;
58
+ readonly now?: () => string;
59
+ readonly mode?: RunnerPortalSyncMode;
60
+ readonly schedulerState?: 'installed' | 'running' | 'stopped' | 'degraded' | 'unavailable' | 'unknown';
61
+ readonly syncCursor?: string;
62
+ readonly jobLimit?: number;
63
+ readonly eventLimit?: number;
64
+ readonly receiptLimit?: number;
65
+ readonly commandLimit?: number;
66
+ readonly clientVersion?: string;
67
+ readonly heartbeatTimeoutMs?: number;
68
+ readonly retentionPolicy?: ContinuityRetentionPolicyInput;
69
+ }
70
+ export interface RunnerPortalSyncLoopOptions extends RunnerPortalSyncOptions {
71
+ readonly intervalMs?: number;
72
+ readonly maxRuns?: number;
73
+ }
74
+ export interface RunnerPortalHeartbeatOptions extends RunnerPortalSyncOptions {
75
+ readonly timeoutMs?: number;
76
+ }
77
+ export interface RunnerPortalHeartbeatLoopOptions extends RunnerPortalHeartbeatOptions {
78
+ readonly intervalMs?: number;
79
+ readonly maxRuns?: number;
80
+ readonly backoffMs?: number;
81
+ readonly jitterRatio?: number;
82
+ readonly random?: () => number;
83
+ }
84
+ export type RunnerPortalCommandApplyStatus = 'applied' | 'already_applied' | 'rejected' | 'expired' | 'failed-local';
85
+ export interface RunnerPortalCommandAckSummary {
86
+ readonly commandId: string;
87
+ readonly jobId?: string;
88
+ readonly workspaceId: string;
89
+ readonly workspaceLabel: string;
90
+ readonly projectId: string;
91
+ readonly projectLabel: string;
92
+ readonly action?: string;
93
+ readonly localStatus: RunnerPortalCommandApplyStatus;
94
+ readonly remoteStatus: 'acknowledged' | 'applied' | 'rejected' | 'expired';
95
+ readonly reasonCode: RunnerPortalSyncReasonCode;
96
+ readonly publicSummary: string;
97
+ readonly acknowledgedAt: string;
98
+ readonly counts: Readonly<Record<string, number>>;
99
+ readonly redactionEvidence: readonly ContinuityRedactionEvidence[];
100
+ readonly publicSafe: true;
101
+ }
102
+ export interface RunnerPortalSyncSummary {
103
+ readonly ok: boolean;
104
+ readonly runnerId: string;
105
+ readonly sessionId?: string;
106
+ readonly workspaceId: string;
107
+ readonly workspaceLabel: string;
108
+ readonly projectId: string;
109
+ readonly projectLabel: string;
110
+ readonly mode: RunnerPortalSyncMode;
111
+ readonly generatedAt: string;
112
+ readonly serverAccessToLocalhost: false;
113
+ readonly serverHeldStream: false;
114
+ readonly localhostCallback: false;
115
+ readonly posted: {
116
+ readonly heartbeat: boolean;
117
+ readonly runnerSync: boolean;
118
+ readonly commandAcks: number;
119
+ };
120
+ readonly commandPoll: {
121
+ readonly polled: number;
122
+ readonly applied: number;
123
+ readonly alreadyApplied: number;
124
+ readonly rejected: number;
125
+ readonly expired: number;
126
+ readonly failedLocal: number;
127
+ };
128
+ readonly sync: {
129
+ readonly previousSyncCursor?: string;
130
+ readonly nextSyncCursor: string;
131
+ readonly counts: Readonly<Record<string, number>>;
132
+ };
133
+ readonly commandAcks: readonly RunnerPortalCommandAckSummary[];
134
+ readonly reasonCodes: readonly RunnerPortalSyncReasonCode[];
135
+ readonly redactionEvidence: readonly ContinuityRedactionEvidence[];
136
+ readonly publicSafe: true;
137
+ }
138
+ export interface RunnerPortalHeartbeatSummary {
139
+ readonly ok: boolean;
140
+ readonly runnerId: string;
141
+ readonly sessionId?: string;
142
+ readonly workspaceId: string;
143
+ readonly workspaceLabel: string;
144
+ readonly projectId: string;
145
+ readonly projectLabel: string;
146
+ readonly mode: RunnerPortalSyncMode;
147
+ readonly generatedAt: string;
148
+ readonly serverAccessToLocalhost: false;
149
+ readonly serverHeldStream: false;
150
+ readonly localhostCallback: false;
151
+ readonly posted: {
152
+ readonly heartbeat: boolean;
153
+ };
154
+ readonly counts: Readonly<Record<string, number>>;
155
+ readonly reasonCodes: readonly RunnerPortalSyncReasonCode[];
156
+ readonly redactionEvidence: readonly ContinuityRedactionEvidence[];
157
+ readonly publicSafe: true;
158
+ }
159
+ export interface RunnerPortalSyncLoopSummary {
160
+ readonly ok: boolean;
161
+ readonly runs: readonly RunnerPortalSyncSummary[];
162
+ readonly reasonCodes: readonly RunnerPortalSyncReasonCode[];
163
+ readonly publicSafe: true;
164
+ }
165
+ export interface RunnerPortalHeartbeatLoopSummary {
166
+ readonly ok: boolean;
167
+ readonly runs: readonly RunnerPortalHeartbeatSummary[];
168
+ readonly reasonCodes: readonly RunnerPortalSyncReasonCode[];
169
+ readonly schedule: {
170
+ readonly intervalMs: number;
171
+ readonly backoffMs: number;
172
+ readonly jitterRatio: number;
173
+ readonly maxRuns: number;
174
+ };
175
+ readonly publicSafe: true;
176
+ }
177
+ export declare const DEFAULT_RUNNER_HEARTBEAT_INTERVAL_MS = 60000;
178
+ export declare const DEFAULT_RUNNER_HEARTBEAT_BACKOFF_MS = 30000;
179
+ export declare const DEFAULT_RUNNER_HEARTBEAT_TIMEOUT_MS = 10000;
180
+ export declare const DEFAULT_RUNNER_HEARTBEAT_JITTER_RATIO = 0.2;
181
+ export declare function runRunnerPortalHeartbeat(options?: RunnerPortalHeartbeatOptions): Promise<RunnerPortalHeartbeatSummary>;
182
+ export declare function runRunnerPortalSync(options?: RunnerPortalSyncOptions): Promise<RunnerPortalSyncSummary>;
183
+ export declare function runRunnerPortalSyncLoop(options?: RunnerPortalSyncLoopOptions): Promise<RunnerPortalSyncLoopSummary>;
184
+ export declare function runRunnerPortalHeartbeatLoop(options?: RunnerPortalHeartbeatLoopOptions): Promise<RunnerPortalHeartbeatLoopSummary>;
@@ -0,0 +1 @@
1
+ import{createHash as ve}from"node:crypto";import{resolve as ae}from"node:path";import{DEFAULT_SERVER_URL as $e}from"../constants.js";import{loadSecureConfig as se}from"../config/secure-config.js";import{LicenseClient as Ke}from"../license/license-client.js";import{deriveProjectIdentity as G}from"./project-identity.js";import{CONTINUITY_CLIENT_CONTRACT_VERSION as $,CONTINUITY_CLIENT_PORTAL_SYNC_ENVELOPE_VERSION as Z,CONTINUITY_CLIENT_SCHEMA_VERSION as K,ContinuityClientStateStore as de}from"../continuity/continuity-client-state-store.js";import{isContinuityPublicStage as Me,normalizeContinuityStageIteration as Ue,openContinuitySqliteStore as ce,sanitizeContinuityStageHistory as Fe}from"../continuity/sqlite-store.js";const d=Object.freeze({OK:"continuity-ok",AUTH_TOKEN_PERMISSION_FAILURE:"auth-token-permission-failure",BACKOFF_SCHEDULED:"backoff-scheduled",COMMAND_EXPIRED:"command-expired",IDEMPOTENCY_REPLAY:"idempotency-replay",INVALID_STATE_TRANSITION:"invalid-state-transition",JOB_CANCELLED:"job-cancelled",PORTAL_COMMAND_LOCAL_AUDIT_RECORDED:"portal-command-local-audit-recorded",PORTAL_COMMAND_PAYLOAD_REJECTED:"portal-command-payload-rejected",PORTAL_SYNC_PAYLOAD_REJECTED:"portal-sync-payload-rejected",RUNNER_DIRECTIVE_UNTRUSTED:"runner-directive-untrusted",SQLITE_ADAPTER_UNAVAILABLE:"sqlite-adapter-unavailable",SQLITE_INTEGRITY_FAILED:"sqlite-integrity-failed",UNSAFE_FIELD_REJECTED:"unsafe-field-rejected",WAITING_HUMAN:"waiting-human"}),ie=new Set(["approve","deny","hold"]),qe=new Set(["option","decisionId","gateId","publicSafe"]),M="3.9.62",He=6e4,Ve=3e4,Je=1e4,Ye=.2,Be=`${Date.now()}:${Math.random().toString(16).slice(2)}`,ue=new Set(["pause","resume","cancel","run_once","retry","snapshot","approve_review_gate","deny_review_gate","answer_decision"]),le=new Set(["commandId","jobId","action","decision","status","queuedAt","expiresAt","acknowledgedAt","idempotencyKey","delivery","workspaceId","workspaceLabel","runnerId","projectId","projectLabel","reasonCode","publicSafe"]),ye=/^[A-Za-z0-9][A-Za-z0-9._:-]{0,159}$/,fe=/^runner-[A-Za-z0-9._-]{1,80}$/,ze=/^(?:job|goal|loop|runner)-[A-Za-z0-9._-]{1,80}$/,pe=/^pcmd-[a-f0-9]{8,64}$/i,V=/^[a-z0-9][a-z0-9-]{1,80}$/,W=/(raw[_-]?(?:logs?|payloads?)|std(?:out|err)|stack(?:[_-]?trace)?|transcript|prompt(?:[_-]?(?:body|text))?|private[_-]?(?:urls?|prompts?)|secret|token|password|protected(?:[_-]?(?:field|body|bodies|internals))?|workflow(?:[_-]?body)?|step(?:[_-]?body)?|customer(?:[_-]?(?:pii|data))?|\bpii\b|authorization|api[_-]?key|license[_-]?key|argv|args|executable(?:[_-]?path)?|binary(?:[_-]?path)?|shell|cwd|command[_-]?path|vendor(?:[_-]?(?:payload|corpus|response|output)))/i,g=/(https?:\/\/\S+|(?:^|\s)(?:\/(?:home|Users|media|mnt|tmp|var|etc|private)\/\S+|[A-Za-z]:\\\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[_-]?(?:logs?)\s*[:=]|transcript|stack\s*trace|stderr:|stdout:|system prompt|workflow body|step body|PROTECTED_|PRIVATE_INTERNALS|CUSTOMER_PII|\bPII\b|VENDOR_CORPUS|P180[_-]?SYNTHETIC[_-]?CONTINUITY|P185[_-]?SYNTHETIC[_-]?CONTINUITY|P187[_-]?SYNTHETIC[_-]?(?:CONTINUITY|RUNNER|WATCH)|P190[_-]?SYNTHETIC[_-]?(?:HEADLESS|CONTINUITY)|P192[_-]?SYNTHETIC[_-]?(?:PORTAL|RUNNER|SYNC))/i,me=/(?:[;&|`$<>]|\$\(|\n|\r|\0|(?:^|\s)(?:bash|sh|zsh|fish|cmd\.exe|powershell|pwsh|npm|pnpm|yarn|node|python|ruby|go|cargo|sudo|chmod|curl|wget)\s+(?:-c|run|exec|install|test|build|[A-Za-z0-9_./:-]+))/i;async function Ge(e={}){const t=ae(e.projectRoot??process.cwd()),r=e.now??(()=>new Date().toISOString()),o=r(),n=ge(e.runnerId??_e(t)),a=Se(e.sessionId)??Ce(t),s=Ae(t,e),{workspaceId:u,workspaceLabel:l,projectId:c,projectLabel:y}=s,h=e.mode??"background",C=[],S=[],L={heartbeat:!1};let b;try{b=await ce({projectRoot:t,adapter:e.adapter,adapterLoader:e.adapterLoader,now:r});const I=new de(b,r,G(t)).collectSnapshot({nowIso:o,jobLimit:_(e.jobLimit??20,1,50),dueJobLimit:20,eventLimit:1,receiptLimit:1,staleLeaseLimit:20,processingSummaryLimit:1,snapshotLimit:1}),k=e.httpClient?e.authToken:await ee(e),H=e.httpClient??Ee(X(e),k),p=Le(e.clientVersion??M,k),v=Ie(I,{runnerId:n,sessionId:a,identity:s,generatedAt:o,schedulerState:e.schedulerState??"unknown",clientVersion:e.clientVersion??M}),j=await F(H,{method:"POST",path:"/api/v1/continuity/runner/heartbeat",body:v,headers:p},{timeoutMs:e.timeoutMs??e.heartbeatTimeoutMs??Je});j.ok?L.heartbeat=!0:C.push(j.reasonCode);const w=bt(I,S.length);return{ok:L.heartbeat,runnerId:n,sessionId:a,workspaceId:u,workspaceLabel:l,projectId:c,projectLabel:y,mode:h,generatedAt:o,serverAccessToLocalhost:!1,serverHeldStream:!1,localhostCallback:!1,posted:L,counts:w,reasonCodes:Y(C.length>0?C:[d.OK]),redactionEvidence:S,publicSafe:!0}}catch(f){const I=ke(f);return{ok:!1,runnerId:n,sessionId:a,workspaceId:u,workspaceLabel:l,projectId:c,projectLabel:y,mode:h,generatedAt:o,serverAccessToLocalhost:!1,serverHeldStream:!1,localhostCallback:!1,posted:L,counts:{redactions:S.length},reasonCodes:[I],redactionEvidence:S,publicSafe:!0}}finally{b?.close()}}async function Ze(e={}){const t=ae(e.projectRoot??process.cwd()),r=e.now??(()=>new Date().toISOString()),o=r(),n=ge(e.runnerId??_e(t)),a=Se(e.sessionId)??Ce(t),s=Ae(t,e),{workspaceId:u,workspaceLabel:l,projectId:c,projectLabel:y}=s,h=e.mode??"manual",C=[],S=[],L=[],b={heartbeat:!1,runnerSync:!1,commandAcks:0},f={polled:0,applied:0,alreadyApplied:0,rejected:0,expired:0,failedLocal:0};let I;try{I=await ce({projectRoot:t,adapter:e.adapter,adapterLoader:e.adapterLoader,now:r});const k=I.compactPublicReceiptsAndOutputs({nowIso:o,policy:e.retentionPolicy}),p=new de(I,r,G(t)).collectSnapshot({nowIso:o,jobLimit:_(e.jobLimit??50,1,50),dueJobLimit:50,eventLimit:_(e.eventLimit??50,1,100),receiptLimit:_(e.receiptLimit??50,1,100),staleLeaseLimit:20,processingSummaryLimit:20,snapshotLimit:10}),v=At(p,o),j=e.httpClient??Ee(X(e),await ee(e)),w=Le(e.clientVersion??M,e.httpClient?e.authToken:await ee(e)),re=Ie(p,{runnerId:n,sessionId:a,identity:s,generatedAt:o,schedulerState:e.schedulerState??"unknown",clientVersion:e.clientVersion??M}),oe=await F(j,{method:"POST",path:"/api/v1/continuity/runner/heartbeat",body:re,headers:w});oe.ok?b.heartbeat=!0:C.push(oe.reasonCode);const Ne=tt(p,{runnerId:n,identity:s,generatedAt:o,previousSyncCursor:e.syncCursor,nextSyncCursor:v,heartbeat:re}),E=rt(I,p,{runnerId:n,identity:s,generatedAt:o,previousSyncCursor:e.syncCursor,nextSyncCursor:v}),B=E.status==="acked"&&E.replay?{ok:!0,body:{reasonCode:d.IDEMPOTENCY_REPLAY,publicSafe:!0}}:E.status==="conflict"||E.status==="dead_letter"?{ok:!1,reasonCode:E.reasonCode??d.BACKOFF_SCHEDULED}:await F(j,{method:"POST",path:"/api/v1/continuity/jobs/sync",body:Ne,headers:w});B.ok?(b.runnerSync=!0,I.ackOutbox({outboxId:E.outboxId,deliveryCursor:E.deliveryCursor,ackedAt:r(),reasonCode:d.OK})):(C.push(B.reasonCode),I.failOutboxDelivery({outboxId:E.outboxId,deliveryCursor:E.deliveryCursor,failedAt:r(),reasonCode:B.reasonCode,summary:"Runner sync delivery failed with a public reason code and will retry or dead-letter by policy.",policy:{maxAttempts:3}}));const z=await F(j,{method:"GET",path:"/api/v1/continuity/runner/commands",query:{runnerId:n,workspaceId:u,workspaceLabel:l,projectId:c,projectLabel:y},headers:w});if(z.ok){const ne=mt(z.body).slice(0,_(e.commandLimit??20,1,20));f.polled=ne.length;for(const De of ne){const R=await We({store:I,http:j,headers:w,rawCommand:De,runnerId:n,identity:s,nowIso:r()});L.push(R),b.commandAcks+=1,R.localStatus==="applied"?f.applied+=1:R.localStatus==="already_applied"?f.alreadyApplied+=1:R.localStatus==="rejected"?f.rejected+=1:R.localStatus==="expired"?f.expired+=1:f.failedLocal+=1,S.push(...R.redactionEvidence),C.push(R.reasonCode)}}else C.push(z.reasonCode);const Oe={jobs:p.counts.jobs??p.jobs.length,dueJobs:p.dueJobCount,receipts:p.counts.receipts??p.lastReceipts.length,events:p.counts.events??p.lastEvents.length,commandsPolled:f.polled,commandAcks:b.commandAcks,commandApplied:f.applied,commandAlreadyApplied:f.alreadyApplied,commandRejected:f.rejected,commandExpired:f.expired,commandFailedLocal:f.failedLocal,receiptCompactionSummaries:k.counts.summariesCreated,receiptsCompacted:k.counts.receiptsRemoved,processingSummariesCompacted:k.counts.outputsRemoved,redactions:S.length,...N(p)},Pe=Y(C.length>0?C:[d.OK]);return{ok:b.heartbeat&&b.runnerSync&&f.failedLocal===0,runnerId:n,sessionId:a,workspaceId:u,workspaceLabel:l,projectId:c,projectLabel:y,mode:h,generatedAt:o,serverAccessToLocalhost:!1,serverHeldStream:!1,localhostCallback:!1,posted:b,commandPoll:f,sync:{...e.syncCursor?{previousSyncCursor:e.syncCursor}:{},nextSyncCursor:v,counts:Oe},commandAcks:L,reasonCodes:Pe,redactionEvidence:S.slice(0,50),publicSafe:!0}}catch(k){const H=ke(k);return{ok:!1,runnerId:n,sessionId:a,workspaceId:u,workspaceLabel:l,projectId:c,projectLabel:y,mode:h,generatedAt:o,serverAccessToLocalhost:!1,serverHeldStream:!1,localhostCallback:!1,posted:b,commandPoll:f,sync:{nextSyncCursor:`sync-${A(o).slice(0,24)}`,counts:{commandAcks:0}},commandAcks:L,reasonCodes:[H],redactionEvidence:S,publicSafe:!0}}finally{I?.close()}}async function Dt(e={}){const t=_(e.maxRuns??1,1,1e4),r=_(e.intervalMs??6e4,0,1440*60*1e3),o=[];let n=e.syncCursor;for(let a=0;a<t;a++){const s=await Ze({...e,mode:e.mode??"background",syncCursor:n});o.push(s),n=s.sync.nextSyncCursor,a<t-1&&r>0&&await xe(r)}return{ok:o.every(a=>a.ok),runs:o,reasonCodes:Y(o.flatMap(a=>a.reasonCodes)),publicSafe:!0}}async function vt(e={}){const t=_(e.maxRuns??1,1,1e4),r=_(e.intervalMs??He,0,1440*60*1e3),o=_(e.backoffMs??Ve,1e3,1800*1e3),n=Te(e.jitterRatio??Ye,0,.5),a=e.random??Math.random,s=[];for(let u=0;u<t;u++){const l=await Ge({...e,mode:e.mode??"background"});if(s.push(l),u<t-1){const c=l.ok?r:o,y=ht(c,n,a);y>0&&await xe(y)}}return{ok:s.every(u=>u.ok),runs:s,reasonCodes:Y(s.flatMap(u=>u.reasonCodes)),schedule:{intervalMs:r,backoffMs:o,jitterRatio:n,maxRuns:t},publicSafe:!0}}async function We(e){const t=ft(e.rawCommand);if(!t.ok||!t.command)return Xe(e.store,t,e.runnerId,e.nowIso),T(e.http,e.headers,{commandId:t.commandId??`pcmd-${A("invalid-command").slice(0,16)}`,jobId:t.jobId,action:t.action,runnerId:e.runnerId,identity:e.identity,idempotencyKey:`invalid:${t.commandId??"unknown"}`,localStatus:"rejected",remoteStatus:"rejected",reasonCode:d.PORTAL_COMMAND_PAYLOAD_REJECTED,publicSummary:"Runner rejected unsafe Portal command before local application.",acknowledgedAt:e.nowIso,redactionEvidence:t.redactions,counts:{rejected:1,redactions:t.redactions.length}});const r=t.command,o=U(r.commandId),n={commandId:r.commandId,jobId:r.jobId,action:r.action,runnerId:e.runnerId,identity:e.identity,idempotencyKey:r.idempotencyKey,acknowledgedAt:e.nowIso,redactionEvidence:t.redactions};if(r.expiresAt&&Date.parse(r.expiresAt)<=Date.parse(e.nowIso))return Q(e.store,r,{operationId:o,status:"ignored",reasonCode:d.COMMAND_EXPIRED,createdAt:e.nowIso,summary:"Portal command expired before local application.",redactionEvidence:t.redactions}),T(e.http,e.headers,{...n,localStatus:"expired",remoteStatus:"expired",reasonCode:d.COMMAND_EXPIRED,publicSummary:"Runner skipped expired Portal command.",counts:{expired:1}});if(e.store.hasOperationRef(o,r.idempotencyKey))return et(e.store,r,o,e.runnerId,e.nowIso,t.redactions),T(e.http,e.headers,{...n,localStatus:"already_applied",remoteStatus:"applied",reasonCode:d.IDEMPOTENCY_REPLAY,publicSummary:"Runner already applied Portal command; duplicate poll was acknowledged without local mutation.",counts:{alreadyApplied:1}});if(!e.store.jobExists(r.jobId))return T(e.http,e.headers,{...n,localStatus:"failed-local",remoteStatus:"rejected",reasonCode:d.INVALID_STATE_TRANSITION,publicSummary:"Runner could not find the public job for Portal command application.",counts:{failedLocal:1}});try{const a=be(r);return e.store.runInTransaction(()=>{Qe(e.store,r,e.nowIso),e.store.appendEvent({eventId:`${o}:event`,jobId:r.jobId,operationId:o,idempotencyKey:r.idempotencyKey,type:"portal_command_applied",summary:`Portal command ${r.action} applied locally by runner.`,reasonCode:a,createdAt:e.nowIso,metadata:x(r,o,e.runnerId,"applied",e.nowIso,t.redactions,a)}),e.store.appendReceipt({receiptId:`receipt-${o}`,jobId:r.jobId,operationId:o,idempotencyKey:r.idempotencyKey,status:"applied",reasonCode:a,appliedOperationIds:[o],createdAt:e.nowIso,metadata:x(r,o,e.runnerId,"applied",e.nowIso,t.redactions,a)})}),T(e.http,e.headers,{...n,localStatus:"applied",remoteStatus:"applied",reasonCode:a,publicSummary:`Runner applied Portal command ${r.action} locally.`,counts:{applied:1}})}catch{return Q(e.store,r,{operationId:o,status:"failed",reasonCode:d.INVALID_STATE_TRANSITION,createdAt:e.nowIso,summary:"Portal command failed local application with public reason code.",redactionEvidence:t.redactions}),T(e.http,e.headers,{...n,localStatus:"failed-local",remoteStatus:"rejected",reasonCode:d.INVALID_STATE_TRANSITION,publicSummary:"Runner failed local Portal command application with public reason code.",counts:{failedLocal:1}})}}function Qe(e,t,r){switch(t.action){case"pause":e.updateJobAndExistingGoalCampaignStatus({jobId:t.jobId,status:"paused",updatedAt:r,reasonCode:d.WAITING_HUMAN});return;case"resume":case"approve_review_gate":e.updateJobAndExistingGoalCampaignStatus({jobId:t.jobId,status:"active",updatedAt:r,reasonCode:d.OK});return;case"cancel":case"deny_review_gate":e.updateJobAndExistingGoalCampaignStatus({jobId:t.jobId,status:"cancelled",updatedAt:r,reasonCode:d.JOB_CANCELLED});return;case"answer_decision":if(t.decision?.option==="approve"){e.updateJobAndExistingGoalCampaignStatus({jobId:t.jobId,status:"active",updatedAt:r,reasonCode:d.OK});return}if(t.decision?.option==="deny"){e.updateJobAndExistingGoalCampaignStatus({jobId:t.jobId,status:"cancelled",updatedAt:r,reasonCode:d.JOB_CANCELLED});return}if(t.decision?.option==="hold"){e.updateJobAndExistingGoalCampaignStatus({jobId:t.jobId,status:"blocked",updatedAt:r,reasonCode:d.WAITING_HUMAN});return}throw new Error("unsupported-review-gate-decision");case"run_once":case"retry":e.scheduleNextTick({jobId:t.jobId,scheduledAt:r,updatedAt:r,reasonCode:d.OK});return;case"snapshot":e.recordStateSnapshot({snapshotId:`snapshot-${U(t.commandId)}`,jobId:t.jobId,kind:"portal_command_snapshot",summary:"Portal snapshot command recorded public local state checkpoint request.",capturedAt:r,operationId:U(t.commandId),idempotencyKey:t.idempotencyKey,metadata:x(t,U(t.commandId),t.runnerId,"applied",r,[],d.OK)});return;default:throw new Error("unsupported-command-action")}}async function T(e,t,r){return await F(e,{method:"POST",path:`/api/v1/continuity/runner/commands/${encodeURIComponent(r.commandId)}/ack`,body:{status:r.remoteStatus,runnerId:r.runnerId,workspaceId:r.identity.workspaceId,workspaceLabel:r.identity.workspaceLabel,projectId:r.identity.projectId,projectLabel:r.identity.projectLabel,idempotencyKey:r.idempotencyKey,reasonCode:r.reasonCode,publicSummary:m(r.publicSummary,280),counts:Re(r.counts),redactionEvidence:r.redactionEvidence.slice(0,20),publicSafe:!0},headers:t}),{commandId:r.commandId,...r.jobId?{jobId:r.jobId}:{},workspaceId:r.identity.workspaceId,workspaceLabel:r.identity.workspaceLabel,projectId:r.identity.projectId,projectLabel:r.identity.projectLabel,...r.action?{action:r.action}:{},localStatus:r.localStatus,remoteStatus:r.remoteStatus,reasonCode:r.reasonCode,publicSummary:m(r.publicSummary,280),acknowledgedAt:r.acknowledgedAt,counts:r.counts,redactionEvidence:r.redactionEvidence.slice(0,20),publicSafe:!0}}function Q(e,t,r){try{if(!e.jobExists(t.jobId)||e.hasOperationRef(r.operationId,t.idempotencyKey))return;e.appendReceipt({receiptId:`receipt-${r.operationId}`,jobId:t.jobId,operationId:r.operationId,idempotencyKey:t.idempotencyKey,status:r.status,reasonCode:r.reasonCode,ignoredOperationIds:[r.operationId],createdAt:r.createdAt,metadata:x(t,r.operationId,t.runnerId,r.status,r.createdAt,r.redactionEvidence,r.reasonCode)}),e.appendEvent({eventId:`${r.operationId}:event`,jobId:t.jobId,operationId:`${r.operationId}:event`,idempotencyKey:`${t.idempotencyKey}:event`,type:r.status==="failed"?"portal_command_failed":"portal_command_rejected",summary:r.summary,reasonCode:r.reasonCode,createdAt:r.createdAt,metadata:x(t,r.operationId,t.runnerId,r.status,r.createdAt,r.redactionEvidence,r.reasonCode)})}catch{}}function Xe(e,t,r,o){if(!t.commandId||!pe.test(t.commandId)||!t.jobId||!J(t.jobId)||!t.action||!ue.has(t.action))return;const n={commandId:t.commandId,jobId:t.jobId,action:t.action,status:"queued",queuedAt:o,idempotencyKey:`rejected:${t.commandId}`,delivery:"runner_poll",runnerId:r,reasonCode:d.PORTAL_COMMAND_PAYLOAD_REJECTED,publicSafe:!0};Q(e,n,{operationId:`${U(t.commandId)}:rejected`,status:"ignored",reasonCode:d.PORTAL_COMMAND_PAYLOAD_REJECTED,createdAt:o,summary:"Runner rejected unsafe Portal command before local application.",redactionEvidence:t.redactions})}function et(e,t,r,o,n,a){const s=`${r}:replay`;try{if(!e.jobExists(t.jobId)||e.hasOperationRef(s,`${t.idempotencyKey}:replay`))return;e.appendEvent({eventId:`${s}:event`,jobId:t.jobId,operationId:s,idempotencyKey:`${t.idempotencyKey}:replay`,type:"portal_command_replay",summary:"Runner recorded idempotent Portal command replay without local mutation.",reasonCode:d.IDEMPOTENCY_REPLAY,createdAt:n,metadata:x(t,s,o,"already_applied",n,a,d.IDEMPOTENCY_REPLAY)})}catch{}}function Ie(e,t){const r=It(e),o=e.jobs.filter(s=>["planned","active","running","backoff","waiting_external","waiting_human"].includes(s.status)).map(s=>s.jobId).filter(J).slice(0,20),n=e.staleLeases.map(s=>s.leaseId).filter(P).slice(0,20),a=we(e.dueJobs.map(s=>s.nextRunAt).filter(s=>!!s));return{schemaVersion:K,contractVersion:$,runnerId:t.runnerId,...t.sessionId?{sessionId:t.sessionId}:{},workspaceId:t.identity.workspaceId,workspaceLabel:t.identity.workspaceLabel,projectId:t.identity.projectId,projectLabel:t.identity.projectLabel,status:r,observedAt:t.generatedAt,version:m(t.clientVersion,80),activeJobIds:o,leaseIds:n,...a?{nextTickAt:a}:{},schedulerState:t.schedulerState,doctorSummary:r==="degraded"?"Runner sync is degraded by public stale lease or retryable outbox counts.":"Runner sync heartbeat contains public local continuity summaries.",reasonCode:r==="degraded"?d.BACKOFF_SCHEDULED:d.OK,queue:{depth:e.queue.depth,queued:e.queue.queued,running:e.queue.running,retrying:e.queue.retrying,deadLetter:e.queue.deadLetter,capacity:e.queue.capacity,available:e.queue.available,backpressure:e.queue.backpressure,generatedAt:e.queue.generatedAt,...e.queue.nextRetryAt?{nextRetryAt:e.queue.nextRetryAt}:{},...e.queue.reasonCode?{reasonCode:q(e.queue.reasonCode)}:{},publicSafe:!0},metadata:{schemaVersion:K,contractVersion:$,transportKind:"runner_heartbeat",...t.sessionId?{sessionId:t.sessionId}:{},workspaceId:t.identity.workspaceId,workspaceLabel:t.identity.workspaceLabel,projectId:t.identity.projectId,projectLabel:t.identity.projectLabel,observedAt:t.generatedAt,serverAccessToLocalhost:!1,serverHeldStream:!1,counts:{jobs:e.counts.jobs??e.jobs.length,dueJobs:e.dueJobCount,activeLeases:e.counts.activeLeases??0,staleLeases:e.counts.staleLeases??e.staleLeases.length,outboxPending:e.outbox.pending??0,outboxFailed:(e.outbox.failed??0)+(e.outbox.deadLetter??0),...N(e)},reasonCodes:[r==="degraded"?d.BACKOFF_SCHEDULED:d.OK],publicSummary:"Runner heartbeat generated from local continuity SQLite public summaries."},publicSafe:!0}}function tt(e,t){const r=e.jobs.map(s=>dt(s,t.identity,e)).slice(0,50),o=[...e.lastEvents.map(it),...(e.headlessExecutionAttempts??[]).map(ut)].slice(0,100),n=e.lastReceipts.map(lt).slice(0,100),a=yt(e,t.generatedAt);return{runnerId:t.runnerId,workspaceId:t.identity.workspaceId,workspaceLabel:t.identity.workspaceLabel,projectId:t.identity.projectId,projectLabel:t.identity.projectLabel,runner:{...t.heartbeat,metadata:{schemaVersion:K,contractVersion:$,syncVersion:Z,transportKind:"runner_sync",workspaceId:t.identity.workspaceId,workspaceLabel:t.identity.workspaceLabel,projectId:t.identity.projectId,projectLabel:t.identity.projectLabel,syncCursor:t.previousSyncCursor??"sync-initial",nextSyncCursor:t.nextSyncCursor,generatedAt:t.generatedAt,serverAccessToLocalhost:!1,serverHeldStream:!1,counts:{jobs:r.length,events:o.length,receipts:n.length,outbox:a.length,headlessExecutionAttempts:e.headlessExecutionAttempts?.length??0,...N(e)},publicSummary:"Runner sync uploaded public job, event and receipt summaries."}},jobs:r,events:o,receipts:n,outbox:a,runnerSync:{runnerId:t.runnerId,workspaceId:t.identity.workspaceId,workspaceLabel:t.identity.workspaceLabel,projectId:t.identity.projectId,projectLabel:t.identity.projectLabel,syncCursor:t.previousSyncCursor??"sync-initial",nextSyncCursor:t.nextSyncCursor,generatedAt:t.generatedAt,publicSummary:"Runner sync uploaded public job, event and receipt summaries.",counts:{jobs:r.length,events:o.length,receipts:n.length,outbox:a.length,...N(e)},publicSafe:!0}}}function rt(e,t,r){const o=ot({runnerId:r.runnerId,workspaceId:r.identity.workspaceId,projectId:r.identity.projectId,nextSyncCursor:r.nextSyncCursor}),n=nt({runnerId:r.runnerId,workspaceId:r.identity.workspaceId,projectId:r.identity.projectId,nextSyncCursor:r.nextSyncCursor});return e.enqueueOutbox({outboxId:o,jobId:st(t),operationId:`op-${o}`,idempotencyKey:`idem-${o}`,type:"runner_sync",status:"pending",payload:at(t,r),createdAt:r.generatedAt,updatedAt:r.generatedAt}),e.markOutboxSent({outboxId:o,deliveryCursor:n,sentAt:r.generatedAt,reasonCode:d.OK})}function ot(e){return`outbox-runner-sync-${A(`${e.runnerId}:${e.workspaceId}:${e.projectId??"project"}:${e.nextSyncCursor}`).slice(0,32)}`}function nt(e){return`cursor-runner-sync-${A(`${e.workspaceId}:${e.projectId??"project"}:${e.runnerId}:${e.nextSyncCursor}`).slice(0,32)}`}function at(e,t){return{schemaVersion:K,contractVersion:$,syncVersion:Z,transportKind:"runner_sync",envelopeId:`runner-sync-${A(`${t.runnerId}:${t.nextSyncCursor}`).slice(0,24)}`,runnerId:t.runnerId,workspaceId:t.identity.workspaceId,workspaceLabel:t.identity.workspaceLabel,projectId:t.identity.projectId,projectLabel:t.identity.projectLabel,syncCursor:t.previousSyncCursor??"sync-initial",nextSyncCursor:t.nextSyncCursor,generatedAt:t.generatedAt,serverAccessToLocalhost:!1,serverHeldStream:!1,counts:{jobs:e.counts.jobs??e.jobs.length,events:e.counts.events??e.lastEvents.length,receipts:e.counts.receipts??e.lastReceipts.length,outboxPending:e.outbox.pending??0,outboxFailed:e.outbox.failed??0,outboxDeadLetter:e.outbox.deadLetter??0,headlessExecutionAttempts:e.headlessExecutionAttempts?.length??0,...N(e)},redactionEvidence:[{field:"runnerSyncBody",reason:"unbounded_text",evidence:"operation-denied",publicSafe:!0}],publicSummary:"Runner sync outbox stores public IDs, counts, redaction evidence and cursor state only."}}function st(e){return e.jobs.map(t=>t.jobId).find(J)}function dt(e,t,r){const o=Me(e.currentStage)?e.currentStage:void 0,n=Fe(e.stageHistory),a=Ue(e.iteration),s=ct(e.jobId,r);return{jobId:e.jobId,workspaceId:t.workspaceId,workspaceLabel:t.workspaceLabel,projectId:t.projectId,projectLabel:t.projectLabel,kind:Lt(e.kind),status:kt(e.status),publicSummary:m(e.publicSummary,240),updatedAt:e.updatedAt,...e.nextRunAt?{nextRunAt:e.nextRunAt}:{},...e.reasonCode?{reasonCode:q(e.reasonCode)}:{},...e.counts?{counts:Re(e.counts)}:{},...s?{operations:s}:{},...o?{currentStage:o}:{},...n.length>0?{stageHistory:n}:{},...a!==void 0?{iteration:a}:{},publicSafe:!0}}function ct(e,t){const r=(t.headlessExecutionAttempts??[]).filter(c=>c.jobId===e).slice(0,50),o=t.staleLeases.filter(c=>c.jobId===e).slice(0,50);if(r.length===0&&o.length===0)return;const n=r.filter(c=>c.status==="backoff"||c.retryCount>0&&!!c.nextRetryAt).length,a=r.filter(c=>!!c.deadLetteredAt||c.status==="dead_letter").length,s=r.filter(c=>["queued","pending","backoff"].includes(c.status)).length,u=we(r.map(c=>c.nextRetryAt).filter(c=>!!c)),l=[...r].map(c=>c.leaseExpiresAt).filter(c=>!!c).sort().at(-1);return{attempts:r.length,retries:r.reduce((c,y)=>c+Math.max(0,Math.trunc(y.retryCount)),0),retrying:n,deadLetter:a,activeLeases:r.filter(c=>!!c.leaseId&&c.status==="running").length,staleLeases:o.length,queueDepth:s,backpressure:t.queue.backpressure&&s>0,generatedAt:t.generatedAt,...u?{nextRetryAt:u}:{},...l?{latestLeaseExpiresAt:l}:{},publicSafe:!0}}function it(e){return{eventId:e.eventId,jobId:e.jobId,operationId:e.operationId,type:m(e.type,80),summary:m(e.publicSummary,240),publicSummary:m(e.publicSummary,240),createdAt:e.createdAt,...e.metadata?{metadata:e.metadata}:{},...e.reasonCode?{reasonCode:q(e.reasonCode)}:{},publicSafe:!0}}function ut(e){return{eventId:`headless-${O(e.attemptId)}`,jobId:e.jobId,operationId:e.executionId,type:"headless_execution_attempt",summary:m(e.publicSummary,240),publicSummary:m(e.publicSummary,240),createdAt:e.heartbeatAt??e.enqueuedAt,...e.reasonCode?{reasonCode:q(e.reasonCode)}:{},publicSafe:!0}}function lt(e){return{receiptId:e.receiptId,jobId:e.jobId,...e.operationId?{operationId:e.operationId}:{},status:gt(e.status),summary:`Runner receipt ${e.status} for ${e.jobId}.`,createdAt:e.createdAt,...e.reasonCode?{reasonCode:q(e.reasonCode)}:{},publicSafe:!0}}function yt(e,t){const r=[];for(const[o,n]of Object.entries(e.outbox))o==="total"||!Number.isFinite(n)||n<=0||r.push({outboxId:`outbox-${o}`,operationId:`outbox-${o}-${A(t).slice(0,12)}`,status:o==="failed"||o==="deadLetter"?"failed":o==="acked"||o==="sent"?"applied":"accepted",summary:`Outbox ${o} count ${Math.trunc(n)} synced as public status evidence.`,updatedAt:t,reasonCode:o==="failed"||o==="deadLetter"?d.BACKOFF_SCHEDULED:d.OK,counts:{[o]:Math.trunc(n)},publicSafe:!0});return r.slice(0,20)}function ft(e){const t=[];if(!D(e))return t.push(i("command","unsafe_key","operation-denied")),{ok:!1,reasonCode:d.UNSAFE_FIELD_REJECTED,redactions:t};for(const y of Object.keys(e))(!le.has(y)||W.test(y))&&t.push(i(`command.${m(y,80)}`,"unsafe_key","key-denied"));for(const[y,h]of Object.entries(e))le.has(y)&&te(h,`command.${y}`,t);const r=typeof e.commandId=="string"?e.commandId:void 0,o=typeof e.jobId=="string"?e.jobId:void 0,n=typeof e.action=="string"?e.action:void 0,a=typeof e.status=="string"?e.status:void 0,s=typeof e.queuedAt=="string"?e.queuedAt:void 0,u=typeof e.idempotencyKey=="string"?e.idempotencyKey:void 0,l=typeof e.delivery=="string"?e.delivery:void 0;(!r||!pe.test(r))&&t.push(i("command.commandId","unsafe_key")),(!o||!J(o))&&t.push(i("command.jobId","unsafe_key")),(!n||!ue.has(n))&&t.push(i("command.action","unsafe_key")),a!=="queued"&&t.push(i("command.status","unsafe_key"));const c=pt(e.decision,n,t);return(!s||!Number.isFinite(Date.parse(s)))&&t.push(i("command.queuedAt","unsafe_key")),(!u||!P(u))&&t.push(i("command.idempotencyKey","unsafe_key")),l!=="runner_poll"&&t.push(i("command.delivery","unsafe_key")),e.publicSafe!==!0&&t.push(i("command.publicSafe","unsafe_key")),typeof e.expiresAt=="string"&&!Number.isFinite(Date.parse(e.expiresAt))&&t.push(i("command.expiresAt","unsafe_key")),typeof e.workspaceId=="string"&&!P(e.workspaceId)&&t.push(i("command.workspaceId","unsafe_key")),typeof e.workspaceLabel=="string"&&!je(e.workspaceLabel)&&t.push(i("command.workspaceLabel","unsafe_key")),typeof e.runnerId=="string"&&!fe.test(e.runnerId)&&t.push(i("command.runnerId","unsafe_key")),typeof e.projectId=="string"&&!P(e.projectId)&&t.push(i("command.projectId","unsafe_key")),typeof e.projectLabel=="string"&&!je(e.projectLabel)&&t.push(i("command.projectLabel","unsafe_key")),typeof e.reasonCode=="string"&&!V.test(e.reasonCode)&&t.push(i("command.reasonCode","unsafe_key")),t.length>0||!r||!o||!n||!s||!u||!l?{ok:!1,commandId:r,jobId:o,action:n,reasonCode:d.UNSAFE_FIELD_REJECTED,redactions:Et(t)}:{ok:!0,command:{commandId:r,jobId:o,action:n,...c?{decision:c}:{},status:a??"queued",queuedAt:s,...typeof e.expiresAt=="string"?{expiresAt:e.expiresAt}:{},idempotencyKey:u,delivery:l??"runner_poll",...typeof e.workspaceId=="string"?{workspaceId:e.workspaceId}:{},...typeof e.workspaceLabel=="string"?{workspaceLabel:e.workspaceLabel}:{},...typeof e.runnerId=="string"?{runnerId:e.runnerId}:{},...typeof e.projectId=="string"?{projectId:e.projectId}:{},...typeof e.projectLabel=="string"?{projectLabel:e.projectLabel}:{},...typeof e.reasonCode=="string"?{reasonCode:e.reasonCode}:{},publicSafe:!0},reasonCode:d.OK,redactions:[]}}function pt(e,t,r){if(t!=="answer_decision"&&t!=="approve_review_gate"&&t!=="deny_review_gate"){e!==void 0&&r.push(i("command.decision","unsafe_key"));return}if(e===void 0){t==="answer_decision"&&r.push(i("command.decision","unsafe_key"));return}if(!D(e)){r.push(i("command.decision","unsafe_key"));return}for(const n of Object.keys(e))(!qe.has(n)||W.test(n))&&r.push(i(`command.decision.${m(n,80)}`,"unsafe_key","key-denied"));const o=typeof e.option=="string"?e.option:void 0;if((!o||!ie.has(o))&&r.push(i("command.decision.option","unsafe_key")),typeof e.decisionId=="string"&&!P(e.decisionId)&&r.push(i("command.decision.decisionId","unsafe_key")),typeof e.gateId=="string"&&!P(e.gateId)&&r.push(i("command.decision.gateId","unsafe_key")),t==="approve_review_gate"&&o!=="approve"&&r.push(i("command.decision.option","unsafe_key")),t==="deny_review_gate"&&o!=="deny"&&r.push(i("command.decision.option","unsafe_key")),!(!o||!ie.has(o)))return{option:o,...typeof e.decisionId=="string"?{decisionId:e.decisionId}:{},...typeof e.gateId=="string"?{gateId:e.gateId}:{},publicSafe:!0}}function mt(e){return D(e)?Array.isArray(e.commands)?e.commands:[]:[]}function x(e,t,r,o,n,a,s){const u=s??be(e),l=r??e.runnerId;return{schemaVersion:K,contractVersion:$,syncVersion:Z,transportKind:"command_ack",actorType:"runner",...l?{actorId:l,runnerId:l}:{},jobId:e.jobId,...e.workspaceId?{workspaceId:e.workspaceId}:{},...e.workspaceLabel?{workspaceLabel:e.workspaceLabel}:{},...e.projectId?{projectId:e.projectId}:{},...e.projectLabel?{projectLabel:e.projectLabel}:{},operationId:t,idempotencyKey:e.idempotencyKey,commandId:e.commandId,commandKind:e.action,...e.decision?{decisionOption:e.decision.option}:{},...e.decision?.decisionId?{decisionId:e.decision.decisionId}:{},...e.decision?.gateId?{gateId:e.decision.gateId}:{},commandStatus:o,auditStatus:o,acknowledgedAt:n,reasonCode:u,redactionCount:a.length,redactionEvidence:a.slice(0,20),counts:{redactions:a.length},publicSummary:`Portal command ${e.action} ${o}.`}}function U(e){return`portal-command-${O(e)}`}function be(e){return e.action==="cancel"||e.action==="deny_review_gate"||e.action==="answer_decision"&&e.decision?.option==="deny"?d.JOB_CANCELLED:e.action==="pause"||e.action==="answer_decision"&&e.decision?.option==="hold"?d.WAITING_HUMAN:d.OK}function It(e){return(e.counts.staleLeases??0)>0||(e.outbox.failed??0)>0||(e.outbox.deadLetter??0)>0||e.queue.backpressure?"degraded":(e.counts.activeLeases??0)>0||e.dueJobCount>0||(e.counts.headlessRunningAttempts??0)>0?"busy":"idle"}function bt(e,t){return{jobs:e.counts.jobs??e.jobs.length,dueJobs:e.dueJobCount,activeLeases:e.counts.activeLeases??0,staleLeases:e.counts.staleLeases??e.staleLeases.length,headlessRunningAttempts:e.counts.headlessRunningAttempts??0,outboxPending:e.outbox.pending??0,outboxFailed:(e.outbox.failed??0)+(e.outbox.deadLetter??0),redactions:t,...N(e)}}function N(e){return{queueDepth:e.queue.depth,queueQueued:e.queue.queued,queueRunning:e.queue.running,queueRetrying:e.queue.retrying,queueDeadLetter:e.queue.deadLetter,queueCapacity:e.queue.capacity,queueAvailable:e.queue.available,queueBackpressure:e.queue.backpressure?1:0}}function At(e,t){return`sync-${A(JSON.stringify({generatedAt:t,counts:e.counts,outbox:e.outbox})).slice(0,24)}`}function Ae(e,t){const r=G(e),o=O(t.workspaceId??r.workspaceId),n=O(t.projectId??r.projectId),a=he(t.projectLabel??(t.projectId?void 0:r.projectLabel),t.projectId?`Project ${n}`:r.projectLabel),s=he(t.workspaceLabel??(t.workspaceId?void 0:r.workspaceLabel),t.workspaceId?`Workspace ${o}`:r.workspaceLabel);return{workspaceId:o,workspaceLabel:s,projectId:n,projectLabel:a}}function _e(e){return`runner-${A(e).slice(0,16)}`}function Ce(e){return`session-${A(`${e}:${process.pid}:${Be}`).slice(0,16)}`}function Se(e){if(!e)return;const t=O(e);return ye.test(t)?t.slice(0,96):void 0}function X(e){return(e.serverUrl??process.env.NEOCORTEX_SERVER_URL??se()?.serverUrl??$e).replace(/\/+$/,"")}async function ee(e){if(e.authToken)return e.authToken;if(e.httpClient)return;const t=X(e),r=e.licenseKey??se()?.licenseKey;if(r)return await new Ke({serverUrl:t,licenseKey:r,clientVersion:e.clientVersion??M}).getToken()??void 0}function Ee(e,t){return async r=>{if(!t)return{ok:!1,status:401,body:{reasonCode:d.AUTH_TOKEN_PERMISSION_FAILURE}};const o=new URL(`${e}${r.path}`);for(const[u,l]of Object.entries(r.query??{}))l!==void 0&&o.searchParams.set(u,l);const n=await fetch(o,{method:r.method,headers:r.headers,body:r.method==="POST"?JSON.stringify(r.body??{}):void 0}),a=await n.text().catch(()=>"");let s;try{s=a?JSON.parse(a):void 0}catch{s=void 0}return{ok:n.ok,status:n.status,body:s}}}function Le(e,t){return{"Content-Type":"application/json","X-Client-Version":m(e,80),...t?{Authorization:`Bearer ${t}`}:{}}}async function F(e,t,r={}){try{const o=_(r.timeoutMs??0,0,6e4),n=o>0?await Ct(e(t),o):await e(t);return n.ok?{ok:!0,body:n.body}:{ok:!1,reasonCode:_t(n.body,n.status),body:n.body}}catch{return{ok:!1,reasonCode:d.BACKOFF_SCHEDULED}}}function _t(e,t){if(D(e)){const r=typeof e.reasonCode=="string"?e.reasonCode:typeof e.error_code=="string"?e.error_code.toLowerCase().replaceAll("_","-"):void 0;if(r&&V.test(r))return r}return t===401||t===403?d.AUTH_TOKEN_PERMISSION_FAILURE:t===400?d.PORTAL_SYNC_PAYLOAD_REJECTED:d.BACKOFF_SCHEDULED}function ke(e){if(D(e)){const r=typeof e.reasonCode=="string"?e.reasonCode:typeof e.code=="string"?e.code:void 0;if(r&&V.test(r))return r}const t=e instanceof Error?e.message:String(e);return/sqlite-adapter-unavailable/i.test(t)?d.SQLITE_ADAPTER_UNAVAILABLE:/integrity|corrupt|malformed|not a database/i.test(t)?d.SQLITE_INTEGRITY_FAILED:d.BACKOFF_SCHEDULED}function Ct(e,t){return new Promise((r,o)=>{const n=setTimeout(()=>o(new Error("portal-http-timeout")),t);typeof n.unref=="function"&&n.unref(),e.then(a=>{clearTimeout(n),r(a)},a=>{clearTimeout(n),o(a)})})}function te(e,t,r){if(typeof e=="string"){g.test(e)&&r.push(i(t,St(e),"value-denied"));return}if(!(e===null||typeof e=="number"||typeof e=="boolean"||e===void 0)){if(Array.isArray(e)){for(const[o,n]of e.entries())te(n,`${t}.${o}`,r);return}if(D(e))for(const[o,n]of Object.entries(e)){const a=`${t}.${m(o,80)}`;W.test(o)&&r.push(i(a,"unsafe_key","key-denied")),te(n,a,r)}}}function St(e){return/https?:\/\//i.test(e)?"private_url":/(?:^|\s)(?:\/(?:home|Users|media|mnt|tmp|var|etc|private)\/\S+|[A-Za-z]:\\\S+)/i.test(e)?"local_absolute_path":/secret|token|password|api[_-]?key|license[_-]?key|authorization/i.test(e)?"secret":/stdout|stderr|raw[_-]?log|transcript|stack/i.test(e)?"raw_log":/prompt|workflow body|step body/i.test(e)?"prompt_body":"protected_field"}function i(e,t,r="value-denied"){return{field:m(e,120),reason:t,evidence:r,publicSafe:!0}}function Et(e){const t=new Set,r=[];for(const o of e){const n=`${o.field}:${o.reason}:${o.evidence}`;t.has(n)||(t.add(n),r.push(o))}return r.slice(0,20)}function ge(e){const t=O(e);return fe.test(t)?t:`runner-${A(e).slice(0,16)}`}function O(e){if(g.test(e))return`id-${A(e).slice(0,16)}`;const t=e.replace(/[^A-Za-z0-9._:-]+/g,"-").replace(/^-+|-+$/g,"").slice(0,120);return t.length>0?t:`id-${A(e).slice(0,16)}`}function he(e,t){const r=(e??"").replace(/\s+/g," ").trim();if(!r||g.test(r)||me.test(r))return t;const o=r.replace(/[^A-Za-z0-9 ._-]+/g," ").replace(/\s+/g," ").trim();return o?o.length<=80?o:`${o.slice(0,77)}...`:t}function P(e){return ye.test(e)&&!g.test(e)}function je(e){return e.trim().length>0&&e.length<=80&&!g.test(e)&&!me.test(e)}function J(e){return ze.test(e)&&!g.test(e)}function q(e){return V.test(e)&&!g.test(e)?e:d.OK}function Lt(e){return["goal","loop","runner","jobs"].includes(e)?e:"jobs"}function kt(e){return["draft","planned","active","running","waiting_external","waiting_human","backoff","paused","blocked","completed","aborted","cancelled"].includes(e)?e:"active"}function gt(e){return["accepted","applied","ignored","failed","deferred"].includes(e)?e:"accepted"}function Re(e){const t={};for(const[r,o]of Object.entries(e))/^[A-Za-z][A-Za-z0-9_:-]{0,63}$/.test(r)&&Number.isFinite(o)&&o>=0&&(t[r]=Math.trunc(o));return t}function we(e){return e.filter(t=>Number.isFinite(Date.parse(t))).sort()[0]}function _(e,t,r){return Number.isFinite(e)?Math.max(t,Math.min(r,Math.floor(e))):t}function Te(e,t,r){return Number.isFinite(e)?Math.max(t,Math.min(r,e)):t}function ht(e,t,r){if(e<=0)return 0;if(t<=0)return e;const o=Te(r(),0,1),n=Math.floor(e*t*o);return Math.max(0,e+n)}function A(e){return ve("sha256").update(e).digest("hex")}function m(e,t){const r=g.test(e)?"[REDACTED]":e;return r.length<=t?r:`${r.slice(0,t)}...[TRUNCATED:${r.length-t}]`}function D(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function Y(e){return Array.from(new Set(e))}function xe(e){return new Promise(t=>setTimeout(t,e))}export{Ve as DEFAULT_RUNNER_HEARTBEAT_BACKOFF_MS,He as DEFAULT_RUNNER_HEARTBEAT_INTERVAL_MS,Ye as DEFAULT_RUNNER_HEARTBEAT_JITTER_RATIO,Je as DEFAULT_RUNNER_HEARTBEAT_TIMEOUT_MS,d as RUNNER_PORTAL_SYNC_REASON_CODES,Ge as runRunnerPortalHeartbeat,vt as runRunnerPortalHeartbeatLoop,Ze as runRunnerPortalSync,Dt as runRunnerPortalSyncLoop};
@@ -0,0 +1,19 @@
1
+ /**
2
+ * @license FSL-1.1
3
+ * Copyright (c) 2026 OrNexus AI
4
+ *
5
+ * P197.01 -- shared client-local project identity derivation.
6
+ */
7
+ export declare const PROJECT_IDENTITY_HASH_CHARS: 12;
8
+ export declare const PROJECT_IDENTITY_LABEL_CHARS: 24;
9
+ export interface ProjectIdentity {
10
+ readonly projectId: string;
11
+ readonly projectLabel: string;
12
+ readonly workspaceId: string;
13
+ readonly workspaceLabel: string;
14
+ readonly publicSafe: true;
15
+ }
16
+ export declare function deriveProjectIdentity(projectRoot: string): ProjectIdentity;
17
+ export declare function normalizeIdentityRoot(value: string): string;
18
+ export declare function basenameForIdentity(normalizedRoot: string): string;
19
+ export declare function sanitizeProjectBasename(value: string): string;
@@ -0,0 +1 @@
1
+ import{createHash as L}from"node:crypto";import{isAbsolute as d,resolve as f}from"node:path";const h=12,R=24,i="project",y="workspace",_=/(?:@|ghp_[A-Za-z0-9_]+|sk-[A-Za-z0-9_-]+|password|passwd|secret|token|api[_-]?key|license[_-]?key|private[_-]?key|credential|customer[_-]?pii|\bpii\b)/i;function B(t){const e=typeof t=="string"?t:"",n=$(e)??f(e||"."),r=A(n),a=A(e||"."),o=m(z(a),i),u=g(o,r),s=C(a),p=T(r),l=s?m(s,y):o,I=s&&p?g(l,p):u;return{projectId:u,projectLabel:o,workspaceId:I,workspaceLabel:l,publicSafe:!0}}function A(t){let e=t.replace(/\\/g,"/").replace(/\/+$/g,"");return e||(e="/"),e=e.replace(/^([A-Z]):\//,(n,r)=>`${r.toLowerCase()}:/`),e}function z(t){const e=c(t);return e[e.length-1]??i}function b(t){return t.normalize("NFKD").replace(/[\u0300-\u036f]/g,"").toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,R).replace(/-+$/g,"")||i}function g(t,e){return`${t}-${E(e)}`}function E(t){return L("sha256").update(t).digest("hex").slice(0,h)}function m(t,e){if(_.test(t))return e;const n=b(t);return _.test(n)?e:n}function C(t){const e=c(t);if(e.length<2)return;const n=e[e.length-2];if(!/^[A-Za-z]:$/.test(n))return n}function T(t){const e=c(t);if(e.length<2||/^[A-Za-z]:$/.test(e[e.length-2]??""))return;const n=e.slice(0,-1);return/^[A-Za-z]:$/.test(n[0]??"")?n.join("/"):t.startsWith("/")?`/${n.join("/")}`:n.join("/")}function c(t){return t.split("/").filter(Boolean)}function $(t){if(!t||/[\r\n\0]/.test(t))return null;const e=d(t)?t:f(t);return d(e)?e:null}export{h as PROJECT_IDENTITY_HASH_CHARS,R as PROJECT_IDENTITY_LABEL_CHARS,z as basenameForIdentity,B as deriveProjectIdentity,A as normalizeIdentityRoot,b as sanitizeProjectBasename};
@@ -0,0 +1,186 @@
1
+ /**
2
+ * @license FSL-1.1
3
+ * Copyright (c) 2026 OrNexus AI
4
+ *
5
+ * P180.07 -- user-scope scheduler install/start/stop/status/doctor for
6
+ * `neocortex-runner`.
7
+ */
8
+ import { type RunnerBinaryResolveOptions, type RunnerBinaryResolution } from './binary.js';
9
+ export declare const SCHEDULER_REASON_CODES: Readonly<{
10
+ readonly OK: "continuity-ok";
11
+ readonly SCHEDULER_INSTALL_UNSAFE: "scheduler-install-unsafe";
12
+ readonly PRIMARY_USER_SCHEDULER_UNAVAILABLE: "primary-user-scheduler-unavailable";
13
+ readonly CRON_FALLBACK_SELECTED: "cron-fallback-selected";
14
+ readonly CRON_FALLBACK_NOT_ALLOWED: "cron-fallback-primary-scheduler-available";
15
+ readonly SCHEDULER_UNAVAILABLE: "scheduler-unavailable";
16
+ readonly SCHEDULER_COMMAND_FAILED: "scheduler-command-failed";
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";
29
+ }>;
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;
32
+ export type SchedulerCommand = 'install' | 'start' | 'stop' | 'status' | 'doctor';
33
+ export type SchedulerStrategy = 'systemd-user' | 'launchd-user' | 'windows-task-scheduler' | 'cron-fallback';
34
+ export interface SchedulerBinaryTrustResult {
35
+ readonly trusted: boolean;
36
+ readonly reasonCode?: string;
37
+ readonly reasonCodes?: readonly string[];
38
+ readonly packageName?: string;
39
+ readonly packageVersion?: string;
40
+ readonly packageRoot?: string;
41
+ readonly executablePath?: string;
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;
51
+ readonly publicSafe: true;
52
+ }
53
+ export interface SchedulerManifest {
54
+ readonly kind: 'systemd-service' | 'systemd-timer' | 'launchd-plist' | 'windows-task-xml' | 'cron-snippet';
55
+ readonly path: string;
56
+ readonly content: string;
57
+ readonly publicSafe: true;
58
+ }
59
+ export interface SchedulerControlCommand {
60
+ readonly command: string;
61
+ readonly args: readonly string[];
62
+ readonly preview: string;
63
+ readonly safeUserScope: true;
64
+ readonly manualOnly?: boolean;
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
+ }
92
+ export interface SchedulerCommandRunResult {
93
+ readonly ok: boolean;
94
+ readonly code?: number | null;
95
+ readonly signal?: string | null;
96
+ readonly reasonCode?: string;
97
+ }
98
+ export interface SchedulerCapabilityReport {
99
+ readonly platform: NodeJS.Platform;
100
+ readonly primaryStrategy?: SchedulerStrategy;
101
+ readonly selectedStrategy?: SchedulerStrategy;
102
+ readonly fallbackStrategy?: SchedulerStrategy;
103
+ readonly primaryAvailable: boolean;
104
+ readonly cronFallbackAvailable: boolean;
105
+ readonly safeToInstall: boolean;
106
+ readonly blockers: readonly SchedulerReasonCode[];
107
+ readonly reasonCodes: readonly SchedulerReasonCode[];
108
+ readonly publicSafe: true;
109
+ }
110
+ export interface RunnerSchedulerCommandOptions {
111
+ readonly command: SchedulerCommand;
112
+ readonly projectRoot?: string;
113
+ readonly executablePath?: string;
114
+ readonly platform?: NodeJS.Platform;
115
+ readonly env?: NodeJS.ProcessEnv;
116
+ readonly dryRun?: boolean;
117
+ readonly intervalSeconds?: number;
118
+ readonly strategy?: SchedulerStrategy;
119
+ readonly allowCronFallback?: boolean;
120
+ readonly trustCheck?: boolean;
121
+ readonly uid?: number | null;
122
+ readonly commandAvailable?: (command: string) => boolean;
123
+ readonly commandRunner?: (command: SchedulerControlCommand) => SchedulerCommandRunResult;
124
+ readonly trustChecker?: (executablePath: string | undefined) => SchedulerBinaryTrustResult;
125
+ readonly binaryResolver?: (options: RunnerBinaryResolveOptions) => RunnerBinaryResolution;
126
+ readonly now?: () => string;
127
+ }
128
+ export interface RunnerSchedulerCommandResult {
129
+ readonly ok: boolean;
130
+ readonly command: SchedulerCommand;
131
+ readonly platform: NodeJS.Platform;
132
+ readonly strategy?: SchedulerStrategy;
133
+ readonly dryRun: boolean;
134
+ readonly manifestPaths: readonly string[];
135
+ readonly manifests: readonly SchedulerManifest[];
136
+ readonly identity: SchedulerProjectIdentity;
137
+ readonly legacyEntries: readonly SchedulerLegacyEntry[];
138
+ readonly controlCommands: readonly SchedulerControlCommand[];
139
+ readonly uninstallGuidance: readonly string[];
140
+ readonly capability: SchedulerCapabilityReport;
141
+ readonly reasonCodes: readonly SchedulerReasonCode[];
142
+ readonly applied: boolean;
143
+ readonly publicSafe: true;
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>;
161
+ export declare function runRunnerSchedulerCommand(options: RunnerSchedulerCommandOptions): Promise<RunnerSchedulerCommandResult>;
162
+ export declare function detectSchedulerCapability(input?: {
163
+ readonly platform?: NodeJS.Platform;
164
+ readonly env?: NodeJS.ProcessEnv;
165
+ readonly strategy?: SchedulerStrategy;
166
+ readonly allowCronFallback?: boolean;
167
+ readonly uid?: number | null;
168
+ readonly commandAvailable?: (command: string) => boolean;
169
+ }): SchedulerCapabilityReport;
170
+ export declare function renderSchedulerManifests(input: {
171
+ readonly strategy: SchedulerStrategy;
172
+ readonly paths: SchedulerPaths;
173
+ readonly projectRoot: string;
174
+ readonly executablePath: string;
175
+ readonly runnerCommand?: SchedulerRunnerCommand;
176
+ readonly intervalSeconds: number;
177
+ readonly identity?: SchedulerProjectIdentity;
178
+ }): readonly SchedulerManifest[];
179
+ interface SchedulerPaths {
180
+ readonly systemdServicePath: string;
181
+ readonly systemdTimerPath: string;
182
+ readonly launchdPlistPath: string;
183
+ readonly windowsTaskXmlPath: string;
184
+ readonly cronSnippetPath: string;
185
+ }
186
+ export {};
@@ -0,0 +1,7 @@
1
+ import{Buffer as le}from"node:buffer";import{spawnSync as ie}from"node:child_process";import{existsSync as j,mkdirSync as de,readFileSync as me,writeFileSync as pe}from"node:fs";import{delimiter as fe,dirname as he,isAbsolute as F,join as c,resolve as Q}from"node:path";import{checkRunnerBinaryTrust as ye,resolveTrustedRunnerBinary as z}from"./binary.js";import{deriveProjectIdentity as Ee}from"./project-identity.js";const i=Object.freeze({OK:"continuity-ok",SCHEDULER_INSTALL_UNSAFE:"scheduler-install-unsafe",PRIMARY_USER_SCHEDULER_UNAVAILABLE:"primary-user-scheduler-unavailable",CRON_FALLBACK_SELECTED:"cron-fallback-selected",CRON_FALLBACK_NOT_ALLOWED:"cron-fallback-primary-scheduler-available",SCHEDULER_UNAVAILABLE:"scheduler-unavailable",SCHEDULER_COMMAND_FAILED:"scheduler-command-failed",RUNNER_BINARY_UNTRUSTED:"runner-binary-untrusted",LEGACY_GLOBAL_SCHEDULER_DETECTED:"legacy-global-scheduler-detected",LEGACY_GLOBAL_SCHEDULER_AMBIGUOUS:"legacy-global-scheduler-ambiguous",LEGACY_GLOBAL_SCHEDULER_OTHER_PROJECT:"legacy-global-scheduler-other-project"}),b=Object.freeze({OK:"runner-bootstrap-ok",ALREADY_ACTIVE:"runner-bootstrap-already-active",BINARY_UNAVAILABLE:"runner-bootstrap-binary-unavailable",INSTALL_FAILED:"runner-bootstrap-install-failed",START_FAILED:"runner-bootstrap-start-failed",UNEXPECTED_ERROR:"runner-bootstrap-unexpected-error"}),$="neocortex-runner",ge=`${$}.service`,N=`${$}.timer`,B="com.ornexus.neocortex.runner",Se=`${B}.plist`,M="NeocortexRunner",Ce="neocortex-runner-task.xml",Le="runner.cron",ke=60,H=new Map;function G(e){const r=y(e)??Q(e||"."),t=Ee(r),n=t.projectLabel,s=t.projectId,a=`${$}-${s}`,o=`com.ornexus.neocortex.runner.${s}`;return{projectKey:s,projectBasename:n,systemdServiceName:`${a}.service`,systemdTimerName:`${a}.timer`,systemdServiceFile:`${a}.service`,systemdTimerFile:`${a}.timer`,launchdLabel:o,launchdFile:`${o}.plist`,windowsTaskName:`NeocortexRunner-${s}`,windowsXmlFile:`${a}-task.xml`,cronFile:`runner-${s}.cron`,cronMarkerStart:`# BEGIN neocortex-runner:${s}`,cronMarkerEnd:`# END neocortex-runner:${s}`,publicSafe:!0}}function cr(){H.clear()}async function ur(e={}){const r=e.platform??process.platform,t=y(e.projectRoot??process.cwd())??process.cwd(),n=G(t),s=`${r}:${n.projectKey}`,a=H.get(s);if(a?.ok)return{...a,attempted:!1,installed:!1,started:!1,cached:!0,reasonCodes:S([...a.reasonCodes,b.ALREADY_ACTIVE]),publicSummary:"runner scheduler bootstrap already active for project key.",publicSafe:!0};try{const o=e.binaryResolver??z,d=y(e.executablePath??process.argv[1])??process.argv[1],E=o({from:d,platform:r});if(!E.ok)return w({projectKey:n.projectKey,reasonCodes:[b.BINARY_UNAVAILABLE,...E.reasonCodes],publicSummary:"runner scheduler bootstrap could not resolve a trusted runner binary."});const l=Ae(e.env??process.env),g={...e,projectRoot:t,executablePath:E.executablePath,platform:r,env:l,binaryResolver:()=>E},p=await q({...g,command:"install"});if(!p.ok)return w({projectKey:n.projectKey,strategy:p.strategy,reasonCodes:[b.INSTALL_FAILED,...p.reasonCodes],publicSummary:"runner scheduler bootstrap install failed.",attempted:!0});const f=await q({...g,command:"start"});if(!f.ok)return w({projectKey:n.projectKey,strategy:f.strategy??p.strategy,reasonCodes:[b.START_FAILED,...f.reasonCodes],publicSummary:"runner scheduler bootstrap start failed.",attempted:!0,installed:p.applied||p.ok});const L={ok:!0,attempted:!0,installed:p.applied||p.ok,started:f.applied||f.ok,cached:!1,projectKey:n.projectKey,strategy:f.strategy??p.strategy,reasonCodes:S([b.OK,...p.reasonCodes,...f.reasonCodes]),publicSummary:"runner scheduler bootstrap completed for project key.",publicSafe:!0};return H.set(s,L),L}catch{return w({projectKey:n.projectKey,reasonCodes:[b.UNEXPECTED_ERROR],publicSummary:"runner scheduler bootstrap stopped unexpectedly."})}}function w(e){return{ok:!1,attempted:e.attempted??!1,installed:e.installed??!1,started:!1,cached:!1,projectKey:e.projectKey,strategy:e.strategy,reasonCodes:S(e.reasonCodes),publicSummary:e.publicSummary,publicSafe:!0}}function Ae(e){return{...e,NEOCORTEX_RUNNER_BOOTSTRAP_IN_PROGRESS:"1",NEOCORTEX_BOOTSTRAP_IN_PROGRESS:"1"}}async function q(e){const r=e.env??process.env,t=e.platform??process.platform,n=e.dryRun===!0,s=y(e.projectRoot??process.cwd()),a=y(e.executablePath??process.argv[1]),o=We(e,a,t),d=o.runnerCommand,E=d?.executablePath??a,l=G(s??process.cwd()),g=e.commandAvailable??(h=>te(h,r)),p=Ze(e.intervalSeconds??ke,10,1440*60),f=be({platform:t,env:r,strategy:e.strategy,allowCronFallback:e.allowCronFallback,commandAvailable:g,uid:e.uid}),L=Qe(e,E,o.resolution),k=[...f.blockers];if((!s||!d)&&k.push(i.SCHEDULER_INSTALL_UNSAFE),!L.trusted){const h=L.reasonCodes&&L.reasonCodes.length>0?L.reasonCodes:[L.reasonCode??i.RUNNER_BINARY_UNTRUSTED];k.push(i.SCHEDULER_INSTALL_UNSAFE,i.RUNNER_BINARY_UNTRUSTED,...h)}const m=f.selectedStrategy;m||k.push(i.SCHEDULER_UNAVAILABLE);const A=m?_e(m,r,l):void 0,R=m&&s&&He(e.command)?Ge({strategy:m,env:r,projectRoot:s}):[],ue=R.flatMap(h=>h.reasonCodes),O=(e.command==="install"||e.command==="start"||e.command==="stop")&&k.length>0,Y=S([...f.reasonCodes,...k,...ue,O?i.SCHEDULER_INSTALL_UNSAFE:i.OK]);if(O||!m||!A||!s||!d)return{ok:!O&&!!m,command:e.command,platform:t,strategy:m,dryRun:n,manifestPaths:[],manifests:[],identity:l,legacyEntries:R,controlCommands:[],uninstallGuidance:m&&A?Z(m,A,l):[],capability:ne(f,k),reasonCodes:Y,applied:!1,publicSafe:!0};const T=e.command==="install"?Re({strategy:m,paths:A,projectRoot:s,executablePath:d.command,runnerCommand:d,intervalSeconds:p,identity:l}):[],I=Te(e.command,m,A,l,R,r);let U=!1,x=!0;const X=[];if(e.command==="install"&&!n){for(const h of T)de(he(h.path),{recursive:!0}),pe(h.path,h.content,"utf8");U=T.length>0}if(!n&&I.length>0){const h=e.commandRunner??ze;for(const V of I){if(V.manualOnly)continue;const W=h(V);W.ok?U=!0:(x=!1,X.push(W.reasonCode??i.SCHEDULER_COMMAND_FAILED))}}return{ok:x,command:e.command,platform:t,strategy:m,dryRun:n,manifestPaths:T.map(h=>h.path),manifests:T,identity:l,legacyEntries:R,controlCommands:I,uninstallGuidance:[...Z(m,A,l),...Ue(m,R)],capability:ne(f,k),reasonCodes:S([...Y,...X,x?i.OK:i.SCHEDULER_COMMAND_FAILED]),applied:U,publicSafe:!0}}function be(e={}){const r=e.env??process.env,t=e.platform??process.platform,n=e.commandAvailable??(p=>te(p,r)),s=Ve(t,r,e.uid),a=Xe(t),o=a?ee(a,n):!1,d=t!=="win32"&&n("crontab"),E=e.allowCronFallback!==!1;let l=e.strategy;const g=[];return l||(a&&o?l=a:E&&d&&(l="cron-fallback",g.push(i.PRIMARY_USER_SCHEDULER_UNAVAILABLE,i.CRON_FALLBACK_SELECTED))),l==="cron-fallback"&&o&&(l=void 0,g.push(i.CRON_FALLBACK_NOT_ALLOWED)),l&&!ee(l,n)&&(l!=="cron-fallback"||!d)&&(l=void 0),l||g.push(i.SCHEDULER_UNAVAILABLE),s.length>0&&g.push(...s),g.length===0&&g.push(i.OK),{platform:t,primaryStrategy:a,selectedStrategy:l,fallbackStrategy:d?"cron-fallback":void 0,primaryAvailable:o,cronFallbackAvailable:d,safeToInstall:s.length===0,blockers:s,reasonCodes:S(g),publicSafe:!0}}function Re(e){const r=e.identity??G(e.projectRoot),t=e.runnerCommand??{command:e.executablePath,args:[],executablePath:e.executablePath,publicSafe:!0};switch(e.strategy){case"systemd-user":return[{kind:"systemd-service",path:e.paths.systemdServicePath,content:xe(t,e.projectRoot,r),publicSafe:!0},{kind:"systemd-timer",path:e.paths.systemdTimerPath,content:Fe(e.intervalSeconds,r),publicSafe:!0}];case"launchd-user":return[{kind:"launchd-plist",path:e.paths.launchdPlistPath,content:$e(t,e.projectRoot,e.intervalSeconds,r),publicSafe:!0}];case"windows-task-scheduler":return[{kind:"windows-task-xml",path:e.paths.windowsTaskXmlPath,content:Be(t,e.projectRoot,e.intervalSeconds,r),publicSafe:!0}];case"cron-fallback":return[{kind:"cron-snippet",path:e.paths.cronSnippetPath,content:Me(t,e.projectRoot,r),publicSafe:!0}]}}function _e(e,r,t){const n=re(r),s=y(r.XDG_CONFIG_HOME)??c(n,".config"),a=c(s,"systemd","user"),o=c(n,"Library","LaunchAgents"),d=y(r.APPDATA)??c(y(r.USERPROFILE)??n,"AppData","Roaming"),E=c(d,"Neocortex","Runner"),l=c(s,"neocortex");return{systemdServicePath:c(a,t.systemdServiceFile),systemdTimerPath:c(a,t.systemdTimerFile),launchdPlistPath:c(o,t.launchdFile),windowsTaskXmlPath:c(E,t.windowsXmlFile),cronSnippetPath:c(l,t.cronFile)}}function J(e,r){const t=re(r),n=y(r.XDG_CONFIG_HOME)??c(t,".config"),s=c(n,"systemd","user"),a=c(t,"Library","LaunchAgents"),o=y(r.APPDATA)??c(y(r.USERPROFILE)??t,"AppData","Roaming"),d=c(o,"Neocortex","Runner"),E=c(n,"neocortex");return{systemdServicePath:c(s,ge),systemdTimerPath:c(s,N),launchdPlistPath:c(a,Se),windowsTaskXmlPath:c(d,Ce),cronSnippetPath:c(E,Le)}}function Te(e,r,t,n,s,a){return e==="doctor"?[]:[...e==="install"?Ne(r,t,n):e==="start"?we(r,t,n):e==="stop"?Pe(r,t,n):De(r,t,n),...ve(e,r,s,a)]}function Ne(e,r,t){switch(e){case"systemd-user":return[u("systemctl",["--user","daemon-reload"]),u("systemctl",["--user","enable","--now",t.systemdTimerName])];case"launchd-user":return[u("launchctl",["load","-w",r.launchdPlistPath])];case"windows-task-scheduler":return[u("schtasks",["/Create","/TN",t.windowsTaskName,"/XML",r.windowsTaskXmlPath,"/F"])];case"cron-fallback":return[u("crontab",["-l","# append snippet from",r.cronSnippetPath],!0)]}}function we(e,r,t){switch(e){case"systemd-user":return[u("systemctl",["--user","start",t.systemdTimerName])];case"launchd-user":return[u("launchctl",["load","-w",r.launchdPlistPath])];case"windows-task-scheduler":return[u("schtasks",["/Run","/TN",t.windowsTaskName])];case"cron-fallback":return[u("crontab",["-l","# ensure snippet from",r.cronSnippetPath,"is installed"],!0)]}}function Pe(e,r,t){switch(e){case"systemd-user":return[u("systemctl",["--user","stop",t.systemdTimerName])];case"launchd-user":return[u("launchctl",["unload","-w",r.launchdPlistPath])];case"windows-task-scheduler":return[u("schtasks",["/End","/TN",t.windowsTaskName])];case"cron-fallback":return[u("crontab",["-l","# remove scoped neocortex-runner snippet"],!0)]}}function De(e,r,t){switch(e){case"systemd-user":return[u("systemctl",["--user","status",t.systemdTimerName,"--no-pager"])];case"launchd-user":return[u("launchctl",["list",t.launchdLabel])];case"windows-task-scheduler":return[u("schtasks",["/Query","/TN",t.windowsTaskName,"/FO","LIST"])];case"cron-fallback":return[u("crontab",["-l","# look for neocortex-runner snippet from",r.cronSnippetPath],!0)]}}function Z(e,r,t){switch(e){case"systemd-user":return[`systemctl --user disable --now ${t.systemdTimerName}`,`rm ${r.systemdServicePath}`,`rm ${r.systemdTimerPath}`];case"launchd-user":return[`launchctl unload -w ${r.launchdPlistPath}`,`rm ${r.launchdPlistPath}`];case"windows-task-scheduler":return[`schtasks /Delete /TN ${t.windowsTaskName} /F`,`Remove-Item ${r.windowsTaskXmlPath}`];case"cron-fallback":return[`Remove the ${t.cronMarkerStart} block from the user crontab.`,`rm ${r.cronSnippetPath}`]}}function ve(e,r,t,n){if(!t.some(o=>o.relation==="current-project")||e!=="status"&&e!=="stop")return[];const a=J(r,n);return e==="status"?Oe(r,a):Ie(r,a)}function Oe(e,r){switch(e){case"systemd-user":return[u("systemctl",["--user","status",N,"--no-pager"])];case"launchd-user":return[u("launchctl",["list",B])];case"windows-task-scheduler":return[u("schtasks",["/Query","/TN",M,"/FO","LIST"])];case"cron-fallback":return[u("crontab",["-l","# look for legacy neocortex-runner snippet from",r.cronSnippetPath],!0)]}}function Ie(e,r){switch(e){case"systemd-user":return[u("systemctl",["--user","stop",N])];case"launchd-user":return[u("launchctl",["unload","-w",r.launchdPlistPath])];case"windows-task-scheduler":return[u("schtasks",["/End","/TN",M])];case"cron-fallback":return[u("crontab",["-l","# remove legacy neocortex-runner snippet"],!0)]}}function Ue(e,r){if(r.length===0)return[];const t=r.filter(o=>o.relation==="current-project"),n=r.filter(o=>o.relation==="ambiguous"),s=r.filter(o=>o.relation==="other-project"),a=[];return t.length>0&&a.push(`Legacy global ${e} scheduler matches this project; stop it before relying on project-scoped runner scheduling.`),n.length>0&&a.push(`Legacy global ${e} scheduler ownership is ambiguous; inspect it manually before removal.`),s.length>0&&a.push(`Legacy global ${e} scheduler appears to belong to another project; leave it unchanged.`),a}function xe(e,r,t){const n=[...je(e),"tick","--project-root",r,"--scheduled"].map(se).join(" ");return["[Unit]",`Description=Neocortex Enterprise Continuity Runner (${t.projectKey}, user scope)`,`# Managed by Neocortex runner for project ${t.projectKey}`,"After=network-online.target","","[Service]","Type=oneshot",`WorkingDirectory=${oe(r)}`,`ExecStart=${n}`,"","[Install]","WantedBy=default.target",""].join(`
2
+ `)}function je(e){const r=y(process.execPath);return!r||e.command===r?[e.command,...e.args]:[r,e.command,...e.args]}function Fe(e,r){return["[Unit]",`Description=Run Neocortex Enterprise Continuity Runner periodically (${r.projectKey}, user scope)`,`# Managed by Neocortex runner for project ${r.projectKey}`,"","[Timer]","OnBootSec=60s",`OnUnitActiveSec=${e}s`,`Unit=${r.systemdServiceName}`,"","[Install]","WantedBy=timers.target",""].join(`
3
+ `)}function $e(e,r,t,n){const s=[e.command,...e.args,"tick","--project-root",r,"--scheduled"];return['<?xml version="1.0" encoding="UTF-8"?>','<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">','<plist version="1.0">',"<dict>",` <!-- Managed by Neocortex runner for project ${C(n.projectKey)} -->`," <key>Label</key>",` <string>${C(n.launchdLabel)}</string>`," <key>ProgramArguments</key>"," <array>",...s.map(a=>` <string>${C(a)}</string>`)," </array>"," <key>WorkingDirectory</key>",` <string>${C(r)}</string>`," <key>StartInterval</key>",` <integer>${t}</integer>`," <key>RunAtLoad</key>"," <true/>","</dict>","</plist>",""].join(`
4
+ `)}function Be(e,r,t,n){const s=[...e.args,"tick","--project-root",r,"--scheduled"].map(ce).join(" ");return['<?xml version="1.0" encoding="UTF-16"?>','<Task version="1.4" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">'," <RegistrationInfo>",` <Description>Neocortex Enterprise Continuity Runner (${C(n.projectKey)}, user scope)</Description>`," </RegistrationInfo>"," <Triggers>"," <TimeTrigger>"," <Repetition>",` <Interval>PT${t}S</Interval>`," <StopAtDurationEnd>false</StopAtDurationEnd>"," </Repetition>"," <Enabled>true</Enabled>"," </TimeTrigger>"," </Triggers>"," <Principals>",' <Principal id="Author">'," <LogonType>InteractiveToken</LogonType>"," <RunLevel>LeastPrivilege</RunLevel>"," </Principal>"," </Principals>"," <Settings>"," <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>"," <DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>"," <StopIfGoingOnBatteries>false</StopIfGoingOnBatteries>"," <Enabled>true</Enabled>"," </Settings>",' <Actions Context="Author">'," <Exec>",` <Command>${C(e.command)}</Command>`,` <Arguments>${C(s)}</Arguments>`,` <WorkingDirectory>${C(r)}</WorkingDirectory>`," </Exec>"," </Actions>","</Task>",""].join(`
5
+ `)}function Me(e,r,t){const n=[e.command,...e.args,"tick","--project-root",r,"--scheduled"].map(K).join(" ");return[t.cronMarkerStart,`# neocortex-runner user-scope cron fallback for project ${t.projectKey}`,"# Reason: primary-user-scheduler-unavailable",`* * * * * ${n} # neocortex-runner:${t.projectKey}`,t.cronMarkerEnd,""].join(`
6
+ `)}function He(e){return e==="status"||e==="stop"||e==="doctor"}function Ge(e){const r=J(e.strategy,e.env);switch(e.strategy){case"systemd-user":{const t=_(r.systemdServicePath),n=_(r.systemdTimerPath),s=t?v(t):!1,a=n?Ye(n):!1;if(!s&&!a)return[];const o=D([t,n].filter(Boolean).join(`
7
+ `),e.projectRoot,s);return[P(e.strategy,"systemd-timer",N,o)]}case"launchd-user":{const t=_(r.launchdPlistPath);return!t||!v(t)?[]:[P(e.strategy,"launchd-plist",B,D(t,e.projectRoot,!0))]}case"windows-task-scheduler":{const t=_(r.windowsTaskXmlPath);return!t||!v(t)?[]:[P(e.strategy,"windows-task-xml",M,D(t,e.projectRoot,!0))]}case"cron-fallback":{const t=_(r.cronSnippetPath);return!t||!v(t)?[]:[P(e.strategy,"cron-snippet","# neocortex-runner",D(t,e.projectRoot,!0))]}}}function P(e,r,t,n){const s=n==="current-project"?i.LEGACY_GLOBAL_SCHEDULER_DETECTED:n==="ambiguous"?i.LEGACY_GLOBAL_SCHEDULER_AMBIGUOUS:i.LEGACY_GLOBAL_SCHEDULER_OTHER_PROJECT;return{strategy:e,kind:r,name:t,relation:n,reasonCodes:[s],remediation:n==="current-project"?"stop-safe":n==="ambiguous"?"manual-review-only":"report-only",publicSafe:!0}}function D(e,r,t){return Ke(e,r)?"current-project":t&&/--project-root|WorkingDirectory=|<key>WorkingDirectory<\/key>|<Arguments>[^<]*--project-root/i.test(e)?"other-project":"ambiguous"}function Ke(e,r){return S([r,se(r),qe(r),oe(r),Je(r),K(r),ce(r),C(r)].filter(Boolean)).some(n=>e.includes(n))}function v(e){return/neocortex-runner|com\.ornexus\.neocortex\.runner|NeocortexRunner|Neocortex Enterprise Continuity Runner/i.test(e)&&/tick|--project-root|StartInterval|OnUnitActiveSec|InteractiveToken|primary-user-scheduler-unavailable/i.test(e)}function Ye(e){return/neocortex-runner\.service|Neocortex Enterprise Continuity Runner|OnUnitActiveSec/i.test(e)}function _(e){try{return me(e,"utf8")}catch{return null}}function Xe(e){if(e==="linux")return"systemd-user";if(e==="darwin")return"launchd-user";if(e==="win32")return"windows-task-scheduler"}function ee(e,r){switch(e){case"systemd-user":return r("systemctl");case"launchd-user":return r("launchctl");case"windows-task-scheduler":return r("schtasks")||r("schtasks.exe");case"cron-fallback":return r("crontab")}}function Ve(e,r,t){const n=[],s=t??(typeof process.getuid=="function"?process.getuid():null);e!=="win32"&&s===0&&n.push(i.SCHEDULER_INSTALL_UNSAFE),e!=="win32"&&(r.SUDO_USER||r.SUDO_UID||r.SUDO_COMMAND)&&n.push(i.SCHEDULER_INSTALL_UNSAFE);const a=r.HOME??r.USERPROFILE;return(!a||!F(a)||!y(a))&&n.push(i.SCHEDULER_INSTALL_UNSAFE),S(n)}function We(e,r,t){if(e.trustCheck===!1||e.trustChecker)return{runnerCommand:r?{command:r,args:[],executablePath:r,publicSafe:!0}:void 0};const s=(e.binaryResolver??z)({from:r??process.argv[1],platform:t});return s.ok?{runnerCommand:{command:s.command,args:s.args,executablePath:s.executablePath,provenance:s.provenance,publicSafe:!0},resolution:s}:{runnerCommand:r?{command:r,args:[],executablePath:r,provenance:s.provenance,publicSafe:!0}:void 0,resolution:s}}function Qe(e,r,t){return e.trustCheck===!1?{trusted:!0,executablePath:r??void 0,publicSafe:!0}:e.trustChecker?e.trustChecker(r??void 0):t?t.ok?{trusted:!0,packageName:t.packageName,packageVersion:t.packageVersion,packageRoot:t.packageRoot,executablePath:t.executablePath,expectedRelativePath:t.expectedRelativePath,provenance:t.provenance,reasonCodes:t.reasonCodes,publicSafe:!0}:{trusted:!1,reasonCode:t.reasonCode,reasonCodes:t.reasonCodes,packageName:t.packageName,packageVersion:t.packageVersion,packageRoot:t.packageRoot,executablePath:t.executablePath??r??void 0,expectedRelativePath:t.expectedRelativePath,provenance:t.provenance,publicSafe:!0}:ye(r??void 0)}function re(e){return e.HOME??e.USERPROFILE??process.env.HOME??process.cwd()}function y(e){if(!e||/[\r\n\0]/.test(e))return null;const r=F(e)?e:Q(e);return F(r)?r:null}function u(e,r,t=!1){return{command:e,args:r,preview:[e,...r.map(K)].join(" "),safeUserScope:!0,...t?{manualOnly:!0}:{}}}function ze(e){const r=ie(e.command,[...e.args],{stdio:"ignore",shell:!1});return{ok:r.status===0,code:r.status,signal:r.signal,reasonCode:r.status===0?i.OK:i.SCHEDULER_COMMAND_FAILED}}function te(e,r){const t=r.PATH??process.env.PATH??"",n=(r.PATHEXT??".EXE;.CMD;.BAT;.COM").split(";").filter(Boolean),s=t.split(fe).filter(Boolean);for(const a of s){const o=c(a,e);if(j(o))return!0;for(const d of n)if(j(c(a,`${e}${d.toLowerCase()}`))||j(c(a,`${e}${d.toUpperCase()}`)))return!0}return!1}function ne(e,r){const t=S([...e.blockers,...r]);return{...e,safeToInstall:t.length===0,blockers:t,reasonCodes:S([...e.reasonCodes,...t])}}function se(e){return ae(e,!0)}function qe(e){return ae(e,!1)}function ae(e,r){const t=e.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/%/g,r?"%%":"%");return/[\s"'\\]/.test(e)?`"${t}"`:t}function oe(e){return e.replace(/%/g,"%%")}function Je(e){return Array.from(e,r=>/^[A-Za-z0-9_./:@+=,-]$/.test(r)?r:r==="%"?"%%":Array.from(le.from(r,"utf8"),t=>`\\x${t.toString(16).padStart(2,"0")}`).join("")).join("")}function K(e){return/^[A-Za-z0-9_./:=@%+-]+$/.test(e)?e:`'${e.replace(/'/g,"'\\''")}'`}function ce(e){return/[\s"]/.test(e)?`"${e.replace(/"/g,'\\"')}"`:e}function C(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&apos;")}function Ze(e,r,t){return Number.isFinite(e)?Math.max(r,Math.min(t,Math.floor(e))):r}function S(e){return Array.from(new Set(e))}export{b as RUNNER_SCHEDULER_BOOTSTRAP_REASON_CODES,i as SCHEDULER_REASON_CODES,cr as __resetRunnerSchedulerBootstrapCacheForTests,G as createRunnerSchedulerIdentity,be as detectSchedulerCapability,ur as ensureRunnerSchedulerBootstrap,Re as renderSchedulerManifests,q as runRunnerSchedulerCommand};
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * @license FSL-1.1
4
+ * Copyright (c) 2026 OrNexus AI
5
+ *
6
+ * Published neocortex-runner binary shim. The implementation lives in
7
+ * `runner/cli.ts`; this top-level source emits `dist/runner-cli.js`.
8
+ */
9
+ export {};
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ import{runRunnerCli as r}from"./runner/cli.js";r(process.argv.slice(2)).then(e=>{process.exit(e)}).catch(e=>{const s=e instanceof Error?e.message:String(e);process.stderr.write(JSON.stringify({error_code:"runner-fatal",message:s})+`
3
+ `),process.exit(1)});
@@ -0,0 +1,24 @@
1
+ /**
2
+ * @license FSL-1.1
3
+ * Copyright (c) 2026 OrNexus AI
4
+ *
5
+ * Pure request-scoped projection helpers for invoke state snapshots.
6
+ */
7
+ import type { StateSnapshot } from '../commands/invoke.js';
8
+ /**
9
+ * P198.04 -- deterministic post-assembly state degradation.
10
+ *
11
+ * This helper is intentionally pure and request-only. It removes historical story
12
+ * bodies that are not structural for the already-projected request, converts the
13
+ * epic map to public stubs, keeps `stateSummary`, and preserves structural-required
14
+ * story/yolo/yoloop target state instead of silently corrupting it.
15
+ */
16
+ export declare function degradeStateSnapshotForPayloadLimit(snapshot: StateSnapshot): StateSnapshot;
17
+ /**
18
+ * Return a request-scoped state snapshot for invoke commands.
19
+ *
20
+ * The function is intentionally pure. If a structural-required target cannot be
21
+ * proven from the already-sanitized snapshot, it returns a full scoped snapshot
22
+ * instead of sending an ambiguous partial projection.
23
+ */
24
+ export declare function projectStateSnapshotForInvoke(args: string, snapshot: StateSnapshot): StateSnapshot;