@protolabsai/proto 0.25.8 → 0.25.10

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 (3) hide show
  1. package/README.md +24 -6
  2. package/cli.js +108 -14
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -159,6 +159,14 @@ Tools are exposed as `mcp__<server_name>__<tool_name>` and available to the agen
159
159
 
160
160
  proto auto-discovers Claude Code plugins installed at `~/.claude/plugins/`. Any plugin's `commands/` directory is automatically loaded as slash commands — no additional config needed.
161
161
 
162
+ ### Environment variable overrides
163
+
164
+ | Variable | Default | Description |
165
+ | ------------------------------- | ------- | ----------------------------------------------------------------------------------------------- |
166
+ | `PROTO_STREAM_STALL_TIMEOUT_MS` | `90000` | Max ms to wait between streaming chunks before declaring the connection stalled (then retrying) |
167
+ | `PROTO_SYSTEM_DEFAULTS_PATH` | — | Override path to the system defaults settings file |
168
+ | `PROTO_SYSTEM_SETTINGS_PATH` | — | Override path to the system settings override file |
169
+
162
170
  ## Observability
163
171
 
164
172
  proto supports [Langfuse](https://langfuse.com) tracing out of the box. Set three environment variables and every session is fully traced — LLM calls (all providers), tool executions, subagent lifecycles, and turn hierarchy.
@@ -331,15 +339,20 @@ Results are cached at `.proto/repo-map-cache.json` and auto-invalidate on file c
331
339
 
332
340
  proto ships with 22 bundled skills for agentic workflows:
333
341
 
334
- - **browser-automation** — Web browser automation
342
+ - **adversarial-verification** — Adversarial review and stress-testing of agent output
335
343
  - **brainstorming** — Structured ideation
344
+ - **browser-automation** — Web browser automation
345
+ - **coding-agent-standards** — Enforced coding conventions for agent-written code
336
346
  - **dispatching-parallel-agents** — Fan-out/fan-in subagent patterns
337
347
  - **executing-plans** — Step-by-step plan execution
338
348
  - **finishing-a-development-branch** — Pre-merge cleanup
349
+ - **harness-reference** — Sprint contracts, verification gates, and retry logic reference
350
+ - **loop** — Iterative refinement loops
339
351
  - **qc-helper** — Quality control checks
340
352
  - **receiving-code-review** — Process review feedback
341
353
  - **requesting-code-review** — Generate review requests
342
354
  - **review** — Code review workflow
355
+ - **sprint-contract** — Scope lock and contract negotiation
343
356
  - **subagent-driven-development** — Delegate to specialized subagents
344
357
  - **systematic-debugging** — Structured debug methodology
345
358
  - **test-driven-development** — TDD workflow
@@ -457,11 +470,16 @@ Any user-defined sub-agent from `.proto/agents/` can also be used as a member ty
457
470
 
458
471
  ## Keyboard Shortcuts
459
472
 
460
- | Shortcut | Action |
461
- | --------- | ------------------------ |
462
- | `Ctrl+C` | Cancel current operation |
463
- | `Ctrl+D` | Exit (on empty line) |
464
- | `Up/Down` | Navigate command history |
473
+ | Shortcut | Action |
474
+ | ----------- | --------------------------------------------------------------- |
475
+ | `Ctrl+C` | Cancel ongoing request. Press twice to exit. |
476
+ | `Ctrl+D` | Exit if input is empty. |
477
+ | `Ctrl+L` | Clear the screen |
478
+ | `Ctrl+Y` | Retry the last failed request |
479
+ | `Shift+Tab` | Cycle approval modes: `plan` → `default` → `auto-edit` → `yolo` |
480
+ | `Up/Down` | Navigate command history |
481
+
482
+ See [Keyboard Shortcuts reference](docs/reference/keyboard-shortcuts.md) for the full list.
465
483
 
466
484
  ## Voice Integration
467
485
 
package/cli.js CHANGED
@@ -170887,7 +170887,7 @@ __export(geminiContentGenerator_exports, {
170887
170887
  createGeminiContentGenerator: () => createGeminiContentGenerator
170888
170888
  });
170889
170889
  function createGeminiContentGenerator(config2, gcConfig) {
170890
- const version2 = "0.25.8";
170890
+ const version2 = "0.25.10";
170891
170891
  const userAgent2 = config2.userAgent || `QwenCode/${version2} (${process.platform}; ${process.arch})`;
170892
170892
  const baseHeaders = {
170893
170893
  "User-Agent": userAgent2
@@ -414864,7 +414864,7 @@ __name(getPackageJson, "getPackageJson");
414864
414864
  // packages/cli/src/utils/version.ts
414865
414865
  async function getCliVersion() {
414866
414866
  const pkgJson = await getPackageJson();
414867
- return "0.25.8";
414867
+ return "0.25.10";
414868
414868
  }
414869
414869
  __name(getCliVersion, "getCliVersion");
414870
414870
 
@@ -422636,7 +422636,7 @@ var formatDuration = /* @__PURE__ */ __name((milliseconds) => {
422636
422636
 
422637
422637
  // packages/cli/src/generated/git-commit.ts
422638
422638
  init_esbuild_shims();
422639
- var GIT_COMMIT_INFO = "7fcd8c75a";
422639
+ var GIT_COMMIT_INFO = "08c8a70da";
422640
422640
 
422641
422641
  // packages/cli/src/utils/systemInfo.ts
422642
422642
  async function getNpmVersion() {
@@ -453851,6 +453851,7 @@ var Command = /* @__PURE__ */ ((Command2) => {
453851
453851
  Command2["EXIT"] = "exit";
453852
453852
  Command2["SHOW_MORE_LINES"] = "showMoreLines";
453853
453853
  Command2["RETRY_LAST"] = "retryLast";
453854
+ Command2["BACKGROUND_SESSION"] = "backgroundSession";
453854
453855
  Command2["REVERSE_SEARCH"] = "reverseSearch";
453855
453856
  Command2["SUBMIT_REVERSE_SEARCH"] = "submitReverseSearch";
453856
453857
  Command2["ACCEPT_SUGGESTION_REVERSE_SEARCH"] = "acceptSuggestionReverseSearch";
@@ -453927,6 +453928,7 @@ var defaultKeyBindings = {
453927
453928
  ["exit" /* EXIT */]: [{ key: "d", ctrl: true }],
453928
453929
  ["showMoreLines" /* SHOW_MORE_LINES */]: [{ key: "s", ctrl: true }],
453929
453930
  ["retryLast" /* RETRY_LAST */]: [{ key: "y", ctrl: true }],
453931
+ ["backgroundSession" /* BACKGROUND_SESSION */]: [{ key: "b", ctrl: true }],
453930
453932
  // Shell commands
453931
453933
  ["reverseSearch" /* REVERSE_SEARCH */]: [{ key: "r", ctrl: true }],
453932
453934
  // Note: original logic ONLY checked ctrl=false, ignored meta/shift/paste
@@ -475103,7 +475105,11 @@ function tildify(p2) {
475103
475105
  return p2.startsWith(homePrefix) ? `~${p2.slice(home.length)}` : p2;
475104
475106
  }
475105
475107
  __name(tildify, "tildify");
475106
- var StatusBar = /* @__PURE__ */ __name(({ cwd: cwd6, terminalWidth }) => {
475108
+ var StatusBar = /* @__PURE__ */ __name(({
475109
+ cwd: cwd6,
475110
+ terminalWidth,
475111
+ bgSessionActive
475112
+ }) => {
475107
475113
  const branch = useGitBranchName(cwd6);
475108
475114
  const diff4 = useGitDiffStat(cwd6);
475109
475115
  const { activeAgents } = useBackgroundAgentProgress();
@@ -475131,6 +475137,10 @@ var StatusBar = /* @__PURE__ */ __name(({ cwd: cwd6, terminalWidth }) => {
475131
475137
  /* @__PURE__ */ (0, import_jsx_runtime137.jsx)(Badge, { children: /* @__PURE__ */ (0, import_jsx_runtime137.jsx)(Text3, { color: theme.text.secondary, children: label }) })
475132
475138
  ] }, agent.agentId);
475133
475139
  }),
475140
+ bgSessionActive && /* @__PURE__ */ (0, import_jsx_runtime137.jsxs)(import_jsx_runtime137.Fragment, { children: [
475141
+ /* @__PURE__ */ (0, import_jsx_runtime137.jsx)(Sep, {}),
475142
+ /* @__PURE__ */ (0, import_jsx_runtime137.jsx)(Badge, { children: /* @__PURE__ */ (0, import_jsx_runtime137.jsx)(Text3, { color: theme.text.secondary, children: "\u27F3 bg session" }) })
475143
+ ] }),
475134
475144
  hasDiff && /* @__PURE__ */ (0, import_jsx_runtime137.jsxs)(import_jsx_runtime137.Fragment, { children: [
475135
475145
  /* @__PURE__ */ (0, import_jsx_runtime137.jsx)(Sep, {}),
475136
475146
  /* @__PURE__ */ (0, import_jsx_runtime137.jsxs)(Badge, { children: [
@@ -475212,7 +475222,14 @@ var DefaultAppLayout = /* @__PURE__ */ __name(() => {
475212
475222
  ] })
475213
475223
  ] }),
475214
475224
  hasAgents && !uiState.dialogsVisible && /* @__PURE__ */ (0, import_jsx_runtime138.jsx)(AgentTabBar, {}),
475215
- /* @__PURE__ */ (0, import_jsx_runtime138.jsx)(StatusBar, { cwd: config2.getTargetDir(), terminalWidth })
475225
+ /* @__PURE__ */ (0, import_jsx_runtime138.jsx)(
475226
+ StatusBar,
475227
+ {
475228
+ cwd: config2.getTargetDir(),
475229
+ terminalWidth,
475230
+ bgSessionActive: uiState.streamingState === "backgrounded" /* Backgrounded */
475231
+ }
475232
+ )
475216
475233
  ] });
475217
475234
  }, "DefaultAppLayout");
475218
475235
 
@@ -478300,6 +478317,9 @@ var useGeminiStream = /* @__PURE__ */ __name((geminiClient, history, addItem, co
478300
478317
  const lastPromptRef = (0, import_react148.useRef)(null);
478301
478318
  const lastPromptErroredRef = (0, import_react148.useRef)(false);
478302
478319
  const [isResponding, setIsResponding] = (0, import_react148.useState)(false);
478320
+ const isBackgroundedRef = (0, import_react148.useRef)(false);
478321
+ const bgResponseTextRef = (0, import_react148.useRef)("");
478322
+ const [isBackgrounded, setIsBackgrounded] = (0, import_react148.useState)(false);
478303
478323
  const pendingCompletedToolsRef = (0, import_react148.useRef)([]);
478304
478324
  const [thought, setThought] = (0, import_react148.useState)(null);
478305
478325
  const [pendingHistoryItem, pendingHistoryItemRef, setPendingHistoryItem] = useStateAndRef(null);
@@ -478458,13 +478478,16 @@ var useGeminiStream = /* @__PURE__ */ __name((geminiClient, history, addItem, co
478458
478478
  })) {
478459
478479
  return "waiting_for_confirmation" /* WaitingForConfirmation */;
478460
478480
  }
478481
+ if (isBackgrounded) {
478482
+ return "backgrounded" /* Backgrounded */;
478483
+ }
478461
478484
  if (isResponding || toolCalls.some(
478462
478485
  (tc) => tc.status === "executing" || tc.status === "scheduled" || tc.status === "validating" || (tc.status === "success" || tc.status === "error" || tc.status === "cancelled") && !tc.responseSubmittedToGemini
478463
478486
  )) {
478464
478487
  return "responding" /* Responding */;
478465
478488
  }
478466
478489
  return "idle" /* Idle */;
478467
- }, [isResponding, toolCalls]);
478490
+ }, [isResponding, toolCalls, isBackgrounded]);
478468
478491
  (0, import_react148.useEffect)(() => {
478469
478492
  if (config2.getApprovalMode() === ApprovalMode.YOLO && streamingState === "idle" /* Idle */) {
478470
478493
  const lastUserMessageIndex = history.findLastIndex(
@@ -478480,7 +478503,7 @@ var useGeminiStream = /* @__PURE__ */ __name((geminiClient, history, addItem, co
478480
478503
  }
478481
478504
  }, [streamingState, config2, history]);
478482
478505
  const cancelOngoingRequest = (0, import_react148.useCallback)(() => {
478483
- if (streamingState !== "responding" /* Responding */) {
478506
+ if (streamingState !== "responding" /* Responding */ && streamingState !== "backgrounded" /* Backgrounded */) {
478484
478507
  return;
478485
478508
  }
478486
478509
  if (turnCancelledRef.current) {
@@ -478523,6 +478546,24 @@ var useGeminiStream = /* @__PURE__ */ __name((geminiClient, history, addItem, co
478523
478546
  config2,
478524
478547
  getPromptCount
478525
478548
  ]);
478549
+ const backgroundCurrentSession = (0, import_react148.useCallback)(() => {
478550
+ if (streamingState !== "responding" /* Responding */) return;
478551
+ if (pendingHistoryItemRef.current) {
478552
+ addItem(pendingHistoryItemRef.current, Date.now());
478553
+ setPendingHistoryItem(null);
478554
+ }
478555
+ isBackgroundedRef.current = true;
478556
+ bgResponseTextRef.current = "";
478557
+ setIsBackgrounded(true);
478558
+ setIsResponding(false);
478559
+ addItem(
478560
+ {
478561
+ type: "info" /* INFO */,
478562
+ text: "\u2193 Running in background \u2014 you'll be notified when done"
478563
+ },
478564
+ Date.now()
478565
+ );
478566
+ }, [streamingState, pendingHistoryItemRef, addItem, setPendingHistoryItem]);
478526
478567
  const prepareQueryForGemini = (0, import_react148.useCallback)(
478527
478568
  async (query, userMessageTimestamp, abortSignal, prompt_id) => {
478528
478569
  if (turnCancelledRef.current) {
@@ -478618,6 +478659,10 @@ var useGeminiStream = /* @__PURE__ */ __name((geminiClient, history, addItem, co
478618
478659
  if (turnCancelledRef.current) {
478619
478660
  return "";
478620
478661
  }
478662
+ if (isBackgroundedRef.current) {
478663
+ bgResponseTextRef.current += eventValue;
478664
+ return currentGeminiMessageBuffer;
478665
+ }
478621
478666
  let newGeminiMessageBuffer = currentGeminiMessageBuffer + eventValue;
478622
478667
  if (pendingHistoryItemRef.current?.type !== "gemini" && pendingHistoryItemRef.current?.type !== "gemini_content") {
478623
478668
  if (pendingHistoryItemRef.current) {
@@ -478667,6 +478712,9 @@ var useGeminiStream = /* @__PURE__ */ __name((geminiClient, history, addItem, co
478667
478712
  if (turnCancelledRef.current) {
478668
478713
  return "";
478669
478714
  }
478715
+ if (isBackgroundedRef.current) {
478716
+ return currentThoughtBuffer;
478717
+ }
478670
478718
  const thoughtText = eventValue.description ?? "";
478671
478719
  if (!thoughtText) {
478672
478720
  return currentThoughtBuffer;
@@ -479014,7 +479062,7 @@ var useGeminiStream = /* @__PURE__ */ __name((geminiClient, history, addItem, co
479014
479062
  return;
479015
479063
  }
479016
479064
  }
479017
- if ((streamingState === "responding" /* Responding */ || streamingState === "waiting_for_confirmation" /* WaitingForConfirmation */) && !bypassGuard) {
479065
+ if ((streamingState === "responding" /* Responding */ || streamingState === "waiting_for_confirmation" /* WaitingForConfirmation */ || streamingState === "backgrounded" /* Backgrounded */) && !bypassGuard) {
479018
479066
  if (generation !== null) queryGuardRef.current.end(generation);
479019
479067
  return;
479020
479068
  }
@@ -479110,6 +479158,9 @@ var useGeminiStream = /* @__PURE__ */ __name((geminiClient, history, addItem, co
479110
479158
  } catch (error40) {
479111
479159
  if (error40 instanceof UnauthorizedError) {
479112
479160
  onAuthError("Session expired or is unauthorized.");
479161
+ } else if (isBackgroundedRef.current && isNodeError(error40) && error40.name === "AbortError") {
479162
+ } else if (isBackgroundedRef.current) {
479163
+ lastPromptErroredRef.current = true;
479113
479164
  } else if (!isNodeError(error40) || error40.name !== "AbortError") {
479114
479165
  lastPromptErroredRef.current = true;
479115
479166
  const retryHint = t4("Press Ctrl+Y to retry");
@@ -479123,6 +479174,42 @@ var useGeminiStream = /* @__PURE__ */ __name((geminiClient, history, addItem, co
479123
479174
  });
479124
479175
  }
479125
479176
  } finally {
479177
+ if (isBackgroundedRef.current) {
479178
+ const wasCancelled = turnCancelledRef.current;
479179
+ const hadError = lastPromptErroredRef.current;
479180
+ const response = bgResponseTextRef.current.trim();
479181
+ isBackgroundedRef.current = false;
479182
+ bgResponseTextRef.current = "";
479183
+ setIsBackgrounded(false);
479184
+ if (wasCancelled) {
479185
+ addItem(
479186
+ {
479187
+ type: "info" /* INFO */,
479188
+ text: "\u2193 Background session cancelled"
479189
+ },
479190
+ Date.now()
479191
+ );
479192
+ } else if (hadError) {
479193
+ addItem(
479194
+ {
479195
+ type: "warning" /* WARNING */,
479196
+ text: "\u2193 Background session failed"
479197
+ },
479198
+ Date.now()
479199
+ );
479200
+ } else {
479201
+ const preview = response.length > 0 ? response.length > 300 ? response.slice(0, 300) + "\u2026" : response : "(no response)";
479202
+ addItem(
479203
+ {
479204
+ type: "info" /* INFO */,
479205
+ text: `\u2713 Background session complete
479206
+
479207
+ ${preview}`
479208
+ },
479209
+ Date.now()
479210
+ );
479211
+ }
479212
+ }
479126
479213
  setIsResponding(false);
479127
479214
  if (generation !== null) queryGuardRef.current.end(generation);
479128
479215
  Promise.resolve().then(() => (init_dist4(), dist_exports)).then((core) => {
@@ -479181,7 +479268,7 @@ var useGeminiStream = /* @__PURE__ */ __name((geminiClient, history, addItem, co
479181
479268
  ]
479182
479269
  );
479183
479270
  const retryLastPrompt = (0, import_react148.useCallback)(async () => {
479184
- if (streamingState === "responding" /* Responding */ || streamingState === "waiting_for_confirmation" /* WaitingForConfirmation */) {
479271
+ if (streamingState === "responding" /* Responding */ || streamingState === "waiting_for_confirmation" /* WaitingForConfirmation */ || streamingState === "backgrounded" /* Backgrounded */) {
479185
479272
  return;
479186
479273
  }
479187
479274
  const lastPrompt = lastPromptRef.current;
@@ -479531,7 +479618,8 @@ ${verifyResult}` });
479531
479618
  pendingToolCalls: toolCalls,
479532
479619
  handleApprovalModeChange,
479533
479620
  activePtyId,
479534
- loopDetectionConfirmationRequest
479621
+ loopDetectionConfirmationRequest,
479622
+ backgroundCurrentSession
479535
479623
  };
479536
479624
  }, "useGeminiStream");
479537
479625
 
@@ -480126,7 +480214,8 @@ function useKeyboardHandling(params) {
480126
480214
  ideContextState,
480127
480215
  handleExit,
480128
480216
  handleSlashCommand: handleSlashCommand2,
480129
- debugKeystrokeLogging
480217
+ debugKeystrokeLogging,
480218
+ onBackgroundSession
480130
480219
  } = params;
480131
480220
  const [showToolDescriptions, setShowToolDescriptions] = (0, import_react151.useState)(false);
480132
480221
  const [ctrlCPressedOnce, setCtrlCPressedOnce] = (0, import_react151.useState)(false);
@@ -480246,6 +480335,9 @@ function useKeyboardHandling(params) {
480246
480335
  if (activePtyId || embeddedShellFocused) {
480247
480336
  setEmbeddedShellFocused((prev) => !prev);
480248
480337
  }
480338
+ } else if (keyMatchers["backgroundSession" /* BACKGROUND_SESSION */](key) && onBackgroundSession) {
480339
+ onBackgroundSession();
480340
+ return;
480249
480341
  }
480250
480342
  };
480251
480343
  const handleGlobalKeypress = (0, import_react151.useCallback)(
@@ -485150,7 +485242,8 @@ var AppContainer = /* @__PURE__ */ __name((props) => {
485150
485242
  retryLastPrompt,
485151
485243
  handleApprovalModeChange,
485152
485244
  activePtyId,
485153
- loopDetectionConfirmationRequest
485245
+ loopDetectionConfirmationRequest,
485246
+ backgroundCurrentSession
485154
485247
  } = useGeminiStream(
485155
485248
  config2.getGeminiClient(),
485156
485249
  historyManager.history,
@@ -485616,7 +485709,8 @@ ${migrationResult.failedFiles.map((f5) => ` \u2022 ${f5.file}: ${f5.error}`).jo
485616
485709
  config: config2,
485617
485710
  ideContextState,
485618
485711
  handleExit,
485619
- debugKeystrokeLogging: settings2.merged.general?.debugKeystrokeLogging
485712
+ debugKeystrokeLogging: settings2.merged.general?.debugKeystrokeLogging,
485713
+ onBackgroundSession: backgroundCurrentSession
485620
485714
  });
485621
485715
  useWindowTitle(
485622
485716
  streamingState,
@@ -490068,7 +490162,7 @@ var QwenAgent = class {
490068
490162
  async initialize(args2) {
490069
490163
  this.clientCapabilities = args2.clientCapabilities;
490070
490164
  const authMethods = buildAuthMethods();
490071
- const version2 = "0.25.8";
490165
+ const version2 = "0.25.10";
490072
490166
  return {
490073
490167
  protocolVersion: PROTOCOL_VERSION,
490074
490168
  agentInfo: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@protolabsai/proto",
3
- "version": "0.25.8",
3
+ "version": "0.25.10",
4
4
  "description": "proto - AI-powered coding agent",
5
5
  "repository": {
6
6
  "type": "git",
@@ -21,7 +21,7 @@
21
21
  "bundled"
22
22
  ],
23
23
  "config": {
24
- "sandboxImageUri": "ghcr.io/qwenlm/qwen-code:0.25.8"
24
+ "sandboxImageUri": "ghcr.io/qwenlm/qwen-code:0.25.10"
25
25
  },
26
26
  "dependencies": {},
27
27
  "optionalDependencies": {