dexto 2.0.0-beta.0 → 2.0.0-beta.1

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 (102) hide show
  1. package/dist/agents/coding-agent/coding-agent.yml +0 -2
  2. package/dist/cli/agent-audit.d.ts +12 -0
  3. package/dist/cli/agent-audit.d.ts.map +1 -0
  4. package/dist/cli/agent-audit.js +52 -0
  5. package/dist/cli/cloud/command.d.ts +3 -39
  6. package/dist/cli/cloud/command.d.ts.map +1 -1
  7. package/dist/cli/cloud/command.js +12 -60
  8. package/dist/cli/cloud/commands/account.d.ts.map +1 -1
  9. package/dist/cli/cloud/commands/account.js +2 -1
  10. package/dist/cli/cloud/commands/agents.d.ts.map +1 -1
  11. package/dist/cli/cloud/commands/agents.js +3 -1
  12. package/dist/cli/cloud/commands/artifacts.d.ts +3 -0
  13. package/dist/cli/cloud/commands/artifacts.d.ts.map +1 -0
  14. package/dist/cli/cloud/commands/artifacts.js +267 -0
  15. package/dist/cli/cloud/commands/automations.d.ts.map +1 -1
  16. package/dist/cli/cloud/commands/automations.js +2 -1
  17. package/dist/cli/cloud/commands/chats.d.ts.map +1 -1
  18. package/dist/cli/cloud/commands/chats.js +20 -5
  19. package/dist/cli/cloud/commands/data-deletions.d.ts.map +1 -1
  20. package/dist/cli/cloud/commands/data-deletions.js +2 -1
  21. package/dist/cli/cloud/commands/deploys.d.ts.map +1 -1
  22. package/dist/cli/cloud/commands/deploys.js +3 -1
  23. package/dist/cli/cloud/commands/drive.d.ts.map +1 -1
  24. package/dist/cli/cloud/commands/drive.js +2 -1
  25. package/dist/cli/cloud/commands/files.d.ts.map +1 -1
  26. package/dist/cli/cloud/commands/files.js +3 -1
  27. package/dist/cli/cloud/commands/models.d.ts.map +1 -1
  28. package/dist/cli/cloud/commands/models.js +3 -1
  29. package/dist/cli/cloud/commands/profile.d.ts.map +1 -1
  30. package/dist/cli/cloud/commands/profile.js +2 -1
  31. package/dist/cli/cloud/commands/publish.d.ts.map +1 -1
  32. package/dist/cli/cloud/commands/publish.js +2 -1
  33. package/dist/cli/cloud/commands/sandboxes.d.ts.map +1 -1
  34. package/dist/cli/cloud/commands/sandboxes.js +2 -1
  35. package/dist/cli/cloud/commands/secrets.d.ts.map +1 -1
  36. package/dist/cli/cloud/commands/secrets.js +2 -1
  37. package/dist/cli/cloud/commands/skills.d.ts.map +1 -1
  38. package/dist/cli/cloud/commands/skills.js +2 -1
  39. package/dist/cli/cloud/commands/traces.d.ts +3 -0
  40. package/dist/cli/cloud/commands/traces.d.ts.map +1 -0
  41. package/dist/cli/cloud/commands/traces.js +142 -0
  42. package/dist/cli/cloud/commands/workspace-apps.d.ts.map +1 -1
  43. package/dist/cli/cloud/commands/workspace-apps.js +2 -1
  44. package/dist/cli/cloud/commands/workspace.d.ts.map +1 -1
  45. package/dist/cli/cloud/commands/workspace.js +3 -1
  46. package/dist/cli/cloud/host.d.ts.map +1 -1
  47. package/dist/cli/cloud/host.js +4 -0
  48. package/dist/cli/cloud/output.d.ts.map +1 -1
  49. package/dist/cli/cloud/output.js +2 -1
  50. package/dist/cli/cloud/run.d.ts.map +1 -1
  51. package/dist/cli/cloud/run.js +10 -10
  52. package/dist/cli/cloud/transfer.d.ts.map +1 -1
  53. package/dist/cli/cloud/transfer.js +2 -1
  54. package/dist/cli/cloud/v1.d.ts +2 -1
  55. package/dist/cli/cloud/v1.d.ts.map +1 -1
  56. package/dist/cli/cloud/v1.js +2 -1
  57. package/dist/cli/commands/auth/sign-in-commands.d.ts.map +1 -1
  58. package/dist/cli/commands/auth/sign-in-commands.js +2 -1
  59. package/dist/cli/commands/cloud/register.d.ts.map +1 -1
  60. package/dist/cli/commands/cloud/register.js +2 -0
  61. package/dist/cli/commands/run/headless.d.ts.map +1 -1
  62. package/dist/cli/commands/run/headless.js +55 -0
  63. package/dist/cli/commands/run/step-log.d.ts +11 -0
  64. package/dist/cli/commands/run/step-log.d.ts.map +1 -0
  65. package/dist/cli/commands/run/step-log.js +42 -0
  66. package/dist/cli/failure.d.ts +29 -0
  67. package/dist/cli/failure.d.ts.map +1 -0
  68. package/dist/cli/failure.js +31 -0
  69. package/dist/cli/help-json.d.ts.map +1 -1
  70. package/dist/cli/help-json.js +1 -1
  71. package/dist/cli/import/claude-code.d.ts +10 -0
  72. package/dist/cli/import/claude-code.d.ts.map +1 -0
  73. package/dist/cli/import/claude-code.js +131 -0
  74. package/dist/cli/import/codex.d.ts +27 -0
  75. package/dist/cli/import/codex.d.ts.map +1 -0
  76. package/dist/cli/import/codex.js +148 -0
  77. package/dist/cli/import/git.d.ts +19 -0
  78. package/dist/cli/import/git.d.ts.map +1 -0
  79. package/dist/cli/import/git.js +95 -0
  80. package/dist/cli/import/local-chats.d.ts +28 -0
  81. package/dist/cli/import/local-chats.d.ts.map +1 -0
  82. package/dist/cli/import/local-chats.js +129 -0
  83. package/dist/cli/import/redaction.d.ts +37 -0
  84. package/dist/cli/import/redaction.d.ts.map +1 -0
  85. package/dist/cli/import/redaction.js +148 -0
  86. package/dist/cli/import/test-utils.d.ts +16 -0
  87. package/dist/cli/import/test-utils.d.ts.map +1 -0
  88. package/dist/cli/import/test-utils.js +223 -0
  89. package/dist/cli/import/transcript.d.ts +75 -0
  90. package/dist/cli/import/transcript.d.ts.map +1 -0
  91. package/dist/cli/import/transcript.js +123 -0
  92. package/dist/cli/interaction.d.ts +18 -0
  93. package/dist/cli/interaction.d.ts.map +1 -0
  94. package/dist/cli/interaction.js +30 -0
  95. package/dist/cli/output.d.ts +9 -0
  96. package/dist/cli/output.d.ts.map +1 -0
  97. package/dist/cli/output.js +6 -0
  98. package/dist/index-main.js +12 -1
  99. package/package.json +10 -10
  100. package/dist/cli/cloud/local-chats.d.ts +0 -73
  101. package/dist/cli/cloud/local-chats.d.ts.map +0 -1
  102. package/dist/cli/cloud/local-chats.js +0 -441
