@ornexus/neocortex 4.0.1

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.

Potentially problematic release.


This version of @ornexus/neocortex might be problematic. Click here for more details.

Files changed (121) hide show
  1. package/LICENSE +56 -0
  2. package/README.md +32 -0
  3. package/install.js +486 -0
  4. package/install.ps1 +1790 -0
  5. package/install.sh +1587 -0
  6. package/package.json +104 -0
  7. package/packages/client/dist/adapters/adapter-registry.d.ts +61 -0
  8. package/packages/client/dist/adapters/adapter-registry.js +106 -0
  9. package/packages/client/dist/adapters/antigravity-adapter.d.ts +18 -0
  10. package/packages/client/dist/adapters/antigravity-adapter.js +77 -0
  11. package/packages/client/dist/adapters/claude-code-adapter.d.ts +19 -0
  12. package/packages/client/dist/adapters/claude-code-adapter.js +79 -0
  13. package/packages/client/dist/adapters/codex-adapter.d.ts +19 -0
  14. package/packages/client/dist/adapters/codex-adapter.js +80 -0
  15. package/packages/client/dist/adapters/cursor-adapter.d.ts +19 -0
  16. package/packages/client/dist/adapters/cursor-adapter.js +115 -0
  17. package/packages/client/dist/adapters/gemini-adapter.d.ts +18 -0
  18. package/packages/client/dist/adapters/gemini-adapter.js +71 -0
  19. package/packages/client/dist/adapters/index.d.ts +19 -0
  20. package/packages/client/dist/adapters/index.js +21 -0
  21. package/packages/client/dist/adapters/platform-detector.d.ts +46 -0
  22. package/packages/client/dist/adapters/platform-detector.js +106 -0
  23. package/packages/client/dist/adapters/target-adapter.d.ts +70 -0
  24. package/packages/client/dist/adapters/target-adapter.js +12 -0
  25. package/packages/client/dist/adapters/vscode-adapter.d.ts +19 -0
  26. package/packages/client/dist/adapters/vscode-adapter.js +72 -0
  27. package/packages/client/dist/agent/refresh-stubs.d.ts +65 -0
  28. package/packages/client/dist/agent/refresh-stubs.js +234 -0
  29. package/packages/client/dist/agent/update-agent-yaml.d.ts +26 -0
  30. package/packages/client/dist/agent/update-agent-yaml.js +102 -0
  31. package/packages/client/dist/agent/update-description.d.ts +45 -0
  32. package/packages/client/dist/agent/update-description.js +251 -0
  33. package/packages/client/dist/cache/crypto-utils.d.ts +30 -0
  34. package/packages/client/dist/cache/crypto-utils.js +76 -0
  35. package/packages/client/dist/cache/encrypted-cache.d.ts +30 -0
  36. package/packages/client/dist/cache/encrypted-cache.js +94 -0
  37. package/packages/client/dist/cache/in-memory-asset-cache.d.ts +59 -0
  38. package/packages/client/dist/cache/in-memory-asset-cache.js +70 -0
  39. package/packages/client/dist/cache/index.d.ts +13 -0
  40. package/packages/client/dist/cache/index.js +13 -0
  41. package/packages/client/dist/cli.d.ts +14 -0
  42. package/packages/client/dist/cli.js +194 -0
  43. package/packages/client/dist/commands/activate.d.ts +55 -0
  44. package/packages/client/dist/commands/activate.js +390 -0
  45. package/packages/client/dist/commands/cache-status.d.ts +39 -0
  46. package/packages/client/dist/commands/cache-status.js +112 -0
  47. package/packages/client/dist/commands/invoke.d.ts +70 -0
  48. package/packages/client/dist/commands/invoke.js +490 -0
  49. package/packages/client/dist/config/resolver-selection.d.ts +40 -0
  50. package/packages/client/dist/config/resolver-selection.js +278 -0
  51. package/packages/client/dist/config/secure-config.d.ts +78 -0
  52. package/packages/client/dist/config/secure-config.js +269 -0
  53. package/packages/client/dist/constants.d.ts +25 -0
  54. package/packages/client/dist/constants.js +25 -0
  55. package/packages/client/dist/context/context-collector.d.ts +28 -0
  56. package/packages/client/dist/context/context-collector.js +222 -0
  57. package/packages/client/dist/context/context-sanitizer.d.ts +28 -0
  58. package/packages/client/dist/context/context-sanitizer.js +145 -0
  59. package/packages/client/dist/index.d.ts +55 -0
  60. package/packages/client/dist/index.js +38 -0
  61. package/packages/client/dist/license/index.d.ts +5 -0
  62. package/packages/client/dist/license/index.js +5 -0
  63. package/packages/client/dist/license/license-client.d.ts +79 -0
  64. package/packages/client/dist/license/license-client.js +257 -0
  65. package/packages/client/dist/machine/fingerprint.d.ts +34 -0
  66. package/packages/client/dist/machine/fingerprint.js +160 -0
  67. package/packages/client/dist/machine/index.d.ts +5 -0
  68. package/packages/client/dist/machine/index.js +5 -0
  69. package/packages/client/dist/resilience/circuit-breaker.d.ts +70 -0
  70. package/packages/client/dist/resilience/circuit-breaker.js +170 -0
  71. package/packages/client/dist/resilience/degradation-manager.d.ts +67 -0
  72. package/packages/client/dist/resilience/degradation-manager.js +164 -0
  73. package/packages/client/dist/resilience/freshness-indicator.d.ts +59 -0
  74. package/packages/client/dist/resilience/freshness-indicator.js +100 -0
  75. package/packages/client/dist/resilience/index.d.ts +8 -0
  76. package/packages/client/dist/resilience/index.js +8 -0
  77. package/packages/client/dist/resilience/recovery-detector.d.ts +59 -0
  78. package/packages/client/dist/resilience/recovery-detector.js +74 -0
  79. package/packages/client/dist/resolvers/asset-resolver.d.ts +79 -0
  80. package/packages/client/dist/resolvers/asset-resolver.js +13 -0
  81. package/packages/client/dist/resolvers/local-resolver.d.ts +26 -0
  82. package/packages/client/dist/resolvers/local-resolver.js +218 -0
  83. package/packages/client/dist/resolvers/remote-resolver.d.ts +91 -0
  84. package/packages/client/dist/resolvers/remote-resolver.js +282 -0
  85. package/packages/client/dist/telemetry/index.d.ts +5 -0
  86. package/packages/client/dist/telemetry/index.js +5 -0
  87. package/packages/client/dist/telemetry/offline-queue.d.ts +57 -0
  88. package/packages/client/dist/telemetry/offline-queue.js +131 -0
  89. package/packages/client/dist/tier/index.d.ts +5 -0
  90. package/packages/client/dist/tier/index.js +5 -0
  91. package/packages/client/dist/tier/tier-aware-client.d.ts +97 -0
  92. package/packages/client/dist/tier/tier-aware-client.js +260 -0
  93. package/packages/client/dist/types/index.d.ts +140 -0
  94. package/packages/client/dist/types/index.js +38 -0
  95. package/postinstall.js +272 -0
  96. package/targets-stubs/antigravity/README.md +36 -0
  97. package/targets-stubs/antigravity/gemini.md +22 -0
  98. package/targets-stubs/antigravity/install-antigravity.sh +44 -0
  99. package/targets-stubs/antigravity/mcp-config.json +9 -0
  100. package/targets-stubs/antigravity/skill/SKILL.md +67 -0
  101. package/targets-stubs/claude-code/README.md +20 -0
  102. package/targets-stubs/claude-code/neocortex.agent.yaml +24 -0
  103. package/targets-stubs/claude-code/neocortex.md +125 -0
  104. package/targets-stubs/codex/README.md +32 -0
  105. package/targets-stubs/codex/agents.md +61 -0
  106. package/targets-stubs/codex/config-mcp.toml +6 -0
  107. package/targets-stubs/codex/install-codex.sh +61 -0
  108. package/targets-stubs/cursor/README.md +33 -0
  109. package/targets-stubs/cursor/agent.md +94 -0
  110. package/targets-stubs/cursor/install-cursor.sh +35 -0
  111. package/targets-stubs/cursor/mcp.json +11 -0
  112. package/targets-stubs/gemini-cli/README.md +34 -0
  113. package/targets-stubs/gemini-cli/agent.md +101 -0
  114. package/targets-stubs/gemini-cli/gemini.md +16 -0
  115. package/targets-stubs/gemini-cli/install-gemini.sh +56 -0
  116. package/targets-stubs/gemini-cli/settings-mcp.json +11 -0
  117. package/targets-stubs/vscode/README.md +34 -0
  118. package/targets-stubs/vscode/agent.md +102 -0
  119. package/targets-stubs/vscode/copilot-instructions.md +16 -0
  120. package/targets-stubs/vscode/install-vscode.sh +42 -0
  121. package/targets-stubs/vscode/mcp.json +13 -0
