clawborrator-cli 0.0.8 → 0.0.10
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 +48 -169
- package/package.json +1 -1
package/dist-bundled/claw.cjs
CHANGED
|
@@ -6874,12 +6874,26 @@ var sessionAttach = new Command("attach").description("open a TUI on a session \
|
|
|
6874
6874
|
console.error("error: not logged in. run `claw login`.");
|
|
6875
6875
|
process.exit(2);
|
|
6876
6876
|
}
|
|
6877
|
+
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
6878
|
let sessionId = ref;
|
|
6878
|
-
if (
|
|
6879
|
+
if (!UUID_RE2.test(sessionId)) {
|
|
6880
|
+
const needle = sessionId.startsWith("@") ? sessionId : "@" + sessionId;
|
|
6881
|
+
const slash = needle.indexOf("/");
|
|
6882
|
+
let ownerLogin = null;
|
|
6883
|
+
let slug;
|
|
6884
|
+
if (slash > 0) {
|
|
6885
|
+
ownerLogin = needle.slice(1, slash);
|
|
6886
|
+
slug = "@" + needle.slice(slash + 1).replace(/^@/, "");
|
|
6887
|
+
} else {
|
|
6888
|
+
slug = needle;
|
|
6889
|
+
}
|
|
6879
6890
|
const data = await api.get("/api/v1/sessions");
|
|
6880
|
-
const match = data.items.find(
|
|
6891
|
+
const match = data.items.find(
|
|
6892
|
+
(s) => s.routingName === slug && (ownerLogin === null || s.startedByLogin === ownerLogin)
|
|
6893
|
+
);
|
|
6881
6894
|
if (!match) {
|
|
6882
|
-
|
|
6895
|
+
const label = ownerLogin ? `@${ownerLogin}/${slug.slice(1)}` : slug;
|
|
6896
|
+
console.error(`error: no session with routing name ${label} (run \`claw session list\` to see what's available)`);
|
|
6883
6897
|
process.exit(2);
|
|
6884
6898
|
}
|
|
6885
6899
|
sessionId = match.id;
|
|
@@ -7111,158 +7125,6 @@ function truncate(s, max) {
|
|
|
7111
7125
|
return s.slice(0, max - 1) + "\u2026";
|
|
7112
7126
|
}
|
|
7113
7127
|
|
|
7114
|
-
// src/commands/session-init.ts
|
|
7115
|
-
var import_node_path2 = require("node:path");
|
|
7116
|
-
var import_node_fs2 = require("node:fs");
|
|
7117
|
-
var import_node_child_process = require("node:child_process");
|
|
7118
|
-
var HOOK_NAMES = [
|
|
7119
|
-
"SessionStart",
|
|
7120
|
-
"SessionEnd",
|
|
7121
|
-
"UserPromptSubmit",
|
|
7122
|
-
"PreToolUse",
|
|
7123
|
-
"PostToolUse",
|
|
7124
|
-
"PostToolUseFailure",
|
|
7125
|
-
"TaskCreated",
|
|
7126
|
-
"SubagentStart",
|
|
7127
|
-
"SubagentStop",
|
|
7128
|
-
"TaskCompleted",
|
|
7129
|
-
"Stop",
|
|
7130
|
-
"Notification"
|
|
7131
|
-
];
|
|
7132
|
-
var TAG = "clawborrator-hook";
|
|
7133
|
-
function hookCommand(name) {
|
|
7134
|
-
return `node ".claude/hooks/clawborrator-tail.mjs" ${name} #${TAG}`;
|
|
7135
|
-
}
|
|
7136
|
-
function isOurHook(h) {
|
|
7137
|
-
return h.type === "command" && h.command.includes(`#${TAG}`);
|
|
7138
|
-
}
|
|
7139
|
-
function fetchHookBundle() {
|
|
7140
|
-
try {
|
|
7141
|
-
const stdout = (0, import_node_child_process.execFileSync)("npx", ["-y", "clawborrator-mcp", "--print-hook-file"], {
|
|
7142
|
-
stdio: ["ignore", "pipe", "inherit"],
|
|
7143
|
-
encoding: "utf8",
|
|
7144
|
-
// npx may take a while if the cache is cold (download + extract).
|
|
7145
|
-
timeout: 12e4,
|
|
7146
|
-
shell: true
|
|
7147
|
-
// cross-platform PATH resolution on Windows
|
|
7148
|
-
});
|
|
7149
|
-
if (!stdout || !stdout.trim()) {
|
|
7150
|
-
throw new Error("--print-hook-file returned empty output");
|
|
7151
|
-
}
|
|
7152
|
-
return stdout;
|
|
7153
|
-
} catch (e) {
|
|
7154
|
-
throw new Error(`failed to fetch hook bundle via npx: ${e?.message ?? String(e)}`);
|
|
7155
|
-
}
|
|
7156
|
-
}
|
|
7157
|
-
var sessionInit = new Command("init").description("install clawborrator hooks into <cwd>/.claude/settings.json + .claude/hooks/").option("--cwd <dir>", "project directory (defaults to current cwd)").option("--remove", "remove the clawborrator hooks (and the bundled .mjs)").option("--refresh-hook", "re-fetch the bundled hook file even if it already exists").action(async (opts) => {
|
|
7158
|
-
const root = (0, import_node_path2.resolve)(opts.cwd ?? process.cwd());
|
|
7159
|
-
const claudeDir = (0, import_node_path2.resolve)(root, ".claude");
|
|
7160
|
-
const hooksDir = (0, import_node_path2.resolve)(claudeDir, "hooks");
|
|
7161
|
-
const hookFile = (0, import_node_path2.resolve)(hooksDir, "clawborrator-tail.mjs");
|
|
7162
|
-
const settings = (0, import_node_path2.resolve)(claudeDir, "settings.json");
|
|
7163
|
-
if (opts.remove) {
|
|
7164
|
-
removeHooks(settings, hookFile);
|
|
7165
|
-
return;
|
|
7166
|
-
}
|
|
7167
|
-
if (!(0, import_node_fs2.existsSync)(hooksDir)) (0, import_node_fs2.mkdirSync)(hooksDir, { recursive: true });
|
|
7168
|
-
if (!(0, import_node_fs2.existsSync)(hookFile) || opts.refreshHook) {
|
|
7169
|
-
console.log("fetching bundled hook from npm via `npx -y clawborrator-mcp --print-hook-file`...");
|
|
7170
|
-
const bundle = fetchHookBundle();
|
|
7171
|
-
(0, import_node_fs2.writeFileSync)(hookFile, bundle, "utf8");
|
|
7172
|
-
try {
|
|
7173
|
-
(0, import_node_fs2.chmodSync)(hookFile, 493);
|
|
7174
|
-
} catch {
|
|
7175
|
-
}
|
|
7176
|
-
console.log(`\u2713 wrote ${hookFile} (${bundle.length} bytes)`);
|
|
7177
|
-
} else {
|
|
7178
|
-
console.log(`(${hookFile} already present \u2014 pass --refresh-hook to overwrite)`);
|
|
7179
|
-
}
|
|
7180
|
-
if (!(0, import_node_fs2.existsSync)(claudeDir)) (0, import_node_fs2.mkdirSync)(claudeDir, { recursive: true });
|
|
7181
|
-
let s = {};
|
|
7182
|
-
if ((0, import_node_fs2.existsSync)(settings)) {
|
|
7183
|
-
try {
|
|
7184
|
-
const raw = (0, import_node_fs2.readFileSync)(settings, "utf8");
|
|
7185
|
-
if (raw.trim()) s = JSON.parse(raw);
|
|
7186
|
-
} catch (e) {
|
|
7187
|
-
console.error(`error: could not parse existing ${settings}: ${e?.message ?? e}`);
|
|
7188
|
-
console.error(" fix the JSON and re-run `claw session init`");
|
|
7189
|
-
process.exit(2);
|
|
7190
|
-
}
|
|
7191
|
-
}
|
|
7192
|
-
if (!s.hooks) s.hooks = {};
|
|
7193
|
-
let added = 0, alreadyPresent = 0, refreshed = 0;
|
|
7194
|
-
for (const name of HOOK_NAMES) {
|
|
7195
|
-
const arr = s.hooks[name] ??= [];
|
|
7196
|
-
let entry = arr.find((e) => (e.matcher ?? ".*") === ".*");
|
|
7197
|
-
if (!entry) {
|
|
7198
|
-
entry = { matcher: ".*", hooks: [] };
|
|
7199
|
-
arr.push(entry);
|
|
7200
|
-
}
|
|
7201
|
-
const existingIdx = entry.hooks.findIndex(isOurHook);
|
|
7202
|
-
const desiredCmd = hookCommand(name);
|
|
7203
|
-
if (existingIdx >= 0) {
|
|
7204
|
-
if (entry.hooks[existingIdx].command !== desiredCmd) {
|
|
7205
|
-
entry.hooks[existingIdx] = { type: "command", command: desiredCmd };
|
|
7206
|
-
refreshed++;
|
|
7207
|
-
} else {
|
|
7208
|
-
alreadyPresent++;
|
|
7209
|
-
}
|
|
7210
|
-
continue;
|
|
7211
|
-
}
|
|
7212
|
-
entry.hooks.push({ type: "command", command: desiredCmd });
|
|
7213
|
-
added++;
|
|
7214
|
-
}
|
|
7215
|
-
(0, import_node_fs2.writeFileSync)(settings, JSON.stringify(s, null, 2) + "\n");
|
|
7216
|
-
if (added > 0) console.log(`\u2713 installed ${added} clawborrator hook${added === 1 ? "" : "s"} \u2192 ${settings}`);
|
|
7217
|
-
if (refreshed > 0) console.log(`\u2713 refreshed ${refreshed} command line${refreshed === 1 ? "" : "s"} (e.g. updated to call the local file)`);
|
|
7218
|
-
if (alreadyPresent > 0) console.log(` (${alreadyPresent} already up-to-date, untouched)`);
|
|
7219
|
-
console.log("");
|
|
7220
|
-
console.log("next: drop a .mcp.json with your channel token (`claw token mint --kind=channel");
|
|
7221
|
-
console.log(" --name=<label> --mcp-snippet --out=.mcp.json`), then start CC with:");
|
|
7222
|
-
console.log(" claude --dangerously-load-development-channels server:clawborrator");
|
|
7223
|
-
console.log(" events will flow as you prompt; watch via `claw session attach <id>`.");
|
|
7224
|
-
});
|
|
7225
|
-
function removeHooks(settingsPath, hookFile) {
|
|
7226
|
-
if ((0, import_node_fs2.existsSync)(hookFile)) {
|
|
7227
|
-
try {
|
|
7228
|
-
(0, import_node_fs2.unlinkSync)(hookFile);
|
|
7229
|
-
console.log(`\u2713 removed ${hookFile}`);
|
|
7230
|
-
} catch (e) {
|
|
7231
|
-
console.warn(`warning: could not delete ${hookFile}: ${e?.message ?? e}`);
|
|
7232
|
-
}
|
|
7233
|
-
}
|
|
7234
|
-
if (!(0, import_node_fs2.existsSync)(settingsPath)) {
|
|
7235
|
-
console.log("(no settings.json to clean up)");
|
|
7236
|
-
return;
|
|
7237
|
-
}
|
|
7238
|
-
let s;
|
|
7239
|
-
try {
|
|
7240
|
-
const raw = (0, import_node_fs2.readFileSync)(settingsPath, "utf8");
|
|
7241
|
-
s = raw.trim() ? JSON.parse(raw) : {};
|
|
7242
|
-
} catch (e) {
|
|
7243
|
-
console.error(`error: could not parse ${settingsPath}: ${e?.message ?? e}`);
|
|
7244
|
-
process.exit(2);
|
|
7245
|
-
}
|
|
7246
|
-
if (!s.hooks) {
|
|
7247
|
-
console.log("(no hooks block in settings.json)");
|
|
7248
|
-
return;
|
|
7249
|
-
}
|
|
7250
|
-
let touched = 0;
|
|
7251
|
-
for (const name of HOOK_NAMES) {
|
|
7252
|
-
const arr = s.hooks[name];
|
|
7253
|
-
if (!arr) continue;
|
|
7254
|
-
for (const entry of arr) {
|
|
7255
|
-
const before = entry.hooks.length;
|
|
7256
|
-
entry.hooks = entry.hooks.filter((h) => !isOurHook(h));
|
|
7257
|
-
if (entry.hooks.length !== before) touched++;
|
|
7258
|
-
}
|
|
7259
|
-
s.hooks[name] = arr.filter((e) => e.hooks.length > 0);
|
|
7260
|
-
if (s.hooks[name].length === 0) delete s.hooks[name];
|
|
7261
|
-
}
|
|
7262
|
-
(0, import_node_fs2.writeFileSync)(settingsPath, JSON.stringify(s, null, 2) + "\n");
|
|
7263
|
-
console.log(`\u2713 removed ${touched} clawborrator hook entr${touched === 1 ? "y" : "ies"} from ${settingsPath}`);
|
|
7264
|
-
}
|
|
7265
|
-
|
|
7266
7128
|
// src/commands/session.ts
|
|
7267
7129
|
function fmtDuration(ms) {
|
|
7268
7130
|
if (!Number.isFinite(ms) || ms < 0) return "\u2014";
|
|
@@ -7277,12 +7139,27 @@ function fmtDuration(ms) {
|
|
|
7277
7139
|
function fmtAgo(iso) {
|
|
7278
7140
|
return fmtDuration(Date.now() - new Date(iso).getTime());
|
|
7279
7141
|
}
|
|
7142
|
+
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
7280
7143
|
async function resolveSessionId(idOrName) {
|
|
7281
|
-
if (
|
|
7144
|
+
if (UUID_RE.test(idOrName)) return idOrName;
|
|
7145
|
+
const needle = idOrName.startsWith("@") ? idOrName : "@" + idOrName;
|
|
7146
|
+
const slash = needle.indexOf("/");
|
|
7147
|
+
let ownerLogin = null;
|
|
7148
|
+
let slug;
|
|
7149
|
+
if (slash > 0) {
|
|
7150
|
+
ownerLogin = needle.slice(1, slash);
|
|
7151
|
+
slug = "@" + needle.slice(slash + 1).replace(/^@/, "");
|
|
7152
|
+
} else {
|
|
7153
|
+
slug = needle;
|
|
7154
|
+
}
|
|
7282
7155
|
const data = await api.get("/api/v1/sessions");
|
|
7283
|
-
const match = data.items.find(
|
|
7156
|
+
const match = data.items.find(
|
|
7157
|
+
(s) => s.routingName === slug && (ownerLogin === null || s.startedByLogin === ownerLogin)
|
|
7158
|
+
);
|
|
7284
7159
|
if (!match) {
|
|
7285
|
-
const err = new Error(
|
|
7160
|
+
const err = new Error(
|
|
7161
|
+
ownerLogin ? `no session @${ownerLogin}/${slug.slice(1)} (run \`claw session list\`)` : `no session with routing name ${slug} (run \`claw session list\`)`
|
|
7162
|
+
);
|
|
7286
7163
|
err.code = "CLW_NO_ROUTING_MATCH";
|
|
7287
7164
|
throw err;
|
|
7288
7165
|
}
|
|
@@ -7301,18 +7178,20 @@ var sessionList = new Command("list").alias("ls").description("list sessions you
|
|
|
7301
7178
|
}
|
|
7302
7179
|
for (const s of data.items) {
|
|
7303
7180
|
const dot = s.connected ? "\u25CF" : "\u25CB";
|
|
7304
|
-
const
|
|
7181
|
+
const slug = s.routingName ?? "";
|
|
7182
|
+
const qualified = slug ? `@${s.startedByLogin}/${slug.replace(/^@/, "")}` : "(no routing name)";
|
|
7305
7183
|
const where = s.cwd ? ` ${s.cwd}` : "";
|
|
7306
7184
|
const role = s.role.padEnd(8);
|
|
7307
7185
|
const seen = s.connected ? "online" : `offline \xB7 ${fmtAgo(s.lastSeenAt)}`;
|
|
7308
7186
|
const arch = s.archivedAt ? " \xB7 ARCHIVED" : "";
|
|
7309
|
-
console.log(`${dot} ${
|
|
7187
|
+
console.log(`${dot} ${qualified.padEnd(28)} ${role}${where} [${seen}]${arch}`);
|
|
7310
7188
|
console.log(` id: ${s.id}`);
|
|
7311
7189
|
}
|
|
7312
7190
|
console.log("");
|
|
7313
|
-
console.log("
|
|
7314
|
-
console.log(" claw session events <ref>
|
|
7315
|
-
console.log("
|
|
7191
|
+
console.log(" attach to a session: claw session attach <ref>");
|
|
7192
|
+
console.log(" recent hook/chat: claw session events <ref>");
|
|
7193
|
+
console.log(" operator-to-op chat: claw session messages <ref>");
|
|
7194
|
+
console.log(" <ref> = UUID, @owner/slug, @slug, or bare slug");
|
|
7316
7195
|
});
|
|
7317
7196
|
var sessionInfo = new Command("info").description("show metadata for a single session").argument("<ref>", "session UUID or @routingName").action(async (ref) => {
|
|
7318
7197
|
const id = await resolveSessionId(ref);
|
|
@@ -7389,11 +7268,11 @@ var sessionMessages = new Command("messages").alias("msgs").description("dump op
|
|
|
7389
7268
|
console.log(`(more \u2014 older: --before ${data.firstId} \xB7 newer: --after ${data.lastId})`);
|
|
7390
7269
|
}
|
|
7391
7270
|
});
|
|
7392
|
-
var sessionCmd = new Command("session").description("manage Claude Code sessions registered with this hub").addCommand(sessionList).addCommand(sessionInfo).addCommand(sessionAttach).addCommand(
|
|
7271
|
+
var sessionCmd = new Command("session").description("manage Claude Code sessions registered with this hub").addCommand(sessionList).addCommand(sessionInfo).addCommand(sessionAttach).addCommand(sessionEvents).addCommand(sessionMessages);
|
|
7393
7272
|
|
|
7394
7273
|
// src/commands/token.ts
|
|
7395
|
-
var
|
|
7396
|
-
var
|
|
7274
|
+
var import_node_fs2 = require("node:fs");
|
|
7275
|
+
var import_node_path2 = require("node:path");
|
|
7397
7276
|
|
|
7398
7277
|
// ../shared/dist/scopes.js
|
|
7399
7278
|
var ALL_SCOPES = [
|
|
@@ -7450,8 +7329,8 @@ var tokenMint = new Command("mint").description("create a new token").requiredOp
|
|
|
7450
7329
|
}
|
|
7451
7330
|
}, null, 2) + "\n";
|
|
7452
7331
|
if (opts.out) {
|
|
7453
|
-
const target = (0,
|
|
7454
|
-
(0,
|
|
7332
|
+
const target = (0, import_node_path2.resolve)(opts.out);
|
|
7333
|
+
(0, import_node_fs2.writeFileSync)(target, json, "utf8");
|
|
7455
7334
|
prose("");
|
|
7456
7335
|
prose(`\u2713 wrote ${target}`);
|
|
7457
7336
|
} else {
|
|
@@ -7597,7 +7476,7 @@ var webhookCmd = new Command("webhook").description("manage webhook subscription
|
|
|
7597
7476
|
|
|
7598
7477
|
// src/index.ts
|
|
7599
7478
|
var program2 = new Command();
|
|
7600
|
-
program2.name("claw").description("clawborrator CLI \u2014 control your Claude Code sessions from the terminal").version("0.0.
|
|
7479
|
+
program2.name("claw").description("clawborrator CLI \u2014 control your Claude Code sessions from the terminal").version("0.0.10");
|
|
7601
7480
|
program2.addCommand(loginCmd);
|
|
7602
7481
|
program2.addCommand(logoutCmd);
|
|
7603
7482
|
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.10",
|
|
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",
|