@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.
- package/LICENSE +56 -0
- package/LICENSE-COMMERCIAL.md +70 -0
- package/README.md +58 -0
- package/dist/sbom.cdx.json +11159 -0
- package/docs/install/coderabbit-manual-setup.md +86 -0
- package/docs/install/installer-diagnostics.md +107 -0
- package/docs/install/linux-global-install.md +97 -0
- package/install.js +572 -0
- package/install.ps1 +2214 -0
- package/install.sh +2013 -0
- package/package.json +132 -0
- package/packages/client/dist/adapters/adapter-registry.d.ts +61 -0
- package/packages/client/dist/adapters/adapter-registry.js +1 -0
- package/packages/client/dist/adapters/antigravity-adapter.d.ts +18 -0
- package/packages/client/dist/adapters/antigravity-adapter.js +2 -0
- package/packages/client/dist/adapters/claude-code-adapter.d.ts +19 -0
- package/packages/client/dist/adapters/claude-code-adapter.js +3 -0
- package/packages/client/dist/adapters/codex-adapter.d.ts +19 -0
- package/packages/client/dist/adapters/codex-adapter.js +2 -0
- package/packages/client/dist/adapters/cursor-adapter.d.ts +19 -0
- package/packages/client/dist/adapters/cursor-adapter.js +4 -0
- package/packages/client/dist/adapters/gemini-adapter.d.ts +18 -0
- package/packages/client/dist/adapters/gemini-adapter.js +2 -0
- package/packages/client/dist/adapters/index.d.ts +19 -0
- package/packages/client/dist/adapters/index.js +1 -0
- package/packages/client/dist/adapters/platform-detector.d.ts +48 -0
- package/packages/client/dist/adapters/platform-detector.js +1 -0
- package/packages/client/dist/adapters/target-adapter.d.ts +70 -0
- package/packages/client/dist/adapters/target-adapter.js +0 -0
- package/packages/client/dist/adapters/vscode-adapter.d.ts +19 -0
- package/packages/client/dist/adapters/vscode-adapter.js +2 -0
- package/packages/client/dist/agent/refresh-stubs.d.ts +90 -0
- package/packages/client/dist/agent/refresh-stubs.js +2 -0
- package/packages/client/dist/agent/update-agent-yaml.d.ts +26 -0
- package/packages/client/dist/agent/update-agent-yaml.js +1 -0
- package/packages/client/dist/agent/update-description.d.ts +45 -0
- package/packages/client/dist/agent/update-description.js +1 -0
- package/packages/client/dist/cache/crypto-utils.d.ts +30 -0
- package/packages/client/dist/cache/crypto-utils.js +1 -0
- package/packages/client/dist/cache/encrypted-cache.d.ts +30 -0
- package/packages/client/dist/cache/encrypted-cache.js +1 -0
- package/packages/client/dist/cache/in-memory-asset-cache.d.ts +62 -0
- package/packages/client/dist/cache/in-memory-asset-cache.js +1 -0
- package/packages/client/dist/cache/index.d.ts +13 -0
- package/packages/client/dist/cache/index.js +1 -0
- package/packages/client/dist/cache/protected-pi-boundary.d.ts +19 -0
- package/packages/client/dist/cache/protected-pi-boundary.js +1 -0
- package/packages/client/dist/checkpoint/checkpoint-client-reader.d.ts +45 -0
- package/packages/client/dist/checkpoint/checkpoint-client-reader.js +2 -0
- package/packages/client/dist/checkpoint/index.d.ts +12 -0
- package/packages/client/dist/checkpoint/index.js +1 -0
- package/packages/client/dist/checkpoint/shared-checkpoint-types.d.ts +85 -0
- package/packages/client/dist/checkpoint/shared-checkpoint-types.js +1 -0
- package/packages/client/dist/cli.d.ts +14 -0
- package/packages/client/dist/cli.js +81 -0
- package/packages/client/dist/commands/activate.d.ts +55 -0
- package/packages/client/dist/commands/activate.js +8 -0
- package/packages/client/dist/commands/cache-status.d.ts +39 -0
- package/packages/client/dist/commands/cache-status.js +2 -0
- package/packages/client/dist/commands/invoke.d.ts +546 -0
- package/packages/client/dist/commands/invoke.js +140 -0
- package/packages/client/dist/commands/refresh-memory.d.ts +11 -0
- package/packages/client/dist/commands/refresh-memory.js +1 -0
- package/packages/client/dist/config/resolver-selection.d.ts +40 -0
- package/packages/client/dist/config/resolver-selection.js +1 -0
- package/packages/client/dist/config/secure-config.d.ts +78 -0
- package/packages/client/dist/config/secure-config.js +12 -0
- package/packages/client/dist/constants.d.ts +25 -0
- package/packages/client/dist/constants.js +1 -0
- package/packages/client/dist/context/context-collector.d.ts +28 -0
- package/packages/client/dist/context/context-collector.js +2 -0
- package/packages/client/dist/context/context-sanitizer.d.ts +28 -0
- package/packages/client/dist/context/context-sanitizer.js +1 -0
- package/packages/client/dist/continuity/autonomous-governance.d.ts +84 -0
- package/packages/client/dist/continuity/autonomous-governance.js +1 -0
- package/packages/client/dist/continuity/continuity-client-state-store.d.ts +302 -0
- package/packages/client/dist/continuity/continuity-client-state-store.js +1 -0
- package/packages/client/dist/continuity/invoke-hooks.d.ts +19 -0
- package/packages/client/dist/continuity/invoke-hooks.js +1 -0
- package/packages/client/dist/continuity/migrations/001-initial-schema.d.ts +11 -0
- package/packages/client/dist/continuity/migrations/001-initial-schema.js +263 -0
- package/packages/client/dist/continuity/migrations/002-processing-output-summary-indexes.d.ts +11 -0
- package/packages/client/dist/continuity/migrations/002-processing-output-summary-indexes.js +7 -0
- package/packages/client/dist/continuity/migrations/003-headless-execution-attempts.d.ts +11 -0
- package/packages/client/dist/continuity/migrations/003-headless-execution-attempts.js +62 -0
- package/packages/client/dist/continuity/migrations/004-outbox-delivery-state.d.ts +11 -0
- package/packages/client/dist/continuity/migrations/004-outbox-delivery-state.js +19 -0
- package/packages/client/dist/continuity/migrations/005-bounded-headless-queue.d.ts +11 -0
- package/packages/client/dist/continuity/migrations/005-bounded-headless-queue.js +35 -0
- package/packages/client/dist/continuity/outbox.d.ts +83 -0
- package/packages/client/dist/continuity/outbox.js +1 -0
- package/packages/client/dist/continuity/runner-bootstrap-policy.d.ts +50 -0
- package/packages/client/dist/continuity/runner-bootstrap-policy.js +1 -0
- package/packages/client/dist/continuity/sqlite-store.d.ts +926 -0
- package/packages/client/dist/continuity/sqlite-store.js +619 -0
- package/packages/client/dist/errors/error-messages.d.ts +40 -0
- package/packages/client/dist/errors/error-messages.js +2 -0
- package/packages/client/dist/graph-retrieval/pre-command-hook.d.ts +34 -0
- package/packages/client/dist/graph-retrieval/pre-command-hook.js +1 -0
- package/packages/client/dist/graph-retrieval/shared-graph-retrieval-contract.d.ts +99 -0
- package/packages/client/dist/graph-retrieval/shared-graph-retrieval-contract.js +1 -0
- package/packages/client/dist/i18n/first-run.d.ts +23 -0
- package/packages/client/dist/i18n/first-run.js +2 -0
- package/packages/client/dist/index.d.ts +56 -0
- package/packages/client/dist/index.js +1 -0
- package/packages/client/dist/license/index.d.ts +5 -0
- package/packages/client/dist/license/index.js +1 -0
- package/packages/client/dist/license/license-client.d.ts +79 -0
- package/packages/client/dist/license/license-client.js +1 -0
- package/packages/client/dist/machine/fingerprint.d.ts +34 -0
- package/packages/client/dist/machine/fingerprint.js +2 -0
- package/packages/client/dist/machine/index.d.ts +5 -0
- package/packages/client/dist/machine/index.js +1 -0
- package/packages/client/dist/memory/project-memory-writer.d.ts +74 -0
- package/packages/client/dist/memory/project-memory-writer.js +36 -0
- package/packages/client/dist/memory/shared-project-memory-types.d.ts +370 -0
- package/packages/client/dist/memory/shared-project-memory-types.js +2 -0
- package/packages/client/dist/policy/architecture-policy.d.ts +40 -0
- package/packages/client/dist/policy/architecture-policy.js +2 -0
- package/packages/client/dist/policy/index.d.ts +8 -0
- package/packages/client/dist/policy/index.js +1 -0
- package/packages/client/dist/policy/shared-policy-types.d.ts +89 -0
- package/packages/client/dist/policy/shared-policy-types.js +0 -0
- package/packages/client/dist/resilience/circuit-breaker.d.ts +70 -0
- package/packages/client/dist/resilience/circuit-breaker.js +1 -0
- package/packages/client/dist/resilience/degradation-manager.d.ts +67 -0
- package/packages/client/dist/resilience/degradation-manager.js +1 -0
- package/packages/client/dist/resilience/freshness-indicator.d.ts +59 -0
- package/packages/client/dist/resilience/freshness-indicator.js +1 -0
- package/packages/client/dist/resilience/index.d.ts +8 -0
- package/packages/client/dist/resilience/index.js +1 -0
- package/packages/client/dist/resilience/recovery-detector.d.ts +59 -0
- package/packages/client/dist/resilience/recovery-detector.js +1 -0
- package/packages/client/dist/resolvers/asset-resolver.d.ts +79 -0
- package/packages/client/dist/resolvers/asset-resolver.js +0 -0
- package/packages/client/dist/resolvers/local-resolver.d.ts +26 -0
- package/packages/client/dist/resolvers/local-resolver.js +8 -0
- package/packages/client/dist/resolvers/remote-resolver.d.ts +91 -0
- package/packages/client/dist/resolvers/remote-resolver.js +1 -0
- package/packages/client/dist/runner/binary.d.ts +115 -0
- package/packages/client/dist/runner/binary.js +1 -0
- package/packages/client/dist/runner/cli.d.ts +168 -0
- package/packages/client/dist/runner/cli.js +70 -0
- package/packages/client/dist/runner/headless/adapters.d.ts +20 -0
- package/packages/client/dist/runner/headless/adapters.js +1 -0
- package/packages/client/dist/runner/headless/claude-code-adapter.d.ts +8 -0
- package/packages/client/dist/runner/headless/claude-code-adapter.js +1 -0
- package/packages/client/dist/runner/headless/fake-adapter.d.ts +8 -0
- package/packages/client/dist/runner/headless/fake-adapter.js +1 -0
- package/packages/client/dist/runner/headless/opencode-adapter.d.ts +15 -0
- package/packages/client/dist/runner/headless/opencode-adapter.js +2 -0
- package/packages/client/dist/runner/headless/resolver.d.ts +68 -0
- package/packages/client/dist/runner/headless/resolver.js +1 -0
- package/packages/client/dist/runner/headless/run-yolo.d.ts +59 -0
- package/packages/client/dist/runner/headless/run-yolo.js +1 -0
- package/packages/client/dist/runner/headless/run-yoloop.d.ts +113 -0
- package/packages/client/dist/runner/headless/run-yoloop.js +1 -0
- package/packages/client/dist/runner/headless/types.d.ts +194 -0
- package/packages/client/dist/runner/headless/types.js +2 -0
- package/packages/client/dist/runner/local-console.d.ts +83 -0
- package/packages/client/dist/runner/local-console.js +13 -0
- package/packages/client/dist/runner/portal-sync-worker.d.ts +184 -0
- package/packages/client/dist/runner/portal-sync-worker.js +1 -0
- package/packages/client/dist/runner/project-identity.d.ts +19 -0
- package/packages/client/dist/runner/project-identity.js +1 -0
- package/packages/client/dist/runner/scheduler.d.ts +186 -0
- package/packages/client/dist/runner/scheduler.js +7 -0
- package/packages/client/dist/runner-cli.d.ts +9 -0
- package/packages/client/dist/runner-cli.js +3 -0
- package/packages/client/dist/state/project-state-snapshot.d.ts +24 -0
- package/packages/client/dist/state/project-state-snapshot.js +1 -0
- package/packages/client/dist/state/state-json-repair.d.ts +74 -0
- package/packages/client/dist/state/state-json-repair.js +3 -0
- package/packages/client/dist/telemetry/index.d.ts +5 -0
- package/packages/client/dist/telemetry/index.js +1 -0
- package/packages/client/dist/telemetry/offline-queue.d.ts +57 -0
- package/packages/client/dist/telemetry/offline-queue.js +1 -0
- package/packages/client/dist/tier/index.d.ts +5 -0
- package/packages/client/dist/tier/index.js +1 -0
- package/packages/client/dist/tier/tier-aware-client.d.ts +105 -0
- package/packages/client/dist/tier/tier-aware-client.js +1 -0
- package/packages/client/dist/types/index.d.ts +140 -0
- package/packages/client/dist/types/index.js +1 -0
- package/packages/client/dist/yoloop/discovery-hook.d.ts +85 -0
- package/packages/client/dist/yoloop/discovery-hook.js +2 -0
- package/packages/client/dist/yoloop/index.d.ts +10 -0
- package/packages/client/dist/yoloop/index.js +1 -0
- package/packages/client/dist/yoloop/invoke-hooks.d.ts +127 -0
- package/packages/client/dist/yoloop/invoke-hooks.js +5 -0
- package/packages/client/dist/yoloop/shared-discover-epics.d.ts +289 -0
- package/packages/client/dist/yoloop/shared-discover-epics.js +1 -0
- package/packages/client/dist/yoloop/shared-yoloop-types.d.ts +172 -0
- package/packages/client/dist/yoloop/shared-yoloop-types.js +1 -0
- package/packages/client/dist/yoloop/yoloop-client-state-store.d.ts +124 -0
- package/packages/client/dist/yoloop/yoloop-client-state-store.js +1 -0
- package/postinstall.js +754 -0
- package/targets-stubs/antigravity/README.md +36 -0
- package/targets-stubs/antigravity/gemini.md +29 -0
- package/targets-stubs/antigravity/install-antigravity.sh +153 -0
- package/targets-stubs/antigravity/mcp-config.json +30 -0
- package/targets-stubs/antigravity/skill/SKILL.md +166 -0
- package/targets-stubs/claude-code/.mcp.json +32 -0
- package/targets-stubs/claude-code/README.md +20 -0
- package/targets-stubs/claude-code/neocortex-root.agent.yaml +42 -0
- package/targets-stubs/claude-code/neocortex-root.md +317 -0
- package/targets-stubs/claude-code/neocortex.agent.yaml +42 -0
- package/targets-stubs/claude-code/neocortex.md +385 -0
- package/targets-stubs/codex/AGENTS.md +250 -0
- package/targets-stubs/codex/README.md +47 -0
- package/targets-stubs/codex/config-mcp.toml +22 -0
- package/targets-stubs/codex/install-codex.sh +63 -0
- package/targets-stubs/codex/neocortex.toml +33 -0
- package/targets-stubs/cursor/README.md +33 -0
- package/targets-stubs/cursor/agent.md +211 -0
- package/targets-stubs/cursor/install-cursor.sh +50 -0
- package/targets-stubs/cursor/mcp.json +30 -0
- package/targets-stubs/gemini-cli/README.md +34 -0
- package/targets-stubs/gemini-cli/agent.md +241 -0
- package/targets-stubs/gemini-cli/agents/neocortex.md +60 -0
- package/targets-stubs/gemini-cli/gemini.md +46 -0
- package/targets-stubs/gemini-cli/install-gemini.sh +70 -0
- package/targets-stubs/gemini-cli/settings-mcp.json +30 -0
- package/targets-stubs/kimi/mcp.json +33 -0
- package/targets-stubs/kimi/neocortex.md +60 -0
- package/targets-stubs/lib/mcp-merge.js +189 -0
- package/targets-stubs/openclaw/README.md +12 -0
- package/targets-stubs/openclaw/SKILL.md +92 -0
- package/targets-stubs/opencode/neocortex-root.md +267 -0
- package/targets-stubs/opencode/neocortex.md +65 -0
- package/targets-stubs/opencode/opencode-mcp.json +35 -0
- package/targets-stubs/vscode/README.md +34 -0
- package/targets-stubs/vscode/copilot-instructions.md +47 -0
- package/targets-stubs/vscode/install-vscode.sh +72 -0
- package/targets-stubs/vscode/mcp.json +36 -0
- package/targets-stubs/vscode/neocortex.agent.md +252 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license FSL-1.1
|
|
3
|
+
* Copyright (c) 2026 OrNexus AI
|
|
4
|
+
*
|
|
5
|
+
* This file is part of Neocortex CLI, licensed under the
|
|
6
|
+
* Functional Source License, Version 1.1 (FSL-1.1).
|
|
7
|
+
*
|
|
8
|
+
* Change Date: February 20, 2029
|
|
9
|
+
* Change License: MIT
|
|
10
|
+
*
|
|
11
|
+
* See the LICENSE file in the project root for full license text.
|
|
12
|
+
*/
|
|
13
|
+
export type CircuitState = 'CLOSED' | 'OPEN' | 'HALF_OPEN';
|
|
14
|
+
export interface CircuitBreakerConfig {
|
|
15
|
+
/** Number of failures within window to trip circuit. Default: 3 */
|
|
16
|
+
failureThreshold: number;
|
|
17
|
+
/** Window in ms for counting failures. Default: 60_000 (60s) */
|
|
18
|
+
failureWindowMs: number;
|
|
19
|
+
/** Time in ms before OPEN transitions to HALF_OPEN. Default: 60_000 (60s) */
|
|
20
|
+
halfOpenAfterMs: number;
|
|
21
|
+
/** Path to persist circuit state. Default: ~/.neocortex/.circuit-state */
|
|
22
|
+
stateFilePath: string;
|
|
23
|
+
}
|
|
24
|
+
export interface FailureRecord {
|
|
25
|
+
timestamp: number;
|
|
26
|
+
}
|
|
27
|
+
export interface CircuitBreakerState {
|
|
28
|
+
state: CircuitState;
|
|
29
|
+
failures: FailureRecord[];
|
|
30
|
+
openedAt: number | null;
|
|
31
|
+
lastProbeAt: number | null;
|
|
32
|
+
}
|
|
33
|
+
export declare class ClientCircuitBreaker {
|
|
34
|
+
private readonly config;
|
|
35
|
+
private internalState;
|
|
36
|
+
constructor(config?: Partial<CircuitBreakerConfig>, initialState?: CircuitBreakerState);
|
|
37
|
+
/**
|
|
38
|
+
* Check if a request can be made to the server.
|
|
39
|
+
* Returns false if circuit is OPEN (fail-fast to cache).
|
|
40
|
+
*/
|
|
41
|
+
canCall(): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Record a successful server response. Closes the circuit.
|
|
44
|
+
*/
|
|
45
|
+
recordSuccess(): Promise<void>;
|
|
46
|
+
/**
|
|
47
|
+
* Record a failed server response. Opens circuit after threshold failures in window.
|
|
48
|
+
*/
|
|
49
|
+
recordFailure(): Promise<void>;
|
|
50
|
+
/**
|
|
51
|
+
* Get current circuit breaker state (copy).
|
|
52
|
+
*/
|
|
53
|
+
getState(): CircuitBreakerState;
|
|
54
|
+
/**
|
|
55
|
+
* Reset circuit breaker to initial CLOSED state.
|
|
56
|
+
*/
|
|
57
|
+
reset(): Promise<void>;
|
|
58
|
+
/**
|
|
59
|
+
* Load circuit breaker state from disk.
|
|
60
|
+
*/
|
|
61
|
+
static loadFromDisk(path?: string): Promise<ClientCircuitBreaker>;
|
|
62
|
+
/**
|
|
63
|
+
* Remove failures outside the counting window.
|
|
64
|
+
*/
|
|
65
|
+
private pruneExpiredFailures;
|
|
66
|
+
/**
|
|
67
|
+
* Persist state to disk with atomic write.
|
|
68
|
+
*/
|
|
69
|
+
private saveToDisk;
|
|
70
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{readFile as l,writeFile as o,mkdir as h}from"node:fs/promises";import{dirname as u}from"node:path";import{homedir as c}from"node:os";import{join as f}from"node:path";const n={failureThreshold:3,failureWindowMs:6e4,halfOpenAfterMs:6e4,stateFilePath:f(c(),".neocortex",".circuit-state")},r={state:"CLOSED",failures:[],openedAt:null,lastProbeAt:null};class i{config;internalState;constructor(t,e){this.config={...n,...t},this.internalState=e?{...e}:{...r,failures:[]}}canCall(){switch(this.pruneExpiredFailures(),this.internalState.state){case"CLOSED":return!0;case"OPEN":{const t=Date.now(),e=this.internalState.openedAt??0;return t-e>=this.config.halfOpenAfterMs?(this.internalState.state="HALF_OPEN",this.internalState.lastProbeAt=t,!0):!1}case"HALF_OPEN":return!0;default:return!0}}async recordSuccess(){this.internalState.state="CLOSED",this.internalState.failures=[],this.internalState.openedAt=null,this.internalState.lastProbeAt=null,await this.saveToDisk()}async recordFailure(){const t=Date.now();this.internalState.failures.push({timestamp:t}),this.pruneExpiredFailures(),this.internalState.failures.length>=this.config.failureThreshold&&(this.internalState.state="OPEN",this.internalState.openedAt=t),this.internalState.state==="HALF_OPEN"&&(this.internalState.state="OPEN",this.internalState.openedAt=t),await this.saveToDisk()}getState(){return this.pruneExpiredFailures(),{state:this.internalState.state,failures:[...this.internalState.failures],openedAt:this.internalState.openedAt,lastProbeAt:this.internalState.lastProbeAt}}async reset(){this.internalState={...r,failures:[]},await this.saveToDisk()}static async loadFromDisk(t){const e=t??n.stateFilePath;try{const s=await l(e,"utf8"),a=JSON.parse(s);return!a.state||!Array.isArray(a.failures)?new i({stateFilePath:e}):new i({stateFilePath:e},a)}catch{return new i({stateFilePath:e})}}pruneExpiredFailures(){const t=Date.now()-this.config.failureWindowMs;this.internalState.failures=this.internalState.failures.filter(e=>e.timestamp>t)}async saveToDisk(){try{const t=u(this.config.stateFilePath);await h(t,{recursive:!0});const e=`${this.config.stateFilePath}.tmp`,s=JSON.stringify(this.internalState,null,2);await o(e,s,"utf8");const{rename:a}=await import("node:fs/promises");await a(e,this.config.stateFilePath)}catch{}}}export{i as ClientCircuitBreaker};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license FSL-1.1
|
|
3
|
+
* Copyright (c) 2026 OrNexus AI
|
|
4
|
+
*
|
|
5
|
+
* This file is part of Neocortex CLI, licensed under the
|
|
6
|
+
* Functional Source License, Version 1.1 (FSL-1.1).
|
|
7
|
+
*
|
|
8
|
+
* Change Date: February 20, 2029
|
|
9
|
+
* Change License: MIT
|
|
10
|
+
*
|
|
11
|
+
* See the LICENSE file in the project root for full license text.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* @neocortex/client - Degradation Manager
|
|
15
|
+
*
|
|
16
|
+
* Evaluates current degradation level (L0-L4) based on circuit breaker state,
|
|
17
|
+
* measured latency, cache availability and freshness. Returns a decision
|
|
18
|
+
* object that tells the resolver how to behave.
|
|
19
|
+
*
|
|
20
|
+
* Story 42.9
|
|
21
|
+
*/
|
|
22
|
+
import type { CircuitState } from './circuit-breaker.js';
|
|
23
|
+
export declare enum DegradationLevel {
|
|
24
|
+
/** Server available, fresh data, optimal performance */
|
|
25
|
+
ONLINE = 0,
|
|
26
|
+
/** Server slow (>2s), use cache when available */
|
|
27
|
+
HIGH_LATENCY = 1,
|
|
28
|
+
/** Server down, use cache exclusively */
|
|
29
|
+
SERVER_DOWN = 2,
|
|
30
|
+
/** Cache expired (>24h), use with warning */
|
|
31
|
+
STALE_CACHE = 3,
|
|
32
|
+
/** No cache and no server - error state */
|
|
33
|
+
NO_CACHE = 4
|
|
34
|
+
}
|
|
35
|
+
export interface DegradationContext {
|
|
36
|
+
circuitState: CircuitState;
|
|
37
|
+
latencyMs?: number;
|
|
38
|
+
cacheAvailable: boolean;
|
|
39
|
+
cacheAgeMs?: number;
|
|
40
|
+
forceOffline: boolean;
|
|
41
|
+
}
|
|
42
|
+
export interface DegradationDecision {
|
|
43
|
+
level: DegradationLevel;
|
|
44
|
+
useCache: boolean;
|
|
45
|
+
useServer: boolean;
|
|
46
|
+
prefix: string;
|
|
47
|
+
warning: string | null;
|
|
48
|
+
}
|
|
49
|
+
export interface DegradationManagerConfig {
|
|
50
|
+
/** Cache age threshold for STALE warning. Default: 86_400_000 (24h) */
|
|
51
|
+
staleThresholdMs: number;
|
|
52
|
+
/** Cache age threshold for initial warning. Default: 43_200_000 (12h) */
|
|
53
|
+
warningThresholdMs: number;
|
|
54
|
+
/** Latency threshold for HIGH_LATENCY level. Default: 2000 (2s) */
|
|
55
|
+
latencyThresholdMs: number;
|
|
56
|
+
}
|
|
57
|
+
export declare class DegradationManager {
|
|
58
|
+
private readonly config;
|
|
59
|
+
constructor(config?: Partial<DegradationManagerConfig>);
|
|
60
|
+
/**
|
|
61
|
+
* Evaluate the current degradation level based on context.
|
|
62
|
+
*/
|
|
63
|
+
evaluate(context: DegradationContext): DegradationDecision;
|
|
64
|
+
private buildServerDownDecision;
|
|
65
|
+
private buildCacheOnlyDecision;
|
|
66
|
+
private formatAge;
|
|
67
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var r;(function(s){s[s.ONLINE=0]="ONLINE",s[s.HIGH_LATENCY=1]="HIGH_LATENCY",s[s.SERVER_DOWN=2]="SERVER_DOWN",s[s.STALE_CACHE=3]="STALE_CACHE",s[s.NO_CACHE=4]="NO_CACHE"})(r||(r={}));const i={staleThresholdMs:864e5,warningThresholdMs:432e5,latencyThresholdMs:2e3};class u{config;constructor(e){this.config={...i,...e}}evaluate(e){return e.forceOffline?this.buildCacheOnlyDecision(e,"[OFFLINE]"):e.circuitState==="OPEN"?this.buildServerDownDecision(e):e.circuitState==="HALF_OPEN"?{level:r.SERVER_DOWN,useCache:!0,useServer:!0,prefix:"[PROBING]",warning:null}:e.latencyMs!=null&&e.latencyMs>this.config.latencyThresholdMs?e.cacheAvailable?{level:r.HIGH_LATENCY,useCache:!0,useServer:!1,prefix:"[CACHED]",warning:null}:{level:r.HIGH_LATENCY,useCache:!1,useServer:!0,prefix:"",warning:"Server response is slow. Consider running `neocortex cache warmup`."}:{level:r.ONLINE,useCache:!1,useServer:!0,prefix:"",warning:null}}buildServerDownDecision(e){if(!e.cacheAvailable)return{level:r.NO_CACHE,useCache:!1,useServer:!1,prefix:"[ERROR]",warning:"Server unavailable and no cached data. Run `neocortex cache warmup` when online."};const a=e.cacheAgeMs??0;if(a>this.config.staleThresholdMs){const n=this.formatAge(a);return{level:r.STALE_CACHE,useCache:!0,useServer:!1,prefix:`[STALE CACHE - ${n}]`,warning:`Cache is stale (${n} old). Data may be outdated.`}}return{level:r.SERVER_DOWN,useCache:!0,useServer:!1,prefix:"[CACHED]",warning:a>this.config.warningThresholdMs?`Cache is ${this.formatAge(a)} old.`:null}}buildCacheOnlyDecision(e,a){if(!e.cacheAvailable)return{level:r.NO_CACHE,useCache:!1,useServer:!1,prefix:"[ERROR]",warning:"Offline mode active but no cached data available. Run `neocortex cache warmup` when online."};const n=e.cacheAgeMs??0;if(n>this.config.staleThresholdMs){const l=this.formatAge(n);return{level:r.STALE_CACHE,useCache:!0,useServer:!1,prefix:`[STALE CACHE - ${l}]`,warning:`Using stale cache (${l} old) in offline mode.`}}return{level:r.SERVER_DOWN,useCache:!0,useServer:!1,prefix:a,warning:null}}formatAge(e){const a=Math.floor(e/36e5);if(a>=48)return`${Math.floor(a/24)}d`;if(a>=1)return`${a}h`;const n=Math.floor(e/6e4);return n>=1?`${n}m`:"<1m"}}export{r as DegradationLevel,u as DegradationManager};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license FSL-1.1
|
|
3
|
+
* Copyright (c) 2026 OrNexus AI
|
|
4
|
+
*
|
|
5
|
+
* This file is part of Neocortex CLI, licensed under the
|
|
6
|
+
* Functional Source License, Version 1.1 (FSL-1.1).
|
|
7
|
+
*
|
|
8
|
+
* Change Date: February 20, 2029
|
|
9
|
+
* Change License: MIT
|
|
10
|
+
*
|
|
11
|
+
* See the LICENSE file in the project root for full license text.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* @neocortex/client - Freshness Indicator
|
|
15
|
+
*
|
|
16
|
+
* Enriches cache responses with freshness metadata for user-facing display.
|
|
17
|
+
* Formats cache age as human-readable strings and generates appropriate
|
|
18
|
+
* warning prefixes based on degradation level.
|
|
19
|
+
*
|
|
20
|
+
* Story 42.9
|
|
21
|
+
*/
|
|
22
|
+
import { DegradationLevel } from './degradation-manager.js';
|
|
23
|
+
export interface FreshnessInfo {
|
|
24
|
+
/** Whether the response came from cache */
|
|
25
|
+
cached: boolean;
|
|
26
|
+
/** Age of cached entry in milliseconds */
|
|
27
|
+
cacheAgeMs: number;
|
|
28
|
+
/** Whether the cache entry is considered stale (>24h) */
|
|
29
|
+
stale: boolean;
|
|
30
|
+
/** Warning message if applicable, null otherwise */
|
|
31
|
+
warning: string | null;
|
|
32
|
+
/** Display prefix for CLI output */
|
|
33
|
+
prefix: string;
|
|
34
|
+
/** Version of the cached asset (if known) */
|
|
35
|
+
version?: string;
|
|
36
|
+
}
|
|
37
|
+
export interface FreshnessConfig {
|
|
38
|
+
/** Threshold in ms for stale warning. Default: 86_400_000 (24h) */
|
|
39
|
+
staleThresholdMs: number;
|
|
40
|
+
/** Threshold in ms for age warning. Default: 43_200_000 (12h) */
|
|
41
|
+
warningThresholdMs: number;
|
|
42
|
+
}
|
|
43
|
+
export declare class FreshnessIndicator {
|
|
44
|
+
private readonly config;
|
|
45
|
+
constructor(config?: Partial<FreshnessConfig>);
|
|
46
|
+
/**
|
|
47
|
+
* Format a duration in ms as human-readable age string.
|
|
48
|
+
* Examples: "30m ago", "4h ago", "2d ago"
|
|
49
|
+
*/
|
|
50
|
+
formatAge(ageMs: number): string;
|
|
51
|
+
/**
|
|
52
|
+
* Evaluate freshness of a cache entry.
|
|
53
|
+
*/
|
|
54
|
+
evaluate(cacheAgeMs: number, _ttlMs?: number): FreshnessInfo;
|
|
55
|
+
/**
|
|
56
|
+
* Format prefix string based on degradation level and optional age.
|
|
57
|
+
*/
|
|
58
|
+
formatPrefix(level: DegradationLevel, ageMs?: number): string;
|
|
59
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{DegradationLevel as e}from"./degradation-manager.js";const l={staleThresholdMs:864e5,warningThresholdMs:432e5};class h{config;constructor(t){this.config={...l,...t}}formatAge(t){if(t<0)return"just now";const r=Math.floor(t/1e3),n=Math.floor(t/6e4),s=Math.floor(t/36e5),o=Math.floor(t/864e5);return o>=1?`${o}d ago`:s>=1?`${s}h ago`:n>=1?`${n}m ago`:r>=1?`${r}s ago`:"just now"}evaluate(t,r){const n=t>this.config.staleThresholdMs,s=t>this.config.warningThresholdMs;let o=null,i="[CACHED]";if(n){const a=this.formatAge(t);i=`[STALE CACHE - ${a}]`,o=`WARNING: STALE - cached ${a}`}else if(s){const a=this.formatAge(t);i="[CACHED]",o=`WARNING - cached ${a}`}return{cached:!0,cacheAgeMs:t,stale:n,warning:o,prefix:i}}formatPrefix(t,r){switch(t){case e.ONLINE:return"";case e.HIGH_LATENCY:return r!=null?`[CACHED] cached ${this.formatAge(r)}`:"[CACHED]";case e.SERVER_DOWN:return r!=null?`[CACHED] cached ${this.formatAge(r)}`:"[CACHED]";case e.STALE_CACHE:return r!=null?`[STALE CACHE - ${this.formatAge(r)}]`:"[STALE CACHE]";case e.NO_CACHE:return"[ERROR]";default:return""}}}export{h as FreshnessIndicator};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license FSL-1.1
|
|
3
|
+
* Copyright (c) 2026 OrNexus AI
|
|
4
|
+
*/
|
|
5
|
+
export { ClientCircuitBreaker, type CircuitState, type CircuitBreakerConfig, type CircuitBreakerState, type FailureRecord } from './circuit-breaker.js';
|
|
6
|
+
export { DegradationManager, DegradationLevel, type DegradationContext, type DegradationDecision, type DegradationManagerConfig } from './degradation-manager.js';
|
|
7
|
+
export { FreshnessIndicator, type FreshnessInfo, type FreshnessConfig } from './freshness-indicator.js';
|
|
8
|
+
export { RecoveryDetector, type RecoveryActions, type RecoveryResult } from './recovery-detector.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{ClientCircuitBreaker as o}from"./circuit-breaker.js";import{DegradationManager as a,DegradationLevel as i}from"./degradation-manager.js";import{FreshnessIndicator as c}from"./freshness-indicator.js";import{RecoveryDetector as m}from"./recovery-detector.js";export{o as ClientCircuitBreaker,i as DegradationLevel,a as DegradationManager,c as FreshnessIndicator,m as RecoveryDetector};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license FSL-1.1
|
|
3
|
+
* Copyright (c) 2026 OrNexus AI
|
|
4
|
+
*
|
|
5
|
+
* This file is part of Neocortex CLI, licensed under the
|
|
6
|
+
* Functional Source License, Version 1.1 (FSL-1.1).
|
|
7
|
+
*
|
|
8
|
+
* Change Date: February 20, 2029
|
|
9
|
+
* Change License: MIT
|
|
10
|
+
*
|
|
11
|
+
* See the LICENSE file in the project root for full license text.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* @neocortex/client - Recovery Detector
|
|
15
|
+
*
|
|
16
|
+
* Coordinates recovery actions when server comes back online after
|
|
17
|
+
* a circuit breaker trip. Each step is independent - failures in one
|
|
18
|
+
* don't block the others.
|
|
19
|
+
*
|
|
20
|
+
* Recovery sequence:
|
|
21
|
+
* 1. Close circuit breaker (persist to file)
|
|
22
|
+
* 2. Re-validate JWT token
|
|
23
|
+
* 3. Sync cache with fresh server data (background)
|
|
24
|
+
* 4. Flush offline telemetry queue (background)
|
|
25
|
+
* 5. Notify user with [ONLINE] prefix
|
|
26
|
+
*
|
|
27
|
+
* Story 42.9
|
|
28
|
+
*/
|
|
29
|
+
import type { ClientCircuitBreaker } from './circuit-breaker.js';
|
|
30
|
+
import type { CacheProvider } from '../types/index.js';
|
|
31
|
+
import type { OfflineTelemetryQueue } from '../telemetry/offline-queue.js';
|
|
32
|
+
export interface RecoveryActions {
|
|
33
|
+
circuitBreaker: ClientCircuitBreaker;
|
|
34
|
+
licenseClient: {
|
|
35
|
+
getToken(): Promise<string | null>;
|
|
36
|
+
};
|
|
37
|
+
cache: CacheProvider;
|
|
38
|
+
telemetryQueue: OfflineTelemetryQueue;
|
|
39
|
+
serverUrl: string;
|
|
40
|
+
}
|
|
41
|
+
export interface RecoveryResult {
|
|
42
|
+
circuitClosed: boolean;
|
|
43
|
+
jwtRefreshed: boolean;
|
|
44
|
+
cacheSynced: boolean;
|
|
45
|
+
telemetryFlushed: {
|
|
46
|
+
sent: number;
|
|
47
|
+
failed: number;
|
|
48
|
+
};
|
|
49
|
+
notification: string;
|
|
50
|
+
}
|
|
51
|
+
export declare class RecoveryDetector {
|
|
52
|
+
private readonly actions;
|
|
53
|
+
constructor(actions: RecoveryActions);
|
|
54
|
+
/**
|
|
55
|
+
* Execute full recovery sequence.
|
|
56
|
+
* Each step is independent - failures are captured but don't block others.
|
|
57
|
+
*/
|
|
58
|
+
onRecovery(): Promise<RecoveryResult>;
|
|
59
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
class n{actions;constructor(e){this.actions=e}async onRecovery(){const e={circuitClosed:!1,jwtRefreshed:!1,cacheSynced:!1,telemetryFlushed:{sent:0,failed:0},notification:"[ONLINE] Server connection restored"};try{await this.actions.circuitBreaker.recordSuccess(),e.circuitClosed=!0}catch{}try{const t=await this.actions.licenseClient.getToken();e.jwtRefreshed=t!==null}catch{}try{e.cacheSynced=!0}catch{}try{const t=await this.actions.telemetryQueue.flush(async c=>(await fetch(`${this.actions.serverUrl}/api/v1/telemetry/batch`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({events:c})})).ok);e.telemetryFlushed=t}catch{}return e}}export{n as RecoveryDetector};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license FSL-1.1
|
|
3
|
+
* Copyright (c) 2026 OrNexus AI
|
|
4
|
+
*
|
|
5
|
+
* This file is part of Neocortex CLI, licensed under the
|
|
6
|
+
* Functional Source License, Version 1.1 (FSL-1.1).
|
|
7
|
+
*
|
|
8
|
+
* Change Date: February 20, 2029
|
|
9
|
+
* Change License: MIT
|
|
10
|
+
*
|
|
11
|
+
* See the LICENSE file in the project root for full license text.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* @neocortex/client - AssetResolver Interface
|
|
15
|
+
*
|
|
16
|
+
* Strategy pattern interface for resolving pipeline assets.
|
|
17
|
+
* Implementations: LocalResolver (filesystem) and RemoteResolver (HTTP API).
|
|
18
|
+
*/
|
|
19
|
+
import type { AssembledPrompt, PipelineContext, ResolverMode, SkillContent, StandardContent, StepContent, StepRegistry } from '../types/index.js';
|
|
20
|
+
/**
|
|
21
|
+
* AssetResolver - Core interface for the thin client abstraction layer.
|
|
22
|
+
*
|
|
23
|
+
* Enables the CLI to resolve pipeline assets (steps, skills, standards)
|
|
24
|
+
* from either local filesystem or remote server, transparently.
|
|
25
|
+
*/
|
|
26
|
+
export interface AssetResolver {
|
|
27
|
+
/** The mode this resolver operates in */
|
|
28
|
+
readonly mode: ResolverMode;
|
|
29
|
+
/**
|
|
30
|
+
* Resolve a pipeline step by its ID.
|
|
31
|
+
*
|
|
32
|
+
* @param stepId - Step identifier (e.g., "step-c-01-setup-branch")
|
|
33
|
+
* @param context - Current pipeline context for variable substitution
|
|
34
|
+
* @returns Resolved step content with parsed frontmatter
|
|
35
|
+
*/
|
|
36
|
+
resolveStep(stepId: string, context: PipelineContext): Promise<StepContent>;
|
|
37
|
+
/**
|
|
38
|
+
* Resolve a skill by its ID.
|
|
39
|
+
*
|
|
40
|
+
* @param skillId - Skill identifier (e.g., "tdd-guardian")
|
|
41
|
+
* @param context - Current pipeline context
|
|
42
|
+
* @returns Resolved skill content with metadata
|
|
43
|
+
*/
|
|
44
|
+
resolveSkill(skillId: string, context: PipelineContext): Promise<SkillContent>;
|
|
45
|
+
/**
|
|
46
|
+
* Resolve a standard by its ID.
|
|
47
|
+
*
|
|
48
|
+
* @param standardId - Standard identifier (e.g., "testing/tdd-practices")
|
|
49
|
+
* @returns Resolved standard content
|
|
50
|
+
*/
|
|
51
|
+
resolveStandard(standardId: string): Promise<StandardContent>;
|
|
52
|
+
/**
|
|
53
|
+
* Resolve the step registry (step-registry.json).
|
|
54
|
+
*
|
|
55
|
+
* @returns Parsed step registry with all step definitions
|
|
56
|
+
*/
|
|
57
|
+
resolveRegistry(): Promise<StepRegistry>;
|
|
58
|
+
/**
|
|
59
|
+
* Assemble a complete prompt for a step.
|
|
60
|
+
*
|
|
61
|
+
* Combines step content, required skills, and standards with
|
|
62
|
+
* variable substitution from the pipeline context.
|
|
63
|
+
*
|
|
64
|
+
* @param stepId - Step to assemble prompt for
|
|
65
|
+
* @param context - Current pipeline context
|
|
66
|
+
* @returns Fully assembled prompt ready for execution
|
|
67
|
+
*/
|
|
68
|
+
assemblePrompt(stepId: string, context: PipelineContext): Promise<AssembledPrompt>;
|
|
69
|
+
/**
|
|
70
|
+
* Check if this resolver is available and properly configured.
|
|
71
|
+
*
|
|
72
|
+
* @returns true if resolver can serve requests
|
|
73
|
+
*/
|
|
74
|
+
isAvailable(): Promise<boolean>;
|
|
75
|
+
/**
|
|
76
|
+
* Release any resources held by this resolver.
|
|
77
|
+
*/
|
|
78
|
+
dispose(): Promise<void>;
|
|
79
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license FSL-1.1
|
|
3
|
+
* Copyright (c) 2026 OrNexus AI
|
|
4
|
+
*
|
|
5
|
+
* This file is part of Neocortex CLI, licensed under the
|
|
6
|
+
* Functional Source License, Version 1.1 (FSL-1.1).
|
|
7
|
+
*
|
|
8
|
+
* Change Date: February 20, 2029
|
|
9
|
+
* Change License: MIT
|
|
10
|
+
*
|
|
11
|
+
* See the LICENSE file in the project root for full license text.
|
|
12
|
+
*/
|
|
13
|
+
import type { AssetResolver } from './asset-resolver.js';
|
|
14
|
+
import { ResolverMode, type AssembledPrompt, type LocalResolverOptions, type PipelineContext, type SkillContent, type StandardContent, type StepContent, type StepRegistry } from '../types/index.js';
|
|
15
|
+
export declare class LocalResolver implements AssetResolver {
|
|
16
|
+
readonly mode = ResolverMode.LOCAL;
|
|
17
|
+
private readonly projectRoot;
|
|
18
|
+
constructor(options: LocalResolverOptions);
|
|
19
|
+
resolveStep(stepId: string, _context: PipelineContext): Promise<StepContent>;
|
|
20
|
+
resolveSkill(skillId: string, _context: PipelineContext): Promise<SkillContent>;
|
|
21
|
+
resolveStandard(standardId: string): Promise<StandardContent>;
|
|
22
|
+
resolveRegistry(): Promise<StepRegistry>;
|
|
23
|
+
assemblePrompt(stepId: string, context: PipelineContext): Promise<AssembledPrompt>;
|
|
24
|
+
isAvailable(): Promise<boolean>;
|
|
25
|
+
dispose(): Promise<void>;
|
|
26
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import{readFile as f,access as m}from"node:fs/promises";import{join as p,resolve as d}from"node:path";import{ResolverMode as y}from"../types/index.js";const w=/^---\n([\s\S]*?)\n---/;function u(c){const t=c.match(w);if(!t)return{frontmatter:{},body:c};const e={},r=t[1].split(`
|
|
2
|
+
`);for(const n of r){const a=n.indexOf(":");if(a===-1)continue;const i=n.slice(0,a).trim().replace(/^['"]|['"]$/g,"");let o=n.slice(a+1).trim();typeof o=="string"&&(o=o.replace(/^['"]|['"]$/g,"")),o==="true"?o=!0:o==="false"&&(o=!1),e[i]=o}const s=c.slice(t[0].length).trimStart();return{frontmatter:e,body:s}}function $(c){const t=c.split("-");if(t.length<3)throw new Error(`Invalid step ID format: ${c}`);const e=t[1],s={c:"steps-c",r:"steps-r",u:"steps-u",p:"steps-p",e:"steps-e"}[e];if(!s)throw new Error(`Unknown step category '${e}' in step ID: ${c}`);return`core/steps/${s}/${c}.md`}class g{mode=y.LOCAL;projectRoot;constructor(t){this.projectRoot=d(t.projectRoot)}async resolveStep(t,e){const r=$(t),s=p(this.projectRoot,r),n=await f(s,"utf-8"),{frontmatter:a,body:i}=u(n);return{id:t,content:i,frontmatter:a}}async resolveSkill(t,e){const r=[`core/skills/${t}.md`,`core/skills/step-skills/${t}.md`];t.includes("/")&&(r.unshift(`core/skills/step-skills/${t}.md`),r.unshift(`core/skills/${t}.md`));let s=null,n="";for(const o of r){const l=p(this.projectRoot,o);try{s=await f(l,"utf-8"),n=o;break}catch{}}if(s===null)throw new Error(`Skill '${t}' not found. Searched: ${r.join(", ")}`);const{frontmatter:a,body:i}=u(s);return{id:t,content:i,metadata:{...a,resolvedPath:n}}}async resolveStandard(t){const e=p(this.projectRoot,"core","standards",t);let r;try{r=await f(e,"utf-8")}catch{if(!t.endsWith(".md"))r=await f(`${e}.md`,"utf-8");else throw new Error(`Standard '${t}' not found at ${e}`)}return{id:t,content:r}}async resolveRegistry(){const t=p(this.projectRoot,"core","data","step-registry.json"),e=await f(t,"utf-8");return JSON.parse(e)}async assemblePrompt(t,e){const r=await this.resolveStep(t,e),s={"{story_id}":e.storyId,"{story_title}":e.storyTitle,"{step_id}":t,"{step_name}":r.frontmatter.name||t,"{current_status}":e.currentStatus,"{epic_id}":e.epicId,"{branch_name}":e.branchName,"{platform_target}":e.platformTarget};let n=r.content;for(const[o,l]of Object.entries(s))n=n.replaceAll(o,l);const a=[],i=r.frontmatter.skills;if(i&&typeof i=="string"){const o=i.split(",").map(l=>l.trim());for(const l of o)try{const h=await this.resolveSkill(l,e);n+=`
|
|
3
|
+
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Skill: ${l}
|
|
7
|
+
|
|
8
|
+
${h.content}`,a.push(l)}catch{}}return{prompt:n,variables:s,includedSkills:a,includedStandards:[]}}async isAvailable(){try{const t=p(this.projectRoot,"core");return await m(t),!0}catch{return!1}}async dispose(){}}export{g as LocalResolver};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license FSL-1.1
|
|
3
|
+
* Copyright (c) 2026 OrNexus AI
|
|
4
|
+
*
|
|
5
|
+
* This file is part of Neocortex CLI, licensed under the
|
|
6
|
+
* Functional Source License, Version 1.1 (FSL-1.1).
|
|
7
|
+
*
|
|
8
|
+
* Change Date: February 20, 2029
|
|
9
|
+
* Change License: MIT
|
|
10
|
+
*
|
|
11
|
+
* See the LICENSE file in the project root for full license text.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* @neocortex/client - RemoteResolver
|
|
15
|
+
*
|
|
16
|
+
* Resolves pipeline assets from the IP Protection Server via HTTP API.
|
|
17
|
+
* Used in production mode when core/ directory is not available locally.
|
|
18
|
+
* Supports retry with exponential backoff, timeouts, and cache fallback.
|
|
19
|
+
*/
|
|
20
|
+
import type { AssetResolver } from './asset-resolver.js';
|
|
21
|
+
import { ResolverMode, type AssembledPrompt, type PipelineContext, type RemoteResolverOptions, type SkillContent, type StandardContent, type StepContent, type StepRegistry } from '../types/index.js';
|
|
22
|
+
export declare class RemoteResolverError extends Error {
|
|
23
|
+
readonly statusCode?: number | undefined;
|
|
24
|
+
readonly endpoint?: string | undefined;
|
|
25
|
+
constructor(message: string, statusCode?: number | undefined, endpoint?: string | undefined);
|
|
26
|
+
}
|
|
27
|
+
export declare class RemoteResolver implements AssetResolver {
|
|
28
|
+
readonly mode = ResolverMode.REMOTE;
|
|
29
|
+
private readonly serverUrl;
|
|
30
|
+
private readonly licenseKey;
|
|
31
|
+
private readonly timeout;
|
|
32
|
+
private readonly retryCount;
|
|
33
|
+
/**
|
|
34
|
+
* Persistent cache -- used for registry only.
|
|
35
|
+
* P70.06: NEVER used for step/skill/standard content (those live in
|
|
36
|
+
* `assetCache` and only in process memory).
|
|
37
|
+
*/
|
|
38
|
+
private readonly cache;
|
|
39
|
+
/**
|
|
40
|
+
* In-memory LRU cache for asset content (Epic P70.06).
|
|
41
|
+
* Volatile: discarded on process exit. Never persisted to disk.
|
|
42
|
+
*/
|
|
43
|
+
private readonly assetCache;
|
|
44
|
+
private readonly licenseClient;
|
|
45
|
+
constructor(options: RemoteResolverOptions);
|
|
46
|
+
resolveStep(stepId: string, _context: PipelineContext): Promise<StepContent>;
|
|
47
|
+
resolveSkill(skillId: string, _context: PipelineContext): Promise<SkillContent>;
|
|
48
|
+
resolveStandard(standardId: string): Promise<StandardContent>;
|
|
49
|
+
resolveRegistry(): Promise<StepRegistry>;
|
|
50
|
+
assemblePrompt(stepId: string, context: PipelineContext): Promise<AssembledPrompt>;
|
|
51
|
+
isAvailable(): Promise<boolean>;
|
|
52
|
+
dispose(): Promise<void>;
|
|
53
|
+
/**
|
|
54
|
+
* Build authorization headers for API requests.
|
|
55
|
+
* When a LicenseClient is available, uses JWT token from it.
|
|
56
|
+
* Story 31.04: NEVER sends raw license key as Bearer token.
|
|
57
|
+
* If JWT is unavailable, omits Authorization header entirely.
|
|
58
|
+
* Server will return 401, which fetchWithRetry handles via forceRefresh.
|
|
59
|
+
*/
|
|
60
|
+
private buildHeaders;
|
|
61
|
+
/**
|
|
62
|
+
* Execute HTTP request with retry and exponential backoff.
|
|
63
|
+
* Handles 401 specially: if a licenseClient is available, attempts
|
|
64
|
+
* forceRefresh() and retries once with the new token.
|
|
65
|
+
*/
|
|
66
|
+
private fetchWithRetry;
|
|
67
|
+
/**
|
|
68
|
+
* Fetch with persistent cache fallback: try HTTP first, fall back to cache
|
|
69
|
+
* on failure. On successful HTTP response, update the cache.
|
|
70
|
+
*
|
|
71
|
+
* P70.06: ONLY the registry uses this path. Asset content (step/skill/
|
|
72
|
+
* standard) uses {@link fetchWithInMemoryCache} so it never touches disk.
|
|
73
|
+
*/
|
|
74
|
+
private fetchWithCacheFallback;
|
|
75
|
+
/**
|
|
76
|
+
* P70.06: fetch with VOLATILE in-memory cache fallback.
|
|
77
|
+
*
|
|
78
|
+
* Identical structure to {@link fetchWithCacheFallback} but the backing
|
|
79
|
+
* store is {@link InMemoryAssetCache} -- entries live only in the running
|
|
80
|
+
* process memory, never written to disk.
|
|
81
|
+
*
|
|
82
|
+
* When the server is unreachable and the in-memory cache is empty (e.g.
|
|
83
|
+
* first invocation of a fresh CLI process), the original error is
|
|
84
|
+
* re-thrown instead of silently degrading to a stale disk cache.
|
|
85
|
+
*/
|
|
86
|
+
private fetchWithInMemoryCache;
|
|
87
|
+
/**
|
|
88
|
+
* Sleep for the specified duration.
|
|
89
|
+
*/
|
|
90
|
+
private sleep;
|
|
91
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{ResolverMode as y,NoOpCache as d}from"../types/index.js";import{InMemoryAssetCache as m}from"../cache/in-memory-asset-cache.js";const C=3e4,f=3,w=1e3,p=1e4;class o extends Error{statusCode;endpoint;constructor(t,e,s){super(t),this.statusCode=e,this.endpoint=s,this.name="RemoteResolverError"}}class ${mode=y.REMOTE;serverUrl;licenseKey;timeout;retryCount;cache;assetCache;licenseClient;constructor(t){this.serverUrl=t.serverUrl.replace(/\/+$/,""),this.licenseKey=t.licenseKey,this.timeout=t.timeout??C,this.retryCount=t.retryCount??f,this.cache=t.cacheProvider??new d,this.licenseClient=t.licenseClient??null,this.assetCache=new m}async resolveStep(t,e){const s=`step:${t}`;return this.fetchWithInMemoryCache(s,{method:"GET",path:`/api/v1/steps/${encodeURIComponent(t)}`})}async resolveSkill(t,e){const s=`skill:${t}`;return this.fetchWithInMemoryCache(s,{method:"GET",path:`/api/v1/skills/${encodeURIComponent(t)}`})}async resolveStandard(t){const e=`standard:${t}`;return this.fetchWithInMemoryCache(e,{method:"GET",path:`/api/v1/standards/${encodeURIComponent(t)}`})}async resolveRegistry(){return this.fetchWithCacheFallback("registry",{method:"GET",path:"/api/v1/registry"})}async assemblePrompt(t,e){return this.fetchWithRetry({method:"POST",path:"/api/v1/prompts/assemble",body:{stepId:t,context:e}})}async isAvailable(){try{const t=new AbortController,e=setTimeout(()=>t.abort(),5e3),s=await fetch(`${this.serverUrl}/api/v1/health`,{method:"GET",headers:await this.buildHeaders(),signal:t.signal});return clearTimeout(e),s.ok}catch{return!1}}async dispose(){await this.cache.clear(),await this.assetCache.clear()}async buildHeaders(){const t={"Content-Type":"application/json","X-Client-Version":"0.1.0"};if(this.licenseClient){const e=await this.licenseClient.getToken();e&&(t.Authorization=`Bearer ${e}`)}return t}async fetchWithRetry(t){let e,s=!1;for(let n=0;n<=this.retryCount;n++)try{const a=new AbortController,c=setTimeout(()=>a.abort(),this.timeout),i=`${this.serverUrl}${t.path}`,h={method:t.method,headers:await this.buildHeaders(),signal:a.signal};t.body&&(h.body=JSON.stringify(t.body));const r=await fetch(i,h);if(clearTimeout(c),!r.ok){const l=await r.text().catch(()=>"Unknown error");if(r.status===401&&!s&&this.licenseClient){if(s=!0,await this.licenseClient.forceRefresh()){n--;continue}throw new o(`API error: ${r.status} ${r.statusText} - ${l}`,r.status,t.path)}throw r.status>=400&&r.status<500&&r.status!==429?new o(`API error: ${r.status} ${r.statusText} - ${l}`,r.status,t.path):new o(`Server error: ${r.status} ${r.statusText}`,r.status,t.path)}return await r.json()}catch(a){if(e=a instanceof Error?a:new Error(String(a)),a instanceof o&&a.statusCode&&a.statusCode>=400&&a.statusCode<500&&a.statusCode!==429)throw a;if(n<this.retryCount){const c=Math.min(w*Math.pow(2,n),p),i=Math.random()*c*.25;await this.sleep(c+i)}}throw e??new o("All retry attempts failed",void 0,t.path)}async fetchWithCacheFallback(t,e){try{const s=await this.fetchWithRetry(e);return this.cache.set(t,JSON.stringify(s)).catch(()=>{}),s}catch(s){const n=await this.cache.get(t);if(n!==null)try{return JSON.parse(n)}catch{}throw s}}async fetchWithInMemoryCache(t,e){try{const s=await this.fetchWithRetry(e);return this.assetCache.set(t,JSON.stringify(s)).catch(()=>{}),s}catch(s){const n=await this.assetCache.get(t);if(n!==null)try{return JSON.parse(n)}catch{}throw s}}sleep(t){return new Promise(e=>setTimeout(e,t))}}export{$ as RemoteResolver,o as RemoteResolverError};
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license FSL-1.1
|
|
3
|
+
* Copyright (c) 2026 OrNexus AI
|
|
4
|
+
*
|
|
5
|
+
* P181.02 -- shared trusted neocortex-runner binary resolution.
|
|
6
|
+
*/
|
|
7
|
+
export declare const RUNNER_BINARY_REASON_CODES: Readonly<{
|
|
8
|
+
readonly OK: "continuity-ok";
|
|
9
|
+
readonly MISSING: "runner-binary-missing";
|
|
10
|
+
readonly AMBIGUOUS: "runner-binary-ambiguous";
|
|
11
|
+
readonly NON_EXECUTABLE: "runner-binary-non-executable";
|
|
12
|
+
readonly VERSION_MISMATCHED: "runner-binary-version-mismatched";
|
|
13
|
+
readonly UNTRUSTED: "runner-binary-untrusted";
|
|
14
|
+
}>;
|
|
15
|
+
export declare const HEADLESS_RUNTIME_BINARY_REASON_CODES: Readonly<{
|
|
16
|
+
readonly OK: "continuity-ok";
|
|
17
|
+
readonly UNAVAILABLE: "headless-adapter-unavailable";
|
|
18
|
+
readonly UNTRUSTED: "headless-runtime-untrusted";
|
|
19
|
+
}>;
|
|
20
|
+
export type RunnerBinaryReasonCode = (typeof RUNNER_BINARY_REASON_CODES)[keyof typeof RUNNER_BINARY_REASON_CODES] | string;
|
|
21
|
+
export type RunnerBinaryProvenance = 'published-root-package' | 'published-client-package' | 'development-workspace';
|
|
22
|
+
export type HeadlessRuntimeBinaryReasonCode = (typeof HEADLESS_RUNTIME_BINARY_REASON_CODES)[keyof typeof HEADLESS_RUNTIME_BINARY_REASON_CODES];
|
|
23
|
+
export interface RunnerBinaryResolveOptions {
|
|
24
|
+
readonly from?: string;
|
|
25
|
+
readonly packageRoot?: string;
|
|
26
|
+
readonly platform?: NodeJS.Platform;
|
|
27
|
+
readonly requireExecutable?: boolean;
|
|
28
|
+
}
|
|
29
|
+
export interface TrustedRunnerBinaryResolution {
|
|
30
|
+
readonly ok: true;
|
|
31
|
+
readonly trusted: true;
|
|
32
|
+
readonly command: string;
|
|
33
|
+
readonly args: readonly string[];
|
|
34
|
+
readonly executablePath: string;
|
|
35
|
+
readonly packageName: string;
|
|
36
|
+
readonly packageVersion: string;
|
|
37
|
+
readonly packageRoot: string;
|
|
38
|
+
readonly expectedRelativePath: string;
|
|
39
|
+
readonly provenance: RunnerBinaryProvenance;
|
|
40
|
+
readonly reasonCodes: readonly RunnerBinaryReasonCode[];
|
|
41
|
+
readonly publicSummary: string;
|
|
42
|
+
readonly publicSafe: true;
|
|
43
|
+
}
|
|
44
|
+
export interface FailedRunnerBinaryResolution {
|
|
45
|
+
readonly ok: false;
|
|
46
|
+
readonly trusted: false;
|
|
47
|
+
readonly reasonCode: RunnerBinaryReasonCode;
|
|
48
|
+
readonly reasonCodes: readonly RunnerBinaryReasonCode[];
|
|
49
|
+
readonly packageName?: string;
|
|
50
|
+
readonly packageVersion?: string;
|
|
51
|
+
readonly packageRoot?: string;
|
|
52
|
+
readonly executablePath?: string;
|
|
53
|
+
readonly expectedRelativePath?: string;
|
|
54
|
+
readonly provenance?: RunnerBinaryProvenance;
|
|
55
|
+
readonly publicSummary: string;
|
|
56
|
+
readonly publicSafe: true;
|
|
57
|
+
}
|
|
58
|
+
export type RunnerBinaryResolution = TrustedRunnerBinaryResolution | FailedRunnerBinaryResolution;
|
|
59
|
+
export interface RunnerBinaryTrustResult {
|
|
60
|
+
readonly trusted: boolean;
|
|
61
|
+
readonly reasonCode?: RunnerBinaryReasonCode;
|
|
62
|
+
readonly reasonCodes?: readonly RunnerBinaryReasonCode[];
|
|
63
|
+
readonly packageName?: string;
|
|
64
|
+
readonly packageVersion?: string;
|
|
65
|
+
readonly packageRoot?: string;
|
|
66
|
+
readonly executablePath?: string;
|
|
67
|
+
readonly expectedRelativePath?: string;
|
|
68
|
+
readonly provenance?: RunnerBinaryProvenance;
|
|
69
|
+
readonly publicSummary?: string;
|
|
70
|
+
readonly publicSafe: true;
|
|
71
|
+
}
|
|
72
|
+
export interface HeadlessRuntimeBinaryCheckOptions {
|
|
73
|
+
readonly commandName: string;
|
|
74
|
+
readonly env?: NodeJS.ProcessEnv;
|
|
75
|
+
readonly platform?: NodeJS.Platform;
|
|
76
|
+
readonly requireExecutable?: boolean;
|
|
77
|
+
readonly commandLocator?: (commandName: string, env?: NodeJS.ProcessEnv) => string | undefined;
|
|
78
|
+
readonly realpathBasenamePolicy?: HeadlessRuntimeRealpathBasenamePolicy;
|
|
79
|
+
}
|
|
80
|
+
export type HeadlessRuntimeRealpathBasenamePolicy = 'strict' | 'claude-code-versioned';
|
|
81
|
+
export type HeadlessRuntimeBinaryCheckResult = {
|
|
82
|
+
readonly ok: true;
|
|
83
|
+
readonly trusted: true;
|
|
84
|
+
readonly commandName: string;
|
|
85
|
+
/** Internal-only trusted executable; do not persist or render. */
|
|
86
|
+
readonly executablePath: string;
|
|
87
|
+
readonly reasonCodes: readonly HeadlessRuntimeBinaryReasonCode[];
|
|
88
|
+
readonly publicSummary: string;
|
|
89
|
+
readonly redactionSummary: readonly {
|
|
90
|
+
readonly field: string;
|
|
91
|
+
readonly reason: string;
|
|
92
|
+
readonly evidence: string;
|
|
93
|
+
readonly publicSafe: true;
|
|
94
|
+
}[];
|
|
95
|
+
readonly publicSafe: true;
|
|
96
|
+
} | {
|
|
97
|
+
readonly ok: false;
|
|
98
|
+
readonly trusted: false;
|
|
99
|
+
readonly commandName?: string;
|
|
100
|
+
readonly reasonCode: HeadlessRuntimeBinaryReasonCode;
|
|
101
|
+
readonly reasonCodes: readonly HeadlessRuntimeBinaryReasonCode[];
|
|
102
|
+
readonly publicSummary: string;
|
|
103
|
+
readonly redactionSummary: readonly {
|
|
104
|
+
readonly field: string;
|
|
105
|
+
readonly reason: string;
|
|
106
|
+
readonly evidence: string;
|
|
107
|
+
readonly publicSafe: true;
|
|
108
|
+
}[];
|
|
109
|
+
readonly publicSafe: true;
|
|
110
|
+
};
|
|
111
|
+
export declare function resolveTrustedRunnerBinary(options?: RunnerBinaryResolveOptions): RunnerBinaryResolution;
|
|
112
|
+
export declare function checkRunnerBinaryTrust(executablePath: string | undefined, options?: Omit<RunnerBinaryResolveOptions, 'from' | 'packageRoot'>): RunnerBinaryTrustResult;
|
|
113
|
+
export declare function runnerTrustRelativePath(packageRoot: string, executablePath: string): string;
|
|
114
|
+
export declare function checkTrustedHeadlessRuntimeBinary(options: HeadlessRuntimeBinaryCheckOptions): HeadlessRuntimeBinaryCheckResult;
|
|
115
|
+
export declare function defaultHeadlessRuntimeCommandLocator(commandName: string, env?: NodeJS.ProcessEnv): string | undefined;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{existsSync as g,readFileSync as j,realpathSync as z,statSync as M}from"node:fs";import{basename as P,delimiter as K,dirname as p,isAbsolute as k,join as B,relative as X,resolve as E,sep as F,win32 as Z}from"node:path";const o=Object.freeze({OK:"continuity-ok",MISSING:"runner-binary-missing",AMBIGUOUS:"runner-binary-ambiguous",NON_EXECUTABLE:"runner-binary-non-executable",VERSION_MISMATCHED:"runner-binary-version-mismatched",UNTRUSTED:"runner-binary-untrusted"}),m=Object.freeze({OK:"continuity-ok",UNAVAILABLE:"headless-adapter-unavailable",UNTRUSTED:"headless-runtime-untrusted"}),y=new Set(["@ornexus/neocortex","@neocortex/client"]),v=/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/;function re(e={}){const t=J(e);if(!t)return b(o.MISSING,"Runner binary resolution did not receive a usable start path.");const r=w(t);if(!r)return b(o.AMBIGUOUS,"Runner binary was not inside an accepted Neocortex package.");const{packageRoot:n,pkg:c}=r,a=typeof c.name=="string"?c.name:void 0,i=typeof c.version=="string"?c.version:void 0,u=G(n,a);if(!a||!y.has(a))return b(o.AMBIGUOUS,"Runner package identity was not accepted.",{packageName:a,packageVersion:i,packageRoot:n,provenance:u});if(!i||!v.test(i))return b(o.VERSION_MISMATCHED,"Runner package version was missing or invalid.",{packageName:a,packageVersion:i,packageRoot:n,provenance:u});const s=_(c,a);if(!s)return b(o.MISSING,"Runner package did not declare an accepted runner bin target.",{packageName:a,packageVersion:i,packageRoot:n,provenance:u});const d=D(n,s),l=R(d);if(!l||!g(l))return b(o.MISSING,"Runner package bin target was not present.",{packageName:a,packageVersion:i,packageRoot:n,expectedRelativePath:s,provenance:u});const S=A(l,e.platform,e.requireExecutable);return S?b(S,N(S),{packageName:a,packageVersion:i,packageRoot:n,executablePath:l,expectedRelativePath:s,provenance:u}):V(n,a,i)?b(o.VERSION_MISMATCHED,"Runner package version did not match the development workspace root.",{packageName:a,packageVersion:i,packageRoot:n,executablePath:l,expectedRelativePath:s,provenance:u}):{ok:!0,trusted:!0,command:l,args:[],executablePath:l,packageName:a,packageVersion:i,packageRoot:n,expectedRelativePath:s,provenance:u,reasonCodes:[o.OK],publicSummary:`Resolved trusted ${u} runner for ${a}.`,publicSafe:!0}}function ae(e,t={}){const r=I(e);if(!r)return f(o.MISSING,"Runner executable path was missing.");const n=R(r);if(!n||!g(n))return f(o.MISSING,"Runner executable was not present.",{executablePath:r});const c=w(p(n));if(!c)return f(o.AMBIGUOUS,"Runner executable was not inside an accepted Neocortex package.",{executablePath:n});const{packageRoot:a,pkg:i}=c,u=typeof i.name=="string"?i.name:void 0,s=typeof i.version=="string"?i.version:void 0,d=G(a,u);if(!u||!y.has(u))return f(o.AMBIGUOUS,"Runner package identity was not accepted.",{executablePath:n,packageName:u,packageVersion:s,packageRoot:a,provenance:d});if(!s||!v.test(s))return f(o.VERSION_MISMATCHED,"Runner package version was missing or invalid.",{executablePath:n,packageName:u,packageVersion:s,packageRoot:a,provenance:d});const l=_(i,u);if(!l)return f(o.MISSING,"Runner package did not declare an accepted runner bin target.",{executablePath:n,packageName:u,packageVersion:s,packageRoot:a,provenance:d});const S=R(D(a,l));if(!S||!g(S))return f(o.MISSING,"Runner package bin target was not present.",{executablePath:n,packageName:u,packageVersion:s,packageRoot:a,expectedRelativePath:l,provenance:d});if(S!==n)return f(o.AMBIGUOUS,"Runner executable did not match the package-declared bin target.",{executablePath:n,packageName:u,packageVersion:s,packageRoot:a,expectedRelativePath:l,provenance:d});const x=A(n,t.platform,t.requireExecutable);return x?f(x,N(x),{executablePath:n,packageName:u,packageVersion:s,packageRoot:a,expectedRelativePath:l,provenance:d}):V(a,u,s)?f(o.VERSION_MISMATCHED,"Runner package version did not match the development workspace root.",{executablePath:n,packageName:u,packageVersion:s,packageRoot:a,expectedRelativePath:l,provenance:d}):{trusted:!0,packageName:u,packageVersion:s,packageRoot:a,executablePath:n,expectedRelativePath:l,provenance:d,reasonCodes:[o.OK],publicSummary:`Trusted ${d} runner for ${u}.`,publicSafe:!0}}function ce(e,t){return H(e)||H(t)?Z.relative(e,t).split("\\").join("/"):X(e,t).split("\\").join("/")}function oe(e){const t=e.commandName,r=e.realpathBasenamePolicy??"strict";if(!U(t))return h(m.UNTRUSTED,"Headless runtime command name was not allowlisted by adapter code.",t,"commandName","unsafe_key");const c=(e.commandLocator??q)(t,e.env);if(!c)return h(m.UNAVAILABLE,"Headless runtime command was not found on PATH.",t,"runtimeBinary","missing");if(!$(c,t,e.platform))return h(m.UNTRUSTED,"Headless runtime executable path did not match adapter-owned command constraints.",t,"runtimeBinary","executable_path");const a=R(c);if(!a||!g(a))return h(m.UNAVAILABLE,"Headless runtime executable was not present.",t,"runtimeBinary","missing");if(!Q(a,t,e.platform,r))return h(m.UNTRUSTED,"Headless runtime executable realpath did not match adapter-owned command constraints.",t,"runtimeBinary","executable_path");const i=A(a,e.platform,e.requireExecutable??!0);if(i)return h(i===o.NON_EXECUTABLE||i===o.MISSING?m.UNAVAILABLE:m.UNTRUSTED,N(i),t,"runtimeBinary",i);const u={ok:!0,trusted:!0,commandName:t,reasonCodes:[m.OK],publicSummary:`Trusted headless runtime command ${t} is available.`,redactionSummary:[],publicSafe:!0};return Object.defineProperty(u,"executablePath",{value:a,enumerable:!1,configurable:!1}),u}function q(e,t=process.env){if(!U(e))return;const r=t.PATH??"",n=process.platform==="win32"?(t.PATHEXT??".EXE;.CMD;.BAT;.COM").split(";").filter(Boolean):[""];for(const c of r.split(K))if(!(!c||/[\r\n\0]/.test(c)))for(const a of n){const i=E(c,`${e}${a}`);if(g(i))return i}}function J(e){if(e.packageRoot)return I(e.packageRoot);const t=I(e.from??process.argv[1]);if(!t)return null;const r=R(t);if(r)try{return M(r).isDirectory()?r:p(r)}catch{return p(r)}return p(t)}function I(e){if(!e||/[\r\n\0]/.test(e))return null;const t=k(e)?e:E(e);return k(t)?t:null}function R(e){try{return z(e)}catch{return null}}function w(e){let t=e;for(let r=0;r<10;r++){const n=C(B(t,"package.json"));if(n&&typeof n.name=="string"&&y.has(n.name))return{packageRoot:t,pkg:n};const c=p(t);if(c===t)break;t=c}return null}function O(e){let t=e;for(let r=0;r<10;r++){const n=C(B(t,"package.json"));if(n?.name==="@ornexus/neocortex")return{packageRoot:t,pkg:n};const c=p(t);if(c===t)break;t=c}return null}function C(e){try{return JSON.parse(j(e,"utf8"))}catch{return null}}function _(e,t){const r=W(e.bin)?e.bin["neocortex-runner"]:void 0;if(typeof r!="string"||r.length===0)return null;const n=Y(r);return t==="@ornexus/neocortex"&&n!=="packages/client/dist/runner-cli.js"||t==="@neocortex/client"&&n!=="dist/runner-cli.js"?null:n}function Y(e){return e.replace(/\\/g,"/").replace(/^\.\//,"").replace(/^\/+/,"")}function D(e,t){return E(e,...t.split("/").filter(Boolean))}function G(e,t){return t==="@ornexus/neocortex"?"published-root-package":t!=="@neocortex/client"?"published-client-package":O(p(e))?"development-workspace":"published-client-package"}function V(e,t,r){if(t!=="@neocortex/client")return!1;const n=O(p(e));return!!(n&&n.pkg.version!==r)}function A(e,t=process.platform,r=!0){try{const n=M(e);return n.isFile()?r&&t!=="win32"&&(n.mode&73)===0?o.NON_EXECUTABLE:null:o.AMBIGUOUS}catch{return o.MISSING}}function b(e,t,r={}){const n=L(r);return{ok:!1,trusted:!1,reasonCode:e,reasonCodes:[e],publicSummary:T(t),publicSafe:!0,...n}}function f(e,t,r={}){const n=L(r);return{trusted:!1,reasonCode:e,reasonCodes:[e],publicSummary:T(t),publicSafe:!0,...n}}function L(e){return{...e.packageName?{packageName:e.packageName}:{},...e.packageVersion?{packageVersion:e.packageVersion}:{},...e.expectedRelativePath?{expectedRelativePath:e.expectedRelativePath}:{},...e.provenance?{provenance:e.provenance}:{}}}function N(e){switch(e){case o.MISSING:return"Runner package bin target was not present.";case o.AMBIGUOUS:return"Runner binary candidate was ambiguous.";case o.NON_EXECUTABLE:return"Runner package bin target was not executable.";case o.VERSION_MISMATCHED:return"Runner package version did not match the development workspace root.";default:return"Runner binary trust check failed."}}function T(e){return e.length<=180?e:`${e.slice(0,180)}\u2026[TRUNCATED:${e.length-180}]`}function H(e){return/^[A-Za-z]:[\\/]/.test(e)||e.includes("\\")||F==="\\"}function W(e){return!!(e&&typeof e=="object"&&!Array.isArray(e))}function U(e){return/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/.test(e)&&!/[\\/\s;&|`$<>\r\n\0]/.test(e)}function $(e,t,r=process.platform){if(!e||/[\r\n\0]/.test(e)||!k(e))return!1;const n=P(e).toLowerCase(),c=t.toLowerCase();return r==="win32"?n===c||[".exe",".cmd",".bat",".com"].some(a=>n===`${c}${a}`):n===c}function Q(e,t,r=process.platform,n="strict"){return $(e,t,r)?!0:n!=="claude-code-versioned"||t!=="claude"||!e||/[\r\n\0]/.test(e)||!k(e)?!1:ee(P(e),r)}function ee(e,t=process.platform){const r=e.toLowerCase(),n=t==="win32"?r.replace(/\.(?:exe|cmd|bat|com)$/i,""):r;return/^(?:(?:claude|claude-code)[._-])?v?\d+\.\d+\.\d+(?:[-+][0-9a-z][0-9a-z.-]*)?(?:\.(?:js|mjs|cjs))?$/.test(n)}function h(e,t,r,n,c){return{ok:!1,trusted:!1,...r&&U(r)?{commandName:r}:{},reasonCode:e,reasonCodes:[e],publicSummary:T(t),redactionSummary:[{field:n,reason:c,evidence:"value-denied",publicSafe:!0}],publicSafe:!0}}export{m as HEADLESS_RUNTIME_BINARY_REASON_CODES,o as RUNNER_BINARY_REASON_CODES,ae as checkRunnerBinaryTrust,oe as checkTrustedHeadlessRuntimeBinary,q as defaultHeadlessRuntimeCommandLocator,re as resolveTrustedRunnerBinary,ce as runnerTrustRelativePath};
|