@@ -1,6 +1,7 @@
1
1
  // `dexto login`, `logout`, `whoami` and `accounts`: signing in to Dexto and the saved profiles.
2
+ import { CommandFailure } from '../../failure.js';
2
3
  import { dextoAccounts } from '@dexto/agent-management';
3
- import { CommandFailure, UsageError } from '../../cloud/command.js';
4
+ import { UsageError } from '../../cloud/command.js';
4
5
  const { DEFAULT_PROFILE, forgetLogin, listAccounts: readAccounts, profileNameFor, readCurrentProfile, readLogin, requireProfileName, resolveCredential, resolveProfile, writeCurrentProfile, writeLogin, } = dextoAccounts;
5
6
  export async function login(context, options) {
6
7
  const named = options.profile ?? nonEmpty(context.environment.DEXTO_PROFILE);
@@ -1 +1 @@
1
- {"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/cloud/register.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAmBzC;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAuB3D"}
1
+ {"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/cloud/register.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAqBzC;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAuB3D"}
@@ -13,6 +13,8 @@ const ENGINE_WORDS = {
13
13
  publish: 'Publish a file, folder or .zip as a link anyone with it can open',
14
14
  profile: 'Show and change your Dexto profile: handle, name, bio and who can see it',
15
15
  skills: 'Push a local Skill folder into your Dexto Skills library',
16
+ trace: "List your run traces and show one run's trace from Dexto",
17
+ span: "List one run's spans from Dexto",
16
18
  };
17
19
  /**
18
20
  * These words run on the cloud command engine, which reads its own arguments and global options
@@ -1 +1 @@
1
- {"version":3,"file":"headless.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/run/headless.ts"],"names":[],"mappings":"AAAA,OAAO,EAGH,KAAK,UAAU,EAIlB,MAAM,aAAa,CAAC;AAErB,OAAO,EAGH,KAAK,wBAAwB,EAC7B,KAAK,oBAAoB,EAC5B,MAAM,aAAa,CAAC;AAWrB,MAAM,MAAM,iBAAiB,GAAG;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,KAAK,CAAC;IACnB,gBAAgB,CAAC,EAAE,wBAAwB,EAAE,CAAC;CACjD,CAAC;AA0IF,wBAAsB,qBAAqB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAY/E;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAgC/D;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE;IAC5C,KAAK,EAAE,UAAU,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACtB,GAAG,IAAI,CAgBP;AAED,wBAAsB,kBAAkB,CACpC,KAAK,EAAE,UAAU,EACjB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,MAAM,GAAE,oBAA6B,GACtC,OAAO,CAAC,iBAAiB,CAAC,CAmI5B;AAED,wBAAgB,8BAA8B,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAM1F;AAED,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAM/D;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAExD"}
1
+ {"version":3,"file":"headless.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/run/headless.ts"],"names":[],"mappings":"AAAA,OAAO,EAGH,KAAK,UAAU,EAIlB,MAAM,aAAa,CAAC;AAErB,OAAO,EAGH,KAAK,wBAAwB,EAC7B,KAAK,oBAAoB,EAC5B,MAAM,aAAa,CAAC;AAarB,MAAM,MAAM,iBAAiB,GAAG;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,KAAK,CAAC;IACnB,gBAAgB,CAAC,EAAE,wBAAwB,EAAE,CAAC;CACjD,CAAC;AA+IF,wBAAsB,qBAAqB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAY/E;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CA2C/D;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE;IAC5C,KAAK,EAAE,UAAU,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACtB,GAAG,IAAI,CAqBP;AAED,wBAAsB,kBAAkB,CACpC,KAAK,EAAE,UAAU,EACjB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,MAAM,GAAE,oBAA6B,GACtC,OAAO,CAAC,iBAAiB,CAAC,CAkK5B;AAED,wBAAgB,8BAA8B,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAc1F;AAED,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAM/D;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAExD"}
@@ -1,5 +1,7 @@
1
1
  import { isTextPart, safeStringify, } from '@dexto/core';
2
2
  import { writeHeadlessEvent, toHeadlessApprovalRequired, } from './output.js';
3
+ import { finishedToolStep } from '@dexto/tui/tool-step';
4
+ import { logLine, startLine, stepLine, stepLogEnabled } from './step-log.js';
3
5
  const HEADLESS_TOOL_OUTPUT_MAX_LINES = 20;
4
6
  const HEADLESS_SECTION_SEPARATOR = '========================================';
5
7
  function writeHeadlessLine(line = '') {
@@ -9,6 +11,11 @@ function writeHeadlessSeparator() {
9
11
  writeHeadlessLine(HEADLESS_SECTION_SEPARATOR);
10
12
  }
11
13
  function writeHeadlessTaggedLine(tag, message) {
14
+ if (stepLogEnabled()) {
15
+ const error = tag === 'ERROR';
16
+ writeHeadlessLine(logLine(tag.toLowerCase(), message, { error }));
17
+ return;
18
+ }
12
19
  writeHeadlessLine(`[${tag}] ${message}`);
13
20
  }
14
21
  function writeHeadlessTaggedBlock(tag, content) {
@@ -123,6 +130,16 @@ export async function resolveHeadlessPrompt(promptArg) {
123
130
  }
124
131
  export function printHeadlessMcpStartup(agent) {
125
132
  const serverStatuses = agent.getMcpServersWithStatus().filter((server) => server.enabled);
133
+ if (stepLogEnabled()) {
134
+ for (const server of serverStatuses) {
135
+ if (server.status === 'connected')
136
+ continue;
137
+ writeHeadlessLine(logLine('mcp', `${server.name} failed: ${server.error ?? server.status}`, {
138
+ error: true,
139
+ }));
140
+ }
141
+ return;
142
+ }
126
143
  if (serverStatuses.length === 0) {
127
144
  writeHeadlessTaggedLine('MCP', 'startup: no servers');
128
145
  return;
@@ -151,6 +168,10 @@ export function printHeadlessMcpStartup(agent) {
151
168
  export function printHeadlessRunSummary(params) {
152
169
  const { agent, sessionId, prompt, agentPath, cliVersion } = params;
153
170
  const llmConfig = agent.getCurrentLLMConfig(sessionId);
171
+ if (stepLogEnabled()) {
172
+ writeHeadlessLine(startLine(`${llmConfig.provider}/${llmConfig.model}`, sessionId));
173
+ return;
174
+ }
154
175
  writeHeadlessSeparator();
155
176
  writeHeadlessTaggedLine('RUN', `Dexto CLI v${cliVersion}`);
156
177
  writeHeadlessSeparator();
@@ -179,6 +200,10 @@ export async function executeHeadlessRun(agent, sessionId, prompt, format = 'tex
179
200
  case 'approval:request': {
180
201
  const required = toHeadlessApprovalRequired(event);
181
202
  approvalRequired.push(required);
203
+ if (stepLogEnabled()) {
204
+ writeHeadlessLine(logLine('denied', `${'tool_name' in required ? required.tool_name : required.approval_type} · ${required.message} · approval ${required.approval_id}`, { error: false }));
205
+ break;
206
+ }
182
207
  writeHeadlessTaggedLine('APPROVAL_REQUIRED', `${'tool_name' in required ? required.tool_name : required.approval_type}: ${required.message} (approval ${required.approval_id})`);
183
208
  break;
184
209
  }
@@ -190,6 +215,8 @@ export async function executeHeadlessRun(agent, sessionId, prompt, format = 'tex
190
215
  startedAt: Date.now(),
191
216
  };
192
217
  toolCallState.set(callKey, call);
218
+ if (stepLogEnabled())
219
+ break;
193
220
  writeHeadlessTaggedLine('TOOL', formatToolInvocationForHeadless(call.toolName, call.args));
194
221
  break;
195
222
  }
@@ -215,6 +242,27 @@ export async function executeHeadlessRun(agent, sessionId, prompt, format = 'tex
215
242
  }
216
243
  const toolName = matchedCall?.toolName ?? event.toolName;
217
244
  const args = matchedCall?.args ?? {};
245
+ if (stepLogEnabled()) {
246
+ const display = event.sanitized?.meta.display;
247
+ const { step, output } = finishedToolStep({
248
+ toolName,
249
+ args,
250
+ success: event.success,
251
+ rawResult: event.rawResult,
252
+ ...(event.error !== undefined && { error: event.error }),
253
+ ...(event.presentationSnapshot !== undefined && {
254
+ presentationSnapshot: event.presentationSnapshot,
255
+ }),
256
+ ...(display !== undefined && { display }),
257
+ });
258
+ writeHeadlessLine(stepLine(step));
259
+ for (const line of output) {
260
+ writeHeadlessLine(logLine('', line, { error: true }));
261
+ }
262
+ if (matchedCallKey)
263
+ toolCallState.delete(matchedCallKey);
264
+ break;
265
+ }
218
266
  const invocation = formatToolInvocationForHeadless(toolName, args);
219
267
  const durationText = matchedCall
220
268
  ? ` in ${formatHeadlessDuration(Date.now() - matchedCall.startedAt)}`
@@ -279,6 +327,13 @@ export async function executeHeadlessRun(agent, sessionId, prompt, format = 'tex
279
327
  return result;
280
328
  }
281
329
  export function printHeadlessAssistantResponse(message, totalTokens) {
330
+ if (stepLogEnabled()) {
331
+ const tokens = typeof totalTokens === 'number'
332
+ ? `${new Intl.NumberFormat('en-US').format(totalTokens)} tokens`
333
+ : 'finished';
334
+ writeHeadlessLine(logLine('done', tokens, { error: false }));
335
+ return;
336
+ }
282
337
  writeHeadlessSeparator();
283
338
  writeHeadlessTaggedBlock('DEXTO', message);
284
339
  if (typeof totalTokens === 'number') {
@@ -0,0 +1,11 @@
1
+ import type { Step } from '@dexto/tui/tool-step';
2
+ export declare function stepLogEnabled(): boolean;
3
+ /** A line that isn't a tool call: start, done, an error. */
4
+ export declare function logLine(word: string, text: string, { error, at }: {
5
+ error: boolean;
6
+ at?: Date;
7
+ }): string;
8
+ export declare function startLine(model: string, chatId: string, at?: Date): string;
9
+ /** One finished tool call as one line: verb, target, detail, time, state. */
10
+ export declare function stepLine(step: Step, at?: Date): string;
11
+ //# sourceMappingURL=step-log.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"step-log.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/run/step-log.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAMjD,wBAAgB,cAAc,IAAI,OAAO,CAExC;AAMD,4DAA4D;AAC5D,wBAAgB,OAAO,CACnB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,EAAE,KAAK,EAAE,EAAe,EAAE,EAAE;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,EAAE,CAAC,EAAE,IAAI,CAAA;CAAE,GAC1D,MAAM,CAGR;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,GAAE,IAAiB,GAAG,MAAM,CAEtF;AASD,6EAA6E;AAC7E,wBAAgB,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,GAAE,IAAiB,GAAG,MAAM,CAWlE"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * The Signal log `dexto run` writes to stderr at a terminal: one time-stamped line per step, in
3
+ * the same words as the TUI's step rows. On until the Signal look ships only with
4
+ * DEXTO_PALETTE=signal; the bracketed tags stay the default until then.
5
+ */
6
+ import { chalkStderr as chalk } from 'chalk';
7
+ const VERB_CELLS = 7;
8
+ const TARGET_CELLS = 30;
9
+ const DETAIL_CELLS = 16;
10
+ export function stepLogEnabled() {
11
+ return process.env.DEXTO_PALETTE === 'signal';
12
+ }
13
+ function clock(at) {
14
+ return chalk.dim(at.toLocaleTimeString('en-GB', { hour12: false }));
15
+ }
16
+ /** A line that isn't a tool call: start, done, an error. */
17
+ export function logLine(word, text, { error, at = new Date() }) {
18
+ const label = word.padEnd(VERB_CELLS);
19
+ return `${clock(at)} ${error ? chalk.red(label) : chalk.bold(label)} ${text}`;
20
+ }
21
+ export function startLine(model, chatId, at = new Date()) {
22
+ return logLine('start', `${model} · local · chat ${chatId}`, { error: false, at });
23
+ }
24
+ const STATE_WORD = {
25
+ ok: 'ok',
26
+ fail: 'fail',
27
+ deny: 'denied',
28
+ stop: 'stopped',
29
+ };
30
+ /** One finished tool call as one line: verb, target, detail, time, state. */
31
+ export function stepLine(step, at = new Date()) {
32
+ const failed = step.state === 'fail';
33
+ const word = STATE_WORD[step.state] ?? step.state;
34
+ return [
35
+ `${clock(at)} `,
36
+ chalk.bold(step.verb.toLowerCase().padEnd(VERB_CELLS)),
37
+ step.target.padEnd(TARGET_CELLS),
38
+ (step.detail ?? '').padEnd(DETAIL_CELLS),
39
+ (step.time ?? '').padStart(5),
40
+ ` ${failed ? chalk.red(word) : chalk.dim(word)}`,
41
+ ].join(' ');
42
+ }
@@ -0,0 +1,29 @@
1
+ /** What kind of thing went wrong; each kind has an exit code an agent can branch on. */
2
+ export type FailureKind = 'failed' | 'invalid_input' | 'needs_confirmation' | 'needs_permission' | 'needs_sign_in' | 'not_found' | 'waiting_on_person';
3
+ export declare const EXIT_CODES: {
4
+ readonly failed: 1;
5
+ readonly invalid_input: 2;
6
+ readonly needs_confirmation: 4;
7
+ readonly needs_permission: 3;
8
+ readonly needs_sign_in: 3;
9
+ readonly not_found: 5;
10
+ readonly waiting_on_person: 6;
11
+ readonly usage: 2;
12
+ };
13
+ /** What each exit code means; frozen in 2.0 and shown in help. */
14
+ export declare const EXIT_CODE_MEANINGS: {
15
+ readonly '0': "done";
16
+ readonly '1': "failed";
17
+ readonly '2': "usage or invalid input";
18
+ readonly '3': "needs sign-in or permission";
19
+ readonly '4': "needs confirmation: pass --yes once your person has agreed";
20
+ readonly '5': "not found";
21
+ readonly '6': "waiting on a person, such as an approval";
22
+ };
23
+ /** A failure that says what kind it is and, where there is one, the command that fixes it. */
24
+ export declare class CommandFailure extends Error {
25
+ readonly fix: string | null;
26
+ readonly kind: FailureKind;
27
+ constructor(kind: FailureKind, message: string, fix: string | null);
28
+ }
29
+ //# sourceMappingURL=failure.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"failure.d.ts","sourceRoot":"","sources":["../../src/cli/failure.ts"],"names":[],"mappings":"AAAA,wFAAwF;AACxF,MAAM,MAAM,WAAW,GACjB,QAAQ,GACR,eAAe,GACf,oBAAoB,GACpB,kBAAkB,GAClB,eAAe,GACf,WAAW,GACX,mBAAmB,CAAC;AAE1B,eAAO,MAAM,UAAU;;;;;;;;;CASmC,CAAC;AAE3D,kEAAkE;AAClE,eAAO,MAAM,kBAAkB;;;;;;;;CAQrB,CAAC;AAEX,8FAA8F;AAC9F,qBAAa,cAAe,SAAQ,KAAK;IACrC,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;gBAEf,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;CAMrE"}
@@ -0,0 +1,31 @@
1
+ export const EXIT_CODES = {
2
+ failed: 1,
3
+ invalid_input: 2,
4
+ needs_confirmation: 4,
5
+ needs_permission: 3,
6
+ needs_sign_in: 3,
7
+ not_found: 5,
8
+ waiting_on_person: 6,
9
+ usage: 2,
10
+ };
11
+ /** What each exit code means; frozen in 2.0 and shown in help. */
12
+ export const EXIT_CODE_MEANINGS = {
13
+ '0': 'done',
14
+ '1': 'failed',
15
+ '2': 'usage or invalid input',
16
+ '3': 'needs sign-in or permission',
17
+ '4': 'needs confirmation: pass --yes once your person has agreed',
18
+ '5': 'not found',
19
+ '6': 'waiting on a person, such as an approval',
20
+ };
21
+ /** A failure that says what kind it is and, where there is one, the command that fixes it. */
22
+ export class CommandFailure extends Error {
23
+ fix;
24
+ kind;
25
+ constructor(kind, message, fix) {
26
+ super(message);
27
+ this.name = 'CommandFailure';
28
+ this.fix = fix;
29
+ this.kind = kind;
30
+ }
31
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"help-json.d.ts","sourceRoot":"","sources":["../../src/cli/help-json.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGzC,0DAA0D;AAC1D,wBAAgB,cAAc,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAM/D;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO;;;;;;;;;;;;;;;;;EAW5C"}
1
+ {"version":3,"file":"help-json.d.ts","sourceRoot":"","sources":["../../src/cli/help-json.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,0DAA0D;AAC1D,wBAAgB,cAAc,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAM/D;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO;;;;;;;;;;;;;;;;;EAW5C"}
@@ -1,5 +1,5 @@
1
1
  // `dexto --help --json`: the commands and the frozen exit codes, for agents.
2
- import { EXIT_CODE_MEANINGS } from './cloud/command.js';
2
+ import { EXIT_CODE_MEANINGS } from './failure.js';
3
3
  /** `--help` (or `-h`) with `--json`, and nothing else. */
4
4
  export function isRootJsonHelp(args) {
5
5
  return (args.length === 2 &&
@@ -0,0 +1,10 @@
1
+ import { type ParsedChat } from './transcript.js';
2
+ /**
3
+ * A Claude Code session file: one Agent SDK message per line (`type` `user` or `assistant`, with
4
+ * Anthropic `message.content`), plus title, `pr-link` and bookkeeping lines. Sidechain (subagent),
5
+ * meta and compact-summary lines are left out, as is thinking.
6
+ */
7
+ export declare function parseClaudeCodeTranscript(text: string, file: string): ParsedChat | null;
8
+ /** Where Claude Code keeps its sessions on this machine. */
9
+ export declare function claudeCodeFolder(environment: Readonly<Record<string, string | undefined>>, homeDirectory: string): string;
10
+ //# sourceMappingURL=claude-code.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-code.d.ts","sourceRoot":"","sources":["../../../src/cli/import/claude-code.ts"],"names":[],"mappings":"AAIA,OAAO,EAUH,KAAK,UAAU,EAClB,MAAM,iBAAiB,CAAC;AAsCzB;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CA8DvF;AAiBD,4DAA4D;AAC5D,wBAAgB,gBAAgB,CAC5B,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,EACzD,aAAa,EAAE,MAAM,GACtB,MAAM,CAKR"}
@@ -0,0 +1,131 @@
1
+ // Reads Claude Code session files: `$CLAUDE_CONFIG_DIR/projects/<dashed-cwd>/<session>.jsonl`.
2
+ import path from 'node:path';
3
+ import { createTurns, finishChat, isRecord, jsonLines, stringField, toolCallText, toolResultText, validTime, } from './transcript.js';
4
+ /** What Claude Code writes as a `user` line but the person never typed: slash commands and their output. */
5
+ const CLAUDE_CODE_INJECTED = /^\s*<(command-name|command-message|local-command-[a-z]+)>/u;
6
+ /**
7
+ * The title Claude Code shows for a session, in this order: the person's own (`custom-title`, from
8
+ * renaming it), the one Claude Code generates (`ai-title`, the last one written), then a `summary`
9
+ * line (Claude Code before 2.1). Null when there is none, and the chat is titled by its first line.
10
+ */
11
+ class ClaudeCodeTitle {
12
+ custom = null;
13
+ generated = null;
14
+ summary = null;
15
+ /** Whether the line was a title line. */
16
+ read(line) {
17
+ if (line.type === 'custom-title')
18
+ this.custom = stringField(line, 'customTitle');
19
+ else if (line.type === 'ai-title')
20
+ this.generated = stringField(line, 'aiTitle');
21
+ else if (line.type === 'summary')
22
+ this.summary ??= stringField(line, 'summary');
23
+ else
24
+ return false;
25
+ return true;
26
+ }
27
+ get title() {
28
+ return this.custom ?? this.generated ?? this.summary;
29
+ }
30
+ }
31
+ /** Claude Code's `pr-link` line: `{prNumber, prRepository: "owner/name", prUrl}`. */
32
+ function pullRequest(line) {
33
+ const repository = stringField(line, 'prRepository');
34
+ const url = stringField(line, 'prUrl');
35
+ const number = line.prNumber;
36
+ if (repository === null || url === null || typeof number !== 'number')
37
+ return null;
38
+ return { number, repository, url };
39
+ }
40
+ /**
41
+ * A Claude Code session file: one Agent SDK message per line (`type` `user` or `assistant`, with
42
+ * Anthropic `message.content`), plus title, `pr-link` and bookkeeping lines. Sidechain (subagent),
43
+ * meta and compact-summary lines are left out, as is thinking.
44
+ */
45
+ export function parseClaudeCodeTranscript(text, file) {
46
+ const turns = createTurns();
47
+ const title = new ClaudeCodeTitle();
48
+ const pullRequests = new Map();
49
+ let sessionId = null;
50
+ let cwd = null;
51
+ let gitBranch = null;
52
+ for (const line of jsonLines(text)) {
53
+ if (title.read(line))
54
+ continue;
55
+ if (line.type === 'pr-link') {
56
+ const linked = pullRequest(line);
57
+ if (linked !== null && !pullRequests.has(linked.url))
58
+ pullRequests.set(linked.url, linked);
59
+ continue;
60
+ }
61
+ if (line.type !== 'user' && line.type !== 'assistant')
62
+ continue;
63
+ // A compact summary is Claude Code's own recap of the turns before it, written as `user`.
64
+ if (line.isSidechain === true || line.isMeta === true || line.isCompactSummary === true)
65
+ continue;
66
+ const message = line.message;
67
+ const at = validTime(stringField(line, 'timestamp'));
68
+ if (!isRecord(message) || at === null)
69
+ continue;
70
+ sessionId ??= stringField(line, 'sessionId');
71
+ cwd ??= stringField(line, 'cwd');
72
+ gitBranch ??= stringField(line, 'gitBranch');
73
+ const content = message.content;
74
+ if (typeof content === 'string') {
75
+ if (line.type === 'assistant')
76
+ turns.assistant(content, at);
77
+ else if (!CLAUDE_CODE_INJECTED.test(content))
78
+ turns.user(content, at);
79
+ continue;
80
+ }
81
+ if (!Array.isArray(content))
82
+ continue;
83
+ for (const block of content) {
84
+ if (!isRecord(block))
85
+ continue;
86
+ if (block.type === 'text' && typeof block.text === 'string') {
87
+ if (line.type === 'assistant')
88
+ turns.assistant(block.text, at);
89
+ else if (!CLAUDE_CODE_INJECTED.test(block.text))
90
+ turns.user(block.text, at);
91
+ }
92
+ else if (block.type === 'tool_use') {
93
+ turns.assistant(toolCallText(stringField(block, 'name') ?? 'tool', block.input), at);
94
+ }
95
+ else if (block.type === 'tool_result') {
96
+ turns.assistant(toolResultText(claudeToolResultText(block.content)), at);
97
+ }
98
+ else if (block.type === 'image' && line.type === 'user') {
99
+ turns.user('[An image was attached here; it was not imported.]', at);
100
+ }
101
+ }
102
+ }
103
+ return finishChat({
104
+ cwd,
105
+ gitBranch,
106
+ id: sessionId ?? path.basename(file, '.jsonl'),
107
+ path: file,
108
+ pullRequests: [...pullRequests.values()],
109
+ recordedRemoteUrl: null,
110
+ source: 'claude-code',
111
+ title: title.title,
112
+ }, turns.done());
113
+ }
114
+ function claudeToolResultText(content) {
115
+ if (typeof content === 'string')
116
+ return content;
117
+ if (!Array.isArray(content))
118
+ return '';
119
+ return content
120
+ .map((part) => isRecord(part) && typeof part.text === 'string'
121
+ ? part.text
122
+ : isRecord(part) && part.type === 'image'
123
+ ? '[image]'
124
+ : '')
125
+ .filter((part) => part !== '')
126
+ .join('\n');
127
+ }
128
+ /** Where Claude Code keeps its sessions on this machine. */
129
+ export function claudeCodeFolder(environment, homeDirectory) {
130
+ return path.join(environment.CLAUDE_CONFIG_DIR ?? path.join(homeDirectory, '.claude'), 'projects');
131
+ }
@@ -0,0 +1,27 @@
1
+ import { type ParsedChat } from './transcript.js';
2
+ /**
3
+ * A Codex rollout: `{timestamp, type, payload}` lines, as `codex-rs/history` writes them. The
4
+ * `session_meta` line names the thread and its git remote; `response_item` lines carry messages and
5
+ * tool calls. Developer and system messages, injected context, reasoning and compaction are left out.
6
+ * `titleOf` gives the title Codex keeps for a thread, or null when it keeps none.
7
+ */
8
+ export declare function parseCodexRollout(text: string, file: string, titleOf: (threadId: string) => string | null): ParsedChat | null;
9
+ /** `$CODEX_HOME`, or `~/.codex`. */
10
+ export declare function codexHome(environment: Readonly<Record<string, string | undefined>>, homeDirectory: string): string;
11
+ /** A row of Codex's `threads` table, as much of it as an import needs. */
12
+ export interface CodexThread {
13
+ readonly cwd: string;
14
+ readonly id: string;
15
+ /** Whether its rollout file is still on disk; `codex migrate-rollouts` moves history out. */
16
+ readonly hasRollout: boolean;
17
+ /** The name the person gave it, else the title Codex gave it; null when both are blank. */
18
+ readonly title: string | null;
19
+ readonly updatedAt: string;
20
+ }
21
+ /**
22
+ * The threads Codex lists, read from its state database without writing to it; null when there is
23
+ * no such database. A present database that cannot be read is reported to the caller.
24
+ * Archived threads are left out, as their rollouts are not where sessions are read from.
25
+ */
26
+ export declare function readCodexThreads(home: string): Promise<CodexThread[] | null>;
27
+ //# sourceMappingURL=codex.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex.d.ts","sourceRoot":"","sources":["../../../src/cli/import/codex.ts"],"names":[],"mappings":"AAOA,OAAO,EASH,KAAK,UAAU,EAClB,MAAM,iBAAiB,CAAC;AAMzB;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC7B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,GAC7C,UAAU,GAAG,IAAI,CAiEnB;AAgBD,oCAAoC;AACpC,wBAAgB,SAAS,CACrB,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,EACzD,aAAa,EAAE,MAAM,GACtB,MAAM,CAER;AAMD,0EAA0E;AAC1E,MAAM,WAAW,WAAW;IACxB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,6FAA6F;IAC7F,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,2FAA2F;IAC3F,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC9B;AAiBD;;;;GAIG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,CAsClF"}
@@ -0,0 +1,148 @@
1
+ // Reads Codex sessions: rollouts in `$CODEX_HOME/sessions/YYYY/MM/DD/`, titled from `state_5.sqlite`.
2
+ import { access } from 'node:fs/promises';
3
+ import path from 'node:path';
4
+ import { z } from 'zod';
5
+ import { createTurns, finishChat, isRecord, jsonLines, stringField, toolCallText, toolResultText, validTime, } from './transcript.js';
6
+ /** Context Codex sends as `user` messages that the person never typed. */
7
+ const CODEX_INJECTED = /^\s*(<environment_context>|<user_instructions>|<permissions instructions>|<turn_aborted>|# AGENTS\.md instructions)/u;
8
+ /**
9
+ * A Codex rollout: `{timestamp, type, payload}` lines, as `codex-rs/history` writes them. The
10
+ * `session_meta` line names the thread and its git remote; `response_item` lines carry messages and
11
+ * tool calls. Developer and system messages, injected context, reasoning and compaction are left out.
12
+ * `titleOf` gives the title Codex keeps for a thread, or null when it keeps none.
13
+ */
14
+ export function parseCodexRollout(text, file, titleOf) {
15
+ const turns = createTurns();
16
+ let id = null;
17
+ let cwd = null;
18
+ let gitBranch = null;
19
+ let remoteUrl = null;
20
+ for (const line of jsonLines(text)) {
21
+ const payload = line.payload;
22
+ if (!isRecord(payload))
23
+ continue;
24
+ if (line.type === 'session_meta') {
25
+ id ??= stringField(payload, 'id');
26
+ cwd ??= stringField(payload, 'cwd');
27
+ if (isRecord(payload.git)) {
28
+ gitBranch ??= stringField(payload.git, 'branch');
29
+ remoteUrl ??= stringField(payload.git, 'repository_url');
30
+ }
31
+ continue;
32
+ }
33
+ const at = validTime(stringField(line, 'timestamp'));
34
+ if (line.type !== 'response_item' || at === null)
35
+ continue;
36
+ switch (payload.type) {
37
+ case 'message': {
38
+ const said = codexContentText(payload.content);
39
+ if (payload.role === 'user' && !CODEX_INJECTED.test(said))
40
+ turns.user(said, at);
41
+ if (payload.role === 'assistant')
42
+ turns.assistant(said, at);
43
+ break;
44
+ }
45
+ case 'function_call':
46
+ turns.assistant(toolCallText(stringField(payload, 'name') ?? 'tool', payload.arguments ?? ''), at);
47
+ break;
48
+ case 'custom_tool_call':
49
+ turns.assistant(toolCallText(stringField(payload, 'name') ?? 'tool', payload.input ?? ''), at);
50
+ break;
51
+ case 'local_shell_call': {
52
+ const action = isRecord(payload.action) ? payload.action : {};
53
+ const command = Array.isArray(action.command) ? action.command : [];
54
+ turns.assistant(toolCallText('shell', { command }), at);
55
+ break;
56
+ }
57
+ case 'function_call_output':
58
+ case 'custom_tool_call_output':
59
+ turns.assistant(toolResultText(codexOutputText(payload.output)), at);
60
+ break;
61
+ }
62
+ }
63
+ const threadId = id ?? path.basename(file, '.jsonl');
64
+ return finishChat({
65
+ cwd,
66
+ gitBranch,
67
+ id: threadId,
68
+ path: file,
69
+ pullRequests: [],
70
+ recordedRemoteUrl: remoteUrl,
71
+ source: 'codex',
72
+ title: titleOf(threadId),
73
+ }, turns.done());
74
+ }
75
+ function codexContentText(content) {
76
+ if (!Array.isArray(content))
77
+ return '';
78
+ return content
79
+ .map((part) => (isRecord(part) && typeof part.text === 'string' ? part.text : ''))
80
+ .filter((part) => part !== '')
81
+ .join('\n');
82
+ }
83
+ function codexOutputText(output) {
84
+ if (typeof output === 'string')
85
+ return output;
86
+ if (isRecord(output) && typeof output.content === 'string')
87
+ return output.content;
88
+ return codexContentText(output);
89
+ }
90
+ /** `$CODEX_HOME`, or `~/.codex`. */
91
+ export function codexHome(environment, homeDirectory) {
92
+ return environment.CODEX_HOME ?? path.join(homeDirectory, '.codex');
93
+ }
94
+ /** The state database Codex 0.1xx keeps beside its rollouts. */
95
+ const CODEX_STATE_DB = 'state_5.sqlite';
96
+ const ThreadRowsSchema = z.array(z.object({
97
+ archived: z.number(),
98
+ cwd: z.string(),
99
+ id: z.string(),
100
+ name: z.string().nullable(),
101
+ rollout_path: z.string().nullable(),
102
+ title: z.string(),
103
+ updated_at: z.number(),
104
+ }));
105
+ /**
106
+ * The threads Codex lists, read from its state database without writing to it; null when there is
107
+ * no such database. A present database that cannot be read is reported to the caller.
108
+ * Archived threads are left out, as their rollouts are not where sessions are read from.
109
+ */
110
+ export async function readCodexThreads(home) {
111
+ const file = path.join(home, CODEX_STATE_DB);
112
+ if (!(await exists(file)))
113
+ return null;
114
+ let rows;
115
+ try {
116
+ const { default: Database } = await import('better-sqlite3');
117
+ const db = new Database(file, { fileMustExist: true, readonly: true });
118
+ try {
119
+ rows = ThreadRowsSchema.parse(db
120
+ .prepare('SELECT id, rollout_path, cwd, title, name, archived, updated_at FROM threads')
121
+ .all());
122
+ }
123
+ finally {
124
+ db.close();
125
+ }
126
+ }
127
+ catch (error) {
128
+ throw new Error(`Cannot read Codex state database; titles and migrated history are unavailable. Use --dir to read rollout files without it. ${error instanceof Error ? error.message : 'Unknown error.'}`, { cause: error });
129
+ }
130
+ const threads = [];
131
+ for (const row of rows) {
132
+ if (row.archived !== 0)
133
+ continue;
134
+ const name = row.name?.trim() ?? '';
135
+ const title = row.title.trim();
136
+ threads.push({
137
+ cwd: row.cwd,
138
+ hasRollout: row.rollout_path !== null && (await exists(row.rollout_path)),
139
+ id: row.id,
140
+ title: name !== '' ? name : title !== '' ? title : null,
141
+ updatedAt: new Date(row.updated_at * 1_000).toISOString(),
142
+ });
143
+ }
144
+ return threads;
145
+ }
146
+ async function exists(file) {
147
+ return await access(file).then(() => true, () => false);
148
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * The repository `folder` is in: the main checkout's folder, so every worktree of one repository
3
+ * names the same one, and its `origin` remote. Null when the folder is gone or in no repository.
4
+ */
5
+ export declare function findRepository(folder: string): Promise<{
6
+ readonly remoteUrl: string | null;
7
+ readonly root: string;
8
+ } | null>;
9
+ type FoundRepository = ReturnType<typeof findRepository>;
10
+ /** A lookup of `findRepository` that reads each folder once. */
11
+ export declare function createRepositoryFinder(): (folder: string | null) => FoundRepository;
12
+ /** `[remote "origin"] url = …` in a git config, without credentials. */
13
+ export declare function originUrl(config: string): string | null;
14
+ /**
15
+ * A remote URL with userinfo, query and fragment removed, including scp-style userinfo.
16
+ */
17
+ export declare function withoutCredentials(url: string): string;
18
+ export {};
19
+ //# sourceMappingURL=git.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../../src/cli/import/git.ts"],"names":[],"mappings":"AAKA;;;GAGG;AACH,wBAAsB,cAAc,CAChC,MAAM,EAAE,MAAM,GACf,OAAO,CAAC;IAAE,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAW9E;AAED,KAAK,eAAe,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AAEzD,gEAAgE;AAChE,wBAAgB,sBAAsB,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,KAAK,eAAe,CAWnF;AA6BD,wEAAwE;AACxE,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAavD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAatD"}