grokbox 0.1.0-alpha.7 → 0.1.0-alpha.8

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
@@ -10,9 +10,8 @@ This project is not affiliated with or endorsed by Anysphere, Cursor, xAI, or
10
10
  Grok Bot. Grok Bot, Cursor, and related names identify compatible products and
11
11
  remain the property of their respective owners.
12
12
 
13
- > **Alpha:** current source is `0.1.0-alpha.7`. npm `next` currently points to
14
- > `0.1.0-alpha.6`; `0.0.1` remains `latest`. `v0.1.0-alpha.1` through
15
- > `v0.1.0-alpha.6` exist as Git tags only. Prereleases publish only after
13
+ > **Alpha:** current source is `0.1.0-alpha.8`. npm `next` currently points to
14
+ > `0.1.0-alpha.7`; `0.0.1` remains `latest`. Prereleases publish only after
16
15
  > release checks and explicitly scoped external acceptance.
17
16
 
18
17
  ## What it does
@@ -148,7 +147,7 @@ grokbox jobs list --table
148
147
  grokbox desktop status --table
149
148
  ```
150
149
 
151
- Routine reads expose bounded metadata only: prompt bodies, webhook credentials, native paths, and unknown provider fields stay private. Routine create always writes a disabled definition; update/enable/disable/delete require explicit confirmation, and all mutations other than create also require the exact revision from a fresh `agents routines list/show`. Upstream Routine writes have no native compare-and-swap or idempotency contract, so an uncertain acknowledgement is never replayed automatically.
150
+ Routine reads expose bounded metadata only: prompt bodies, webhook credentials, native paths, and unknown provider fields stay private. Box-local Bots support create/update/enable/disable/delete; create always writes a disabled definition and later mutations require explicit confirmation plus the exact revision from a fresh `agents routines list/show`. Temporal Bots are Server-authoritative: list/show, webhook credential, enable/disable, and delete use the bounded Temporal Routine bridge; current upstream contracts do not expose Temporal definition create/update, so those commands refuse instead of writing the legacy Box store. `agents routines webhook credential <agent> <routine-id> --confirm` returns the URL while hiding the key; add `--reveal-key` only when secret output is explicitly required. Without the Host bridge, Temporal Routine reads fail closed rather than reporting a false empty list. Upstream Routine writes have no native compare-and-swap or idempotency contract, so an uncertain acknowledgement is never replayed automatically.
152
151
 
153
152
  Mutating commands require explicit capability and, where destructive, explicit
154
153
  confirmation. `desktop prune run` defaults to dry-run; `--yes` invokes the
package/README.zh-CN.md CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  本项目与 Anysphere、Cursor、xAI 或 Grok Bot 没有隶属或背书关系。Grok Bot、Cursor 及相关名称仅用于标识兼容产品,其权利归各自所有者。
8
8
 
9
- > **Alpha:** 当前源码版本是 `0.1.0-alpha.7`。npm 的 `next` dist-tag 目前指向 `0.1.0-alpha.6`;`0.0.1` 仍是 `latest`。`v0.1.0-alpha.1` 到 `v0.1.0-alpha.6` 已有 Git tag。只有通过发布检查及明确范围的外部验收后,才会发布新的预发布版本。
9
+ > **Alpha:** 当前源码版本是 `0.1.0-alpha.8`。npm 的 `next` dist-tag 目前指向 `0.1.0-alpha.7`;`0.0.1` 仍是 `latest`。只有通过发布检查及明确范围的外部验收后,才会发布新的预发布版本。
10
10
 
11
11
  ## 它能做什么
12
12
 
@@ -128,7 +128,7 @@ grokbox jobs list --table
128
128
  grokbox desktop status --table
129
129
  ```
130
130
 
