@gkorepanov/ccodex 0.4.12 → 0.4.14

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.
Files changed (70) hide show
  1. package/README.md +1 -1
  2. package/config/compatibility.json +3 -3
  3. package/dist/claude/service.d.ts +1 -0
  4. package/dist/claude/service.js +102 -22
  5. package/dist/claude/service.js.map +1 -1
  6. package/dist/claude/session/commands.d.ts +2 -0
  7. package/dist/claude/session/providerRuntimeFactory.d.ts +1 -0
  8. package/dist/claude/session/providerRuntimeFactory.js +5 -0
  9. package/dist/claude/session/providerRuntimeFactory.js.map +1 -1
  10. package/dist/claude/session/session.js +14 -2
  11. package/dist/claude/session/session.js.map +1 -1
  12. package/dist/claude/toolMapper.js +1 -1
  13. package/dist/claude/toolMapper.js.map +1 -1
  14. package/dist/codex/generated/ClientRequest.d.ts +5 -0
  15. package/dist/codex/generated/PathUri.d.ts +3 -2
  16. package/dist/codex/generated/PlanType.d.ts +1 -1
  17. package/dist/codex/generated/ResponseItemRuntimeSchema.js +1 -1
  18. package/dist/codex/generated/v2/AppMetadata.d.ts +0 -1
  19. package/dist/codex/generated/v2/AppToolSummary.d.ts +3 -0
  20. package/dist/codex/generated/v2/BrowserUseRequirements.d.ts +3 -0
  21. package/dist/codex/generated/v2/BrowserUseRequirements.js +3 -0
  22. package/dist/codex/generated/v2/BrowserUseRequirements.js.map +1 -0
  23. package/dist/codex/generated/v2/ConfigBatchWriteParams.d.ts +3 -1
  24. package/dist/codex/generated/v2/ConfigRequirements.d.ts +11 -0
  25. package/dist/codex/generated/v2/ExternalAgentConfigDetectParams.d.ts +8 -0
  26. package/dist/codex/generated/v2/ExternalAgentConfigImportHistory.d.ts +1 -0
  27. package/dist/codex/generated/v2/ExternalAgentConfigImportHistoryRecordParams.d.ts +11 -0
  28. package/dist/codex/generated/v2/ExternalAgentConfigImportHistoryRecordParams.js +3 -0
  29. package/dist/codex/generated/v2/ExternalAgentConfigImportHistoryRecordParams.js.map +1 -0
  30. package/dist/codex/generated/v2/ExternalAgentConfigImportHistoryRecordResponse.d.ts +3 -0
  31. package/dist/codex/generated/v2/ExternalAgentConfigImportHistoryRecordResponse.js +3 -0
  32. package/dist/codex/generated/v2/ExternalAgentConfigImportHistoryRecordResponse.js.map +1 -0
  33. package/dist/codex/generated/v2/ExternalAgentConfigImportParams.d.ts +5 -0
  34. package/dist/codex/generated/v2/FeedbackRequirements.d.ts +3 -0
  35. package/dist/codex/generated/v2/FeedbackRequirements.js +3 -0
  36. package/dist/codex/generated/v2/FeedbackRequirements.js.map +1 -0
  37. package/dist/codex/generated/v2/PluginListParams.d.ts +4 -0
  38. package/dist/codex/generated/v2/PluginShareContext.d.ts +1 -0
  39. package/dist/codex/generated/v2/PluginShareSaveResponse.d.ts +1 -0
  40. package/dist/codex/generated/v2/SkillInterface.d.ts +8 -0
  41. package/dist/codex/generated/v2/Thread.d.ts +4 -0
  42. package/dist/codex/generated/v2/ThreadItem.d.ts +8 -0
  43. package/dist/codex/generated/v2/ThreadListParams.d.ts +4 -0
  44. package/dist/codex/generated/v2/ThreadMetadataUpdateParams.d.ts +4 -0
  45. package/dist/codex/generated/v2/ThreadRealtimeStartParams.d.ts +7 -0
  46. package/dist/codex/generated/v2/index.d.ts +4 -0
  47. package/dist/daemon/probe.js +1 -1
  48. package/dist/gateway/threadList.js +6 -2
  49. package/dist/gateway/threadList.js.map +1 -1
  50. package/dist/handoff/lineageStore.d.ts +9 -2
  51. package/dist/handoff/lineageStore.js +29 -10
  52. package/dist/handoff/lineageStore.js.map +1 -1
  53. package/dist/handoff/providerEpochs.js +5 -1
  54. package/dist/handoff/providerEpochs.js.map +1 -1
  55. package/dist/handoff/service.js +49 -12
  56. package/dist/handoff/service.js.map +1 -1
  57. package/dist/management/setup.js +41 -10
  58. package/dist/management/setup.js.map +1 -1
  59. package/dist/runtime/dependencies.js +1 -1
  60. package/dist/store/HybridStore.d.ts +2 -0
  61. package/dist/store/HybridStore.js +4 -0
  62. package/dist/store/HybridStore.js.map +1 -1
  63. package/dist/store/sqliteStore.js +11 -1
  64. package/dist/store/sqliteStore.js.map +1 -1
  65. package/dist/store/threadFilter.d.ts +1 -0
  66. package/dist/store/threadFilter.js +14 -2
  67. package/dist/store/threadFilter.js.map +1 -1
  68. package/legal/LICENSES.md +1 -1
  69. package/legal/THIRD_PARTY_NOTICES.md +97 -96
  70. package/package.json +5 -5
