abelien-harness 0.16.0 → 0.16.1

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 CHANGED
@@ -73,6 +73,8 @@ ab generate 3d <providers|submit|status|fetch> …
73
73
  ab doctor
74
74
  ```
75
75
 
76
+ `studio probe` 只登记 `state.probe` bootstrap 凭据的安装消费,不是通用健康检查。主回合凭据会在网络前被拒绝;不要据此判定全部 Studio 工具不可用,也不要自动刷新或重试 probe。具体工具仍由其权限与宿主授权判定。
77
+
76
78
  输出契约:stdout 恒为单行 JSON——成功 `{ok:true,data}`(exit 0);
77
79
  运行错误 `{ok:false,error:{code,message,details?}}`(exit 1);
78
80
  用法错误同结构写 stderr(exit 2)。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "abelien-harness",
3
- "version": "0.16.0",
3
+ "version": "0.16.1",
4
4
  "description": "npx-installable multi-agent skill harness: generic kernel + pluggable domain packs",
5
5
  "type": "module",
6
6
  "engines": {
@@ -120,6 +120,13 @@ ab studio invocation get <invocationId>
120
120
  以同 workflow identity 和根预算创建后继 attempt。已有点选必须与原 designContext 一致;纯文字目标
121
121
  仍须由 Web 在当前 F2 editableTargets 唯一验证。CLI 不接受自由文字直接扩大 target 或 impact。
122
122
 
123
+ `studio probe` 是安装消费登记,只接受 `state.probe` actionScope 及 `state:read`、
124
+ `requests:write`,不是通用健康检查。其它 actionScope 在网络前返回
125
+ `STUDIO_PROBE_CONTEXT_REQUIRED`;不自动更新凭据或重试。每次命令调用重新读取当前文件。
126
+ 合法上下文收到 broker HTTP 403 时,两种现有错误 envelope 的错误码、status、retry、requestId
127
+ 保持原义,并增加 `details.context = {attemptId, expiresAt, actionScope}`;仅发送一次请求。
128
+ 该严格白名单不包含 token、secret、origin、owner,也不证明签名或服务端当前 attempt 有效。
129
+
123
130
  CLI 默认只读固定 `/home/agent/workspace/abelien-runtime-delegation/current.json`,与 Web EaaS driver
124
131
  的 file-API 挂载根一致;不搜索旧 `/tmp` 路径,也不提供 CLI/环境变量/模型 context、origin 或 token override。
125
132
  受信本地宿主仍可通过模块级 `studioCmd(...,{contextFile})` 注入隔离上下文;它不构成容器默认路径验收。
@@ -26,7 +26,7 @@ export { interpolate, findWorkflow, loadWorkflow, resolveWorkflowDefinition, wor
26
26
  // doctor must report the shipped package version, never a frozen constant (0.2.3 drifted across
27
27
  // six releases). The npm tree always ships package.json at the skill root; standalone skill copies
28
28
  // fall back to FALLBACK_VERSION, which scripts/release-check.mjs pins to package.json.
29
- const FALLBACK_VERSION = "0.16.0";
29
+ const FALLBACK_VERSION = "0.16.1";
30
30
  export let VERSION = FALLBACK_VERSION;
31
31
  try {
32
32
  VERSION = String(JSON.parse(fs.readFileSync(new URL("../../../package.json", import.meta.url), "utf8")).version || FALLBACK_VERSION);
@@ -53,7 +53,7 @@ const COMMAND_HELP = [
53
53
  example: `workflow run user-journey --input '{"prompt":"…"}'` },
54
54
  { name: "studio",
55
55
  usage: "studio probe\n studio replacement request --input '<json>'\n studio creation create --input '<json>' | active | get <id>\n studio modification create --input '<json>' | active | get <id>\n studio tool register --input '<json>'\n studio invocation submit --input '<json>' | get <id>",
56
- about: "宿主可信集成面(创建/修改/工具/调用登记),宿主进程专用,模型不直接调用",
56
+ about: "宿主可信集成面(创建/修改/工具/调用登记),宿主进程专用,模型不直接调用;probe 只登记 state.probe bootstrap 安装消费,不是通用健康检查",
57
57
  example: `studio probe` },
58
58
  { name: "receipt",
59
59
  usage: "receipt consume --file <path> | get --wait <waitId> [--digest <sha256>]",
@@ -303,14 +303,19 @@ async function responseJson(response) {
303
303
  if (Buffer.byteLength(body) > MAX_RESPONSE_BYTES) throw fail("STUDIO_RESPONSE_INVALID", "Studio response is too large");
304
304
  try { return JSON.parse(body); } catch { throw fail("STUDIO_RESPONSE_INVALID", "Studio response is invalid JSON"); }
305
305
  }
306
- function serverError(value, status) {
306
+ function serverError(value, status, context) {
307
+ // Never spread the context: only these validated, non-credential fields may
308
+ // explain a forbidden attempt. The broker remains the authority on freshness.
309
+ const diagnostic = status === 403 ? {context: {
310
+ attemptId: context.attemptId, expiresAt: context.expiresAt, actionScope: context.actionScope,
311
+ }} : {};
307
312
  if (value && typeof value === "object" && !Array.isArray(value)
308
313
  && Object.keys(value).length === 1 && value.error && typeof value.error === "object" && !Array.isArray(value.error)) {
309
314
  const error = exact(value.error, ["code", "requestId"], [], "Agent runtime error");
310
315
  if (typeof error.code === "string" && typeof error.requestId === "string") {
311
316
  const retry = status >= 500 ? "backoff" : status === 409 ? "resync" : "never";
312
317
  throw fail(`STUDIO_${error.code.toUpperCase().replace(/[^A-Z0-9]+/g, "_")}`,
313
- "Studio runtime rejected the request", { status, retry, requestId: error.requestId });
318
+ "Studio runtime rejected the request", { status, retry, requestId: error.requestId, ...diagnostic });
314
319
  }
315
320
  }
316
321
  const body = exact(value, ["schemaVersion", "requestId", "error"], [], "Studio error");
@@ -320,7 +325,7 @@ function serverError(value, status) {
320
325
  throw fail("STUDIO_RESPONSE_INVALID", "Studio error response is invalid");
321
326
  }
322
327
  throw fail(`STUDIO_${error.code.toUpperCase().replace(/[^A-Z0-9]+/g, "_")}`,
323
- "Studio broker rejected the request", { status, retry: error.retry, requestId: body.requestId });
328
+ "Studio broker rejected the request", { status, retry: error.retry, requestId: body.requestId, ...diagnostic });
324
329
  }
325
330
  function safeInvocation(value) {
326
331
  const row = exact(value, ["invocationId", "operationId", "tool", "policyId", "policyVersion", "status", "accounting", "output", "error"], ["execution"], "invocation");
@@ -454,7 +459,7 @@ async function request(context, method, suffix, body, kind, fetchImpl) {
454
459
  }
455
460
  if (response.ok) return safeSuccess(kind, value);
456
461
  if (response.status >= 500 && attempt + 1 < attempts) continue;
457
- serverError(value, response.status);
462
+ serverError(value, response.status, context);
458
463
  }
459
464
  throw fail("STUDIO_READ_UNAVAILABLE", "Studio broker is unavailable", {retry: "backoff"});
460
465
  }
@@ -466,6 +471,11 @@ export async function studioCmd(pos, flags, deps = {}) {
466
471
  const context = readStudioContext(deps.contextFile ?? STUDIO_CONTEXT_FILE, deps.now?.() ?? Date.now());
467
472
  if (resource === "probe" && action === undefined) {
468
473
  argsExactly(pos, 1, "studio probe"); flagsOnly(flags);
474
+ if (context.actionScope !== "state.probe") {
475
+ throw fail("STUDIO_PROBE_CONTEXT_REQUIRED",
476
+ "Studio installation probe requires a state.probe bootstrap context; it is not a health check");
477
+ }
478
+ // parseStudioContext already requires state:read for every delegation.
469
479
  requireScope(context, "requests:write");
470
480
  return request(context, "POST", "probe", {schemaVersion: 1}, "probe", fetchImpl);
471
481
  }