@mininglamp-oss/octo-runtime-client 0.0.0-stage → 1.1.11

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.
Files changed (87) hide show
  1. package/LICENSE +190 -0
  2. package/README.md +38 -2
  3. package/build-info.json +5 -0
  4. package/dist/async-question-reply.d.ts +30 -0
  5. package/dist/async-question-reply.js +199 -0
  6. package/dist/browser.d.ts +1 -0
  7. package/dist/browser.js +1 -0
  8. package/dist/client.d.ts +10 -0
  9. package/dist/client.js +465 -0
  10. package/dist/index.d.ts +6 -0
  11. package/dist/index.js +6 -0
  12. package/dist/internal.d.ts +4 -0
  13. package/dist/internal.js +5 -0
  14. package/dist/invocation-lifecycle.d.ts +59 -0
  15. package/dist/invocation-lifecycle.js +287 -0
  16. package/dist/notification.d.ts +1 -0
  17. package/dist/notification.js +1 -0
  18. package/dist/protocol.d.ts +1 -0
  19. package/dist/protocol.js +1 -0
  20. package/dist/runtime-path.d.ts +21 -0
  21. package/dist/runtime-path.js +138 -0
  22. package/dist/startup-catalog.d.ts +8 -0
  23. package/dist/startup-catalog.js +65 -0
  24. package/dist/startup-diagnostics.d.ts +82 -0
  25. package/dist/startup-diagnostics.js +371 -0
  26. package/dist/submission-error.d.ts +10 -0
  27. package/dist/submission-error.js +23 -0
  28. package/dist/types.d.ts +72 -0
  29. package/dist/types.js +10 -0
  30. package/node_modules/@mininglamp-oss/octo-runtime-protocol/dist/actmode.d.ts +4 -0
  31. package/node_modules/@mininglamp-oss/octo-runtime-protocol/dist/actmode.js +36 -0
  32. package/node_modules/@mininglamp-oss/octo-runtime-protocol/dist/adapter-metadata.d.ts +7 -0
  33. package/node_modules/@mininglamp-oss/octo-runtime-protocol/dist/adapter-metadata.js +1 -0
  34. package/node_modules/@mininglamp-oss/octo-runtime-protocol/dist/browser.d.ts +7 -0
  35. package/node_modules/@mininglamp-oss/octo-runtime-protocol/dist/browser.js +6 -0
  36. package/node_modules/@mininglamp-oss/octo-runtime-protocol/dist/context-catalog.d.ts +11 -0
  37. package/node_modules/@mininglamp-oss/octo-runtime-protocol/dist/context-catalog.js +33 -0
  38. package/node_modules/@mininglamp-oss/octo-runtime-protocol/dist/context-configuration.d.ts +5 -0
  39. package/node_modules/@mininglamp-oss/octo-runtime-protocol/dist/context-configuration.js +58 -0
  40. package/node_modules/@mininglamp-oss/octo-runtime-protocol/dist/context-hash.d.ts +2 -0
  41. package/node_modules/@mininglamp-oss/octo-runtime-protocol/dist/context-hash.js +5 -0
  42. package/node_modules/@mininglamp-oss/octo-runtime-protocol/dist/context.d.ts +29 -0
  43. package/node_modules/@mininglamp-oss/octo-runtime-protocol/dist/context.js +566 -0
  44. package/node_modules/@mininglamp-oss/octo-runtime-protocol/dist/execution-plan.d.ts +3 -0
  45. package/node_modules/@mininglamp-oss/octo-runtime-protocol/dist/execution-plan.js +80 -0
  46. package/node_modules/@mininglamp-oss/octo-runtime-protocol/dist/experience.d.ts +4 -0
  47. package/node_modules/@mininglamp-oss/octo-runtime-protocol/dist/experience.js +166 -0
  48. package/node_modules/@mininglamp-oss/octo-runtime-protocol/dist/failure.d.ts +82 -0
  49. package/node_modules/@mininglamp-oss/octo-runtime-protocol/dist/failure.js +562 -0
  50. package/node_modules/@mininglamp-oss/octo-runtime-protocol/dist/generated/protocol-types.d.ts +3022 -0
  51. package/node_modules/@mininglamp-oss/octo-runtime-protocol/dist/generated/protocol-types.js +6 -0
  52. package/node_modules/@mininglamp-oss/octo-runtime-protocol/dist/index.d.ts +124 -0
  53. package/node_modules/@mininglamp-oss/octo-runtime-protocol/dist/index.js +709 -0
  54. package/node_modules/@mininglamp-oss/octo-runtime-protocol/dist/invoke-input.d.ts +129 -0
  55. package/node_modules/@mininglamp-oss/octo-runtime-protocol/dist/invoke-input.js +177 -0
  56. package/node_modules/@mininglamp-oss/octo-runtime-protocol/dist/invoke-size.d.ts +3 -0
  57. package/node_modules/@mininglamp-oss/octo-runtime-protocol/dist/invoke-size.js +11 -0
  58. package/node_modules/@mininglamp-oss/octo-runtime-protocol/dist/json-size.d.ts +2 -0
  59. package/node_modules/@mininglamp-oss/octo-runtime-protocol/dist/json-size.js +91 -0
  60. package/node_modules/@mininglamp-oss/octo-runtime-protocol/dist/model-context.d.ts +3 -0
  61. package/node_modules/@mininglamp-oss/octo-runtime-protocol/dist/model-context.js +9 -0
  62. package/node_modules/@mininglamp-oss/octo-runtime-protocol/dist/multimodal.d.ts +15 -0
  63. package/node_modules/@mininglamp-oss/octo-runtime-protocol/dist/multimodal.js +166 -0
  64. package/node_modules/@mininglamp-oss/octo-runtime-protocol/dist/notification.d.ts +2 -0
  65. package/node_modules/@mininglamp-oss/octo-runtime-protocol/dist/notification.js +137 -0
  66. package/node_modules/@mininglamp-oss/octo-runtime-protocol/dist/questions.d.ts +9 -0
  67. package/node_modules/@mininglamp-oss/octo-runtime-protocol/dist/questions.js +84 -0
  68. package/node_modules/@mininglamp-oss/octo-runtime-protocol/dist/run-protocol.d.ts +20 -0
  69. package/node_modules/@mininglamp-oss/octo-runtime-protocol/dist/run-protocol.js +294 -0
  70. package/node_modules/@mininglamp-oss/octo-runtime-protocol/dist/runtime-selection.d.ts +3 -0
  71. package/node_modules/@mininglamp-oss/octo-runtime-protocol/dist/runtime-selection.js +68 -0
  72. package/node_modules/@mininglamp-oss/octo-runtime-protocol/dist/service-processes.d.ts +5 -0
  73. package/node_modules/@mininglamp-oss/octo-runtime-protocol/dist/service-processes.js +65 -0
  74. package/node_modules/@mininglamp-oss/octo-runtime-protocol/dist/stream-limits.d.ts +27 -0
  75. package/node_modules/@mininglamp-oss/octo-runtime-protocol/dist/stream-limits.js +56 -0
  76. package/node_modules/@mininglamp-oss/octo-runtime-protocol/package.json +15 -0
  77. package/package.json +55 -4
  78. package/schema/context-configuration-fixtures.json +1219 -0
  79. package/schema/context-fixtures.json +5988 -0
  80. package/schema/kernel-client.behavior.json +56 -0
  81. package/schema/kernel-ipc-fixtures.json +53 -0
  82. package/schema/kernel-ipc.schema.json +538 -0
  83. package/schema/native-invoke-fixtures.json +116 -0
  84. package/schema/protocol.schema.json +4525 -0
  85. package/schema/run-protocol-fixtures.json +761 -0
  86. package/schema/runtime-selection-fixtures.json +663 -0
  87. package/schema/session-name-fixtures.json +191 -0
