@yagni-app/code-staging 1.2.13-staging.2196.1 → 1.2.13-staging.2198.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.
@@ -48,6 +48,7 @@ import { createGrantCensus } from "./permission/grantCensus.js";
48
48
  import { runsInSandboxHarness, toolchainBashToolDefinition, toolchainSpawnHookFromEnv, toolchainUserBashOperations, } from "./toolchain/spawnHook.js";
49
49
  import { CLOUD_SESSION_ENV } from "./pipeline/cloud.js";
50
50
  import { registerStageClock } from "./pipeline/stageClock.js";
51
+ import { registerBashDefaultTimeout } from "./toolchain/bashDefaultTimeout.js";
51
52
  import { scrubSecrets } from "./pipeline/scrubSecrets.js";
52
53
  import { registerTelemetry as defaultRegisterTelemetry } from "./telemetry/register.js";
53
54
  import { loadHooksConfig, makeHookRunner, registerHooks } from "./hooks.js";
@@ -176,6 +177,9 @@ export async function registerYagni(pi, deps = {}) {
176
177
  // not matter: pi runs every tool_call handler until one blocks, and an allow
177
178
  // (a result without `block`) never ends the loop, so this block always lands.
178
179
  registerStageClock(pi, env, now);
180
+ // A sandbox session's bash call without a timeout gets a default one, so a
181
+ // command that never exits cannot hold the session. It never blocks.
182
+ registerBashDefaultTimeout(pi, env);
179
183
  // The grounding settings switch (the judgment-loop kill switch): resolved
180
184
  // ONCE at boot from the USER-tier config (default on; a malformed config
181
185
  // fails soft to on with a sink warn). Eval mode is its own carve-out and
@@ -0,0 +1,25 @@
1
+ /**
2
+ * A default timeout for bash in a sandbox session. Pi's bash has none, so a
3
+ * command that never exits (a server, an interactive prompt) holds the whole
4
+ * session until an outer clock stops it. A rails build session on staging
5
+ * went quiet for 35 minutes after one such call (YAG-1130).
6
+ */
7
+ import { type ExtensionAPI } from "@earendil-works/pi-coding-agent";
8
+ /**
9
+ * Ten minutes: long enough for an install or a test suite, short enough that a
10
+ * command that never exits does not hold the session. The model can pass a
11
+ * longer `timeout`, and pi's timed-out result tells it so.
12
+ */
13
+ export declare const SANDBOX_BASH_TIMEOUT_SECONDS = 600;
14
+ /**
15
+ * Give every bash call without a positive timeout the default one. pi's bash
16
+ * treats 0 as no timeout, so 0, negatives and non-numbers get it too; every
17
+ * positive number the model asked for stays. A background call
18
+ * (`run_in_background`) is left alone: it returns at once, so it cannot hold
19
+ * the session, and the sandbox's background job (`sandbox/session.ts`) kills
20
+ * the job when its timeout runs out, which would stop a backgrounded server.
21
+ * It never blocks. A developer's own terminal (no sandbox harness) gets
22
+ * nothing.
23
+ */
24
+ export declare function registerBashDefaultTimeout(pi: Pick<ExtensionAPI, "on">, env: NodeJS.ProcessEnv, seconds?: number): void;
25
+ //# sourceMappingURL=bashDefaultTimeout.d.ts.map
@@ -0,0 +1,40 @@
1
+ /**
2
+ * A default timeout for bash in a sandbox session. Pi's bash has none, so a
3
+ * command that never exits (a server, an interactive prompt) holds the whole
4
+ * session until an outer clock stops it. A rails build session on staging
5
+ * went quiet for 35 minutes after one such call (YAG-1130).
6
+ */
7
+ import { isToolCallEventType } from "@earendil-works/pi-coding-agent";
8
+ import { runsInSandboxHarness } from "./spawnHook.js";
9
+ /**
10
+ * Ten minutes: long enough for an install or a test suite, short enough that a
11
+ * command that never exits does not hold the session. The model can pass a
12
+ * longer `timeout`, and pi's timed-out result tells it so.
13
+ */
14
+ export const SANDBOX_BASH_TIMEOUT_SECONDS = 600;
15
+ /**
16
+ * Give every bash call without a positive timeout the default one. pi's bash
17
+ * treats 0 as no timeout, so 0, negatives and non-numbers get it too; every
18
+ * positive number the model asked for stays. A background call
19
+ * (`run_in_background`) is left alone: it returns at once, so it cannot hold
20
+ * the session, and the sandbox's background job (`sandbox/session.ts`) kills
21
+ * the job when its timeout runs out, which would stop a backgrounded server.
22
+ * It never blocks. A developer's own terminal (no sandbox harness) gets
23
+ * nothing.
24
+ */
25
+ export function registerBashDefaultTimeout(pi, env, seconds = SANDBOX_BASH_TIMEOUT_SECONDS) {
26
+ if (!runsInSandboxHarness(env))
27
+ return;
28
+ pi.on("tool_call", async (event) => {
29
+ if (!isToolCallEventType("bash", event))
30
+ return undefined;
31
+ const input = event.input;
32
+ if (input.run_in_background === true)
33
+ return undefined;
34
+ if (typeof input.timeout === "number" && input.timeout > 0)
35
+ return undefined;
36
+ event.input.timeout = seconds;
37
+ return undefined;
38
+ });
39
+ }
40
+ //# sourceMappingURL=bashDefaultTimeout.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yagni-app/code-staging",
3
- "version": "1.2.13-staging.2196.1",
3
+ "version": "1.2.13-staging.2198.1",
4
4
  "description": "YAGNI Code: a terminal coding agent that already knows your company. One YAGNI login routes the model and grounds the agent in your team's context.",
5
5
  "license": "SEE LICENSE IN LICENSE.md",
6
6
  "author": "YAGNI, Inc. <jack@yagni.app> (https://yagni.app)",
@@ -58,5 +58,5 @@
58
58
  "turndown": "^7.2.4",
59
59
  "typebox": "^1.3.15"
60
60
  },
61
- "yagniSourceSha": "c0c70b535de32727cd574cd8c4eedc460601ff76"
61
+ "yagniSourceSha": "a784a903593e5a0174b06dff4e34cc21fff4be4b"
62
62
  }