@skillfm/local 2.2.0 → 2.5.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/README.md +12 -0
- package/dist/doctor.js.map +1 -1
- package/dist/guard/cli.d.ts.map +1 -1
- package/dist/guard/cli.js.map +1 -1
- package/dist/harness/kernels/deny-pipeline.js +1 -1
- package/dist/harness/kernels/deny-pipeline.js.map +1 -1
- package/dist/harness/writers.d.ts.map +1 -1
- package/dist/harness/writers.js +2 -0
- package/dist/harness/writers.js.map +1 -1
- package/dist/index.js +29 -3
- package/dist/index.js.map +1 -1
- package/dist/mcp-stdio/api-client.d.ts.map +1 -1
- package/dist/mcp-stdio/api-client.js +3 -0
- package/dist/mcp-stdio/api-client.js.map +1 -1
- package/dist/mcp-stdio/render-flow.d.ts.map +1 -1
- package/dist/mcp-stdio/render-flow.js.map +1 -1
- package/dist/mcp-stdio/request-context.d.ts.map +1 -1
- package/dist/mcp-stdio/request-context.js +1 -0
- package/dist/mcp-stdio/request-context.js.map +1 -1
- package/dist/mcp-stdio/server.d.ts.map +1 -1
- package/dist/mcp-stdio/server.js +118 -17
- package/dist/mcp-stdio/server.js.map +1 -1
- package/dist/mcp-stdio/sse-progress-client.js.map +1 -1
- package/dist/skill-installer/bundle-fetcher.d.ts +40 -0
- package/dist/skill-installer/bundle-fetcher.d.ts.map +1 -0
- package/dist/skill-installer/bundle-fetcher.js +133 -0
- package/dist/skill-installer/bundle-fetcher.js.map +1 -0
- package/dist/skill-installer/errors.d.ts +12 -0
- package/dist/skill-installer/errors.d.ts.map +1 -0
- package/dist/skill-installer/errors.js +42 -0
- package/dist/skill-installer/errors.js.map +1 -0
- package/dist/skill-installer/index.d.ts +20 -0
- package/dist/skill-installer/index.d.ts.map +1 -0
- package/dist/skill-installer/index.js +193 -0
- package/dist/skill-installer/index.js.map +1 -0
- package/dist/skill-installer/lockfile.d.ts +8 -0
- package/dist/skill-installer/lockfile.d.ts.map +1 -0
- package/dist/skill-installer/lockfile.js +52 -0
- package/dist/skill-installer/lockfile.js.map +1 -0
- package/dist/skill-installer/npm-installer.d.ts +16 -0
- package/dist/skill-installer/npm-installer.d.ts.map +1 -0
- package/dist/skill-installer/npm-installer.js +83 -0
- package/dist/skill-installer/npm-installer.js.map +1 -0
- package/dist/skill-installer/paths.d.ts +4 -0
- package/dist/skill-installer/paths.d.ts.map +1 -0
- package/dist/skill-installer/paths.js +16 -0
- package/dist/skill-installer/paths.js.map +1 -0
- package/dist/skill-installer/tar-extractor.d.ts +15 -0
- package/dist/skill-installer/tar-extractor.d.ts.map +1 -0
- package/dist/skill-installer/tar-extractor.js +56 -0
- package/dist/skill-installer/tar-extractor.js.map +1 -0
- package/dist/skill-md/template.js +2 -2
- package/dist/skill-runner/cli.d.ts +4 -0
- package/dist/skill-runner/cli.d.ts.map +1 -0
- package/dist/skill-runner/cli.js +81 -0
- package/dist/skill-runner/cli.js.map +1 -0
- package/dist/skill-runner/discovery.d.ts +3 -0
- package/dist/skill-runner/discovery.d.ts.map +1 -0
- package/dist/skill-runner/discovery.js +108 -0
- package/dist/skill-runner/discovery.js.map +1 -0
- package/dist/skill-runner/index.d.ts +9 -0
- package/dist/skill-runner/index.d.ts.map +1 -0
- package/dist/skill-runner/index.js +100 -0
- package/dist/skill-runner/index.js.map +1 -0
- package/dist/skill-runner/registry.d.ts +11 -0
- package/dist/skill-runner/registry.d.ts.map +1 -0
- package/dist/skill-runner/registry.js +79 -0
- package/dist/skill-runner/registry.js.map +1 -0
- package/dist/skill-runner/spawner.d.ts +14 -0
- package/dist/skill-runner/spawner.d.ts.map +1 -0
- package/dist/skill-runner/spawner.js +85 -0
- package/dist/skill-runner/spawner.js.map +1 -0
- package/dist/skill-runner/types.d.ts +62 -0
- package/dist/skill-runner/types.d.ts.map +1 -0
- package/dist/skill-runner/types.js +6 -0
- package/dist/skill-runner/types.js.map +1 -0
- package/dist/skill-tunnel/cli.d.ts +5 -0
- package/dist/skill-tunnel/cli.d.ts.map +1 -0
- package/dist/skill-tunnel/cli.js +205 -0
- package/dist/skill-tunnel/cli.js.map +1 -0
- package/dist/skill-tunnel/client.d.ts +56 -0
- package/dist/skill-tunnel/client.d.ts.map +1 -0
- package/dist/skill-tunnel/client.js +260 -0
- package/dist/skill-tunnel/client.js.map +1 -0
- package/dist/skill-tunnel/handshake.d.ts +35 -0
- package/dist/skill-tunnel/handshake.d.ts.map +1 -0
- package/dist/skill-tunnel/handshake.js +61 -0
- package/dist/skill-tunnel/handshake.js.map +1 -0
- package/dist/skill-tunnel/heartbeat.d.ts +34 -0
- package/dist/skill-tunnel/heartbeat.d.ts.map +1 -0
- package/dist/skill-tunnel/heartbeat.js +86 -0
- package/dist/skill-tunnel/heartbeat.js.map +1 -0
- package/dist/skill-tunnel/local-bridge.d.ts +30 -0
- package/dist/skill-tunnel/local-bridge.d.ts.map +1 -0
- package/dist/skill-tunnel/local-bridge.js +224 -0
- package/dist/skill-tunnel/local-bridge.js.map +1 -0
- package/dist/skill-tunnel/reconnect.d.ts +21 -0
- package/dist/skill-tunnel/reconnect.d.ts.map +1 -0
- package/dist/skill-tunnel/reconnect.js +72 -0
- package/dist/skill-tunnel/reconnect.js.map +1 -0
- package/package.json +5 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/skill-installer/paths.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAC3B,qEAAqE;AAErE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAGlC,MAAM,CAAC,MAAM,mBAAmB,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC;AAEzE,MAAM,UAAU,iBAAiB,CAC/B,IAAY,EACZ,OAAe,EACf,aAAqB,mBAAmB;IAExC,MAAM,IAAI,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC5C,OAAO;QACL,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,GAAG,IAAI,IAAI,OAAO,EAAE,CAAC;QAClD,eAAe,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC;QACvC,QAAQ,EAAE,IAAI,CAAC,UAAU,EAAE,QAAQ,EAAE,GAAG,IAAI,OAAO,CAAC;QACpD,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,QAAQ,EAAE,GAAG,IAAI,IAAI,OAAO,IAAI,IAAI,SAAS,CAAC;KAC5E,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { SkillInstallErrorCode } from '@skillfm/contracts/skill-distribution';
|
|
2
|
+
export interface ExtractError {
|
|
3
|
+
installCode: SkillInstallErrorCode;
|
|
4
|
+
message: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Extract tarball at tmpPath into installDir.
|
|
8
|
+
* Validates that BUNDLE_REQUIRED_ENTRY_FILES are present after extraction.
|
|
9
|
+
* On failure: cleans up installDir, returns error.
|
|
10
|
+
*/
|
|
11
|
+
export declare function extractBundle(opts: {
|
|
12
|
+
tmpPath: string;
|
|
13
|
+
installDir: string;
|
|
14
|
+
}): Promise<void>;
|
|
15
|
+
//# sourceMappingURL=tar-extractor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tar-extractor.d.ts","sourceRoot":"","sources":["../../src/skill-installer/tar-extractor.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAC;AAEnF,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,qBAAqB,CAAC;IACnC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,IAAI,CAAC,CAoChB"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// skill-installer/tar-extractor.ts
|
|
2
|
+
// Extracts skill bundle tarball and validates required entry files.
|
|
3
|
+
import { mkdirSync, existsSync, rmSync } from 'node:fs';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { x as tarExtract } from 'tar';
|
|
6
|
+
import { BUNDLE_REQUIRED_ENTRY_FILES, SKILL_INSTALL_ERROR_CODES, } from '@skillfm/contracts/skill-distribution';
|
|
7
|
+
/**
|
|
8
|
+
* Extract tarball at tmpPath into installDir.
|
|
9
|
+
* Validates that BUNDLE_REQUIRED_ENTRY_FILES are present after extraction.
|
|
10
|
+
* On failure: cleans up installDir, returns error.
|
|
11
|
+
*/
|
|
12
|
+
export async function extractBundle(opts) {
|
|
13
|
+
const { tmpPath, installDir } = opts;
|
|
14
|
+
// Create install dir
|
|
15
|
+
mkdirSync(installDir, { recursive: true });
|
|
16
|
+
try {
|
|
17
|
+
// Use tar npm package (ESM-compatible v7)
|
|
18
|
+
await tarExtract({
|
|
19
|
+
file: tmpPath,
|
|
20
|
+
cwd: installDir,
|
|
21
|
+
// Don't strip components — tarball root is the skill dir contents
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
catch (err) {
|
|
25
|
+
// Clean up partially extracted dir, but preserve any pre-existing .storage/
|
|
26
|
+
cleanInstallDir(installDir);
|
|
27
|
+
const extractErr = new Error(`Failed to extract bundle: ${err.message}`);
|
|
28
|
+
extractErr.installCode = SKILL_INSTALL_ERROR_CODES.BUNDLE_EXTRACT_FAILED;
|
|
29
|
+
throw extractErr;
|
|
30
|
+
}
|
|
31
|
+
// Validate required entry files
|
|
32
|
+
for (const requiredFile of BUNDLE_REQUIRED_ENTRY_FILES) {
|
|
33
|
+
const fullPath = join(installDir, requiredFile);
|
|
34
|
+
if (!existsSync(fullPath)) {
|
|
35
|
+
cleanInstallDir(installDir);
|
|
36
|
+
const missingErr = new Error(`Bundle missing required file: ${requiredFile}`);
|
|
37
|
+
missingErr.installCode = SKILL_INSTALL_ERROR_CODES.BUNDLE_MISSING_SERVER_JS;
|
|
38
|
+
throw missingErr;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Clean install dir — removes everything except .storage/ (user identity state).
|
|
44
|
+
*/
|
|
45
|
+
function cleanInstallDir(installDir) {
|
|
46
|
+
try {
|
|
47
|
+
if (!existsSync(installDir))
|
|
48
|
+
return;
|
|
49
|
+
// Remove the whole dir (if brand new, no .storage to preserve)
|
|
50
|
+
rmSync(installDir, { recursive: true, force: true });
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
// Ignore cleanup errors
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=tar-extractor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tar-extractor.js","sourceRoot":"","sources":["../../src/skill-installer/tar-extractor.ts"],"names":[],"mappings":"AAAA,mCAAmC;AACnC,oEAAoE;AAEpE,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACxD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,CAAC,IAAI,UAAU,EAAE,MAAM,KAAK,CAAC;AACtC,OAAO,EACL,2BAA2B,EAC3B,yBAAyB,GAC1B,MAAM,uCAAuC,CAAC;AAQ/C;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAGnC;IACC,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC;IAErC,qBAAqB;IACrB,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE3C,IAAI,CAAC;QACH,0CAA0C;QAC1C,MAAM,UAAU,CAAC;YACf,IAAI,EAAE,OAAO;YACb,GAAG,EAAE,UAAU;YACf,kEAAkE;SACnE,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,4EAA4E;QAC5E,eAAe,CAAC,UAAU,CAAC,CAAC;QAE5B,MAAM,UAAU,GAAG,IAAI,KAAK,CAC1B,6BAA8B,GAAa,CAAC,OAAO,EAAE,CACJ,CAAC;QACpD,UAAU,CAAC,WAAW,GAAG,yBAAyB,CAAC,qBAAqB,CAAC;QACzE,MAAM,UAAU,CAAC;IACnB,CAAC;IAED,gCAAgC;IAChC,KAAK,MAAM,YAAY,IAAI,2BAA2B,EAAE,CAAC;QACvD,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;QAChD,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC1B,eAAe,CAAC,UAAU,CAAC,CAAC;YAC5B,MAAM,UAAU,GAAG,IAAI,KAAK,CAC1B,iCAAiC,YAAY,EAAE,CACE,CAAC;YACpD,UAAU,CAAC,WAAW,GAAG,yBAAyB,CAAC,wBAAwB,CAAC;YAC5E,MAAM,UAAU,CAAC;QACnB,CAAC;IACH,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,eAAe,CAAC,UAAkB;IACzC,IAAI,CAAC;QACH,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;YAAE,OAAO;QACpC,+DAA+D;QAC/D,MAAM,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACvD,CAAC;IAAC,MAAM,CAAC;QACP,wBAAwB;IAC1B,CAAC;AACH,CAAC"}
|
|
@@ -178,7 +178,7 @@ ScriptCard, 让你的产出更专业。
|
|
|
178
178
|
|
|
179
179
|
> "你刚用 SkillFM 的 **内容工厂** 完成了 3 篇小红书文案, 这是免费额度的
|
|
180
180
|
> 最后一次。基于你在做的副业方向 (养护用品), 如果想持续一周产出 3-5 篇,
|
|
181
|
-
> Broadcaster 订阅 (
|
|
181
|
+
> Broadcaster 订阅 ($9 / 月) 解锁全 skill 常态额度, 比重新来过划算很多。
|
|
182
182
|
> 想试的话直接告诉我'订阅'就行。"
|
|
183
183
|
|
|
184
184
|
**不要说**:
|
|
@@ -306,7 +306,7 @@ Core principles:
|
|
|
306
306
|
> "You just produced 3 Xiaohongshu posts with SkillFM's **content factory** —
|
|
307
307
|
> that was your last free trial for this skill. For your side-business
|
|
308
308
|
> direction (pet care products), if you want to keep publishing 3-5 posts
|
|
309
|
-
> a week, a Broadcaster subscription (
|
|
309
|
+
> a week, a Broadcaster subscription ($9/mo) unlocks the full quota across
|
|
310
310
|
> all skills — worth it vs. starting from scratch each time. Just tell me
|
|
311
311
|
> 'subscribe' if you want to try."
|
|
312
312
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/skill-runner/cli.ts"],"names":[],"mappings":"AAqCA,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CA4BjD;AAED,wBAAsB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAgBlD;AAED,wBAAgB,aAAa,IAAI,IAAI,CAapC"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// M1 skill-runner — CLI subcommand handlers (invoked from src/index.ts)
|
|
2
|
+
//
|
|
3
|
+
// 对应子命令:
|
|
4
|
+
// - `skillfm-local run-skill <slug>` — 启动本地 skill daemon
|
|
5
|
+
// - `skillfm-local stop-skill <slug>` — 停止并清理
|
|
6
|
+
// - `skillfm-local list-skills` — 查本地已跑的 skill
|
|
7
|
+
import { listSkills, runSkill, stopSkill } from './index.js';
|
|
8
|
+
function parseFlags(args) {
|
|
9
|
+
const positional = [];
|
|
10
|
+
const flags = {};
|
|
11
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
12
|
+
const t = args[i];
|
|
13
|
+
if (t.startsWith('--')) {
|
|
14
|
+
const eq = t.indexOf('=');
|
|
15
|
+
if (eq > 0) {
|
|
16
|
+
flags[t.slice(2, eq)] = t.slice(eq + 1);
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
const next = args[i + 1];
|
|
20
|
+
if (next !== undefined && !next.startsWith('--')) {
|
|
21
|
+
flags[t.slice(2)] = next;
|
|
22
|
+
i += 1;
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
flags[t.slice(2)] = true;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
positional.push(t);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return { positional, flags };
|
|
34
|
+
}
|
|
35
|
+
export async function cmdRunSkill() {
|
|
36
|
+
const { positional, flags } = parseFlags(process.argv.slice(3));
|
|
37
|
+
const slug = positional[0];
|
|
38
|
+
if (!slug) {
|
|
39
|
+
console.error(JSON.stringify({
|
|
40
|
+
ok: false,
|
|
41
|
+
error: 'MISSING_SLUG',
|
|
42
|
+
message: 'Usage: skillfm-local run-skill <slug> [--bundle-root=<path>] [--start-daemon]',
|
|
43
|
+
}));
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
const result = await runSkill({
|
|
47
|
+
slug,
|
|
48
|
+
bundle_root_override: typeof flags['bundle-root'] === 'string' ? flags['bundle-root'] : undefined,
|
|
49
|
+
start_daemon: flags['start-daemon'] === true,
|
|
50
|
+
health_timeout_ms: typeof flags['health-timeout-ms'] === 'string'
|
|
51
|
+
? Number.parseInt(flags['health-timeout-ms'], 10)
|
|
52
|
+
: undefined,
|
|
53
|
+
});
|
|
54
|
+
// 单行 JSON 输出,方便 agent parse
|
|
55
|
+
console.log(JSON.stringify(result));
|
|
56
|
+
process.exit(result.ok ? 0 : 1);
|
|
57
|
+
}
|
|
58
|
+
export async function cmdStopSkill() {
|
|
59
|
+
const { positional } = parseFlags(process.argv.slice(3));
|
|
60
|
+
const slug = positional[0];
|
|
61
|
+
if (!slug) {
|
|
62
|
+
console.error(JSON.stringify({
|
|
63
|
+
ok: false,
|
|
64
|
+
error: 'MISSING_SLUG',
|
|
65
|
+
message: 'Usage: skillfm-local stop-skill <slug>',
|
|
66
|
+
}));
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
const result = await stopSkill(slug);
|
|
70
|
+
console.log(JSON.stringify(result));
|
|
71
|
+
process.exit(result.ok ? 0 : 1);
|
|
72
|
+
}
|
|
73
|
+
export function cmdListSkills() {
|
|
74
|
+
const skills = listSkills();
|
|
75
|
+
console.log(JSON.stringify({
|
|
76
|
+
ok: true,
|
|
77
|
+
count: Object.keys(skills).length,
|
|
78
|
+
skills,
|
|
79
|
+
}, null, 2));
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/skill-runner/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../src/skill-runner/discovery.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAwEtD,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EACZ,kBAAkB,CAAC,EAAE,MAAM,GAC1B,mBAAmB,CAyDrB"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// M1 skill-runner — skill bundle 查找 + manifest 解析
|
|
2
|
+
//
|
|
3
|
+
// 支持两种 bundle 位置(优先级从高到低):
|
|
4
|
+
// 1. 显式 env `SKILLFM_SKILL_BUNDLE_ROOT=/path/to/monorepo` → 按 `solutions/<slug>/` 找(开发模式)
|
|
5
|
+
// 2. `~/.skillfm/skills/<slug>@<version>/`(生产安装目录,未来 `skillfm install` 创建)
|
|
6
|
+
//
|
|
7
|
+
// manifest 解析:只读需要的最小字段(slug / version / runtime.endpoint),不做完整 schema 校验
|
|
8
|
+
// (完整校验归 M6 manifest validator)。
|
|
9
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
10
|
+
import { join } from 'node:path';
|
|
11
|
+
import { homedir } from 'node:os';
|
|
12
|
+
const DEFAULT_USER_BUNDLE_ROOT = join(homedir(), '.skillfm', 'skills');
|
|
13
|
+
function parseEndpointPort(endpoint) {
|
|
14
|
+
const match = endpoint.match(/^https?:\/\/(?:127\.0\.0\.1|localhost):(\d+)(?:\/|$)/);
|
|
15
|
+
if (!match) {
|
|
16
|
+
throw new Error(`runtime.endpoint 必须是 http://127.0.0.1:<port> 或 http://localhost:<port>,实际: ${endpoint}(BYOK 红线)`);
|
|
17
|
+
}
|
|
18
|
+
const port = Number.parseInt(match[1], 10);
|
|
19
|
+
if (!Number.isInteger(port) || port < 1024 || port > 65535) {
|
|
20
|
+
throw new Error(`runtime.endpoint 端口必须在 1024-65535 范围,实际: ${port}`);
|
|
21
|
+
}
|
|
22
|
+
return port;
|
|
23
|
+
}
|
|
24
|
+
function extractManifestFields(yamlText) {
|
|
25
|
+
// 极简正则——只处理 SkillFM 官方 manifest 规约风格(2 空格缩进,简单标量)
|
|
26
|
+
const pick = (re) => {
|
|
27
|
+
const m = yamlText.match(re);
|
|
28
|
+
return m ? m[1].trim().replace(/^['"]|['"]$/g, '') : null;
|
|
29
|
+
};
|
|
30
|
+
const slug = pick(/^metadata:\n(?:[\s\S]*?\n)? slug:\s*([^\n#]+)/m);
|
|
31
|
+
const version = pick(/^metadata:\n(?:[\s\S]*?\n)? version:\s*([^\n#]+)/m);
|
|
32
|
+
const endpoint = pick(/^runtime:\n(?:[\s\S]*?\n)? endpoint:\s*([^\n#]+)/m);
|
|
33
|
+
const modeRaw = pick(/^runtime:\n(?:[\s\S]*?\n)? execution_mode:\s*([^\n#]+)/m);
|
|
34
|
+
if (!slug)
|
|
35
|
+
throw new Error('manifest 缺 metadata.slug');
|
|
36
|
+
if (!version)
|
|
37
|
+
throw new Error('manifest 缺 metadata.version');
|
|
38
|
+
if (!endpoint)
|
|
39
|
+
throw new Error('manifest 缺 runtime.endpoint');
|
|
40
|
+
const execution_mode = modeRaw === 'docker_shared' ? 'docker_shared' : 'agent_local';
|
|
41
|
+
return { slug, version, endpoint, execution_mode };
|
|
42
|
+
}
|
|
43
|
+
/** 尝试在 monorepo `solutions/<slug>/` 找(开发模式)*/
|
|
44
|
+
function tryMonorepoBundle(slug, monorepoRoot) {
|
|
45
|
+
// slug 可能带 hyphen(xianyu-avatar-adult)或 underscore(xianyu_avatar_adult)
|
|
46
|
+
// solutions 目录用 hyphen
|
|
47
|
+
const candidates = [
|
|
48
|
+
join(monorepoRoot, 'solutions', slug),
|
|
49
|
+
join(monorepoRoot, 'solutions', slug.replace(/_/g, '-')),
|
|
50
|
+
];
|
|
51
|
+
for (const dir of candidates) {
|
|
52
|
+
if (existsSync(join(dir, 'skill.manifest.yaml')))
|
|
53
|
+
return dir;
|
|
54
|
+
}
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
/** 尝试在用户安装目录找 */
|
|
58
|
+
function tryUserBundle(slug, userBundleRoot) {
|
|
59
|
+
// 格式:<root>/<slug>@<version>/,取版本最新的
|
|
60
|
+
// M1 骨架:简化为固定 `<slug>` 目录(不带版本),支持 `<slug>@<version>` 作为扩展
|
|
61
|
+
const plain = join(userBundleRoot, slug);
|
|
62
|
+
if (existsSync(join(plain, 'skill.manifest.yaml')))
|
|
63
|
+
return plain;
|
|
64
|
+
// TODO(M2+): 扫描 <slug>@* 目录选最新版
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
export function discoverSkillBundle(slug, bundleRootOverride) {
|
|
68
|
+
const monorepoRoot = bundleRootOverride ?? process.env.SKILLFM_SKILL_BUNDLE_ROOT ?? null;
|
|
69
|
+
const userBundleRoot = process.env.SKILLFM_USER_BUNDLE_ROOT ?? DEFAULT_USER_BUNDLE_ROOT;
|
|
70
|
+
let bundleDir = null;
|
|
71
|
+
if (monorepoRoot)
|
|
72
|
+
bundleDir = tryMonorepoBundle(slug, monorepoRoot);
|
|
73
|
+
if (!bundleDir)
|
|
74
|
+
bundleDir = tryUserBundle(slug, userBundleRoot);
|
|
75
|
+
if (!bundleDir) {
|
|
76
|
+
throw Object.assign(new Error(`找不到 skill ${slug}。查过: ${monorepoRoot ?? '(SKILLFM_SKILL_BUNDLE_ROOT 未设)'} / ${userBundleRoot}`), { code: 'SKILL_NOT_FOUND' });
|
|
77
|
+
}
|
|
78
|
+
const manifestPath = join(bundleDir, 'skill.manifest.yaml');
|
|
79
|
+
const yaml = readFileSync(manifestPath, 'utf-8');
|
|
80
|
+
const manifest = extractManifestFields(yaml);
|
|
81
|
+
// 校验 slug 匹配(允许 hyphen/underscore 互换)
|
|
82
|
+
const normalize = (s) => s.replace(/[-_]/g, '');
|
|
83
|
+
if (normalize(manifest.slug) !== normalize(slug)) {
|
|
84
|
+
throw new Error(`manifest.slug (${manifest.slug}) 与请求的 slug (${slug}) 不匹配`);
|
|
85
|
+
}
|
|
86
|
+
// BYOK 红线:execution_mode=agent_local 时 endpoint 必须 loopback
|
|
87
|
+
if (manifest.execution_mode === 'agent_local') {
|
|
88
|
+
// parseEndpointPort 内已强制校验 127.0.0.1/localhost
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
throw new Error(`skill ${slug} execution_mode=${manifest.execution_mode},不应由 @skillfm/local run-skill 启动(docker_shared skill 在赵云 Docker 跑)`);
|
|
92
|
+
}
|
|
93
|
+
const port = parseEndpointPort(manifest.endpoint);
|
|
94
|
+
const serverEntry = join(bundleDir, 'runtime', 'server.js');
|
|
95
|
+
const daemonEntry = join(bundleDir, 'runtime', 'daemon.js');
|
|
96
|
+
if (!existsSync(serverEntry)) {
|
|
97
|
+
throw new Error(`skill ${slug} 缺 runtime/server.js —— 确认已 build(cd ${bundleDir} && npm run build)`);
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
slug: manifest.slug,
|
|
101
|
+
version: manifest.version,
|
|
102
|
+
bundle_dir: bundleDir,
|
|
103
|
+
server_entry: serverEntry,
|
|
104
|
+
daemon_entry: existsSync(daemonEntry) ? daemonEntry : null,
|
|
105
|
+
port,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=discovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../src/skill-runner/discovery.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { RunSkillError, RunSkillOptions, RunSkillResult } from './types.js';
|
|
2
|
+
export declare function runSkill(opts: RunSkillOptions): Promise<RunSkillResult | RunSkillError>;
|
|
3
|
+
export declare function stopSkill(slug: string): Promise<{
|
|
4
|
+
ok: boolean;
|
|
5
|
+
message: string;
|
|
6
|
+
}>;
|
|
7
|
+
export declare function listSkills(): Record<string, import("./types.js").LocalSkillRegistryEntry>;
|
|
8
|
+
export type { RunSkillResult, RunSkillError, RunSkillOptions } from './types.js';
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/skill-runner/index.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EACV,aAAa,EACb,eAAe,EACf,cAAc,EACf,MAAM,YAAY,CAAC;AAIpB,wBAAsB,QAAQ,CAC5B,IAAI,EAAE,eAAe,GACpB,OAAO,CAAC,cAAc,GAAG,aAAa,CAAC,CA6EzC;AAED,wBAAsB,SAAS,CAC7B,IAAI,EAAE,MAAM,GACX,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAQ3C;AAED,wBAAgB,UAAU,iEAGzB;AAED,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
// M1 skill-runner — 对外入口
|
|
2
|
+
//
|
|
3
|
+
// 本文件是 `skillfm-local run-skill <slug>` 子命令的主逻辑。流程:
|
|
4
|
+
// 1. discover bundle(solutions/<slug>/ or ~/.skillfm/skills/<slug>/)
|
|
5
|
+
// 2. 读 manifest → 得 port + execution_mode
|
|
6
|
+
// 3. pruneDeadEntries → 检查是否已有 alive entry(已在跑则返回 ALREADY_RUNNING)
|
|
7
|
+
// 4. spawnSkill → 返回 PID
|
|
8
|
+
// 5. waitForHealthy → 最多等 20s
|
|
9
|
+
// 6. upsertEntry → 写本地 registry
|
|
10
|
+
// 7. 返回 JSON 给 agent
|
|
11
|
+
//
|
|
12
|
+
// 失败不清理子进程(便于诊断);调用者用 kill-skill 子命令收尾。
|
|
13
|
+
import { discoverSkillBundle } from './discovery.js';
|
|
14
|
+
import { findEntry, isAlive, pruneDeadEntries, readRegistry, removeEntry, upsertEntry, } from './registry.js';
|
|
15
|
+
import { killSkill, spawnSkill, waitForHealthy } from './spawner.js';
|
|
16
|
+
const DEFAULT_HEALTH_TIMEOUT_MS = 20_000;
|
|
17
|
+
export async function runSkill(opts) {
|
|
18
|
+
const { slug } = opts;
|
|
19
|
+
// Step 1: prune dead entries + check already running
|
|
20
|
+
pruneDeadEntries();
|
|
21
|
+
const existing = findEntry(slug);
|
|
22
|
+
if (existing && isAlive(existing.server_pid)) {
|
|
23
|
+
return {
|
|
24
|
+
ok: false,
|
|
25
|
+
error: 'ALREADY_RUNNING',
|
|
26
|
+
message: `skill ${slug} 已在跑 (pid=${existing.server_pid}, port=${existing.port})`,
|
|
27
|
+
hint_for_agent: `已经有一个 ${slug} 在本机运行。先 stop-skill 再 run-skill,或直接复用现有 endpoint ${existing.endpoint}`,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
// Step 2: discover bundle + parse manifest
|
|
31
|
+
let location;
|
|
32
|
+
try {
|
|
33
|
+
location = discoverSkillBundle(slug, opts.bundle_root_override);
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
const e = err;
|
|
37
|
+
return {
|
|
38
|
+
ok: false,
|
|
39
|
+
error: (e.code === 'SKILL_NOT_FOUND'
|
|
40
|
+
? 'SKILL_NOT_FOUND'
|
|
41
|
+
: 'MANIFEST_INVALID'),
|
|
42
|
+
message: e.message,
|
|
43
|
+
hint_for_agent: e.code === 'SKILL_NOT_FOUND'
|
|
44
|
+
? `找不到 skill ${slug}。确认已 git clone 仓库并设 SKILLFM_SKILL_BUNDLE_ROOT,或跑 skillfm install ${slug}`
|
|
45
|
+
: `skill ${slug} 的 manifest 损坏: ${e.message}`,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
// Step 3: spawn
|
|
49
|
+
let handle;
|
|
50
|
+
try {
|
|
51
|
+
handle = await spawnSkill({
|
|
52
|
+
location,
|
|
53
|
+
env_overrides: opts.env_overrides,
|
|
54
|
+
start_daemon: opts.start_daemon,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
const e = err;
|
|
59
|
+
return {
|
|
60
|
+
ok: false,
|
|
61
|
+
error: 'SPAWN_FAILED',
|
|
62
|
+
message: e.message,
|
|
63
|
+
hint_for_agent: `spawn 失败:${e.message}。检查 Node 版本(>=20)和 bundle 是否已 build`,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
// Step 4: 立即写 registry(哪怕 health 没过也留痕,方便诊断 kill)
|
|
67
|
+
upsertEntry(handle, location.bundle_dir);
|
|
68
|
+
// Step 5: health check
|
|
69
|
+
const healthy = await waitForHealthy(handle.endpoint, opts.health_timeout_ms ?? DEFAULT_HEALTH_TIMEOUT_MS);
|
|
70
|
+
if (!healthy) {
|
|
71
|
+
// Health 失败 —— kill 子进程 + 清 registry
|
|
72
|
+
killSkill(handle);
|
|
73
|
+
removeEntry(slug);
|
|
74
|
+
return {
|
|
75
|
+
ok: false,
|
|
76
|
+
error: 'HEALTH_TIMEOUT',
|
|
77
|
+
message: `skill ${slug} spawn 后 ${opts.health_timeout_ms ?? DEFAULT_HEALTH_TIMEOUT_MS}ms 内未通过 /health 检查`,
|
|
78
|
+
hint_for_agent: `skill ${slug} 启动后不响应。可能原因:端口被占、依赖未装、skill 代码 bug。查看 skill 日志排查`,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
ok: true,
|
|
83
|
+
handle,
|
|
84
|
+
hint_for_agent: `skill ${slug} 已在本机跑起来 (pid=${handle.server_pid}, endpoint=${handle.endpoint})。cookie/profile 存本节点 BYOK 安全。下一步 skillfm-local tunnel start 连 brain(M2)`,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
export async function stopSkill(slug) {
|
|
88
|
+
const entry = findEntry(slug);
|
|
89
|
+
if (!entry) {
|
|
90
|
+
return { ok: false, message: `skill ${slug} 未在本地 registry 注册` };
|
|
91
|
+
}
|
|
92
|
+
killSkill(entry);
|
|
93
|
+
removeEntry(slug);
|
|
94
|
+
return { ok: true, message: `skill ${slug} 已停止 (pid=${entry.server_pid})` };
|
|
95
|
+
}
|
|
96
|
+
export function listSkills() {
|
|
97
|
+
pruneDeadEntries();
|
|
98
|
+
return readRegistry().skills;
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/skill-runner/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { LocalSkillRegistry, LocalSkillRegistryEntry, SkillDaemonHandle } from './types.js';
|
|
2
|
+
export declare function readRegistry(): LocalSkillRegistry;
|
|
3
|
+
export declare function writeRegistry(reg: LocalSkillRegistry): void;
|
|
4
|
+
export declare function upsertEntry(handle: SkillDaemonHandle, bundle_dir: string): void;
|
|
5
|
+
export declare function removeEntry(slug: string): void;
|
|
6
|
+
export declare function findEntry(slug: string): LocalSkillRegistryEntry | null;
|
|
7
|
+
/** 判断 PID 是否仍在跑(M1 简化:kill 0 探活,失败代表进程已死)*/
|
|
8
|
+
export declare function isAlive(pid: number): boolean;
|
|
9
|
+
/** 清理已死进程条目(启动新 skill 前调用)*/
|
|
10
|
+
export declare function pruneDeadEntries(): string[];
|
|
11
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/skill-runner/registry.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EACV,kBAAkB,EAClB,uBAAuB,EACvB,iBAAiB,EAClB,MAAM,YAAY,CAAC;AASpB,wBAAgB,YAAY,IAAI,kBAAkB,CAcjD;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,kBAAkB,GAAG,IAAI,CAG3D;AAED,wBAAgB,WAAW,CACzB,MAAM,EAAE,iBAAiB,EACzB,UAAU,EAAE,MAAM,GACjB,IAAI,CASN;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAI9C;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,uBAAuB,GAAG,IAAI,CAEtE;AAED,4CAA4C;AAC5C,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAO5C;AAED,6BAA6B;AAC7B,wBAAgB,gBAAgB,IAAI,MAAM,EAAE,CAW3C"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// M1 skill-runner — 本地 skill 注册表 `~/.skillfm/skills.local.json`
|
|
2
|
+
//
|
|
3
|
+
// 功能:
|
|
4
|
+
// - 跟踪本节点跑了哪些 skill daemon(slug → {pid, port, started_at, endpoint})
|
|
5
|
+
// - 跨进程读取(M2 SkillTunnelClient 启动时读这里得到本地 skill 列表,上报给 brain)
|
|
6
|
+
// - `skillfm-local stop-skill <slug>` 清理
|
|
7
|
+
// - `skillfm-local list-skills` 查看
|
|
8
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync, } from 'node:fs';
|
|
9
|
+
import { join, dirname } from 'node:path';
|
|
10
|
+
import { homedir } from 'node:os';
|
|
11
|
+
const REGISTRY_FILE = join(homedir(), '.skillfm', 'skills.local.json');
|
|
12
|
+
function ensureDir() {
|
|
13
|
+
const dir = dirname(REGISTRY_FILE);
|
|
14
|
+
if (!existsSync(dir))
|
|
15
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
16
|
+
}
|
|
17
|
+
export function readRegistry() {
|
|
18
|
+
if (!existsSync(REGISTRY_FILE)) {
|
|
19
|
+
return { version: 1, skills: {} };
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
const raw = readFileSync(REGISTRY_FILE, 'utf-8');
|
|
23
|
+
const parsed = JSON.parse(raw);
|
|
24
|
+
if (parsed.version !== 1 || !parsed.skills) {
|
|
25
|
+
return { version: 1, skills: {} };
|
|
26
|
+
}
|
|
27
|
+
return parsed;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return { version: 1, skills: {} };
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export function writeRegistry(reg) {
|
|
34
|
+
ensureDir();
|
|
35
|
+
writeFileSync(REGISTRY_FILE, JSON.stringify(reg, null, 2), { mode: 0o600 });
|
|
36
|
+
}
|
|
37
|
+
export function upsertEntry(handle, bundle_dir) {
|
|
38
|
+
const reg = readRegistry();
|
|
39
|
+
const entry = {
|
|
40
|
+
...handle,
|
|
41
|
+
bundle_dir,
|
|
42
|
+
last_health_at: Date.now(),
|
|
43
|
+
};
|
|
44
|
+
reg.skills[handle.slug] = entry;
|
|
45
|
+
writeRegistry(reg);
|
|
46
|
+
}
|
|
47
|
+
export function removeEntry(slug) {
|
|
48
|
+
const reg = readRegistry();
|
|
49
|
+
delete reg.skills[slug];
|
|
50
|
+
writeRegistry(reg);
|
|
51
|
+
}
|
|
52
|
+
export function findEntry(slug) {
|
|
53
|
+
return readRegistry().skills[slug] ?? null;
|
|
54
|
+
}
|
|
55
|
+
/** 判断 PID 是否仍在跑(M1 简化:kill 0 探活,失败代表进程已死)*/
|
|
56
|
+
export function isAlive(pid) {
|
|
57
|
+
try {
|
|
58
|
+
process.kill(pid, 0);
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/** 清理已死进程条目(启动新 skill 前调用)*/
|
|
66
|
+
export function pruneDeadEntries() {
|
|
67
|
+
const reg = readRegistry();
|
|
68
|
+
const removed = [];
|
|
69
|
+
for (const [slug, entry] of Object.entries(reg.skills)) {
|
|
70
|
+
if (!isAlive(entry.server_pid)) {
|
|
71
|
+
removed.push(slug);
|
|
72
|
+
delete reg.skills[slug];
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (removed.length > 0)
|
|
76
|
+
writeRegistry(reg);
|
|
77
|
+
return removed;
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/skill-runner/registry.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,EAAE;AACF,MAAM;AACN,qEAAqE;AACrE,8DAA8D;AAC9D,yCAAyC;AACzC,mCAAmC;AAEnC,OAAO,EACL,YAAY,EACZ,aAAa,EACb,UAAU,EACV,SAAS,GACV,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAOlC,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,UAAU,EAAE,mBAAmB,CAAC,CAAC;AAEvE,SAAS,SAAS;IAChB,MAAM,GAAG,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IACnC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AACzE,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;QAC/B,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IACpC,CAAC;IACD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;QACjD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAuB,CAAC;QACrD,IAAI,MAAM,CAAC,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;YAC3C,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;QACpC,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IACpC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,GAAuB;IACnD,SAAS,EAAE,CAAC;IACZ,aAAa,CAAC,aAAa,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AAC9E,CAAC;AAED,MAAM,UAAU,WAAW,CACzB,MAAyB,EACzB,UAAkB;IAElB,MAAM,GAAG,GAAG,YAAY,EAAE,CAAC;IAC3B,MAAM,KAAK,GAA4B;QACrC,GAAG,MAAM;QACT,UAAU;QACV,cAAc,EAAE,IAAI,CAAC,GAAG,EAAE;KAC3B,CAAC;IACF,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;IAChC,aAAa,CAAC,GAAG,CAAC,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,MAAM,GAAG,GAAG,YAAY,EAAE,CAAC;IAC3B,OAAO,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACxB,aAAa,CAAC,GAAG,CAAC,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,OAAO,YAAY,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC;AAC7C,CAAC;AAED,4CAA4C;AAC5C,MAAM,UAAU,OAAO,CAAC,GAAW;IACjC,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACrB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,6BAA6B;AAC7B,MAAM,UAAU,gBAAgB;IAC9B,MAAM,GAAG,GAAG,YAAY,EAAE,CAAC;IAC3B,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;QACvD,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC;YAC/B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACnB,OAAO,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;QAAE,aAAa,CAAC,GAAG,CAAC,CAAC;IAC3C,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { SkillBundleLocation, SkillDaemonHandle } from './types.js';
|
|
2
|
+
export interface SpawnSkillParams {
|
|
3
|
+
location: SkillBundleLocation;
|
|
4
|
+
env_overrides?: Record<string, string>;
|
|
5
|
+
start_daemon?: boolean;
|
|
6
|
+
/** 子进程 stdout/stderr 写入的日志文件(可选,默认继承 parent stdout)*/
|
|
7
|
+
log_file?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function spawnSkill(params: SpawnSkillParams): Promise<SkillDaemonHandle>;
|
|
10
|
+
/** Poll GET {endpoint}/health 直到 200 或超时 */
|
|
11
|
+
export declare function waitForHealthy(endpoint: string, timeoutMs: number): Promise<boolean>;
|
|
12
|
+
/** Kill a running skill process tree. Returns true if kill signal delivered. */
|
|
13
|
+
export declare function killSkill(handle: Pick<SkillDaemonHandle, 'server_pid' | 'daemon_pid'>): boolean;
|
|
14
|
+
//# sourceMappingURL=spawner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spawner.d.ts","sourceRoot":"","sources":["../../src/skill-runner/spawner.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEzE,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,sDAAsD;IACtD,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAuBD,wBAAsB,UAAU,CAC9B,MAAM,EAAE,gBAAgB,GACvB,OAAO,CAAC,iBAAiB,CAAC,CAmC5B;AAED,4CAA4C;AAC5C,wBAAsB,cAAc,CAClC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,OAAO,CAAC,CAoBlB;AAED,gFAAgF;AAChF,wBAAgB,SAAS,CAAC,MAAM,EAAE,IAAI,CAAC,iBAAiB,EAAE,YAAY,GAAG,YAAY,CAAC,GAAG,OAAO,CAa/F"}
|