grokbox 0.1.0-alpha.7 → 0.1.0-alpha.9
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 +3 -4
- package/README.zh-CN.md +2 -2
- package/dist/index.js +191 -19
- package/package.json +1 -1
- package/skills/core.md +1 -1
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.
|
|
14
|
-
> `0.1.0-alpha.
|
|
15
|
-
> `v0.1.0-alpha.6` exist as Git tags only. Prereleases publish only after
|
|
13
|
+
> **Alpha:** current source is `0.1.0-alpha.9`. npm `next` currently points to
|
|
14
|
+
> `0.1.0-alpha.8`; `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.
|
|
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.
|
|
9
|
+
> **Alpha:** 当前源码版本是 `0.1.0-alpha.9`。npm 的 `next` dist-tag 目前指向 `0.1.0-alpha.8`;`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 字段。
|
|
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.
|
|
3477
|
+
version: "0.1.0-alpha.9",
|
|
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 webhook key and routine prompt 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 {
|
|
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,17 +14973,67 @@ async function resolveAgent(client2, target, timeoutMs) {
|
|
|
14912
14973
|
);
|
|
14913
14974
|
}
|
|
14914
14975
|
}
|
|
14915
|
-
async function
|
|
14916
|
-
|
|
14976
|
+
async function resolveRoutineAuthority(client2, agent, timeoutMs) {
|
|
14977
|
+
if (agent.harness !== "temporal") {
|
|
14978
|
+
return { authority: "box-local", discovery: agent.discovery };
|
|
14979
|
+
}
|
|
14980
|
+
let response;
|
|
14917
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
|
+
}
|
|
15011
|
+
try {
|
|
15012
|
+
const projected = projectNativeRoutines(agent.id, response.result);
|
|
14918
15013
|
return {
|
|
14919
|
-
...
|
|
14920
|
-
discovery
|
|
15014
|
+
...projected,
|
|
15015
|
+
discovery,
|
|
15016
|
+
authority: authority.authority,
|
|
15017
|
+
prompts: nativePrompts(response.result, projected.catalog)
|
|
14921
15018
|
};
|
|
14922
15019
|
} catch (error) {
|
|
14923
15020
|
throw routineCliError(error);
|
|
14924
15021
|
}
|
|
14925
15022
|
}
|
|
15023
|
+
function nativePrompts(value, catalog) {
|
|
15024
|
+
if (!Array.isArray(value)) throw new RoutineError("unsupported_shape");
|
|
15025
|
+
const prompts = /* @__PURE__ */ new Map();
|
|
15026
|
+
for (const raw of value) {
|
|
15027
|
+
if (!isRecord(raw) || typeof raw.id !== "string" || typeof raw.prompt !== "string" || raw.prompt.length < 1 || raw.prompt.includes("\0") || Buffer.byteLength(raw.prompt) > 128 * 1024) {
|
|
15028
|
+
throw new RoutineError("unsupported_shape");
|
|
15029
|
+
}
|
|
15030
|
+
prompts.set(raw.id, raw.prompt);
|
|
15031
|
+
}
|
|
15032
|
+
for (const routine of catalog.routines) {
|
|
15033
|
+
if (!prompts.has(routine.id)) throw new RoutineError("unsupported_shape");
|
|
15034
|
+
}
|
|
15035
|
+
return prompts;
|
|
15036
|
+
}
|
|
14926
15037
|
function findRoutine(snapshot, id) {
|
|
14927
15038
|
let rid;
|
|
14928
15039
|
try {
|
|
@@ -14984,19 +15095,19 @@ function listTable(catalog) {
|
|
|
14984
15095
|
async function listOrShow(deps, client2, action, agentTarget, routineTarget, raw) {
|
|
14985
15096
|
const io = ioFromOpts(raw);
|
|
14986
15097
|
const agent = await resolveAgent(client2, agentTarget, io.timeoutMs);
|
|
14987
|
-
const snapshot = await readSnapshot(client2, agent
|
|
15098
|
+
const snapshot = await readSnapshot(client2, agent, io.timeoutMs);
|
|
14988
15099
|
if (action === "list") {
|
|
14989
15100
|
if (io.table) {
|
|
14990
15101
|
deps.stdout.write(listTable(snapshot.catalog));
|
|
14991
15102
|
return;
|
|
14992
15103
|
}
|
|
14993
|
-
writeSuccess(deps.stdout, snapshot.catalog, snapshot.discovery);
|
|
15104
|
+
writeSuccess(deps.stdout, { ...snapshot.catalog, authority: snapshot.authority }, snapshot.discovery);
|
|
14994
15105
|
return;
|
|
14995
15106
|
}
|
|
14996
15107
|
const routine = findRoutine(snapshot, routineTarget ?? "");
|
|
14997
15108
|
writeSuccess(
|
|
14998
15109
|
deps.stdout,
|
|
14999
|
-
{ schemaVersion: 1, agentId: agent.id, routine, coverage: snapshot.catalog.coverage },
|
|
15110
|
+
{ schemaVersion: 1, agentId: agent.id, authority: snapshot.authority, routine, coverage: snapshot.catalog.coverage },
|
|
15000
15111
|
snapshot.discovery
|
|
15001
15112
|
);
|
|
15002
15113
|
}
|
|
@@ -15004,9 +15115,15 @@ async function createRoutine(deps, client2, agentTarget, raw) {
|
|
|
15004
15115
|
requireConfirmed(raw);
|
|
15005
15116
|
const io = ioFromOpts(raw);
|
|
15006
15117
|
const op = operationId(raw, deps);
|
|
15007
|
-
const desired = await definition(raw, deps);
|
|
15008
15118
|
const agent = await resolveAgent(client2, agentTarget, io.timeoutMs);
|
|
15009
|
-
|
|
15119
|
+
if (agent.harness === "temporal") {
|
|
15120
|
+
throw new CliError(
|
|
15121
|
+
"capability_unavailable",
|
|
15122
|
+
"The current official Temporal Routine contract does not expose create through the Box management surface."
|
|
15123
|
+
);
|
|
15124
|
+
}
|
|
15125
|
+
const desired = await definition(raw, deps);
|
|
15126
|
+
const before = await readSnapshot(client2, agent, io.timeoutMs);
|
|
15010
15127
|
if (before.catalog.coverage.atLimit) {
|
|
15011
15128
|
throw new CliError(
|
|
15012
15129
|
"capability_unavailable",
|
|
@@ -15029,7 +15146,7 @@ async function createRoutine(deps, client2, agentTarget, raw) {
|
|
|
15029
15146
|
if (!sameGeneration(before.discovery, gatewayMeta(write.discovery))) {
|
|
15030
15147
|
return unknown(op, "Gateway generation changed during Routine create; inspect the Routine list before any retry.");
|
|
15031
15148
|
}
|
|
15032
|
-
const after = await readSnapshot(client2, agent
|
|
15149
|
+
const after = await readSnapshot(client2, agent, io.timeoutMs);
|
|
15033
15150
|
if (!sameGeneration(before.discovery, after.discovery)) {
|
|
15034
15151
|
return unknown(op, "Gateway generation changed after Routine create; inspect the Routine list before any retry.");
|
|
15035
15152
|
}
|
|
@@ -15056,9 +15173,15 @@ async function updateRoutine(deps, client2, agentTarget, routineTarget, raw) {
|
|
|
15056
15173
|
const io = ioFromOpts(raw);
|
|
15057
15174
|
const op = operationId(raw, deps);
|
|
15058
15175
|
const expected = expectedRevision(raw);
|
|
15059
|
-
const desired = await definition(raw, deps);
|
|
15060
15176
|
const agent = await resolveAgent(client2, agentTarget, io.timeoutMs);
|
|
15061
|
-
|
|
15177
|
+
if (agent.harness === "temporal") {
|
|
15178
|
+
throw new CliError(
|
|
15179
|
+
"capability_unavailable",
|
|
15180
|
+
"The current official Temporal Routine contract does not expose definition update through the Box management surface."
|
|
15181
|
+
);
|
|
15182
|
+
}
|
|
15183
|
+
const desired = await definition(raw, deps);
|
|
15184
|
+
const before = await readSnapshot(client2, agent, io.timeoutMs);
|
|
15062
15185
|
const prior = mutableRoutine(before, routineTarget);
|
|
15063
15186
|
if (prior.revision !== expected) throw routineCliError(new RoutineError("revision_conflict"));
|
|
15064
15187
|
const desiredDigest = routineDefinitionDigest(desired, prior.enabled);
|
|
@@ -15091,7 +15214,7 @@ async function updateRoutine(deps, client2, agentTarget, routineTarget, raw) {
|
|
|
15091
15214
|
if (!sameGeneration(before.discovery, gatewayMeta(write.discovery))) {
|
|
15092
15215
|
return unknown(op, "Gateway generation changed during Routine update; inspect the Routine before any retry.");
|
|
15093
15216
|
}
|
|
15094
|
-
const after = await readSnapshot(client2, agent
|
|
15217
|
+
const after = await readSnapshot(client2, agent, io.timeoutMs);
|
|
15095
15218
|
if (!sameGeneration(before.discovery, after.discovery)) {
|
|
15096
15219
|
return unknown(op, "Gateway generation changed after Routine update; inspect the Routine before any retry.");
|
|
15097
15220
|
}
|
|
@@ -15118,7 +15241,7 @@ async function setRoutineEnabled(deps, client2, agentTarget, routineTarget, acti
|
|
|
15118
15241
|
const op = operationId(raw, deps);
|
|
15119
15242
|
const expected = expectedRevision(raw);
|
|
15120
15243
|
const agent = await resolveAgent(client2, agentTarget, io.timeoutMs);
|
|
15121
|
-
const before = await readSnapshot(client2, agent
|
|
15244
|
+
const before = await readSnapshot(client2, agent, io.timeoutMs);
|
|
15122
15245
|
const prior = mutableRoutine(before, routineTarget);
|
|
15123
15246
|
if (prior.revision !== expected) throw routineCliError(new RoutineError("revision_conflict"));
|
|
15124
15247
|
const enabled = action === "enable";
|
|
@@ -15151,7 +15274,7 @@ async function setRoutineEnabled(deps, client2, agentTarget, routineTarget, acti
|
|
|
15151
15274
|
if (!sameGeneration(before.discovery, gatewayMeta(write.discovery))) {
|
|
15152
15275
|
return unknown(op, "Gateway generation changed during Routine state change; inspect the Routine before any retry.");
|
|
15153
15276
|
}
|
|
15154
|
-
const after = await readSnapshot(client2, agent
|
|
15277
|
+
const after = await readSnapshot(client2, agent, io.timeoutMs);
|
|
15155
15278
|
if (!sameGeneration(before.discovery, after.discovery)) {
|
|
15156
15279
|
return unknown(op, "Gateway generation changed after Routine state change; inspect the Routine before any retry.");
|
|
15157
15280
|
}
|
|
@@ -15172,13 +15295,56 @@ async function setRoutineEnabled(deps, client2, agentTarget, routineTarget, acti
|
|
|
15172
15295
|
routine: current
|
|
15173
15296
|
}, after.discovery);
|
|
15174
15297
|
}
|
|
15298
|
+
async function showWebhookCredential(deps, client2, agentTarget, routineTarget, raw) {
|
|
15299
|
+
requireConfirmed(raw);
|
|
15300
|
+
const io = ioFromOpts(raw);
|
|
15301
|
+
const agent = await resolveAgent(client2, agentTarget, io.timeoutMs);
|
|
15302
|
+
const snapshot = await readSnapshot(client2, agent, io.timeoutMs);
|
|
15303
|
+
const routine = findRoutine(snapshot, routineTarget);
|
|
15304
|
+
if (routine.trigger.type !== "webhook") {
|
|
15305
|
+
throw new CliError("capability_unavailable", "Routine is not webhook-triggered.");
|
|
15306
|
+
}
|
|
15307
|
+
const response = await client2.getAutomationWebhookCredential(agent.id, routine.id, io.timeoutMs);
|
|
15308
|
+
const discovery = gatewayMeta(response.discovery);
|
|
15309
|
+
if (!sameGeneration(snapshot.discovery, discovery)) {
|
|
15310
|
+
throw new CliError("gateway_conflict", "Gateway generation changed while reading webhook credentials.");
|
|
15311
|
+
}
|
|
15312
|
+
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")) {
|
|
15313
|
+
throw new CliError("gateway_internal", "Gateway returned an invalid webhook credential.");
|
|
15314
|
+
}
|
|
15315
|
+
let url;
|
|
15316
|
+
try {
|
|
15317
|
+
url = new URL(response.result.url);
|
|
15318
|
+
} catch {
|
|
15319
|
+
throw new CliError("gateway_internal", "Gateway returned an invalid webhook URL.");
|
|
15320
|
+
}
|
|
15321
|
+
if (url.protocol !== "https:" || url.username || url.password || url.hash) {
|
|
15322
|
+
throw new CliError("gateway_internal", "Gateway returned an unsafe webhook URL.");
|
|
15323
|
+
}
|
|
15324
|
+
const prompt = snapshot.prompts.get(routine.id);
|
|
15325
|
+
if (prompt === void 0) {
|
|
15326
|
+
throw new CliError("gateway_internal", "Gateway returned a Routine without a prompt.");
|
|
15327
|
+
}
|
|
15328
|
+
const revealKey = raw.revealKey === true;
|
|
15329
|
+
writeSuccess(deps.stdout, {
|
|
15330
|
+
schemaVersion: 1,
|
|
15331
|
+
agentId: agent.id,
|
|
15332
|
+
routineId: routine.id,
|
|
15333
|
+
authority: snapshot.authority,
|
|
15334
|
+
url: url.toString(),
|
|
15335
|
+
keyPresent: true,
|
|
15336
|
+
keyIncluded: revealKey,
|
|
15337
|
+
promptIncluded: revealKey,
|
|
15338
|
+
...revealKey ? { key: response.result.key, prompt } : {}
|
|
15339
|
+
}, discovery);
|
|
15340
|
+
}
|
|
15175
15341
|
async function deleteRoutine(deps, client2, agentTarget, routineTarget, raw) {
|
|
15176
15342
|
requireConfirmed(raw);
|
|
15177
15343
|
const io = ioFromOpts(raw);
|
|
15178
15344
|
const op = operationId(raw, deps);
|
|
15179
15345
|
const expected = expectedRevision(raw);
|
|
15180
15346
|
const agent = await resolveAgent(client2, agentTarget, io.timeoutMs);
|
|
15181
|
-
const before = await readSnapshot(client2, agent
|
|
15347
|
+
const before = await readSnapshot(client2, agent, io.timeoutMs);
|
|
15182
15348
|
const prior = mutableRoutine(before, routineTarget);
|
|
15183
15349
|
if (prior.revision !== expected) throw routineCliError(new RoutineError("revision_conflict"));
|
|
15184
15350
|
let write;
|
|
@@ -15195,7 +15361,7 @@ async function deleteRoutine(deps, client2, agentTarget, routineTarget, raw) {
|
|
|
15195
15361
|
if (!sameGeneration(before.discovery, gatewayMeta(write.discovery))) {
|
|
15196
15362
|
return unknown(op, "Gateway generation changed during Routine delete; inspect the Routine list before any retry.");
|
|
15197
15363
|
}
|
|
15198
|
-
const after = await readSnapshot(client2, agent
|
|
15364
|
+
const after = await readSnapshot(client2, agent, io.timeoutMs);
|
|
15199
15365
|
if (!sameGeneration(before.discovery, after.discovery)) {
|
|
15200
15366
|
return unknown(op, "Gateway generation changed after Routine delete; inspect the Routine list before any retry.");
|
|
15201
15367
|
}
|
|
@@ -15225,6 +15391,10 @@ async function runRoutines(deps, action, agentTarget, routineTarget, raw) {
|
|
|
15225
15391
|
return;
|
|
15226
15392
|
}
|
|
15227
15393
|
if (!routineTarget) throw usage("Routine ID is required.");
|
|
15394
|
+
if (action === "webhook-credential") {
|
|
15395
|
+
await showWebhookCredential(deps, client2, agentTarget, routineTarget, raw);
|
|
15396
|
+
return;
|
|
15397
|
+
}
|
|
15228
15398
|
if (action === "update") {
|
|
15229
15399
|
await updateRoutine(deps, client2, agentTarget, routineTarget, raw);
|
|
15230
15400
|
return;
|
|
@@ -15330,6 +15500,7 @@ var FAMILY_DESCRIPTIONS = {
|
|
|
15330
15500
|
daemon: "Local daemon lifecycle",
|
|
15331
15501
|
agents: "Non-group Grok Bot agents",
|
|
15332
15502
|
"agents routines": "Native Grok Bot Routines",
|
|
15503
|
+
"agents routines webhook": "Webhook Routine credentials",
|
|
15333
15504
|
groups: "Product groups",
|
|
15334
15505
|
"groups members": "Product group membership",
|
|
15335
15506
|
history: "Search and read display transcript",
|
|
@@ -15397,6 +15568,7 @@ function actionBindings() {
|
|
|
15397
15568
|
"agents routines enable": async (deps, args, options2) => await runRoutines(deps, "enable", args[0] ?? "", args[1], options2),
|
|
15398
15569
|
"agents routines disable": async (deps, args, options2) => await runRoutines(deps, "disable", args[0] ?? "", args[1], options2),
|
|
15399
15570
|
"agents routines delete": async (deps, args, options2) => await runRoutines(deps, "delete", args[0] ?? "", args[1], options2),
|
|
15571
|
+
"agents routines webhook credential": async (deps, args, options2) => await runRoutines(deps, "webhook-credential", args[0] ?? "", args[1], options2),
|
|
15400
15572
|
"groups list": async (deps, _args, options2) => await runGroupsList(deps, options2),
|
|
15401
15573
|
"groups show": async (deps, args, options2) => await runGroupsShow(deps, args[0] ?? "", options2),
|
|
15402
15574
|
"groups create": async (deps, _args, options2) => await runGroupsCreate(deps, options2),
|
package/package.json
CHANGED
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.
|
|
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` returns the webhook URL and hides the key and prompt by default; `--reveal-key` is the explicit boundary that also emits both. `list` and `show` still never emit them. 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.
|