Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions packages/agent/src/adapters/claude/git-command.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// Pure git command-line parsing, shared by the signed-commit guard (hooks.ts)
// and the RTK rewrite (session/rtk.ts). Kept dependency-free so importers don't
// drag in the hooks module's heavier import chain.
// Pure git command-line parsing used by the signed-commit guard. Kept
// dependency-free so importers don't drag in the hooks module's heavier chain.

// git global options that consume the following token as their value, so the
// subcommand detector must skip both (mirrors the sandbox `git` PATH shim).
Expand Down
40 changes: 31 additions & 9 deletions packages/agent/src/adapters/claude/session/options.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,15 +210,16 @@ describe("buildSessionOptions", () => {
expect(healSpy).not.toHaveBeenCalled();
});

describe("rtk and signed-commit guard ordering", () => {
describe("rtk hook registration", () => {
const originalRtk = process.env.POSTHOG_RTK;
let dir: string;
let binary: string;

beforeEach(() => {
dir = fs.mkdtempSync(path.join(os.tmpdir(), "rtk-order-"));
binary = path.join(dir, "rtk");
fs.writeFileSync(binary, "#!/bin/sh\n");
fs.writeFileSync(binary, "#!/bin/sh\necho 'rtk 0.43.0'\n");
fs.chmodSync(binary, 0o755);
process.env.POSTHOG_RTK = binary;
});

Expand All @@ -244,7 +245,7 @@ describe("buildSessionOptions", () => {
};
};

it("registers the signed-commit guard before the rtk rewrite so the guard evaluates raw commands (cloud)", async () => {
it("keeps the signed-commit guard and pnpm test rewrite active in cloud mode", async () => {
const options = buildSessionOptions({
...makeParams(),
cloudMode: true,
Expand All @@ -254,9 +255,6 @@ describe("buildSessionOptions", () => {
);
const opts = { signal: new AbortController().signal };

// Identify each hook behaviorally: the guard denies `git commit`, the
// rtk hook rewrites `git status`. Their registration order is the
// defense-in-depth guarantee that the guard always sees the raw command.
let guardIndex = -1;
let rtkIndex = -1;
for (const [index, hook] of hooks.entries()) {
Expand All @@ -273,22 +271,46 @@ describe("buildSessionOptions", () => {
}

const rewriteResult = (await hook(
bashInput("git status"),
bashInput("pnpm test"),
undefined,
opts,
)) as PreToolUseOutput;
if (
rtkIndex === -1 &&
rewriteResult.hookSpecificOutput?.updatedInput?.command ===
`${binary} git status`
`${binary} test pnpm test`
) {
rtkIndex = index;
}
}

expect(guardIndex).toBeGreaterThanOrEqual(0);
expect(rtkIndex).toBeGreaterThanOrEqual(0);
expect(guardIndex).toBeLessThan(rtkIndex);
});

it("applies the shared pnpm test policy through the Claude hook", async () => {
const options = buildSessionOptions({
...makeParams(),
cloudMode: false,
});
const hooks = (options.hooks?.PreToolUse ?? []).flatMap(
(entry) => entry.hooks ?? [],
);
const opts = { signal: new AbortController().signal };

const results = await Promise.all(
hooks.map((hook) => hook(bashInput("pnpm test"), undefined, opts)),
);

expect(results).toContainEqual(
expect.objectContaining({
hookSpecificOutput: expect.objectContaining({
updatedInput: {
command: `${binary} test pnpm test`,
},
}),
}),
);
});
});

Expand Down
3 changes: 2 additions & 1 deletion packages/agent/src/adapters/claude/session/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import type { FileEnrichmentDeps } from "../../../enrichment/file-enricher";
import { IS_ROOT } from "../../../utils/common";
import { buildGatewayPropertyHeaders } from "../../../utils/gateway";
import type { Logger } from "../../../utils/logger";
import { resolveRtkPrefix } from "../../rtk";
import type { TaskState } from "../conversion/task-state";
import {
createPostToolUseHook,
Expand All @@ -31,7 +32,7 @@ import type { EffortLevel } from "../types";
import { buildAppendedInstructions } from "./instructions";
import { loadUserClaudeJsonMcpServers } from "./mcp-config";
import { DEFAULT_MODEL, FALLBACK_MODEL } from "./models";
import { createRtkRewriteHook, resolveRtkPrefix } from "./rtk";
import { createRtkRewriteHook } from "./rtk";
import type { SettingsManager } from "./settings";

export interface ProcessSpawnedInfo {
Expand Down
236 changes: 0 additions & 236 deletions packages/agent/src/adapters/claude/session/rtk.test.ts

This file was deleted.

Loading
Loading