deepcode-ai 1.1.27 → 1.1.29

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
@@ -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";
@@ -3516,6 +3516,9 @@ Caminho: ${selectedPath}`;
3516
3516
  if (error instanceof BudgetExceededError) {
3517
3517
  throw error;
3518
3518
  }
3519
+ if (options.signal?.aborted) {
3520
+ throw error;
3521
+ }
3519
3522
  session.metadata.planError = formatErrorChain(error);
3520
3523
  this.eventBus.emit("app:warn", {
3521
3524
  message: formatPlanningFailureWarning(error),
@@ -3552,7 +3555,7 @@ Caminho: ${selectedPath}`;
3552
3555
  const model = options.model ?? session.model ?? resolveConfiguredModelForProvider(this.config, providerId);
3553
3556
  if (!model) {
3554
3557
  throw new Error(
3555
- "No model configured. Set 'defaultModel'/'defaultModels' in .deepcode/config.json or DEEPCODE_MODEL environment variable."
3558
+ `No model configured for ${providerId}. Run /model or set defaultModels.${providerId} in .deepcode/config.json, or set DEEPCODE_MODEL.`
3556
3559
  );
3557
3560
  }
3558
3561
  const alreadyTrackingBudget = this.activeBudgets.has(session.id);
@@ -3919,6 +3922,7 @@ ${assistantText}` : assistantText;
3919
3922
  errorMessage: `Invalid arguments for ${call.name}: ${parsed.error.message}`
3920
3923
  };
3921
3924
  }
3925
+ const scopedSecurity = this.securityForSession(session);
3922
3926
  const context = {
3923
3927
  sessionId: session.id,
3924
3928
  messageId: createId("msg"),
@@ -3928,8 +3932,8 @@ ${assistantText}` : assistantText;
3928
3932
  config: this.config,
3929
3933
  agentMode: mode,
3930
3934
  cache: this.cache,
3931
- permissions: this.permissions,
3932
- pathSecurity: this.pathSecurity,
3935
+ permissions: scopedSecurity.permissions,
3936
+ pathSecurity: scopedSecurity.pathSecurity,
3933
3937
  logActivity: (activity) => {
3934
3938
  const full = { ...activity, id: createId("activity"), createdAt: nowIso() };
3935
3939
  session.activities.push(full);
@@ -3979,6 +3983,13 @@ ${assistantText}` : assistantText;
3979
3983
  };
3980
3984
  }
3981
3985
  }
3986
+ securityForSession(session) {
3987
+ const pathSecurity = this.pathSecurity.forWorktree(session.worktree);
3988
+ return {
3989
+ pathSecurity,
3990
+ permissions: this.permissions.forPathSecurity(pathSecurity)
3991
+ };
3992
+ }
3982
3993
  logToolActivity(session, activity) {
3983
3994
  const full = { ...activity, id: createId("activity"), createdAt: nowIso() };
3984
3995
  session.activities.push(full);
@@ -4234,8 +4245,9 @@ ${assistantText}` : assistantText;
4234
4245
  return "Git nao esta instalado. Quer que eu instale?";
4235
4246
  }
4236
4247
  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 });
4248
+ const security = this.securityForSession(session);
4249
+ const rootPath = await security.pathSecurity.normalize(scanInput, { enforceAccess: false });
4250
+ await security.permissions.ensure({ operation: "list_projects", kind: "read", path: rootPath });
4239
4251
  const results = [];
4240
4252
  await this.walkForProjects(rootPath, 3, results, /* @__PURE__ */ new Set());
4241
4253
  if (results.length === 0) {
@@ -6485,10 +6497,14 @@ function globToRegex(glob) {
6485
6497
  }
6486
6498
  return new RegExp(`^${globPatternToRegexSource(glob)}$`);
6487
6499
  }