@@ -0,0 +1,74 @@
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
+ // ── RecoveryDetector ─────────────────────────────────────────────────────
14
+ export class RecoveryDetector {
15
+ actions;
16
+ constructor(actions) {
17
+ this.actions = actions;
18
+ }
19
+ /**
20
+ * Execute full recovery sequence.
21
+ * Each step is independent - failures are captured but don't block others.
22
+ */
23
+ async onRecovery() {
24
+ const result = {
25
+ circuitClosed: false,
26
+ jwtRefreshed: false,
27
+ cacheSynced: false,
28
+ telemetryFlushed: { sent: 0, failed: 0 },
29
+ notification: '[ONLINE] Server connection restored',
30
+ };
31
+ // Step 1: Close circuit breaker
32
+ try {
33
+ await this.actions.circuitBreaker.recordSuccess();
34
+ result.circuitClosed = true;
35
+ }
36
+ catch {
37
+ // Non-critical: breaker will close on next successful call
38
+ }
39
+ // Step 2: Re-validate JWT
40
+ try {
41
+ const token = await this.actions.licenseClient.getToken();
42
+ result.jwtRefreshed = token !== null;
43
+ }
44
+ catch {
45
+ // Non-critical: will be retried on next server call
46
+ }
47
+ // Step 3: Sync cache (background - just attempt, don't block)
48
+ try {
49
+ // We don't actually sync here - the next resolver call will
50
+ // update the cache automatically via fetchWithCacheFallback.
51
+ // We just mark as synced since the circuit is now closed.
52
+ result.cacheSynced = true;
53
+ }
54
+ catch {
55
+ // Non-critical
56
+ }
57
+ // Step 4: Flush telemetry queue
58
+ try {
59
+ const flushResult = await this.actions.telemetryQueue.flush(async (events) => {
60
+ const response = await fetch(`${this.actions.serverUrl}/api/v1/telemetry/batch`, {
61
+ method: 'POST',
62
+ headers: { 'Content-Type': 'application/json' },
63
+ body: JSON.stringify({ events }),
64
+ });
65
+ return response.ok;
66
+ });
67
+ result.telemetryFlushed = flushResult;
68
+ }
69
+ catch {
70
+ // Non-critical: queue will be flushed on next recovery
71
+ }
72
+ return result;
73
+ }
74
+ }
@@ -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
+ }
@@ -0,0 +1,13 @@
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 {};
@@ -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,218 @@
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 - LocalResolver
15
+ *
16
+ * Resolves pipeline assets from the local filesystem.
17
+ * Used in development mode when core/ directory is available locally.
18
+ * Replicates the current CLI behavior of reading .md files directly.
19
+ */
20
+ import { readFile, access } from 'node:fs/promises';
21
+ import { join, resolve } from 'node:path';
22
+ import { ResolverMode, } from '../types/index.js';
23
+ // ── Frontmatter Parser ───────────────────────────────────────────────────
24
+ const FRONTMATTER_REGEX = /^---\n([\s\S]*?)\n---/;
25
+ /**
26
+ * Parse YAML-like frontmatter from markdown content.
27
+ * Simple key-value parser sufficient for step/skill frontmatter.
28
+ */
29
+ function parseFrontmatter(content) {
30
+ const match = content.match(FRONTMATTER_REGEX);
31
+ if (!match) {
32
+ return { frontmatter: {}, body: content };
33
+ }
34
+ const frontmatter = {};
35
+ const lines = match[1].split('\n');
36
+ for (const line of lines) {
37
+ const colonIndex = line.indexOf(':');
38
+ if (colonIndex === -1)
39
+ continue;
40
+ const key = line.slice(0, colonIndex).trim().replace(/^['"]|['"]$/g, '');
41
+ let value = line.slice(colonIndex + 1).trim();
42
+ // Remove surrounding quotes
43
+ if (typeof value === 'string') {
44
+ value = value.replace(/^['"]|['"]$/g, '');
45
+ }
46
+ // Parse booleans
47
+ if (value === 'true')
48
+ value = true;
49
+ else if (value === 'false')
50
+ value = false;
51
+ frontmatter[key] = value;
52
+ }
53
+ const body = content.slice(match[0].length).trimStart();
54
+ return { frontmatter, body };
55
+ }
56
+ // ── Step ID to File Path Mapping ─────────────────────────────────────────
57
+ /**
58
+ * Map step ID to file path within core/steps/.
59
+ *
60
+ * Step IDs follow the pattern: step-{category}-{order}-{name}
61
+ * File paths: core/steps/steps-{category}/{id}.md
62
+ */
63
+ function stepIdToPath(stepId) {
64
+ // Extract category from step ID: step-c-01-setup-branch -> c
65
+ // step-r-fix-blocked -> r, step-u-init -> u, step-p-01-idea-diagnose -> p, step-e-01-epic-init -> e
66
+ const parts = stepId.split('-');
67
+ if (parts.length < 3) {
68
+ throw new Error(`Invalid step ID format: ${stepId}`);
69
+ }
70
+ const category = parts[1]; // c, r, u, p, e
71
+ const categoryMap = {
72
+ c: 'steps-c',
73
+ r: 'steps-r',
74
+ u: 'steps-u',
75
+ p: 'steps-p',
76
+ e: 'steps-e',
77
+ };
78
+ const dir = categoryMap[category];
79
+ if (!dir) {
80
+ throw new Error(`Unknown step category '${category}' in step ID: ${stepId}`);
81
+ }
82
+ return `core/steps/${dir}/${stepId}.md`;
83
+ }
84
+ // ── LocalResolver Implementation ─────────────────────────────────────────
85
+ export class LocalResolver {
86
+ mode = ResolverMode.LOCAL;
87
+ projectRoot;
88
+ constructor(options) {
89
+ this.projectRoot = resolve(options.projectRoot);
90
+ }
91
+ async resolveStep(stepId, _context) {
92
+ const relativePath = stepIdToPath(stepId);
93
+ const fullPath = join(this.projectRoot, relativePath);
94
+ const raw = await readFile(fullPath, 'utf-8');
95
+ const { frontmatter, body } = parseFrontmatter(raw);
96
+ return {
97
+ id: stepId,
98
+ content: body,
99
+ frontmatter,
100
+ };
101
+ }
102
+ async resolveSkill(skillId, _context) {
103
+ // Skills are organized in: core/skills/{category}/{skillId}.md
104
+ // or: core/skills/step-skills/{step}/{skillId}.md
105
+ // Try multiple paths to find the skill
106
+ const searchPaths = [
107
+ `core/skills/${skillId}.md`,
108
+ `core/skills/step-skills/${skillId}.md`,
109
+ ];
110
+ // Also try with nested path: "diagnose/prompt-enricher" -> core/skills/step-skills/diagnose/prompt-enricher.md
111
+ if (skillId.includes('/')) {
112
+ searchPaths.unshift(`core/skills/step-skills/${skillId}.md`);
113
+ searchPaths.unshift(`core/skills/${skillId}.md`);
114
+ }
115
+ let raw = null;
116
+ let resolvedPath = '';
117
+ for (const searchPath of searchPaths) {
118
+ const fullPath = join(this.projectRoot, searchPath);
119
+ try {
120
+ raw = await readFile(fullPath, 'utf-8');
121
+ resolvedPath = searchPath;
122
+ break;
123
+ }
124
+ catch {
125
+ // Try next path
126
+ }
127
+ }
128
+ if (raw === null) {
129
+ throw new Error(`Skill '${skillId}' not found. Searched: ${searchPaths.join(', ')}`);
130
+ }
131
+ const { frontmatter, body } = parseFrontmatter(raw);
132
+ return {
133
+ id: skillId,
134
+ content: body,
135
+ metadata: { ...frontmatter, resolvedPath },
136
+ };
137
+ }
138
+ async resolveStandard(standardId) {
139
+ const fullPath = join(this.projectRoot, 'core', 'standards', standardId);
140
+ let content;
141
+ try {
142
+ content = await readFile(fullPath, 'utf-8');
143
+ }
144
+ catch {
145
+ // Try with .md extension if not present
146
+ if (!standardId.endsWith('.md')) {
147
+ content = await readFile(`${fullPath}.md`, 'utf-8');
148
+ }
149
+ else {
150
+ throw new Error(`Standard '${standardId}' not found at ${fullPath}`);
151
+ }
152
+ }
153
+ return {
154
+ id: standardId,
155
+ content,
156
+ };
157
+ }
158
+ async resolveRegistry() {
159
+ const fullPath = join(this.projectRoot, 'core', 'data', 'step-registry.json');
160
+ const raw = await readFile(fullPath, 'utf-8');
161
+ return JSON.parse(raw);
162
+ }
163
+ async assemblePrompt(stepId, context) {
164
+ // Resolve the step content
165
+ const step = await this.resolveStep(stepId, context);
166
+ // Build variables map from context
167
+ const variables = {
168
+ '{story_id}': context.storyId,
169
+ '{story_title}': context.storyTitle,
170
+ '{step_id}': stepId,
171
+ '{step_name}': step.frontmatter['name'] || stepId,
172
+ '{current_status}': context.currentStatus,
173
+ '{epic_id}': context.epicId,
174
+ '{branch_name}': context.branchName,
175
+ '{platform_target}': context.platformTarget,
176
+ };
177
+ // Substitute variables in step content
178
+ let prompt = step.content;
179
+ for (const [key, value] of Object.entries(variables)) {
180
+ prompt = prompt.replaceAll(key, value);
181
+ }
182
+ // Resolve skills referenced in step frontmatter
183
+ const includedSkills = [];
184
+ const skillsRef = step.frontmatter['skills'];
185
+ if (skillsRef && typeof skillsRef === 'string') {
186
+ const skillIds = skillsRef.split(',').map((s) => s.trim());
187
+ for (const sid of skillIds) {
188
+ try {
189
+ const skill = await this.resolveSkill(sid, context);
190
+ prompt += `\n\n---\n\n# Skill: ${sid}\n\n${skill.content}`;
191
+ includedSkills.push(sid);
192
+ }
193
+ catch {
194
+ // Skill not found - skip
195
+ }
196
+ }
197
+ }
198
+ return {
199
+ prompt,
200
+ variables,
201
+ includedSkills,
202
+ includedStandards: [],
203
+ };
204
+ }
205
+ async isAvailable() {
206
+ try {
207
+ const corePath = join(this.projectRoot, 'core');
208
+ await access(corePath);
209
+ return true;
210
+ }
211
+ catch {
212
+ return false;
213
+ }
214
+ }
215
+ async dispose() {
216
+ // LocalResolver holds no resources to release
217
+ }
218
+ }
@@ -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
+ }