@generativereality/cctabs 0.1.3 → 0.1.4

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "cctabs",
3
3
  "description": "Claude Code tab manager. Terminal tabs as the UI, no tmux. Claude can orchestrate its own sibling sessions.",
4
- "version": "0.1.3",
4
+ "version": "0.1.4",
5
5
  "author": {
6
6
  "name": "generativereality",
7
7
  "url": "https://cctabs.com"
package/dist/index.js CHANGED
@@ -10,7 +10,7 @@ import { consola } from "consola";
10
10
  import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "fs";
11
11
  //#region package.json
12
12
  var name = "@generativereality/cctabs";
13
- var version = "0.1.3";
13
+ var version = "0.1.4";
14
14
  var description = "Claude Code tab manager. Terminal tabs as the UI, no tmux.";
15
15
  var package_default = {
16
16
  name,
@@ -202,14 +202,17 @@ var WaveAdapter = class {
202
202
  this.jwt = process.env.WAVETERM_JWT ?? "";
203
203
  }
204
204
  blocksList() {
205
+ const wsId = process.env.WAVETERM_WORKSPACEID ?? "";
206
+ const args = [
207
+ "blocks",
208
+ "list",
209
+ "--json",
210
+ "--timeout",
211
+ "15000"
212
+ ];
213
+ if (wsId) args.push("--workspace", wsId);
205
214
  try {
206
- const out = execFileSync("wsh", [
207
- "blocks",
208
- "list",
209
- "--json",
210
- "--timeout",
211
- "15000"
212
- ], { encoding: "utf-8" });
215
+ const out = execFileSync("wsh", args, { encoding: "utf-8" });
213
216
  return JSON.parse(out);
214
217
  } catch {
215
218
  return [];
@@ -325,27 +328,37 @@ var WaveAdapter = class {
325
328
  tabsById.set(b.tabid, arr);
326
329
  }
327
330
  const tabNames = /* @__PURE__ */ new Map();
328
- let workspaces = [];
331
+ let rawWorkspaces = [];
329
332
  try {
330
333
  for (const tabId of tabsById.keys()) {
331
334
  const td = await this.getTab(tabId);
332
335
  tabNames.set(tabId, td.name ?? tabId.slice(0, 8));
333
336
  }
334
- workspaces = await this.workspaceList();
337
+ rawWorkspaces = await this.workspaceList();
335
338
  } catch {} finally {
336
339
  this.closeSocket();
337
340
  }
338
- if (!workspaces.length) {
339
- const wsId = process.env.WAVETERM_WORKSPACEID ?? "";
340
- workspaces = [{
341
- workspacedata: {
342
- oid: wsId,
343
- name: wsId.slice(0, 8) || "default",
344
- tabids: [...tabsById.keys()]
345
- },
346
- windowid: ""
347
- }];
348
- }
341
+ const currentWsId = process.env.WAVETERM_WORKSPACEID ?? "";
342
+ const tabIdsHere = [...tabsById.keys()];
343
+ const existing = rawWorkspaces.find((w) => w.workspacedata.oid === currentWsId);
344
+ const workspaces = [];
345
+ if (currentWsId) workspaces.push({
346
+ workspacedata: {
347
+ oid: currentWsId,
348
+ name: existing?.workspacedata.name ?? (currentWsId.slice(0, 8) || "current"),
349
+ tabids: tabIdsHere
350
+ },
351
+ windowid: existing?.windowid ?? ""
352
+ });
353
+ for (const ws of rawWorkspaces) if (ws.workspacedata.oid !== currentWsId) workspaces.push(ws);
354
+ if (!workspaces.length) workspaces.push({
355
+ workspacedata: {
356
+ oid: "",
357
+ name: "default",
358
+ tabids: tabIdsHere
359
+ },
360
+ windowid: ""
361
+ });
349
362
  return {
350
363
  blocks,
351
364
  tabsById,
@@ -856,6 +869,39 @@ function listSessionNames(dir) {
856
869
  }
857
870
  return results.sort((a, b) => b.mtime - a.mtime);
858
871
  }
872
+ /**
873
+ * Resolve a session ID prefix (e.g. "19aae7b4") to the full UUID by scanning
874
+ * `~/.claude/projects/`. Returns the input unchanged if it already looks like
875
+ * a full UUID, or null if no unique match exists. Pass `dir` to scope the
876
+ * search to one project; otherwise every project is checked.
877
+ *
878
+ * `claude --resume <prefix>` does NOT accept truncated IDs — it treats them
879
+ * as a search query and shows the picker. So callers must expand prefixes
880
+ * before forwarding to claude.
881
+ */
882
+ function expandSessionId(input, dir) {
883
+ if (!input) return null;
884
+ if (/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i.test(input)) return input;
885
+ const projectsRoot = join(homedir(), ".claude", "projects");
886
+ if (!existsSync(projectsRoot)) return null;
887
+ const projectDirs = dir ? [join(projectsRoot, pathToProjectSlug(dir))] : readdirSync(projectsRoot).map((d) => join(projectsRoot, d)).filter((p) => {
888
+ try {
889
+ return statSync(p).isDirectory();
890
+ } catch {
891
+ return false;
892
+ }
893
+ });
894
+ const matches = [];
895
+ for (const pd of projectDirs) {
896
+ if (!existsSync(pd)) continue;
897
+ for (const f of readdirSync(pd)) {
898
+ if (extname(f) !== ".jsonl") continue;
899
+ const id = basename(f, ".jsonl");
900
+ if (id.startsWith(input) && !matches.includes(id)) matches.push(id);
901
+ }
902
+ }
903
+ return matches.length === 1 ? matches[0] : null;
904
+ }
859
905
  //#endregion
860
906
  //#region src/commands/resume.ts
861
907
  function formatAge(mtimeMs) {
@@ -897,8 +943,14 @@ const resumeCommand = define({
897
943
  }
898
944
  const explicitSession = ctx.values.session;
899
945
  let sessionId;
900
- if (explicitSession) sessionId = explicitSession;
901
- else {
946
+ if (explicitSession) {
947
+ const expanded = expandSessionId(explicitSession, dir) ?? expandSessionId(explicitSession);
948
+ if (!expanded) {
949
+ consola.error(`Session '${explicitSession}' not found (or matches multiple sessions). Pass the full UUID.`);
950
+ process.exit(1);
951
+ }
952
+ sessionId = expanded;
953
+ } else {
902
954
  const sessions = findSessionsByName(dir, name);
903
955
  if (sessions.length === 0) {
904
956
  consola.error(`No session named "${name}" in ${dir}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@generativereality/cctabs",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "Claude Code tab manager. Terminal tabs as the UI, no tmux.",
5
5
  "type": "module",
6
6
  "bin": {