package/README.md CHANGED
@@ -155,7 +155,7 @@ keep working):
155
155
  | | |
156
156
  |---|---|
157
157
  | **CCodex** | `0.4.8` |
158
- | **Embedded Codex CLI** | `0.145.0` (pinned; a newer global Codex never replaces it) |
158
+ | **Embedded Codex CLI** | `0.146.0` (pinned; a newer global Codex never replaces it) |
159
159
  | **Claude Agent SDK / Claude Code** | `0.3.219` / `2.1.219` |
160
160
  | **Runtime** | Node.js `>=22.13 <27`, npm `>=10` |
161
161
  | **Platforms** | macOS 11+ (arm64) · Linux arm64 & x64, glibc ≥2.31 (Ubuntu 22.04+, Debian 11+, Fedora/RHEL equivalents). Alpine/musl not supported |
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "productVersion": "0.4.12",
3
+ "productVersion": "0.4.14",
4
4
  "node": ">=22.13 <27",
5
- "codexCli": "0.145.0",
6
- "codexGitRevision": "1635de866c61d1b76e50b31928ee6d61482435a8",
5
+ "codexCli": "0.146.0",
6
+ "codexGitRevision": "be449751a978f02e5bbba886999662956c7f38f5",
7
7
  "claudeAgentSdk": "0.3.219",
8
8
  "claudeCode": "2.1.219",
9
9
  "protocolFixture": "codex-0.144.4",
@@ -66,6 +66,7 @@ export interface ClaudeHandoffSource {
66
66
  readonly thread: Thread;
67
67
  readonly turns: Turn[];
68
68
  readonly settings: ThreadSettings;
69
+ readonly runtimeWorkspaceRoots: readonly string[];
69
70
  }
