clawborrator-cli 0.0.9 → 0.0.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.
- package/dist-bundled/claw.cjs +164 -27
- package/package.json +1 -1
package/dist-bundled/claw.cjs
CHANGED
|
@@ -6,9 +6,16 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
6
6
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
7
|
var __getProtoOf = Object.getPrototypeOf;
|
|
8
8
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __esm = (fn, res) => function __init() {
|
|
10
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
11
|
+
};
|
|
9
12
|
var __commonJS = (cb, mod) => function __require() {
|
|
10
13
|
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
11
14
|
};
|
|
15
|
+
var __export = (target, all) => {
|
|
16
|
+
for (var name in all)
|
|
17
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
18
|
+
};
|
|
12
19
|
var __copyProps = (to, from, except, desc) => {
|
|
13
20
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
21
|
for (let key of __getOwnPropNames(from))
|
|
@@ -6635,6 +6642,34 @@ var require_websocket_server = __commonJS({
|
|
|
6635
6642
|
}
|
|
6636
6643
|
});
|
|
6637
6644
|
|
|
6645
|
+
// ../node_modules/ws/wrapper.mjs
|
|
6646
|
+
var wrapper_exports = {};
|
|
6647
|
+
__export(wrapper_exports, {
|
|
6648
|
+
PerMessageDeflate: () => import_permessage_deflate.default,
|
|
6649
|
+
Receiver: () => import_receiver.default,
|
|
6650
|
+
Sender: () => import_sender.default,
|
|
6651
|
+
WebSocket: () => import_websocket.default,
|
|
6652
|
+
WebSocketServer: () => import_websocket_server.default,
|
|
6653
|
+
createWebSocketStream: () => import_stream.default,
|
|
6654
|
+
default: () => wrapper_default,
|
|
6655
|
+
extension: () => import_extension.default,
|
|
6656
|
+
subprotocol: () => import_subprotocol.default
|
|
6657
|
+
});
|
|
6658
|
+
var import_stream, import_extension, import_permessage_deflate, import_receiver, import_sender, import_subprotocol, import_websocket, import_websocket_server, wrapper_default;
|
|
6659
|
+
var init_wrapper = __esm({
|
|
6660
|
+
"../node_modules/ws/wrapper.mjs"() {
|
|
6661
|
+
import_stream = __toESM(require_stream(), 1);
|
|
6662
|
+
import_extension = __toESM(require_extension(), 1);
|
|
6663
|
+
import_permessage_deflate = __toESM(require_permessage_deflate(), 1);
|
|
6664
|
+
import_receiver = __toESM(require_receiver(), 1);
|
|
6665
|
+
import_sender = __toESM(require_sender(), 1);
|
|
6666
|
+
import_subprotocol = __toESM(require_subprotocol(), 1);
|
|
6667
|
+
import_websocket = __toESM(require_websocket(), 1);
|
|
6668
|
+
import_websocket_server = __toESM(require_websocket_server(), 1);
|
|
6669
|
+
wrapper_default = import_websocket.default;
|
|
6670
|
+
}
|
|
6671
|
+
});
|
|
6672
|
+
|
|
6638
6673
|
// ../node_modules/commander/esm.mjs
|
|
6639
6674
|
var import_index = __toESM(require_commander(), 1);
|
|
6640
6675
|
var {
|
|
@@ -6845,19 +6880,7 @@ var whoamiCmd = new Command("whoami").description("show the currently authentica
|
|
|
6845
6880
|
|
|
6846
6881
|
// src/commands/session-attach.ts
|
|
6847
6882
|
var import_node_readline = require("node:readline");
|
|
6848
|
-
|
|
6849
|
-
// ../node_modules/ws/wrapper.mjs
|
|
6850
|
-
var import_stream = __toESM(require_stream(), 1);
|
|
6851
|
-
var import_extension = __toESM(require_extension(), 1);
|
|
6852
|
-
var import_permessage_deflate = __toESM(require_permessage_deflate(), 1);
|
|
6853
|
-
var import_receiver = __toESM(require_receiver(), 1);
|
|
6854
|
-
var import_sender = __toESM(require_sender(), 1);
|
|
6855
|
-
var import_subprotocol = __toESM(require_subprotocol(), 1);
|
|
6856
|
-
var import_websocket = __toESM(require_websocket(), 1);
|
|
6857
|
-
var import_websocket_server = __toESM(require_websocket_server(), 1);
|
|
6858
|
-
var wrapper_default = import_websocket.default;
|
|
6859
|
-
|
|
6860
|
-
// src/commands/session-attach.ts
|
|
6883
|
+
init_wrapper();
|
|
6861
6884
|
var RESET = "\x1B[0m";
|
|
6862
6885
|
var DIM = "\x1B[2m";
|
|
6863
6886
|
var AMBER = "\x1B[33m";
|
|
@@ -6874,12 +6897,26 @@ var sessionAttach = new Command("attach").description("open a TUI on a session \
|
|
|
6874
6897
|
console.error("error: not logged in. run `claw login`.");
|
|
6875
6898
|
process.exit(2);
|
|
6876
6899
|
}
|
|
6900
|
+
const UUID_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
6877
6901
|
let sessionId = ref;
|
|
6878
|
-
if (
|
|
6902
|
+
if (!UUID_RE2.test(sessionId)) {
|
|
6903
|
+
const needle = sessionId.startsWith("@") ? sessionId : "@" + sessionId;
|
|
6904
|
+
const slash = needle.indexOf("/");
|
|
6905
|
+
let ownerLogin = null;
|
|
6906
|
+
let slug;
|
|
6907
|
+
if (slash > 0) {
|
|
6908
|
+
ownerLogin = needle.slice(1, slash);
|
|
6909
|
+
slug = "@" + needle.slice(slash + 1).replace(/^@/, "");
|
|
6910
|
+
} else {
|
|
6911
|
+
slug = needle;
|
|
6912
|
+
}
|
|
6879
6913
|
const data = await api.get("/api/v1/sessions");
|
|
6880
|
-
const match = data.items.find(
|
|
6914
|
+
const match = data.items.find(
|
|
6915
|
+
(s) => s.routingName === slug && (ownerLogin === null || s.startedByLogin === ownerLogin)
|
|
6916
|
+
);
|
|
6881
6917
|
if (!match) {
|
|
6882
|
-
|
|
6918
|
+
const label = ownerLogin ? `@${ownerLogin}/${slug.slice(1)}` : slug;
|
|
6919
|
+
console.error(`error: no session with routing name ${label} (run \`claw session list\` to see what's available)`);
|
|
6883
6920
|
process.exit(2);
|
|
6884
6921
|
}
|
|
6885
6922
|
sessionId = match.id;
|
|
@@ -6949,8 +6986,19 @@ var sessionAttach = new Command("attach").description("open a TUI on a session \
|
|
|
6949
6986
|
ws.send(JSON.stringify(approval));
|
|
6950
6987
|
return;
|
|
6951
6988
|
}
|
|
6989
|
+
if (text === "/p" || text.startsWith("/p ")) {
|
|
6990
|
+
const promptText = text.slice(2).trim();
|
|
6991
|
+
if (!promptText) {
|
|
6992
|
+
console.log(`${DIM}usage: /p <text>${RESET}`);
|
|
6993
|
+
return;
|
|
6994
|
+
}
|
|
6995
|
+
const out2 = { type: "prompt", sessionId, text: promptText };
|
|
6996
|
+
ws.send(JSON.stringify(out2));
|
|
6997
|
+
console.log(`${DIM}[${ts()}]${RESET} ${AMBER}\u2192 prompt sent${RESET} ${promptText}`);
|
|
6998
|
+
return;
|
|
6999
|
+
}
|
|
6952
7000
|
if (text.startsWith("/")) {
|
|
6953
|
-
console.log(`${DIM}unknown slash-command: ${text} (try /y /n /q)${RESET}`);
|
|
7001
|
+
console.log(`${DIM}unknown slash-command: ${text} (try /p /y /n /q)${RESET}`);
|
|
6954
7002
|
return;
|
|
6955
7003
|
}
|
|
6956
7004
|
const out = { type: "op_message", sessionId, text };
|
|
@@ -7125,12 +7173,27 @@ function fmtDuration(ms) {
|
|
|
7125
7173
|
function fmtAgo(iso) {
|
|
7126
7174
|
return fmtDuration(Date.now() - new Date(iso).getTime());
|
|
7127
7175
|
}
|
|
7176
|
+
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
7128
7177
|
async function resolveSessionId(idOrName) {
|
|
7129
|
-
if (
|
|
7178
|
+
if (UUID_RE.test(idOrName)) return idOrName;
|
|
7179
|
+
const needle = idOrName.startsWith("@") ? idOrName : "@" + idOrName;
|
|
7180
|
+
const slash = needle.indexOf("/");
|
|
7181
|
+
let ownerLogin = null;
|
|
7182
|
+
let slug;
|
|
7183
|
+
if (slash > 0) {
|
|
7184
|
+
ownerLogin = needle.slice(1, slash);
|
|
7185
|
+
slug = "@" + needle.slice(slash + 1).replace(/^@/, "");
|
|
7186
|
+
} else {
|
|
7187
|
+
slug = needle;
|
|
7188
|
+
}
|
|
7130
7189
|
const data = await api.get("/api/v1/sessions");
|
|
7131
|
-
const match = data.items.find(
|
|
7190
|
+
const match = data.items.find(
|
|
7191
|
+
(s) => s.routingName === slug && (ownerLogin === null || s.startedByLogin === ownerLogin)
|
|
7192
|
+
);
|
|
7132
7193
|
if (!match) {
|
|
7133
|
-
const err = new Error(
|
|
7194
|
+
const err = new Error(
|
|
7195
|
+
ownerLogin ? `no session @${ownerLogin}/${slug.slice(1)} (run \`claw session list\`)` : `no session with routing name ${slug} (run \`claw session list\`)`
|
|
7196
|
+
);
|
|
7134
7197
|
err.code = "CLW_NO_ROUTING_MATCH";
|
|
7135
7198
|
throw err;
|
|
7136
7199
|
}
|
|
@@ -7149,18 +7212,20 @@ var sessionList = new Command("list").alias("ls").description("list sessions you
|
|
|
7149
7212
|
}
|
|
7150
7213
|
for (const s of data.items) {
|
|
7151
7214
|
const dot = s.connected ? "\u25CF" : "\u25CB";
|
|
7152
|
-
const
|
|
7215
|
+
const slug = s.routingName ?? "";
|
|
7216
|
+
const qualified = slug ? `@${s.startedByLogin}/${slug.replace(/^@/, "")}` : "(no routing name)";
|
|
7153
7217
|
const where = s.cwd ? ` ${s.cwd}` : "";
|
|
7154
7218
|
const role = s.role.padEnd(8);
|
|
7155
7219
|
const seen = s.connected ? "online" : `offline \xB7 ${fmtAgo(s.lastSeenAt)}`;
|
|
7156
7220
|
const arch = s.archivedAt ? " \xB7 ARCHIVED" : "";
|
|
7157
|
-
console.log(`${dot} ${
|
|
7221
|
+
console.log(`${dot} ${qualified.padEnd(28)} ${role}${where} [${seen}]${arch}`);
|
|
7158
7222
|
console.log(` id: ${s.id}`);
|
|
7159
7223
|
}
|
|
7160
7224
|
console.log("");
|
|
7161
|
-
console.log("
|
|
7162
|
-
console.log(" claw session events <ref>
|
|
7163
|
-
console.log("
|
|
7225
|
+
console.log(" attach to a session: claw session attach <ref>");
|
|
7226
|
+
console.log(" recent hook/chat: claw session events <ref>");
|
|
7227
|
+
console.log(" operator-to-op chat: claw session messages <ref>");
|
|
7228
|
+
console.log(" <ref> = UUID, @owner/slug, @slug, or bare slug");
|
|
7164
7229
|
});
|
|
7165
7230
|
var sessionInfo = new Command("info").description("show metadata for a single session").argument("<ref>", "session UUID or @routingName").action(async (ref) => {
|
|
7166
7231
|
const id = await resolveSessionId(ref);
|
|
@@ -7237,7 +7302,79 @@ var sessionMessages = new Command("messages").alias("msgs").description("dump op
|
|
|
7237
7302
|
console.log(`(more \u2014 older: --before ${data.firstId} \xB7 newer: --after ${data.lastId})`);
|
|
7238
7303
|
}
|
|
7239
7304
|
});
|
|
7240
|
-
var
|
|
7305
|
+
var sessionArchive = new Command("archive").description("soft-delete a session (sets archivedAt). Note: register-time reconnect unarchives, so a session whose UUID is still in a project's .claude/clawborrator/session.json will resurrect on its next start.").argument("<ref>", "session UUID or @routingName").action(async (ref) => {
|
|
7306
|
+
const id = await resolveSessionId(ref);
|
|
7307
|
+
const r = await api.post(
|
|
7308
|
+
`/api/v1/sessions/${encodeURIComponent(id)}/archive`,
|
|
7309
|
+
{}
|
|
7310
|
+
);
|
|
7311
|
+
if (r.alreadyArchived) {
|
|
7312
|
+
console.log(`(already archived: ${r.sessionId} at ${r.archivedAt})`);
|
|
7313
|
+
} else {
|
|
7314
|
+
console.log(`\u2713 archived ${r.sessionId} at ${r.archivedAt}`);
|
|
7315
|
+
}
|
|
7316
|
+
});
|
|
7317
|
+
var sessionPrune = new Command("prune").description("archive duplicate session rows that share a routing name. The live (or most-recently-seen) row is kept; the rest are archived. Stale dups never reconnect, so they're effectively gone after this.").option("--dry-run", "show what would be pruned without writing").option("--routing <name>", "narrow to a single routing name (e.g. @driver)").action(async (opts) => {
|
|
7318
|
+
const body = { dryRun: !!opts.dryRun };
|
|
7319
|
+
if (opts.routing) body.routingName = opts.routing.startsWith("@") ? opts.routing : "@" + opts.routing;
|
|
7320
|
+
const r = await api.post(`/api/v1/sessions/prune`, body);
|
|
7321
|
+
if (r.pruned.length === 0) {
|
|
7322
|
+
console.log("nothing to prune (no routing-name duplicates).");
|
|
7323
|
+
return;
|
|
7324
|
+
}
|
|
7325
|
+
const verb = r.dryRun ? "would archive" : "archived";
|
|
7326
|
+
console.log(`${verb} ${r.pruned.length} duplicate${r.pruned.length === 1 ? "" : "s"}:`);
|
|
7327
|
+
for (const p of r.pruned) {
|
|
7328
|
+
console.log(` \u2022 ${p.routingName.padEnd(20)} ${p.sessionId} (last seen ${p.lastSeenAt})`);
|
|
7329
|
+
}
|
|
7330
|
+
console.log(`keeping:`);
|
|
7331
|
+
for (const k of r.kept) {
|
|
7332
|
+
console.log(` \u2713 ${k.routingName.padEnd(20)} ${k.sessionId}`);
|
|
7333
|
+
}
|
|
7334
|
+
if (r.dryRun) console.log("\n(--dry-run \u2014 re-run without it to apply)");
|
|
7335
|
+
});
|
|
7336
|
+
var sessionPrompt = new Command("prompt").description("send a one-shot prompt to a session's live Claude (lands in the same inbox as cross-session route prompts; receiving Claude must be polling `await_routed_prompt`)").argument("<ref>", "session UUID or @routingName").argument("<text>", "prompt text \u2014 quote multi-word").action(async (ref, text) => {
|
|
7337
|
+
const id = await resolveSessionId(ref);
|
|
7338
|
+
const cfg = loadConfig();
|
|
7339
|
+
if (!cfg.pat) {
|
|
7340
|
+
console.error("error: not logged in. run `claw login`.");
|
|
7341
|
+
process.exit(2);
|
|
7342
|
+
}
|
|
7343
|
+
const wsUrl = cfg.hubUrl.replace(/^http/i, "ws") + "/cli";
|
|
7344
|
+
const WS = (await Promise.resolve().then(() => (init_wrapper(), wrapper_exports))).default;
|
|
7345
|
+
const ws = new WS(wsUrl, { headers: { Authorization: `Bearer ${cfg.pat}` } });
|
|
7346
|
+
let timer = null;
|
|
7347
|
+
await new Promise((resolve3, reject) => {
|
|
7348
|
+
timer = setTimeout(() => {
|
|
7349
|
+
ws.close();
|
|
7350
|
+
reject(new Error("timeout waiting for ack"));
|
|
7351
|
+
}, 1e4);
|
|
7352
|
+
ws.on("open", () => {
|
|
7353
|
+
ws.send(JSON.stringify({ type: "prompt", sessionId: id, text }));
|
|
7354
|
+
});
|
|
7355
|
+
ws.on("message", (data) => {
|
|
7356
|
+
let m;
|
|
7357
|
+
try {
|
|
7358
|
+
m = JSON.parse(data.toString("utf8"));
|
|
7359
|
+
} catch {
|
|
7360
|
+
return;
|
|
7361
|
+
}
|
|
7362
|
+
if (m.type === "ack" && m.ok) {
|
|
7363
|
+
console.log(`\u2713 delivered (chatId=${m.chatId})`);
|
|
7364
|
+
ws.close();
|
|
7365
|
+
resolve3();
|
|
7366
|
+
} else if (m.type === "error") {
|
|
7367
|
+
ws.close();
|
|
7368
|
+
reject(new Error(`${m.code}: ${m.message}`));
|
|
7369
|
+
}
|
|
7370
|
+
});
|
|
7371
|
+
ws.on("error", (err) => reject(err));
|
|
7372
|
+
ws.on("close", () => {
|
|
7373
|
+
if (timer) clearTimeout(timer);
|
|
7374
|
+
});
|
|
7375
|
+
});
|
|
7376
|
+
});
|
|
7377
|
+
var sessionCmd = new Command("session").description("manage Claude Code sessions registered with this hub").addCommand(sessionList).addCommand(sessionInfo).addCommand(sessionAttach).addCommand(sessionEvents).addCommand(sessionMessages).addCommand(sessionArchive).addCommand(sessionPrune).addCommand(sessionPrompt);
|
|
7241
7378
|
|
|
7242
7379
|
// src/commands/token.ts
|
|
7243
7380
|
var import_node_fs2 = require("node:fs");
|
|
@@ -7445,7 +7582,7 @@ var webhookCmd = new Command("webhook").description("manage webhook subscription
|
|
|
7445
7582
|
|
|
7446
7583
|
// src/index.ts
|
|
7447
7584
|
var program2 = new Command();
|
|
7448
|
-
program2.name("claw").description("clawborrator CLI \u2014 control your Claude Code sessions from the terminal").version("0.0.
|
|
7585
|
+
program2.name("claw").description("clawborrator CLI \u2014 control your Claude Code sessions from the terminal").version("0.0.11");
|
|
7449
7586
|
program2.addCommand(loginCmd);
|
|
7450
7587
|
program2.addCommand(logoutCmd);
|
|
7451
7588
|
program2.addCommand(whoamiCmd);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clawborrator-cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.11",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "claw — command-line client for clawborrator hub_v1. Manages PATs, channel tokens, sessions, cross-session routing, and webhooks; ships an inline TUI for live multi-operator session attach.",
|
|
6
6
|
"license": "MIT",
|