@toddzheng024/dscode-bundle 0.7.8 → 0.7.9

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/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.7.8",
2
+ "version": "0.7.9",
3
3
  "type": "module",
4
4
  "license": "MIT",
5
5
  "author": "Todd Zheng",
@@ -10,7 +10,11 @@ export function auditStore(directory) {
10
10
  read(id) {
11
11
  const path = pathFor(id);
12
12
  if (!existsSync(path)) return [];
13
- return readFileSync(path, 'utf8').split('\n').filter(Boolean).map(line => JSON.parse(line));
13
+ // A torn or corrupt line is skipped, never allowed to break every later read.
14
+ // Audit rows are a telemetry sidecar: silent skips are accepted and the usable trail stays readable.
15
+ return readFileSync(path, 'utf8').split('\n').filter(Boolean).flatMap(line => {
16
+ try { return [JSON.parse(line)]; } catch { return []; }
17
+ });
14
18
  },
15
19
  append(id, record) {
16
20
  mkdirSync(directory, { recursive: true, mode: 0o700 });
@@ -25,7 +25,7 @@ export function redact(text) {
25
25
  return String(text)
26
26
  .replace(/-----BEGIN [^-]*PRIVATE KEY-----[\s\S]*?-----END [^-]*PRIVATE KEY-----/g, '[REDACTED]')
27
27
  .replace(/\b(?:sk-[A-Za-z0-9_-]{12,}|gh[pousr]_[A-Za-z0-9_]{16,}|github_pat_[A-Za-z0-9_]{16,}|AKIA[A-Z0-9]{16})\b/g, '[REDACTED]')
28
- .replace(/\b(Bearer\s+)[A-Za-z0-9._~+\/-]{8,}=*/gi, '$1[REDACTED]')
28
+ .replace(/\b(Bearer\s+)[A-Za-z0-9._~+/-]{8,}=*/gi, '$1[REDACTED]')
29
29
  .replace(/((?:api[_-]?key|access[_-]?token|refresh[_-]?token|password|secret|authorization|cookie)["']?\s*[:=]\s*["']?)([^\s"',;}]+)/gi, '$1[REDACTED]')
30
30
  .replace(/(https?:\/\/)[^\s/@:]+:[^\s/@]+@/g, '$1[REDACTED]@');
31
31
  }
@@ -65,7 +65,7 @@ export function parseDecision(text) {
65
65
  const ESCALATION_DIAGNOSTICS = new Set(['ps', 'lsof', 'pgrep', 'sw_vers', 'uname', 'id', 'date', 'hostname', 'pwd', 'sysctl']);
66
66
  // Quotes, substitution, redirects and chaining all mean the command can do more
67
67
  // than the diagnostic whose name it starts with.
68
- const SHELL_META = /[;&|<>`$(){}\[\]\n\\'"]/;
68
+ const SHELL_META = /[;&|<>`$()[\]\n\\'"]/;
69
69
 
70
70
  /**
71
71
  * Match one pending escalation against the read-only diagnostic allowlist.
@@ -80,5 +80,9 @@ export function escalationDiagnosticGrant(toolName, args) {
80
80
  if (command.length === 0 || command.length > 200 || SHELL_META.test(command)) return undefined;
81
81
  const argv = command.split(/\s+/);
82
82
  if (!ESCALATION_DIAGNOSTICS.has(argv[0])) return undefined;
83
+ // A diagnostic is only safe read-only: `sysctl -w` and assignment-like sysctl keys write
84
+ // kernel state, and arguments can turn hostname/date into a system change when privileged.
85
+ if (argv[0] === 'sysctl' && argv.some(token => token === '-w' || token.includes('='))) return undefined;
86
+ if ((argv[0] === 'hostname' || argv[0] === 'date') && argv.length > 1) return undefined;
83
87
  return { command, argv };
84
88
  }
@@ -51,9 +51,9 @@ export async function readClipboardImage() {
51
51
  await execFile(binary, [path], { timeout: 10_000, maxBuffer: 1024 });
52
52
  } catch (error) {
53
53
  await rm(directory, { recursive: true, force: true });
54
- if (error?.code === 2) throw Error('Clipboard has no image');
55
- if (error?.code === 4) throw Error('Clipboard image is too large');
56
- throw Error('Could not read clipboard image');
54
+ if (error?.code === 2) throw Error('Clipboard has no image', { cause: error });
55
+ if (error?.code === 4) throw Error('Clipboard image is too large', { cause: error });
56
+ throw Error('Could not read clipboard image', { cause: error });
57
57
  }
58
58
  clipboardDirs.add(directory);
59
59
  if (!cleanupRegistered) {
@@ -39,7 +39,7 @@ async function git(dir, cwd, args, { index, signal, env = {} } = {}) {
39
39
  });
40
40
  return stdout;
41
41
  } catch (error) {
42
- if (error.code === 'ERR_CHILD_PROCESS_STDIO_MAXBUFFER') throw Error('Review diff exceeds 160 KiB. Use --path to review a smaller part.');
42
+ if (error.code === 'ERR_CHILD_PROCESS_STDIO_MAXBUFFER') throw Error('Review diff exceeds 160 KiB. Use --path to review a smaller part.', { cause: error });
43
43
  throw error;
44
44
  }
45
45
  }
@@ -39,7 +39,7 @@ const matchesPath = (file, path) => !path || file === path || file.startsWith(`$
39
39
  const safeLabel = value => JSON.stringify(value);
40
40
  const sensitiveFile = file => /^(?:\.env(?:\..*)?|\.npmrc|\.pypirc|id_(?:rsa|ed25519))$|\.(?:pem|p12|pfx|key)$/i.test(posix.basename(file));
41
41
 
42
- async function untracked(cwd, path, signal) {
42
+ export async function untracked(cwd, path, signal) {
43
43
  const args = ['ls-files', '--others', '--exclude-standard', '-z', '--', ...(path ? [path] : [])];
44
44
  const names = (await git(cwd, args, signal)).split('\0').filter(Boolean).filter(file => matchesPath(file, path));
45
45
  const chunks = [], omitted = [];
@@ -51,13 +51,21 @@ async function untracked(cwd, path, signal) {
51
51
  continue;
52
52
  }
53
53
  const full = join(cwd, file);
54
- const info = await lstat(full);
55
- if (!info.isFile() || info.size > 128 * 1024) {
54
+ let data;
55
+ try {
56
+ const info = await lstat(full);
57
+ if (!info.isFile() || info.size > 128 * 1024) {
58
+ omitted.push(file);
59
+ chunks.push(`Untracked file omitted from review: ${safeLabel(file)} (not a small regular file)\n`);
60
+ continue;
61
+ }
62
+ data = await readFile(full);
63
+ } catch {
64
+ // A file that vanishes or turns unreadable between listing and reading is omitted, never fatal.
56
65
  omitted.push(file);
57
- chunks.push(`Untracked file omitted from review: ${safeLabel(file)} (not a small regular file)\n`);
66
+ chunks.push(`Untracked file omitted from review: ${safeLabel(file)} (unreadable or vanished during collection)\n`);
58
67
  continue;
59
68
  }
60
- const data = await readFile(full);
61
69
  if (data.includes(0)) {
62
70
  omitted.push(file);
63
71
  chunks.push(`Untracked binary file omitted from review: ${safeLabel(file)}\n`);
@@ -88,7 +96,7 @@ export function isGitWorkspaceSync(cwd, run = execFileSync, now = Date.now()) {
88
96
  // Any failure (no repository, missing directory, git unavailable) means the review tool cannot work here.
89
97
  let value = false;
90
98
  try { run('git', ['rev-parse', '--is-inside-work-tree'], { cwd, encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], timeout: 3000 }); value = true; }
91
- catch { value = false; }
99
+ catch { /* any failure means the review tool cannot work here */ }
92
100
  gitWorkspaceCache.set(cwd, { at: now, value });
93
101
  return value;
94
102
  }
@@ -99,7 +107,7 @@ export function isGitAvailableSync(run = execFileSync) {
99
107
  if (run === execFileSync && gitAvailable !== undefined) return gitAvailable;
100
108
  let value = false;
101
109
  try { run('git', ['--version'], { stdio: 'ignore', timeout: 3000 }); value = true; }
102
- catch { value = false; }
110
+ catch { /* git is unavailable */ }
103
111
  if (run === execFileSync) gitAvailable = value;
104
112
  return value;
105
113
  }
@@ -186,7 +186,7 @@ export function createGmailConnector({ inbox = createEmailInbox(), directory = j
186
186
  store.write('state.json', next); return { accepted: next.accepted, skipped: next.skipped };
187
187
  } catch (error) {
188
188
  const safe = error.status ? error.message : /^(Google|Gmail|Grant|Set DSCODE_|Cannot read|Invalid Gmail)/.test(error.message) ? error.message : 'Gmail sync interrupted. Retry sync.';
189
- store.write('state.json', { ...state, error: safe }); throw Error(safe);
189
+ store.write('state.json', { ...state, error: safe }); throw Error(safe, { cause: error });
190
190
  }
191
191
  });
