@phyzess/pappra 0.1.0-beta.1 → 0.1.0-beta.10
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 +30 -11
- package/assets/integrations/skills/pappra/SKILL.md +7 -4
- package/assets/integrations/skills/pappra/references/hosts.md +21 -11
- package/assets/integrations/skills/pappra/references/lifecycle.md +4 -0
- package/assets/integrations/skills/pappra/references/operations.md +20 -7
- package/dist/app/collaboration.js +6 -13
- 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 +5 -1
- package/dist/cli/commands/host.js +80 -6
- 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 +159 -7
- package/dist/hosts/detect.d.ts +1 -0
- package/dist/hosts/detect.js +1 -1
- package/dist/hosts/integration/bundle-export.d.ts +24 -0
- package/dist/hosts/integration/bundle-export.js +128 -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 +24610 -0
- package/dist/hosts/integration/pappra-hook.mjs +24728 -0
- package/dist/hosts/integration/service.d.ts +8 -0
- package/dist/hosts/integration/service.js +71 -31
- package/dist/hosts/integration/support.d.ts +23 -0
- package/dist/hosts/integration/support.js +25 -0
- package/dist/hosts/integration/templates.d.ts +3 -3
- package/dist/hosts/integration/templates.js +15 -10
- package/dist/hosts/pi/rpc.d.ts +2 -0
- package/dist/hosts/pi/rpc.js +39 -1
- 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
- package/skills/pappra/SKILL.md +7 -4
- package/skills/pappra/references/hosts.md +21 -11
- package/skills/pappra/references/lifecycle.md +4 -0
- package/skills/pappra/references/operations.md +20 -7
|
@@ -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,19 @@ 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
|
+
marketplace: { type: 'boolean' },
|
|
29
|
+
scope: { type: 'string' },
|
|
30
|
+
bind: { type: 'boolean' },
|
|
31
|
+
force: { type: 'boolean' },
|
|
32
|
+
'no-interactive': { type: 'boolean' },
|
|
33
|
+
'print-choices': { type: 'boolean' },
|
|
20
34
|
'install-runtime': { type: 'boolean' },
|
|
21
35
|
'runtime-tarball': { type: 'string' },
|
|
22
36
|
'runtime-version': { type: 'string' },
|
|
@@ -73,6 +87,7 @@ function parseOptions(args) {
|
|
|
73
87
|
hostAction: null,
|
|
74
88
|
collaborationAction: null,
|
|
75
89
|
resumeTaskId: null,
|
|
90
|
+
runtimeAction: null,
|
|
76
91
|
};
|
|
77
92
|
}
|
|
78
93
|
if (command === 'resume') {
|
|
@@ -88,6 +103,7 @@ function parseOptions(args) {
|
|
|
88
103
|
hostAction: null,
|
|
89
104
|
collaborationAction: null,
|
|
90
105
|
resumeTaskId: positionals[1] ?? null,
|
|
106
|
+
runtimeAction: null,
|
|
91
107
|
};
|
|
92
108
|
}
|
|
93
109
|
if (command === 'code') {
|
|
@@ -103,6 +119,7 @@ function parseOptions(args) {
|
|
|
103
119
|
hostAction: null,
|
|
104
120
|
collaborationAction: null,
|
|
105
121
|
resumeTaskId: null,
|
|
122
|
+
runtimeAction: null,
|
|
106
123
|
};
|
|
107
124
|
}
|
|
108
125
|
if (command === 'host') {
|
|
@@ -118,6 +135,23 @@ function parseOptions(args) {
|
|
|
118
135
|
hostAction: positionals[1] ?? null,
|
|
119
136
|
collaborationAction: null,
|
|
120
137
|
resumeTaskId: null,
|
|
138
|
+
runtimeAction: null,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
if (command === 'runtime') {
|
|
142
|
+
if (positionals.length > 2) {
|
|
143
|
+
throw new Error('runtime accepts one action: install, status, verify, or remove.');
|
|
144
|
+
}
|
|
145
|
+
return {
|
|
146
|
+
values,
|
|
147
|
+
command,
|
|
148
|
+
docsAction: null,
|
|
149
|
+
docsArgument: null,
|
|
150
|
+
codeAction: null,
|
|
151
|
+
hostAction: null,
|
|
152
|
+
collaborationAction: null,
|
|
153
|
+
resumeTaskId: null,
|
|
154
|
+
runtimeAction: positionals[1] ?? null,
|
|
121
155
|
};
|
|
122
156
|
}
|
|
123
157
|
if (command === 'collab') {
|
|
@@ -133,6 +167,7 @@ function parseOptions(args) {
|
|
|
133
167
|
hostAction: null,
|
|
134
168
|
collaborationAction: positionals[1] ?? null,
|
|
135
169
|
resumeTaskId: null,
|
|
170
|
+
runtimeAction: null,
|
|
136
171
|
};
|
|
137
172
|
}
|
|
138
173
|
if (positionals.length > 1) {
|
|
@@ -147,10 +182,15 @@ function parseOptions(args) {
|
|
|
147
182
|
hostAction: null,
|
|
148
183
|
collaborationAction: null,
|
|
149
184
|
resumeTaskId: null,
|
|
185
|
+
runtimeAction: null,
|
|
150
186
|
};
|
|
151
187
|
}
|
|
152
188
|
function failure(output, json, code, error) {
|
|
153
|
-
const message =
|
|
189
|
+
const message = typeof error === 'string'
|
|
190
|
+
? error
|
|
191
|
+
: error instanceof Error
|
|
192
|
+
? error.message
|
|
193
|
+
: 'Operation failed.';
|
|
154
194
|
if (json) {
|
|
155
195
|
output.stdout(`${JSON.stringify({ ok: false, code, message })}\n`);
|
|
156
196
|
}
|
|
@@ -176,7 +216,7 @@ function hasContinuityOptions(values, includeSession = true) {
|
|
|
176
216
|
(includeSession && values.session !== undefined));
|
|
177
217
|
}
|
|
178
218
|
const globalUsage = 'pappra [--help | --version] [--json]\n' +
|
|
179
|
-
'pappra init [--config <file>] [--apply] [--json]\n' +
|
|
219
|
+
'pappra init [--config <file> | --yes] [--apply] [--json] [--print-choices]\n' +
|
|
180
220
|
' [--install-runtime (--runtime-tarball <file> | --runtime-version <version>)]\n' +
|
|
181
221
|
'pappra doctor [--root <path>] [--json]\n' +
|
|
182
222
|
'pappra docs <list|check|archive> [options]\n' +
|
|
@@ -184,6 +224,7 @@ const globalUsage = 'pappra [--help | --version] [--json]\n' +
|
|
|
184
224
|
'pappra resume <taskId> [--session <id>] [--json]\n' +
|
|
185
225
|
'pappra code <status|prepare|query> --repo <id> [options] [--json]\n' +
|
|
186
226
|
'pappra host <detect|describe|plan|install|verify> --host <name> [options] [--json]\n' +
|
|
227
|
+
'pappra runtime <install|status|verify|remove> [options] [--json]\n' +
|
|
187
228
|
'pappra collab <prepare|run|query> [options]';
|
|
188
229
|
export async function runCli(args, output) {
|
|
189
230
|
const jsonRequested = args.includes('--json');
|
|
@@ -195,8 +236,56 @@ export async function runCli(args, output) {
|
|
|
195
236
|
failure(output, jsonRequested, 'invalid_arguments', error);
|
|
196
237
|
return 2;
|
|
197
238
|
}
|
|
198
|
-
const { values, command, docsAction, docsArgument, codeAction, hostAction, collaborationAction, resumeTaskId, } = parsed;
|
|
239
|
+
const { values, command, docsAction, docsArgument, codeAction, hostAction, collaborationAction, resumeTaskId, runtimeAction, } = parsed;
|
|
199
240
|
const json = values.json === true;
|
|
241
|
+
const applyRequested = values.apply === true;
|
|
242
|
+
if (command !== 'init' &&
|
|
243
|
+
(values.yes === true ||
|
|
244
|
+
values['no-interactive'] === true ||
|
|
245
|
+
values['print-choices'] === true ||
|
|
246
|
+
values['no-runtime'] === true ||
|
|
247
|
+
values.reconfigure === true)) {
|
|
248
|
+
failure(output, json, 'invalid_arguments', '--yes, --no-interactive, --print-choices, --no-runtime and --reconfigure are only valid for init.');
|
|
249
|
+
return 2;
|
|
250
|
+
}
|
|
251
|
+
if (command !== 'host' && values.out !== undefined) {
|
|
252
|
+
failure(output, json, 'invalid_arguments', '--out is only valid for host.');
|
|
253
|
+
return 2;
|
|
254
|
+
}
|
|
255
|
+
if (values.scope !== undefined &&
|
|
256
|
+
values.scope !== 'project' &&
|
|
257
|
+
values.scope !== 'user') {
|
|
258
|
+
failure(output, json, 'invalid_arguments', '--scope accepts project or user.');
|
|
259
|
+
return 2;
|
|
260
|
+
}
|
|
261
|
+
if (command !== 'host' && values.scope !== undefined) {
|
|
262
|
+
failure(output, json, 'invalid_arguments', '--scope is only valid for host.');
|
|
263
|
+
return 2;
|
|
264
|
+
}
|
|
265
|
+
if (command !== 'host' && values.marketplace === true) {
|
|
266
|
+
failure(output, json, 'invalid_arguments', '--marketplace is only valid for host bundle.');
|
|
267
|
+
return 2;
|
|
268
|
+
}
|
|
269
|
+
if (command !== 'host' &&
|
|
270
|
+
values.mode !== undefined &&
|
|
271
|
+
command !== 'runtime') {
|
|
272
|
+
failure(output, json, 'invalid_arguments', '--mode is only valid for host.');
|
|
273
|
+
return 2;
|
|
274
|
+
}
|
|
275
|
+
if (values.mode !== undefined &&
|
|
276
|
+
values.mode !== 'project-settings' &&
|
|
277
|
+
values.mode !== 'plugin') {
|
|
278
|
+
failure(output, json, 'invalid_arguments', '--mode accepts project-settings or plugin.');
|
|
279
|
+
return 2;
|
|
280
|
+
}
|
|
281
|
+
if (command !== 'runtime' &&
|
|
282
|
+
(values.from !== undefined ||
|
|
283
|
+
values.tarball !== undefined ||
|
|
284
|
+
values.bind === true ||
|
|
285
|
+
values.force === true)) {
|
|
286
|
+
failure(output, json, 'invalid_arguments', '--from, --tarball, --bind and --force are only valid for runtime.');
|
|
287
|
+
return 2;
|
|
288
|
+
}
|
|
200
289
|
let info;
|
|
201
290
|
try {
|
|
202
291
|
info = getPackageInfo();
|
|
@@ -231,7 +320,6 @@ export async function runCli(args, output) {
|
|
|
231
320
|
if (action === null ||
|
|
232
321
|
values.version ||
|
|
233
322
|
values.config !== undefined ||
|
|
234
|
-
values.apply === true ||
|
|
235
323
|
values['install-runtime'] === true ||
|
|
236
324
|
values['runtime-tarball'] !== undefined ||
|
|
237
325
|
values['runtime-version'] !== undefined ||
|
|
@@ -256,13 +344,12 @@ export async function runCli(args, output) {
|
|
|
256
344
|
if (command === 'docs') {
|
|
257
345
|
if (values.version ||
|
|
258
346
|
values.config !== undefined ||
|
|
259
|
-
values.apply === true ||
|
|
260
347
|
values['install-runtime'] === true ||
|
|
261
348
|
values['runtime-tarball'] !== undefined ||
|
|
262
349
|
values['runtime-version'] !== undefined ||
|
|
263
350
|
values.root !== undefined ||
|
|
264
351
|
hasContinuityOptions(values)) {
|
|
265
|
-
failure(output, json, 'invalid_arguments', 'docs only accepts list/check/archive, --include-private, --include-archived, --help, and --json.');
|
|
352
|
+
failure(output, json, 'invalid_arguments', 'docs only accepts list/check/archive/scan, --include-private, --include-archived, --apply (scan only), --help, and --json.');
|
|
266
353
|
return 2;
|
|
267
354
|
}
|
|
268
355
|
if (values.help) {
|
|
@@ -281,6 +368,7 @@ export async function runCli(args, output) {
|
|
|
281
368
|
json,
|
|
282
369
|
includePrivate: values['include-private'] === true,
|
|
283
370
|
includeArchived: values['include-archived'] === true,
|
|
371
|
+
apply: applyRequested,
|
|
284
372
|
}, output);
|
|
285
373
|
}
|
|
286
374
|
if (command === 'doctor') {
|
|
@@ -339,6 +427,55 @@ export async function runCli(args, output) {
|
|
|
339
427
|
installRuntime: values['install-runtime'] === true,
|
|
340
428
|
runtimeTarball: values['runtime-tarball'] ?? null,
|
|
341
429
|
runtimeVersion: values['runtime-version'] ?? null,
|
|
430
|
+
yes: values.yes === true || values['no-interactive'] === true,
|
|
431
|
+
printChoices: values['print-choices'] === true,
|
|
432
|
+
noRuntime: values['no-runtime'] === true,
|
|
433
|
+
reconfigure: values.reconfigure === true,
|
|
434
|
+
}, output);
|
|
435
|
+
}
|
|
436
|
+
if (command === 'runtime') {
|
|
437
|
+
if (values.help) {
|
|
438
|
+
if (json) {
|
|
439
|
+
output.stdout(`${JSON.stringify({ ...info, commands: ['runtime'], usage: runtimeUsage })}\n`);
|
|
440
|
+
}
|
|
441
|
+
else {
|
|
442
|
+
output.stdout(runtimeUsage);
|
|
443
|
+
}
|
|
444
|
+
return 0;
|
|
445
|
+
}
|
|
446
|
+
if (values.version ||
|
|
447
|
+
values.config !== undefined ||
|
|
448
|
+
values['install-runtime'] === true ||
|
|
449
|
+
values['runtime-tarball'] !== undefined ||
|
|
450
|
+
values.root !== undefined ||
|
|
451
|
+
values.host !== undefined ||
|
|
452
|
+
values.repo !== undefined ||
|
|
453
|
+
values.query !== undefined ||
|
|
454
|
+
values.kind !== undefined ||
|
|
455
|
+
hasContinuityOptions(values)) {
|
|
456
|
+
failure(output, json, 'invalid_arguments', 'runtime accepts only --from, --tarball, --version, --apply, --bind, --force, --help, and --json.');
|
|
457
|
+
return 2;
|
|
458
|
+
}
|
|
459
|
+
const action = runtimeAction === 'install' ||
|
|
460
|
+
runtimeAction === 'status' ||
|
|
461
|
+
runtimeAction === 'verify' ||
|
|
462
|
+
runtimeAction === 'remove'
|
|
463
|
+
? runtimeAction
|
|
464
|
+
: null;
|
|
465
|
+
return runRuntimeCommand({
|
|
466
|
+
cwd: process.cwd(),
|
|
467
|
+
action,
|
|
468
|
+
json,
|
|
469
|
+
from: values.from === 'self' ||
|
|
470
|
+
values.from === 'tarball' ||
|
|
471
|
+
values.from === 'registry'
|
|
472
|
+
? values.from
|
|
473
|
+
: null,
|
|
474
|
+
tarball: values.tarball ?? null,
|
|
475
|
+
version: values['runtime-version'] ?? null,
|
|
476
|
+
apply: values.apply === true,
|
|
477
|
+
bind: values.bind === true,
|
|
478
|
+
force: values.force === true,
|
|
342
479
|
}, output);
|
|
343
480
|
}
|
|
344
481
|
if (command === 'checkpoint') {
|
|
@@ -516,6 +653,7 @@ export async function runCli(args, output) {
|
|
|
516
653
|
'plan',
|
|
517
654
|
'install',
|
|
518
655
|
'verify',
|
|
656
|
+
'bundle',
|
|
519
657
|
];
|
|
520
658
|
const action = allowedActions.find((item) => item === hostAction) ?? null;
|
|
521
659
|
const parsedHost = hostNameSchema.safeParse(values.host);
|
|
@@ -536,6 +674,12 @@ export async function runCli(args, output) {
|
|
|
536
674
|
values.rebuild === true ||
|
|
537
675
|
hasContinuityOptions(values) ||
|
|
538
676
|
(values.apply === true && action !== 'install') ||
|
|
677
|
+
(values.mode !== undefined && action !== 'install') ||
|
|
678
|
+
(values.marketplace === true && action !== 'bundle') ||
|
|
679
|
+
(values.scope !== undefined &&
|
|
680
|
+
action !== 'plan' &&
|
|
681
|
+
action !== 'install' &&
|
|
682
|
+
action !== 'verify') ||
|
|
539
683
|
(values['host-root'] !== undefined && action === null) ||
|
|
540
684
|
(values['host-version'] !== undefined && action === null);
|
|
541
685
|
if (values.help) {
|
|
@@ -548,7 +692,7 @@ export async function runCli(args, output) {
|
|
|
548
692
|
return 0;
|
|
549
693
|
}
|
|
550
694
|
if (action === null || host === null || invalid) {
|
|
551
|
-
failure(output, json, 'invalid_arguments', 'host requires detect/describe/plan/install/verify, --host, and action-compatible options.');
|
|
695
|
+
failure(output, json, 'invalid_arguments', 'host requires detect/describe/plan/install/verify/bundle, --host, and action-compatible options.');
|
|
552
696
|
return 2;
|
|
553
697
|
}
|
|
554
698
|
return runHostCommand({
|
|
@@ -559,6 +703,14 @@ export async function runCli(args, output) {
|
|
|
559
703
|
hostRoot: values['host-root'] ?? null,
|
|
560
704
|
hostVersion: values['host-version'] ?? null,
|
|
561
705
|
apply: values.apply === true,
|
|
706
|
+
out: values.out ?? null,
|
|
707
|
+
mode: values.mode === 'project-settings' || values.mode === 'plugin'
|
|
708
|
+
? values.mode
|
|
709
|
+
: null,
|
|
710
|
+
marketplace: values.marketplace === true,
|
|
711
|
+
scope: values.scope === 'project' || values.scope === 'user'
|
|
712
|
+
? values.scope
|
|
713
|
+
: null,
|
|
562
714
|
}, output);
|
|
563
715
|
}
|
|
564
716
|
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,24 @@
|
|
|
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
|
+
/** Writes a marketplace root with the plugin under `pappra/`. */
|
|
23
|
+
readonly marketplace?: boolean;
|
|
24
|
+
}): Promise<HostPluginBundle>;
|