131
- Routine 读取只输出有界元数据,不暴露 prompt 正文、Webhook credential、原生路径或未知 provider 字段。Routine create 始终只创建 disabled definition;update/enable/disable/delete 需要显式确认,create 之外的 mutation 还必须携带刚从 `agents routines list/show` 读到的精确 revision。上游 Routine 写接口没有 native compare-and-swap 或 idempotency 合同,因此回执不确定时不会自动重放。
131
+ Routine 读取只输出有界元数据,不暴露 prompt 正文、Webhook credential、原生路径或未知 provider 字段。Box-local Bot 支持 create/update/enable/disable/delete;create 始终只创建 disabled definition,后续 mutation 需要显式确认,并携带刚从 `agents routines list/show` 读到的精确 revision。Temporal Bot 的 Routine 以 Server 为权威:list/show、Webhook credential、enable/disable/delete 通过受限的 Temporal Routine bridge;当前官方合同没有暴露 Temporal definition create/update,因此 CLI 会明确拒绝,而不会误写旧 Box store。`agents routines webhook credential <agent> <routine-id> --confirm` 默认返回 URL 并隐藏 key;只有显式增加 `--reveal-key` 才把 key 输出到 stdout。Host bridge 不可用时,Temporal Routine 查询 fail-closed,不再冒充为空列表。上游 Routine 写接口没有 native compare-and-swap 或 idempotency 合同,因此回执不确定时不会自动重放。
132
132
 
133
133
  变更命令需要显式 capability;破坏性操作还需要显式确认。`desktop prune run` 默认 dry-run;传入 `--yes` 后会调用上游 stop-window 路径,并删除该 fork 的 Chrome profile。
134
134
 
package/dist/index.js CHANGED
@@ -3474,7 +3474,7 @@ import { fileURLToPath } from "node:url";
3474
3474
  // package.json
