@t4h.framework/cli 0.0.0-experimental-20261008133517 → 0.0.0-experimental-29d0277
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/CHANGELOG.md +0 -49
- package/LICENSE +21 -0
- package/dist/bin/bin.js +16 -1
- package/dist/bin/bin.js.map +1 -1
- package/dist/commands/ai/ai-bootstrap.js +183 -48
- package/dist/commands/ai/ai-bootstrap.js.map +1 -1
- package/dist/commands/ai/ai-hook.js +84 -0
- package/dist/commands/ai/ai-hook.js.map +1 -0
- package/dist/commands/ai/tools/agent-instructions.js +75 -0
- package/dist/commands/ai/tools/agent-instructions.js.map +1 -0
- package/dist/commands/ai/tools/agent-settings.js +56 -0
- package/dist/commands/ai/tools/agent-settings.js.map +1 -0
- package/dist/commands/ai/tools/assets-lock.js +34 -0
- package/dist/commands/ai/tools/assets-lock.js.map +1 -0
- package/dist/commands/build/build.js +6 -2
- package/dist/commands/build/build.js.map +1 -1
- package/dist/commands/check/check.js +185 -0
- package/dist/commands/check/check.js.map +1 -0
- package/dist/commands/dev/dev.js +4 -1
- package/dist/commands/dev/dev.js.map +1 -1
- package/dist/commands/mcp/mcp-server.js +235 -0
- package/dist/commands/mcp/mcp-server.js.map +1 -0
- package/dist/commands/mcp/mcp-tools.js +283 -0
- package/dist/commands/mcp/mcp-tools.js.map +1 -0
- package/dist/commands/mcp/mcp.js +71 -0
- package/dist/commands/mcp/mcp.js.map +1 -0
- package/dist/commands/runtime/runtime.js +15 -3
- package/dist/commands/runtime/runtime.js.map +1 -1
- package/dist/commands/workflows/workflows.js +54 -12
- package/dist/commands/workflows/workflows.js.map +1 -1
- package/dist/tools/debug-log-option.js +2 -1
- package/dist/tools/debug-log-option.js.map +1 -1
- package/dist/tools/dev-server-client.js +261 -0
- package/dist/tools/dev-server-client.js.map +1 -0
- package/dist/tools/load-dev.js +23 -0
- package/dist/tools/load-dev.js.map +1 -0
- package/dist/tools/project-package.js +67 -0
- package/dist/tools/project-package.js.map +1 -0
- package/dist/tools/project-scripts.js +53 -0
- package/dist/tools/project-scripts.js.map +1 -0
- package/package.json +11 -2
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
async function readJson(filePath) {
|
|
4
|
+
try {
|
|
5
|
+
return JSON.parse(await fs.readFile(filePath, 'utf8'));
|
|
6
|
+
}
|
|
7
|
+
catch (error) {
|
|
8
|
+
if (error.code === 'ENOENT')
|
|
9
|
+
return {};
|
|
10
|
+
throw new Error(`${filePath} is not valid JSON; fix it and run again`, {
|
|
11
|
+
cause: error,
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
async function writeJson(filePath, value) {
|
|
16
|
+
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
17
|
+
await fs.writeFile(filePath, `${JSON.stringify(value, null, 2)}\n`);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Adds the hooks to a Claude Code settings object, keeping the project's own;
|
|
21
|
+
* a hook whose command is already there is not added twice.
|
|
22
|
+
*/
|
|
23
|
+
export function mergeClaudeHooks(settings, entries) {
|
|
24
|
+
const hooks = { ...(settings.hooks ?? {}) };
|
|
25
|
+
for (const { event, matcher, command } of entries) {
|
|
26
|
+
const groups = [...(hooks[event] ?? [])];
|
|
27
|
+
const exists = groups.some(group => (group.hooks ?? []).some((hook) => hook.command === command));
|
|
28
|
+
if (!exists)
|
|
29
|
+
groups.push({
|
|
30
|
+
...(matcher ? { matcher } : {}),
|
|
31
|
+
hooks: [{ type: 'command', command }],
|
|
32
|
+
});
|
|
33
|
+
hooks[event] = groups;
|
|
34
|
+
}
|
|
35
|
+
return { ...settings, hooks };
|
|
36
|
+
}
|
|
37
|
+
export async function installClaudeHooks(settingsPath, entries) {
|
|
38
|
+
const settings = await readJson(settingsPath);
|
|
39
|
+
const next = mergeClaudeHooks(settings, entries);
|
|
40
|
+
if (JSON.stringify(next) === JSON.stringify(settings))
|
|
41
|
+
return false;
|
|
42
|
+
await writeJson(settingsPath, next);
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
/** Registers the `framework` MCP server in a `.mcp.json`-shaped file. */
|
|
46
|
+
export async function installMcpServer(configPath, server) {
|
|
47
|
+
const config = await readJson(configPath);
|
|
48
|
+
if (config.mcpServers?.framework)
|
|
49
|
+
return false;
|
|
50
|
+
await writeJson(configPath, {
|
|
51
|
+
...config,
|
|
52
|
+
mcpServers: { ...(config.mcpServers ?? {}), framework: server },
|
|
53
|
+
});
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=agent-settings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-settings.js","sourceRoot":"","sources":["../../../../src/commands/ai/tools/agent-settings.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import crypto from 'node:crypto';
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { createDirectorySnapshot } from './create-directory-snapshot.js';
|
|
5
|
+
import { isDirectory } from './is-directory.js';
|
|
6
|
+
import { pathExists } from './path-exists.js';
|
|
7
|
+
export const ASSETS_LOCK_PATH = path.join('.framework', 'ai-assets.lock.json');
|
|
8
|
+
/** A content hash of a file or a whole directory; null when it doesn't exist. */
|
|
9
|
+
export async function hashAsset(assetPath) {
|
|
10
|
+
if (!(await pathExists(assetPath)))
|
|
11
|
+
return null;
|
|
12
|
+
const hash = crypto.createHash('sha256');
|
|
13
|
+
if (await isDirectory(assetPath))
|
|
14
|
+
for (const [entry, entryHash] of await createDirectorySnapshot(assetPath))
|
|
15
|
+
hash.update(`${entry}\0${entryHash}\n`);
|
|
16
|
+
else
|
|
17
|
+
hash.update(await fs.readFile(assetPath));
|
|
18
|
+
return hash.digest('hex');
|
|
19
|
+
}
|
|
20
|
+
export async function readAssetsLock(targetDir) {
|
|
21
|
+
try {
|
|
22
|
+
return JSON.parse(await fs.readFile(path.join(targetDir, ASSETS_LOCK_PATH), 'utf8'));
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export async function writeAssetsLock(targetDir, lock) {
|
|
29
|
+
const lockPath = path.join(targetDir, ASSETS_LOCK_PATH);
|
|
30
|
+
await fs.mkdir(path.dirname(lockPath), { recursive: true });
|
|
31
|
+
const assets = Object.fromEntries(Object.entries(lock.assets).sort(([a], [b]) => a.localeCompare(b)));
|
|
32
|
+
await fs.writeFile(lockPath, `${JSON.stringify({ ...lock, assets }, null, 2)}\n`);
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=assets-lock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assets-lock.js","sourceRoot":"","sources":["../../../../src/commands/ai/tools/assets-lock.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAA;AAChC,OAAO,EAAE,MAAM,kBAAkB,CAAA;AACjC,OAAO,IAAI,MAAM,WAAW,CAAA;AAE5B,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAA;AACxE,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAe7C,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,qBAAqB,CAAC,CAAA;AAE9E,iFAAiF;AACjF,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,SAAiB;IAC/C,IAAI,CAAC,CAAC,MAAM,UAAU,CAAC,SAAS,CAAC,CAAC;QAAE,OAAO,IAAI,CAAA;IAE/C,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAA;IAExC,IAAI,MAAM,WAAW,CAAC,SAAS,CAAC;QAC9B,KAAK,MAAM,CAAC,KAAK,EAAE,SAAS,CAAC,IAAI,MAAM,uBAAuB,CAAC,SAAS,CAAC;YACvE,IAAI,CAAC,MAAM,CAAC,GAAG,KAAK,KAAK,SAAS,IAAI,CAAC,CAAA;;QACtC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAA;IAE9C,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;AAC3B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,SAAiB;IAEjB,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CACf,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,gBAAgB,CAAC,EAAE,MAAM,CAAC,CAClE,CAAA;IACH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,SAAiB,EAAE,IAAgB;IACvE,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAA;IAEvD,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAE3D,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,CAC/B,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CACnE,CAAA;IAED,MAAM,EAAE,CAAC,SAAS,CAChB,QAAQ,EACR,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CACpD,CAAA;AACH,CAAC"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import { mkdirOutDirProjectFromTsConfigPathAndJsonPackagePath, resolvePackageJsonPath, resolveTsconfigFromPackageJsonPath, tsBuild, upApp, } from '@t4h.framework/dev/build';
|
|
4
3
|
import { Command, Option } from 'commander';
|
|
4
|
+
import { loadDevBuild, toProjectDir } from '../../tools/load-dev.js';
|
|
5
|
+
import { importProjectPackage } from '../../tools/project-package.js';
|
|
5
6
|
export const buildCommand = new Command('build')
|
|
6
7
|
.option('--entrypoint <entrypoint path>', 'The entrypoint package json path', './package.json')
|
|
7
8
|
.addOption(new Option('-e, --env <envs..>', 'The env secrets')
|
|
@@ -18,6 +19,8 @@ export const buildCommand = new Command('build')
|
|
|
18
19
|
})
|
|
19
20
|
.default({}))
|
|
20
21
|
.action(async (options) => {
|
|
22
|
+
const projectDir = toProjectDir(options.entrypoint);
|
|
23
|
+
const { mkdirOutDirProjectFromTsConfigPathAndJsonPackagePath, resolvePackageJsonPath, resolveTsconfigFromPackageJsonPath, tsBuild, upApp, } = await loadDevBuild(projectDir);
|
|
21
24
|
const entrypointPackageJsonPath = await resolvePackageJsonPath(options.entrypoint);
|
|
22
25
|
const entrypointTsConfigPath = await resolveTsconfigFromPackageJsonPath(entrypointPackageJsonPath);
|
|
23
26
|
const { outDir } = await mkdirOutDirProjectFromTsConfigPathAndJsonPackagePath(entrypointTsConfigPath, entrypointPackageJsonPath);
|
|
@@ -29,7 +32,8 @@ export const buildCommand = new Command('build')
|
|
|
29
32
|
});
|
|
30
33
|
if (!compileResult.ok)
|
|
31
34
|
throw new Error(compileResult.diagnostics.join('\n'));
|
|
32
|
-
|
|
35
|
+
// The core the app imports, so `Env.run` reaches it.
|
|
36
|
+
const { Env } = await importProjectPackage('@t4h.framework/core', projectDir);
|
|
33
37
|
await Env.run(options.env, async () => {
|
|
34
38
|
const { default: packageJson } = await import(entrypointPackageJsonPath, {
|
|
35
39
|
with: { type: 'json' },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.js","sourceRoot":"","sources":["../../../src/commands/build/build.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAA;AACxB,OAAO,IAAI,MAAM,WAAW,CAAA;AAE5B,OAAO,
|
|
1
|
+
{"version":3,"file":"build.js","sourceRoot":"","sources":["../../../src/commands/build/build.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { parseEnv } from 'node:util';
|
|
4
|
+
import { Command, Option } from 'commander';
|
|
5
|
+
import { loadDev, toProjectDir } from '../../tools/load-dev.js';
|
|
6
|
+
import { readProjectScripts, runCommand, runProjectScript, } from '../../tools/project-scripts.js';
|
|
7
|
+
export const CHECK_STEPS = ['types', 'lint', 'manifest', 'test'];
|
|
8
|
+
const OUTPUT_TAIL_LINES = 80;
|
|
9
|
+
const tail = (output, lines = OUTPUT_TAIL_LINES) => output.trimEnd().split('\n').slice(-lines).join('\n');
|
|
10
|
+
/**
|
|
11
|
+
* What an agent (or a person) needs from each workflow: an id to call it, a
|
|
12
|
+
* schema so the input is validated and discoverable, a description of intent.
|
|
13
|
+
*/
|
|
14
|
+
export function validateManifest(manifest) {
|
|
15
|
+
const issues = [];
|
|
16
|
+
const workflows = manifest.workflows.filter(({ id }) => id !== null);
|
|
17
|
+
if (workflows.length === 0)
|
|
18
|
+
issues.push({
|
|
19
|
+
level: 'warning',
|
|
20
|
+
message: 'The App registers no workflow with an id; pass them to `new App({ workflows })`',
|
|
21
|
+
});
|
|
22
|
+
for (const workflow of workflows) {
|
|
23
|
+
const id = workflow.id;
|
|
24
|
+
if (!workflow.schema)
|
|
25
|
+
issues.push({
|
|
26
|
+
level: 'warning',
|
|
27
|
+
workflow: id,
|
|
28
|
+
message: 'No input schema: the input is not validated and callers cannot discover it',
|
|
29
|
+
});
|
|
30
|
+
if (!workflow.description)
|
|
31
|
+
issues.push({
|
|
32
|
+
level: 'warning',
|
|
33
|
+
workflow: id,
|
|
34
|
+
message: 'No description: say what the workflow does and when to run it',
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
return issues;
|
|
38
|
+
}
|
|
39
|
+
const fromCommand = (name, startedAt, { command, exitCode, output }) => exitCode === 0
|
|
40
|
+
? { name, status: 'passed', durationMs: Date.now() - startedAt, command }
|
|
41
|
+
: {
|
|
42
|
+
name,
|
|
43
|
+
status: 'failed',
|
|
44
|
+
durationMs: Date.now() - startedAt,
|
|
45
|
+
command,
|
|
46
|
+
reason: `\`${command}\` exited with ${exitCode}`,
|
|
47
|
+
output: tail(output),
|
|
48
|
+
};
|
|
49
|
+
const skipped = (name, reason) => ({
|
|
50
|
+
name,
|
|
51
|
+
status: 'skipped',
|
|
52
|
+
durationMs: 0,
|
|
53
|
+
reason,
|
|
54
|
+
});
|
|
55
|
+
async function checkTypes(projectDir) {
|
|
56
|
+
const startedAt = Date.now();
|
|
57
|
+
if (readProjectScripts(projectDir)['check-types'])
|
|
58
|
+
return fromCommand('types', startedAt, await runProjectScript(projectDir, 'check-types'));
|
|
59
|
+
const tsc = path.join(projectDir, 'node_modules', '.bin', 'tsc');
|
|
60
|
+
if (!fs.existsSync(tsc))
|
|
61
|
+
return skipped('types', 'No `check-types` script and no local `tsc`');
|
|
62
|
+
return fromCommand('types', startedAt, await runCommand(tsc, ['--noEmit'], projectDir));
|
|
63
|
+
}
|
|
64
|
+
/** Runs the project's own lint: the CLI does not ship or pick the rules. */
|
|
65
|
+
async function checkLint(projectDir) {
|
|
66
|
+
if (!readProjectScripts(projectDir).lint)
|
|
67
|
+
return skipped('lint', 'No `lint` script; add one with @t4h.framework/eslint-plugin to catch non-deterministic workflows');
|
|
68
|
+
const startedAt = Date.now();
|
|
69
|
+
return fromCommand('lint', startedAt, await runProjectScript(projectDir, 'lint'));
|
|
70
|
+
}
|
|
71
|
+
async function checkManifest(options) {
|
|
72
|
+
const startedAt = Date.now();
|
|
73
|
+
let app = null;
|
|
74
|
+
try {
|
|
75
|
+
const { HeadlessApp } = await loadDev(toProjectDir(options.entrypoint), [
|
|
76
|
+
'HeadlessApp',
|
|
77
|
+
]);
|
|
78
|
+
app = await HeadlessApp.up({
|
|
79
|
+
entrypoint: options.entrypoint,
|
|
80
|
+
env: options.env,
|
|
81
|
+
});
|
|
82
|
+
const issues = validateManifest(app.manifest);
|
|
83
|
+
const failed = issues.some(({ level }) => level === 'error');
|
|
84
|
+
return {
|
|
85
|
+
name: 'manifest',
|
|
86
|
+
status: failed ? 'failed' : 'passed',
|
|
87
|
+
durationMs: Date.now() - startedAt,
|
|
88
|
+
issues,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
const details = error.details;
|
|
93
|
+
return {
|
|
94
|
+
name: 'manifest',
|
|
95
|
+
status: 'failed',
|
|
96
|
+
durationMs: Date.now() - startedAt,
|
|
97
|
+
reason: `The app did not build or boot: ${error instanceof Error ? error.message : String(error)}${details?.diagnostics ? '' : ' (the app error is on stderr; a missing variable needs -e or --env-file-if-exists)'}`,
|
|
98
|
+
output: details?.diagnostics
|
|
99
|
+
? tail(details.diagnostics.join('\n'))
|
|
100
|
+
: undefined,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
finally {
|
|
104
|
+
await app?.down().catch(() => { });
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
async function checkTest(projectDir) {
|
|
108
|
+
if (!readProjectScripts(projectDir).test)
|
|
109
|
+
return skipped('test', 'No `test` script');
|
|
110
|
+
const startedAt = Date.now();
|
|
111
|
+
return fromCommand('test', startedAt, await runProjectScript(projectDir, 'test'));
|
|
112
|
+
}
|
|
113
|
+
export async function runCheck(options, onStep = () => { }) {
|
|
114
|
+
const projectDir = toProjectDir(options.entrypoint);
|
|
115
|
+
const run = {
|
|
116
|
+
types: () => checkTypes(projectDir),
|
|
117
|
+
lint: () => checkLint(projectDir),
|
|
118
|
+
manifest: () => checkManifest(options),
|
|
119
|
+
test: () => checkTest(projectDir),
|
|
120
|
+
};
|
|
121
|
+
const steps = [];
|
|
122
|
+
for (const name of CHECK_STEPS) {
|
|
123
|
+
const step = options.skip.includes(name) ||
|
|
124
|
+
(options.only && !options.only.includes(name))
|
|
125
|
+
? skipped(name, 'Skipped by option')
|
|
126
|
+
: await run[name]();
|
|
127
|
+
steps.push(step);
|
|
128
|
+
onStep(step);
|
|
129
|
+
}
|
|
130
|
+
return { ok: steps.every(({ status }) => status !== 'failed'), steps };
|
|
131
|
+
}
|
|
132
|
+
const STATUS_MARK = {
|
|
133
|
+
passed: '✔',
|
|
134
|
+
failed: '✖',
|
|
135
|
+
skipped: '-',
|
|
136
|
+
};
|
|
137
|
+
export function formatCheckStep(step) {
|
|
138
|
+
const lines = [
|
|
139
|
+
`${STATUS_MARK[step.status]} ${step.name}${step.status === 'skipped' ? '' : ` (${(step.durationMs / 1000).toFixed(1)}s)`}${step.reason ? ` — ${step.reason}` : ''}`,
|
|
140
|
+
];
|
|
141
|
+
for (const issue of step.issues ?? [])
|
|
142
|
+
lines.push(` ${issue.level}${issue.workflow ? ` [${issue.workflow}]` : ''}: ${issue.message}`);
|
|
143
|
+
if (step.output)
|
|
144
|
+
lines.push(step.output
|
|
145
|
+
.split('\n')
|
|
146
|
+
.map(line => ` ${line}`)
|
|
147
|
+
.join('\n'));
|
|
148
|
+
return lines.join('\n');
|
|
149
|
+
}
|
|
150
|
+
const stepsParser = (value) => {
|
|
151
|
+
const names = value.split(',').map(name => name.trim());
|
|
152
|
+
for (const name of names)
|
|
153
|
+
if (!CHECK_STEPS.includes(name))
|
|
154
|
+
throw new Error(`Unknown step: ${name} (expected ${CHECK_STEPS.join(', ')})`);
|
|
155
|
+
return names;
|
|
156
|
+
};
|
|
157
|
+
export const checkCommand = new Command('check')
|
|
158
|
+
.description('Type-check, lint, boot the app and validate its workflows, then run the tests; one verdict for CI and AI agents')
|
|
159
|
+
.option('--entrypoint <entrypoint path>', 'The entrypoint package json path', './package.json')
|
|
160
|
+
.addOption(new Option('-e, --env <envs..>', 'The env secrets (NAME=value)')
|
|
161
|
+
.argParser((value, previous) => {
|
|
162
|
+
const index = value.indexOf('=');
|
|
163
|
+
if (index < 1)
|
|
164
|
+
throw new Error('Invalid secret format');
|
|
165
|
+
return { ...previous, [value.slice(0, index)]: value.slice(index + 1) };
|
|
166
|
+
})
|
|
167
|
+
.default({}))
|
|
168
|
+
.addOption(new Option('--env-file-if-exists <file-path>', 'Load variables from a .env file if it exists').argParser(value => path.resolve(process.cwd(), value)))
|
|
169
|
+
.addOption(new Option('--only <steps>', `Run only these steps (${CHECK_STEPS.join(',')})`).argParser(stepsParser))
|
|
170
|
+
.addOption(new Option('--skip <steps>', 'Skip these steps')
|
|
171
|
+
.argParser(stepsParser)
|
|
172
|
+
.default([]))
|
|
173
|
+
.option('--json', 'Print one JSON result instead of readable lines', false)
|
|
174
|
+
.action(async (options) => {
|
|
175
|
+
if (options.envFileIfExists && fs.existsSync(options.envFileIfExists))
|
|
176
|
+
Object.assign(options.env, parseEnv(fs.readFileSync(options.envFileIfExists, 'utf8')));
|
|
177
|
+
const result = await runCheck(options, step => {
|
|
178
|
+
if (!options.json)
|
|
179
|
+
process.stdout.write(`${formatCheckStep(step)}\n`);
|
|
180
|
+
});
|
|
181
|
+
if (options.json)
|
|
182
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
183
|
+
process.exit(result.ok ? 0 : 1);
|
|
184
|
+
});
|
|
185
|
+
//# sourceMappingURL=check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check.js","sourceRoot":"","sources":["../../../src/commands/check/check.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/dev/dev.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { parseEnv } from 'node:util';
|
|
4
|
-
import { Server } from '@t4h.framework/dev';
|
|
5
4
|
import { Command, Option } from 'commander';
|
|
6
5
|
import { debugLogOption, debugOption, toDebugLog, } from '../../tools/debug-log-option.js';
|
|
6
|
+
import { loadDev, toProjectDir } from '../../tools/load-dev.js';
|
|
7
7
|
export const devCommand = new Command('dev')
|
|
8
8
|
.description('Start the development server')
|
|
9
9
|
.option('--entrypoint <entrypoint path>', 'The entrypoint package json path', './package.json')
|
|
@@ -31,6 +31,9 @@ export const devCommand = new Command('dev')
|
|
|
31
31
|
.action(async (options) => {
|
|
32
32
|
if (options.envFileIfExists && fs.existsSync(options.envFileIfExists))
|
|
33
33
|
Object.assign(options.env, parseEnv(fs.readFileSync(options.envFileIfExists, 'utf8')));
|
|
34
|
+
const { Server } = await loadDev(toProjectDir(options.entrypoint), [
|
|
35
|
+
'Server',
|
|
36
|
+
]);
|
|
34
37
|
const server = new Server({
|
|
35
38
|
entrypoint: options.entrypoint,
|
|
36
39
|
env: options.env,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev.js","sourceRoot":"","sources":["../../../src/commands/dev/dev.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAA;AACxB,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AAEpC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"dev.js","sourceRoot":"","sources":["../../../src/commands/dev/dev.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import readline from 'node:readline';
|
|
2
|
+
/** MCP revisions this server speaks, newest first. */
|
|
3
|
+
export const MCP_PROTOCOL_VERSIONS = [
|
|
4
|
+
'2025-11-25',
|
|
5
|
+
'2025-06-18',
|
|
6
|
+
'2025-03-26',
|
|
7
|
+
'2024-11-05',
|
|
8
|
+
];
|
|
9
|
+
export const JSON_RPC_ERROR = {
|
|
10
|
+
parseError: -32700,
|
|
11
|
+
invalidRequest: -32600,
|
|
12
|
+
methodNotFound: -32601,
|
|
13
|
+
invalidParams: -32602,
|
|
14
|
+
internalError: -32603,
|
|
15
|
+
};
|
|
16
|
+
/** A JSON-RPC error answered as is, e.g. invalid params. */
|
|
17
|
+
export class JsonRpcError extends Error {
|
|
18
|
+
code;
|
|
19
|
+
data;
|
|
20
|
+
name = 'JsonRpcError';
|
|
21
|
+
constructor(code, message, data) {
|
|
22
|
+
super(message);
|
|
23
|
+
this.code = code;
|
|
24
|
+
this.data = data;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
const toText = (value) => typeof value === 'string' ? value : JSON.stringify(value, null, 2);
|
|
28
|
+
/** `{ message, status?, details? }` of any error, for the agent to act on. */
|
|
29
|
+
export function toToolError(error) {
|
|
30
|
+
if (!(error instanceof Error))
|
|
31
|
+
return { error: { message: String(error) } };
|
|
32
|
+
const { status, details } = error;
|
|
33
|
+
return {
|
|
34
|
+
error: {
|
|
35
|
+
message: error.message,
|
|
36
|
+
...(status !== undefined && status !== null ? { status } : {}),
|
|
37
|
+
...(details !== undefined && details !== null ? { details } : {}),
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
const isObject = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
42
|
+
const JSON_TYPES = {
|
|
43
|
+
string: value => typeof value === 'string',
|
|
44
|
+
boolean: value => typeof value === 'boolean',
|
|
45
|
+
number: value => typeof value === 'number' && Number.isFinite(value),
|
|
46
|
+
integer: value => Number.isInteger(value),
|
|
47
|
+
object: isObject,
|
|
48
|
+
array: Array.isArray,
|
|
49
|
+
};
|
|
50
|
+
/** Checks the required and top-level typed properties of the arguments. */
|
|
51
|
+
export function checkToolArguments(schema, args) {
|
|
52
|
+
const problems = [];
|
|
53
|
+
const properties = (schema.properties ?? {});
|
|
54
|
+
for (const name of (schema.required ?? []))
|
|
55
|
+
if (args[name] === undefined)
|
|
56
|
+
problems.push(`${name} is required`);
|
|
57
|
+
for (const [name, value] of Object.entries(args)) {
|
|
58
|
+
const property = properties[name];
|
|
59
|
+
if (value === undefined)
|
|
60
|
+
continue;
|
|
61
|
+
if (!property) {
|
|
62
|
+
if (schema.additionalProperties === false)
|
|
63
|
+
problems.push(`${name} is not a known argument`);
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
if (property.type && !JSON_TYPES[property.type]?.(value))
|
|
67
|
+
problems.push(`${name} must be of type ${property.type}`);
|
|
68
|
+
else if (property.enum && !property.enum.includes(value))
|
|
69
|
+
problems.push(`${name} must be one of ${property.enum.join(', ')}`);
|
|
70
|
+
}
|
|
71
|
+
return problems;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* The Model Context Protocol over JSON-RPC 2.0: lifecycle, ping and tools.
|
|
75
|
+
* Transport-free, so tests hand it messages directly.
|
|
76
|
+
*/
|
|
77
|
+
export class McpServer {
|
|
78
|
+
options;
|
|
79
|
+
tools;
|
|
80
|
+
constructor(options) {
|
|
81
|
+
this.options = options;
|
|
82
|
+
this.tools = new Map(options.tools.map(tool => [tool.name, tool]));
|
|
83
|
+
}
|
|
84
|
+
/** Answers one message (or batch); `null` for notifications and responses. */
|
|
85
|
+
async handle(message) {
|
|
86
|
+
if (Array.isArray(message)) {
|
|
87
|
+
if (!message.length)
|
|
88
|
+
return this.error(null, JSON_RPC_ERROR.invalidRequest, 'Empty batch');
|
|
89
|
+
const responses = (await Promise.all(message.map(item => this.handleOne(item)))).filter(response => response !== null);
|
|
90
|
+
return responses.length ? responses : null;
|
|
91
|
+
}
|
|
92
|
+
return this.handleOne(message);
|
|
93
|
+
}
|
|
94
|
+
/** Parses one line of the stdio transport and answers it. */
|
|
95
|
+
async handleLine(line) {
|
|
96
|
+
let message;
|
|
97
|
+
try {
|
|
98
|
+
message = JSON.parse(line);
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
return this.error(null, JSON_RPC_ERROR.parseError, `Parse error: ${error.message}`);
|
|
102
|
+
}
|
|
103
|
+
return this.handle(message);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Newline-delimited JSON on `input` / `output` (the MCP stdio transport).
|
|
107
|
+
* Requests are answered as they finish, so `ping` is not stuck behind a
|
|
108
|
+
* long tool call. Resolves when `input` ends.
|
|
109
|
+
*/
|
|
110
|
+
async serve(input, output) {
|
|
111
|
+
const lines = readline.createInterface({ input, crlfDelay: Infinity });
|
|
112
|
+
const pending = new Set();
|
|
113
|
+
for await (const line of lines) {
|
|
114
|
+
if (!line.trim())
|
|
115
|
+
continue;
|
|
116
|
+
const answer = this.handleLine(line)
|
|
117
|
+
.then(response => {
|
|
118
|
+
if (response !== null)
|
|
119
|
+
output.write(`${JSON.stringify(response)}\n`);
|
|
120
|
+
})
|
|
121
|
+
.catch(error => this.options.log?.(`[mcp] ${String(error)}`))
|
|
122
|
+
.finally(() => pending.delete(answer));
|
|
123
|
+
pending.add(answer);
|
|
124
|
+
}
|
|
125
|
+
await Promise.all(pending);
|
|
126
|
+
}
|
|
127
|
+
async handleOne(message) {
|
|
128
|
+
if (!isObject(message))
|
|
129
|
+
return this.error(null, JSON_RPC_ERROR.invalidRequest, 'Invalid Request: not an object');
|
|
130
|
+
const { jsonrpc, id, method, params } = message;
|
|
131
|
+
const isRequest = id !== undefined;
|
|
132
|
+
// A response to a request of ours: the server sends none, so drop it.
|
|
133
|
+
if (method === undefined && ('result' in message || 'error' in message))
|
|
134
|
+
return null;
|
|
135
|
+
if (jsonrpc !== '2.0' ||
|
|
136
|
+
typeof method !== 'string' ||
|
|
137
|
+
(isRequest && typeof id !== 'string' && typeof id !== 'number'))
|
|
138
|
+
return this.error(typeof id === 'string' || typeof id === 'number' ? id : null, JSON_RPC_ERROR.invalidRequest, 'Invalid Request');
|
|
139
|
+
if (!isRequest) {
|
|
140
|
+
// `notifications/initialized`, `notifications/cancelled`, …: nothing to do.
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
const requestId = id;
|
|
144
|
+
try {
|
|
145
|
+
return {
|
|
146
|
+
jsonrpc: '2.0',
|
|
147
|
+
id: requestId,
|
|
148
|
+
result: await this.dispatch(method, params),
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
catch (error) {
|
|
152
|
+
if (error instanceof JsonRpcError)
|
|
153
|
+
return this.error(requestId, error.code, error.message, error.data);
|
|
154
|
+
this.options.log?.(`[mcp] ${method} failed: ${error instanceof Error ? (error.stack ?? error.message) : String(error)}`);
|
|
155
|
+
return this.error(requestId, JSON_RPC_ERROR.internalError, error instanceof Error ? error.message : String(error));
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
dispatch(method, params) {
|
|
159
|
+
switch (method) {
|
|
160
|
+
case 'initialize':
|
|
161
|
+
return this.initialize(params);
|
|
162
|
+
case 'ping':
|
|
163
|
+
return {};
|
|
164
|
+
case 'tools/list':
|
|
165
|
+
return {
|
|
166
|
+
tools: [...this.tools.values()].map(({ name, description, inputSchema }) => ({
|
|
167
|
+
name,
|
|
168
|
+
description,
|
|
169
|
+
inputSchema,
|
|
170
|
+
})),
|
|
171
|
+
};
|
|
172
|
+
case 'tools/call':
|
|
173
|
+
return this.callTool(params);
|
|
174
|
+
default:
|
|
175
|
+
throw new JsonRpcError(JSON_RPC_ERROR.methodNotFound, `Method not found: ${method}`);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
initialize(params) {
|
|
179
|
+
const requested = isObject(params) ? params.protocolVersion : undefined;
|
|
180
|
+
const protocolVersion = MCP_PROTOCOL_VERSIONS.find(version => version === requested);
|
|
181
|
+
return {
|
|
182
|
+
protocolVersion: protocolVersion ?? MCP_PROTOCOL_VERSIONS[0],
|
|
183
|
+
capabilities: { tools: { listChanged: false } },
|
|
184
|
+
serverInfo: { name: this.options.name, version: this.options.version },
|
|
185
|
+
...(this.options.instructions
|
|
186
|
+
? { instructions: this.options.instructions }
|
|
187
|
+
: {}),
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
async callTool(params) {
|
|
191
|
+
if (!isObject(params) || typeof params.name !== 'string')
|
|
192
|
+
throw new JsonRpcError(JSON_RPC_ERROR.invalidParams, 'tools/call needs params.name');
|
|
193
|
+
const tool = this.tools.get(params.name);
|
|
194
|
+
if (!tool)
|
|
195
|
+
throw new JsonRpcError(JSON_RPC_ERROR.invalidParams, `Unknown tool: ${params.name}`, { tools: [...this.tools.keys()] });
|
|
196
|
+
const args = params.arguments ?? {};
|
|
197
|
+
if (!isObject(args))
|
|
198
|
+
throw new JsonRpcError(JSON_RPC_ERROR.invalidParams, 'tools/call params.arguments must be an object');
|
|
199
|
+
// Bad arguments are a tool error, so the agent reads them and retries.
|
|
200
|
+
const problems = checkToolArguments(tool.inputSchema, args);
|
|
201
|
+
if (problems.length)
|
|
202
|
+
return {
|
|
203
|
+
content: [
|
|
204
|
+
{
|
|
205
|
+
type: 'text',
|
|
206
|
+
text: toText({
|
|
207
|
+
error: {
|
|
208
|
+
message: `Invalid arguments for ${tool.name}: ${problems.join('; ')}`,
|
|
209
|
+
},
|
|
210
|
+
}),
|
|
211
|
+
},
|
|
212
|
+
],
|
|
213
|
+
isError: true,
|
|
214
|
+
};
|
|
215
|
+
try {
|
|
216
|
+
return {
|
|
217
|
+
content: [{ type: 'text', text: toText(await tool.call(args)) }],
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
catch (error) {
|
|
221
|
+
return {
|
|
222
|
+
content: [{ type: 'text', text: toText(toToolError(error)) }],
|
|
223
|
+
isError: true,
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
error(id, code, message, data) {
|
|
228
|
+
return {
|
|
229
|
+
jsonrpc: '2.0',
|
|
230
|
+
id,
|
|
231
|
+
error: { code, message, ...(data !== undefined ? { data } : {}) },
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
//# sourceMappingURL=mcp-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-server.js","sourceRoot":"","sources":["../../../src/commands/mcp/mcp-server.ts"],"names":[],"mappings":"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"}
|