@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,143 @@
|
|
|
1
|
+
# Generation patterns
|
|
2
|
+
|
|
3
|
+
This file is generation-only guidance and is not published. Start with your assigned packet and this guide. The runner has created and registered your command, mock and test files. Fill only `writable_paths`; do not edit registration, authentication, shared helpers or the capability manifest.
|
|
4
|
+
|
|
5
|
+
## Helpers from a command file
|
|
6
|
+
|
|
7
|
+
- `../shared/http.js`: `request({ baseUrl?, method, path, query?, body?, mediaType?, timeoutMs? })` returns `{ body: Uint8Array, mediaType: string, status: number }`. Use `URLSearchParams` for query values and bytes for request bodies. The packet lists the full signature.
|
|
8
|
+
- Forward `command.optsWithGlobals().baseUrl` to `request`. When absent, the helper uses the customer API and configured credentials. When present, it permits only loopback mocks and sends no credential. Do not build authentication yourself.
|
|
9
|
+
- `../shared/output.js`: `parseJson(body)` preserves large JSON numbers; `printSuccess(data, command)` writes the success envelope. Do not convert exact identifiers through `Number`.
|
|
10
|
+
- `../shared/errors.js`: throw `new CliError(cliErrors.invalidInput(message))` for invalid customer input. `runCli` owns formatting errors and exit codes; the transport owns upstream errors, redirects and header/body timeouts (30 seconds by default).
|
|
11
|
+
- `../shared/files.js`: `await saveFile(path, body, mediaType)` preserves bytes, rejects existing destinations, and returns `{ path, media_type }`.
|
|
12
|
+
- For file-producing commands, call `await validateOutputFile(path)` from the same helper before the first request, so invalid destinations also fail in dry run. `saveFile` rechecks the destination and writes exclusively during execution.
|
|
13
|
+
|
|
14
|
+
All results, including errors, use a versioned JSON envelope on stdout. Never print credentials or raw request bodies. Commands must validate every locally available input before calling `request`, including parsing input files and checking output destinations. Keep all writes after that call. Non-interactive commands must never prompt.
|
|
15
|
+
|
|
16
|
+
Every generated command must pass `workflow: { summary, steps }` to its first `request`. Describe the complete intended sequence, including conditional branches, repeated requests and output-file writes. Each step has a plain `summary`; add `depends_on_response: true` when its values or whether it runs depend on a previous response. The helper validates request construction, prints all declared steps and stops before HTTP in dry-run mode. Do not fabricate responses or swallow the completion signal. Keep summaries specific to the selected action but never interpolate secrets, raw input values or file contents. For workflows without HTTP, call `previewWorkflow(workflow, commandName)` from `../shared/dry-run.js` after local validation and before any effects.
|
|
17
|
+
|
|
18
|
+
Missing files, invalid inputs and existing output files must fail even in dry run. Server permissions, customer existence and response-dependent values remain explicitly unchecked; they do not make an otherwise valid preview fail. Test the real command with `--dry-run`: assert every intended step appears, invalid local inputs fail, and no requests or writes occur. Keep general usage instructions and examples in `--help`.
|
|
19
|
+
|
|
20
|
+
## Minimal JSON example
|
|
21
|
+
|
|
22
|
+
Synthetic `records` illustrates the wiring, not customer requirements. Replace its command, flags, validation, path and mock data with your packet's exact requirements. Imports below are relative to the named files.
|
|
23
|
+
|
|
24
|
+
`src/commands/records.ts`:
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
import type { Command } from 'commander';
|
|
28
|
+
import { request } from '../shared/http.js';
|
|
29
|
+
import { CliError, cliErrors } from '../shared/errors.js';
|
|
30
|
+
import { parseJson, printSuccess } from '../shared/output.js';
|
|
31
|
+
|
|
32
|
+
export function register(program: Command): void {
|
|
33
|
+
program
|
|
34
|
+
.command('records')
|
|
35
|
+
.requiredOption('--id <id>', 'Exact decimal identifier', (value: string) => {
|
|
36
|
+
if (!/^[0-9]+$/.test(value))
|
|
37
|
+
throw new CliError(cliErrors.invalidInput('ID must be a non-negative integer.'));
|
|
38
|
+
return value;
|
|
39
|
+
})
|
|
40
|
+
.allowExcessArguments(false)
|
|
41
|
+
.action(async (_options, command) => {
|
|
42
|
+
const { id, baseUrl } = command.optsWithGlobals() as { id: string; baseUrl?: string };
|
|
43
|
+
const response = await request({
|
|
44
|
+
baseUrl,
|
|
45
|
+
method: 'GET',
|
|
46
|
+
path: '/records',
|
|
47
|
+
query: new URLSearchParams({ id }),
|
|
48
|
+
workflow: {
|
|
49
|
+
summary: 'Look up the record matching the supplied ID.',
|
|
50
|
+
steps: [{ summary: 'Fetch the matching record' }],
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
printSuccess(parseJson(response.body), 'records');
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
`mock/routes/records.ts`:
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
import type { MockRoute } from '../types.js';
|
|
62
|
+
|
|
63
|
+
export const routes: MockRoute[] = [
|
|
64
|
+
{
|
|
65
|
+
method: 'GET',
|
|
66
|
+
path: '/records',
|
|
67
|
+
handle(_url, response) {
|
|
68
|
+
response.writeHead(200, { 'content-type': 'application/json' });
|
|
69
|
+
response.end('{"id":9007199254740993}');
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
];
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
`test/records.test.ts` — test the real CLI in an asynchronous child process so the mock server can respond:
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
import assert from 'node:assert/strict';
|
|
79
|
+
import { execFile } from 'node:child_process';
|
|
80
|
+
import { createServer } from 'node:http';
|
|
81
|
+
import { promisify } from 'node:util';
|
|
82
|
+
import test from 'node:test';
|
|
83
|
+
import { routes } from '../mock/routes/records.js';
|
|
84
|
+
|
|
85
|
+
const exec = promisify(execFile);
|
|
86
|
+
test('records preserves IDs and rejects invalid input before HTTP', async () => {
|
|
87
|
+
const requests: string[] = [];
|
|
88
|
+
const server = createServer((request, response) => {
|
|
89
|
+
requests.push(request.url ?? '');
|
|
90
|
+
const url = new URL(request.url ?? '/', 'http://127.0.0.1');
|
|
91
|
+
const route = routes.find(
|
|
92
|
+
(item) => item.method === request.method && item.path === url.pathname,
|
|
93
|
+
);
|
|
94
|
+
if (route) route.handle(url, response);
|
|
95
|
+
else {
|
|
96
|
+
response.writeHead(404);
|
|
97
|
+
response.end();
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
await new Promise<void>((ready) => server.listen(0, '127.0.0.1', ready));
|
|
101
|
+
try {
|
|
102
|
+
const address = server.address();
|
|
103
|
+
assert.ok(address && typeof address !== 'string');
|
|
104
|
+
const run = (args: string[]) =>
|
|
105
|
+
exec(
|
|
106
|
+
process.execPath,
|
|
107
|
+
[
|
|
108
|
+
'--import',
|
|
109
|
+
'tsx',
|
|
110
|
+
'src/index.ts',
|
|
111
|
+
'records',
|
|
112
|
+
...args,
|
|
113
|
+
'--base-url',
|
|
114
|
+
`http://127.0.0.1:${address.port}`,
|
|
115
|
+
],
|
|
116
|
+
{ timeout: 10_000 },
|
|
117
|
+
);
|
|
118
|
+
await assert.rejects(run(['--id', '1junk']), (error) => {
|
|
119
|
+
assert.equal((error as { code: number }).code, 2);
|
|
120
|
+
assert.equal(JSON.parse((error as { stdout: string }).stdout).error.code, 'INVALID_INPUT');
|
|
121
|
+
return true;
|
|
122
|
+
});
|
|
123
|
+
assert.equal(requests.length, 0);
|
|
124
|
+
const result = await run(['--id', '9007199254740993']);
|
|
125
|
+
assert.equal(result.stderr, '');
|
|
126
|
+
assert.match(result.stdout, /"id":9007199254740993/);
|
|
127
|
+
assert.deepEqual(requests, ['/records?id=9007199254740993']);
|
|
128
|
+
} finally {
|
|
129
|
+
server.closeAllConnections();
|
|
130
|
+
await new Promise<void>((done) => server.close(() => done()));
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Run the packet's `focused_check` directly from `package/`, preserving its real exit code. If it fails, repair the affected code or report a blocker. Rerun only after an affected repair or relevant code change. After it passes, move to the next assigned packet; when all assigned packets pass, report results from existing tool output and finish without separate evidence files or a post-pass file review. This example shows the test structure, not complete coverage: add your packet's source-specific cases and required safety checks without duplicating shared-foundation tests.
|
|
136
|
+
|
|
137
|
+
## Response variations
|
|
138
|
+
|
|
139
|
+
- JSON: call `request`, parse bytes with `parseJson`, then call `printSuccess`.
|
|
140
|
+
- Text: call `request`, decode bytes as UTF-8, then call `printSuccess`.
|
|
141
|
+
- File: require `--output-file`, call `request`, preserve bytes with `saveFile`, then call `printSuccess` with the returned file metadata.
|
|
142
|
+
|
|
143
|
+
For text, use `Buffer.from(response.body).toString('utf8')`. For files, pass `response.body` and `response.mediaType` directly to `saveFile`; include source-required identifiers alongside its returned metadata. Do not parse and re-encode file contents. The approved packet decides the response pattern, not this example.
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# __DISPLAY_NAME__
|
|
2
|
+
|
|
3
|
+
`__BINARY__` is an agent-ready CLI for the approved capabilities of this API.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install --global __PACKAGE_NAME__
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Connect
|
|
12
|
+
|
|
13
|
+
Create an API token in the customer platform, then store it in your operating system's secure
|
|
14
|
+
credential manager:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
__BINARY__ login
|
|
18
|
+
__BINARY__ status
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The token is entered through a hidden prompt. It is not printed or stored in a plaintext file.
|
|
22
|
+
For CI, set `__ENV__` through the CI provider's secret manager instead of running `login`.
|
|
23
|
+
|
|
24
|
+
## Install Agent Skills
|
|
25
|
+
|
|
26
|
+
Install the bundled Skills in the shared Agent Skills directory:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
__BINARY__ setup --help
|
|
30
|
+
__BINARY__ setup --scope project --project-dir .
|
|
31
|
+
__BINARY__ status
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Skill setup and authentication are independent. Status reports both states.
|
|
35
|
+
|
|
36
|
+
## Use
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
__BINARY__ --help
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Read command help before using unfamiliar flags. Customer workflows and verified examples replace
|
|
43
|
+
this section during generation.
|
|
44
|
+
|
|
45
|
+
## Disconnect
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
__BINARY__ logout
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
This removes the local credential. It does not revoke the token in the customer platform.
|
|
52
|
+
|
|
53
|
+
## Update
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
__BINARY__ update --help
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Update installs the latest npm package and synchronizes only this CLI's managed Skills.
|
|
60
|
+
|
|
61
|
+
## Troubleshooting
|
|
62
|
+
|
|
63
|
+
- `AUTH_REQUIRED`: run `__BINARY__ login` or configure `__ENV__`.
|
|
64
|
+
- `AUTH_FAILED`: replace an expired or revoked token by running `__BINARY__ login` again.
|
|
65
|
+
- `CREDENTIAL_STORE_UNAVAILABLE`: unlock or enable the operating system credential manager.
|
|
66
|
+
|
|
67
|
+
Development and offline verification instructions are in `CONTRIBUTING.md` in the source repository.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "commands": [], "excluded": [] }
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { createServer } from 'node:http';
|
|
2
|
+
import { routes } from './routes.js';
|
|
3
|
+
|
|
4
|
+
createServer((request, response) => {
|
|
5
|
+
const url = new URL(request.url ?? '/', 'http://127.0.0.1');
|
|
6
|
+
const route = routes.find((item) => item.method === request.method && item.path === url.pathname);
|
|
7
|
+
if (route) {
|
|
8
|
+
route.handle(url, response);
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
response.writeHead(404, { 'content-type': 'application/json' });
|
|
12
|
+
response.end('{"message":"No mock route configured"}');
|
|
13
|
+
}).listen(8787, '127.0.0.1', () => {
|
|
14
|
+
process.stderr.write('Mock listening at http://127.0.0.1:8787\n');
|
|
15
|
+
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "customer-cli-starter",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Agent-ready customer API CLI foundation",
|
|
5
|
+
"private": true,
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"customer-cli": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"skills",
|
|
13
|
+
"README.md",
|
|
14
|
+
"capabilities.json"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"check": "tsc --noEmit",
|
|
18
|
+
"test": "tsx --test --test-concurrency=1 test/*.test.ts",
|
|
19
|
+
"build": "tsc --project tsconfig.build.json && node -e \"require('node:fs').chmodSync('dist/index.js', 0o755)\"",
|
|
20
|
+
"mock:run": "tsx test/run-with-mock.ts"
|
|
21
|
+
},
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=22"
|
|
24
|
+
},
|
|
25
|
+
"packageManager": "pnpm@11.21.0",
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@napi-rs/keyring": "1.3.0",
|
|
28
|
+
"commander": "15.0.0",
|
|
29
|
+
"lossless-json": "4.3.1"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/node": "24.13.3",
|
|
33
|
+
"tsx": "4.20.6",
|
|
34
|
+
"typescript": "6.0.3"
|
|
35
|
+
}
|
|
36
|
+
}
|