@phyzess/pappra 0.1.0-beta.2 → 0.1.0-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -7
- package/dist/app/doctor.js +2 -2
- package/dist/app/init.d.ts +28 -0
- package/dist/app/init.js +419 -88
- package/dist/cli/commands/docs.d.ts +1 -0
- package/dist/cli/commands/docs.js +104 -3
- package/dist/cli/commands/host.d.ts +3 -1
- package/dist/cli/commands/host.js +50 -2
- package/dist/cli/commands/init.d.ts +8 -0
- package/dist/cli/commands/init.js +186 -9
- package/dist/cli/commands/runtime.d.ts +14 -0
- package/dist/cli/commands/runtime.js +263 -0
- package/dist/cli/run.js +134 -7
- package/dist/hosts/detect.d.ts +1 -0
- package/dist/hosts/detect.js +1 -1
- package/dist/hosts/integration/bundle-export.d.ts +22 -0
- package/dist/hosts/integration/bundle-export.js +114 -0
- package/dist/hosts/integration/bundle.d.ts +4 -1
- package/dist/hosts/integration/bundle.js +20 -2
- package/dist/hosts/integration/pappra-extension-runtime.mjs +24605 -0
- package/dist/hosts/integration/pappra-hook.mjs +24723 -0
- package/dist/hosts/integration/service.d.ts +8 -0
- package/dist/hosts/integration/service.js +62 -30
- package/dist/hosts/integration/templates.d.ts +3 -3
- package/dist/hosts/integration/templates.js +15 -10
- package/dist/hosts/pilot.d.ts +77 -77
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/install/runtime.d.ts +1 -1
- package/dist/install/runtime.js +117 -10
- package/dist/package-info.d.ts +2 -0
- package/dist/package-info.js +6 -0
- package/dist/schemas/host.js +4 -2
- package/dist/schemas/install.d.ts +14 -0
- package/dist/schemas/install.js +8 -0
- package/package.json +8 -2
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
import { getPackageInfo, getPackageRoot } from '../../package-info.js';
|
|
3
|
+
import { inspectRuntimeState, inspectRuntimeStatePassive, installRuntime, removeRuntime, resolveUserDataDir, runtimePaths, } from '../../install/runtime.js';
|
|
4
|
+
import { updateMachineRuntime } from '../../install/apply.js';
|
|
5
|
+
import { inspectMachineConfig } from '../../workspace/config.js';
|
|
6
|
+
import { resolveWorkspaceRoot } from '../../workspace/resolve.js';
|
|
7
|
+
export const runtimeUsage = 'pappra runtime <install|status|verify|remove> [options] [--json]\n' +
|
|
8
|
+
' install [--from self|tarball|registry] [--tarball <file>] [--runtime-version <v>]\n' +
|
|
9
|
+
' [--apply] [--bind]\n' +
|
|
10
|
+
' status\n' +
|
|
11
|
+
' verify [--runtime-version <v>]\n' +
|
|
12
|
+
' remove [--runtime-version <v>] --apply [--force]\n\n' +
|
|
13
|
+
'Install keeps a durable copy of the package outside the checkout. --from self packs the\n' +
|
|
14
|
+
'package that is currently executing, which is what makes an npx/dlx bootstrap survive\n' +
|
|
15
|
+
'cache eviction. Writes require --apply; --bind records the copy in machine.json.\n';
|
|
16
|
+
async function inspectBinding(cwd) {
|
|
17
|
+
const resolution = await resolveWorkspaceRoot({ startPath: cwd });
|
|
18
|
+
if (resolution.root === null)
|
|
19
|
+
return null;
|
|
20
|
+
const machine = await inspectMachineConfig(resolution.root);
|
|
21
|
+
return {
|
|
22
|
+
root: resolution.root,
|
|
23
|
+
machinePath: machine.path,
|
|
24
|
+
runtime: machine.value?.runtime === null || machine.value?.runtime === undefined
|
|
25
|
+
? null
|
|
26
|
+
: {
|
|
27
|
+
version: machine.value.runtime.version,
|
|
28
|
+
executable: machine.value.runtime.executable,
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function printDiagnostics(output, diagnostics) {
|
|
33
|
+
for (const diagnostic of diagnostics) {
|
|
34
|
+
output.stderr(` ${diagnostic.severity} ${diagnostic.code}: ${diagnostic.message}\n`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function sourceFor(options) {
|
|
38
|
+
const from = options.from ?? (options.tarball === null ? 'self' : 'tarball');
|
|
39
|
+
if (from === 'self')
|
|
40
|
+
return { kind: 'self' };
|
|
41
|
+
if (from === 'tarball') {
|
|
42
|
+
if (options.tarball === null)
|
|
43
|
+
return null;
|
|
44
|
+
return { kind: 'tarball', path: resolve(options.cwd, options.tarball) };
|
|
45
|
+
}
|
|
46
|
+
return { kind: 'version' };
|
|
47
|
+
}
|
|
48
|
+
async function runInstall(options, output, binding) {
|
|
49
|
+
const packageInfo = getPackageInfo();
|
|
50
|
+
const version = options.version ?? packageInfo.version;
|
|
51
|
+
const source = sourceFor(options);
|
|
52
|
+
if (source === null) {
|
|
53
|
+
output.stderr('pappra runtime install: --from tarball requires --tarball.\n');
|
|
54
|
+
return 2;
|
|
55
|
+
}
|
|
56
|
+
const dataDir = resolveUserDataDir();
|
|
57
|
+
const paths = runtimePaths(version, dataDir);
|
|
58
|
+
if (!options.apply) {
|
|
59
|
+
if (options.json) {
|
|
60
|
+
output.stdout(`${JSON.stringify({
|
|
61
|
+
ok: true,
|
|
62
|
+
command: 'runtime',
|
|
63
|
+
action: 'install',
|
|
64
|
+
mode: 'plan',
|
|
65
|
+
version,
|
|
66
|
+
source: source.kind,
|
|
67
|
+
dataDir,
|
|
68
|
+
runtimeRoot: paths.runtimeRoot,
|
|
69
|
+
bind: options.bind,
|
|
70
|
+
workspaceRoot: binding?.root ?? null,
|
|
71
|
+
nextActions: ['Rerun with --apply to install this exact runtime.'],
|
|
72
|
+
})}\n`);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
output.stdout(`Runtime plan: ${packageInfo.name}@${version}\n`);
|
|
76
|
+
output.stdout(`Source: ${source.kind}\n`);
|
|
77
|
+
output.stdout(`Target: ${paths.runtimeRoot}\n`);
|
|
78
|
+
output.stdout('Plan only; rerun with --apply to install it.\n');
|
|
79
|
+
}
|
|
80
|
+
return 0;
|
|
81
|
+
}
|
|
82
|
+
const installed = await installRuntime({
|
|
83
|
+
version,
|
|
84
|
+
source: source.kind === 'tarball'
|
|
85
|
+
? { kind: 'tarball', path: source.path }
|
|
86
|
+
: source.kind === 'self'
|
|
87
|
+
? { kind: 'self', path: getPackageRoot() }
|
|
88
|
+
: { kind: 'version' },
|
|
89
|
+
packageName: packageInfo.name,
|
|
90
|
+
});
|
|
91
|
+
let bindingResult = null;
|
|
92
|
+
if (installed.ok && installed.manifest !== null && options.bind) {
|
|
93
|
+
if (binding === null) {
|
|
94
|
+
output.stderr('pappra runtime install: --bind requires a registered workspace root.\n');
|
|
95
|
+
return 1;
|
|
96
|
+
}
|
|
97
|
+
const updated = await updateMachineRuntime(binding.root, installed.manifest);
|
|
98
|
+
bindingResult = { ok: updated.ok, diagnostics: updated.diagnostics };
|
|
99
|
+
if (!updated.ok) {
|
|
100
|
+
if (options.json) {
|
|
101
|
+
output.stdout(`${JSON.stringify({
|
|
102
|
+
ok: false,
|
|
103
|
+
command: 'runtime',
|
|
104
|
+
action: 'install',
|
|
105
|
+
version,
|
|
106
|
+
runtime: installed,
|
|
107
|
+
bind: { ok: false, diagnostics: updated.diagnostics },
|
|
108
|
+
})}\n`);
|
|
109
|
+
}
|
|
110
|
+
printDiagnostics(output, updated.diagnostics);
|
|
111
|
+
return 1;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (options.json) {
|
|
115
|
+
output.stdout(`${JSON.stringify({
|
|
116
|
+
ok: installed.ok,
|
|
117
|
+
command: 'runtime',
|
|
118
|
+
action: 'install',
|
|
119
|
+
version,
|
|
120
|
+
source: source.kind,
|
|
121
|
+
runtime: installed,
|
|
122
|
+
bind: bindingResult,
|
|
123
|
+
diagnostics: installed.diagnostics,
|
|
124
|
+
})}\n`);
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
output.stdout(`Runtime: ${installed.status} ${version}\n`);
|
|
128
|
+
if (installed.runtimeRoot !== null) {
|
|
129
|
+
output.stdout(`Location: ${installed.runtimeRoot}\n`);
|
|
130
|
+
}
|
|
131
|
+
if (bindingResult?.ok === true) {
|
|
132
|
+
output.stdout('Machine binding updated.\n');
|
|
133
|
+
}
|
|
134
|
+
printDiagnostics(output, installed.diagnostics);
|
|
135
|
+
}
|
|
136
|
+
return installed.ok ? 0 : 1;
|
|
137
|
+
}
|
|
138
|
+
async function runStatus(options, output, binding) {
|
|
139
|
+
const packageInfo = getPackageInfo();
|
|
140
|
+
const version = options.version ?? binding?.runtime?.version ?? packageInfo.version;
|
|
141
|
+
const dataDir = resolveUserDataDir();
|
|
142
|
+
const state = await inspectRuntimeStatePassive(version, dataDir);
|
|
143
|
+
if (options.json) {
|
|
144
|
+
output.stdout(`${JSON.stringify({
|
|
145
|
+
ok: true,
|
|
146
|
+
command: 'runtime',
|
|
147
|
+
action: 'status',
|
|
148
|
+
version,
|
|
149
|
+
dataDir,
|
|
150
|
+
workspaceRoot: binding?.root ?? null,
|
|
151
|
+
machineRuntime: binding?.runtime ?? null,
|
|
152
|
+
runtime: {
|
|
153
|
+
status: state.status,
|
|
154
|
+
runtimeRoot: state.runtimeRoot,
|
|
155
|
+
packageDigestMatch: state.packageDigestMatch,
|
|
156
|
+
executableExists: state.executableExists,
|
|
157
|
+
verifiedAt: state.manifest?.verifiedAt ?? null,
|
|
158
|
+
source: state.manifest?.source.kind ?? null,
|
|
159
|
+
},
|
|
160
|
+
diagnostics: state.diagnostics,
|
|
161
|
+
})}\n`);
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
output.stdout(`Runtime ${version}: ${state.status}\n`);
|
|
165
|
+
output.stdout(`Location: ${state.runtimeRoot}\n`);
|
|
166
|
+
if (state.manifest !== null) {
|
|
167
|
+
output.stdout(`Verified at: ${state.manifest.verifiedAt}\n`);
|
|
168
|
+
}
|
|
169
|
+
output.stdout(`Bound in machine.json: ${binding?.runtime?.version === version ? 'yes' : 'no'}\n`);
|
|
170
|
+
printDiagnostics(output, state.diagnostics);
|
|
171
|
+
}
|
|
172
|
+
return 0;
|
|
173
|
+
}
|
|
174
|
+
async function runVerify(options, output, binding) {
|
|
175
|
+
const packageInfo = getPackageInfo();
|
|
176
|
+
const version = options.version ?? binding?.runtime?.version ?? packageInfo.version;
|
|
177
|
+
const state = await inspectRuntimeState(version, resolveUserDataDir());
|
|
178
|
+
const ok = state.status === 'complete';
|
|
179
|
+
if (options.json) {
|
|
180
|
+
output.stdout(`${JSON.stringify({
|
|
181
|
+
ok,
|
|
182
|
+
command: 'runtime',
|
|
183
|
+
action: 'verify',
|
|
184
|
+
version,
|
|
185
|
+
status: state.status,
|
|
186
|
+
runtimeRoot: state.runtimeRoot,
|
|
187
|
+
manifest: state.manifest,
|
|
188
|
+
diagnostics: state.diagnostics,
|
|
189
|
+
})}\n`);
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
output.stdout(`Runtime ${version}: ${state.status}\n`);
|
|
193
|
+
printDiagnostics(output, state.diagnostics);
|
|
194
|
+
}
|
|
195
|
+
return ok ? 0 : 1;
|
|
196
|
+
}
|
|
197
|
+
async function runRemove(options, output, binding) {
|
|
198
|
+
const version = options.version ?? binding?.runtime?.version ?? null;
|
|
199
|
+
if (version === null) {
|
|
200
|
+
output.stderr('pappra runtime remove: --version is required.\n');
|
|
201
|
+
return 2;
|
|
202
|
+
}
|
|
203
|
+
if (!options.apply) {
|
|
204
|
+
output.stderr('pappra runtime remove: rerun with --apply to remove it.\n');
|
|
205
|
+
return 2;
|
|
206
|
+
}
|
|
207
|
+
const boundHere = binding?.runtime?.version === version;
|
|
208
|
+
if (boundHere && !options.force) {
|
|
209
|
+
const message = 'machine.json still binds this runtime; pass --force to remove it anyway.';
|
|
210
|
+
if (options.json) {
|
|
211
|
+
output.stdout(`${JSON.stringify({
|
|
212
|
+
ok: false,
|
|
213
|
+
command: 'runtime',
|
|
214
|
+
action: 'remove',
|
|
215
|
+
version,
|
|
216
|
+
message,
|
|
217
|
+
})}\n`);
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
output.stderr(`pappra runtime remove: ${message}\n`);
|
|
221
|
+
}
|
|
222
|
+
return 1;
|
|
223
|
+
}
|
|
224
|
+
const removed = await removeRuntime({
|
|
225
|
+
version,
|
|
226
|
+
dataDir: resolveUserDataDir(),
|
|
227
|
+
// The current workspace was already checked above; callers that need to
|
|
228
|
+
// protect other checkouts pass --force only after checking them.
|
|
229
|
+
activeReferences: [],
|
|
230
|
+
});
|
|
231
|
+
if (options.json) {
|
|
232
|
+
output.stdout(`${JSON.stringify({
|
|
233
|
+
ok: removed.ok,
|
|
234
|
+
command: 'runtime',
|
|
235
|
+
action: 'remove',
|
|
236
|
+
version,
|
|
237
|
+
removed,
|
|
238
|
+
machineBindingRetained: boundHere,
|
|
239
|
+
})}\n`);
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
output.stdout(`Runtime ${version}: ${removed.status}\n`);
|
|
243
|
+
printDiagnostics(output, removed.diagnostics);
|
|
244
|
+
}
|
|
245
|
+
return removed.ok ? 0 : 1;
|
|
246
|
+
}
|
|
247
|
+
export async function runRuntimeCommand(options, output) {
|
|
248
|
+
if (options.action === null) {
|
|
249
|
+
output.stderr(`${runtimeUsage}`);
|
|
250
|
+
return 2;
|
|
251
|
+
}
|
|
252
|
+
const binding = await inspectBinding(options.cwd);
|
|
253
|
+
switch (options.action) {
|
|
254
|
+
case 'install':
|
|
255
|
+
return runInstall(options, output, binding);
|
|
256
|
+
case 'status':
|
|
257
|
+
return runStatus(options, output, binding);
|
|
258
|
+
case 'verify':
|
|
259
|
+
return runVerify(options, output, binding);
|
|
260
|
+
case 'remove':
|
|
261
|
+
return runRemove(options, output, binding);
|
|
262
|
+
}
|
|
263
|
+
}
|
package/dist/cli/run.js
CHANGED
|
@@ -7,6 +7,7 @@ import { checkpointUsage, resumeUsage, runCheckpointCommand, runResumeCommand, }
|
|
|
7
7
|
import { codeUsage, runCodeCommand } from './commands/code.js';
|
|
8
8
|
import { collaborationUsage, runCollaborationCommand, } from './commands/collaboration.js';
|
|
9
9
|
import { hostUsage, runHostCommand } from './commands/host.js';
|
|
10
|
+
import { runtimeUsage, runRuntimeCommand } from './commands/runtime.js';
|
|
10
11
|
import { hostNameSchema } from '../schemas/host.js';
|
|
11
12
|
function parseOptions(args) {
|
|
12
13
|
const { values, positionals } = parseArgs({
|
|
@@ -17,6 +18,17 @@ function parseOptions(args) {
|
|
|
17
18
|
json: { type: 'boolean' },
|
|
18
19
|
config: { type: 'string' },
|
|
19
20
|
apply: { type: 'boolean' },
|
|
21
|
+
yes: { type: 'boolean', short: 'y' },
|
|
22
|
+
'no-runtime': { type: 'boolean' },
|
|
23
|
+
reconfigure: { type: 'boolean' },
|
|
24
|
+
from: { type: 'string' },
|
|
25
|
+
tarball: { type: 'string' },
|
|
26
|
+
out: { type: 'string' },
|
|
27
|
+
mode: { type: 'string' },
|
|
28
|
+
bind: { type: 'boolean' },
|
|
29
|
+
force: { type: 'boolean' },
|
|
30
|
+
'no-interactive': { type: 'boolean' },
|
|
31
|
+
'print-choices': { type: 'boolean' },
|
|
20
32
|
'install-runtime': { type: 'boolean' },
|
|
21
33
|
'runtime-tarball': { type: 'string' },
|
|
22
34
|
'runtime-version': { type: 'string' },
|
|
@@ -73,6 +85,7 @@ function parseOptions(args) {
|
|
|
73
85
|
hostAction: null,
|
|
74
86
|
collaborationAction: null,
|
|
75
87
|
resumeTaskId: null,
|
|
88
|
+
runtimeAction: null,
|
|
76
89
|
};
|
|
77
90
|
}
|
|
78
91
|
if (command === 'resume') {
|
|
@@ -88,6 +101,7 @@ function parseOptions(args) {
|
|
|
88
101
|
hostAction: null,
|
|
89
102
|
collaborationAction: null,
|
|
90
103
|
resumeTaskId: positionals[1] ?? null,
|
|
104
|
+
runtimeAction: null,
|
|
91
105
|
};
|
|
92
106
|
}
|
|
93
107
|
if (command === 'code') {
|
|
@@ -103,6 +117,7 @@ function parseOptions(args) {
|
|
|
103
117
|
hostAction: null,
|
|
104
118
|
collaborationAction: null,
|
|
105
119
|
resumeTaskId: null,
|
|
120
|
+
runtimeAction: null,
|
|
106
121
|
};
|
|
107
122
|
}
|
|
108
123
|
if (command === 'host') {
|
|
@@ -118,6 +133,23 @@ function parseOptions(args) {
|
|
|
118
133
|
hostAction: positionals[1] ?? null,
|
|
119
134
|
collaborationAction: null,
|
|
120
135
|
resumeTaskId: null,
|
|
136
|
+
runtimeAction: null,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
if (command === 'runtime') {
|
|
140
|
+
if (positionals.length > 2) {
|
|
141
|
+
throw new Error('runtime accepts one action: install, status, verify, or remove.');
|
|
142
|
+
}
|
|
143
|
+
return {
|
|
144
|
+
values,
|
|
145
|
+
command,
|
|
146
|
+
docsAction: null,
|
|
147
|
+
docsArgument: null,
|
|
148
|
+
codeAction: null,
|
|
149
|
+
hostAction: null,
|
|
150
|
+
collaborationAction: null,
|
|
151
|
+
resumeTaskId: null,
|
|
152
|
+
runtimeAction: positionals[1] ?? null,
|
|
121
153
|
};
|
|
122
154
|
}
|
|
123
155
|
if (command === 'collab') {
|
|
@@ -133,6 +165,7 @@ function parseOptions(args) {
|
|
|
133
165
|
hostAction: null,
|
|
134
166
|
collaborationAction: positionals[1] ?? null,
|
|
135
167
|
resumeTaskId: null,
|
|
168
|
+
runtimeAction: null,
|
|
136
169
|
};
|
|
137
170
|
}
|
|
138
171
|
if (positionals.length > 1) {
|
|
@@ -147,10 +180,15 @@ function parseOptions(args) {
|
|
|
147
180
|
hostAction: null,
|
|
148
181
|
collaborationAction: null,
|
|
149
182
|
resumeTaskId: null,
|
|
183
|
+
runtimeAction: null,
|
|
150
184
|
};
|
|
151
185
|
}
|
|
152
186
|
function failure(output, json, code, error) {
|
|
153
|
-
const message =
|
|
187
|
+
const message = typeof error === 'string'
|
|
188
|
+
? error
|
|
189
|
+
: error instanceof Error
|
|
190
|
+
? error.message
|
|
191
|
+
: 'Operation failed.';
|
|
154
192
|
if (json) {
|
|
155
193
|
output.stdout(`${JSON.stringify({ ok: false, code, message })}\n`);
|
|
156
194
|
}
|
|
@@ -176,7 +214,7 @@ function hasContinuityOptions(values, includeSession = true) {
|
|
|
176
214
|
(includeSession && values.session !== undefined));
|
|
177
215
|
}
|
|
178
216
|
const globalUsage = 'pappra [--help | --version] [--json]\n' +
|
|
179
|
-
'pappra init [--config <file>] [--apply] [--json]\n' +
|
|
217
|
+
'pappra init [--config <file> | --yes] [--apply] [--json] [--print-choices]\n' +
|
|
180
218
|
' [--install-runtime (--runtime-tarball <file> | --runtime-version <version>)]\n' +
|
|
181
219
|
'pappra doctor [--root <path>] [--json]\n' +
|
|
182
220
|
'pappra docs <list|check|archive> [options]\n' +
|
|
@@ -184,6 +222,7 @@ const globalUsage = 'pappra [--help | --version] [--json]\n' +
|
|
|
184
222
|
'pappra resume <taskId> [--session <id>] [--json]\n' +
|
|
185
223
|
'pappra code <status|prepare|query> --repo <id> [options] [--json]\n' +
|
|
186
224
|
'pappra host <detect|describe|plan|install|verify> --host <name> [options] [--json]\n' +
|
|
225
|
+
'pappra runtime <install|status|verify|remove> [options] [--json]\n' +
|
|
187
226
|
'pappra collab <prepare|run|query> [options]';
|
|
188
227
|
export async function runCli(args, output) {
|
|
189
228
|
const jsonRequested = args.includes('--json');
|
|
@@ -195,8 +234,42 @@ export async function runCli(args, output) {
|
|
|
195
234
|
failure(output, jsonRequested, 'invalid_arguments', error);
|
|
196
235
|
return 2;
|
|
197
236
|
}
|
|
198
|
-
const { values, command, docsAction, docsArgument, codeAction, hostAction, collaborationAction, resumeTaskId, } = parsed;
|
|
237
|
+
const { values, command, docsAction, docsArgument, codeAction, hostAction, collaborationAction, resumeTaskId, runtimeAction, } = parsed;
|
|
199
238
|
const json = values.json === true;
|
|
239
|
+
const applyRequested = values.apply === true;
|
|
240
|
+
if (command !== 'init' &&
|
|
241
|
+
(values.yes === true ||
|
|
242
|
+
values['no-interactive'] === true ||
|
|
243
|
+
values['print-choices'] === true ||
|
|
244
|
+
values['no-runtime'] === true ||
|
|
245
|
+
values.reconfigure === true)) {
|
|
246
|
+
failure(output, json, 'invalid_arguments', '--yes, --no-interactive, --print-choices, --no-runtime and --reconfigure are only valid for init.');
|
|
247
|
+
return 2;
|
|
248
|
+
}
|
|
249
|
+
if (command !== 'host' && values.out !== undefined) {
|
|
250
|
+
failure(output, json, 'invalid_arguments', '--out is only valid for host.');
|
|
251
|
+
return 2;
|
|
252
|
+
}
|
|
253
|
+
if (command !== 'host' &&
|
|
254
|
+
values.mode !== undefined &&
|
|
255
|
+
command !== 'runtime') {
|
|
256
|
+
failure(output, json, 'invalid_arguments', '--mode is only valid for host.');
|
|
257
|
+
return 2;
|
|
258
|
+
}
|
|
259
|
+
if (values.mode !== undefined &&
|
|
260
|
+
values.mode !== 'project-settings' &&
|
|
261
|
+
values.mode !== 'plugin') {
|
|
262
|
+
failure(output, json, 'invalid_arguments', '--mode accepts project-settings or plugin.');
|
|
263
|
+
return 2;
|
|
264
|
+
}
|
|
265
|
+
if (command !== 'runtime' &&
|
|
266
|
+
(values.from !== undefined ||
|
|
267
|
+
values.tarball !== undefined ||
|
|
268
|
+
values.bind === true ||
|
|
269
|
+
values.force === true)) {
|
|
270
|
+
failure(output, json, 'invalid_arguments', '--from, --tarball, --bind and --force are only valid for runtime.');
|
|
271
|
+
return 2;
|
|
272
|
+
}
|
|
200
273
|
let info;
|
|
201
274
|
try {
|
|
202
275
|
info = getPackageInfo();
|
|
@@ -231,7 +304,6 @@ export async function runCli(args, output) {
|
|
|
231
304
|
if (action === null ||
|
|
232
305
|
values.version ||
|
|
233
306
|
values.config !== undefined ||
|
|
234
|
-
values.apply === true ||
|
|
235
307
|
values['install-runtime'] === true ||
|
|
236
308
|
values['runtime-tarball'] !== undefined ||
|
|
237
309
|
values['runtime-version'] !== undefined ||
|
|
@@ -256,13 +328,12 @@ export async function runCli(args, output) {
|
|
|
256
328
|
if (command === 'docs') {
|
|
257
329
|
if (values.version ||
|
|
258
330
|
values.config !== undefined ||
|
|
259
|
-
values.apply === true ||
|
|
260
331
|
values['install-runtime'] === true ||
|
|
261
332
|
values['runtime-tarball'] !== undefined ||
|
|
262
333
|
values['runtime-version'] !== undefined ||
|
|
263
334
|
values.root !== undefined ||
|
|
264
335
|
hasContinuityOptions(values)) {
|
|
265
|
-
failure(output, json, 'invalid_arguments', 'docs only accepts list/check/archive, --include-private, --include-archived, --help, and --json.');
|
|
336
|
+
failure(output, json, 'invalid_arguments', 'docs only accepts list/check/archive/scan, --include-private, --include-archived, --apply (scan only), --help, and --json.');
|
|
266
337
|
return 2;
|
|
267
338
|
}
|
|
268
339
|
if (values.help) {
|
|
@@ -281,6 +352,7 @@ export async function runCli(args, output) {
|
|
|
281
352
|
json,
|
|
282
353
|
includePrivate: values['include-private'] === true,
|
|
283
354
|
includeArchived: values['include-archived'] === true,
|
|
355
|
+
apply: applyRequested,
|
|
284
356
|
}, output);
|
|
285
357
|
}
|
|
286
358
|
if (command === 'doctor') {
|
|
@@ -339,6 +411,55 @@ export async function runCli(args, output) {
|
|
|
339
411
|
installRuntime: values['install-runtime'] === true,
|
|
340
412
|
runtimeTarball: values['runtime-tarball'] ?? null,
|
|
341
413
|
runtimeVersion: values['runtime-version'] ?? null,
|
|
414
|
+
yes: values.yes === true || values['no-interactive'] === true,
|
|
415
|
+
printChoices: values['print-choices'] === true,
|
|
416
|
+
noRuntime: values['no-runtime'] === true,
|
|
417
|
+
reconfigure: values.reconfigure === true,
|
|
418
|
+
}, output);
|
|
419
|
+
}
|
|
420
|
+
if (command === 'runtime') {
|
|
421
|
+
if (values.help) {
|
|
422
|
+
if (json) {
|
|
423
|
+
output.stdout(`${JSON.stringify({ ...info, commands: ['runtime'], usage: runtimeUsage })}\n`);
|
|
424
|
+
}
|
|
425
|
+
else {
|
|
426
|
+
output.stdout(runtimeUsage);
|
|
427
|
+
}
|
|
428
|
+
return 0;
|
|
429
|
+
}
|
|
430
|
+
if (values.version ||
|
|
431
|
+
values.config !== undefined ||
|
|
432
|
+
values['install-runtime'] === true ||
|
|
433
|
+
values['runtime-tarball'] !== undefined ||
|
|
434
|
+
values.root !== undefined ||
|
|
435
|
+
values.host !== undefined ||
|
|
436
|
+
values.repo !== undefined ||
|
|
437
|
+
values.query !== undefined ||
|
|
438
|
+
values.kind !== undefined ||
|
|
439
|
+
hasContinuityOptions(values)) {
|
|
440
|
+
failure(output, json, 'invalid_arguments', 'runtime accepts only --from, --tarball, --version, --apply, --bind, --force, --help, and --json.');
|
|
441
|
+
return 2;
|
|
442
|
+
}
|
|
443
|
+
const action = runtimeAction === 'install' ||
|
|
444
|
+
runtimeAction === 'status' ||
|
|
445
|
+
runtimeAction === 'verify' ||
|
|
446
|
+
runtimeAction === 'remove'
|
|
447
|
+
? runtimeAction
|
|
448
|
+
: null;
|
|
449
|
+
return runRuntimeCommand({
|
|
450
|
+
cwd: process.cwd(),
|
|
451
|
+
action,
|
|
452
|
+
json,
|
|
453
|
+
from: values.from === 'self' ||
|
|
454
|
+
values.from === 'tarball' ||
|
|
455
|
+
values.from === 'registry'
|
|
456
|
+
? values.from
|
|
457
|
+
: null,
|
|
458
|
+
tarball: values.tarball ?? null,
|
|
459
|
+
version: values['runtime-version'] ?? null,
|
|
460
|
+
apply: values.apply === true,
|
|
461
|
+
bind: values.bind === true,
|
|
462
|
+
force: values.force === true,
|
|
342
463
|
}, output);
|
|
343
464
|
}
|
|
344
465
|
if (command === 'checkpoint') {
|
|
@@ -516,6 +637,7 @@ export async function runCli(args, output) {
|
|
|
516
637
|
'plan',
|
|
517
638
|
'install',
|
|
518
639
|
'verify',
|
|
640
|
+
'bundle',
|
|
519
641
|
];
|
|
520
642
|
const action = allowedActions.find((item) => item === hostAction) ?? null;
|
|
521
643
|
const parsedHost = hostNameSchema.safeParse(values.host);
|
|
@@ -536,6 +658,7 @@ export async function runCli(args, output) {
|
|
|
536
658
|
values.rebuild === true ||
|
|
537
659
|
hasContinuityOptions(values) ||
|
|
538
660
|
(values.apply === true && action !== 'install') ||
|
|
661
|
+
(values.mode !== undefined && action !== 'install') ||
|
|
539
662
|
(values['host-root'] !== undefined && action === null) ||
|
|
540
663
|
(values['host-version'] !== undefined && action === null);
|
|
541
664
|
if (values.help) {
|
|
@@ -548,7 +671,7 @@ export async function runCli(args, output) {
|
|
|
548
671
|
return 0;
|
|
549
672
|
}
|
|
550
673
|
if (action === null || host === null || invalid) {
|
|
551
|
-
failure(output, json, 'invalid_arguments', 'host requires detect/describe/plan/install/verify, --host, and action-compatible options.');
|
|
674
|
+
failure(output, json, 'invalid_arguments', 'host requires detect/describe/plan/install/verify/bundle, --host, and action-compatible options.');
|
|
552
675
|
return 2;
|
|
553
676
|
}
|
|
554
677
|
return runHostCommand({
|
|
@@ -559,6 +682,10 @@ export async function runCli(args, output) {
|
|
|
559
682
|
hostRoot: values['host-root'] ?? null,
|
|
560
683
|
hostVersion: values['host-version'] ?? null,
|
|
561
684
|
apply: values.apply === true,
|
|
685
|
+
out: values.out ?? null,
|
|
686
|
+
mode: values.mode === 'project-settings' || values.mode === 'plugin'
|
|
687
|
+
? values.mode
|
|
688
|
+
: null,
|
|
562
689
|
}, output);
|
|
563
690
|
}
|
|
564
691
|
if (command !== null) {
|
package/dist/hosts/detect.d.ts
CHANGED
|
@@ -23,6 +23,7 @@ export interface HostDetectionOptions {
|
|
|
23
23
|
readonly selectedHosts: readonly string[];
|
|
24
24
|
readonly observedAt?: string;
|
|
25
25
|
}
|
|
26
|
+
export declare function executableOnPath(command: string, pathEnv: string): string | null;
|
|
26
27
|
export declare function detectPassiveTool(command: string, pathEnv: string): PassiveToolObservation;
|
|
27
28
|
/** Passive host discovery. It never starts a host or reads config contents. */
|
|
28
29
|
export declare function detectPassiveHosts(options: HostDetectionOptions): readonly PassiveHostObservation[];
|
package/dist/hosts/detect.js
CHANGED
|
@@ -9,7 +9,7 @@ function evidence(path, observedAt) {
|
|
|
9
9
|
scope: 'live-owned',
|
|
10
10
|
};
|
|
11
11
|
}
|
|
12
|
-
function executableOnPath(command, pathEnv) {
|
|
12
|
+
export function executableOnPath(command, pathEnv) {
|
|
13
13
|
for (const directory of pathEnv.split(delimiter)) {
|
|
14
14
|
if (directory === '')
|
|
15
15
|
continue;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { HostName } from '../../schemas/host.js';
|
|
2
|
+
export interface HostPluginBundle {
|
|
3
|
+
readonly host: HostName;
|
|
4
|
+
readonly outDir: string;
|
|
5
|
+
readonly files: readonly string[];
|
|
6
|
+
readonly pluginManifest: string;
|
|
7
|
+
readonly hookConfig: string | null;
|
|
8
|
+
readonly registration: readonly string[];
|
|
9
|
+
/** Plugin registration and native callability are not verified here. */
|
|
10
|
+
readonly verification: 'unsupported';
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Writes a host-native plugin/package directory. This is an artifact export: it
|
|
14
|
+
* does not register the plugin with a host, and it never claims the host will
|
|
15
|
+
* load or trust it.
|
|
16
|
+
*/
|
|
17
|
+
export declare function exportHostPluginBundle(options: {
|
|
18
|
+
readonly host: HostName;
|
|
19
|
+
readonly hostVersion: string;
|
|
20
|
+
readonly outDir: string;
|
|
21
|
+
readonly packageVersion: string;
|
|
22
|
+
}): Promise<HostPluginBundle>;
|