@malmhq/intermesh-cli 0.1.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 +198 -0
- package/README.md +77 -0
- package/dist/generation/.opencode/AGENTS.md +38 -0
- package/dist/generation/.opencode/agents/generation-builder.md +9 -0
- package/dist/generation/.opencode/agents/generation-fidelity.md +9 -0
- package/dist/generation/.opencode/agents/generation-source.md +13 -0
- package/dist/generation/.opencode/prompts/analyze-capabilities.md +61 -0
- package/dist/generation/.opencode/prompts/analyze-source.md +41 -0
- package/dist/generation/.opencode/prompts/generate.md +9 -0
- package/dist/generation/.opencode/prompts/repair-capability-proposal.md +5 -0
- package/dist/generation/.opencode/skills/generation-building/SKILL.md +32 -0
- package/dist/generation/.opencode/skills/generation-package-review/SKILL.md +36 -0
- package/dist/generation/.opencode/skills/generation-source-analysis/SKILL.md +36 -0
- package/dist/generation/AGENTS.md +38 -0
- package/dist/generation/agent-skill-installer/index.ts +4 -0
- package/dist/generation/agent-skill-installer/install.ts +503 -0
- package/dist/generation/agent-skill-installer/lock.ts +128 -0
- package/dist/generation/agent-skill-installer/manifest.ts +271 -0
- package/dist/generation/agent-skill-installer/targets.ts +169 -0
- package/dist/generation/runtime-entrypoint.js +39980 -0
- package/dist/generation/scripts/check-package.mjs +45 -0
- package/dist/generation/scripts/installed-help.mjs +98 -0
- package/dist/generation/scripts/lead-input.mjs +584 -0
- package/dist/generation/scripts/prepare-opencode.mjs +33 -0
- package/dist/generation/scripts/prepared-work.mjs +197 -0
- package/dist/generation/scripts/repair-loop.mjs +519 -0
- package/dist/generation/scripts/run-reviewers.mjs +306 -0
- package/dist/generation/scripts/runtime-capture.mjs +119 -0
- package/dist/generation/scripts/stage-timings.mjs +53 -0
- package/dist/generation/scripts/validate-source-brief.mjs +220 -0
- package/dist/generation/scripts/verify-package.mjs +365 -0
- package/dist/generation/templates/npm-cli/CONTRIBUTING.md +20 -0
- package/dist/generation/templates/npm-cli/GENERATION-PATTERNS.md +143 -0
- package/dist/generation/templates/npm-cli/README.md +67 -0
- package/dist/generation/templates/npm-cli/capabilities.json +1 -0
- package/dist/generation/templates/npm-cli/mock/routes.ts +3 -0
- package/dist/generation/templates/npm-cli/mock/server.ts +15 -0
- package/dist/generation/templates/npm-cli/mock/types.ts +7 -0
- package/dist/generation/templates/npm-cli/package.json +36 -0
- package/dist/generation/templates/npm-cli/pnpm-lock.yaml +495 -0
- package/dist/generation/templates/npm-cli/pnpm-workspace.yaml +2 -0
- package/dist/generation/templates/npm-cli/skills/customer-cli-management/SKILL.md +22 -0
- package/dist/generation/templates/npm-cli/skills/customer-workflow/SKILL.md +22 -0
- package/dist/generation/templates/npm-cli/src/auth/commands.ts +77 -0
- package/dist/generation/templates/npm-cli/src/auth/credentials.ts +66 -0
- package/dist/generation/templates/npm-cli/src/auth/prompt.ts +27 -0
- package/dist/generation/templates/npm-cli/src/cli.ts +53 -0
- package/dist/generation/templates/npm-cli/src/commands.ts +6 -0
- package/dist/generation/templates/npm-cli/src/customer.ts +16 -0
- package/dist/generation/templates/npm-cli/src/index.ts +11 -0
- package/dist/generation/templates/npm-cli/src/lifecycle/commands.ts +344 -0
- package/dist/generation/templates/npm-cli/src/lifecycle/config.ts +32 -0
- package/dist/generation/templates/npm-cli/src/shared/dry-run.ts +32 -0
- package/dist/generation/templates/npm-cli/src/shared/errors.ts +162 -0
- package/dist/generation/templates/npm-cli/src/shared/files.ts +45 -0
- package/dist/generation/templates/npm-cli/src/shared/http.ts +125 -0
- package/dist/generation/templates/npm-cli/src/shared/output.ts +33 -0
- package/dist/generation/templates/npm-cli/test/auth.test.ts +113 -0
- package/dist/generation/templates/npm-cli/test/fixture-cli.ts +51 -0
- package/dist/generation/templates/npm-cli/test/foundation.test.ts +316 -0
- package/dist/generation/templates/npm-cli/test/helpers.ts +34 -0
- package/dist/generation/templates/npm-cli/test/mock-lifecycle.test.ts +86 -0
- package/dist/generation/templates/npm-cli/test/run-with-mock.ts +142 -0
- package/dist/generation/templates/npm-cli/tsconfig.build.json +5 -0
- package/dist/generation/templates/npm-cli/tsconfig.json +11 -0
- package/dist/generation/templates/opencode-bootstrap/package-lock.json +402 -0
- package/dist/generation/templates/opencode-bootstrap/package.json +7 -0
- package/dist/index.js +51965 -0
- package/dist/runtime/candidate-inspection/inspect.Dockerfile +4 -0
- package/dist/runtime/candidate-inspection/install.Dockerfile +5 -0
- package/dist/runtime/candidate-inspection/registry-proxy.mjs +37 -0
- package/dist/runtime/harbor/bootstrap/package-lock.json +402 -0
- package/dist/runtime/harbor/bootstrap/package.json +7 -0
- package/dist/runtime/harbor/evaluation.Dockerfile +31 -0
- package/dist/runtime/harbor/harbor_launcher.py +62 -0
- package/dist/runtime/harbor/intermesh_opencode.py +44 -0
- package/dist/runtime/harbor/model-forwarder.mjs +52 -0
- package/dist/runtime/live-task.md +13 -0
- package/package.json +44 -0
- package/skills/inter-cli-management/SKILL.md +38 -0
- package/skills/inter-cli-management/evals/evals.json +40 -0
- package/skills/inter-context/SKILL.md +72 -0
- package/skills/inter-context/evals/cases.json +82 -0
- package/skills/inter-eval-authoring/SKILL.md +70 -0
- package/skills/inter-eval-authoring/evals/evals.json +69 -0
- package/skills/inter-eval-authoring/evals/trigger-queries.json +34 -0
- package/skills/inter-eval-authoring/references/authoring-guide.md +70 -0
- package/skills/inter-eval-authoring/references/eval-plan.example.json +92 -0
- package/skills/inter-eval-authoring/references/eval-plan.schema.json +304 -0
- package/skills/inter-evaluation/SKILL.md +51 -0
- package/skills/inter-evaluation/evals/evals.json +49 -0
- package/skills/inter-evaluation/evals/trigger-queries.json +30 -0
- package/skills/inter-generation/SKILL.md +42 -0
- package/skills/inter-generation/evals/evals.json +81 -0
- package/skills/inter-generation/evals/trigger-queries.json +58 -0
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { chmod, mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
|
|
5
|
+
const JSON_MEDIA = /^(application\/(?:json|[^;]+\+json))(?:;|$)/iu;
|
|
6
|
+
const TEXT_MEDIA = /^text\/plain(?:;|$)/iu;
|
|
7
|
+
const SAFE_SEGMENT = /^[a-z0-9][a-z0-9-]*$/u;
|
|
8
|
+
|
|
9
|
+
function fail(message) {
|
|
10
|
+
throw new TypeError(message);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function record(value, name) {
|
|
14
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) fail(`${name} is invalid`);
|
|
15
|
+
return value;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function successContent(operation) {
|
|
19
|
+
const responses = record(operation.responses, 'Operation responses');
|
|
20
|
+
const successful = Object.keys(responses)
|
|
21
|
+
.filter((status) => /^2\d\d$/u.test(status))
|
|
22
|
+
.sort();
|
|
23
|
+
if (successful.length === 0) fail('Operation has no explicit successful response');
|
|
24
|
+
const mediaTypes = new Set();
|
|
25
|
+
for (const status of successful) {
|
|
26
|
+
const response = record(responses[status], `Response ${status}`);
|
|
27
|
+
const content = record(response.content, `Response ${status} content`);
|
|
28
|
+
for (const mediaType of Object.keys(content)) mediaTypes.add(mediaType.toLowerCase());
|
|
29
|
+
}
|
|
30
|
+
return [...mediaTypes].sort();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function responsePattern(capability) {
|
|
34
|
+
const mediaTypes = successContent(capability.operation);
|
|
35
|
+
const kinds = new Set(
|
|
36
|
+
mediaTypes.map((mediaType) => {
|
|
37
|
+
if (JSON_MEDIA.test(mediaType)) return 'json';
|
|
38
|
+
if (TEXT_MEDIA.test(mediaType)) return 'text';
|
|
39
|
+
return 'unsupported';
|
|
40
|
+
}),
|
|
41
|
+
);
|
|
42
|
+
if (kinds.has('unsupported') || kinds.size !== 1)
|
|
43
|
+
fail(`Unsupported or mixed success response for ${capability.operation_key}`);
|
|
44
|
+
const derived = [...kinds][0];
|
|
45
|
+
if (capability.requested_response_pattern === 'file') {
|
|
46
|
+
if (
|
|
47
|
+
!capability.context_evidence.some((item) =>
|
|
48
|
+
/\b(download|save|persist|output\s+to\s+a\s+file)\b/iu.test(item.excerpt),
|
|
49
|
+
)
|
|
50
|
+
)
|
|
51
|
+
fail(`File response lacks exact business evidence: ${capability.operation_key}`);
|
|
52
|
+
return 'file';
|
|
53
|
+
}
|
|
54
|
+
return derived;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function slug(value) {
|
|
58
|
+
const result = value
|
|
59
|
+
.toLowerCase()
|
|
60
|
+
.trim()
|
|
61
|
+
.replaceAll(/[^a-z0-9]+/gu, '-')
|
|
62
|
+
.replaceAll(/^-|-$/gu, '');
|
|
63
|
+
if (!SAFE_SEGMENT.test(result)) fail(`Unsafe command family: ${value}`);
|
|
64
|
+
return result;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function createWorkPackets(capabilities, binary) {
|
|
68
|
+
const sorted = [...capabilities].sort(
|
|
69
|
+
(a, b) =>
|
|
70
|
+
a.proposed_command.localeCompare(b.proposed_command) ||
|
|
71
|
+
a.operation_key.localeCompare(b.operation_key),
|
|
72
|
+
);
|
|
73
|
+
const families = new Map();
|
|
74
|
+
for (const capability of sorted) {
|
|
75
|
+
const family = capability.proposed_command.trim().split(/\s+/u)[0];
|
|
76
|
+
if (!family) fail('Proposed command has no family');
|
|
77
|
+
const values = families.get(family) ?? [];
|
|
78
|
+
values.push({ ...capability, response_pattern: responsePattern(capability) });
|
|
79
|
+
families.set(family, values);
|
|
80
|
+
}
|
|
81
|
+
const cli = [];
|
|
82
|
+
for (const [family, values] of [...families].sort(([a], [b]) => a.localeCompare(b))) {
|
|
83
|
+
for (let offset = 0; offset < values.length; offset += 3) {
|
|
84
|
+
const chunk = values.slice(offset, offset + 3);
|
|
85
|
+
const suffix = values.length > 3 ? `-${offset / 3 + 1}` : '';
|
|
86
|
+
const id = `${slug(family)}${suffix}`;
|
|
87
|
+
cli.push({
|
|
88
|
+
id: `cli-${id}`,
|
|
89
|
+
kind: 'cli',
|
|
90
|
+
command_family: family,
|
|
91
|
+
capabilities: chunk.map((item) => {
|
|
92
|
+
const prepared = { ...item };
|
|
93
|
+
delete prepared.requested_response_pattern;
|
|
94
|
+
return prepared;
|
|
95
|
+
}),
|
|
96
|
+
writable_paths: [
|
|
97
|
+
`package/src/commands/${id}.ts`,
|
|
98
|
+
`package/mock/routes/${id}.ts`,
|
|
99
|
+
`package/test/${id}.test.ts`,
|
|
100
|
+
],
|
|
101
|
+
helper_signatures: [
|
|
102
|
+
"../shared/http.js: request({ baseUrl?: string, method: 'DELETE' | 'GET' | 'HEAD' | 'OPTIONS' | 'PATCH' | 'POST' | 'PUT', path: string, query?: URLSearchParams, body?: Uint8Array, mediaType?: string, timeoutMs?: number, workflow?: { summary: string, steps: Array<{ summary: string, depends_on_response?: boolean }> } }): Promise<{ body: Uint8Array; mediaType: string; status: number }>. Pass the complete workflow preview on the first request after validating all locally available inputs.",
|
|
103
|
+
'../shared/output.js: parseJson(body: Uint8Array): unknown; printSuccess(data: unknown, command: string): void',
|
|
104
|
+
'../shared/files.js: validateOutputFile(path: string): Promise<void> before the first request; saveFile(path: string, body: Uint8Array, mediaType: string): Promise<{ path: string; media_type: string }>',
|
|
105
|
+
'../shared/errors.js: throw new CliError(cliErrors.invalidInput(message)) for source-specific validation failures',
|
|
106
|
+
],
|
|
107
|
+
focused_check: `pnpm exec tsx --test test/${id}.test.ts`,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return {
|
|
112
|
+
cli,
|
|
113
|
+
skill: {
|
|
114
|
+
id: 'skill-customer-workflows',
|
|
115
|
+
kind: 'skill',
|
|
116
|
+
capabilities: sorted.map((item) => item.operation_key),
|
|
117
|
+
writable_paths: [
|
|
118
|
+
'package/README.md',
|
|
119
|
+
`package/skills/${binary}-workflow/**`,
|
|
120
|
+
'package/skills/<focused-name>/SKILL.md',
|
|
121
|
+
],
|
|
122
|
+
excluded_paths: [`package/skills/${binary}-cli-management/**`],
|
|
123
|
+
focused_check: 'validate Skill frontmatter and command names against trusted work packets',
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function commandScaffold(packet) {
|
|
129
|
+
return `import type { Command } from 'commander';\n\n// Assigned operations: ${packet.capabilities.map((item) => item.operation_key).join(', ')}\n// Fill only this command family's customer-specific behavior.\nexport function register(program: Command): void {\n void program;\n}\n`;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function mockScaffold(packet) {
|
|
133
|
+
return `import type { MockRoute } from '../types.js';\n\n// Synthetic offline routes for: ${packet.capabilities.map((item) => item.operation_key).join(', ')}\nexport const routes: MockRoute[] = [];\n`;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function testScaffold(packet) {
|
|
137
|
+
return `import test from 'node:test';\n\ntest.todo(${JSON.stringify(`implement focused coverage for ${packet.command_family}`)});\n`;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export async function scaffoldPreparedWork(packageDirectory, leadInput) {
|
|
141
|
+
const packets = leadInput.work_packets.cli;
|
|
142
|
+
await mkdir(join(packageDirectory, 'src/commands'), { recursive: true });
|
|
143
|
+
await mkdir(join(packageDirectory, 'mock/routes'), { recursive: true });
|
|
144
|
+
await mkdir(join(packageDirectory, 'test'), { recursive: true });
|
|
145
|
+
const imports = [];
|
|
146
|
+
const registrations = [];
|
|
147
|
+
const mockImports = [];
|
|
148
|
+
const mockRoutes = [];
|
|
149
|
+
for (const [index, packet] of packets.entries()) {
|
|
150
|
+
const id = packet.id.slice(4);
|
|
151
|
+
await writeFile(join(packageDirectory, `src/commands/${id}.ts`), commandScaffold(packet), {
|
|
152
|
+
flag: 'wx',
|
|
153
|
+
});
|
|
154
|
+
await writeFile(join(packageDirectory, `mock/routes/${id}.ts`), mockScaffold(packet), {
|
|
155
|
+
flag: 'wx',
|
|
156
|
+
});
|
|
157
|
+
await writeFile(join(packageDirectory, `test/${id}.test.ts`), testScaffold(packet), {
|
|
158
|
+
flag: 'wx',
|
|
159
|
+
});
|
|
160
|
+
imports.push(`import { register as register${index} } from './commands/${id}.js';`);
|
|
161
|
+
registrations.push(` register${index}(program);`);
|
|
162
|
+
mockImports.push(`import { routes as routes${index} } from './routes/${id}.js';`);
|
|
163
|
+
mockRoutes.push(`...routes${index}`);
|
|
164
|
+
}
|
|
165
|
+
await writeFile(
|
|
166
|
+
join(packageDirectory, 'src/commands.ts'),
|
|
167
|
+
`import type { Command } from 'commander';\n${imports.join('\n')}\n\nexport function registerCommands(program: Command): void {\n${registrations.join('\n')}\n}\n`,
|
|
168
|
+
);
|
|
169
|
+
await writeFile(
|
|
170
|
+
join(packageDirectory, 'mock/routes.ts'),
|
|
171
|
+
`import type { MockRoute } from './types.js';\n${mockImports.join('\n')}\n\nexport const routes: MockRoute[] = [${mockRoutes.join(', ')}];\n`,
|
|
172
|
+
);
|
|
173
|
+
const capabilities = leadInput.capabilities
|
|
174
|
+
.map((item) => ({
|
|
175
|
+
command: item.proposed_command,
|
|
176
|
+
method: item.operation.method,
|
|
177
|
+
path: item.operation.path,
|
|
178
|
+
effect: item.effect,
|
|
179
|
+
}))
|
|
180
|
+
.sort((a, b) => a.command.localeCompare(b.command));
|
|
181
|
+
await writeFile(
|
|
182
|
+
join(packageDirectory, 'capabilities.json'),
|
|
183
|
+
`${JSON.stringify({ commands: capabilities, excluded: [] }, null, 2)}\n`,
|
|
184
|
+
);
|
|
185
|
+
const protectedFiles = ['src/commands.ts', 'mock/routes.ts', 'capabilities.json'];
|
|
186
|
+
const hashes = {};
|
|
187
|
+
for (const path of protectedFiles) {
|
|
188
|
+
const bytes = await readFile(join(packageDirectory, path));
|
|
189
|
+
hashes[path] = createHash('sha256').update(bytes).digest('hex');
|
|
190
|
+
await chmod(join(packageDirectory, path), 0o444);
|
|
191
|
+
}
|
|
192
|
+
return hashes;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export async function readLeadInput(path) {
|
|
196
|
+
return record(JSON.parse(await readFile(path, 'utf8')), 'Lead input');
|
|
197
|
+
}
|