3475
3475
  var package_default = {
3476
3476
  name: "grokbox",
3477
- version: "0.1.0-alpha.7",
3477
+ version: "0.1.0-alpha.8",
3478
3478
  packageManager: "bun@1.3.14",
3479
3479
  description: "Unofficial CLI and control plane for Grok Bot cloud computers",
3480
3480
  license: "MIT",
@@ -4069,6 +4069,25 @@ var LEAF_COMMANDS = [
4069
4069
  gateway: true,
4070
4070
  streaming: false
4071
4071
  },
4072
+ {
4073
+ path: ["agents", "routines", "webhook", "credential"],
4074
+ usage: "grokbox agents routines webhook credential <agent> <routine-id> --confirm [--reveal-key]",
4075
+ summary: "Read or mint one webhook Routine credential; key is hidden unless explicitly revealed.",
4076
+ arguments: [
4077
+ { syntax: "<agent>", description: "Agent ID or unambiguous name/title", role: "agent", kinds: ["agent"] },
4078
+ { syntax: "<routine-id>", description: "Exact native Routine ID" }
4079
+ ],
4080
+ options: options([
4081
+ { flags: "--confirm", description: "Confirm credential access/mint", required: true },
4082
+ { flags: "--reveal-key", description: "Include the sensitive webhook key in stdout" }
4083
+ ], { timeout: true }),
4084
+ stdin: "none",
4085
+ table: false,
4086
+ timeout: true,
4087
+ destructive: true,
4088
+ gateway: true,
4089
+ streaming: false
4090
+ },
4072
4091
  ...["enable", "disable", "delete"].map((action) => ({
4073
4092
  path: ["agents", "routines", action],
4074
4093
  usage: `grokbox agents routines ${action} <agent> <routine-id> --expect-revision <sha256> --confirm`,
@@ -5584,6 +5603,8 @@ var DAEMON_METHODS = [
5584
5603
  "getAgentThread",
5585
5604
  "getAgentMemories",
5586
5605
  "getAgentAutomations",
5606
+ "getGrokboxRoutineAuthority",
5607
+ "getAutomationWebhookCredential",
5587
5608
  "createAgentAutomation",
5588
5609
  "updateAgentAutomation",
5589
5610
  "setAgentAutomationEnabled",
@@ -5631,6 +5652,7 @@ var DAEMON_CAPABILITIES = [
5631
5652
  "grok.transcript.write",
5632
5653
  "grok.memory.read",
5633
5654
  "grok.routines.read",
5655
+ "grok.routines.credentials",
5634
5656
  "grok.routines.write",
5635
5657
  "grok.roster.write",
5636
5658
  "grok.events.read"
@@ -6302,6 +6324,28 @@ var GatewayClient = class {
6302
6324
  }
6303
6325
  return await this.rpc("getAgentAutomations", { id }, { timeoutMs });
6304
6326
  }
6327
+ async getGrokboxRoutineAuthority(id, timeoutMs) {
6328
+ const daemon = await this.daemonFor("grok.routines.read", timeoutMs);
6329
+ if (daemon) {
6330
+ const response = await daemon.call("getGrokboxRoutineAuthority", { id, timeoutMs });
6331
+ if (!response.gateway) throw new CliError("gateway_internal", "Daemon Routine authority response lacks generation.");
6332
+ const discovery = this.discoveryFromDaemon(response.gateway);
6333
+ this.lastDiscovery = discovery;
6334
+ return { result: response.result, discovery };
6335
+ }
6336
+ return await this.rpc("getGrokboxRoutineAuthority", { id }, { timeoutMs });
6337
+ }
6338
+ async getAutomationWebhookCredential(id, automationId, timeoutMs) {
6339
+ const daemon = await this.daemonFor("grok.routines.credentials", timeoutMs);
6340
+ if (daemon) {
6341
+ const response = await daemon.call("getAutomationWebhookCredential", { id, automationId, timeoutMs });
6342
+ if (!response.gateway) throw new CliError("gateway_internal", "Daemon Routine credential response lacks generation.");
6343
+ const discovery = this.discoveryFromDaemon(response.gateway);
6344
+ this.lastDiscovery = discovery;
6345
+ return { result: response.result, discovery };
6346
+ }
6347
+ return await this.rpc("getAutomationWebhookCredential", { id, automationId }, { timeoutMs });
6348
+ }
6305
6349
  async createAgentAutomation(body, timeoutMs, operationId2, expectedGateway) {
6306
6350
  return await this.routineWrite("createAgentAutomation", body, timeoutMs, operationId2, expectedGateway);
6307
6351
  }
@@ -11592,6 +11636,19 @@ async function startDaemonHost(deps, socketPath, networkConfig, filesystemRoots
11592
11636
  const value = await gateway.getAgentAutomations(id, params.timeoutMs);
11593
11637
  return { result: value.result, gateway: gatewayMeta(value.discovery) };
11594
11638
  }
11639
+ if (method === "getGrokboxRoutineAuthority") {
11640
+ assertExactParams(params, { id: "string", timeoutMs: "number" });
11641
+ const id = routineInput(() => routineAgentId(params.id));
11642
+ const value = await gateway.getGrokboxRoutineAuthority(id, params.timeoutMs);
11643
+ return { result: value.result, gateway: gatewayMeta(value.discovery) };
11644
+ }
11645
+ if (method === "getAutomationWebhookCredential") {
11646
+ assertExactParams(params, { id: "string", automationId: "string", timeoutMs: "number" });
11647
+ const id = routineInput(() => routineAgentId(params.id));
11648
+ const automationId = routineInput(() => routineId(params.automationId));
11649
+ const value = await gateway.getAutomationWebhookCredential(id, automationId, params.timeoutMs);
11650
+ return { result: value.result, gateway: gatewayMeta(value.discovery) };
11651
+ }
11595
11652
  if (method === "createAgentAutomation") {
11596
11653
  assertParamKeys(params, ["id", "spec", "timeoutMs", "expectedGatewayPid", "expectedGatewayStartedAt"], "Routine create");
11597
11654
  const id = routineInput(() => routineAgentId(params.id));
@@ -14904,7 +14961,11 @@ async function resolveAgent(client2, target, timeoutMs) {
14904
14961
  const roster = await client2.listAgents(timeoutMs);
14905
14962
  const row = findRosterRow(roster.agents, target, ["agent"]);
14906
14963
  try {
14907
- return { id: routineAgentId(asString(row.id)), discovery: gatewayMeta(roster.discovery) };
14964
+ return {
14965
+ id: routineAgentId(asString(row.id)),
14966
+ discovery: gatewayMeta(roster.discovery),
14967
+ harness: row.harness === "temporal" ? "temporal" : row.harness === "box" ? "box" : null
14968
+ };
14908
14969
  } catch {
14909
14970
  throw new CliError(
14910
14971
  "capability_unavailable",
@@ -14912,12 +14973,46 @@ async function resolveAgent(client2, target, timeoutMs) {
14912
14973
  );
14913
14974
  }
14914
14975
  }
14915
- async function readSnapshot(client2, agentId, timeoutMs) {
14916
- const response = await client2.getAgentAutomations(agentId, timeoutMs);
14976
+ async function resolveRoutineAuthority(client2, agent, timeoutMs) {
14977
+ if (agent.harness !== "temporal") {
14978
+ return { authority: "box-local", discovery: agent.discovery };
14979
+ }
14980
+ let response;
14981
+ try {
14982
+ response = await client2.getGrokboxRoutineAuthority(agent.id, timeoutMs);
14983
+ } catch (error) {
14984
+ if (error instanceof CliError && ["gateway_not_found", "gateway_bad_request", "capability_unavailable"].includes(error.code)) {
14985
+ throw new CliError(
14986
+ "capability_unavailable",
14987
+ "This Temporal Bot requires the Grokbox Temporal Routine bridge before Routine state can be read safely."
14988
+ );
14989
+ }
14990
+ throw error;
14991
+ }
14992
+ const discovery = gatewayMeta(response.discovery);
14993
+ if (!sameGeneration(agent.discovery, discovery)) {
14994
+ throw new CliError("gateway_conflict", "Gateway generation changed while resolving Routine authority.");
14995
+ }
14996
+ if (!isRecord(response.result) || JSON.stringify(Object.keys(response.result).sort()) !== JSON.stringify(["source"]) || response.result.source !== "server-temporal") {
14997
+ throw new CliError(
14998
+ "capability_unavailable",
14999
+ "Temporal Routine authority is not Server-backed on the selected Host."
15000
+ );
15001
+ }
15002
+ return { authority: "server-temporal", discovery };
15003
+ }
15004
+ async function readSnapshot(client2, agent, timeoutMs) {
15005
+ const authority = await resolveRoutineAuthority(client2, agent, timeoutMs);
15006
+ const response = await client2.getAgentAutomations(agent.id, timeoutMs);
15007
+ const discovery = gatewayMeta(response.discovery);
15008
+ if (!sameGeneration(authority.discovery, discovery)) {
15009
+ throw new CliError("gateway_conflict", "Gateway generation changed while reading Routines.");
15010
+ }
14917
15011
  try {
14918
15012
  return {
14919
- ...projectNativeRoutines(agentId, response.result),
14920
- discovery: gatewayMeta(response.discovery)
15013
+ ...projectNativeRoutines(agent.id, response.result),
15014
+ discovery,
15015
+ authority: authority.authority
14921
15016
  };
14922
15017
  } catch (error) {
14923
15018
  throw routineCliError(error);
@@ -14984,19 +15079,19 @@ function listTable(catalog) {
14984
15079
  async function listOrShow(deps, client2, action, agentTarget, routineTarget, raw) {
14985
15080
  const io = ioFromOpts(raw);
14986
15081
  const agent = await resolveAgent(client2, agentTarget, io.timeoutMs);
14987
- const snapshot = await readSnapshot(client2, agent.id, io.timeoutMs);
15082
+ const snapshot = await readSnapshot(client2, agent, io.timeoutMs);
14988
15083
  if (action === "list") {
14989
15084
  if (io.table) {
14990
15085
  deps.stdout.write(listTable(snapshot.catalog));
14991
15086
  return;
14992
15087
  }
14993
- writeSuccess(deps.stdout, snapshot.catalog, snapshot.discovery);
15088
+ writeSuccess(deps.stdout, { ...snapshot.catalog, authority: snapshot.authority }, snapshot.discovery);
14994
15089
  return;
14995
15090
  }
14996
15091
  const routine = findRoutine(snapshot, routineTarget ?? "");
14997
15092
  writeSuccess(
14998
15093
  deps.stdout,
14999
- { schemaVersion: 1, agentId: agent.id, routine, coverage: snapshot.catalog.coverage },
15094
+ { schemaVersion: 1, agentId: agent.id, authority: snapshot.authority, routine, coverage: snapshot.catalog.coverage },
15000
15095
  snapshot.discovery
15001
15096
  );
15002
15097
  }
@@ -15004,9 +15099,15 @@ async function createRoutine(deps, client2, agentTarget, raw) {
15004
15099
  requireConfirmed(raw);
15005
15100
  const io = ioFromOpts(raw);
15006
15101
  const op = operationId(raw, deps);
15007
- const desired = await definition(raw, deps);
15008
15102
  const agent = await resolveAgent(client2, agentTarget, io.timeoutMs);
15009
- const before = await readSnapshot(client2, agent.id, io.timeoutMs);
15103
+ if (agent.harness === "temporal") {
15104
+ throw new CliError(
15105
+ "capability_unavailable",
15106
+ "The current official Temporal Routine contract does not expose create through the Box management surface."
15107
+ );
15108
+ }
15109
+ const desired = await definition(raw, deps);
15110
+ const before = await readSnapshot(client2, agent, io.timeoutMs);
15010
15111
  if (before.catalog.coverage.atLimit) {
15011
15112
  throw new CliError(
15012
15113
  "capability_unavailable",
@@ -15029,7 +15130,7 @@ async function createRoutine(deps, client2, agentTarget, raw) {
15029
15130
  if (!sameGeneration(before.discovery, gatewayMeta(write.discovery))) {
15030
15131
  return unknown(op, "Gateway generation changed during Routine create; inspect the Routine list before any retry.");
15031
15132
  }
15032
- const after = await readSnapshot(client2, agent.id, io.timeoutMs);
15133
+ const after = await readSnapshot(client2, agent, io.timeoutMs);
15033
15134
  if (!sameGeneration(before.discovery, after.discovery)) {
15034
15135
  return unknown(op, "Gateway generation changed after Routine create; inspect the Routine list before any retry.");
15035
15136
  }
@@ -15056,9 +15157,15 @@ async function updateRoutine(deps, client2, agentTarget, routineTarget, raw) {
15056
15157
  const io = ioFromOpts(raw);
15057
15158
  const op = operationId(raw, deps);
15058
15159
  const expected = expectedRevision(raw);
15059
- const desired = await definition(raw, deps);
15060
15160
  const agent = await resolveAgent(client2, agentTarget, io.timeoutMs);
15061
- const before = await readSnapshot(client2, agent.id, io.timeoutMs);
15161
+ if (agent.harness === "temporal") {
15162
+ throw new CliError(
15163
+ "capability_unavailable",
15164
+ "The current official Temporal Routine contract does not expose definition update through the Box management surface."
15165
+ );
15166
+ }
15167
+ const desired = await definition(raw, deps);
15168
+ const before = await readSnapshot(client2, agent, io.timeoutMs);
15062
15169
  const prior = mutableRoutine(before, routineTarget);
15063
15170
  if (prior.revision !== expected) throw routineCliError(new RoutineError("revision_conflict"));
15064
15171
  const desiredDigest = routineDefinitionDigest(desired, prior.enabled);
@@ -15091,7 +15198,7 @@ async function updateRoutine(deps, client2, agentTarget, routineTarget, raw) {
15091
15198
  if (!sameGeneration(before.discovery, gatewayMeta(write.discovery))) {
15092
15199
  return unknown(op, "Gateway generation changed during Routine update; inspect the Routine before any retry.");
15093
15200
  }
15094
- const after = await readSnapshot(client2, agent.id, io.timeoutMs);
15201
+ const after = await readSnapshot(client2, agent, io.timeoutMs);
15095
15202
  if (!sameGeneration(before.discovery, after.discovery)) {
15096
15203
  return unknown(op, "Gateway generation changed after Routine update; inspect the Routine before any retry.");
15097
15204
  }
@@ -15118,7 +15225,7 @@ async function setRoutineEnabled(deps, client2, agentTarget, routineTarget, acti
15118
15225
  const op = operationId(raw, deps);
15119
15226
  const expected = expectedRevision(raw);
15120
15227
  const agent = await resolveAgent(client2, agentTarget, io.timeoutMs);
15121
- const before = await readSnapshot(client2, agent.id, io.timeoutMs);
15228
+ const before = await readSnapshot(client2, agent, io.timeoutMs);
15122
15229
  const prior = mutableRoutine(before, routineTarget);
15123
15230
  if (prior.revision !== expected) throw routineCliError(new RoutineError("revision_conflict"));
15124
15231
  const enabled = action === "enable";
@@ -15151,7 +15258,7 @@ async function setRoutineEnabled(deps, client2, agentTarget, routineTarget, acti
15151
15258
  if (!sameGeneration(before.discovery, gatewayMeta(write.discovery))) {
15152
15259
  return unknown(op, "Gateway generation changed during Routine state change; inspect the Routine before any retry.");
15153
15260
  }
15154
- const after = await readSnapshot(client2, agent.id, io.timeoutMs);
15261
+ const after = await readSnapshot(client2, agent, io.timeoutMs);
15155
15262
  if (!sameGeneration(before.discovery, after.discovery)) {
15156
15263
  return unknown(op, "Gateway generation changed after Routine state change; inspect the Routine before any retry.");
15157
15264
  }
@@ -15172,13 +15279,51 @@ async function setRoutineEnabled(deps, client2, agentTarget, routineTarget, acti
15172
15279
  routine: current
15173
15280
  }, after.discovery);
15174
15281
  }
15282
+ async function showWebhookCredential(deps, client2, agentTarget, routineTarget, raw) {
15283
+ requireConfirmed(raw);
15284
+ const io = ioFromOpts(raw);
15285
+ const agent = await resolveAgent(client2, agentTarget, io.timeoutMs);
15286
+ const snapshot = await readSnapshot(client2, agent, io.timeoutMs);
15287
+ const routine = findRoutine(snapshot, routineTarget);
15288
+ if (routine.trigger.type !== "webhook") {
15289
+ throw new CliError("capability_unavailable", "Routine is not webhook-triggered.");
15290
+ }
15291
+ const response = await client2.getAutomationWebhookCredential(agent.id, routine.id, io.timeoutMs);
15292
+ const discovery = gatewayMeta(response.discovery);
15293
+ if (!sameGeneration(snapshot.discovery, discovery)) {
15294
+ throw new CliError("gateway_conflict", "Gateway generation changed while reading webhook credentials.");
15295
+ }
15296
+ if (!isRecord(response.result) || JSON.stringify(Object.keys(response.result).sort()) !== JSON.stringify(["key", "url"]) || typeof response.result.url !== "string" || typeof response.result.key !== "string" || response.result.key.length < 1 || response.result.key.length > 4096 || response.result.key.includes("\0")) {
15297
+ throw new CliError("gateway_internal", "Gateway returned an invalid webhook credential.");
15298
+ }
15299
+ let url;
15300
+ try {
15301
+ url = new URL(response.result.url);
15302
+ } catch {
15303
+ throw new CliError("gateway_internal", "Gateway returned an invalid webhook URL.");
15304
+ }
15305
+ if (url.protocol !== "https:" || url.username || url.password || url.hash) {
15306
+ throw new CliError("gateway_internal", "Gateway returned an unsafe webhook URL.");
15307
+ }
15308
+ const revealKey = raw.revealKey === true;
15309
+ writeSuccess(deps.stdout, {
15310
+ schemaVersion: 1,
15311
+ agentId: agent.id,
15312
+ routineId: routine.id,
15313
+ authority: snapshot.authority,
15314
+ url: url.toString(),
15315
+ keyPresent: true,
15316
+ keyIncluded: revealKey,
15317
+ ...revealKey ? { key: response.result.key } : {}
15318
+ }, discovery);
15319
+ }
15175
15320
  async function deleteRoutine(deps, client2, agentTarget, routineTarget, raw) {
15176
15321
  requireConfirmed(raw);
15177
15322
  const io = ioFromOpts(raw);
15178
15323
  const op = operationId(raw, deps);
15179
15324
  const expected = expectedRevision(raw);
15180
15325
  const agent = await resolveAgent(client2, agentTarget, io.timeoutMs);
15181
- const before = await readSnapshot(client2, agent.id, io.timeoutMs);
15326
+ const before = await readSnapshot(client2, agent, io.timeoutMs);
15182
15327
  const prior = mutableRoutine(before, routineTarget);
15183
15328
  if (prior.revision !== expected) throw routineCliError(new RoutineError("revision_conflict"));
15184
15329
  let write;
@@ -15195,7 +15340,7 @@ async function deleteRoutine(deps, client2, agentTarget, routineTarget, raw) {
15195
15340
  if (!sameGeneration(before.discovery, gatewayMeta(write.discovery))) {
15196
15341
  return unknown(op, "Gateway generation changed during Routine delete; inspect the Routine list before any retry.");
15197
15342
  }
15198
- const after = await readSnapshot(client2, agent.id, io.timeoutMs);
15343
+ const after = await readSnapshot(client2, agent, io.timeoutMs);
15199
15344
  if (!sameGeneration(before.discovery, after.discovery)) {
15200
15345
  return unknown(op, "Gateway generation changed after Routine delete; inspect the Routine list before any retry.");
15201
15346
  }
@@ -15225,6 +15370,10 @@ async function runRoutines(deps, action, agentTarget, routineTarget, raw) {
15225
15370
  return;
15226
15371
  }
15227
15372
  if (!routineTarget) throw usage("Routine ID is required.");
15373
+ if (action === "webhook-credential") {
15374
+ await showWebhookCredential(deps, client2, agentTarget, routineTarget, raw);
15375
+ return;
15376
+ }
15228
15377
  if (action === "update") {
15229
15378
  await updateRoutine(deps, client2, agentTarget, routineTarget, raw);
15230
15379
  return;
@@ -15330,6 +15479,7 @@ var FAMILY_DESCRIPTIONS = {
15330
15479
  daemon: "Local daemon lifecycle",
15331
15480
  agents: "Non-group Grok Bot agents",
15332
15481
  "agents routines": "Native Grok Bot Routines",
15482
+ "agents routines webhook": "Webhook Routine credentials",
15333
15483
  groups: "Product groups",
15334
15484
  "groups members": "Product group membership",
15335
15485
  history: "Search and read display transcript",
@@ -15397,6 +15547,7 @@ function actionBindings() {
15397
15547
  "agents routines enable": async (deps, args, options2) => await runRoutines(deps, "enable", args[0] ?? "", args[1], options2),
15398
15548
  "agents routines disable": async (deps, args, options2) => await runRoutines(deps, "disable", args[0] ?? "", args[1], options2),
15399
15549
  "agents routines delete": async (deps, args, options2) => await runRoutines(deps, "delete", args[0] ?? "", args[1], options2),
15550
+ "agents routines webhook credential": async (deps, args, options2) => await runRoutines(deps, "webhook-credential", args[0] ?? "", args[1], options2),
15400
15551
  "groups list": async (deps, _args, options2) => await runGroupsList(deps, options2),
15401
15552
  "groups show": async (deps, args, options2) => await runGroupsShow(deps, args[0] ?? "", options2),
15402
15553
  "groups create": async (deps, _args, options2) => await runGroupsCreate(deps, options2),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "grokbox",
3
- "version": "0.1.0-alpha.7",
3
+ "version": "0.1.0-alpha.8",
4
4
  "packageManager": "bun@1.3.14",
5
5
  "description": "Unofficial CLI and control plane for Grok Bot cloud computers",
6
6
  "license": "MIT",
package/skills/core.md CHANGED
@@ -72,7 +72,7 @@ Targets accept an exact ID first, then an unambiguous case-insensitive name/titl
72
72
  `groups list/show/create/update/delete` only own product groups. Membership is only
73
73
  `groups members list/add/remove/set`; every member must resolve to a non-group agent and a group
74
74
  must retain 1-6 unique members.
75
- 3. **Manage native Routines**: `agents routines list/show` returns bounded metadata only and never emits prompt bodies, credentials, or native paths. `create` writes a disabled definition; `update/enable/disable/delete` require `--expect-revision` from a fresh read and `--confirm`. `update` is a complete name/prompt/trigger replacement and preserves enabled state. Native writes have no upstream CAS or idempotency guarantee; uncertain writes return `operation_outcome_unknown` and must be reconciled by another read, never automatic replay. Credential minting, webhook invocation, and run-now are intentionally absent.
75
+ 3. **Manage native Routines**: `agents routines list/show` returns bounded metadata only and never emits prompt bodies, credentials, or native paths. Box-local Bots support create/update/enable/disable/delete; create writes a disabled definition and later mutations require `--expect-revision` from a fresh read plus `--confirm`. Temporal Bots are Server-authoritative: list/show, webhook credential, enable/disable, and delete require the bounded Temporal Routine Host bridge; create/update refuse because the current official Temporal contract exposes neither mutation. `agents routines webhook credential <agent> <routine-id> --confirm` hides the key by default; `--reveal-key` is the explicit secret-output boundary. Without the bridge, Temporal reads fail closed instead of reporting the legacy local store. Native writes have no upstream CAS or idempotency guarantee; uncertain writes return `operation_outcome_unknown` and must be reconciled by another read, never automatic replay.
76
76
  4. **Search/read transcript**: `history search <query>`, `history tail <target>`, and
77
77
  `history thread <target> --root <entry-id>` own transcript access. Object `show` commands do
78
78
  not add transcript side projections.