@stigmer/runner 3.14.0 → 3.14.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.
Files changed (56) hide show
  1. package/dist/.build-fingerprint +1 -1
  2. package/dist/__test-utils__/hermetic-activity.d.ts +245 -0
  3. package/dist/__test-utils__/hermetic-activity.js +369 -0
  4. package/dist/__test-utils__/hermetic-activity.js.map +1 -0
  5. package/dist/__test-utils__/mock-client.d.ts +13 -0
  6. package/dist/__test-utils__/mock-client.js +45 -0
  7. package/dist/__test-utils__/mock-client.js.map +1 -0
  8. package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.d.ts +172 -0
  9. package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.js +331 -0
  10. package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.js.map +1 -0
  11. package/dist/activities/execute-cursor/__test-utils__/scripted-agent.d.ts +167 -0
  12. package/dist/activities/execute-cursor/__test-utils__/scripted-agent.js +239 -0
  13. package/dist/activities/execute-cursor/__test-utils__/scripted-agent.js.map +1 -0
  14. package/dist/activities/execute-cursor/__test-utils__/scripted-sdk.d.ts +97 -0
  15. package/dist/activities/execute-cursor/__test-utils__/scripted-sdk.js +132 -0
  16. package/dist/activities/execute-cursor/__test-utils__/scripted-sdk.js.map +1 -0
  17. package/dist/harness/capabilities.d.ts +71 -0
  18. package/dist/harness/capabilities.js +36 -0
  19. package/dist/harness/capabilities.js.map +1 -0
  20. package/dist/harness/registry.d.ts +67 -0
  21. package/dist/harness/registry.js +112 -0
  22. package/dist/harness/registry.js.map +1 -0
  23. package/dist/harness/types.d.ts +268 -0
  24. package/dist/harness/types.js +55 -0
  25. package/dist/harness/types.js.map +1 -0
  26. package/package.json +4 -4
  27. package/src/__test-utils__/__tests__/harness-contract-self-check.test.ts +229 -0
  28. package/src/__test-utils__/config-fixture.ts +63 -0
  29. package/src/__test-utils__/harness-contract/contract.ts +536 -0
  30. package/src/__test-utils__/harness-contract/recording-sink.ts +96 -0
  31. package/src/__test-utils__/harness-contract/scripted-adapter.ts +289 -0
  32. package/src/__test-utils__/harness-contract/types.ts +100 -0
  33. package/src/__test-utils__/hermetic-activity.ts +477 -0
  34. package/src/__test-utils__/proto-helpers.ts +25 -0
  35. package/src/__tests__/harness-contract.test.ts +25 -0
  36. package/src/activities/execute-cursor/__test-utils__/hermetic-cursor.ts +422 -0
  37. package/src/activities/execute-cursor/__test-utils__/scripted-agent.ts +342 -0
  38. package/src/activities/execute-cursor/__test-utils__/scripted-sdk.ts +166 -0
  39. package/src/activities/execute-cursor/__tests__/hermetic/deny-and-retry.test.ts +228 -0
  40. package/src/activities/execute-cursor/__tests__/hermetic/file-review-capture.test.ts +180 -0
  41. package/src/activities/execute-cursor/__tests__/hermetic/goldens/deny-and-retry.turn1.status.json +55 -0
  42. package/src/activities/execute-cursor/__tests__/hermetic/goldens/deny-and-retry.turn2.status.json +77 -0
  43. package/src/activities/execute-cursor/__tests__/hermetic/goldens/file-review-capture.status.json +126 -0
  44. package/src/activities/execute-cursor/__tests__/hermetic/goldens/pause.status.json +45 -0
  45. package/src/activities/execute-cursor/__tests__/hermetic/goldens/plain-turn.status.json +48 -0
  46. package/src/activities/execute-cursor/__tests__/hermetic/goldens/recovery-fresh-agent.status.json +53 -0
  47. package/src/activities/execute-cursor/__tests__/hermetic/goldens/tool-call.status.json +68 -0
  48. package/src/activities/execute-cursor/__tests__/hermetic/goldens/worker-shutdown.status.json +47 -0
  49. package/src/activities/execute-cursor/__tests__/hermetic/pause-vs-shutdown.test.ts +201 -0
  50. package/src/activities/execute-cursor/__tests__/hermetic/plain-turn.test.ts +171 -0
  51. package/src/activities/execute-cursor/__tests__/hermetic/recovery-fresh-agent.test.ts +156 -0
  52. package/src/activities/execute-cursor/__tests__/hermetic/tool-call.test.ts +137 -0
  53. package/src/harness/__tests__/registry.test.ts +167 -0
  54. package/src/harness/capabilities.ts +75 -0
  55. package/src/harness/registry.ts +123 -0
  56. package/src/harness/types.ts +278 -0
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Shared mock factory for StigmerClient used across test suites.
3
+ *
4
+ * StigmerClient is a class (not an interface), so mocks use
5
+ * `as unknown as StigmerClient` — matching the established pattern
6
+ * in grpc-retry.test.ts and connect-backfill.test.ts.
7
+ */
8
+ import { vi } from "vitest";
9
+ import { ExecutionControlSignal } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
10
+ export function mockStigmerClient(overrides = {}) {
11
+ return {
12
+ updateStatus: vi.fn().mockResolvedValue({
13
+ signal: ExecutionControlSignal.UNSPECIFIED,
14
+ }),
15
+ getExecution: vi.fn().mockResolvedValue({}),
16
+ getExecutionContextByExecutionId: vi.fn().mockResolvedValue({}),
17
+ // No scoped token by default — the OSS/local shape (no runner credential).
18
+ acquireScopedRunnerToken: vi.fn().mockResolvedValue(undefined),
19
+ getRunnerScopedToken: vi.fn().mockResolvedValue(undefined),
20
+ getSession: vi.fn().mockResolvedValue({}),
21
+ updateSession: vi.fn().mockResolvedValue({}),
22
+ // No proactive channels by default — the everyday answer for most
23
+ // agents (DD-006 D2); tests opt in to a channel-bound agent.
24
+ listMessagingChannels: vi.fn().mockResolvedValue([]),
25
+ listChannelTemplates: vi.fn().mockResolvedValue([]),
26
+ getAgent: vi.fn().mockResolvedValue({}),
27
+ getAgentInstance: vi.fn().mockResolvedValue({}),
28
+ getMcpServer: vi.fn().mockResolvedValue({}),
29
+ getMcpServerByReference: vi.fn().mockResolvedValue({}),
30
+ connectMcpServer: vi.fn().mockResolvedValue({}),
31
+ getSkill: vi.fn().mockResolvedValue({}),
32
+ getSkillByReference: vi.fn().mockResolvedValue({}),
33
+ getSkillArtifact: vi.fn().mockResolvedValue({}),
34
+ recordLlmCallUsage: vi.fn().mockResolvedValue({}),
35
+ getWorkflowExecution: vi.fn().mockResolvedValue({}),
36
+ getWorkflow: vi.fn().mockResolvedValue({}),
37
+ getWorkflowInstance: vi.fn().mockResolvedValue({}),
38
+ updateWorkflowExecutionStatus: vi.fn().mockResolvedValue({}),
39
+ getAgentByReference: vi.fn().mockResolvedValue({}),
40
+ createSession: vi.fn().mockResolvedValue({}),
41
+ createAgentExecution: vi.fn().mockResolvedValue({}),
42
+ ...overrides,
43
+ };
44
+ }
45
+ //# sourceMappingURL=mock-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock-client.js","sourceRoot":"","sources":["../../src/__test-utils__/mock-client.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAE,sBAAsB,EAAE,MAAM,8DAA8D,CAAC;AAOtG,MAAM,UAAU,iBAAiB,CAAC,YAAyB,EAAE;IAC3D,OAAO;QACL,YAAY,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC;YACtC,MAAM,EAAE,sBAAsB,CAAC,WAAW;SAC3C,CAAC;QACF,YAAY,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC;QAC3C,gCAAgC,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC;QAC/D,2EAA2E;QAC3E,wBAAwB,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,SAAS,CAAC;QAC9D,oBAAoB,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,SAAS,CAAC;QAC1D,UAAU,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC;QACzC,aAAa,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC;QAC5C,kEAAkE;QAClE,6DAA6D;QAC7D,qBAAqB,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC;QACpD,oBAAoB,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC;QACnD,QAAQ,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC;QACvC,gBAAgB,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC;QAC/C,YAAY,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC;QAC3C,uBAAuB,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC;QACtD,gBAAgB,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC;QAC/C,QAAQ,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC;QACvC,mBAAmB,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC;QAClD,gBAAgB,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC;QAC/C,kBAAkB,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC;QACjD,oBAAoB,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC;QACnD,WAAW,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC;QAC1C,mBAAmB,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC;QAClD,6BAA6B,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC;QAC5D,mBAAmB,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC;QAClD,aAAa,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC;QAC5C,oBAAoB,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC;QACnD,GAAG,SAAS;KACe,CAAC;AAChC,CAAC"}
@@ -0,0 +1,172 @@
1
+ /**
2
+ * The Cursor slice of the hermetic activity driver: build the fixture record,
3
+ * the scripted SDK and the `Config`, run the REAL `ExecuteCursor` activity under
4
+ * `MockActivityEnvironment`, and hand back what it persisted.
5
+ *
6
+ * Layering (the `approval-contract/` + `gateway-substrate.ts` split): everything
7
+ * harness-agnostic lives in `src/__test-utils__/hermetic-activity.ts` (the
8
+ * activity environment, the execution record behind the client, the temp
9
+ * `~/.stigmer`, the ticking clock, the shutdown signal). This module adds only
10
+ * what is Cursor's: the `@cursor/sdk` double, the model catalog and pricing
11
+ * registry the harness reads at setup, the Cursor `Config` slice, and the
12
+ * per-scenario reset of the harness's module-level caches.
13
+ *
14
+ * What the two `vi.mock` calls a scenario file must carry look like — they are
15
+ * hoisted by vitest and so cannot live here:
16
+ *
17
+ * ```ts
18
+ * vi.mock("@cursor/sdk", async () =>
19
+ * (await import("../../__test-utils__/scripted-sdk.js")).scriptedCursorSdkModule());
20
+ * vi.mock("../../../../client/stigmer-client.js", async () =>
21
+ * (await import("../../../../__test-utils__/hermetic-activity.js")).hermeticStigmerClientModule());
22
+ * ```
23
+ *
24
+ * Network: the activity's only HTTP fetch is the model registry
25
+ * (`model-pricing-data.ts`, `shared/model-registry.ts`; both fail SOFT to
26
+ * defaults with a 60s failure cache, which would make the goldens depend on
27
+ * DEFAULT_PRICING and log warnings on every run). `fetch` is stubbed to answer
28
+ * one registry document — and to THROW for any other URL, so a new network
29
+ * dependency on the activity path fails the hermetic run instead of leaking.
30
+ *
31
+ * The fixture model is `composer-2.5`, pinned (not Auto) on purpose: Auto short-
32
+ * circuits `resolveServiceTierParams` before the catalog, and a pinned model runs
33
+ * the catalog path, the variant-param pinning, and the `run.wait()` model echo
34
+ * check — more of the production path under the golden.
35
+ */
36
+ import type { ModelListItem } from "@cursor/sdk";
37
+ import { type WorkspaceEntry } from "@stigmer/protos/ai/stigmer/agentic/session/v1/workspace_pb";
38
+ import type { Config } from "../../../config.js";
39
+ import { ExecutionRecord, ScriptedClock, type ActivityInvocation, type HermeticEnvironment, type InvocationControls } from "../../../__test-utils__/hermetic-activity.js";
40
+ import { ScriptedCursorSdk, type ScriptedSdkOptions } from "./scripted-sdk.js";
41
+ export declare const FIXTURE: {
42
+ readonly org: "hermetic-org";
43
+ readonly executionId: "aex_hermetic_0001";
44
+ readonly sessionId: "ses_hermetic_0001";
45
+ readonly agentInstanceId: "ain_hermetic_0001";
46
+ readonly agentId: "agt_hermetic_0001";
47
+ readonly agentName: "hermetic-agent";
48
+ /** The pinned model; in the registry stub AND the SDK catalog below. */
49
+ readonly model: "composer-2.5";
50
+ readonly cursorApiKey: "hermetic-cursor-api-key";
51
+ };
52
+ export interface CursorRecordOptions {
53
+ /** The user's message for this execution. */
54
+ readonly message: string;
55
+ /** The agent's instructions (system prompt body). */
56
+ readonly instructions?: string;
57
+ /** Session workspace entries (a `local_path` entry turns on capture mode). */
58
+ readonly workspaceEntries?: WorkspaceEntry[];
59
+ readonly modelName?: string;
60
+ readonly autoApproveAll?: boolean;
61
+ }
62
+ /** The four resources of one execution, wired by id into a chain. */
63
+ export declare function cursorExecutionRecord(options: CursorRecordOptions): ExecutionRecord;
64
+ /**
65
+ * The model registry document both readers parse (`parsePricingTable` wants
66
+ * `harness: "cursor"` + `pricing`; `parseRegistry` wants `id` + `provider` and
67
+ * reads `capabilities.vision`). One entry, the fixture model, priced at round
68
+ * numbers so the golden's `estimatedCostUsd` is legible.
69
+ */
70
+ export declare const REGISTRY_DOCUMENT: {
71
+ readonly models: readonly [{
72
+ readonly id: "composer-2.5";
73
+ readonly displayName: "Composer 2.5 (hermetic fixture)";
74
+ readonly provider: "cursor";
75
+ readonly harness: "cursor";
76
+ readonly costTier: "standard";
77
+ readonly featured: true;
78
+ readonly capabilities: {
79
+ readonly vision: true;
80
+ };
81
+ readonly pricing: {
82
+ readonly inputPricePerMillion: 1;
83
+ readonly outputPricePerMillion: 4;
84
+ readonly cacheWritePricePerMillion: 1;
85
+ readonly cacheReadPricePerMillion: 0.1;
86
+ };
87
+ readonly pricingVariants: {
88
+ readonly fast: {
89
+ readonly inputPricePerMillion: 3;
90
+ readonly outputPricePerMillion: 12;
91
+ readonly cacheWritePricePerMillion: 3;
92
+ readonly cacheReadPricePerMillion: 0.3;
93
+ };
94
+ };
95
+ }];
96
+ };
97
+ /** The SDK catalog entry for the fixture model: both pinnable params declared. */
98
+ export declare const SDK_CATALOG: readonly ModelListItem[];
99
+ /**
100
+ * Stub `fetch` to answer the registry document and refuse everything else.
101
+ * Returns the URLs fetched, for the "no other network" assertion.
102
+ */
103
+ export declare function stubRegistryFetch(): {
104
+ readonly urls: string[];
105
+ restore(): void;
106
+ };
107
+ /** The OSS/local runner posture: direct Cursor API key, no proxy, local mode. */
108
+ export declare function hermeticCursorConfig(env: HermeticEnvironment): Config;
109
+ /**
110
+ * The primary workspace directory a session with NO workspace entries runs in
111
+ * (`session-root.ts`: `<workspaceRootDir>/sessions/<sessionId>`).
112
+ */
113
+ export declare function sessionWorkspaceDir(env: HermeticEnvironment): string;
114
+ /**
115
+ * Run the workspace's installed preToolUse hook exactly as the Cursor SDK does:
116
+ * read `<workspaceRoot>/.cursor/hooks.json`, take the `preToolUse` command the
117
+ * gate installed (an absolute path to the runner's own stable bash script under
118
+ * `~/.stigmer/hitl-gate/<key>/`), and run it with the hook input on stdin. The
119
+ * script resolves the CURRENT turn's state file and denial ledger from the
120
+ * active-turn pointer, walks its parent PIDs to confirm this process is the
121
+ * runner, and prints `{"permission":"allow"|"deny"}`. A deny appends to the
122
+ * ledger the activity's stream loop reads.
123
+ *
124
+ * This is the out-of-process half of deny-and-retry, driven by the real script
125
+ * against the real gate the activity installed — not a simulation of either.
126
+ */
127
+ export declare function runWorkspaceHook(workspaceRoot: string, hookInput: object): {
128
+ readonly permission: "allow" | "deny" | "?";
129
+ readonly raw: string;
130
+ };
131
+ /**
132
+ * A git work tree with one committed file, for the file-review capture
133
+ * scenario. Author, committer and both dates are pinned so the commit AND tree
134
+ * object ids are byte-stable — a file-review golden may carry them.
135
+ */
136
+ export declare function initGitWorkspace(root: string, files: Record<string, string>): void;
137
+ /** A session workspace entry mounting an absolute local path (local mode only). */
138
+ export declare function localPathEntry(name: string, path: string): WorkspaceEntry;
139
+ /**
140
+ * Drop every module-level cache the harness keeps across invocations. Called
141
+ * at the START of a scenario, never between its invocations: a deny-and-retry
142
+ * scenario relies on the parked agent surviving from turn 1 into turn 2 exactly
143
+ * as it does in a live worker.
144
+ */
145
+ export declare function resetCursorModuleState(): void;
146
+ export interface CursorScenario {
147
+ readonly env: HermeticEnvironment;
148
+ readonly clock: ScriptedClock;
149
+ readonly record: ExecutionRecord;
150
+ readonly sdk: ScriptedCursorSdk;
151
+ }
152
+ export interface CursorScenarioOptions {
153
+ readonly env: HermeticEnvironment;
154
+ readonly clock: ScriptedClock;
155
+ readonly record: ExecutionRecord;
156
+ readonly sdk: ScriptedSdkOptions;
157
+ }
158
+ /** Bind the record and the SDK for a scenario; resets the harness caches first. */
159
+ export declare function beginCursorScenario(options: CursorScenarioOptions): CursorScenario;
160
+ export interface CursorTurnOptions {
161
+ /** Empty for a first invocation; the agent id for a HITL reinvocation. */
162
+ readonly threadId?: string;
163
+ /** The HITL cycle index (0 on the first turn); mints the change-set id. */
164
+ readonly turnSeq?: number;
165
+ readonly onControls?: (controls: InvocationControls) => void;
166
+ }
167
+ /**
168
+ * Run ONE `ExecuteCursor` invocation for the scenario. The activities are
169
+ * constructed per invocation (the factory constructs its client, which is the
170
+ * one bound at `beginCursorScenario`).
171
+ */
172
+ export declare function runCursorTurn(scenario: CursorScenario, options?: CursorTurnOptions): Promise<ActivityInvocation>;
@@ -0,0 +1,331 @@
1
+ /**
2
+ * The Cursor slice of the hermetic activity driver: build the fixture record,
3
+ * the scripted SDK and the `Config`, run the REAL `ExecuteCursor` activity under
4
+ * `MockActivityEnvironment`, and hand back what it persisted.
5
+ *
6
+ * Layering (the `approval-contract/` + `gateway-substrate.ts` split): everything
7
+ * harness-agnostic lives in `src/__test-utils__/hermetic-activity.ts` (the
8
+ * activity environment, the execution record behind the client, the temp
9
+ * `~/.stigmer`, the ticking clock, the shutdown signal). This module adds only
10
+ * what is Cursor's: the `@cursor/sdk` double, the model catalog and pricing
11
+ * registry the harness reads at setup, the Cursor `Config` slice, and the
12
+ * per-scenario reset of the harness's module-level caches.
13
+ *
14
+ * What the two `vi.mock` calls a scenario file must carry look like — they are
15
+ * hoisted by vitest and so cannot live here:
16
+ *
17
+ * ```ts
18
+ * vi.mock("@cursor/sdk", async () =>
19
+ * (await import("../../__test-utils__/scripted-sdk.js")).scriptedCursorSdkModule());
20
+ * vi.mock("../../../../client/stigmer-client.js", async () =>
21
+ * (await import("../../../../__test-utils__/hermetic-activity.js")).hermeticStigmerClientModule());
22
+ * ```
23
+ *
24
+ * Network: the activity's only HTTP fetch is the model registry
25
+ * (`model-pricing-data.ts`, `shared/model-registry.ts`; both fail SOFT to
26
+ * defaults with a 60s failure cache, which would make the goldens depend on
27
+ * DEFAULT_PRICING and log warnings on every run). `fetch` is stubbed to answer
28
+ * one registry document — and to THROW for any other URL, so a new network
29
+ * dependency on the activity path fails the hermetic run instead of leaking.
30
+ *
31
+ * The fixture model is `composer-2.5`, pinned (not Auto) on purpose: Auto short-
32
+ * circuits `resolveServiceTierParams` before the catalog, and a pinned model runs
33
+ * the catalog path, the variant-param pinning, and the `run.wait()` model echo
34
+ * check — more of the production path under the golden.
35
+ */
36
+ import { execFileSync } from "node:child_process";
37
+ import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
38
+ import { dirname, join } from "node:path";
39
+ import { create } from "@bufbuild/protobuf";
40
+ import { vi } from "vitest";
41
+ import { AgentExecutionSchema, } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
42
+ import { AgentExecutionSpecSchema, ExecutionConfigSchema, } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/spec_pb";
43
+ import { SessionSchema } from "@stigmer/protos/ai/stigmer/agentic/session/v1/api_pb";
44
+ import { SessionSpecSchema } from "@stigmer/protos/ai/stigmer/agentic/session/v1/spec_pb";
45
+ import { LocalPathSourceSchema, WorkspaceEntrySchema, WorkspaceSourceSchema, } from "@stigmer/protos/ai/stigmer/agentic/session/v1/workspace_pb";
46
+ import { AgentSchema } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/api_pb";
47
+ import { AgentSpecSchema } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/spec_pb";
48
+ import { AgentInstanceSchema, } from "@stigmer/protos/ai/stigmer/agentic/agentinstance/v1/api_pb";
49
+ import { AgentInstanceSpecSchema } from "@stigmer/protos/ai/stigmer/agentic/agentinstance/v1/spec_pb";
50
+ import { ApiResourceMetadataSchema } from "@stigmer/protos/ai/stigmer/commons/apiresource/metadata_pb";
51
+ import { ExecutionRecord, bindHermeticClient, runActivityHermetically, } from "../../../__test-utils__/hermetic-activity.js";
52
+ import { _resetAgentSessionCacheForTests } from "../agent-session-cache.js";
53
+ import { _resetPricingCache } from "../model-pricing-data.js";
54
+ import { resetCatalogCacheForTests } from "../service-tier.js";
55
+ import { _resetRegistryCache } from "../../../shared/model-registry.js";
56
+ import { ScriptedCursorSdk, bindScriptedSdk } from "./scripted-sdk.js";
57
+ // ---------------------------------------------------------------------------
58
+ // Fixture ids — fixed so goldens are readable and byte-stable
59
+ // ---------------------------------------------------------------------------
60
+ export const FIXTURE = {
61
+ org: "hermetic-org",
62
+ executionId: "aex_hermetic_0001",
63
+ sessionId: "ses_hermetic_0001",
64
+ agentInstanceId: "ain_hermetic_0001",
65
+ agentId: "agt_hermetic_0001",
66
+ agentName: "hermetic-agent",
67
+ /** The pinned model; in the registry stub AND the SDK catalog below. */
68
+ model: "composer-2.5",
69
+ cursorApiKey: "hermetic-cursor-api-key",
70
+ };
71
+ /** The four resources of one execution, wired by id into a chain. */
72
+ export function cursorExecutionRecord(options) {
73
+ const execution = create(AgentExecutionSchema, {
74
+ metadata: create(ApiResourceMetadataSchema, {
75
+ id: FIXTURE.executionId,
76
+ org: FIXTURE.org,
77
+ name: FIXTURE.executionId,
78
+ }),
79
+ spec: create(AgentExecutionSpecSchema, {
80
+ sessionId: FIXTURE.sessionId,
81
+ message: options.message,
82
+ autoApproveAll: options.autoApproveAll ?? false,
83
+ executionConfig: create(ExecutionConfigSchema, {
84
+ modelName: options.modelName ?? FIXTURE.model,
85
+ }),
86
+ }),
87
+ });
88
+ const session = create(SessionSchema, {
89
+ metadata: create(ApiResourceMetadataSchema, {
90
+ id: FIXTURE.sessionId,
91
+ org: FIXTURE.org,
92
+ name: FIXTURE.sessionId,
93
+ }),
94
+ spec: create(SessionSpecSchema, {
95
+ agentInstanceId: FIXTURE.agentInstanceId,
96
+ workspaceEntries: options.workspaceEntries ?? [],
97
+ }),
98
+ });
99
+ const agentInstance = create(AgentInstanceSchema, {
100
+ metadata: create(ApiResourceMetadataSchema, {
101
+ id: FIXTURE.agentInstanceId,
102
+ org: FIXTURE.org,
103
+ name: FIXTURE.agentInstanceId,
104
+ }),
105
+ spec: create(AgentInstanceSpecSchema, { agentId: FIXTURE.agentId }),
106
+ });
107
+ const agent = create(AgentSchema, {
108
+ metadata: create(ApiResourceMetadataSchema, {
109
+ id: FIXTURE.agentId,
110
+ org: FIXTURE.org,
111
+ name: FIXTURE.agentName,
112
+ }),
113
+ spec: create(AgentSpecSchema, {
114
+ description: "Hermetic fixture agent",
115
+ instructions: options.instructions ?? "You are the hermetic fixture agent. Answer briefly.",
116
+ }),
117
+ });
118
+ return new ExecutionRecord({ execution, session, agentInstance, agent });
119
+ }
120
+ // ---------------------------------------------------------------------------
121
+ // The registry document and the SDK catalog
122
+ // ---------------------------------------------------------------------------
123
+ /**
124
+ * The model registry document both readers parse (`parsePricingTable` wants
125
+ * `harness: "cursor"` + `pricing`; `parseRegistry` wants `id` + `provider` and
126
+ * reads `capabilities.vision`). One entry, the fixture model, priced at round
127
+ * numbers so the golden's `estimatedCostUsd` is legible.
128
+ */
129
+ export const REGISTRY_DOCUMENT = {
130
+ models: [
131
+ {
132
+ id: FIXTURE.model,
133
+ displayName: "Composer 2.5 (hermetic fixture)",
134
+ provider: "cursor",
135
+ harness: "cursor",
136
+ costTier: "standard",
137
+ featured: true,
138
+ capabilities: { vision: true },
139
+ pricing: {
140
+ inputPricePerMillion: 1.0,
141
+ outputPricePerMillion: 4.0,
142
+ cacheWritePricePerMillion: 1.0,
143
+ cacheReadPricePerMillion: 0.1,
144
+ },
145
+ pricingVariants: {
146
+ fast: {
147
+ inputPricePerMillion: 3.0,
148
+ outputPricePerMillion: 12.0,
149
+ cacheWritePricePerMillion: 3.0,
150
+ cacheReadPricePerMillion: 0.3,
151
+ },
152
+ },
153
+ },
154
+ ],
155
+ };
156
+ /** The SDK catalog entry for the fixture model: both pinnable params declared. */
157
+ export const SDK_CATALOG = [
158
+ {
159
+ id: FIXTURE.model,
160
+ displayName: "Composer 2.5",
161
+ parameters: [
162
+ { id: "fast", values: [{ value: "true" }, { value: "false" }] },
163
+ { id: "thinking", values: [{ value: "true" }, { value: "false" }] },
164
+ ],
165
+ },
166
+ ];
167
+ /**
168
+ * Stub `fetch` to answer the registry document and refuse everything else.
169
+ * Returns the URLs fetched, for the "no other network" assertion.
170
+ */
171
+ export function stubRegistryFetch() {
172
+ const urls = [];
173
+ vi.stubGlobal("fetch", vi.fn(async (input) => {
174
+ const url = typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
175
+ urls.push(url);
176
+ if (!url.includes("/model-registry")) {
177
+ throw new Error(`hermetic run attempted a non-registry network call: ${url}`);
178
+ }
179
+ return { ok: true, status: 200, json: async () => REGISTRY_DOCUMENT };
180
+ }));
181
+ return { urls, restore: () => vi.unstubAllGlobals() };
182
+ }
183
+ // ---------------------------------------------------------------------------
184
+ // Config
185
+ // ---------------------------------------------------------------------------
186
+ /** The OSS/local runner posture: direct Cursor API key, no proxy, local mode. */
187
+ export function hermeticCursorConfig(env) {
188
+ return {
189
+ taskQueue: "hermetic-test-queue",
190
+ temporalAddress: "localhost:7233",
191
+ temporalNamespace: "default",
192
+ stigmerBackendEndpoint: "http://localhost:7234",
193
+ mcpBridgeEndpoint: null,
194
+ stigmerToken: null,
195
+ cursorApiKey: FIXTURE.cursorApiKey,
196
+ workspaceRootDir: env.workspaceRootDir,
197
+ mode: "local",
198
+ proxyEndpoint: null,
199
+ maxConcurrentActivities: 1,
200
+ idleTimeoutSeconds: null,
201
+ cloudModeEnabled: false,
202
+ checkpointerType: "memory",
203
+ checkpointerProxyEndpoint: null,
204
+ artifactProxyEndpoint: null,
205
+ primaryModel: FIXTURE.model,
206
+ cursorStreamStallTimeoutMs: 180_000,
207
+ agentResolveTimeoutMs: 120_000,
208
+ workspaceLockTimeoutMs: 900_000,
209
+ };
210
+ }
211
+ // ---------------------------------------------------------------------------
212
+ // The side effects the real SDK performs, for `effect` steps
213
+ // ---------------------------------------------------------------------------
214
+ /**
215
+ * The primary workspace directory a session with NO workspace entries runs in
216
+ * (`session-root.ts`: `<workspaceRootDir>/sessions/<sessionId>`).
217
+ */
218
+ export function sessionWorkspaceDir(env) {
219
+ return join(env.workspaceRootDir, "sessions", FIXTURE.sessionId);
220
+ }
221
+ /**
222
+ * Run the workspace's installed preToolUse hook exactly as the Cursor SDK does:
223
+ * read `<workspaceRoot>/.cursor/hooks.json`, take the `preToolUse` command the
224
+ * gate installed (an absolute path to the runner's own stable bash script under
225
+ * `~/.stigmer/hitl-gate/<key>/`), and run it with the hook input on stdin. The
226
+ * script resolves the CURRENT turn's state file and denial ledger from the
227
+ * active-turn pointer, walks its parent PIDs to confirm this process is the
228
+ * runner, and prints `{"permission":"allow"|"deny"}`. A deny appends to the
229
+ * ledger the activity's stream loop reads.
230
+ *
231
+ * This is the out-of-process half of deny-and-retry, driven by the real script
232
+ * against the real gate the activity installed — not a simulation of either.
233
+ */
234
+ export function runWorkspaceHook(workspaceRoot, hookInput) {
235
+ const hooksJsonPath = join(workspaceRoot, ".cursor", "hooks.json");
236
+ const parsed = JSON.parse(readFileSync(hooksJsonPath, "utf-8"));
237
+ const command = parsed.hooks?.preToolUse?.[0]?.command;
238
+ if (!command) {
239
+ throw new Error(`runWorkspaceHook: no preToolUse hook installed in ${hooksJsonPath}`);
240
+ }
241
+ const raw = execFileSync("bash", [command], { input: JSON.stringify(hookInput) }).toString();
242
+ const permission = raw.includes('"permission":"deny"')
243
+ ? "deny"
244
+ : raw.includes('"permission":"allow"')
245
+ ? "allow"
246
+ : "?";
247
+ return { permission, raw };
248
+ }
249
+ /**
250
+ * A git work tree with one committed file, for the file-review capture
251
+ * scenario. Author, committer and both dates are pinned so the commit AND tree
252
+ * object ids are byte-stable — a file-review golden may carry them.
253
+ */
254
+ export function initGitWorkspace(root, files) {
255
+ mkdirSync(root, { recursive: true });
256
+ const gitEnv = {
257
+ ...process.env,
258
+ GIT_AUTHOR_NAME: "hermetic",
259
+ GIT_AUTHOR_EMAIL: "hermetic@stigmer.test",
260
+ GIT_COMMITTER_NAME: "hermetic",
261
+ GIT_COMMITTER_EMAIL: "hermetic@stigmer.test",
262
+ GIT_AUTHOR_DATE: "2026-01-01T00:00:00Z",
263
+ GIT_COMMITTER_DATE: "2026-01-01T00:00:00Z",
264
+ };
265
+ const git = (args) => {
266
+ execFileSync("git", args, { cwd: root, env: gitEnv, stdio: "ignore" });
267
+ };
268
+ git(["init", "-q", "-b", "main"]);
269
+ for (const [rel, content] of Object.entries(files)) {
270
+ const abs = join(root, rel);
271
+ mkdirSync(dirname(abs), { recursive: true });
272
+ writeFileSync(abs, content, "utf-8");
273
+ }
274
+ git(["add", "-A"]);
275
+ git(["commit", "-q", "-m", "initial"]);
276
+ }
277
+ /** A session workspace entry mounting an absolute local path (local mode only). */
278
+ export function localPathEntry(name, path) {
279
+ return create(WorkspaceEntrySchema, {
280
+ name,
281
+ source: create(WorkspaceSourceSchema, {
282
+ source: { case: "localPath", value: create(LocalPathSourceSchema, { path }) },
283
+ }),
284
+ });
285
+ }
286
+ // ---------------------------------------------------------------------------
287
+ // Running a scenario
288
+ // ---------------------------------------------------------------------------
289
+ /**
290
+ * Drop every module-level cache the harness keeps across invocations. Called
291
+ * at the START of a scenario, never between its invocations: a deny-and-retry
292
+ * scenario relies on the parked agent surviving from turn 1 into turn 2 exactly
293
+ * as it does in a live worker.
294
+ */
295
+ export function resetCursorModuleState() {
296
+ _resetAgentSessionCacheForTests();
297
+ resetCatalogCacheForTests();
298
+ _resetPricingCache();
299
+ _resetRegistryCache();
300
+ }
301
+ /** Bind the record and the SDK for a scenario; resets the harness caches first. */
302
+ export function beginCursorScenario(options) {
303
+ resetCursorModuleState();
304
+ const sdk = new ScriptedCursorSdk(options.sdk);
305
+ bindScriptedSdk(sdk);
306
+ bindHermeticClient(options.record.client());
307
+ return { env: options.env, clock: options.clock, record: options.record, sdk };
308
+ }
309
+ /**
310
+ * Run ONE `ExecuteCursor` invocation for the scenario. The activities are
311
+ * constructed per invocation (the factory constructs its client, which is the
312
+ * one bound at `beginCursorScenario`).
313
+ */
314
+ export async function runCursorTurn(scenario, options = {}) {
315
+ // Imported lazily so the scenario file's `vi.mock` declarations are in
316
+ // force before the activity module (and, through it, `@cursor/sdk` and the
317
+ // client) is loaded.
318
+ const { createCursorActivities } = await import("../index.js");
319
+ const activities = createCursorActivities(hermeticCursorConfig(scenario.env));
320
+ // The typed wire shape the control plane's workflow sends (activity-input.ts).
321
+ const input = {
322
+ execution_id: scenario.record.executionId,
323
+ thread_id: options.threadId ?? "",
324
+ turn_seq: options.turnSeq ?? 0,
325
+ };
326
+ return runActivityHermetically(activities.ExecuteCursor, [input], {
327
+ taskQueue: "hermetic-test-queue",
328
+ onControls: options.onControls,
329
+ });
330
+ }
331
+ //# sourceMappingURL=hermetic-cursor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hermetic-cursor.js","sourceRoot":"","sources":["../../../../src/activities/execute-cursor/__test-utils__/hermetic-cursor.ts"],"names":[],"mappings":"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"}