@@ -0,0 +1,371 @@
1
+ import { STARTUP_CATALOG } from "./startup-catalog.js";
2
+ export { STARTUP_CATALOG } from "./startup-catalog.js";
3
+ /** CLI 继续提供 #306 的 startup 字段;恢复建议始终来自同一 catalog。 */
4
+ export function startupPathDiagnostic(diagnostic) {
5
+ if (!/^(HOME_|IPC_ENDPOINT_)/.test(diagnostic.rootCode))
6
+ return undefined;
7
+ const { path, resource, operation, systemCode, endpoint, measured, limit, unit } = diagnostic.context;
8
+ return {
9
+ domain: "startup",
10
+ code: diagnostic.rootCode,
11
+ resource: resource ?? "home",
12
+ operation: operation ?? "validate-input",
13
+ action: diagnostic.actions.join(" "),
14
+ ...(path !== undefined ? { path } : {}),
15
+ ...(systemCode !== undefined ? { systemCode } : {}),
16
+ ...(endpoint !== undefined ? { endpoint } : {}),
17
+ ...(measured !== undefined ? { measured } : {}),
18
+ ...(limit !== undefined ? { limit } : {}),
19
+ ...(unit !== undefined ? { unit } : {})
20
+ };
21
+ }
22
+ /** 保持原类型/message/code/cause,仅在可扩展错误上增加安全诊断;冻结错误可由调用边界直接投影。 */
23
+ export function withStartupContext(error, location, classification) {
24
+ try {
25
+ if (error instanceof Error && Object.isExtensible(error) && !Object.hasOwn(error, "diagnostic"))
26
+ Object.defineProperty(error, "diagnostic", {
27
+ value: describeStartupError(classification ? { code: classification, cause: error } : error, location)
28
+ });
29
+ }
30
+ catch {
31
+ // 不可信代理/不可写对象不能让诊断遮盖原错误。
32
+ }
33
+ return error;
34
+ }
35
+ const phases = new Set([
36
+ "created",
37
+ "initializing",
38
+ "ready",
39
+ "closing",
40
+ "closed",
41
+ "failed"
42
+ ]);
43
+ const wrappers = new Set([
44
+ "SERVICE_INITIALIZATION_FAILED",
45
+ "KERNEL_START_CLEANUP_INCOMPLETE",
46
+ "COMMAND_FAILED"
47
+ ]);
48
+ const object = (value) => value !== null && (typeof value === "object" || typeof value === "function") ? value : undefined;
49
+ // 不执行 getter/toJSON;代理或损坏对象按未知处理,错误投影本身不能覆盖启动失败。
50
+ function own(value, key) {
51
+ try {
52
+ return object(value) ? Object.getOwnPropertyDescriptor(value, key)?.value : undefined;
53
+ }
54
+ catch {
55
+ return undefined;
56
+ }
57
+ }
58
+ function arrayItems(value, maximum) {
59
+ try {
60
+ if (!Array.isArray(value))
61
+ return undefined;
62
+ const length = own(value, "length");
63
+ if (typeof length !== "number" || !Number.isSafeInteger(length) || length < 0)
64
+ return undefined;
65
+ return Array.from({ length: Math.min(length, maximum) }, (_, index) => own(value, String(index)));
66
+ }
67
+ catch {
68
+ return undefined;
69
+ }
70
+ }
71
+ const codeOf = (value) => typeof value === "string" && /^[A-Z][A-Z0-9_]{1,100}$/.test(value) ? value : undefined;
72
+ const errorCode = (value) => codeOf(own(value, "code")) ?? codeOf(own(value, "message"));
73
+ /** 文本与 JSON 同用确定性规范化:去控制字符,去 URL 认证/query/hash 和显式敏感赋值。 */
74
+ export function safeStartupValue(value, maximum = 32768) {
75
+ const truncated = value.length > maximum;
76
+ return (value
77
+ .slice(0, maximum)
78
+ .replace(/[\p{Cc}\p{Cf}]/gu, " ")
79
+ // 完整标量交给 URL parser,不能在 userinfo 的空格/引号处切开并泄漏后缀。
80
+ // 截断过的 URL 不再猜 authority;内联模块载荷整体隐藏。前缀锚点限制回溯。
81
+ .replace(/(^|[^a-z0-9+.-])((?:data:|[a-z][a-z0-9+.-]*:\/\/)[\s\S]*)/gi, (match, prefix) => {
82
+ const selected = match.slice(prefix.length);
83
+ if (/^data:/i.test(selected))
84
+ return prefix + "[redacted-inline-module]";
85
+ if (truncated ||
86
+ /[\s"<>]/u.test(selected) ||
87
+ selected.indexOf("://", selected.indexOf("://") + 3) !== -1)
88
+ return prefix + "[redacted-url]";
89
+ try {
90
+ const url = new URL(selected);
91
+ url.username = "";
92
+ url.password = "";
93
+ url.search = "";
94
+ url.hash = "";
95
+ return prefix + url.toString();
96
+ }
97
+ catch {
98
+ return prefix + "[redacted-url]";
99
+ }
100
+ })
101
+ .replace(/\bBearer\s+[^\s,;]+/gi, "Bearer [redacted]")
102
+ .replace(/\b(?:sk-|bf_)[A-Za-z0-9_-]{8,}/g, "[redacted]")
103
+ .replace(
104
+ // 资源标量没有可靠的凭据结束语法,带引号或含标点的值也保守隐藏余段。
105
+ /\b(?:token|secret|password|authorization|api[_-]?key)\s*[:=][\s\S]*/gi, "[redacted]"));
106
+ }
107
+ function safeContext(value) {
108
+ const result = {};
109
+ for (const key of [
110
+ "path",
111
+ "resource",
112
+ "operation",
113
+ "configKey",
114
+ "endpoint",
115
+ "executable",
116
+ "module",
117
+ "systemCode"
118
+ ]) {
119
+ const field = own(value, key);
120
+ if (typeof field === "string")
121
+ result[key] = safeStartupValue(field, ["path", "endpoint", "executable", "module"].includes(key) ? 32768 : 256);
122
+ }
123
+ for (const key of ["measured", "limit"]) {
124
+ const field = own(value, key);
125
+ if (typeof field === "number" && Number.isSafeInteger(field) && field >= 0)
126
+ result[key] = field;
127
+ }
128
+ const unit = own(value, "unit");
129
+ if (unit === "utf8-bytes" || unit === "utf16-units")
130
+ result.unit = unit;
131
+ return result;
132
+ }
133
+ function safeCleanup(value) {
134
+ const complete = own(value, "complete"), errors = arrayItems(own(value, "errors"), 32), pending = arrayItems(own(value, "pendingResources"), 32);
135
+ if (typeof complete !== "boolean" || !errors || !pending)
136
+ return undefined;
137
+ return {
138
+ complete,
139
+ errors: errors.map((item) => ({
140
+ resource: safeStartupValue(typeof own(item, "resource") === "string" ? own(item, "resource") : "unknown", 256),
141
+ code: codeOf(own(item, "code")) ?? "STARTUP_UNKNOWN"
142
+ })),
143
+ pendingResources: pending.map((item) => typeof item === "string" ? safeStartupValue(item, 256) : "unknown")
144
+ };
145
+ }
146
+ function safeCause(value) {
147
+ const component = own(value, "component"), phase = own(value, "phase");
148
+ const cleanup = safeCleanup(own(value, "cleanup"));
149
+ return {
150
+ code: codeOf(own(value, "code")) ?? "STARTUP_UNKNOWN",
151
+ context: safeContext(own(value, "context")),
152
+ ...(typeof component === "string" ? { component: safeStartupValue(component, 128) } : {}),
153
+ ...(typeof phase === "string" && phases.has(phase)
154
+ ? { phase: phase }
155
+ : {}),
156
+ ...(cleanup ? { cleanup } : {})
157
+ };
158
+ }
159
+ /**
160
+ * 在失败调用边界投影启动事实;不依赖 IPC/Run,不改变原错误、退出码或清理行为。
161
+ * cause/aggregate 按主失败优先有界遍历(16 节点/6 层);循环和原始异常正文均不输出。
162
+ */
163
+ export function describeStartupError(error, location = { component: "host", phase: "created" }) {
164
+ const existing = restoreStartupDiagnostic(own(error, "diagnostic"));
165
+ if (existing)
166
+ return existing;
167
+ const seen = new Set();
168
+ const causes = [];
169
+ let truncated = false;
170
+ let cleanup;
171
+ let visited = 0;
172
+ const visit = (value, depth, inherited = {}) => {
173
+ if (depth > 6 || visited >= 16) {
174
+ truncated = true;
175
+ return undefined;
176
+ }
177
+ const reference = object(value);
178
+ if (!reference)
179
+ return undefined;
180
+ if (seen.has(reference)) {
181
+ truncated = true;
182
+ return undefined;
183
+ }
184
+ seen.add(reference);
185
+ visited++;
186
+ const diagnostic = own(value, "diagnostic");
187
+ const embedded = own(diagnostic, "domain") === "startup" ? diagnostic : undefined;
188
+ const nodeCleanup = safeCleanup(own(value, "cleanup")) ?? safeCleanup(own(embedded, "cleanup"));
189
+ cleanup ??= nodeCleanup;
190
+ const code = errorCode(value) ?? codeOf(own(embedded, "code"));
191
+ const context = {
192
+ ...inherited,
193
+ ...safeContext(own(value, "startupContext")),
194
+ ...safeContext(embedded),
195
+ ...safeContext(own(embedded, "context"))
196
+ };
197
+ // Node 系统错误字段是实际 IO 事实;spawn 的 path 是可执行文件,不能误建议 mkdir。
198
+ const syscall = own(value, "syscall"), path = own(value, "path"), address = own(value, "address");
199
+ if (typeof syscall === "string")
200
+ context.operation ??= safeStartupValue(syscall, 256);
201
+ if (typeof path === "string") {
202
+ if (typeof syscall === "string" && syscall.startsWith("spawn")) {
203
+ context.executable ??= safeStartupValue(path);
204
+ context.resource ??= "executable";
205
+ }
206
+ else
207
+ context.path ??= safeStartupValue(path);
208
+ }
209
+ if (typeof address === "string")
210
+ context.endpoint ??= safeStartupValue(address);
211
+ if (code && /^(E[A-Z0-9]+|UV_[A-Z0-9_]+)$/.test(code))
212
+ context.systemCode ??= code;
213
+ const current = code
214
+ ? safeCause({
215
+ code,
216
+ context,
217
+ component: own(embedded, "component"),
218
+ phase: own(embedded, "phase"),
219
+ cleanup: nodeCleanup
220
+ })
221
+ : undefined;
222
+ if (current)
223
+ causes.push(current);
224
+ let child;
225
+ const rawErrors = own(value, "errors");
226
+ const errors = arrayItems(rawErrors, 16);
227
+ if (errors) {
228
+ for (let i = 0; i < errors.length; i++) {
229
+ const found = visit(errors[i], depth + 1, context);
230
+ if (i === 0)
231
+ child = found ?? { code: "STARTUP_UNKNOWN", context };
232
+ }
233
+ // 所有分支都必须遍历以保留清理失败;不能被 ??= 短路。
234
+ if (Number(own(rawErrors, "length")) > 16)
235
+ truncated = true;
236
+ }
237
+ const cause = own(value, "cause");
238
+ const nested = cause === undefined ? undefined : visit(cause, depth + 1, context);
239
+ const savedRoot = codeOf(own(embedded, "rootCode"));
240
+ // 后台回读只有白名单诊断而没有原始 cause;保留已确认根因及清理事实,不反序列化异常。
241
+ if (!errors && cause === undefined && savedRoot) {
242
+ const savedCauses = arrayItems(own(embedded, "causes"), 15);
243
+ if (savedCauses) {
244
+ for (const item of savedCauses) {
245
+ visit({
246
+ code: codeOf(own(item, "code")),
247
+ startupContext: safeContext(own(item, "context")),
248
+ cleanup: safeCleanup(own(item, "cleanup")),
249
+ diagnostic: {
250
+ domain: "startup",
251
+ component: own(item, "component"),
252
+ phase: own(item, "phase")
253
+ }
254
+ }, depth + 1);
255
+ }
256
+ }
257
+ return { code: savedRoot, context };
258
+ }
259
+ const primary = child ?? nested;
260
+ // Home/端点所有者已验证的资源分类比系统 errno 更精确;errno 仍保留在 context/causes。
261
+ // 初始化/加载包装不能采用此规则,否则会再次遮盖真正根因。
262
+ if (current &&
263
+ STARTUP_CATALOG[current.code] &&
264
+ /^(HOME_|IPC_ENDPOINT_|ENDPOINT_|ORPHAN_)/.test(current.code))
265
+ return { code: current.code, context: { ...context, ...primary?.context } };
266
+ return primary ?? (current && !wrappers.has(current.code) ? current : undefined);
267
+ };
268
+ const root = visit(error, 0);
269
+ const embedded = own(error, "diagnostic");
270
+ const component = typeof own(embedded, "component") === "string"
271
+ ? own(embedded, "component")
272
+ : location.component;
273
+ const phase = own(embedded, "phase");
274
+ const context = {
275
+ ...safeContext(location.context),
276
+ ...safeContext(own(embedded, "context")),
277
+ ...(root?.context ?? {})
278
+ };
279
+ const code = errorCode(error) ?? codeOf(own(embedded, "code")) ?? "STARTUP_UNKNOWN";
280
+ const rootCode = root?.code ?? (wrappers.has(code) ? "STARTUP_UNKNOWN" : code);
281
+ return buildDiagnostic({
282
+ code,
283
+ rootCode,
284
+ component: safeStartupValue(component, 128),
285
+ phase: typeof phase === "string" && phases.has(phase)
286
+ ? phase
287
+ : location.phase,
288
+ context,
289
+ causes,
290
+ ...(cleanup ? { cleanup } : {}),
291
+ truncated
292
+ });
293
+ }
294
+ function buildDiagnostic(facts) {
295
+ const { rootCode } = facts;
296
+ const catalog = STARTUP_CATALOG[rootCode] ?? STARTUP_CATALOG.STARTUP_UNKNOWN;
297
+ const context = safeContext({
298
+ ...(catalog.configKey ? { configKey: catalog.configKey } : {}),
299
+ ...facts.context
300
+ });
301
+ const details = Object.entries(context)
302
+ .map(([key, value]) => `${key}=${JSON.stringify(value)}`)
303
+ .join(", ");
304
+ let action = catalog.action;
305
+ if (rootCode === "ENOENT" && context.executable)
306
+ action = `Check that executable ${JSON.stringify(context.executable)} is installed and the host's selected working directory exists. Correct the executable or working directory configuration, then retry. Creating a directory does not provide an executable.`;
307
+ else if (rootCode === "ENOENT" && context.resource === "directory")
308
+ action = `Correct the configured directory ${JSON.stringify(context.path ?? "unknown")}, or create it if this is the intended location, then retry.`;
309
+ else if (["HOME_NOT_FOUND", "HOME_NOT_DIRECTORY"].includes(rootCode) &&
310
+ context.resource &&
311
+ context.resource !== "home" &&
312
+ context.resource !== "home-probe")
313
+ action = `Inspect the reported ${JSON.stringify(context.resource)} path and its parent directory. Correct the host's resource selection or prepare its required parent directory, then retry. Do not create a replacement Runtime Home or delete an unrelated resource.`;
314
+ if (context.configKey)
315
+ action += ` Check configuration key ${JSON.stringify(context.configKey)}.`;
316
+ return {
317
+ ...facts,
318
+ domain: "startup",
319
+ context,
320
+ summary: catalog.summary,
321
+ explanation: `${catalog.summary}${details ? ` Observed: ${details}.` : " No further safe resource facts were recorded."}`,
322
+ actions: [action],
323
+ retryable: catalog.retryable,
324
+ userActionRequired: !catalog.retryable
325
+ };
326
+ }
327
+ /** 可读投影只消费已净化的共享结构;SDK 可直接按 rootCode/context 分支。 */
328
+ export function formatStartupDiagnostic(diagnostic) {
329
+ const nested = diagnostic.causes
330
+ .filter((cause) => cause.cleanup && !cause.cleanup.complete)
331
+ .map((cause) => `\nCause cleanup [${cause.code}]${cause.component ? ` (${cause.component})` : ""}: incomplete; pending: ${cause.cleanup?.pendingResources.join(", ") || "none"}`)
332
+ .join("");
333
+ return `[${diagnostic.code}] ${diagnostic.explanation}\nComponent: ${diagnostic.component}; phase: ${diagnostic.phase}; root: ${diagnostic.rootCode}\n${diagnostic.actions.map((action) => `Action: ${action}`).join("\n")}${diagnostic.cleanup ? `\nCleanup: ${diagnostic.cleanup.complete ? "complete" : "incomplete"}; pending: ${diagnostic.cleanup.pendingResources.join(", ") || "none"}` : ""}${nested}${diagnostic.truncated ? "\nDetails: additional causes were omitted by diagnostic limits." : ""}`;
334
+ }
335
+ /** 持久化/JSON 是不可信边界:仅重建码、位置、资源和清理,文案始终重新来自当前 catalog。 */
336
+ export function restoreStartupDiagnostic(value) {
337
+ const code = codeOf(own(value, "code")), rootCode = codeOf(own(value, "rootCode"));
338
+ const component = own(value, "component"), phase = own(value, "phase"), causes = arrayItems(own(value, "causes"), 16);
339
+ if (own(value, "domain") !== "startup" ||
340
+ !code ||
341
+ !rootCode ||
342
+ typeof component !== "string" ||
343
+ typeof phase !== "string" ||
344
+ !phases.has(phase) ||
345
+ !causes)
346
+ return undefined;
347
+ const context = safeContext(own(value, "context"));
348
+ const cleanup = safeCleanup(own(value, "cleanup"));
349
+ return buildDiagnostic({
350
+ code,
351
+ rootCode,
352
+ component: safeStartupValue(component, 128),
353
+ phase: phase,
354
+ context,
355
+ causes: causes.map(safeCause),
356
+ ...(cleanup ? { cleanup } : {}),
357
+ truncated: own(value, "truncated") === true || Number(own(own(value, "causes"), "length")) > 16
358
+ });
359
+ }
360
+ /** 仅供启动边界补充已确认的位置事实;cause 保留给本地深度排障,公开输出用 diagnostic。 */
361
+ export class StartupError extends Error {
362
+ code;
363
+ diagnostic;
364
+ constructor(code, location, cause) {
365
+ super(code, { cause });
366
+ this.name = "StartupError";
367
+ this.code = code;
368
+ Object.defineProperty(this, "startupContext", { value: location.context });
369
+ this.diagnostic = describeStartupError(this, location);
370
+ }
371
+ }
@@ -0,0 +1,10 @@
1
+ import { KernelError } from "./types.js";
2
+ /** 包内接纳检查专用;当前 client 在请求写出前拒绝时创建证据。 */
3
+ export declare function admissionClosedError(): KernelError;
4
+ /** 仅实际 invoke RPC 的拒绝响应、且实例和专用证据均匹配,才标记未进入执行源。 */
5
+ export declare function markSubmissionRejected(error: unknown, instance: string): void;
6
+ /**
7
+ * 判断本模块验证的未执行拒绝;包装、序列化及同名错误均返回 false。
8
+ * 只证明本次未进入执行源,不证明此前业务尝试没有执行,也不授权自动重放。
9
+ */
10
+ export declare function isInvocationNotSubmitted(error: unknown): boolean;
@@ -0,0 +1,23 @@
1
+ import { KernelError } from "./types.js";
2
+ const notSubmitted = new WeakSet();
3
+ /** 包内接纳检查专用;当前 client 在请求写出前拒绝时创建证据。 */
4
+ export function admissionClosedError() {
5
+ const error = new KernelError("CLIENT_INVOCATION_ADMISSION_CLOSED");
6
+ notSubmitted.add(error);
7
+ return error;
8
+ }
9
+ /** 仅实际 invoke RPC 的拒绝响应、且实例和专用证据均匹配,才标记未进入执行源。 */
10
+ export function markSubmissionRejected(error, instance) {
11
+ if (error instanceof KernelError &&
12
+ ["KERNEL_UNAVAILABLE", "WORKER_RESTART_EXHAUSTED"].includes(error.code) &&
13
+ error.data?.invocation_not_submitted === true &&
14
+ error.data.kernel_instance_id === instance)
15
+ notSubmitted.add(error);
16
+ }
17
+ /**
18
+ * 判断本模块验证的未执行拒绝;包装、序列化及同名错误均返回 false。
19
+ * 只证明本次未进入执行源,不证明此前业务尝试没有执行,也不授权自动重放。
20
+ */
21
+ export function isInvocationNotSubmitted(error) {
22
+ return error instanceof KernelError && notSubmitted.has(error);
23
+ }
@@ -0,0 +1,72 @@
1
+ import type { KernelLookupKey, KernelRunRef, KernelRunSnapshot, KernelStatus, InvokeInput, InvokeEnvironment, InputInvoke, HostFrame, InteractionResponse, NativeInteractionResponse } from "@mininglamp-oss/octo-runtime-protocol";
2
+ import type { HostedAdapterMetadata } from "@mininglamp-oss/octo-runtime-protocol";
3
+ export type LookupKey = KernelLookupKey;
4
+ export type RunRef = KernelRunRef;
5
+ export type RunSnapshot = KernelRunSnapshot;
6
+ export type { KernelStatus };
7
+ export interface KernelInvocationRecord {
8
+ readonly key: LookupKey;
9
+ readonly ref?: RunRef;
10
+ readonly phase: "admitting" | "accepted" | "acceptance_unknown" | "unobserved";
11
+ readonly cancellation: "none" | "requested" | "acknowledged" | "unknown";
12
+ readonly lastSeq: number;
13
+ readonly observationError?: string;
14
+ }
15
+ /** 只确认本 client 登记的执行是否排空;不代表卡片投递或业务 dispose 已完成。 */
16
+ export interface KernelInvocationDrainResult {
17
+ readonly complete: boolean;
18
+ readonly unresolved: readonly KernelInvocationRecord[];
19
+ }
20
+ export interface KernelInvocationLifecycle {
21
+ /** 身份与观察状态的副本,不缓存消息正文;结果未知的执行仍保留在列表中。 */
22
+ snapshot(): readonly KernelInvocationRecord[];
23
+ /** 同步关闭 invoke 接纳;已有执行仍可取消、查询和消费尾流。 */
24
+ stopAdmission(): void;
25
+ /** 共享 Date.now() 毫秒绝对期限;首次调用确定预算,后续调用复用同一排空结果。 */
26
+ drain(options: {
27
+ deadline: number;
28
+ reason: string;
29
+ }): Promise<KernelInvocationDrainResult>;
30
+ }
31
+ /**
32
+ * 附着到独立 Kernel 的客户端,不拥有 Kernel 进程。
33
+ * 常规接入使用 invoke;owner 退出时先 stopAdmission,再并行 drain 与业务收尾,最后 close。
34
+ * submit/subscribe 是低层入口,调用方自行保存 RunRef、管理取消与尾流,不自动登记为 invoke。
35
+ */
36
+ export interface KernelClient {
37
+ readonly topology: "kernel-ipc";
38
+ readonly ownership: "attached";
39
+ /** 开始消费才提交;signal 请求取消但保留尾流,提前结束迭代则仅停止观察。 */
40
+ readonly invoke: InputInvoke;
41
+ readonly invocations: KernelInvocationLifecycle;
42
+ /** 仅操作当前 client 的 invoke 登记;accepted 是取消受理,不是终态或清理完成。 */
43
+ cancelInvocation(invocationId: string, reason?: string): Promise<{
44
+ accepted: boolean;
45
+ }>;
46
+ respondInteraction(invocationId: string, response: InteractionResponse): Promise<void>;
47
+ respondNativeInteraction(invocationId: string, response: NativeInteractionResponse): Promise<void>;
48
+ status(): Promise<KernelStatus>;
49
+ list(): Promise<HostedAdapterMetadata[]>;
50
+ /** 接纳后由 Kernel 持续驱动执行;ACK 丢失只查原身份,不重复执行。 */
51
+ submit(input: InvokeInput, environment?: InvokeEnvironment): Promise<{
52
+ ref: RunRef;
53
+ }>;
54
+ /** 按完整 LookupKey 查询原执行;指定 expectedInstance 可拒绝服务重启后的同名身份。 */
55
+ get(key: LookupKey, expectedInstance?: string): Promise<RunSnapshot>;
56
+ /** 从 afterSeq 之后观察同一执行;signal 只关闭订阅,游标过期/身份变化须交给调用方处理。 */
57
+ subscribe(ref: RunRef, afterSeq?: number, signal?: AbortSignal): AsyncGenerator<HostFrame>;
58
+ /** 显式控制原 RunRef;ACK 丢失报结果未知,不能自动重试可能已受理的控制动作。 */
59
+ cancel(ref: RunRef, reason?: string): Promise<{
60
+ accepted: boolean;
61
+ }>;
62
+ /** 交互响应必须匹配原引用和协议模式,过期/未知的响应不能改投其他 Run。 */
63
+ respond(ref: RunRef, response: InteractionResponse): Promise<void>;
64
+ respondNative(ref: RunRef, response: NativeInteractionResponse): Promise<void>;
65
+ /** 释放本 client 的连接和控制请求,不取消已接纳 Run,也不关闭共享 Kernel。 */
66
+ close(): void;
67
+ }
68
+ export declare class KernelError extends Error {
69
+ readonly code: string;
70
+ readonly data?: Record<string, unknown> | undefined;
71
+ constructor(code: string, data?: Record<string, unknown> | undefined);
72
+ }
package/dist/types.js ADDED
@@ -0,0 +1,10 @@
1
+ export class KernelError extends Error {
2
+ code;
3
+ data;
4
+ constructor(code, data) {
5
+ super(code);
6
+ this.code = code;
7
+ this.data = data;
8
+ this.name = "KernelError";
9
+ }
10
+ }
@@ -0,0 +1,4 @@
1
+ import type { ContextEnvelope, ExecutionEvidence } from "./generated/protocol-types.js";
2
+ /** 只读取本轮已解析的显式意图;不补默认、不读取历史会话。 */
3
+ export declare function contextActmode(context: ContextEnvelope): "default" | "plan" | undefined;
4
+ export declare function assertExecutionEvidence(value: unknown): asserts value is ExecutionEvidence;
@@ -0,0 +1,36 @@
1
+ /** 只读取本轮已解析的显式意图;不补默认、不读取历史会话。 */
2
+ export function contextActmode(context) {
3
+ const item = context.items.find((item) => item.namespace === "octo.execution" && item.name === "actmode");
4
+ if (!item)
5
+ return undefined;
6
+ if (item.payload.mode !== "default" && item.payload.mode !== "plan")
7
+ throw new TypeError("CONTEXT_SCHEMA_INVALID");
8
+ return item.payload.mode;
9
+ }
10
+ export function assertExecutionEvidence(value) {
11
+ if (!record(value) ||
12
+ Object.keys(value).some((key) => key !== "actmode") ||
13
+ !record(value.actmode))
14
+ throw new TypeError("EXECUTION_EVIDENCE_INVALID");
15
+ const mode = value.actmode;
16
+ if (Object.keys(mode).some((key) => !["requested", "effective", "status", "nativeMode", "reason"].includes(key)) ||
17
+ (mode.requested !== "default" && mode.requested !== "plan") ||
18
+ !["default", "plan", null].includes(mode.effective) ||
19
+ (mode.status !== "applied" && mode.status !== "fallback" && mode.status !== "unknown") ||
20
+ (mode.nativeMode !== undefined && (typeof mode.nativeMode !== "string" || !mode.nativeMode)) ||
21
+ (mode.reason !== undefined &&
22
+ mode.reason !== "provider_unsupported" &&
23
+ mode.reason !== "adapter_unmapped" &&
24
+ mode.reason !== "provider_unconfirmed") ||
25
+ (mode.status === "applied" &&
26
+ (mode.effective !== mode.requested || mode.reason !== undefined)) ||
27
+ (mode.status === "fallback" &&
28
+ (mode.effective !== "default" ||
29
+ (mode.reason !== "provider_unsupported" && mode.reason !== "adapter_unmapped"))) ||
30
+ (mode.status === "unknown" &&
31
+ (mode.effective !== null || mode.reason !== "provider_unconfirmed")))
32
+ throw new TypeError("EXECUTION_EVIDENCE_INVALID");
33
+ }
34
+ function record(value) {
35
+ return value !== null && typeof value === "object" && !Array.isArray(value);
36
+ }
@@ -0,0 +1,7 @@
1
+ import type { AdapterProtocolSupport } from "./run-protocol.js";
2
+ import type { HostedAdapterMetadataWire } from "./generated/protocol-types.js";
3
+ /** 宿主注册及执行时使用的完整元数据;编写时的可选默认值须由 Adapter 工厂先补齐。 */
4
+ export type HostedAdapterMetadata = Pick<HostedAdapterMetadataWire, "workspace" | "type" | "agentSources" | "processModel" | "transport" | "providerVersion" | "providerPath" | "available" | "unavailableReason"> & {
5
+ /** wire 可省略的编写输入不能放宽 Core 注册合同。 */
6
+ protocolSupport: AdapterProtocolSupport;
7
+ };
@@ -0,0 +1,7 @@
1
+ export type * from "./generated/protocol-types.js";
2
+ export * from "./questions.js";
3
+ export * from "./context.js";
4
+ export * from "./model-context.js";
5
+ export * from "./execution-plan.js";
6
+ export * from "./context-configuration.js";
7
+ export * from "./context-catalog.js";
@@ -0,0 +1,6 @@
1
+ export * from "./questions.js";
2
+ export * from "./context.js";
3
+ export * from "./model-context.js";
4
+ export * from "./execution-plan.js";
5
+ export * from "./context-configuration.js";
6
+ export * from "./context-catalog.js";
@@ -0,0 +1,11 @@
1
+ export interface ContextTypeDefinition {
2
+ readonly namespace: string;
3
+ readonly name: string;
4
+ readonly schemaRef: string;
5
+ readonly persistent: boolean;
6
+ readonly trustedOnly: boolean;
7
+ }
8
+ /** Built-in schema and execution-configuration classification; no processing stages. */
9
+ export declare const CONTEXT_TYPE_CATALOG: readonly ContextTypeDefinition[];
10
+ export declare function contextTypeDefinition(namespace: string, name: string): ContextTypeDefinition;
11
+ export declare function findContextTypeDefinition(namespace: string, name: string): ContextTypeDefinition | undefined;
@@ -0,0 +1,33 @@
1
+ function entry(namespace, name, schema, persistent, trustedOnly = false) {
2
+ return Object.freeze({
3
+ namespace,
4
+ name,
5
+ schemaRef: `#/definitions/${schema}`,
6
+ persistent,
7
+ trustedOnly
8
+ });
9
+ }
10
+ /** Built-in schema and execution-configuration classification; no processing stages. */
11
+ export const CONTEXT_TYPE_CATALOG = Object.freeze([
12
+ entry("octo.execution", "adapter", "ContextAdapterPayload", true),
13
+ entry("octo.execution", "model", "ContextModelPayload", true),
14
+ entry("octo.execution", "actmode", "ContextActmodePayload", true),
15
+ entry("octo.execution", "workspace", "ContextWorkspacePayload", true),
16
+ entry("octo.execution", "envs", "ContextEnvsPayload", true),
17
+ entry("octo.execution", "mcp", "ContextMcpPayload", true),
18
+ entry("octo.execution", "limits", "ContextLimitsPayload", true),
19
+ entry("octo.runtime", "selection", "ContextRuntimeSelectionPayload", true),
20
+ entry("octo.security", "approval_policy", "ContextApprovalPolicyPayload", true),
21
+ entry("octo.content", "inline", "ContextInlinePayload", false),
22
+ entry("octo.content", "references", "ContextReferencesPayload", false),
23
+ entry("octo.control", "instructions", "ContextInstructionsPayload", true, true)
24
+ ]);
25
+ export function contextTypeDefinition(namespace, name) {
26
+ const definition = findContextTypeDefinition(namespace, name);
27
+ if (!definition)
28
+ throw new TypeError(`CONTEXT_TYPE_UNSUPPORTED: ${namespace}/${name}`);
29
+ return definition;
30
+ }
31
+ export function findContextTypeDefinition(namespace, name) {
32
+ return CONTEXT_TYPE_CATALOG.find((item) => item.namespace === namespace && item.name === name);
33
+ }
@@ -0,0 +1,5 @@
1
+ import type { ContextConfiguration, ContextEnvelope } from "./generated/protocol-types.js";
2
+ /** 校验可持久化配置;身份、资源权限和强制来源仍由 Worker 验证。 */
3
+ export declare function assertContextConfiguration(value: unknown): asserts value is ContextConfiguration;
4
+ /** Agent mandatory values are authoritative; request differences are overwritten. */
5
+ export declare function resolveContextConfiguration(configuration: ContextConfiguration, request: ContextEnvelope): ContextEnvelope;