deepcode-ai 1.1.26 → 1.1.28

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/index.js CHANGED
@@ -2281,8 +2281,8 @@ var PermissionDeniedError = class extends DeepCodeError {
2281
2281
  }
2282
2282
  };
2283
2283
  var PathNotAllowedError = class extends DeepCodeError {
2284
- constructor(path15, reason) {
2285
- super(`Path is not allowed: ${path15}. ${reason}`, "PATH_NOT_ALLOWED");
2284
+ constructor(path152, reason) {
2285
+ super(`Path is not allowed: ${path152}. ${reason}`, "PATH_NOT_ALLOWED");
2286
2286
  this.name = "PathNotAllowedError";
2287
2287
  }
2288
2288
  };
@@ -3489,7 +3489,7 @@ Caminho: ${selectedPath}`;
3489
3489
  const effectiveModel = resolvedModel;
3490
3490
  if (!effectiveModel) {
3491
3491
  throw new Error(
3492
- "No model configured. Set 'defaultModel'/'defaultModels' in .deepcode/config.json or DEEPCODE_MODEL environment variable."
3492
+ `No model configured for ${resolvedTarget.provider}. Run /model or set defaultModels.${resolvedTarget.provider} in .deepcode/config.json, or set DEEPCODE_MODEL.`
3493
3493
  );
3494
3494
  }
3495
3495
  session.status = "planning";
@@ -3552,7 +3552,7 @@ Caminho: ${selectedPath}`;
3552
3552
  const model = options.model ?? session.model ?? resolveConfiguredModelForProvider(this.config, providerId);
3553
3553
  if (!model) {
3554
3554
  throw new Error(
3555
- "No model configured. Set 'defaultModel'/'defaultModels' in .deepcode/config.json or DEEPCODE_MODEL environment variable."
3555
+ `No model configured for ${providerId}. Run /model or set defaultModels.${providerId} in .deepcode/config.json, or set DEEPCODE_MODEL.`
3556
3556
  );
3557
3557
  }
3558
3558
  const alreadyTrackingBudget = this.activeBudgets.has(session.id);
@@ -3919,6 +3919,7 @@ ${assistantText}` : assistantText;
3919
3919
  errorMessage: `Invalid arguments for ${call.name}: ${parsed.error.message}`
3920
3920
  };
3921
3921
  }
3922
+ const scopedSecurity = this.securityForSession(session);
3922
3923
  const context = {
3923
3924
  sessionId: session.id,
3924
3925
  messageId: createId("msg"),
@@ -3928,8 +3929,8 @@ ${assistantText}` : assistantText;
3928
3929
  config: this.config,
3929
3930
  agentMode: mode,
3930
3931
  cache: this.cache,
3931
- permissions: this.permissions,
3932
- pathSecurity: this.pathSecurity,
3932
+ permissions: scopedSecurity.permissions,
3933
+ pathSecurity: scopedSecurity.pathSecurity,
3933
3934
  logActivity: (activity) => {
3934
3935
  const full = { ...activity, id: createId("activity"), createdAt: nowIso() };
3935
3936
  session.activities.push(full);
@@ -3979,6 +3980,13 @@ ${assistantText}` : assistantText;
3979
3980
  };
3980
3981
  }
3981
3982
  }
3983
+ securityForSession(session) {
3984
+ const pathSecurity = this.pathSecurity.forWorktree(session.worktree);
3985
+ return {
3986
+ pathSecurity,
3987
+ permissions: this.permissions.forPathSecurity(pathSecurity)
3988
+ };
3989
+ }
3982
3990
  logToolActivity(session, activity) {
3983
3991
  const full = { ...activity, id: createId("activity"), createdAt: nowIso() };
3984
3992
  session.activities.push(full);
@@ -4234,8 +4242,9 @@ ${assistantText}` : assistantText;
4234
4242
  return "Git nao esta instalado. Quer que eu instale?";
4235
4243
  }
4236
4244
  const scanInput = inputPath === "." ? process.env.HOME ?? inputPath : inputPath;
4237
- const rootPath = await this.pathSecurity.normalize(scanInput, { enforceAccess: false });
4238
- await this.permissions.ensure({ operation: "list_projects", kind: "read", path: rootPath });
4245
+ const security = this.securityForSession(session);
4246
+ const rootPath = await security.pathSecurity.normalize(scanInput, { enforceAccess: false });
4247
+ await security.permissions.ensure({ operation: "list_projects", kind: "read", path: rootPath });
4239
4248
  const results = [];
4240
4249
  await this.walkForProjects(rootPath, 3, results, /* @__PURE__ */ new Set());
4241
4250
  if (results.length === 0) {
@@ -5043,13 +5052,13 @@ var GitHubClient = class {
5043
5052
  }
5044
5053
  return parseGitHubRemote(result.stdout.trim());
5045
5054
  }
5046
- async request(path15, init = {}) {
5055
+ async request(path152, init = {}) {
5047
5056
  if (!this.options.token) {
5048
5057
  throw new Error(
5049
5058
  "GitHub token is required. Set GITHUB_TOKEN or .deepcode/config.json github.token."
5050
5059
  );
5051
5060
  }
5052
- const response = await fetch(`${this.apiBase}${path15}`, {
5061
+ const response = await fetch(`${this.apiBase}${path152}`, {
5053
5062
  ...init,
5054
5063
  headers: {
5055
5064
  accept: "application/vnd.github+json",
@@ -5065,13 +5074,13 @@ var GitHubClient = class {
5065
5074
  if (response.status === 204) return void 0;
5066
5075
  return await response.json();
5067
5076
  }
5068
- async requestText(path15, init = {}) {
5077
+ async requestText(path152, init = {}) {
5069
5078
  if (!this.options.token) {
5070
5079
  throw new Error(
5071
5080
  "GitHub token is required. Set GITHUB_TOKEN or .deepcode/config.json github.token."
5072
5081
  );
5073
5082
  }
5074
- const response = await fetch(`${this.apiBase}${path15}`, {
5083
+ const response = await fetch(`${this.apiBase}${path152}`, {
5075
5084
  ...init,
5076
5085
  headers: {
5077
5086
  accept: "application/vnd.github+json",
@@ -5539,12 +5548,12 @@ function fromFileUri(uri) {
5539
5548
  var SECRET_KEY_PATTERN = /(api[_-]?key|token|authorization|secret|password|passwd|credential|private[_-]?key)/i;
5540
5549
  var MIN_SECRET_VALUE_LENGTH = 4;
5541
5550
  function redactSecrets(value, options = {}) {
5542
- const path15 = options.path ?? [];
5551
+ const path152 = options.path ?? [];
5543
5552
  const secretPlaceholder = options.secretPlaceholder ?? "[redacted]";
5544
5553
  const emptySecretPlaceholder = options.emptySecretPlaceholder ?? "[empty]";
5545
5554
  const secretValues = options.secretValues ?? collectSecretValues();
5546
5555
  if (typeof value === "string") {
5547
- if (isSecretPath(path15)) {
5556
+ if (isSecretPath(path152)) {
5548
5557
  return value.length > 0 ? secretPlaceholder : emptySecretPlaceholder;
5549
5558
  }
5550
5559
  return redactText(value, secretValues, secretPlaceholder);
@@ -5553,7 +5562,7 @@ function redactSecrets(value, options = {}) {
5553
5562
  return value.map(
5554
5563
  (item, index) => redactSecrets(item, {
5555
5564
  ...options,
5556
- path: [...path15, String(index)],
5565
+ path: [...path152, String(index)],
5557
5566
  secretValues
5558
5567
  })
5559
5568
  );
@@ -5564,7 +5573,7 @@ function redactSecrets(value, options = {}) {
5564
5573
  key,
5565
5574
  redactSecrets(item, {
5566
5575
  ...options,
5567
- path: [...path15, key],
5576
+ path: [...path152, key],
5568
5577
  secretValues
5569
5578
  })
5570
5579
  ])
@@ -5602,8 +5611,8 @@ function collectSecretValues(config) {
5602
5611
  }
5603
5612
  return [...values].sort((left, right) => right.length - left.length);
5604
5613
  }
5605
- function isSecretPath(path15) {
5606
- const key = path15[path15.length - 1] ?? "";
5614
+ function isSecretPath(path152) {
5615
+ const key = path152[path152.length - 1] ?? "";
5607
5616
  if (/(api[_-]?key|token|secret|credential).*file/i.test(key)) return false;
5608
5617
  return SECRET_KEY_PATTERN.test(key);
5609
5618
  }
@@ -6485,10 +6494,14 @@ function globToRegex(glob) {
6485
6494
  }
6486
6495
  return new RegExp(`^${globPatternToRegexSource(glob)}$`);
6487
6496
  }
6488
- var PathSecurity = class {
6497
+ var PathSecurity = class _PathSecurity {
6489
6498
  constructor(worktree, rules) {
6490
6499
  this.worktree = worktree;
6491
6500
  this.home = process.env.HOME ?? os2.homedir();
6501
+ this.sourceRules = {
6502
+ whitelist: [...rules.whitelist],
6503
+ blacklist: [...rules.blacklist]
6504
+ };
6492
6505
  this.rules = {
6493
6506
  whitelist: rules.whitelist.map((rule) => this.expand(rule, this.home)),
6494
6507
  blacklist: rules.blacklist.map((rule) => this.expand(rule, this.home))
@@ -6496,7 +6509,11 @@ var PathSecurity = class {
6496
6509
  }
6497
6510
  worktree;
6498
6511
  rules;
6512
+ sourceRules;
6499
6513
  home;
6514
+ forWorktree(worktree) {
6515
+ return new _PathSecurity(path7.resolve(worktree), this.sourceRules);
6516
+ }
6500
6517
  async normalize(inputPath, options = {}) {
6501
6518
  const enforceAccess = options.enforceAccess ?? true;
6502
6519
  const resolved = await this.resolvePath(inputPath);
@@ -6556,13 +6573,16 @@ var PathSecurity = class {
6556
6573
  return targetPath;
6557
6574
  }
6558
6575
  };
6559
- var PermissionGateway = class {
6560
- constructor(config, pathSecurity, audit, eventBus, interactive = false) {
6576
+ var PermissionGateway = class _PermissionGateway {
6577
+ constructor(config, pathSecurity, audit, eventBus, interactive = false, state) {
6561
6578
  this.config = config;
6562
6579
  this.pathSecurity = pathSecurity;
6563
6580
  this.audit = audit;
6564
6581
  this.eventBus = eventBus;
6565
6582
  this.interactive = interactive;
6583
+ this.sessionAllowSet = state?.sessionAllowSet ?? /* @__PURE__ */ new Set();
6584
+ this.alwaysAllowSet = state?.alwaysAllowSet ?? /* @__PURE__ */ new Set();
6585
+ this.pendingApprovals = state?.pendingApprovals ?? /* @__PURE__ */ new Map();
6566
6586
  }
6567
6587
  config;
6568
6588
  pathSecurity;
@@ -6570,11 +6590,25 @@ var PermissionGateway = class {
6570
6590
  eventBus;
6571
6591
  interactive;
6572
6592
  /** Set of operation+path keys that were approved for the current session */
6573
- sessionAllowSet = /* @__PURE__ */ new Set();
6593
+ sessionAllowSet;
6574
6594
  /** Set of operation+path keys that were approved permanently (always) */
6575
- alwaysAllowSet = /* @__PURE__ */ new Set();
6595
+ alwaysAllowSet;
6576
6596
  /** Map of pending approval requests by request ID */
6577
- pendingApprovals = /* @__PURE__ */ new Map();
6597
+ pendingApprovals;
6598
+ forPathSecurity(pathSecurity) {
6599
+ return new _PermissionGateway(
6600
+ this.config,
6601
+ pathSecurity,
6602
+ this.audit,
6603
+ this.eventBus,
6604
+ this.interactive,
6605
+ {
6606
+ sessionAllowSet: this.sessionAllowSet,
6607
+ alwaysAllowSet: this.alwaysAllowSet,
6608
+ pendingApprovals: this.pendingApprovals
6609
+ }
6610
+ );
6611
+ }
6578
6612
  /** Clear all session-scoped permissions (e.g., when session ends) */
6579
6613
  clearSessionAllowSet() {
6580
6614
  this.sessionAllowSet.clear();
@@ -7824,8 +7858,8 @@ import { useState as useState22, useEffect as useEffect22, useCallback as useCal
7824
7858
  import { Box as Box2, Text as Text22, useInput as useInput2, useApp as useApp2 } from "ink";
7825
7859
  import path42 from "path";
7826
7860
  import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
7827
- import fs7 from "fs";
7828
- import path142 from "path";
7861
+ import fs8 from "fs";
7862
+ import path15 from "path";
7829
7863
  import { isValidElement, useCallback as useCallback26, useEffect as useEffect27, useMemo as useMemo18, useRef as useRef17, useState as useState29 } from "react";
7830
7864
  import { Box as Box42, Text as Text50, useInput as useInput6, useStdin as useStdin3 } from "ink";
7831
7865
  import os4 from "os";
@@ -9810,6 +9844,9 @@ import { jsx as jsx39, jsxs as jsxs35 } from "react/jsx-runtime";
9810
9844
  import { Box as Box31, Text as Text39 } from "ink";
9811
9845
  import { jsx as jsx40, jsxs as jsxs36 } from "react/jsx-runtime";
9812
9846
  import { jsx as jsx41, jsxs as jsxs37 } from "react/jsx-runtime";
9847
+ import fs6 from "fs";
9848
+ import os5 from "os";
9849
+ import path132 from "path";
9813
9850
  import { Box as Box33, Text as Text41 } from "ink";
9814
9851
  import { jsx as jsx42, jsxs as jsxs38 } from "react/jsx-runtime";
9815
9852
  import { useCallback as useCallback19, useMemo as useMemo11, useRef as useRef14 } from "react";
@@ -9827,8 +9864,8 @@ import { jsx as jsx46, jsxs as jsxs42 } from "react/jsx-runtime";
9827
9864
  import { useCallback as useCallback23, useEffect as useEffect25, useMemo as useMemo15, useRef as useRef16, useState as useState27 } from "react";
9828
9865
  import { Box as Box38, Text as Text46, useInput as useInput4 } from "ink";
9829
9866
  import { jsx as jsx47, jsxs as jsxs43 } from "react/jsx-runtime";
9830
- import fs6 from "fs";
9831
- import path132 from "path";
9867
+ import fs7 from "fs";
9868
+ import path142 from "path";
9832
9869
  import { useCallback as useCallback24, useMemo as useMemo16 } from "react";
9833
9870
  import { Box as Box39, Text as Text47 } from "ink";
9834
9871
  import { jsx as jsx48, jsxs as jsxs44 } from "react/jsx-runtime";
@@ -28039,6 +28076,109 @@ var compactCommand = {
28039
28076
  await context.ui.compact();
28040
28077
  }
28041
28078
  };
28079
+ var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
28080
+ var PACKAGE_NAME = "deepcode-ai";
28081
+ function cachePath() {
28082
+ const cacheHome = process.env["XDG_CACHE_HOME"] ?? path132.join(os5.homedir(), ".cache");
28083
+ return path132.join(cacheHome, "deepcode-ai", "update.json");
28084
+ }
28085
+ function readCache() {
28086
+ try {
28087
+ const raw = fs6.readFileSync(cachePath(), "utf8");
28088
+ const parsed = JSON.parse(raw);
28089
+ if (typeof parsed.checkedAt !== "number" || typeof parsed.latest !== "string" || Date.now() - parsed.checkedAt >= CACHE_TTL_MS) {
28090
+ return null;
28091
+ }
28092
+ return {
28093
+ checkedAt: parsed.checkedAt,
28094
+ latest: parsed.latest,
28095
+ stable: typeof parsed.stable === "string" ? parsed.stable : null
28096
+ };
28097
+ } catch {
28098
+ return null;
28099
+ }
28100
+ }
28101
+ function writeCache(cache) {
28102
+ try {
28103
+ const filePath = cachePath();
28104
+ fs6.mkdirSync(path132.dirname(filePath), { recursive: true });
28105
+ fs6.writeFileSync(filePath, `${JSON.stringify(cache)}
28106
+ `, "utf8");
28107
+ } catch {
28108
+ }
28109
+ }
28110
+ async function checkForUpdate(_currentVersion, options = {}) {
28111
+ if (process.env["CI"] || process.env["NODE_ENV"] === "test" || process.env["DEEPCODE_DISABLE_UPDATE_CHECK"] === "1") {
28112
+ return null;
28113
+ }
28114
+ if (!options.force) {
28115
+ const cached = readCache();
28116
+ if (cached) {
28117
+ return { latest: cached.latest, stable: cached.stable };
28118
+ }
28119
+ }
28120
+ try {
28121
+ const response = await fetch(
28122
+ `https://registry.npmjs.org/-/package/${PACKAGE_NAME}/dist-tags`,
28123
+ { signal: AbortSignal.timeout(3e3) }
28124
+ );
28125
+ if (!response.ok) return null;
28126
+ const tags = await response.json();
28127
+ const latest = tags["latest"];
28128
+ if (typeof latest !== "string" || latest.length === 0) return null;
28129
+ const stable = typeof tags["stable"] === "string" && tags["stable"].length > 0 ? tags["stable"] : null;
28130
+ const update = { latest, stable };
28131
+ writeCache({ ...update, checkedAt: Date.now() });
28132
+ return update;
28133
+ } catch {
28134
+ return null;
28135
+ }
28136
+ }
28137
+ function isNewer(current, candidate) {
28138
+ const currentParts = parseVersion2(current);
28139
+ const candidateParts = parseVersion2(candidate);
28140
+ if (!currentParts || !candidateParts) return false;
28141
+ for (let index = 0; index < 3; index += 1) {
28142
+ const currentPart = currentParts[index] ?? 0;
28143
+ const candidatePart = candidateParts[index] ?? 0;
28144
+ if (candidatePart !== currentPart) {
28145
+ return candidatePart > currentPart;
28146
+ }
28147
+ }
28148
+ return false;
28149
+ }
28150
+ function parseVersion2(version) {
28151
+ const match = version.trim().match(/^v?(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/);
28152
+ if (!match) return null;
28153
+ return [Number(match[1]), Number(match[2]), Number(match[3])];
28154
+ }
28155
+ var VERSION = "1.1.28".length > 0 ? "1.1.28" : "0.0.0-dev";
28156
+ var updateCommand = {
28157
+ name: "update",
28158
+ description: "Check published DeepCode versions",
28159
+ kind: "built-in",
28160
+ supportedModes: ["interactive"],
28161
+ action: async () => {
28162
+ const update = await checkForUpdate(VERSION, { force: true });
28163
+ const lines = [`Current version: ${VERSION}`];
28164
+ if (!update) {
28165
+ lines.push("Could not reach the npm registry right now.");
28166
+ } else {
28167
+ const latestStatus = isNewer(VERSION, update.latest) ? "available" : "current or older";
28168
+ lines.push(`Latest version: ${update.latest} (${latestStatus})`);
28169
+ if (update.stable) {
28170
+ const stableStatus = isNewer(VERSION, update.stable) ? "available" : "current or older";
28171
+ lines.push(`Stable version: ${update.stable} (${stableStatus})`);
28172
+ } else {
28173
+ lines.push("Stable version: not published yet");
28174
+ }
28175
+ }
28176
+ lines.push("");
28177
+ lines.push("Install latest: npm install -g deepcode-ai@latest");
28178
+ lines.push("Install stable: npm install -g deepcode-ai@stable");
28179
+ return { type: "message", messageType: "info", content: lines.join("\n") };
28180
+ }
28181
+ };
28042
28182
  function sessionNotReady() {
28043
28183
  return {
28044
28184
  type: "message",
@@ -29093,11 +29233,11 @@ var RATINGS = [
29093
29233
  ];
29094
29234
  var CANCEL_VALUE2 = "__cancel__";
29095
29235
  function appendFeedbackEntry(cwd, rating, label) {
29096
- const file = path132.join(cwd, ".deepcode", "feedback.log");
29236
+ const file = path142.join(cwd, ".deepcode", "feedback.log");
29097
29237
  const entry = JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), rating, label });
29098
29238
  try {
29099
- fs6.mkdirSync(path132.dirname(file), { recursive: true });
29100
- fs6.appendFileSync(file, `${entry}
29239
+ fs7.mkdirSync(path142.dirname(file), { recursive: true });
29240
+ fs7.appendFileSync(file, `${entry}
29101
29241
  `, "utf8");
29102
29242
  } catch {
29103
29243
  }
@@ -29591,6 +29731,7 @@ Follow-up suggestion:`;
29591
29731
  return null;
29592
29732
  }
29593
29733
  }
29734
+ var APPROVAL_ENTER_ARM_DELAY_MS = 350;
29594
29735
  var AppContainer = ({ cwd, config, provider, model, resumeSessionId }) => {
29595
29736
  const historyManager = useHistory();
29596
29737
  const addHistoryItem = historyManager.addItem;
@@ -29652,6 +29793,7 @@ var AppContainer = ({ cwd, config, provider, model, resumeSessionId }) => {
29652
29793
  const messageQueueRef = useRef17([]);
29653
29794
  const sessionShellAllowlistRef = useRef17(/* @__PURE__ */ new Set());
29654
29795
  const mainControlsRef = useRef17(null);
29796
+ const approvalPromptVisibleAtRef = useRef17(null);
29655
29797
  const { stdin, setRawMode } = useStdin3();
29656
29798
  const { columns: terminalWidth, rows: terminalHeight } = useTerminalSize();
29657
29799
  const mainAreaWidth = Math.min(Math.max(terminalWidth - 4, 20), 120);
@@ -29674,12 +29816,12 @@ var AppContainer = ({ cwd, config, provider, model, resumeSessionId }) => {
29674
29816
  const configAdapter = configAdapterRef.current ?? new DeepCodeConfigAdapter(cwd);
29675
29817
  const isValidPath = useCallback26(
29676
29818
  (candidate) => {
29677
- const resolved = path142.resolve(cwd, candidate);
29678
- const relative2 = path142.relative(cwd, resolved);
29679
- if (relative2.startsWith("..") || path142.isAbsolute(relative2)) {
29819
+ const resolved = path15.resolve(cwd, candidate);
29820
+ const relative2 = path15.relative(cwd, resolved);
29821
+ if (relative2.startsWith("..") || path15.isAbsolute(relative2)) {
29680
29822
  return false;
29681
29823
  }
29682
- return fs7.existsSync(resolved);
29824
+ return fs8.existsSync(resolved);
29683
29825
  },
29684
29826
  [cwd]
29685
29827
  );
@@ -29709,6 +29851,7 @@ var AppContainer = ({ cwd, config, provider, model, resumeSessionId }) => {
29709
29851
  modelCommand,
29710
29852
  modeCommand,
29711
29853
  renameCommand,
29854
+ updateCommand,
29712
29855
  settingsDialogCommand,
29713
29856
  themeDialogCommand,
29714
29857
  permissionsDialogCommand,
@@ -29878,12 +30021,14 @@ var AppContainer = ({ cwd, config, provider, model, resumeSessionId }) => {
29878
30021
  }, [messageQueue]);
29879
30022
  useEffect27(() => {
29880
30023
  if (approvalQueue.length > 0) {
30024
+ approvalPromptVisibleAtRef.current ??= Date.now();
29881
30025
  setStreamingState(
29882
30026
  "waiting_for_confirmation"
29883
30027
  /* WaitingForConfirmation */
29884
30028
  );
29885
30029
  return;
29886
30030
  }
30031
+ approvalPromptVisibleAtRef.current = null;
29887
30032
  if (isRunning) {
29888
30033
  setStreamingState(
29889
30034
  "responding"
@@ -30091,6 +30236,25 @@ var AppContainer = ({ cwd, config, provider, model, resumeSessionId }) => {
30091
30236
  );
30092
30237
  }
30093
30238
  setIsInitializing(false);
30239
+ checkForUpdate(VERSION).then((update) => {
30240
+ if (!mounted || !update) return;
30241
+ const available = [];
30242
+ if (isNewer(VERSION, update.latest)) {
30243
+ available.push(`latest v${update.latest}`);
30244
+ }
30245
+ if (update.stable && isNewer(VERSION, update.stable)) {
30246
+ available.push(`stable v${update.stable}`);
30247
+ }
30248
+ if (available.length === 0) return;
30249
+ addHistoryItem(
30250
+ {
30251
+ type: "info",
30252
+ text: `Update available: ${available.join(", ")}. Run /update for install commands.`
30253
+ },
30254
+ Date.now()
30255
+ );
30256
+ }).catch(() => {
30257
+ });
30094
30258
  } catch (error) {
30095
30259
  if (!mounted) return;
30096
30260
  const message = error instanceof Error ? error.message : String(error);
@@ -30290,6 +30454,8 @@ var AppContainer = ({ cwd, config, provider, model, resumeSessionId }) => {
30290
30454
  let status = "Success";
30291
30455
  let resultDisplay = "(no output)";
30292
30456
  try {
30457
+ const pathSecurity = runtime.pathSecurity.forWorktree(session.worktree);
30458
+ const permissions = runtime.permissions.forPathSecurity(pathSecurity);
30293
30459
  const result = await runToolEffect(
30294
30460
  tool.execute(parsed.data, {
30295
30461
  sessionId: session.id,
@@ -30300,8 +30466,8 @@ var AppContainer = ({ cwd, config, provider, model, resumeSessionId }) => {
30300
30466
  config: runtime.config,
30301
30467
  agentMode,
30302
30468
  cache: runtime.cache,
30303
- permissions: runtime.permissions,
30304
- pathSecurity: runtime.pathSecurity,
30469
+ permissions,
30470
+ pathSecurity,
30305
30471
  logActivity: (activity) => {
30306
30472
  runtime.events.emit("activity", {
30307
30473
  id: createId("activity"),
@@ -30847,10 +31013,12 @@ var AppContainer = ({ cwd, config, provider, model, resumeSessionId }) => {
30847
31013
  }
30848
31014
  if (approvalQueue.length > 0) {
30849
31015
  const pressed = input.toLowerCase();
30850
- if (pressed === "y" || key.return) {
31016
+ const enterArmed = approvalPromptVisibleAtRef.current !== null && Date.now() - approvalPromptVisibleAtRef.current >= APPROVAL_ENTER_ARM_DELAY_MS;
31017
+ if (pressed === "y" || key.return && enterArmed) {
30851
31018
  resolveApproval({ allowed: true, scope: "once", reason: "Approved in TUI" });
30852
31019
  return;
30853
31020
  }
31021
+ if (key.return) return;
30854
31022
  if (pressed === "s") {
30855
31023
  resolveApproval({ allowed: true, scope: "session", reason: "Approved for session in TUI" });
30856
31024
  return;
@@ -30963,7 +31131,7 @@ var AppContainer = ({ cwd, config, provider, model, resumeSessionId }) => {
30963
31131
  mainControlsRef,
30964
31132
  constrainHeight: false,
30965
31133
  currentModel,
30966
- sessionName: path142.basename(cwd),
31134
+ sessionName: path15.basename(cwd),
30967
31135
  isConfigInitialized: !isInitializing && !initError,
30968
31136
  sessionStats: {
30969
31137
  lastPromptTokenCount,
@@ -31202,11 +31370,11 @@ function isInteractiveDialog(dialog) {
31202
31370
  return dialog === "theme" || dialog === "permissions" || dialog === "auth" || dialog === "provider" || dialog === "model" || dialog === "feedback" || dialog === "sessions";
31203
31371
  }
31204
31372
  function tuiThemeFilePath(cwd) {
31205
- return path142.join(cwd, ".deepcode", "tui-theme.json");
31373
+ return path15.join(cwd, ".deepcode", "tui-theme.json");
31206
31374
  }
31207
31375
  function readSavedTheme(cwd) {
31208
31376
  try {
31209
- const parsed = JSON.parse(fs7.readFileSync(tuiThemeFilePath(cwd), "utf8"));
31377
+ const parsed = JSON.parse(fs8.readFileSync(tuiThemeFilePath(cwd), "utf8"));
31210
31378
  return typeof parsed.theme === "string" ? parsed.theme : null;
31211
31379
  } catch {
31212
31380
  return null;
@@ -31214,8 +31382,8 @@ function readSavedTheme(cwd) {
31214
31382
  }
31215
31383
  function writeSavedTheme(cwd, themeName) {
31216
31384
  const file = tuiThemeFilePath(cwd);
31217
- fs7.mkdirSync(path142.dirname(file), { recursive: true });
31218
- fs7.writeFileSync(file, `${JSON.stringify({ theme: themeName }, null, 2)}
31385
+ fs8.mkdirSync(path15.dirname(file), { recursive: true });
31386
+ fs8.writeFileSync(file, `${JSON.stringify({ theme: themeName }, null, 2)}
31219
31387
  `);
31220
31388
  }
31221
31389
  function errorMessage(error) {
@@ -31354,7 +31522,7 @@ function createProgram() {
31354
31522
  writeOut: writeStdoutSync,
31355
31523
  writeErr: writeStderrSync
31356
31524
  });
31357
- program.name("deepcode").description("AI coding agent for the terminal").version("1.0.0").option("-C, --cwd <path>", "working directory", process.cwd()).option("--config <path>", "config file path");
31525
+ program.name("deepcode").description("AI coding agent for the terminal").version(VERSION).option("-C, --cwd <path>", "working directory", process.cwd()).option("--config <path>", "config file path");
31358
31526
  program.command("init").description("create .deepcode/config.json").action(async () => {
31359
31527
  await initCommand(program.opts().cwd);
31360
31528
  });