@kvman/kvbuilder 0.2.0
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 +9 -0
- package/dist/api.d.ts +271 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +2 -0
- package/dist/api.js.map +1 -0
- package/dist/app/install-source.d.ts +3 -0
- package/dist/app/install-source.d.ts.map +1 -0
- package/dist/app/install-source.js +11 -0
- package/dist/app/install-source.js.map +1 -0
- package/dist/app/register-app-reads.d.ts +3 -0
- package/dist/app/register-app-reads.d.ts.map +1 -0
- package/dist/app/register-app-reads.js +36 -0
- package/dist/app/register-app-reads.js.map +1 -0
- package/dist/app/register-app.d.ts +3 -0
- package/dist/app/register-app.d.ts.map +1 -0
- package/dist/app/register-app.js +124 -0
- package/dist/app/register-app.js.map +1 -0
- package/dist/build/register-build.d.ts +3 -0
- package/dist/build/register-build.d.ts.map +1 -0
- package/dist/build/register-build.js +34 -0
- package/dist/build/register-build.js.map +1 -0
- package/dist/connectors/docs.d.ts +30 -0
- package/dist/connectors/docs.d.ts.map +1 -0
- package/dist/connectors/docs.js +18 -0
- package/dist/connectors/docs.js.map +1 -0
- package/dist/connectors/ext.d.ts +40 -0
- package/dist/connectors/ext.d.ts.map +1 -0
- package/dist/connectors/ext.js +13 -0
- package/dist/connectors/ext.js.map +1 -0
- package/dist/connectors/kvman.d.ts +113 -0
- package/dist/connectors/kvman.d.ts.map +1 -0
- package/dist/connectors/kvman.js +41 -0
- package/dist/connectors/kvman.js.map +1 -0
- package/dist/connectors/preset.d.ts +26 -0
- package/dist/connectors/preset.d.ts.map +1 -0
- package/dist/connectors/preset.js +11 -0
- package/dist/connectors/preset.js.map +1 -0
- package/dist/connectors/preview.d.ts +41 -0
- package/dist/connectors/preview.d.ts.map +1 -0
- package/dist/connectors/preview.js +14 -0
- package/dist/connectors/preview.js.map +1 -0
- package/dist/docs/guides.d.ts +54 -0
- package/dist/docs/guides.d.ts.map +1 -0
- package/dist/docs/guides.js +68 -0
- package/dist/docs/guides.js.map +1 -0
- package/dist/docs/own-docs.d.ts +5 -0
- package/dist/docs/own-docs.d.ts.map +1 -0
- package/dist/docs/own-docs.js +36 -0
- package/dist/docs/own-docs.js.map +1 -0
- package/dist/docs/pages.d.ts +18 -0
- package/dist/docs/pages.d.ts.map +1 -0
- package/dist/docs/pages.js +44 -0
- package/dist/docs/pages.js.map +1 -0
- package/dist/docs/register-docs.d.ts +3 -0
- package/dist/docs/register-docs.d.ts.map +1 -0
- package/dist/docs/register-docs.js +25 -0
- package/dist/docs/register-docs.js.map +1 -0
- package/dist/ext/ext-check.d.ts +8 -0
- package/dist/ext/ext-check.d.ts.map +1 -0
- package/dist/ext/ext-check.js +26 -0
- package/dist/ext/ext-check.js.map +1 -0
- package/dist/ext/ext-list.d.ts +8 -0
- package/dist/ext/ext-list.d.ts.map +1 -0
- package/dist/ext/ext-list.js +20 -0
- package/dist/ext/ext-list.js.map +1 -0
- package/dist/ext/ext-new.d.ts +15 -0
- package/dist/ext/ext-new.d.ts.map +1 -0
- package/dist/ext/ext-new.js +11 -0
- package/dist/ext/ext-new.js.map +1 -0
- package/dist/ext/findings.d.ts +12 -0
- package/dist/ext/findings.d.ts.map +1 -0
- package/dist/ext/findings.js +44 -0
- package/dist/ext/findings.js.map +1 -0
- package/dist/ext/register-ext.d.ts +3 -0
- package/dist/ext/register-ext.d.ts.map +1 -0
- package/dist/ext/register-ext.js +49 -0
- package/dist/ext/register-ext.js.map +1 -0
- package/dist/folders.d.ts +18 -0
- package/dist/folders.d.ts.map +1 -0
- package/dist/folders.js +53 -0
- package/dist/folders.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/job-options.d.ts +33 -0
- package/dist/job-options.d.ts.map +1 -0
- package/dist/job-options.js +13 -0
- package/dist/job-options.js.map +1 -0
- package/dist/preset/register-preset.d.ts +3 -0
- package/dist/preset/register-preset.d.ts.map +1 -0
- package/dist/preset/register-preset.js +55 -0
- package/dist/preset/register-preset.js.map +1 -0
- package/dist/preview/preview-call.d.ts +20 -0
- package/dist/preview/preview-call.d.ts.map +1 -0
- package/dist/preview/preview-call.js +39 -0
- package/dist/preview/preview-call.js.map +1 -0
- package/dist/preview/preview-start.d.ts +8 -0
- package/dist/preview/preview-start.d.ts.map +1 -0
- package/dist/preview/preview-start.js +103 -0
- package/dist/preview/preview-start.js.map +1 -0
- package/dist/preview/preview-state.d.ts +11 -0
- package/dist/preview/preview-state.d.ts.map +1 -0
- package/dist/preview/preview-state.js +18 -0
- package/dist/preview/preview-state.js.map +1 -0
- package/dist/preview/register-preview.d.ts +3 -0
- package/dist/preview/register-preview.d.ts.map +1 -0
- package/dist/preview/register-preview.js +75 -0
- package/dist/preview/register-preview.js.map +1 -0
- package/dist/problems.d.ts +8 -0
- package/dist/problems.d.ts.map +1 -0
- package/dist/problems.js +11 -0
- package/dist/problems.js.map +1 -0
- package/dist/program-command.d.ts +17 -0
- package/dist/program-command.d.ts.map +1 -0
- package/dist/program-command.js +12 -0
- package/dist/program-command.js.map +1 -0
- package/dist/query/register-app-query.d.ts +3 -0
- package/dist/query/register-app-query.d.ts.map +1 -0
- package/dist/query/register-app-query.js +39 -0
- package/dist/query/register-app-query.js.map +1 -0
- package/dist/register-with-kvcoder.d.ts +3 -0
- package/dist/register-with-kvcoder.d.ts.map +1 -0
- package/dist/register-with-kvcoder.js +20 -0
- package/dist/register-with-kvcoder.js.map +1 -0
- package/dist/run-bin.d.ts +31 -0
- package/dist/run-bin.d.ts.map +1 -0
- package/dist/run-bin.js +137 -0
- package/dist/run-bin.js.map +1 -0
- package/dist/run-program.d.ts +12 -0
- package/dist/run-program.d.ts.map +1 -0
- package/dist/run-program.js +49 -0
- package/dist/run-program.js.map +1 -0
- package/docs/building.md +154 -0
- package/docs/guide.md +34 -0
- package/locales/ar.json +12 -0
- package/locales/en.json +12 -0
- package/package.json +55 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview-call.js","sourceRoot":"","sources":["../../src/preview/preview-call.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview-start.d.ts","sourceRoot":"","sources":["../../src/preview/preview-start.ts"],"names":[],"mappings":"AACA,OAAO,EAAmB,KAAK,GAAG,EAAE,MAAM,YAAY,CAAC;AAsEvD,wBAAsB,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE;IAAE,UAAU,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,GAAG,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,CAwBnI"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { setTimeout as delay } from 'node:timers/promises';
|
|
2
|
+
import { ProblemError, z } from '@kvman/sdk';
|
|
3
|
+
import { insideWorkspace, projectAt } from "../folders.js";
|
|
4
|
+
import { kvbuilderProblem } from "../problems.js";
|
|
5
|
+
import { binFailureProblem, binFailureSchema, binFile } from "../run-bin.js";
|
|
6
|
+
import { lastLines } from "../run-program.js";
|
|
7
|
+
import { cleanUpPreview, recordKey } from "./preview-state.js";
|
|
8
|
+
// `preview start` (plan 09 §9.3, ADR 0010, 21): `kvman-preview` runs through the process service in the workspace
|
|
9
|
+
// folder, so its folders and preset stay as given; the call answers once the ready line `{ url }` shows in the
|
|
10
|
+
// process log. When the bin exits first, its failure line becomes its Problem.
|
|
11
|
+
const pollEveryMs = 200;
|
|
12
|
+
const readySchema = z.object({ url: z.string() });
|
|
13
|
+
function readyUrl(log) {
|
|
14
|
+
for (const line of log.split('\n')) {
|
|
15
|
+
let parsed;
|
|
16
|
+
try {
|
|
17
|
+
parsed = JSON.parse(line);
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
const ready = readySchema.safeParse(parsed);
|
|
23
|
+
if (ready.success)
|
|
24
|
+
return ready.data.url;
|
|
25
|
+
}
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
// The bin's failure: the last JSON failure line becomes its Problem; with none, `kvbuilder/PREVIEW_FAILED` with
|
|
29
|
+
// the last lines.
|
|
30
|
+
function previewFailure(log) {
|
|
31
|
+
const lines = log.split('\n');
|
|
32
|
+
for (let index = lines.length - 1; index >= 0; index -= 1) {
|
|
33
|
+
const line = lines[index];
|
|
34
|
+
if (line === undefined || line.trim() === '')
|
|
35
|
+
continue;
|
|
36
|
+
let parsed;
|
|
37
|
+
try {
|
|
38
|
+
parsed = JSON.parse(line);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
const failure = binFailureSchema.safeParse(parsed);
|
|
44
|
+
if (!failure.success)
|
|
45
|
+
continue;
|
|
46
|
+
const problem = binFailureProblem(failure.data);
|
|
47
|
+
if (problem !== undefined)
|
|
48
|
+
return problem;
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
return kvbuilderProblem('PREVIEW_FAILED', `The preview exited before it was ready:\n${lastLines(log)}`);
|
|
52
|
+
}
|
|
53
|
+
async function waitForReady(ctx) {
|
|
54
|
+
while (true) {
|
|
55
|
+
if (!(await ctx.processes.list()).some((process) => process.name === 'preview')) {
|
|
56
|
+
throw previewFailure(await ctx.processes.log('preview', { tail: 20 }));
|
|
57
|
+
}
|
|
58
|
+
const ready = readyUrl(await ctx.processes.log('preview', { tail: 20 }));
|
|
59
|
+
if (ready !== undefined)
|
|
60
|
+
return ready;
|
|
61
|
+
await delay(pollEveryMs, undefined, { signal: ctx.job.signal });
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
async function stopIfRunning(ctx) {
|
|
65
|
+
try {
|
|
66
|
+
await ctx.processes.stop('preview');
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
if (!(error instanceof ProblemError && error.problem.code === 'NOT_FOUND'))
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
export async function startPreview(ctx, input) {
|
|
74
|
+
const workspaceFolder = ctx.job.workspace.path;
|
|
75
|
+
for (const folder of input.extensions)
|
|
76
|
+
projectAt(workspaceFolder, folder);
|
|
77
|
+
if (input.preset !== undefined)
|
|
78
|
+
insideWorkspace(workspaceFolder, input.preset, 'preset');
|
|
79
|
+
const entry = process.argv[1];
|
|
80
|
+
if (entry === undefined)
|
|
81
|
+
throw kvbuilderProblem('PREVIEW_FAILED', "kvman's entry file isn't known in this process.");
|
|
82
|
+
if ((await ctx.processes.list()).some((process) => process.name === 'preview')) {
|
|
83
|
+
throw new ProblemError({ code: 'PROCESS_RUNNING', message: 'A preview already runs in this workspace; run preview stop first.', params: { name: 'preview' } });
|
|
84
|
+
}
|
|
85
|
+
await ctx.processes.start('preview', {
|
|
86
|
+
command: process.execPath,
|
|
87
|
+
args: [...process.execArgv, binFile('kvman-preview'), ...input.extensions, '--kvman', entry, '--name', ctx.job.workspace.id, '--json', ...(input.preset === undefined ? [] : ['--preset', input.preset])],
|
|
88
|
+
cwd: workspaceFolder,
|
|
89
|
+
});
|
|
90
|
+
try {
|
|
91
|
+
const url = await waitForReady(ctx);
|
|
92
|
+
const record = { url, extensions: input.extensions };
|
|
93
|
+
await ctx.store.kv.set(recordKey, record);
|
|
94
|
+
return { url };
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
if ((await ctx.processes.list()).some((process) => process.name === 'preview'))
|
|
98
|
+
await stopIfRunning(ctx);
|
|
99
|
+
await cleanUpPreview(ctx);
|
|
100
|
+
throw error;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=preview-start.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview-start.js","sourceRoot":"","sources":["../../src/preview/preview-start.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { z, type Ctx } from '@kvman/sdk';
|
|
2
|
+
export declare const previewRecordSchema: z.ZodObject<{
|
|
3
|
+
url: z.ZodString;
|
|
4
|
+
extensions: z.ZodArray<z.ZodString>;
|
|
5
|
+
}, z.core.$strip>;
|
|
6
|
+
export type PreviewRecord = z.infer<typeof previewRecordSchema>;
|
|
7
|
+
export declare const recordKey = "preview";
|
|
8
|
+
export declare function previewHome(workspaceId: string): string;
|
|
9
|
+
/** Removes the preview's home and forgets its record. */
|
|
10
|
+
export declare function cleanUpPreview(ctx: Ctx): Promise<void>;
|
|
11
|
+
//# sourceMappingURL=preview-state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview-state.d.ts","sourceRoot":"","sources":["../../src/preview/preview-state.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,KAAK,GAAG,EAAE,MAAM,YAAY,CAAC;AAMzC,eAAO,MAAM,mBAAmB;;;iBAAiE,CAAC;AAElG,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,eAAO,MAAM,SAAS,YAAY,CAAC;AAEnC,wBAAgB,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED,yDAAyD;AACzD,wBAAsB,cAAc,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAG5D"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { rmSync } from 'node:fs';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { z } from '@kvman/sdk';
|
|
5
|
+
// The preview's record in the workspace store, its home folder, and its cleanup (plan 09 §9.3, ADR 0010, 21). The
|
|
6
|
+
// bin owns the preview kvman and its `web:watch` children; kvbuilder only removes the home the bin left behind
|
|
7
|
+
// (a Windows tree-kill skips the bin's own cleanup) and forgets the record.
|
|
8
|
+
export const previewRecordSchema = z.object({ url: z.string(), extensions: z.array(z.string()) });
|
|
9
|
+
export const recordKey = 'preview';
|
|
10
|
+
export function previewHome(workspaceId) {
|
|
11
|
+
return path.join(tmpdir(), `kvman-preview-${workspaceId}`);
|
|
12
|
+
}
|
|
13
|
+
/** Removes the preview's home and forgets its record. */
|
|
14
|
+
export async function cleanUpPreview(ctx) {
|
|
15
|
+
rmSync(previewHome(ctx.job.workspace.id), { recursive: true, force: true });
|
|
16
|
+
await ctx.store.kv.delete(recordKey);
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=preview-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview-state.js","sourceRoot":"","sources":["../../src/preview/preview-state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,CAAC,EAAY,MAAM,YAAY,CAAC;AAEzC,kHAAkH;AAClH,+GAA+G;AAC/G,4EAA4E;AAE5E,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;AAIlG,MAAM,CAAC,MAAM,SAAS,GAAG,SAAS,CAAC;AAEnC,MAAM,UAAU,WAAW,CAAC,WAAmB;IAC7C,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,iBAAiB,WAAW,EAAE,CAAC,CAAC;AAC7D,CAAC;AAED,yDAAyD;AACzD,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,GAAQ;IAC3C,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5E,MAAM,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;AACvC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register-preview.d.ts","sourceRoot":"","sources":["../../src/preview/register-preview.ts"],"names":[],"mappings":"AAAA,OAAO,EAAK,KAAK,GAAG,EAAE,MAAM,YAAY,CAAC;AAkBzC,wBAAgB,eAAe,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI,CA0D9C"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { z } from '@kvman/sdk';
|
|
2
|
+
import { jobOptions } from "../job-options.js";
|
|
3
|
+
import { callPreview, previewAnswerSchema } from "./preview-call.js";
|
|
4
|
+
import { startPreview } from "./preview-start.js";
|
|
5
|
+
import { cleanUpPreview, previewRecordSchema, recordKey } from "./preview-state.js";
|
|
6
|
+
// The `preview` connector's commands (plan 09 §9.3): the preview itself, calls of its commands and queries (ADR 0022, 8),
|
|
7
|
+
// and the cleanup when the preview exits by itself.
|
|
8
|
+
const callSchema = z.object({
|
|
9
|
+
name: z.string().min(1).describe('The full name of a public command or query of the preview, such as notes.item.list.'),
|
|
10
|
+
input: z.record(z.string(), z.json()).optional().describe('Its input; {} when left out.'),
|
|
11
|
+
});
|
|
12
|
+
const queryTimeoutMs = 120_000;
|
|
13
|
+
const statusSchema = z.union([z.object({ running: z.literal(false) }), z.object({ running: z.literal(true), url: z.string(), extensions: z.array(z.string()), startedAt: z.string() })]);
|
|
14
|
+
export function registerPreview(ctx) {
|
|
15
|
+
ctx.registerCommand('kvbuilder.preview.start', {
|
|
16
|
+
description: 'Starts a preview kvman with extension projects of the workspace, and gives its URL.',
|
|
17
|
+
public: true,
|
|
18
|
+
...jobOptions['kvbuilder.preview.start'],
|
|
19
|
+
input: z.object({
|
|
20
|
+
extensions: z.array(z.string().min(1)).min(1).describe('The project folders, relative to the workspace folder.'),
|
|
21
|
+
preset: z.string().min(1).optional().describe('A preset file to add the projects to, relative to the workspace folder.'),
|
|
22
|
+
}),
|
|
23
|
+
output: z.object({ url: z.string() }),
|
|
24
|
+
handle: (input) => startPreview(ctx, input),
|
|
25
|
+
});
|
|
26
|
+
ctx.registerCommand('kvbuilder.preview.stop', {
|
|
27
|
+
description: 'Stops the preview kvman and its component watchers.',
|
|
28
|
+
public: true,
|
|
29
|
+
...jobOptions['kvbuilder.preview.stop'],
|
|
30
|
+
input: z.object({}),
|
|
31
|
+
output: z.object({}),
|
|
32
|
+
handle: async () => {
|
|
33
|
+
await ctx.processes.stop('preview');
|
|
34
|
+
await cleanUpPreview(ctx);
|
|
35
|
+
return {};
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
ctx.registerQuery('kvbuilder.preview.status', {
|
|
39
|
+
description: 'Tells whether the preview kvman runs, and its URL.',
|
|
40
|
+
public: true,
|
|
41
|
+
input: z.object({}),
|
|
42
|
+
output: statusSchema,
|
|
43
|
+
handle: async () => {
|
|
44
|
+
const preview = (await ctx.processes.list()).find((process) => process.name === 'preview');
|
|
45
|
+
const record = previewRecordSchema.safeParse(await ctx.store.kv.get(recordKey));
|
|
46
|
+
if (preview === undefined || !record.success)
|
|
47
|
+
return { running: false };
|
|
48
|
+
return { running: true, url: record.data.url, extensions: record.data.extensions, startedAt: preview.startedAt };
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
ctx.registerQuery('kvbuilder.preview.query.get', {
|
|
52
|
+
description: 'Runs one public query of the preview kvman and gives what it answered: its output, or its Problem.',
|
|
53
|
+
public: true,
|
|
54
|
+
timeoutMs: queryTimeoutMs,
|
|
55
|
+
input: callSchema,
|
|
56
|
+
output: previewAnswerSchema,
|
|
57
|
+
handle: ({ name, input }) => callPreview(ctx, 'queries', name, input ?? {}),
|
|
58
|
+
});
|
|
59
|
+
ctx.registerCommand('kvbuilder.preview.command.run', {
|
|
60
|
+
description: 'Runs one public command of the preview kvman and gives what it answered: its output, or its Problem.',
|
|
61
|
+
public: true,
|
|
62
|
+
...jobOptions['kvbuilder.preview.command.run'],
|
|
63
|
+
input: callSchema,
|
|
64
|
+
output: previewAnswerSchema,
|
|
65
|
+
handle: ({ name, input }) => callPreview(ctx, 'commands', name, input ?? {}),
|
|
66
|
+
});
|
|
67
|
+
ctx.registerHandler('kernel.process.exited', {
|
|
68
|
+
description: 'Stops the component watchers and removes the home of a preview that exited by itself.',
|
|
69
|
+
handle: async (exited) => {
|
|
70
|
+
if (exited.extension === '@kvman/kvbuilder' && exited.name === 'preview')
|
|
71
|
+
await cleanUpPreview(ctx);
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=register-preview.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register-preview.js","sourceRoot":"","sources":["../../src/preview/register-preview.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ProblemError, type Json } from '@kvman/sdk';
|
|
2
|
+
export type KvbuilderCode = 'FOLDER_NOT_EMPTY' | 'FILE_EXISTS' | 'NOT_A_PROJECT' | 'NPM_FAILED' | 'NO_FREE_PORT' | 'PREVIEW_FAILED';
|
|
3
|
+
export declare const kvbuilderCodes: readonly KvbuilderCode[];
|
|
4
|
+
/** A `kvbuilder/<code>` Problem to throw. */
|
|
5
|
+
export declare function kvbuilderProblem(code: KvbuilderCode, message: string, params?: Record<string, Json>): ProblemError;
|
|
6
|
+
/** A `VALIDATION_FAILED` Problem to throw. */
|
|
7
|
+
export declare function invalid(message: string, params?: Record<string, Json>): ProblemError;
|
|
8
|
+
//# sourceMappingURL=problems.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"problems.d.ts","sourceRoot":"","sources":["../src/problems.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,KAAK,IAAI,EAAE,MAAM,YAAY,CAAC;AAIrD,MAAM,MAAM,aAAa,GAAG,kBAAkB,GAAG,aAAa,GAAG,eAAe,GAAG,YAAY,GAAG,cAAc,GAAG,gBAAgB,CAAC;AAEpI,eAAO,MAAM,cAAc,EAAE,SAAS,aAAa,EAAyG,CAAC;AAE7J,6CAA6C;AAC7C,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAM,GAAG,YAAY,CAEtH;AAED,8CAA8C;AAC9C,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAM,GAAG,YAAY,CAExF"}
|
package/dist/problems.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ProblemError } from '@kvman/sdk';
|
|
2
|
+
export const kvbuilderCodes = ['FOLDER_NOT_EMPTY', 'FILE_EXISTS', 'NOT_A_PROJECT', 'NPM_FAILED', 'NO_FREE_PORT', 'PREVIEW_FAILED'];
|
|
3
|
+
/** A `kvbuilder/<code>` Problem to throw. */
|
|
4
|
+
export function kvbuilderProblem(code, message, params = {}) {
|
|
5
|
+
return new ProblemError({ code: `kvbuilder/${code}`, message, params });
|
|
6
|
+
}
|
|
7
|
+
/** A `VALIDATION_FAILED` Problem to throw. */
|
|
8
|
+
export function invalid(message, params = {}) {
|
|
9
|
+
return new ProblemError({ code: 'VALIDATION_FAILED', message, params });
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=problems.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"problems.js","sourceRoot":"","sources":["../src/problems.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAa,MAAM,YAAY,CAAC;AAMrD,MAAM,CAAC,MAAM,cAAc,GAA6B,CAAC,kBAAkB,EAAE,aAAa,EAAE,eAAe,EAAE,YAAY,EAAE,cAAc,EAAE,gBAAgB,CAAC,CAAC;AAE7J,6CAA6C;AAC7C,MAAM,UAAU,gBAAgB,CAAC,IAAmB,EAAE,OAAe,EAAE,SAA+B,EAAE;IACtG,OAAO,IAAI,YAAY,CAAC,EAAE,IAAI,EAAE,aAAa,IAAI,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;AAC1E,CAAC;AAED,8CAA8C;AAC9C,MAAM,UAAU,OAAO,CAAC,OAAe,EAAE,SAA+B,EAAE;IACxE,OAAO,IAAI,YAAY,CAAC,EAAE,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;AAC1E,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export type Program = 'npm' | 'npx';
|
|
2
|
+
export type ProgramCommand = {
|
|
3
|
+
command: string;
|
|
4
|
+
args: string[];
|
|
5
|
+
detached: boolean;
|
|
6
|
+
};
|
|
7
|
+
export type TreeKill = {
|
|
8
|
+
kind: 'group';
|
|
9
|
+
pid: number;
|
|
10
|
+
} | {
|
|
11
|
+
kind: 'taskkill';
|
|
12
|
+
command: 'taskkill';
|
|
13
|
+
args: string[];
|
|
14
|
+
};
|
|
15
|
+
export declare function programCommand(platform: NodeJS.Platform, program: Program, args: readonly string[]): ProgramCommand;
|
|
16
|
+
export declare function treeKill(platform: NodeJS.Platform, pid: number): TreeKill;
|
|
17
|
+
//# sourceMappingURL=program-command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"program-command.d.ts","sourceRoot":"","sources":["../src/program-command.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,OAAO,GAAG,KAAK,GAAG,KAAK,CAAC;AAEpC,MAAM,MAAM,cAAc,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAAC;AAEpF,MAAM,MAAM,QAAQ,GAAG;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,OAAO,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAElH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,cAAc,CAGnH;AAED,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,QAAQ,CAEzE"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// How kvbuilder starts npm and npx, per OS (plan 02 §2.16, CLAUDE.md §3): directly on Linux and macOS, in its own process
|
|
2
|
+
// group so a cancel ends the whole tree; on Windows through `cmd.exe /d /s /c`, since `npm` there is a `.cmd` file,
|
|
3
|
+
// and a cancel runs `taskkill /T /F`.
|
|
4
|
+
export function programCommand(platform, program, args) {
|
|
5
|
+
if (platform === 'win32')
|
|
6
|
+
return { command: 'cmd.exe', args: ['/d', '/s', '/c', program, ...args], detached: false };
|
|
7
|
+
return { command: program, args: [...args], detached: true };
|
|
8
|
+
}
|
|
9
|
+
export function treeKill(platform, pid) {
|
|
10
|
+
return platform === 'win32' ? { kind: 'taskkill', command: 'taskkill', args: ['/PID', String(pid), '/T', '/F'] } : { kind: 'group', pid };
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=program-command.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"program-command.js","sourceRoot":"","sources":["../src/program-command.ts"],"names":[],"mappings":"AAAA,0HAA0H;AAC1H,oHAAoH;AACpH,sCAAsC;AAQtC,MAAM,UAAU,cAAc,CAAC,QAAyB,EAAE,OAAgB,EAAE,IAAuB;IACjG,IAAI,QAAQ,KAAK,OAAO;QAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;IACrH,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AAC/D,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,QAAyB,EAAE,GAAW;IAC7D,OAAO,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC;AAC5I,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register-app-query.d.ts","sourceRoot":"","sources":["../../src/query/register-app-query.ts"],"names":[],"mappings":"AAAA,OAAO,EAA6D,KAAK,GAAG,EAAE,MAAM,YAAY,CAAC;AAyBjG,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI,CAc/C"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { kernelCommandSchemas, kernelQuerySchemas, ProblemError, z } from '@kvman/sdk';
|
|
2
|
+
import { invalid } from "../problems.js";
|
|
3
|
+
// `kvman query-get` (plan 09 §9.1, ADR 0022, 8 and 13): runs one public query of the running app, so the agent can use
|
|
4
|
+
// what is installed. A command is refused: a command of the app is reached only through a connector that names it. A
|
|
5
|
+
// name under `kernel.secrets.` is refused too, so the connector never lists a secret's name (ADR 0010, 6).
|
|
6
|
+
const secretsPrefix = 'kernel.secrets.';
|
|
7
|
+
const registrationSchema = z.object({ name: z.string(), kind: z.enum(['command', 'query']), public: z.boolean() });
|
|
8
|
+
const notAQuery = (name) => invalid(`${name} is a command, and query-get runs queries only.`, { name });
|
|
9
|
+
const noSuchQuery = (name) => new ProblemError({ code: 'NOT_FOUND', message: `No public query is named ${name}; extensions-list names the queries of every extension.`, params: { name } });
|
|
10
|
+
// The kernel's own names aren't among the registrations, which list the run's extensions.
|
|
11
|
+
async function requirePublicQuery(ctx, name) {
|
|
12
|
+
if (name.startsWith(secretsPrefix))
|
|
13
|
+
throw invalid(`${name} isn't available here: this connector never reads or lists a secret.`, { name });
|
|
14
|
+
if (Object.hasOwn(kernelQuerySchemas, name))
|
|
15
|
+
return;
|
|
16
|
+
if (Object.hasOwn(kernelCommandSchemas, name))
|
|
17
|
+
throw notAQuery(name);
|
|
18
|
+
const registered = z.array(registrationSchema).parse(await ctx.exec('kernel.registrations.list', {})).find((row) => row.name === name);
|
|
19
|
+
if (registered === undefined || !registered.public)
|
|
20
|
+
throw noSuchQuery(name);
|
|
21
|
+
if (registered.kind === 'command')
|
|
22
|
+
throw notAQuery(name);
|
|
23
|
+
}
|
|
24
|
+
export function registerAppQuery(ctx) {
|
|
25
|
+
ctx.registerQuery('kvbuilder.app.query.get', {
|
|
26
|
+
description: 'Runs one public query of the running app, of the kernel or of any extension, and gives its output.',
|
|
27
|
+
public: true,
|
|
28
|
+
input: z.object({
|
|
29
|
+
name: z.string().min(1).describe('The full name of a public query, such as kernel.health.get.'),
|
|
30
|
+
input: z.record(z.string(), z.json()).optional().describe("The query's input; {} when left out."),
|
|
31
|
+
}),
|
|
32
|
+
output: z.json(),
|
|
33
|
+
handle: async ({ name, input }) => {
|
|
34
|
+
await requirePublicQuery(ctx, name);
|
|
35
|
+
return z.json().parse(await ctx.exec(name, input ?? {}));
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=register-app-query.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register-app-query.js","sourceRoot":"","sources":["../../src/query/register-app-query.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,YAAY,EAAE,CAAC,EAAY,MAAM,YAAY,CAAC;AACjG,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAEzC,uHAAuH;AACvH,qHAAqH;AACrH,2GAA2G;AAE3G,MAAM,aAAa,GAAG,iBAAiB,CAAC;AAExC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;AAEnH,MAAM,SAAS,GAAG,CAAC,IAAY,EAAgB,EAAE,CAAC,OAAO,CAAC,GAAG,IAAI,iDAAiD,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;AAE9H,MAAM,WAAW,GAAG,CAAC,IAAY,EAAgB,EAAE,CAAC,IAAI,YAAY,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,4BAA4B,IAAI,yDAAyD,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;AAElN,0FAA0F;AAC1F,KAAK,UAAU,kBAAkB,CAAC,GAAQ,EAAE,IAAY;IACtD,IAAI,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC;QAAE,MAAM,OAAO,CAAC,GAAG,IAAI,sEAAsE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3I,IAAI,MAAM,CAAC,MAAM,CAAC,kBAAkB,EAAE,IAAI,CAAC;QAAE,OAAO;IACpD,IAAI,MAAM,CAAC,MAAM,CAAC,oBAAoB,EAAE,IAAI,CAAC;QAAE,MAAM,SAAS,CAAC,IAAI,CAAC,CAAC;IACrE,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,2BAA2B,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IACvI,IAAI,UAAU,KAAK,SAAS,IAAI,CAAC,UAAU,CAAC,MAAM;QAAE,MAAM,WAAW,CAAC,IAAI,CAAC,CAAC;IAC5E,IAAI,UAAU,CAAC,IAAI,KAAK,SAAS;QAAE,MAAM,SAAS,CAAC,IAAI,CAAC,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,GAAQ;IACvC,GAAG,CAAC,aAAa,CAAC,yBAAyB,EAAE;QAC3C,WAAW,EAAE,oGAAoG;QACjH,MAAM,EAAE,IAAI;QACZ,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC;YACd,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,6DAA6D,CAAC;YAC/F,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,sCAAsC,CAAC;SAClG,CAAC;QACF,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE;QAChB,MAAM,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE;YAChC,MAAM,kBAAkB,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YACpC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC;QAC3D,CAAC;KACF,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register-with-kvcoder.d.ts","sourceRoot":"","sources":["../src/register-with-kvcoder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AAYtC,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI,CAUlD"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { docsConnector } from "./connectors/docs.js";
|
|
2
|
+
import { extConnector } from "./connectors/ext.js";
|
|
3
|
+
import { kvmanConnector } from "./connectors/kvman.js";
|
|
4
|
+
import { presetConnector } from "./connectors/preset.js";
|
|
5
|
+
import { previewConnector } from "./connectors/preview.js";
|
|
6
|
+
// kvbuilder extends kvcoder (plan 09, §9.1 and §9.4; ADR 0027, 14): at each start it registers its connectors, which
|
|
7
|
+
// are `optIn`, and its slash command `/build-kvman`, since kvcoder clears both at its own start. Each connector is in
|
|
8
|
+
// its own file.
|
|
9
|
+
export function registerWithKvcoder(ctx) {
|
|
10
|
+
ctx.registerHandler('kernel.started', {
|
|
11
|
+
description: "Registers kvbuilder's connectors and its slash command with kvcoder.",
|
|
12
|
+
handle: async () => {
|
|
13
|
+
await ctx.exec('kvcoder.connector.register', { connectors: [kvmanConnector, extConnector, presetConnector, previewConnector, docsConnector] });
|
|
14
|
+
await ctx.exec('kvcoder.slash.register', {
|
|
15
|
+
commands: [{ name: 'build-kvman', description: 'kvbuilder.slash.build-kvman', command: 'kvbuilder.build.start', message: 'kvbuilder.slash.build-kvman.message' }],
|
|
16
|
+
});
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=register-with-kvcoder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register-with-kvcoder.js","sourceRoot":"","sources":["../src/register-with-kvcoder.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAE3D,qHAAqH;AACrH,sHAAsH;AACtH,gBAAgB;AAEhB,MAAM,UAAU,mBAAmB,CAAC,GAAQ;IAC1C,GAAG,CAAC,eAAe,CAAC,gBAAgB,EAAE;QACpC,WAAW,EAAE,sEAAsE;QACnF,MAAM,EAAE,KAAK,IAAI,EAAE;YACjB,MAAM,GAAG,CAAC,IAAI,CAAC,4BAA4B,EAAE,EAAE,UAAU,EAAE,CAAC,cAAc,EAAE,YAAY,EAAE,eAAe,EAAE,gBAAgB,EAAE,aAAa,CAAC,EAAE,CAAC,CAAC;YAC/I,MAAM,GAAG,CAAC,IAAI,CAAC,wBAAwB,EAAE;gBACvC,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,WAAW,EAAE,6BAA6B,EAAE,OAAO,EAAE,uBAAuB,EAAE,OAAO,EAAE,qCAAqC,EAAE,CAAC;aAClK,CAAC,CAAC;QACL,CAAC;KACF,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { ProblemError, z, type Ctx, type Json } from '@kvman/sdk';
|
|
2
|
+
export type BinRun = {
|
|
3
|
+
exitCode: number;
|
|
4
|
+
stdout: string;
|
|
5
|
+
stderr: string;
|
|
6
|
+
};
|
|
7
|
+
/** A bin's `{ code, message, params? }` failure line, for validating a process log line. */
|
|
8
|
+
export declare const binFailureSchema: z.ZodObject<{
|
|
9
|
+
code: z.ZodString;
|
|
10
|
+
message: z.ZodString;
|
|
11
|
+
params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodType<Json, unknown, z.core.$ZodTypeInternals<Json, unknown>>>>;
|
|
12
|
+
}, z.core.$strip>;
|
|
13
|
+
/** A bin's structured failure: `{ code, message, params? }`. */
|
|
14
|
+
export type BinFailure = z.output<typeof binFailureSchema>;
|
|
15
|
+
/** The testkit's `docs/` folder, which holds the built-in guides. */
|
|
16
|
+
export declare function testkitDocsFolder(): string;
|
|
17
|
+
/** The file of a `@kvman/testkit` bin; a missing entry or file is an installation problem, not a Problem. */
|
|
18
|
+
export declare function binFile(name: string): string;
|
|
19
|
+
/** Runs a bin with the running Node in `cwd`, `--json` always on; stdout and stderr stay apart for the caller. */
|
|
20
|
+
export declare function runBin(name: string, args: readonly string[], cwd: string, signal: AbortSignal): Promise<BinRun>;
|
|
21
|
+
/** The last non-empty line of an output, or `undefined` when there is none. */
|
|
22
|
+
export declare function lastOutputLine(output: string): string | undefined;
|
|
23
|
+
/** The Problem for a bin's structured failure, or `undefined` when its code has no mapping here. */
|
|
24
|
+
export declare function binFailureProblem(failure: BinFailure): ProblemError | undefined;
|
|
25
|
+
/**
|
|
26
|
+
* The bin's output: exit 0 gives the last non-empty stdout line against `outputSchema`; exit 1 with the bin's
|
|
27
|
+
* `{ code, message, params? }` on stderr gives its Problem. Anything else fails `HANDLER_FAILED` in the kernel,
|
|
28
|
+
* after logging the bin and the exit code, never the output or the arguments.
|
|
29
|
+
*/
|
|
30
|
+
export declare function binResult<Output>(log: Ctx['log'], bin: string, run: BinRun, outputSchema: z.ZodType<Output>): Output;
|
|
31
|
+
//# sourceMappingURL=run-bin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-bin.d.ts","sourceRoot":"","sources":["../src/run-bin.ts"],"names":[],"mappings":"AAIA,OAAO,EAAc,YAAY,EAAE,CAAC,EAAE,KAAK,GAAG,EAAE,KAAK,IAAI,EAAE,MAAM,YAAY,CAAC;AAO9E,MAAM,MAAM,MAAM,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAI1E,4FAA4F;AAC5F,eAAO,MAAM,gBAAgB;;;;iBAA2G,CAAC;AAEzI,gEAAgE;AAChE,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAM3D,qEAAqE;AACrE,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED,6GAA6G;AAC7G,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAc5C;AAED,kHAAkH;AAClH,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CA4B/G;AAED,+EAA+E;AAC/E,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAOjE;AAID,oGAAoG;AACpG,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,UAAU,GAAG,YAAY,GAAG,SAAS,CAM/E;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAsCpH"}
|
package/dist/run-bin.js
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
3
|
+
import { createRequire } from 'node:module';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { jsonSchema, ProblemError, z } from '@kvman/sdk';
|
|
6
|
+
import { invalid, kvbuilderProblem } from "./problems.js";
|
|
7
|
+
import { killTree } from "./run-program.js";
|
|
8
|
+
const packageJsonSchema = z.object({ bin: z.record(z.string(), z.string()) });
|
|
9
|
+
/** A bin's `{ code, message, params? }` failure line, for validating a process log line. */
|
|
10
|
+
export const binFailureSchema = z.object({ code: z.string(), message: z.string(), params: z.record(z.string(), jsonSchema).optional() });
|
|
11
|
+
function testkitPackageFile() {
|
|
12
|
+
return createRequire(import.meta.url).resolve('@kvman/testkit/package.json');
|
|
13
|
+
}
|
|
14
|
+
/** The testkit's `docs/` folder, which holds the built-in guides. */
|
|
15
|
+
export function testkitDocsFolder() {
|
|
16
|
+
return path.join(path.dirname(testkitPackageFile()), 'docs');
|
|
17
|
+
}
|
|
18
|
+
/** The file of a `@kvman/testkit` bin; a missing entry or file is an installation problem, not a Problem. */
|
|
19
|
+
export function binFile(name) {
|
|
20
|
+
const packageFile = testkitPackageFile();
|
|
21
|
+
let raw;
|
|
22
|
+
try {
|
|
23
|
+
raw = JSON.parse(readFileSync(packageFile, 'utf8'));
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
throw new Error(`The ${name} bin can't be found; reinstall @kvman/testkit.`);
|
|
27
|
+
}
|
|
28
|
+
const parsed = packageJsonSchema.safeParse(raw);
|
|
29
|
+
const entry = parsed.success ? parsed.data.bin[name] : undefined;
|
|
30
|
+
if (entry === undefined)
|
|
31
|
+
throw new Error(`The ${name} bin is missing from @kvman/testkit; reinstall it.`);
|
|
32
|
+
const file = path.join(path.dirname(packageFile), entry);
|
|
33
|
+
if (!existsSync(file))
|
|
34
|
+
throw new Error(`The ${name} bin is missing at ${file}; reinstall @kvman/testkit.`);
|
|
35
|
+
return file;
|
|
36
|
+
}
|
|
37
|
+
/** Runs a bin with the running Node in `cwd`, `--json` always on; stdout and stderr stay apart for the caller. */
|
|
38
|
+
export function runBin(name, args, cwd, signal) {
|
|
39
|
+
const file = binFile(name);
|
|
40
|
+
return new Promise((resolve, reject) => {
|
|
41
|
+
const child = spawn(process.execPath, [...process.execArgv, file, ...args, '--json'], {
|
|
42
|
+
cwd,
|
|
43
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
44
|
+
detached: process.platform !== 'win32',
|
|
45
|
+
windowsHide: true,
|
|
46
|
+
});
|
|
47
|
+
let stdout = '';
|
|
48
|
+
let stderr = '';
|
|
49
|
+
child.stdout.setEncoding('utf8').on('data', (text) => {
|
|
50
|
+
stdout += text;
|
|
51
|
+
});
|
|
52
|
+
child.stderr.setEncoding('utf8').on('data', (text) => {
|
|
53
|
+
stderr += text;
|
|
54
|
+
});
|
|
55
|
+
const abort = () => killTree(child.pid);
|
|
56
|
+
signal.addEventListener('abort', abort, { once: true });
|
|
57
|
+
child.once('error', (error) => {
|
|
58
|
+
signal.removeEventListener('abort', abort);
|
|
59
|
+
reject(error);
|
|
60
|
+
});
|
|
61
|
+
child.once('close', (code) => {
|
|
62
|
+
signal.removeEventListener('abort', abort);
|
|
63
|
+
resolve({ exitCode: code ?? 1, stdout, stderr });
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
/** The last non-empty line of an output, or `undefined` when there is none. */
|
|
68
|
+
export function lastOutputLine(output) {
|
|
69
|
+
const lines = output.split('\n');
|
|
70
|
+
for (let index = lines.length - 1; index >= 0; index -= 1) {
|
|
71
|
+
const line = lines[index];
|
|
72
|
+
if (line !== undefined && line.trim() !== '')
|
|
73
|
+
return line;
|
|
74
|
+
}
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
const kvbuilderBinCodes = ['FOLDER_NOT_EMPTY', 'FILE_EXISTS', 'NPM_FAILED', 'NO_FREE_PORT', 'PREVIEW_FAILED'];
|
|
78
|
+
/** The Problem for a bin's structured failure, or `undefined` when its code has no mapping here. */
|
|
79
|
+
export function binFailureProblem(failure) {
|
|
80
|
+
const params = failure.params ?? {};
|
|
81
|
+
if (failure.code === 'VALIDATION_FAILED')
|
|
82
|
+
return invalid(failure.message, params);
|
|
83
|
+
if (failure.code === 'NOT_FOUND')
|
|
84
|
+
return new ProblemError({ code: 'NOT_FOUND', message: failure.message, params });
|
|
85
|
+
if (kvbuilderBinCodes.includes(failure.code))
|
|
86
|
+
return kvbuilderProblem(failure.code, failure.message, params);
|
|
87
|
+
return undefined;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* The bin's output: exit 0 gives the last non-empty stdout line against `outputSchema`; exit 1 with the bin's
|
|
91
|
+
* `{ code, message, params? }` on stderr gives its Problem. Anything else fails `HANDLER_FAILED` in the kernel,
|
|
92
|
+
* after logging the bin and the exit code, never the output or the arguments.
|
|
93
|
+
*/
|
|
94
|
+
export function binResult(log, bin, run, outputSchema) {
|
|
95
|
+
if (run.exitCode === 0) {
|
|
96
|
+
const line = lastOutputLine(run.stdout);
|
|
97
|
+
if (line !== undefined) {
|
|
98
|
+
let parsed;
|
|
99
|
+
try {
|
|
100
|
+
parsed = JSON.parse(line);
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
parsed = undefined;
|
|
104
|
+
}
|
|
105
|
+
if (parsed !== undefined) {
|
|
106
|
+
const checked = outputSchema.safeParse(parsed);
|
|
107
|
+
if (checked.success)
|
|
108
|
+
return checked.data;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
log.error(`${bin} printed an unexpected output.`, { bin, exitCode: run.exitCode });
|
|
112
|
+
throw new Error(`${bin} failed.`);
|
|
113
|
+
}
|
|
114
|
+
if (run.exitCode === 1) {
|
|
115
|
+
const line = lastOutputLine(run.stderr);
|
|
116
|
+
if (line !== undefined) {
|
|
117
|
+
let parsed;
|
|
118
|
+
try {
|
|
119
|
+
parsed = JSON.parse(line);
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
parsed = undefined;
|
|
123
|
+
}
|
|
124
|
+
if (parsed !== undefined) {
|
|
125
|
+
const failure = binFailureSchema.safeParse(parsed);
|
|
126
|
+
if (failure.success) {
|
|
127
|
+
const problem = binFailureProblem(failure.data);
|
|
128
|
+
if (problem !== undefined)
|
|
129
|
+
throw problem;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
log.error(`${bin} failed.`, { bin, exitCode: run.exitCode });
|
|
135
|
+
throw new Error(`${bin} failed.`);
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=run-bin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-bin.js","sourceRoot":"","sources":["../src/run-bin.ts"],"names":[],"mappings":"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"}
|