@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,224 @@
|
|
|
1
|
+
// M2 SkillTunnelClient — local bridge
|
|
2
|
+
//
|
|
3
|
+
// 职责: 把 brain → agent 的 JSON-RPC request 转成本地 skill daemon 的 HTTP 调用。
|
|
4
|
+
// 跑在 127.0.0.1 loopback,cookie/profile 全部留在本节点 → 守 BYOK 红线。
|
|
5
|
+
//
|
|
6
|
+
// 映射规则 (对齐 BRAIN-SKILL-CONTRACT §3 HTTP 接口):
|
|
7
|
+
// skill.run → POST /v1/skill/run body = params.request
|
|
8
|
+
// skill.contribute_ctx → POST /v1/skill/contribute-ctx
|
|
9
|
+
// skill.declare_must_relay→ POST /v1/skill/declare-must-relay
|
|
10
|
+
// skill.manifest → GET /v1/skill/manifest
|
|
11
|
+
// skill.tool.invoke → POST /v1/skill/tool/<tool_name>
|
|
12
|
+
// skill.continuation.abort→ POST /v1/skill/continuation/abort
|
|
13
|
+
// skill.health → GET /health
|
|
14
|
+
//
|
|
15
|
+
// 认证: 给本地 skill daemon 发请求时带 X-Skill-Auth (HMAC) 头,
|
|
16
|
+
// 按现有 §3 auth_mode: hmac_shared_secret 规约。
|
|
17
|
+
//
|
|
18
|
+
// 失败路径: fetch 抛 ECONNREFUSED 或 timeout → 返回 TUNNEL_DEGRADED JSON-RPC error,
|
|
19
|
+
// 绝不 hang,绝不吞。
|
|
20
|
+
import { createHmac } from 'node:crypto';
|
|
21
|
+
import { TUNNEL_ERROR_CODES } from '@skillfm/contracts/skill-tunnel';
|
|
22
|
+
export class LocalBridge {
|
|
23
|
+
deps;
|
|
24
|
+
constructor(deps) {
|
|
25
|
+
this.deps = deps;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* 把 server→agent 的 JSON-RPC request 转发到本地 skill daemon。
|
|
29
|
+
* 返回 JsonRpcSuccessResponse 或 JsonRpcErrorResponse(本地不可达等)。
|
|
30
|
+
* 异常不抛出,一律封装成 error response —— 上层 client 按 id 回传。
|
|
31
|
+
*/
|
|
32
|
+
async dispatch(id, method, params) {
|
|
33
|
+
// 1. 白名单校验
|
|
34
|
+
if (!this.isKnownServerMethod(method)) {
|
|
35
|
+
return this.errorResponse(id, TUNNEL_ERROR_CODES.METHOD_NOT_FOUND, `unknown method: ${method}`);
|
|
36
|
+
}
|
|
37
|
+
// 2. 按 method 路由
|
|
38
|
+
try {
|
|
39
|
+
const m = method;
|
|
40
|
+
switch (m) {
|
|
41
|
+
case 'skill.run':
|
|
42
|
+
return await this.handleSkillRun(id, params);
|
|
43
|
+
case 'skill.contribute_ctx':
|
|
44
|
+
return await this.handleSkillPost(id, params, '/v1/skill/contribute-ctx');
|
|
45
|
+
case 'skill.declare_must_relay':
|
|
46
|
+
return await this.handleSkillPost(id, params, '/v1/skill/declare-must-relay');
|
|
47
|
+
case 'skill.manifest':
|
|
48
|
+
return await this.handleSkillGet(id, params, '/v1/skill/manifest');
|
|
49
|
+
case 'skill.tool.invoke':
|
|
50
|
+
return await this.handleToolInvoke(id, params);
|
|
51
|
+
case 'skill.continuation.abort':
|
|
52
|
+
return await this.handleSkillPost(id, params, '/v1/skill/continuation/abort');
|
|
53
|
+
case 'skill.health':
|
|
54
|
+
return await this.handleSkillGet(id, params, '/health');
|
|
55
|
+
default: {
|
|
56
|
+
// 穷尽检查 —— TS 会在新加 method 时报错
|
|
57
|
+
const _exhaustive = m;
|
|
58
|
+
void _exhaustive;
|
|
59
|
+
return this.errorResponse(id, TUNNEL_ERROR_CODES.METHOD_NOT_FOUND, `unroutable method: ${method}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
const e = err;
|
|
65
|
+
return this.errorResponse(id, TUNNEL_ERROR_CODES.INTERNAL_ERROR, `local-bridge dispatch error: ${e.message}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
isKnownServerMethod(method) {
|
|
69
|
+
return [
|
|
70
|
+
'skill.run',
|
|
71
|
+
'skill.contribute_ctx',
|
|
72
|
+
'skill.declare_must_relay',
|
|
73
|
+
'skill.manifest',
|
|
74
|
+
'skill.tool.invoke',
|
|
75
|
+
'skill.continuation.abort',
|
|
76
|
+
'skill.health',
|
|
77
|
+
].includes(method);
|
|
78
|
+
}
|
|
79
|
+
async handleSkillRun(id, params) {
|
|
80
|
+
if (!params?.skill_slug) {
|
|
81
|
+
return this.errorResponse(id, TUNNEL_ERROR_CODES.INVALID_PARAMS, 'missing skill_slug');
|
|
82
|
+
}
|
|
83
|
+
const endpoint = this.deps.resolveEndpoint(params.skill_slug);
|
|
84
|
+
if (!endpoint) {
|
|
85
|
+
return this.errorResponse(id, TUNNEL_ERROR_CODES.METHOD_NOT_FOUND, `skill not registered locally: ${params.skill_slug}`);
|
|
86
|
+
}
|
|
87
|
+
return this.httpJson(id, 'POST', `${endpoint}/v1/skill/run`, params.request);
|
|
88
|
+
}
|
|
89
|
+
async handleToolInvoke(id, params) {
|
|
90
|
+
if (!params?.skill_slug || !params?.tool_name) {
|
|
91
|
+
return this.errorResponse(id, TUNNEL_ERROR_CODES.INVALID_PARAMS, 'missing skill_slug or tool_name');
|
|
92
|
+
}
|
|
93
|
+
const endpoint = this.deps.resolveEndpoint(params.skill_slug);
|
|
94
|
+
if (!endpoint) {
|
|
95
|
+
return this.errorResponse(id, TUNNEL_ERROR_CODES.METHOD_NOT_FOUND, `skill not registered locally: ${params.skill_slug}`);
|
|
96
|
+
}
|
|
97
|
+
const path = `/v1/skill/tool/${encodeURIComponent(params.tool_name)}`;
|
|
98
|
+
return this.httpJson(id, 'POST', `${endpoint}${path}`, {
|
|
99
|
+
args: params.args,
|
|
100
|
+
context: params.context,
|
|
101
|
+
request_id: params.request_id,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
async handleSkillPost(id, params, path) {
|
|
105
|
+
if (!params?.skill_slug) {
|
|
106
|
+
return this.errorResponse(id, TUNNEL_ERROR_CODES.INVALID_PARAMS, 'missing skill_slug');
|
|
107
|
+
}
|
|
108
|
+
const endpoint = this.deps.resolveEndpoint(params.skill_slug);
|
|
109
|
+
if (!endpoint) {
|
|
110
|
+
return this.errorResponse(id, TUNNEL_ERROR_CODES.METHOD_NOT_FOUND, `skill not registered locally: ${params.skill_slug}`);
|
|
111
|
+
}
|
|
112
|
+
return this.httpJson(id, 'POST', `${endpoint}${path}`, params);
|
|
113
|
+
}
|
|
114
|
+
async handleSkillGet(id, params, path) {
|
|
115
|
+
if (!params?.skill_slug) {
|
|
116
|
+
return this.errorResponse(id, TUNNEL_ERROR_CODES.INVALID_PARAMS, 'missing skill_slug');
|
|
117
|
+
}
|
|
118
|
+
const endpoint = this.deps.resolveEndpoint(params.skill_slug);
|
|
119
|
+
if (!endpoint) {
|
|
120
|
+
return this.errorResponse(id, TUNNEL_ERROR_CODES.METHOD_NOT_FOUND, `skill not registered locally: ${params.skill_slug}`);
|
|
121
|
+
}
|
|
122
|
+
return this.httpJson(id, 'GET', `${endpoint}${path}`, null);
|
|
123
|
+
}
|
|
124
|
+
async httpJson(id, httpMethod, url, body) {
|
|
125
|
+
const fetchImpl = this.deps.fetch ?? globalThis.fetch;
|
|
126
|
+
const timeoutMs = this.deps.fetchTimeoutMs ?? 30_000;
|
|
127
|
+
const headers = {};
|
|
128
|
+
let payload;
|
|
129
|
+
if (httpMethod === 'POST') {
|
|
130
|
+
headers['content-type'] = 'application/json';
|
|
131
|
+
payload = JSON.stringify(body ?? {});
|
|
132
|
+
if (this.deps.skillAuthSecret) {
|
|
133
|
+
// HMAC 对 raw body 签名 —— 与 platform §3 auth 规约保持一致
|
|
134
|
+
headers['x-skill-auth'] = createHmac('sha256', this.deps.skillAuthSecret)
|
|
135
|
+
.update(payload)
|
|
136
|
+
.digest('hex');
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
const controller = new AbortController();
|
|
140
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
141
|
+
try {
|
|
142
|
+
const res = await fetchImpl(url, {
|
|
143
|
+
method: httpMethod,
|
|
144
|
+
headers,
|
|
145
|
+
body: payload,
|
|
146
|
+
signal: controller.signal,
|
|
147
|
+
});
|
|
148
|
+
const text = await res.text();
|
|
149
|
+
let data;
|
|
150
|
+
try {
|
|
151
|
+
data = text ? JSON.parse(text) : null;
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
// 非 JSON —— 把 raw 包进 data,不视为致命错
|
|
155
|
+
data = { raw: text };
|
|
156
|
+
}
|
|
157
|
+
if (!res.ok) {
|
|
158
|
+
return this.errorResponse(id, TUNNEL_ERROR_CODES.SKILL_APP_ERROR, `local skill returned HTTP ${res.status}`, { http_status: res.status, data });
|
|
159
|
+
}
|
|
160
|
+
return {
|
|
161
|
+
jsonrpc: '2.0',
|
|
162
|
+
id,
|
|
163
|
+
result: data,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
catch (err) {
|
|
167
|
+
const e = err;
|
|
168
|
+
const isAbort = e.name === 'AbortError';
|
|
169
|
+
// undici fetch wraps underlying socket error into `cause`; walk the chain
|
|
170
|
+
// to find ECONNREFUSED / ENOTFOUND / ECONNRESET / EHOSTUNREACH.
|
|
171
|
+
const isUnreachable = detectUnreachable(e);
|
|
172
|
+
const msg = isAbort
|
|
173
|
+
? `local skill timeout after ${timeoutMs}ms (${url})`
|
|
174
|
+
: isUnreachable
|
|
175
|
+
? `local skill unreachable: ${url} (${describeUnreachable(e)})`
|
|
176
|
+
: `local skill unreachable: ${url} (${e.message})`;
|
|
177
|
+
// 所有 fetch 网络层失败都映射为 TUNNEL_DEGRADED —— 契约 §4b 要求不 hang
|
|
178
|
+
return this.errorResponse(id, TUNNEL_ERROR_CODES.TUNNEL_DEGRADED, msg);
|
|
179
|
+
}
|
|
180
|
+
finally {
|
|
181
|
+
clearTimeout(timer);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
errorResponse(id, code, message, data) {
|
|
185
|
+
return {
|
|
186
|
+
jsonrpc: '2.0',
|
|
187
|
+
id,
|
|
188
|
+
error: { code, message, data },
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
const UNREACHABLE_CODES = new Set([
|
|
193
|
+
'ECONNREFUSED',
|
|
194
|
+
'ENOTFOUND',
|
|
195
|
+
'ECONNRESET',
|
|
196
|
+
'EHOSTUNREACH',
|
|
197
|
+
'EAI_AGAIN',
|
|
198
|
+
'UND_ERR_SOCKET',
|
|
199
|
+
]);
|
|
200
|
+
function detectUnreachable(err) {
|
|
201
|
+
let cur = err;
|
|
202
|
+
let depth = 0;
|
|
203
|
+
while (cur && depth < 6) {
|
|
204
|
+
const c = cur;
|
|
205
|
+
if (c.code && UNREACHABLE_CODES.has(c.code))
|
|
206
|
+
return true;
|
|
207
|
+
cur = c.cause;
|
|
208
|
+
depth += 1;
|
|
209
|
+
}
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
212
|
+
function describeUnreachable(err) {
|
|
213
|
+
let cur = err;
|
|
214
|
+
let depth = 0;
|
|
215
|
+
while (cur && depth < 6) {
|
|
216
|
+
const c = cur;
|
|
217
|
+
if (c.code && UNREACHABLE_CODES.has(c.code))
|
|
218
|
+
return c.code;
|
|
219
|
+
cur = c.cause;
|
|
220
|
+
depth += 1;
|
|
221
|
+
}
|
|
222
|
+
return 'ECONNREFUSED';
|
|
223
|
+
}
|
|
224
|
+
//# sourceMappingURL=local-bridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-bridge.js","sourceRoot":"","sources":["../../src/skill-tunnel/local-bridge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** 不应重连的 close code 集合 */
|
|
2
|
+
export declare const FATAL_CLOSE_CODES: Set<number>;
|
|
3
|
+
export declare function isFatalCloseCode(code: number | null | undefined): boolean;
|
|
4
|
+
/**
|
|
5
|
+
* 给定第 N 次重试(0-indexed),返回延迟 ms。
|
|
6
|
+
* 可注入 jitterFn 方便测试(默认 Math.random)。
|
|
7
|
+
*/
|
|
8
|
+
export declare function computeReconnectDelayMs(attempt: number, jitterFn?: () => number): number;
|
|
9
|
+
/**
|
|
10
|
+
* 简易调度器 —— 包装 setTimeout,便于测试时可注入 fake clock。
|
|
11
|
+
*/
|
|
12
|
+
export declare class ReconnectScheduler {
|
|
13
|
+
private timer;
|
|
14
|
+
private attempt;
|
|
15
|
+
private stopped;
|
|
16
|
+
schedule(fn: () => void): void;
|
|
17
|
+
reset(): void;
|
|
18
|
+
stop(): void;
|
|
19
|
+
get attempts(): number;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=reconnect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reconnect.d.ts","sourceRoot":"","sources":["../../src/skill-tunnel/reconnect.ts"],"names":[],"mappings":"AAaA,0BAA0B;AAC1B,eAAO,MAAM,iBAAiB,aAK5B,CAAC;AAEH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAGzE;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,MAAM,EACf,QAAQ,GAAE,MAAM,MAAoB,GACnC,MAAM,CASR;AAED;;GAEG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,KAAK,CAA+B;IAC5C,OAAO,CAAC,OAAO,CAAK;IACpB,OAAO,CAAC,OAAO,CAAS;IAExB,QAAQ,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,IAAI;IAc9B,KAAK,IAAI,IAAI;IAQb,IAAI,IAAI,IAAI;IAQZ,IAAI,QAAQ,IAAI,MAAM,CAErB;CACF"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// M2 SkillTunnelClient — 指数退避重连调度
|
|
2
|
+
//
|
|
3
|
+
// 策略 (DELTA §5 + TUNNEL_CONSTANTS):
|
|
4
|
+
// delay = INITIAL × 2^attempt, 上限 MAX
|
|
5
|
+
// jitter ±30% (避免多 agent 同时重连导致 brain 侧抖动)
|
|
6
|
+
// 致命 close code (4001/4002/4003/4101) 不重连 —— 要么签名错,要么 token 吊销,要么版本不兼容,
|
|
7
|
+
// 这些情况重连只会继续失败,必须人工介入 → 输出到 stderr 供 agent 看到。
|
|
8
|
+
import { TUNNEL_CLOSE_CODES, TUNNEL_CONSTANTS, } from '@skillfm/contracts/skill-tunnel';
|
|
9
|
+
/** 不应重连的 close code 集合 */
|
|
10
|
+
export const FATAL_CLOSE_CODES = new Set([
|
|
11
|
+
TUNNEL_CLOSE_CODES.AUTH_BAD_SIGNATURE,
|
|
12
|
+
TUNNEL_CLOSE_CODES.AUTH_NONCE_REUSED,
|
|
13
|
+
TUNNEL_CLOSE_CODES.AGENT_TOKEN_REVOKED,
|
|
14
|
+
TUNNEL_CLOSE_CODES.VERSION_UNSUPPORTED,
|
|
15
|
+
]);
|
|
16
|
+
export function isFatalCloseCode(code) {
|
|
17
|
+
if (typeof code !== 'number')
|
|
18
|
+
return false;
|
|
19
|
+
return FATAL_CLOSE_CODES.has(code);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* 给定第 N 次重试(0-indexed),返回延迟 ms。
|
|
23
|
+
* 可注入 jitterFn 方便测试(默认 Math.random)。
|
|
24
|
+
*/
|
|
25
|
+
export function computeReconnectDelayMs(attempt, jitterFn = Math.random) {
|
|
26
|
+
const base = Math.min(TUNNEL_CONSTANTS.RECONNECT_INITIAL_DELAY_MS * 2 ** attempt, TUNNEL_CONSTANTS.RECONNECT_MAX_DELAY_MS);
|
|
27
|
+
// jitter ±30%
|
|
28
|
+
const jitterRange = base * 0.3;
|
|
29
|
+
const jitter = (jitterFn() * 2 - 1) * jitterRange;
|
|
30
|
+
return Math.max(0, Math.round(base + jitter));
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* 简易调度器 —— 包装 setTimeout,便于测试时可注入 fake clock。
|
|
34
|
+
*/
|
|
35
|
+
export class ReconnectScheduler {
|
|
36
|
+
timer = null;
|
|
37
|
+
attempt = 0;
|
|
38
|
+
stopped = false;
|
|
39
|
+
schedule(fn) {
|
|
40
|
+
if (this.stopped)
|
|
41
|
+
return;
|
|
42
|
+
const delay = computeReconnectDelayMs(this.attempt);
|
|
43
|
+
this.attempt += 1;
|
|
44
|
+
this.timer = setTimeout(() => {
|
|
45
|
+
this.timer = null;
|
|
46
|
+
if (!this.stopped)
|
|
47
|
+
fn();
|
|
48
|
+
}, delay);
|
|
49
|
+
// 不让 reconnect timer 阻塞 node exit
|
|
50
|
+
if (typeof this.timer.unref === 'function') {
|
|
51
|
+
this.timer.unref();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
reset() {
|
|
55
|
+
this.attempt = 0;
|
|
56
|
+
if (this.timer) {
|
|
57
|
+
clearTimeout(this.timer);
|
|
58
|
+
this.timer = null;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
stop() {
|
|
62
|
+
this.stopped = true;
|
|
63
|
+
if (this.timer) {
|
|
64
|
+
clearTimeout(this.timer);
|
|
65
|
+
this.timer = null;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
get attempts() {
|
|
69
|
+
return this.attempt;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=reconnect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reconnect.js","sourceRoot":"","sources":["../../src/skill-tunnel/reconnect.ts"],"names":[],"mappings":"AAAA,kCAAkC;AAClC,EAAE;AACF,oCAAoC;AACpC,wCAAwC;AACxC,6CAA6C;AAC7C,0EAA0E;AAC1E,iDAAiD;AAEjD,OAAO,EACL,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,iCAAiC,CAAC;AAEzC,0BAA0B;AAC1B,MAAM,CAAC,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAS;IAC/C,kBAAkB,CAAC,kBAAkB;IACrC,kBAAkB,CAAC,iBAAiB;IACpC,kBAAkB,CAAC,mBAAmB;IACtC,kBAAkB,CAAC,mBAAmB;CACvC,CAAC,CAAC;AAEH,MAAM,UAAU,gBAAgB,CAAC,IAA+B;IAC9D,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC3C,OAAO,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AACrC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CACrC,OAAe,EACf,WAAyB,IAAI,CAAC,MAAM;IAEpC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CACnB,gBAAgB,CAAC,0BAA0B,GAAG,CAAC,IAAI,OAAO,EAC1D,gBAAgB,CAAC,sBAAsB,CACxC,CAAC;IACF,cAAc;IACd,MAAM,WAAW,GAAG,IAAI,GAAG,GAAG,CAAC;IAC/B,MAAM,MAAM,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,WAAW,CAAC;IAClD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC;AAChD,CAAC;AAED;;GAEG;AACH,MAAM,OAAO,kBAAkB;IACrB,KAAK,GAA0B,IAAI,CAAC;IACpC,OAAO,GAAG,CAAC,CAAC;IACZ,OAAO,GAAG,KAAK,CAAC;IAExB,QAAQ,CAAC,EAAc;QACrB,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO;QACzB,MAAM,KAAK,GAAG,uBAAuB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACpD,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC;QAClB,IAAI,CAAC,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC3B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;YAClB,IAAI,CAAC,IAAI,CAAC,OAAO;gBAAE,EAAE,EAAE,CAAC;QAC1B,CAAC,EAAE,KAAK,CAAC,CAAC;QACV,kCAAkC;QAClC,IAAI,OAAQ,IAAI,CAAC,KAA2C,CAAC,KAAK,KAAK,UAAU,EAAE,CAAC;YACjF,IAAI,CAAC,KAA0C,CAAC,KAAK,EAAE,CAAC;QAC3D,CAAC;IACH,CAAC;IAED,KAAK;QACH,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;QACjB,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACzB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QACpB,CAAC;IACH,CAAC;IAED,IAAI;QACF,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACzB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QACpB,CAAC;IACH,CAAC;IAED,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;CACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skillfm/local",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.5.0",
|
|
4
4
|
"description": "SkillFM local sidecar — a tiny localhost HTTP proxy that lets any AI agent activate and run SkillFM skills in the current conversation without restarting its MCP runtime. Writes ~/.skillfm/local.json for service discovery.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -40,17 +40,20 @@
|
|
|
40
40
|
"typecheck": "tsc --noEmit",
|
|
41
41
|
"start": "node dist/index.js start",
|
|
42
42
|
"prepublishOnly": "npm run build",
|
|
43
|
-
"test": "tsx --test src/harness/detector.test.ts src/harness/priming.test.ts src/harness/writers.test.ts src/guard/state.test.ts src/soul.test.ts src/soul-security.test.ts src/harness/kernels/registry.test.ts src/harness/kernels/deny-pipeline.test.ts src/mcp-output/builder.test.ts src/mcp-output/deny-review.test.ts src/mcp-output/integration.test.ts src/skill-md/template.test.ts src/skill-md/writer.test.ts src/mcp-stdio/smoke.test.ts src/mcp-stdio/render-flow.contract.test.ts src/mcp-stdio/render-aha.test.ts src/mcp-stdio/sse-progress-client.test.ts src/mcp-stdio/parse-tolerant-json.test.ts src/self-upgrade.test.ts",
|
|
43
|
+
"test": "tsx --test src/harness/detector.test.ts src/harness/priming.test.ts src/harness/writers.test.ts src/guard/state.test.ts src/soul.test.ts src/soul-security.test.ts src/harness/kernels/registry.test.ts src/harness/kernels/deny-pipeline.test.ts src/mcp-output/builder.test.ts src/mcp-output/deny-review.test.ts src/mcp-output/integration.test.ts src/skill-md/template.test.ts src/skill-md/writer.test.ts src/mcp-stdio/smoke.test.ts src/mcp-stdio/render-flow.contract.test.ts src/mcp-stdio/render-aha.test.ts src/mcp-stdio/sse-progress-client.test.ts src/mcp-stdio/parse-tolerant-json.test.ts src/self-upgrade.test.ts src/skill-tunnel/local-bridge.test.ts src/skill-tunnel/client.test.ts src/skill-runner/discovery.test.ts src/skill-installer/index.test.ts",
|
|
44
44
|
"test:acceptance": "npm run build && bash scripts/acceptance-matrix.sh",
|
|
45
45
|
"postpublish": "curl -sS -m 10 -X PUT 'https://registry.npmmirror.com/-/package/@skillfm/local/syncs?sync_upstream=true' > /dev/null && echo '✓ npmmirror sync triggered' || echo '⚠ npmmirror sync failed (非阻塞,可手动触发)'"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
49
|
+
"tar": "^7.5.0",
|
|
50
|
+
"ws": "^8.20.0",
|
|
49
51
|
"zod": "^3.23.0"
|
|
50
52
|
},
|
|
51
53
|
"devDependencies": {
|
|
52
54
|
"@skillfm/contracts": "*",
|
|
53
55
|
"@types/node": "^22.19.17",
|
|
56
|
+
"@types/ws": "^8.5.10",
|
|
54
57
|
"tsx": "^4.0.0",
|
|
55
58
|
"typescript": "^5.4.0"
|
|
56
59
|
},
|