@harness-nexus/cli 0.1.0-alpha.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.
- package/LICENSE +21 -0
- package/README.md +59 -0
- package/dist/config.d.ts +24 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +38 -0
- package/dist/config.js.map +1 -0
- package/dist/daemon/acp/adapters.d.ts +7 -0
- package/dist/daemon/acp/adapters.d.ts.map +1 -0
- package/dist/daemon/acp/adapters.js +34 -0
- package/dist/daemon/acp/adapters.js.map +1 -0
- package/dist/daemon/acp/agent-connection.d.ts +45 -0
- package/dist/daemon/acp/agent-connection.d.ts.map +1 -0
- package/dist/daemon/acp/agent-connection.js +158 -0
- package/dist/daemon/acp/agent-connection.js.map +1 -0
- package/dist/daemon/chat.d.ts +22 -0
- package/dist/daemon/chat.d.ts.map +1 -0
- package/dist/daemon/chat.js +280 -0
- package/dist/daemon/chat.js.map +1 -0
- package/dist/daemon/client.d.ts +23 -0
- package/dist/daemon/client.d.ts.map +1 -0
- package/dist/daemon/client.js +117 -0
- package/dist/daemon/client.js.map +1 -0
- package/dist/daemon/jobs.d.ts +19 -0
- package/dist/daemon/jobs.d.ts.map +1 -0
- package/dist/daemon/jobs.js +65 -0
- package/dist/daemon/jobs.js.map +1 -0
- package/dist/errors.d.ts +11 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +11 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +481 -0
- package/dist/index.js.map +1 -0
- package/dist/install/adapter-factory.d.ts +24 -0
- package/dist/install/adapter-factory.d.ts.map +1 -0
- package/dist/install/adapter-factory.js +80 -0
- package/dist/install/adapter-factory.js.map +1 -0
- package/dist/install/adapters/codex.d.ts +16 -0
- package/dist/install/adapters/codex.d.ts.map +1 -0
- package/dist/install/adapters/codex.js +172 -0
- package/dist/install/adapters/codex.js.map +1 -0
- package/dist/install/adapters/deepseek.d.ts +26 -0
- package/dist/install/adapters/deepseek.d.ts.map +1 -0
- package/dist/install/adapters/deepseek.js +246 -0
- package/dist/install/adapters/deepseek.js.map +1 -0
- package/dist/install/adapters/hermes.d.ts +16 -0
- package/dist/install/adapters/hermes.d.ts.map +1 -0
- package/dist/install/adapters/hermes.js +267 -0
- package/dist/install/adapters/hermes.js.map +1 -0
- package/dist/install/adapters/stub.d.ts +2 -0
- package/dist/install/adapters/stub.d.ts.map +1 -0
- package/dist/install/adapters/stub.js +22 -0
- package/dist/install/adapters/stub.js.map +1 -0
- package/dist/install/install-state.d.ts +31 -0
- package/dist/install/install-state.d.ts.map +1 -0
- package/dist/install/install-state.js +29 -0
- package/dist/install/install-state.js.map +1 -0
- package/dist/install/installer.d.ts +16 -0
- package/dist/install/installer.d.ts.map +1 -0
- package/dist/install/installer.js +96 -0
- package/dist/install/installer.js.map +1 -0
- package/dist/install/planner.d.ts +26 -0
- package/dist/install/planner.d.ts.map +1 -0
- package/dist/install/planner.js +25 -0
- package/dist/install/planner.js.map +1 -0
- package/dist/install/registry.d.ts +21 -0
- package/dist/install/registry.d.ts.map +1 -0
- package/dist/install/registry.js +31 -0
- package/dist/install/registry.js.map +1 -0
- package/dist/install/resolver.d.ts +15 -0
- package/dist/install/resolver.d.ts.map +1 -0
- package/dist/install/resolver.js +57 -0
- package/dist/install/resolver.js.map +1 -0
- package/dist/install/types.d.ts +93 -0
- package/dist/install/types.d.ts.map +1 -0
- package/dist/install/types.js +2 -0
- package/dist/install/types.js.map +1 -0
- package/dist/install/uninstaller.d.ts +29 -0
- package/dist/install/uninstaller.d.ts.map +1 -0
- package/dist/install/uninstaller.js +107 -0
- package/dist/install/uninstaller.js.map +1 -0
- package/dist/inventory/common.d.ts +86 -0
- package/dist/inventory/common.d.ts.map +1 -0
- package/dist/inventory/common.js +137 -0
- package/dist/inventory/common.js.map +1 -0
- package/dist/inventory/scan.d.ts +23 -0
- package/dist/inventory/scan.d.ts.map +1 -0
- package/dist/inventory/scan.js +117 -0
- package/dist/inventory/scan.js.map +1 -0
- package/dist/inventory/scanners/claude-code.d.ts +3 -0
- package/dist/inventory/scanners/claude-code.d.ts.map +1 -0
- package/dist/inventory/scanners/claude-code.js +191 -0
- package/dist/inventory/scanners/claude-code.js.map +1 -0
- package/dist/inventory/scanners/codex.d.ts +14 -0
- package/dist/inventory/scanners/codex.d.ts.map +1 -0
- package/dist/inventory/scanners/codex.js +201 -0
- package/dist/inventory/scanners/codex.js.map +1 -0
- package/dist/inventory/scanners/deepseek.d.ts +9 -0
- package/dist/inventory/scanners/deepseek.d.ts.map +1 -0
- package/dist/inventory/scanners/deepseek.js +200 -0
- package/dist/inventory/scanners/deepseek.js.map +1 -0
- package/dist/inventory/scanners/hermes.d.ts +3 -0
- package/dist/inventory/scanners/hermes.d.ts.map +1 -0
- package/dist/inventory/scanners/hermes.js +194 -0
- package/dist/inventory/scanners/hermes.js.map +1 -0
- package/dist/inventory/types.d.ts +33 -0
- package/dist/inventory/types.d.ts.map +1 -0
- package/dist/inventory/types.js +2 -0
- package/dist/inventory/types.js.map +1 -0
- package/dist/mcp/serve.d.ts +8 -0
- package/dist/mcp/serve.d.ts.map +1 -0
- package/dist/mcp/serve.js +118 -0
- package/dist/mcp/serve.js.map +1 -0
- package/package.json +50 -0
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hermes target adapter (Phase 3.4 — first real adapter, priority 1).
|
|
3
|
+
*
|
|
4
|
+
* Hermes is a Python agent with a YAML-native config model. An install emits
|
|
5
|
+
* THREE things:
|
|
6
|
+
* A. a Python **plugin bundle** at `~/.hermes/plugins/<profile>/` (skills).
|
|
7
|
+
* B. MCP servers merged (YAML add-only) into `~/.hermes/config.yaml` `mcp_servers:`.
|
|
8
|
+
* C. rules as `AGENTS.md` at the install root (Hermes auto-loads it).
|
|
9
|
+
*
|
|
10
|
+
* sub_agents and hooks are SKIPPED (Hermes has no file format for either —
|
|
11
|
+
* sub_agents are a runtime `delegate_task` tool; hooks are Python callbacks, not
|
|
12
|
+
* declarative hooks.json). Both surface as skipped warnings.
|
|
13
|
+
*
|
|
14
|
+
* Ground-truth format: `docs/research/phase-3-ecc-install-patterns.md` +
|
|
15
|
+
* verified against `~/.hermes/hermes-agent/hermes_cli/{plugins,mcp_config}.py`.
|
|
16
|
+
*
|
|
17
|
+
* Uninstall/upgrade reliability: the config.yaml merge is a single `write-file`
|
|
18
|
+
* operation recorded in the install-state ledger, so a future `hnx uninstall`
|
|
19
|
+
* can roll it back. Hermes's own `hermes plugins remove` has a config-cleanup
|
|
20
|
+
* gap (leaves stale `plugins.enabled`), so we rely on our ledger, not Hermes.
|
|
21
|
+
*/
|
|
22
|
+
import fs from 'node:fs';
|
|
23
|
+
import path from 'node:path';
|
|
24
|
+
import yaml from 'js-yaml';
|
|
25
|
+
import { createTargetAdapter } from '../adapter-factory.js';
|
|
26
|
+
import { hnxExecutablePath } from '../../config.js';
|
|
27
|
+
/** The install-state ledger filename inside the Hermes home. */
|
|
28
|
+
const INSTALL_STATE_FILENAME = 'harness-nexus-install-state.json';
|
|
29
|
+
/** A resource kind Hermes cannot emit as a file artifact. */
|
|
30
|
+
const SKIPPED_KINDS = new Set(['sub_agent', 'hook', 'command']);
|
|
31
|
+
/** A sanitizer for profile/plugin names used as a directory + Python module name. */
|
|
32
|
+
function slugify(name) {
|
|
33
|
+
return (name
|
|
34
|
+
.toLowerCase()
|
|
35
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
36
|
+
.replace(/^-+|-+$/g, '')
|
|
37
|
+
.slice(0, 64) || 'harness-nexus-profile');
|
|
38
|
+
}
|
|
39
|
+
/** Build the `plugin.yaml` content (Hermes PluginManifest schema). */
|
|
40
|
+
function pluginYaml(profile) {
|
|
41
|
+
const slug = slugify(profile.name);
|
|
42
|
+
const manifest = {
|
|
43
|
+
name: slug,
|
|
44
|
+
version: profile.version || '1.0.0',
|
|
45
|
+
description: profile.description ?? `Harness Nexus profile '${profile.name}'.`,
|
|
46
|
+
author: 'Harness Nexus',
|
|
47
|
+
kind: 'standalone',
|
|
48
|
+
};
|
|
49
|
+
return yaml.dump(manifest, { lineWidth: 100 });
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Build the `__init__.py` exposing `register(ctx)`, which registers each skill
|
|
53
|
+
* via `ctx.register_skill(name, path, description)`. Plugin skills resolve as
|
|
54
|
+
* `<plugin>:<skill>` in Hermes and are opt-in (not in the system-prompt index).
|
|
55
|
+
*/
|
|
56
|
+
function pluginInitPy(profile, skills) {
|
|
57
|
+
const slug = slugify(profile.name);
|
|
58
|
+
const lines = [
|
|
59
|
+
'"""Harness Nexus profile plugin (auto-generated by `hnx install`)."""',
|
|
60
|
+
'from pathlib import Path',
|
|
61
|
+
'',
|
|
62
|
+
'',
|
|
63
|
+
'def register(ctx):',
|
|
64
|
+
' _root = Path(__file__).parent',
|
|
65
|
+
];
|
|
66
|
+
for (const s of skills) {
|
|
67
|
+
const pyName = JSON.stringify(s.name);
|
|
68
|
+
const pyPath = `str(_root / "skills" / ${pyName})`;
|
|
69
|
+
const pyDesc = JSON.stringify(s.description);
|
|
70
|
+
lines.push(` ctx.register_skill(${pyName}, ${pyPath}, ${pyDesc})`);
|
|
71
|
+
}
|
|
72
|
+
lines.push('');
|
|
73
|
+
// Suppress the unused-import lint for `slug` if no skills (keeps it valid Python).
|
|
74
|
+
void slug;
|
|
75
|
+
return lines.join('\n');
|
|
76
|
+
}
|
|
77
|
+
/** Extract skill content from a Resource's source (inline / inline-bundle). */
|
|
78
|
+
function skillFiles(artifact) {
|
|
79
|
+
if (artifact.kind === 'mcp')
|
|
80
|
+
return [];
|
|
81
|
+
const resource = artifact.resource;
|
|
82
|
+
const src = resource.source;
|
|
83
|
+
const description = resource.description ?? '';
|
|
84
|
+
if (src.type === 'inline') {
|
|
85
|
+
return [{ relativePath: 'SKILL.md', content: src.content, description }];
|
|
86
|
+
}
|
|
87
|
+
if (src.type === 'inline-bundle') {
|
|
88
|
+
return Object.entries(src.files).map(([rel, content]) => ({
|
|
89
|
+
relativePath: rel,
|
|
90
|
+
content,
|
|
91
|
+
description,
|
|
92
|
+
}));
|
|
93
|
+
}
|
|
94
|
+
// External sources (git/tarball/local/plugin) are not fetchable by the CLI at
|
|
95
|
+
// install time; only inline content can be emitted. The resolver would need a
|
|
96
|
+
// content-fetch step — out of scope for 3.4. Emit nothing + the caller warns.
|
|
97
|
+
return [];
|
|
98
|
+
}
|
|
99
|
+
/** The Hermes config.yaml path under the install root. */
|
|
100
|
+
function configYamlPath(root) {
|
|
101
|
+
return path.join(root, 'config.yaml');
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Plan the MCP merge into config.yaml. Reads the existing config (if any),
|
|
105
|
+
* adds/overwrites the profile's stdio shim entry under `mcp_servers:`,
|
|
106
|
+
* preserves all other user content, and returns a single `write-file` op with
|
|
107
|
+
* the full merged YAML. The ledger records this op so uninstall can roll it
|
|
108
|
+
* back.
|
|
109
|
+
*
|
|
110
|
+
* Phase 8 C2: every profile collapses into ONE stdio shim entry —
|
|
111
|
+
* `hnx mcp serve --profile <id> --server <base>` — regardless of dial sites.
|
|
112
|
+
* The shim dials client-dialed upstreams itself and reaches server-dialed
|
|
113
|
+
* ones through the platform outlet, so no credential ever lands in config.yaml
|
|
114
|
+
* (the pre-C2 direct-mode inlining and the `${HN_PAT_*}` env placeholder are
|
|
115
|
+
* gone).
|
|
116
|
+
*/
|
|
117
|
+
function planMcpMerge(resolved, root, serverBase) {
|
|
118
|
+
const cfgPath = configYamlPath(root);
|
|
119
|
+
let config = {};
|
|
120
|
+
if (fs.existsSync(cfgPath)) {
|
|
121
|
+
try {
|
|
122
|
+
const parsed = yaml.load(fs.readFileSync(cfgPath, 'utf8'));
|
|
123
|
+
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
|
|
124
|
+
config = parsed;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
// Unparseable config: leave config empty and overwrite (best-effort).
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
const mcpServers = config['mcp_servers'] ?? {};
|
|
132
|
+
const slug = slugify(resolved.profile.name);
|
|
133
|
+
const mcpCount = resolved.artifacts.filter((a) => a.kind === 'mcp').length;
|
|
134
|
+
if (mcpCount > 0) {
|
|
135
|
+
mcpServers[`harness-nexus-${slug}`] = {
|
|
136
|
+
command: hnxExecutablePath(),
|
|
137
|
+
args: ['mcp', 'serve', '--profile', resolved.profile.id, '--server', serverBase],
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
config['mcp_servers'] = mcpServers;
|
|
141
|
+
const dumped = yaml.dump(config, { lineWidth: 100 });
|
|
142
|
+
return { kind: 'write-file', content: dumped, destinationPath: cfgPath };
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* The Hermes adapter. Overrides `planOperations` to emit the plugin bundle,
|
|
146
|
+
* the config.yaml MCP merge, and the AGENTS.md rule file.
|
|
147
|
+
*/
|
|
148
|
+
export const hermesAdapter = createTargetAdapter({
|
|
149
|
+
id: 'hermes-home',
|
|
150
|
+
target: 'hermes',
|
|
151
|
+
kind: 'home',
|
|
152
|
+
rootSegments: ['.hermes'],
|
|
153
|
+
planOperations(resolved, input, adapter) {
|
|
154
|
+
const root = adapter.resolveRoot(input);
|
|
155
|
+
const slug = slugify(resolved.profile.name);
|
|
156
|
+
const pluginDir = path.join(root, 'plugins', slug);
|
|
157
|
+
const operations = [];
|
|
158
|
+
const skipped = [];
|
|
159
|
+
// ---- A. Plugin bundle (skills only) ----
|
|
160
|
+
const skillArtifacts = resolved.artifacts.filter((a) => a.kind === 'skill');
|
|
161
|
+
const skillMeta = [];
|
|
162
|
+
if (skillArtifacts.length > 0) {
|
|
163
|
+
// plugin.yaml
|
|
164
|
+
operations.push({
|
|
165
|
+
kind: 'write-file',
|
|
166
|
+
content: pluginYaml(resolved.profile),
|
|
167
|
+
destinationPath: path.join(pluginDir, 'plugin.yaml'),
|
|
168
|
+
});
|
|
169
|
+
// skills + collect meta for __init__.py
|
|
170
|
+
for (const a of skillArtifacts) {
|
|
171
|
+
if (a.kind === 'mcp')
|
|
172
|
+
continue;
|
|
173
|
+
const files = skillFiles(a);
|
|
174
|
+
if (files.length === 0) {
|
|
175
|
+
skipped.push(`skill:${a.resource.key} (non-inline source not fetchable by CLI)`);
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
const skillDir = path.join(pluginDir, 'skills', a.resource.name);
|
|
179
|
+
for (const f of files) {
|
|
180
|
+
operations.push({
|
|
181
|
+
kind: 'write-file',
|
|
182
|
+
content: f.content,
|
|
183
|
+
destinationPath: path.join(skillDir, f.relativePath),
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
skillMeta.push({ name: a.resource.name, description: a.resource.description ?? '' });
|
|
187
|
+
}
|
|
188
|
+
// __init__.py
|
|
189
|
+
operations.push({
|
|
190
|
+
kind: 'write-file',
|
|
191
|
+
content: pluginInitPy(resolved.profile, skillMeta),
|
|
192
|
+
destinationPath: path.join(pluginDir, '__init__.py'),
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
// ---- B. MCP merge into config.yaml ----
|
|
196
|
+
// The shim entry needs the server base URL. The adapter doesn't receive
|
|
197
|
+
// the resolver's server directly, so the CLI sets HN_SERVER before
|
|
198
|
+
// planning (see runInstall); a sensible fallback covers direct
|
|
199
|
+
// planInstall() use in tests.
|
|
200
|
+
const serverBase = process.env.HN_SERVER ?? 'https://harness-nexus.example.com';
|
|
201
|
+
const hasMcp = resolved.artifacts.some((a) => a.kind === 'mcp');
|
|
202
|
+
if (hasMcp) {
|
|
203
|
+
operations.push(planMcpMerge(resolved, root, serverBase));
|
|
204
|
+
}
|
|
205
|
+
// ---- C. Rules → AGENTS.md (auto-loaded by Hermes) ----
|
|
206
|
+
const ruleArtifacts = resolved.artifacts.filter((a) => a.kind === 'rule');
|
|
207
|
+
if (ruleArtifacts.length > 0) {
|
|
208
|
+
// Concatenate rule contents into one AGENTS.md (Hermes loads a single file).
|
|
209
|
+
const body = ruleArtifacts
|
|
210
|
+
.map((a) => {
|
|
211
|
+
if (a.kind === 'mcp')
|
|
212
|
+
return '';
|
|
213
|
+
const src = a.resource.source;
|
|
214
|
+
return src.type === 'inline'
|
|
215
|
+
? src.content
|
|
216
|
+
: `# ${a.resource.name}\n(non-inline source skipped)`;
|
|
217
|
+
})
|
|
218
|
+
.filter(Boolean)
|
|
219
|
+
.join('\n\n---\n\n');
|
|
220
|
+
if (body) {
|
|
221
|
+
operations.push({
|
|
222
|
+
kind: 'write-file',
|
|
223
|
+
content: body,
|
|
224
|
+
destinationPath: path.join(root, 'AGENTS.md'),
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
// ---- skipped kinds ----
|
|
229
|
+
for (const a of resolved.artifacts) {
|
|
230
|
+
if (SKIPPED_KINDS.has(a.kind)) {
|
|
231
|
+
if (a.kind === 'mcp')
|
|
232
|
+
continue;
|
|
233
|
+
const reason = a.kind === 'sub_agent'
|
|
234
|
+
? 'Hermes has no file-based sub-agent format (runtime delegate_task only)'
|
|
235
|
+
: a.kind === 'hook'
|
|
236
|
+
? 'Hermes hooks are Python callbacks, not declarative hooks.json'
|
|
237
|
+
: 'commands are not emitted for Hermes in 3.4';
|
|
238
|
+
skipped.push(`${a.kind}:${a.resource.key} (${reason})`);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
// Stash diagnostics on the plan via a non-enumerable side channel the CLI
|
|
242
|
+
// can read (kept simple: module-level last-warnings for 3.4).
|
|
243
|
+
lastPlanWarnings = {
|
|
244
|
+
skipped,
|
|
245
|
+
needsHnx: hasMcp,
|
|
246
|
+
pluginSlug: slug,
|
|
247
|
+
needsPluginEnable: skillArtifacts.length > 0,
|
|
248
|
+
};
|
|
249
|
+
return {
|
|
250
|
+
adapter: { id: adapter.id, target: adapter.target, kind: adapter.kind },
|
|
251
|
+
targetRoot: root,
|
|
252
|
+
installStatePath: path.join(root, INSTALL_STATE_FILENAME),
|
|
253
|
+
operations,
|
|
254
|
+
sensitive: false,
|
|
255
|
+
};
|
|
256
|
+
},
|
|
257
|
+
});
|
|
258
|
+
let lastPlanWarnings = {
|
|
259
|
+
skipped: [],
|
|
260
|
+
needsHnx: false,
|
|
261
|
+
pluginSlug: '',
|
|
262
|
+
needsPluginEnable: false,
|
|
263
|
+
};
|
|
264
|
+
export function getHermesPlanWarnings() {
|
|
265
|
+
return lastPlanWarnings;
|
|
266
|
+
}
|
|
267
|
+
//# sourceMappingURL=hermes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hermes.js","sourceRoot":"","sources":["../../../src/install/adapters/hermes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stub.d.ts","sourceRoot":"","sources":["../../../src/install/adapters/stub.ts"],"names":[],"mappings":"AAgBA,eAAO,MAAM,WAAW,qCAKtB,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stub adapter — a placeholder for `target: 'generic'`. It uses the factory's
|
|
3
|
+
* default `planOperations`, which writes a minimal `harness-nexus-profile.json`
|
|
4
|
+
* metadata file. This exists so the plan/apply pipeline is exercisable
|
|
5
|
+
* end-to-end in Phase 3.3 before any real target adapter ships (3.4+).
|
|
6
|
+
*
|
|
7
|
+
* Real adapters (hermes / claude-code / codex) override `planOperations` to
|
|
8
|
+
* emit their native layout. This stub intentionally does NOT emit any real
|
|
9
|
+
* target format.
|
|
10
|
+
*
|
|
11
|
+
* NOTE: `generic` is the only registered adapter in 3.3. A profile with
|
|
12
|
+
* `target: 'hermes'` will hit `TARGET_UNSUPPORTED` until the Hermes adapter
|
|
13
|
+
* lands (3.4) — that's expected; the stub is a pipeline demonstrator only.
|
|
14
|
+
*/
|
|
15
|
+
import { createTargetAdapter } from '../adapter-factory.js';
|
|
16
|
+
export const stubAdapter = createTargetAdapter({
|
|
17
|
+
id: 'generic-stub',
|
|
18
|
+
target: 'generic',
|
|
19
|
+
kind: 'home',
|
|
20
|
+
rootSegments: ['.harness-nexus'],
|
|
21
|
+
});
|
|
22
|
+
//# sourceMappingURL=stub.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stub.js","sourceRoot":"","sources":["../../../src/install/adapters/stub.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE5D,MAAM,CAAC,MAAM,WAAW,GAAG,mBAAmB,CAAC;IAC7C,EAAE,EAAE,cAAc;IAClB,MAAM,EAAE,SAAS;IACjB,IAAI,EAAE,MAAM;IACZ,YAAY,EAAE,CAAC,gBAAgB,CAAC;CACjC,CAAC,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { InstallPlan } from './types.js';
|
|
2
|
+
export declare const INSTALL_STATE_SCHEMA_VERSION = "harness-nexus.install.v1";
|
|
3
|
+
/**
|
|
4
|
+
* One ledger operation: the plan op plus the pre-install snapshot of the
|
|
5
|
+
* destination file (`null` = the file did not exist). Snapshots live ONLY in
|
|
6
|
+
* the ledger — plans stay pure — and are what `hnx uninstall` restores.
|
|
7
|
+
*/
|
|
8
|
+
export type LedgerOperation = InstallPlan['operations'][number] & {
|
|
9
|
+
previousContent?: string | null;
|
|
10
|
+
};
|
|
11
|
+
export interface InstallState {
|
|
12
|
+
schemaVersion: typeof INSTALL_STATE_SCHEMA_VERSION;
|
|
13
|
+
installedAt: string;
|
|
14
|
+
target: {
|
|
15
|
+
id: string;
|
|
16
|
+
target: string;
|
|
17
|
+
kind: string;
|
|
18
|
+
root: string;
|
|
19
|
+
};
|
|
20
|
+
profile: {
|
|
21
|
+
id: string;
|
|
22
|
+
name: string;
|
|
23
|
+
version: string;
|
|
24
|
+
};
|
|
25
|
+
operations: LedgerOperation[];
|
|
26
|
+
}
|
|
27
|
+
/** Write the ledger to its path inside the target root. */
|
|
28
|
+
export declare function writeInstallState(plan: InstallPlan, state: Omit<InstallState, 'schemaVersion' | 'operations'>, operations?: LedgerOperation[]): void;
|
|
29
|
+
/** Read a previously-written ledger (returns null if absent). */
|
|
30
|
+
export declare function readInstallState(installStatePath: string): InstallState | null;
|
|
31
|
+
//# sourceMappingURL=install-state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install-state.d.ts","sourceRoot":"","sources":["../../src/install/install-state.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,eAAO,MAAM,4BAA4B,6BAA6B,CAAC;AAEvE;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG,WAAW,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,GAAG;IAChE,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC,CAAC;AAEF,MAAM,WAAW,YAAY;IAC3B,aAAa,EAAE,OAAO,4BAA4B,CAAC;IACnD,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACnE,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IACvD,UAAU,EAAE,eAAe,EAAE,CAAC;CAC/B;AAED,2DAA2D;AAC3D,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,WAAW,EACjB,KAAK,EAAE,IAAI,CAAC,YAAY,EAAE,eAAe,GAAG,YAAY,CAAC,EACzD,UAAU,GAAE,eAAe,EAAoB,GAC9C,IAAI,CAQN;AAED,iEAAiE;AACjE,wBAAgB,gBAAgB,CAAC,gBAAgB,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAG9E"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* install-state ledger — a JSON record written on every `--apply`, enabling
|
|
3
|
+
* future `doctor` (drift detection) / `repair` / `uninstall` (remove only
|
|
4
|
+
* managed files). Mirrors ECC's `ecc.install.v1` ledger concept (see
|
|
5
|
+
* `docs/research/phase-3-ecc-install-patterns.md` Pattern 5).
|
|
6
|
+
*
|
|
7
|
+
* Phase 3.3 only writes + reads the ledger; the doctor/repair/uninstall
|
|
8
|
+
* subcommands come later.
|
|
9
|
+
*/
|
|
10
|
+
import fs from 'node:fs';
|
|
11
|
+
import path from 'node:path';
|
|
12
|
+
export const INSTALL_STATE_SCHEMA_VERSION = 'harness-nexus.install.v1';
|
|
13
|
+
/** Write the ledger to its path inside the target root. */
|
|
14
|
+
export function writeInstallState(plan, state, operations = plan.operations) {
|
|
15
|
+
const full = {
|
|
16
|
+
schemaVersion: INSTALL_STATE_SCHEMA_VERSION,
|
|
17
|
+
...state,
|
|
18
|
+
operations,
|
|
19
|
+
};
|
|
20
|
+
fs.mkdirSync(path.dirname(plan.installStatePath), { recursive: true });
|
|
21
|
+
fs.writeFileSync(plan.installStatePath, `${JSON.stringify(full, null, 2)}\n`, 'utf8');
|
|
22
|
+
}
|
|
23
|
+
/** Read a previously-written ledger (returns null if absent). */
|
|
24
|
+
export function readInstallState(installStatePath) {
|
|
25
|
+
if (!fs.existsSync(installStatePath))
|
|
26
|
+
return null;
|
|
27
|
+
return JSON.parse(fs.readFileSync(installStatePath, 'utf8'));
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=install-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install-state.js","sourceRoot":"","sources":["../../src/install/install-state.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAG7B,MAAM,CAAC,MAAM,4BAA4B,GAAG,0BAA0B,CAAC;AAmBvE,2DAA2D;AAC3D,MAAM,UAAU,iBAAiB,CAC/B,IAAiB,EACjB,KAAyD,EACzD,aAAgC,IAAI,CAAC,UAAU;IAE/C,MAAM,IAAI,GAAiB;QACzB,aAAa,EAAE,4BAA4B;QAC3C,GAAG,KAAK;QACR,UAAU;KACX,CAAC;IACF,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,gBAAgB,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACvE,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,gBAAgB,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AACxF,CAAC;AAED,iEAAiE;AACjE,MAAM,UAAU,gBAAgB,CAAC,gBAAwB;IACvD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,gBAAgB,CAAC;QAAE,OAAO,IAAI,CAAC;IAClD,OAAO,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAiB,CAAC;AAC/E,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { InstallPlan } from './types.js';
|
|
2
|
+
/** Deep-merge `patch` into `base` (objects recurse; non-objects replace). */
|
|
3
|
+
export declare function deepMergeJson(base: unknown, patch: unknown): unknown;
|
|
4
|
+
/**
|
|
5
|
+
* Materialize a plan to disk. Creates parent dirs, writes every operation, then
|
|
6
|
+
* records the install-state ledger — each ledger op carrying the pre-install
|
|
7
|
+
* snapshot of its destination (`null` if absent), which is what
|
|
8
|
+
* `hnx uninstall` restores. If the plan is sensitive, the target root gets
|
|
9
|
+
* restrictive permissions (0700).
|
|
10
|
+
*/
|
|
11
|
+
export declare function applyInstall(plan: InstallPlan, meta: {
|
|
12
|
+
profileId: string;
|
|
13
|
+
profileName: string;
|
|
14
|
+
profileVersion: string;
|
|
15
|
+
}): void;
|
|
16
|
+
//# sourceMappingURL=installer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"installer.d.ts","sourceRoot":"","sources":["../../src/install/installer.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,WAAW,EAAa,MAAM,YAAY,CAAC;AAOzD,6EAA6E;AAC7E,wBAAgB,aAAa,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAUpE;AA+BD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,WAAW,EACjB,IAAI,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,GACvE,IAAI,CAqCN"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Installer — materializes an `InstallPlan` to disk and writes the install-state
|
|
3
|
+
* ledger. Mirrors ECC's `applyInstallPlan`
|
|
4
|
+
* (`scripts/lib/install/apply.js`). Three operation kinds:
|
|
5
|
+
* - `copy-file` — copy a resolved artifact verbatim.
|
|
6
|
+
* - `write-file` — write adapter-generated inline content.
|
|
7
|
+
* - `merge-json` — deep-merge a JSON value into an existing config file.
|
|
8
|
+
*
|
|
9
|
+
* If the plan is `sensitive` (carries decrypted direct-mode credentials), the
|
|
10
|
+
* target root is chmod'd to 0700.
|
|
11
|
+
*/
|
|
12
|
+
import fs from 'node:fs';
|
|
13
|
+
import path from 'node:path';
|
|
14
|
+
import { InstallError } from '../errors.js';
|
|
15
|
+
import { writeInstallState } from './install-state.js';
|
|
16
|
+
/** True for plain objects (not arrays/null) — used by deepMergeJson. */
|
|
17
|
+
function isPlainObject(v) {
|
|
18
|
+
return typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
19
|
+
}
|
|
20
|
+
/** Deep-merge `patch` into `base` (objects recurse; non-objects replace). */
|
|
21
|
+
export function deepMergeJson(base, patch) {
|
|
22
|
+
if (!isPlainObject(base) || !isPlainObject(patch))
|
|
23
|
+
return structuredClone(patch);
|
|
24
|
+
const merged = { ...base };
|
|
25
|
+
for (const [k, v] of Object.entries(patch)) {
|
|
26
|
+
merged[k] =
|
|
27
|
+
isPlainObject(v) && isPlainObject(merged[k])
|
|
28
|
+
? deepMergeJson(merged[k], v)
|
|
29
|
+
: structuredClone(v);
|
|
30
|
+
}
|
|
31
|
+
return merged;
|
|
32
|
+
}
|
|
33
|
+
/** Capture the destination's pre-install content for the ledger (null = absent). */
|
|
34
|
+
function snapshot(op) {
|
|
35
|
+
const previousContent = fs.existsSync(op.destinationPath)
|
|
36
|
+
? fs.readFileSync(op.destinationPath, 'utf8')
|
|
37
|
+
: null;
|
|
38
|
+
return { ...op, previousContent };
|
|
39
|
+
}
|
|
40
|
+
function applyOperation(op) {
|
|
41
|
+
fs.mkdirSync(path.dirname(op.destinationPath), { recursive: true });
|
|
42
|
+
switch (op.kind) {
|
|
43
|
+
case 'copy-file':
|
|
44
|
+
fs.copyFileSync(op.sourcePath, op.destinationPath);
|
|
45
|
+
break;
|
|
46
|
+
case 'write-file':
|
|
47
|
+
fs.writeFileSync(op.destinationPath, op.content, 'utf8');
|
|
48
|
+
break;
|
|
49
|
+
case 'merge-json': {
|
|
50
|
+
const existing = fs.existsSync(op.destinationPath)
|
|
51
|
+
? JSON.parse(fs.readFileSync(op.destinationPath, 'utf8'))
|
|
52
|
+
: {};
|
|
53
|
+
const merged = deepMergeJson(existing, op.mergePayload);
|
|
54
|
+
fs.writeFileSync(op.destinationPath, `${JSON.stringify(merged, null, 2)}\n`, 'utf8');
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Materialize a plan to disk. Creates parent dirs, writes every operation, then
|
|
61
|
+
* records the install-state ledger — each ledger op carrying the pre-install
|
|
62
|
+
* snapshot of its destination (`null` if absent), which is what
|
|
63
|
+
* `hnx uninstall` restores. If the plan is sensitive, the target root gets
|
|
64
|
+
* restrictive permissions (0700).
|
|
65
|
+
*/
|
|
66
|
+
export function applyInstall(plan, meta) {
|
|
67
|
+
const ledgerOps = [];
|
|
68
|
+
try {
|
|
69
|
+
for (const op of plan.operations) {
|
|
70
|
+
ledgerOps.push(snapshot(op));
|
|
71
|
+
applyOperation(op);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
catch (e) {
|
|
75
|
+
throw new InstallError(`Failed to write ${plan.operations.length} operations: ${e.message}`, 'APPLY_FAILED', e);
|
|
76
|
+
}
|
|
77
|
+
writeInstallState(plan, {
|
|
78
|
+
installedAt: new Date().toISOString(),
|
|
79
|
+
target: {
|
|
80
|
+
id: plan.adapter.id,
|
|
81
|
+
target: plan.adapter.target,
|
|
82
|
+
kind: plan.adapter.kind,
|
|
83
|
+
root: plan.targetRoot,
|
|
84
|
+
},
|
|
85
|
+
profile: { id: meta.profileId, name: meta.profileName, version: meta.profileVersion },
|
|
86
|
+
}, ledgerOps);
|
|
87
|
+
if (plan.sensitive) {
|
|
88
|
+
try {
|
|
89
|
+
fs.chmodSync(plan.targetRoot, 0o700);
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
// chmod best-effort (e.g. on some filesystems); the warning is printed by the caller.
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=installer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"installer.js","sourceRoot":"","sources":["../../src/install/installer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Planner — resolves a target adapter, validates input, and asks the adapter to
|
|
3
|
+
* plan file operations. Produces an `InstallPlan` with NO filesystem writes
|
|
4
|
+
* (the dry-run artifact). Mirrors ECC's `planInstallTargetScaffold`.
|
|
5
|
+
*
|
|
6
|
+
* The target resolution rules (from `docs/design/phase-3-install.md`):
|
|
7
|
+
* - If `target` is given and the profile is target-bound and they differ →
|
|
8
|
+
* `TARGET_MISMATCH`.
|
|
9
|
+
* - If `target` is omitted, use the profile's own target.
|
|
10
|
+
* - `zcode` (and any unregistered target) → `TARGET_UNSUPPORTED` (from registry).
|
|
11
|
+
*/
|
|
12
|
+
import type { AgentTarget } from '@harness-nexus/core';
|
|
13
|
+
import type { InstallPlan, ResolvedProfile, ResolveInput } from './types.js';
|
|
14
|
+
export interface PlanOptions {
|
|
15
|
+
/** Explicit --target override; falls back to the profile's own target. */
|
|
16
|
+
target?: AgentTarget;
|
|
17
|
+
/** Passthrough to the adapter (outDir / homeDir). */
|
|
18
|
+
input?: ResolveInput;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Plan an install: pick the adapter, validate, and produce the operation list.
|
|
22
|
+
* Does NOT write anything — the caller prints the plan (dry-run) or passes it
|
|
23
|
+
* to `applyInstall`.
|
|
24
|
+
*/
|
|
25
|
+
export declare function planInstall(resolved: ResolvedProfile, opts?: PlanOptions): InstallPlan;
|
|
26
|
+
//# sourceMappingURL=planner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"planner.d.ts","sourceRoot":"","sources":["../../src/install/planner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAGvD,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE7E,MAAM,WAAW,WAAW;IAC1B,0EAA0E;IAC1E,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,qDAAqD;IACrD,KAAK,CAAC,EAAE,YAAY,CAAC;CACtB;AAaD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,eAAe,EAAE,IAAI,GAAE,WAAgB,GAAG,WAAW,CAW1F"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { InstallError } from '../errors.js';
|
|
2
|
+
import { getAdapter } from './registry.js';
|
|
3
|
+
/** Resolve the effective target, enforcing the mismatch rule. */
|
|
4
|
+
function resolveTarget(profile, requested) {
|
|
5
|
+
if (requested && requested !== profile.profile.target) {
|
|
6
|
+
throw new InstallError(`Target '${requested}' does not match profile's target '${profile.profile.target}' (target is immutable; create a new profile or import instead)`, 'TARGET_MISMATCH');
|
|
7
|
+
}
|
|
8
|
+
return requested ?? profile.profile.target;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Plan an install: pick the adapter, validate, and produce the operation list.
|
|
12
|
+
* Does NOT write anything — the caller prints the plan (dry-run) or passes it
|
|
13
|
+
* to `applyInstall`.
|
|
14
|
+
*/
|
|
15
|
+
export function planInstall(resolved, opts = {}) {
|
|
16
|
+
const target = resolveTarget(resolved, opts.target);
|
|
17
|
+
const adapter = getAdapter(target);
|
|
18
|
+
const issues = adapter.validate(opts.input ?? {});
|
|
19
|
+
const blocking = issues.filter((i) => i.severity === 'error');
|
|
20
|
+
if (blocking.length > 0) {
|
|
21
|
+
throw new InstallError(blocking.map((i) => i.message).join('; '), 'VALIDATION_FAILED');
|
|
22
|
+
}
|
|
23
|
+
return adapter.planOperations(resolved, opts.input ?? {});
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=planner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"planner.js","sourceRoot":"","sources":["../../src/install/planner.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAU3C,iEAAiE;AACjE,SAAS,aAAa,CAAC,OAAwB,EAAE,SAAuB;IACtE,IAAI,SAAS,IAAI,SAAS,KAAK,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;QACtD,MAAM,IAAI,YAAY,CACpB,WAAW,SAAS,sCAAsC,OAAO,CAAC,OAAO,CAAC,MAAM,iEAAiE,EACjJ,iBAAiB,CAClB,CAAC;IACJ,CAAC;IACD,OAAO,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC;AAC7C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,QAAyB,EAAE,OAAoB,EAAE;IAC3E,MAAM,MAAM,GAAG,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IACpD,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;IAEnC,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;IAClD,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC;IAC9D,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,mBAAmB,CAAC,CAAC;IACzF,CAAC;IAED,OAAO,OAAO,CAAC,cAAc,CAAC,QAAQ,EAAE,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;AAC5D,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Target adapter registry. Each target adapter registers itself here; the
|
|
3
|
+
* planner looks one up by `AgentTarget`. Mirrors ECC's
|
|
4
|
+
* `scripts/lib/install-targets/registry.js`.
|
|
5
|
+
*
|
|
6
|
+
* Phase 3.3 ships only the stub `generic` adapter. Real adapters (hermes /
|
|
7
|
+
* claude-code / codex) register here as they land (3.4–3.6). `zcode` has no
|
|
8
|
+
* adapter → `getAdapter('zcode')` throws `TARGET_UNSUPPORTED`.
|
|
9
|
+
*/
|
|
10
|
+
import type { AgentTarget } from '@harness-nexus/core';
|
|
11
|
+
import type { TargetAdapter } from './types.js';
|
|
12
|
+
/** List every registered adapter (for `--help` / discovery). */
|
|
13
|
+
export declare function listAdapters(): readonly TargetAdapter[];
|
|
14
|
+
/** The targets that have an install adapter (excludes zcode). */
|
|
15
|
+
export declare function supportedTargets(): readonly AgentTarget[];
|
|
16
|
+
/**
|
|
17
|
+
* Look up an adapter by target. Throws `TARGET_UNSUPPORTED` if none is
|
|
18
|
+
* registered (e.g. `zcode`).
|
|
19
|
+
*/
|
|
20
|
+
export declare function getAdapter(target: AgentTarget): TargetAdapter;
|
|
21
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/install/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAahD,gEAAgE;AAChE,wBAAgB,YAAY,IAAI,SAAS,aAAa,EAAE,CAEvD;AAED,iEAAiE;AACjE,wBAAgB,gBAAgB,IAAI,SAAS,WAAW,EAAE,CAEzD;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,WAAW,GAAG,aAAa,CAS7D"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { InstallError } from '../errors.js';
|
|
2
|
+
import { stubAdapter } from './adapters/stub.js';
|
|
3
|
+
import { hermesAdapter } from './adapters/hermes.js';
|
|
4
|
+
import { codexAdapter } from './adapters/codex.js';
|
|
5
|
+
import { deepseekAdapter } from './adapters/deepseek.js';
|
|
6
|
+
const ADAPTERS = Object.freeze([
|
|
7
|
+
stubAdapter,
|
|
8
|
+
hermesAdapter,
|
|
9
|
+
codexAdapter,
|
|
10
|
+
deepseekAdapter,
|
|
11
|
+
]);
|
|
12
|
+
/** List every registered adapter (for `--help` / discovery). */
|
|
13
|
+
export function listAdapters() {
|
|
14
|
+
return ADAPTERS;
|
|
15
|
+
}
|
|
16
|
+
/** The targets that have an install adapter (excludes zcode). */
|
|
17
|
+
export function supportedTargets() {
|
|
18
|
+
return ADAPTERS.map((a) => a.target);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Look up an adapter by target. Throws `TARGET_UNSUPPORTED` if none is
|
|
22
|
+
* registered (e.g. `zcode`).
|
|
23
|
+
*/
|
|
24
|
+
export function getAdapter(target) {
|
|
25
|
+
const adapter = ADAPTERS.find((a) => a.target === target);
|
|
26
|
+
if (!adapter) {
|
|
27
|
+
throw new InstallError(`No install adapter for target '${target}' (supported: ${supportedTargets().join(', ')})`, 'TARGET_UNSUPPORTED');
|
|
28
|
+
}
|
|
29
|
+
return adapter;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/install/registry.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEzD,MAAM,QAAQ,GAA6B,MAAM,CAAC,MAAM,CAAC;IACvD,WAAW;IACX,aAAa;IACb,YAAY;IACZ,eAAe;CAChB,CAAC,CAAC;AAEH,gEAAgE;AAChE,MAAM,UAAU,YAAY;IAC1B,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,iEAAiE;AACjE,MAAM,UAAU,gBAAgB;IAC9B,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;AACvC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,MAAmB;IAC5C,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;IAC1D,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,YAAY,CACpB,kCAAkC,MAAM,iBAAiB,gBAAgB,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EACzF,oBAAoB,CACrB,CAAC;IACJ,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
|