6488
- var PathSecurity = class {
6500
+ var PathSecurity = class _PathSecurity {
6489
6501
  constructor(worktree, rules) {
6490
6502
  this.worktree = worktree;
6491
6503
  this.home = process.env.HOME ?? os2.homedir();
6504
+ this.sourceRules = {
6505
+ whitelist: [...rules.whitelist],
6506
+ blacklist: [...rules.blacklist]
6507
+ };
6492
6508
  this.rules = {
6493
6509
  whitelist: rules.whitelist.map((rule) => this.expand(rule, this.home)),
6494
6510
  blacklist: rules.blacklist.map((rule) => this.expand(rule, this.home))
@@ -6496,7 +6512,11 @@ var PathSecurity = class {
6496
6512
  }
6497
6513
  worktree;
6498
6514
  rules;
6515
+ sourceRules;
6499
6516
  home;
6517
+ forWorktree(worktree) {
6518
+ return new _PathSecurity(path7.resolve(worktree), this.sourceRules);
6519
+ }
6500
6520
  async normalize(inputPath, options = {}) {
6501
6521
  const enforceAccess = options.enforceAccess ?? true;
6502
6522
  const resolved = await this.resolvePath(inputPath);
@@ -6556,13 +6576,16 @@ var PathSecurity = class {
6556
6576
  return targetPath;
6557
6577
  }
6558
6578
  };
6559
- var PermissionGateway = class {
6560
- constructor(config, pathSecurity, audit, eventBus, interactive = false) {
6579
+ var PermissionGateway = class _PermissionGateway {
6580
+ constructor(config, pathSecurity, audit, eventBus, interactive = false, state) {
6561
6581
  this.config = config;
6562
6582
  this.pathSecurity = pathSecurity;
6563
6583
  this.audit = audit;
6564
6584
  this.eventBus = eventBus;
6565
6585
  this.interactive = interactive;
6586
+ this.sessionAllowSet = state?.sessionAllowSet ?? /* @__PURE__ */ new Set();
6587
+ this.alwaysAllowSet = state?.alwaysAllowSet ?? /* @__PURE__ */ new Set();
6588
+ this.pendingApprovals = state?.pendingApprovals ?? /* @__PURE__ */ new Map();
6566
6589
  }
6567
6590
  config;
6568
6591
  pathSecurity;
@@ -6570,11 +6593,25 @@ var PermissionGateway = class {
6570
6593
  eventBus;
6571
6594
  interactive;
6572
6595
  /** Set of operation+path keys that were approved for the current session */
6573
- sessionAllowSet = /* @__PURE__ */ new Set();
6596
+ sessionAllowSet;
6574
6597
  /** Set of operation+path keys that were approved permanently (always) */
6575
- alwaysAllowSet = /* @__PURE__ */ new Set();
6598
+ alwaysAllowSet;
6576
6599
  /** Map of pending approval requests by request ID */
6577
- pendingApprovals = /* @__PURE__ */ new Map();
6600
+ pendingApprovals;
6601
+ forPathSecurity(pathSecurity) {
6602
+ return new _PermissionGateway(
6603
+ this.config,
6604
+ pathSecurity,
6605
+ this.audit,
6606
+ this.eventBus,
6607
+ this.interactive,
6608
+ {
6609
+ sessionAllowSet: this.sessionAllowSet,
6610
+ alwaysAllowSet: this.alwaysAllowSet,
6611
+ pendingApprovals: this.pendingApprovals
6612
+ }
6613
+ );
6614
+ }
6578
6615
  /** Clear all session-scoped permissions (e.g., when session ends) */
6579
6616
  clearSessionAllowSet() {
6580
6617
  this.sessionAllowSet.clear();
@@ -7479,7 +7516,15 @@ function classifyShellCommand(command) {
7479
7516
  /\bdd\s+if=/,
7480
7517
  /\bsudo\b/,
7481
7518
  /\bcurl\b.*\|\s*(sh|bash)\b/,
7482
- /\bwget\b.*\|\s*(sh|bash)\b/
7519
+ /\bwget\b.*\|\s*(sh|bash)\b/,
7520
+ // Auto-install and execute remote packages without confirmation
7521
+ /\bnpx\s+(?:--yes|-y)\b/,
7522
+ // Background processes that outlive the agent turn
7523
+ /(?:^|;|\|)\s*[^&]*[^&]\s*&\s*$/,
7524
+ // HTTP/TCP servers that bind to all interfaces (exposes files to the network)
7525
+ /\bpython3?\s+-m\s+http\.server\b(?!.*--bind\s+(?:127\.|::1|localhost))/,
7526
+ /\bnc\s+.*-l\b/,
7527
+ /\bsocat\b.*(?:TCP-LISTEN|UDP-LISTEN)/
7483
7528
  ].some((pattern) => pattern.test(normalized2));
7484
7529
  return dangerous ? "dangerous" : "shell";
7485
7530
  }
@@ -28118,7 +28163,7 @@ function parseVersion2(version) {
28118
28163
  if (!match) return null;
28119
28164
  return [Number(match[1]), Number(match[2]), Number(match[3])];
28120
28165
  }
28121
- var VERSION = "1.1.27".length > 0 ? "1.1.27" : "0.0.0-dev";
28166
+ var VERSION = "1.1.29".length > 0 ? "1.1.29" : "0.0.0-dev";
28122
28167
  var updateCommand = {
28123
28168
  name: "update",
28124
28169
  description: "Check published DeepCode versions",
@@ -29697,6 +29742,7 @@ Follow-up suggestion:`;
29697
29742
  return null;
29698
29743
  }
29699
29744
  }
29745
+ var APPROVAL_ENTER_ARM_DELAY_MS = 350;
29700
29746
  var AppContainer = ({ cwd, config, provider, model, resumeSessionId }) => {
29701
29747
  const historyManager = useHistory();
29702
29748
  const addHistoryItem = historyManager.addItem;
@@ -29758,6 +29804,7 @@ var AppContainer = ({ cwd, config, provider, model, resumeSessionId }) => {
29758
29804
  const messageQueueRef = useRef17([]);
29759
29805
  const sessionShellAllowlistRef = useRef17(/* @__PURE__ */ new Set());
29760
29806
  const mainControlsRef = useRef17(null);
29807
+ const approvalPromptVisibleAtRef = useRef17(null);
29761
29808
  const { stdin, setRawMode } = useStdin3();
29762
29809
  const { columns: terminalWidth, rows: terminalHeight } = useTerminalSize();
29763
29810
  const mainAreaWidth = Math.min(Math.max(terminalWidth - 4, 20), 120);
@@ -29889,6 +29936,14 @@ var AppContainer = ({ cwd, config, provider, model, resumeSessionId }) => {
29889
29936
  }, []);
29890
29937
  const setSessionMode = useCallback26((mode) => {
29891
29938
  setAgentMode(mode);
29939
+ const runtime = runtimeRef.current;
29940
+ const session = sessionRef.current;
29941
+ if (runtime && session) {
29942
+ session.metadata = { ...session.metadata, agentMode: mode };
29943
+ runtime.sessions.save(session);
29944
+ runtime.sessions.persist(session.id).catch(() => {
29945
+ });
29946
+ }
29892
29947
  }, []);
29893
29948
  const setSessionName = useCallback26((name) => {
29894
29949
  const runtime = runtimeRef.current;
@@ -29985,12 +30040,14 @@ var AppContainer = ({ cwd, config, provider, model, resumeSessionId }) => {
29985
30040
  }, [messageQueue]);
29986
30041
  useEffect27(() => {
29987
30042
  if (approvalQueue.length > 0) {
30043
+ approvalPromptVisibleAtRef.current ??= Date.now();
29988
30044
  setStreamingState(
29989
30045
  "waiting_for_confirmation"
29990
30046
  /* WaitingForConfirmation */
29991
30047
  );
29992
30048
  return;
29993
30049
  }
30050
+ approvalPromptVisibleAtRef.current = null;
29994
30051
  if (isRunning) {
29995
30052
  setStreamingState(
29996
30053
  "responding"
@@ -30070,7 +30127,8 @@ var AppContainer = ({ cwd, config, provider, model, resumeSessionId }) => {
30070
30127
  dangerous: runtime.config.permissions.dangerous
30071
30128
  });
30072
30129
  setAuthSummary(formatAuthSummary(runtime.config.github));
30073
- setAgentMode(runtime.config.agentMode);
30130
+ const persistedMode = typeof session.metadata.agentMode === "string" && (session.metadata.agentMode === "build" || session.metadata.agentMode === "plan") ? session.metadata.agentMode : runtime.config.agentMode;
30131
+ setAgentMode(persistedMode);
30074
30132
  setTargetSource(provider || model ? "cli" : "config");
30075
30133
  setCurrentModel(session.model ?? "(unconfigured)");
30076
30134
  setProviderLabel(formatProviderLabel(session.provider, session.model));
@@ -30416,6 +30474,8 @@ var AppContainer = ({ cwd, config, provider, model, resumeSessionId }) => {
30416
30474
  let status = "Success";
30417
30475
  let resultDisplay = "(no output)";
30418
30476
  try {
30477
+ const pathSecurity = runtime.pathSecurity.forWorktree(session.worktree);
30478
+ const permissions = runtime.permissions.forPathSecurity(pathSecurity);
30419
30479
  const result = await runToolEffect(
30420
30480
  tool.execute(parsed.data, {
30421
30481
  sessionId: session.id,
@@ -30426,8 +30486,8 @@ var AppContainer = ({ cwd, config, provider, model, resumeSessionId }) => {
30426
30486
  config: runtime.config,
30427
30487
  agentMode,
30428
30488
  cache: runtime.cache,
30429
- permissions: runtime.permissions,
30430
- pathSecurity: runtime.pathSecurity,
30489
+ permissions,
30490
+ pathSecurity,
30431
30491
  logActivity: (activity) => {
30432
30492
  runtime.events.emit("activity", {
30433
30493
  id: createId("activity"),
@@ -30973,10 +31033,12 @@ var AppContainer = ({ cwd, config, provider, model, resumeSessionId }) => {
30973
31033
  }
30974
31034
  if (approvalQueue.length > 0) {
30975
31035
  const pressed = input.toLowerCase();
30976
- if (pressed === "y" || key.return) {
31036
+ const enterArmed = approvalPromptVisibleAtRef.current !== null && Date.now() - approvalPromptVisibleAtRef.current >= APPROVAL_ENTER_ARM_DELAY_MS;
31037
+ if (pressed === "y" || key.return && enterArmed) {
30977
31038
  resolveApproval({ allowed: true, scope: "once", reason: "Approved in TUI" });
30978
31039
  return;
30979
31040
  }
31041
+ if (key.return) return;
30980
31042
  if (pressed === "s") {
30981
31043
  resolveApproval({ allowed: true, scope: "session", reason: "Approved for session in TUI" });
30982
31044
  return;