70
71
  export interface ClaudeThreadAdminEffects {
71
72
  rename(sessionId: string, name: string, cwd: string): Promise<void>;
@@ -1,8 +1,8 @@
1
- import { join, resolve } from "node:path";
1
+ import { isAbsolute, join, resolve } from "node:path";
2
2
  import { statSync } from "node:fs";
3
3
  import { deleteSession, listSessions, renameSession, } from "@anthropic-ai/claude-agent-sdk";
4
4
  import { v7 as uuidv7 } from "uuid";
5
- import { settingsGeneration } from "../store/HybridStore.js";
5
+ import { runtimeWorkspaceRoots as storedWorkspaceRoots, settingsGeneration } from "../store/HybridStore.js";
6
6
  import { SqliteHybridStore } from "../store/sqliteStore.js";
7
7
  import { LayeredHybridStore } from "../store/memoryStore.js";
8
8
  import { createClaudeQuery } from "./queryFactory.js";
@@ -51,28 +51,77 @@ function existingThreadCwd(value) {
51
51
  function turnReasoningEffort(params) {
52
52
  return params.collaborationMode?.settings.reasoning_effort ?? params.effort ?? undefined;
53
53
  }
54
- function sandboxPolicy(mode, cwd) {
54
+ function workspaceRoots(value) {
55
+ const roots = [];
56
+ const seen = new Set();
57
+ for (const root of value) {
58
+ if (!isAbsolute(root))
59
+ throw invalidParams(`Claude runtime workspace root '${root}' must be absolute.`);
60
+ if (!seen.has(root)) {
61
+ seen.add(root);
62
+ roots.push(root);
63
+ }
64
+ }
65
+ return roots;
66
+ }
67
+ function workspaceSelection(params, previous) {
68
+ const environments = params.environments;
69
+ if (environments?.some((environment) => environment.environmentId !== "local")) {
70
+ throw invalidParams("Claude threads only support the local Codex environment.");
71
+ }
72
+ if (environments && environments.length > 1) {
73
+ throw invalidParams("Claude threads support at most one local Codex environment.");
74
+ }
75
+ const environment = environments?.[0];
76
+ const requestedCwd = environment?.cwd ?? params.cwd ?? previous?.cwd ?? process.cwd();
77
+ const cwd = existingThreadCwd(requestedCwd);
78
+ const explicitRoots = environment
79
+ ? environment.runtimeWorkspaceRoots
80
+ : params.runtimeWorkspaceRoots;
81
+ if (explicitRoots !== undefined && explicitRoots !== null) {
82
+ return { cwd, runtimeWorkspaceRoots: workspaceRoots(explicitRoots) };
83
+ }
84
+ if (!previous)
85
+ return { cwd, runtimeWorkspaceRoots: [cwd] };
86
+ if (cwd === previous.cwd)
87
+ return { cwd, runtimeWorkspaceRoots: [...previous.runtimeWorkspaceRoots] };
88
+ return {
89
+ cwd,
90
+ runtimeWorkspaceRoots: workspaceRoots(previous.runtimeWorkspaceRoots.map((root) => root === previous.cwd ? cwd : root)),
91
+ };
92
+ }
93
+ function writableRoots(cwd, runtimeWorkspaceRoots) {
94
+ return workspaceRoots([cwd, ...runtimeWorkspaceRoots]);
95
+ }
96
+ function sandboxPolicy(mode, cwd, runtimeWorkspaceRoots = [cwd]) {
55
97
  if (mode === "read-only")
56
98
  return { type: "readOnly", networkAccess: false };
57
99
  if (mode === "danger-full-access")
58
100
  return { type: "dangerFullAccess" };
59
101
  return {
60
102
  type: "workspaceWrite",
61
- writableRoots: [cwd],
103
+ writableRoots: writableRoots(cwd, runtimeWorkspaceRoots),
62
104
  networkAccess: false,
63
105
  excludeTmpdirEnvVar: false,
64
106
  excludeSlashTmp: false,
65
107
  };
66
108
  }
67
- function permissionProfileSandboxPolicy(profile, cwd) {
109
+ function permissionProfileSandboxPolicy(profile, cwd, runtimeWorkspaceRoots = [cwd]) {
68
110
  if (profile === ":read-only")
69
- return sandboxPolicy("read-only", cwd);
111
+ return sandboxPolicy("read-only", cwd, runtimeWorkspaceRoots);
70
112
  if (profile === ":workspace")
71
- return sandboxPolicy("workspace-write", cwd);
113
+ return sandboxPolicy("workspace-write", cwd, runtimeWorkspaceRoots);
72
114
  if (profile === ":danger-full-access")
73
- return sandboxPolicy("danger-full-access", cwd);
115
+ return sandboxPolicy("danger-full-access", cwd, runtimeWorkspaceRoots);
74
116
  throw invalidParams(`Claude threads do not support Codex permission profile '${profile}'.`);
75
117
  }
118
+ function inheritedSandboxPolicy(policy, cwd, runtimeWorkspaceRoots) {
119
+ if (policy && typeof policy === "object" && "type" in policy
120
+ && policy.type === "workspaceWrite") {
121
+ return { ...policy, writableRoots: writableRoots(cwd, runtimeWorkspaceRoots) };
122
+ }
123
+ return policy;
124
+ }
76
125
  function approvalsReviewer(value, fallback = "user") {
77
126
  return value ?? fallback;
78
127
  }
@@ -82,10 +131,11 @@ function threadResponse(record, includeTurns) {
82
131
  ...settings,
83
132
  thread: {
84
133
  ...record.thread,
134
+ isPinned: record.thread.isPinned ?? false,
85
135
  canAcceptDirectInput: record.thread.parentThreadId ? false : true,
86
136
  turns: includeTurns ? record.thread.turns : [],
87
137
  },
88
- runtimeWorkspaceRoots: [record.thread.cwd],
138
+ runtimeWorkspaceRoots: [...storedWorkspaceRoots(record)],
89
139
  instructionSources: [],
90
140
  sandbox,
91
141
  reasoningEffort,
@@ -333,6 +383,7 @@ export class ClaudeService {
333
383
  thread: { ...this.withNativeMetadata(snapshot.record), turns },
334
384
  turns,
335
385
  settings: threadSettings(snapshot.record),
386
+ runtimeWorkspaceRoots: storedWorkspaceRoots(snapshot.record),
336
387
  };
337
388
  }
338
389
  currentThreadSettings(threadId) {
@@ -443,6 +494,15 @@ export class ClaudeService {
443
494
  : null,
444
495
  };
445
496
  }
497
+ if (resume.cwd !== undefined || resume.runtimeWorkspaceRoots !== undefined) {
498
+ await this.applySettings({
499
+ threadId,
500
+ ...(resume.cwd !== undefined ? { cwd: resume.cwd } : {}),
501
+ ...(resume.runtimeWorkspaceRoots !== undefined
502
+ ? { runtimeWorkspaceRoots: resume.runtimeWorkspaceRoots }
503
+ : {}),
504
+ });
505
+ }
446
506
  await (await this.sessions.getOrCreate(threadId)).materializeRuntime();
447
507
  record = await this.sessions.submit(threadId, { type: "readThread", includeTurns: true });
448
508
  record = this.withCatalogModel(record);
@@ -848,7 +908,7 @@ export class ClaudeService {
848
908
  this.requireIndependentThread(params.threadId, "update metadata for");
849
909
  return this.sessions.submit(params.threadId, {
850
910
  type: "threadAdmin",
851
- command: { kind: "metadata", gitInfo: params.gitInfo },
911
+ command: { kind: "metadata", gitInfo: params.gitInfo, isPinned: params.isPinned },
852
912
  });
853
913
  }
854
914
  async archiveThread(threadId) {
@@ -1093,10 +1153,13 @@ export class ClaudeService {
1093
1153
  throw error;
1094
1154
  }
1095
1155
  const createdAt = nowSeconds();
1096
- const cwd = existingThreadCwd(params.cwd ?? sourceRecord.thread.cwd);
1156
+ const { cwd, runtimeWorkspaceRoots } = workspaceSelection(params, {
1157
+ cwd: sourceRecord.thread.cwd,
1158
+ runtimeWorkspaceRoots: storedWorkspaceRoots(sourceRecord),
1159
+ });
1097
1160
  const threadId = uuidv7();
1098
1161
  const thread = {
1099
- ...sourceRecord.thread, id: threadId, ephemeral: params.ephemeral ?? false,
1162
+ ...sourceRecord.thread, id: threadId, ephemeral: params.ephemeral ?? false, isPinned: false,
1100
1163
  sessionId: threadId, forkedFromId: visibleForkedFromId,
1101
1164
  cwd, modelProvider: "claude", createdAt, updatedAt: createdAt, recencyAt: createdAt,
1102
1165
  status: params.ephemeral ? { type: "idle" } : { type: "notLoaded" },
@@ -1108,12 +1171,15 @@ export class ClaudeService {
1108
1171
  };
1109
1172
  const copiedTurns = sourceTurns.map((turn) => forkProjection(turn, thread.id));
1110
1173
  const record = {
1111
- ...sourceRecord, thread, claudeSessionId: branch.sessionId, modelPickerId, claudeModelValue, serviceTier,
1174
+ ...sourceRecord, thread, runtimeWorkspaceRoots,
1175
+ claudeSessionId: branch.sessionId, modelPickerId, claudeModelValue, serviceTier,
1112
1176
  approvalPolicy: params.approvalPolicy ?? sourceRecord.approvalPolicy,
1113
1177
  approvalsReviewer: approvalsReviewer(params.approvalsReviewer, sourceRecord.approvalsReviewer),
1114
1178
  sandboxPolicy: params.permissions
1115
- ? permissionProfileSandboxPolicy(params.permissions, cwd)
1116
- : params.sandbox ? sandboxPolicy(params.sandbox, cwd) : sourceRecord.sandboxPolicy,
1179
+ ? permissionProfileSandboxPolicy(params.permissions, cwd, runtimeWorkspaceRoots)
1180
+ : params.sandbox
1181
+ ? sandboxPolicy(params.sandbox, cwd, runtimeWorkspaceRoots)
1182
+ : inheritedSandboxPolicy(sourceRecord.sandboxPolicy, cwd, runtimeWorkspaceRoots),
1117
1183
  baseInstructions: params.baseInstructions === undefined ? sourceRecord.baseInstructions : params.baseInstructions,
1118
1184
  developerInstructions: params.developerInstructions === undefined
1119
1185
  ? sourceRecord.developerInstructions : params.developerInstructions,
@@ -1510,6 +1576,7 @@ export class ClaudeService {
1510
1576
  if (!native)
1511
1577
  return {
1512
1578
  ...record.thread,
1579
+ isPinned: record.thread.isPinned ?? false,
1513
1580
  canAcceptDirectInput: record.thread.parentThreadId ? false : true,
1514
1581
  };
1515
1582
  const createdAt = native.createdAt === undefined
@@ -1518,8 +1585,9 @@ export class ClaudeService {
1518
1585
  const updatedAt = Math.floor(native.lastModified / 1_000);
1519
1586
  return {
1520
1587
  ...record.thread,
1588
+ isPinned: record.thread.isPinned ?? false,
1521
1589
  canAcceptDirectInput: record.thread.parentThreadId ? false : true,
1522
- name: (native.customTitle ?? native.summary) || record.thread.name,
1590
+ name: record.thread.name || native.customTitle || native.summary,
1523
1591
  preview: native.firstPrompt ?? record.thread.preview,
1524
1592
  cwd: native.cwd ?? record.thread.cwd,
1525
1593
  createdAt,
@@ -1587,7 +1655,8 @@ export class ClaudeService {
1587
1655
  const reasoningEffort = settings?.effort ?? null;
1588
1656
  const serviceTier = await this.validatedServiceTier(modelPickerId, reasoningEffort, requestedServiceTier);
1589
1657
  const createdAt = nowSeconds();
1590
- const cwd = existingThreadCwd(params.cwd ?? process.cwd());
1658
+ const workspace = workspaceSelection(params);
1659
+ const { cwd, runtimeWorkspaceRoots } = workspace;
1591
1660
  return {
1592
1661
  thread: {
1593
1662
  id: uuidv7(),
@@ -1597,6 +1666,7 @@ export class ClaudeService {
1597
1666
  parentThreadId: null,
1598
1667
  preview: "",
1599
1668
  ephemeral: params.ephemeral ?? false,
1669
+ isPinned: false,
1600
1670
  historyMode: params.historyMode ?? "legacy",
1601
1671
  modelProvider: "claude",
1602
1672
  createdAt,
@@ -1615,6 +1685,7 @@ export class ClaudeService {
1615
1685
  name: null,
1616
1686
  turns: [],
1617
1687
  },
1688
+ runtimeWorkspaceRoots,
1618
1689
  claudeSessionId: uuidv7(),
1619
1690
  modelPickerId,
1620
1691
  claudeModelValue,
@@ -1622,8 +1693,8 @@ export class ClaudeService {
1622
1693
  approvalPolicy: params.approvalPolicy ?? "on-request",
1623
1694
  approvalsReviewer: approvalsReviewer(params.approvalsReviewer),
1624
1695
  sandboxPolicy: params.permissions
1625
- ? permissionProfileSandboxPolicy(params.permissions, cwd)
1626
- : sandboxPolicy(params.sandbox, cwd),
1696
+ ? permissionProfileSandboxPolicy(params.permissions, cwd, runtimeWorkspaceRoots)
1697
+ : sandboxPolicy(params.sandbox, cwd, runtimeWorkspaceRoots),
1627
1698
  baseInstructions: params.baseInstructions ?? null,
1628
1699
  developerInstructions: params.developerInstructions ?? null,
1629
1700
  personality: settings?.personality ?? params.personality ?? null,
@@ -1678,7 +1749,13 @@ export class ClaudeService {
1678
1749
  const requestedServiceTier = normalizeClaudeServiceTier(this.config, modelPickerId, params.serviceTier === undefined ? before.serviceTier : params.serviceTier);
1679
1750
  if (requestedServiceTier !== null && requestedServiceTier !== "default" && requestedServiceTier !== "fast")
1680
1751
  throw invalidParams(`Unsupported Claude service tier '${requestedServiceTier}'.`);
1681
- const cwd = existingThreadCwd(params.cwd ?? before.thread.cwd);
1752
+ const { cwd, runtimeWorkspaceRoots } = workspaceSelection(params, {
1753
+ cwd: before.thread.cwd,
1754
+ runtimeWorkspaceRoots: storedWorkspaceRoots(before),
1755
+ });
1756
+ const workspaceChanged = cwd !== before.thread.cwd
1757
+ || runtimeWorkspaceRoots.length !== storedWorkspaceRoots(before).length
1758
+ || runtimeWorkspaceRoots.some((root, index) => root !== storedWorkspaceRoots(before)[index]);
1682
1759
  const reasoningEffort = params.effort === undefined ? before.reasoningEffort : params.effort;
1683
1760
  const serviceTier = await this.validatedServiceTier(modelPickerId, reasoningEffort, requestedServiceTier);
1684
1761
  syncCanonicalSettings = requestedServiceTier === "fast" && serviceTier !== "fast";
@@ -1688,14 +1765,17 @@ export class ClaudeService {
1688
1765
  const candidate = {
1689
1766
  ...before,
1690
1767
  thread: { ...before.thread, cwd },
1768
+ runtimeWorkspaceRoots,
1691
1769
  modelPickerId,
1692
1770
  claudeModelValue,
1693
1771
  serviceTier,
1694
1772
  approvalPolicy: params.approvalPolicy ?? before.approvalPolicy,
1695
1773
  approvalsReviewer: approvalsReviewer(params.approvalsReviewer, before.approvalsReviewer),
1696
1774
  sandboxPolicy: params.permissions
1697
- ? permissionProfileSandboxPolicy(params.permissions, cwd)
1698
- : params.sandboxPolicy ?? before.sandboxPolicy,
1775
+ ? permissionProfileSandboxPolicy(params.permissions, cwd, runtimeWorkspaceRoots)
1776
+ : params.sandboxPolicy ?? (workspaceChanged
1777
+ ? inheritedSandboxPolicy(before.sandboxPolicy, cwd, runtimeWorkspaceRoots)
1778
+ : before.sandboxPolicy),
1699
1779
  reasoningEffort,
1700
1780
  reasoningSummary: params.summary === undefined ? before.reasoningSummary : params.summary,
1701
1781
  collaborationMode: collaborationMode === null ? null : syncedCollaborationMode(collaborationMode, modelPickerId, reasoningEffort),