192
192
  },
@@ -52,7 +52,7 @@ export function createEmailInbox({ directory = process.env.DSCODE_EMAIL_DIR || j
52
52
  try {
53
53
  writeFileSync(temp, json, { flag: 'wx', mode: 0o600 });
54
54
  renameSync(temp, target);
55
- } finally { try { unlinkSync(temp); } catch (error) { if (error.code !== 'ENOENT') throw error; } }
55
+ } finally { try { unlinkSync(temp); } catch { /* best-effort cleanup: never mask the write's own outcome */ } }
56
56
  return mail;
57
57
  },
58
58
  list() {
@@ -6,7 +6,7 @@ import { tryLockExclusive } from '@deepseek-ai/node-addon-system/flock';
6
6
  export function emailStore(directory, label = 'email') {
7
7
  const read = name => {
8
8
  try { return JSON.parse(readFileSync(join(directory, name), 'utf8')); }
9
- catch (error) { if (error.code === 'ENOENT') return null; throw Error('Cannot read local ' + label + ' configuration.'); }
9
+ catch (error) { if (error.code === 'ENOENT') return null; throw Error('Cannot read local ' + label + ' configuration.', { cause: error }); }
10
10
  };
11
11
  return {
12
12
  directory, read,
@@ -17,7 +17,7 @@ export function emailStore(directory, label = 'email') {
17
17
  try {
18
18
  writeFileSync(temp, JSON.stringify(value), { flag: 'wx', mode: 0o600 });
19
19
  renameSync(temp, join(directory, name));
20
- } finally { try { unlinkSync(temp); } catch (error) { if (error.code !== 'ENOENT') throw error; } }
20
+ } finally { try { unlinkSync(temp); } catch { /* best-effort cleanup: never mask the write's own outcome */ } }
21
21
  },
22
22
  async locked(action) {
23
23
  mkdirSync(directory, { recursive: true, mode: 0o700 });
@@ -57,7 +57,7 @@ export class CommunicationService {
57
57
  };
58
58
  agent.cancel = state.cancelWrapper;
59
59
  this.states.set(agent.id, state);
60
- state.ready = this.background(this.recover(state));
60
+ this.ensureReady(state);
61
61
  }
62
62
  state(agent) {
63
63
  const state = this.states.get(agent.id);
@@ -65,6 +65,15 @@ export class CommunicationService {
65
65
  this.store.authenticate(state.auth);
66
66
  return state;
67
67
  }
68
+ /** Recovery runs once per agent; a failed attempt fails closed for the step that awaited
69
+ * it and is retried by the next step, instead of failing every later step forever. */
70
+ ensureReady(state) {
71
+ if (!state.ready || state.readyFailed) {
72
+ state.readyFailed = false;
73
+ state.ready = this.background(this.recover(state).catch(error => { state.readyFailed = true; throw error; }));
74
+ }
75
+ return state.ready;
76
+ }
68
77
  async remove(agent) {
69
78
  const state = this.states.get(agent.id);
70
79
  if (!state || state.agent !== agent) return;
@@ -161,7 +170,7 @@ export class CommunicationService {
161
170
  for (const m of messages) if (communicationId(m)) {
162
171
  batch.add(communicationId(m)); this.store.transition(state.auth, communicationId(m), 'admitted', `${state.auth.generation}:${turn}`);
163
172
  }
164
- await state.ready;
173
+ await this.ensureReady(state);
165
174
  await this.confirm(state);
166
175
  signal.throwIfAborted();
167
176
  if (step === 1 && !state.cutoffs.has(turn)) fail('missing_cutoff', 'Missing turn-start mailbox cutoff');
@@ -193,7 +202,7 @@ export class CommunicationService {
193
202
  }
194
203
  async receive(agent, payload) {
195
204
  const state = this.state(agent);
196
- await state.ready;
205
+ await this.ensureReady(state);
197
206
  this.store.authenticate(state.auth);
198
207
  // Reply routing is checked both here and by the shared admission transaction.
199
208
  let admission;
@@ -210,7 +219,7 @@ export class CommunicationService {
210
219
  }
211
220
  async send(agent, args, reply = false) {
212
221
  if (agent.session.header.origin === 'subagent') fail('root_session_required', 'Cross-session requests and replies belong to the root session; report this to your parent agent.');
213
- const state = this.state(agent); await state.ready;
222
+ const state = this.state(agent); await this.ensureReady(state);
214
223
  let destination = args.session_id, kind = args.kind, inReplyTo = args.in_reply_to;
215
224
  if (reply) {
216
225
  const original = this.store.get(args.request_message_id);
@@ -39,7 +39,7 @@ export async function apply(ctx) {
39
39
  }, async ({ project, workspace, cursor = 0, limit = 20 }) => {
40
40
  if (!Number.isSafeInteger(cursor) || cursor < 0 || !Number.isSafeInteger(limit) || limit < 1 || limit > 100) throw Error('Invalid pagination');
41
41
  const all = (await discover(home)).filter(s => (!project || s.card?.project?.id === project) && (!workspace || s.cwd === workspace)).sort((a, b) => a.id.localeCompare(b.id));
42
- return { sessions: all.slice(cursor, cursor + limit).map(({ socket, ...s }) => s), nextCursor: cursor + limit < all.length ? cursor + limit : null };
42
+ return { sessions: all.slice(cursor, cursor + limit).map(({ socket: _socket, ...s }) => s), nextCursor: cursor + limit < all.length ? cursor + limit : null };
43
43
  });
44
44
  register('read_session', 'Read a session event page without waking it or collecting deferred notes.', {
45
45
  session_id: field('Complete active session ID', true), after: field('Last seen session event sequence', false, 'number'), limit: field('1..100', false, 'number'),
@@ -51,9 +51,9 @@ export async function readClipboardImage() {
51
51
  await execFile(binary, [path], { timeout: 10_000, maxBuffer: 1024 });
52
52
  } catch (error) {
53
53
  await rm(directory, { recursive: true, force: true });
54
- if (error?.code === 2) throw Error('Clipboard has no image');
55
- if (error?.code === 4) throw Error('Clipboard image is too large');
56
- throw Error('Could not read clipboard image');
54
+ if (error?.code === 2) throw Error('Clipboard has no image', { cause: error });
55
+ if (error?.code === 4) throw Error('Clipboard image is too large', { cause: error });
56
+ throw Error('Could not read clipboard image', { cause: error });
57
57
  }
58
58
  clipboardDirs.add(directory);
59
59
  if (!cleanupRegistered) {
@@ -186,7 +186,7 @@ export function createGmailConnector({ inbox = createEmailInbox(), directory = j
186
186
  store.write('state.json', next); return { accepted: next.accepted, skipped: next.skipped };
187
187
  } catch (error) {
188
188
  const safe = error.status ? error.message : /^(Google|Gmail|Grant|Set DSCODE_|Cannot read|Invalid Gmail)/.test(error.message) ? error.message : 'Gmail sync interrupted. Retry sync.';
189
- store.write('state.json', { ...state, error: safe }); throw Error(safe);
189
+ store.write('state.json', { ...state, error: safe }); throw Error(safe, { cause: error });
190
190
  }
191
191
  });
192
192
  },
@@ -52,7 +52,7 @@ export function createEmailInbox({ directory = process.env.DSCODE_EMAIL_DIR || j
52
52
  try {
53
53
  writeFileSync(temp, json, { flag: 'wx', mode: 0o600 });
54
54
  renameSync(temp, target);
55
- } finally { try { unlinkSync(temp); } catch (error) { if (error.code !== 'ENOENT') throw error; } }
55
+ } finally { try { unlinkSync(temp); } catch { /* best-effort cleanup: never mask the write's own outcome */ } }
56
56
  return mail;
57
57
  },
58
58
  list() {
@@ -6,7 +6,7 @@ import { tryLockExclusive } from '@deepseek-ai/node-addon-system/flock';
6
6
  export function emailStore(directory, label = 'email') {
7
7
  const read = name => {
8
8
  try { return JSON.parse(readFileSync(join(directory, name), 'utf8')); }
9
- catch (error) { if (error.code === 'ENOENT') return null; throw Error('Cannot read local ' + label + ' configuration.'); }
9
+ catch (error) { if (error.code === 'ENOENT') return null; throw Error('Cannot read local ' + label + ' configuration.', { cause: error }); }
10
10
  };
11
11
  return {
12
12
  directory, read,
@@ -17,7 +17,7 @@ export function emailStore(directory, label = 'email') {
17
17
  try {
18
18
  writeFileSync(temp, JSON.stringify(value), { flag: 'wx', mode: 0o600 });
19
19
  renameSync(temp, join(directory, name));
20
- } finally { try { unlinkSync(temp); } catch (error) { if (error.code !== 'ENOENT') throw error; } }
20
+ } finally { try { unlinkSync(temp); } catch { /* best-effort cleanup: never mask the write's own outcome */ } }
21
21
  },
22
22
  async locked(action) {
23
23
  mkdirSync(directory, { recursive: true, mode: 0o700 });
@@ -32390,7 +32390,7 @@ function Header({ cwd = "", model = "", effort = "", animated = false }) {
32390
32390
  if (!full) return (0, import_react.createElement)(Box, { flexDirection: "column", paddingX: 2, marginBottom: 1 },
32391
32391
  (0, import_react.createElement)(Text, { wrap: "truncate-end" },
32392
32392
  (0, import_react.createElement)(Text, { color: inkColor(getPalette().brandBright), bold: true }, "❄ DSCODE"),
32393
- (0, import_react.createElement)(Text, { color: inkColor(getPalette().dim) }, " v0.7.8")),
32393
+ (0, import_react.createElement)(Text, { color: inkColor(getPalette().dim) }, " v0.7.9")),
32394
32394
  (0, import_react.createElement)(Text, { wrap: "truncate-end" }, truncateColumns(modelName + " · " + effortName, width)),
32395
32395
  (0, import_react.createElement)(Text, { color: inkColor(getPalette().dim), wrap: "truncate-end" }, welcomePath(cwd, width)));
32396
32396
  return (0, import_react.createElement)(Box, { flexDirection: "column", width, borderStyle: "round", borderColor: inkColor(getPalette().brand), paddingX: 1 },
@@ -32401,7 +32401,7 @@ function Header({ cwd = "", model = "", effort = "", animated = false }) {
32401
32401
  (0, import_react.createElement)(Box, { flexDirection: "column", width: detailsWidth, marginTop: 2 },
32402
32402
  (0, import_react.createElement)(Text, { color: inkColor(getPalette().text), bold: true }, "DSCODE"),
32403
32403
  (0, import_react.createElement)(Text, { color: inkColor(getPalette().brandDeep) }, "────────────"),
32404
- (0, import_react.createElement)(Text, { color: inkColor(getPalette().dim) }, "v0.7.8"),
32404
+ (0, import_react.createElement)(Text, { color: inkColor(getPalette().dim) }, "v0.7.9"),
32405
32405
  (0, import_react.createElement)(Text, { wrap: "truncate-end" }, truncateColumns(dscodePadEnd(dscodeT("welcome.model"), 9) + modelName, detailsWidth)),
32406
32406
  (0, import_react.createElement)(Text, { wrap: "truncate-end" }, truncateColumns(dscodePadEnd(dscodeT("welcome.effort"), 9) + effortName, detailsWidth)),
32407
32407
  (0, import_react.createElement)(Text, null, " "),