@stigmer/runner 3.1.3 → 3.1.5
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/.build-fingerprint +1 -1
- package/dist/activities/execute-cursor/attachment-resolver.js +1 -1
- package/dist/activities/execute-cursor/attachment-resolver.js.map +1 -1
- package/dist/activities/execute-cursor/capture-flow.d.ts +26 -15
- package/dist/activities/execute-cursor/capture-flow.js +56 -18
- package/dist/activities/execute-cursor/capture-flow.js.map +1 -1
- package/dist/activities/execute-cursor/command-provenance.d.ts +11 -25
- package/dist/activities/execute-cursor/command-provenance.js +25 -115
- package/dist/activities/execute-cursor/command-provenance.js.map +1 -1
- package/dist/activities/execute-cursor/index.js +297 -478
- package/dist/activities/execute-cursor/index.js.map +1 -1
- package/dist/activities/execute-cursor/skill-resolver.js +1 -1
- package/dist/activities/execute-cursor/skill-resolver.js.map +1 -1
- package/dist/activities/execute-cursor/todo-tracker.d.ts +6 -1
- package/dist/activities/execute-cursor/todo-tracker.js +15 -43
- package/dist/activities/execute-cursor/todo-tracker.js.map +1 -1
- package/dist/activities/execute-cursor/turn-stream.d.ts +141 -0
- package/dist/activities/execute-cursor/turn-stream.js +249 -0
- package/dist/activities/execute-cursor/turn-stream.js.map +1 -0
- package/dist/activities/execute-deep-agent/command-provenance.d.ts +61 -0
- package/dist/activities/execute-deep-agent/command-provenance.js +72 -0
- package/dist/activities/execute-deep-agent/command-provenance.js.map +1 -0
- package/dist/activities/execute-deep-agent/index.js +88 -20
- package/dist/activities/execute-deep-agent/index.js.map +1 -1
- package/dist/activities/execute-deep-agent/status-builder.js +8 -1
- package/dist/activities/execute-deep-agent/status-builder.js.map +1 -1
- package/dist/activities/execute-deep-agent/v3-status-builder.js +12 -1
- package/dist/activities/execute-deep-agent/v3-status-builder.js.map +1 -1
- package/dist/activities/execute-deep-agent/writeback-coordinator.js +5 -1
- package/dist/activities/execute-deep-agent/writeback-coordinator.js.map +1 -1
- package/dist/otel.js +10 -0
- package/dist/otel.js.map +1 -1
- package/dist/shared/filereview/cas-progress.d.ts +63 -0
- package/dist/shared/filereview/cas-progress.js +128 -0
- package/dist/shared/filereview/cas-progress.js.map +1 -0
- package/dist/shared/filereview/cas-substrate.d.ts +29 -0
- package/dist/shared/filereview/cas-substrate.js +46 -21
- package/dist/shared/filereview/cas-substrate.js.map +1 -1
- package/dist/shared/filereview/command-provenance.d.ts +93 -0
- package/dist/shared/filereview/command-provenance.js +132 -0
- package/dist/shared/filereview/command-provenance.js.map +1 -0
- package/dist/shared/filereview/git-substrate.d.ts +9 -3
- package/dist/shared/filereview/git-substrate.js +4 -0
- package/dist/shared/filereview/git-substrate.js.map +1 -1
- package/dist/shared/filereview/index.d.ts +4 -3
- package/dist/shared/filereview/index.js +3 -2
- package/dist/shared/filereview/index.js.map +1 -1
- package/dist/shared/filereview/progress.d.ts +105 -34
- package/dist/shared/filereview/progress.js +96 -34
- package/dist/shared/filereview/progress.js.map +1 -1
- package/dist/shared/plan-mode-prompt.d.ts +9 -0
- package/dist/shared/plan-mode-prompt.js +18 -0
- package/dist/shared/plan-mode-prompt.js.map +1 -1
- package/dist/shared/todos.d.ts +56 -0
- package/dist/shared/todos.js +98 -0
- package/dist/shared/todos.js.map +1 -0
- package/dist/shared/tool-row.d.ts +16 -0
- package/dist/shared/tool-row.js +31 -0
- package/dist/shared/tool-row.js.map +1 -1
- package/dist/shared/workspace/git-identity.d.ts +36 -0
- package/dist/shared/workspace/git-identity.js +39 -0
- package/dist/shared/workspace/git-identity.js.map +1 -0
- package/dist/shared/workspace/local-backend.d.ts +6 -2
- package/dist/shared/workspace/local-backend.js +6 -2
- package/dist/shared/workspace/local-backend.js.map +1 -1
- package/dist/shared/workspace/stigmer-link.d.ts +54 -0
- package/dist/shared/workspace/stigmer-link.js +92 -0
- package/dist/shared/workspace/stigmer-link.js.map +1 -0
- package/dist/shared/workspace/types.d.ts +6 -4
- package/package.json +2 -2
- package/src/__tests__/otel-turn-span.test.ts +61 -0
- package/src/activities/execute-cursor/__tests__/progress-substrate.test.ts +169 -0
- package/src/activities/execute-cursor/__tests__/turn-stream.test.ts +349 -0
- package/src/activities/execute-cursor/attachment-resolver.ts +1 -1
- package/src/activities/execute-cursor/capture-flow.ts +71 -25
- package/src/activities/execute-cursor/command-provenance.ts +25 -120
- package/src/activities/execute-cursor/index.ts +345 -505
- package/src/activities/execute-cursor/skill-resolver.ts +1 -1
- package/src/activities/execute-cursor/todo-tracker.ts +17 -59
- package/src/activities/execute-cursor/turn-stream.ts +418 -0
- package/src/activities/execute-deep-agent/__tests__/command-provenance.test.ts +252 -0
- package/src/activities/execute-deep-agent/__tests__/status-builder.test.ts +78 -0
- package/src/activities/execute-deep-agent/__tests__/v3-status-builder.test.ts +105 -1
- package/src/activities/execute-deep-agent/__tests__/writeback-coordinator.test.ts +30 -3
- package/src/activities/execute-deep-agent/command-provenance.ts +102 -0
- package/src/activities/execute-deep-agent/index.ts +107 -20
- package/src/activities/execute-deep-agent/status-builder.ts +9 -0
- package/src/activities/execute-deep-agent/v3-status-builder.ts +13 -0
- package/src/activities/execute-deep-agent/writeback-coordinator.ts +5 -1
- package/src/otel.ts +8 -0
- package/src/shared/__tests__/todos.test.ts +216 -0
- package/src/shared/filereview/__tests__/cas-progress.test.ts +228 -0
- package/src/shared/filereview/__tests__/cas-substrate.test.ts +66 -0
- package/src/shared/filereview/__tests__/command-provenance.test.ts +252 -0
- package/src/shared/filereview/__tests__/progress.test.ts +112 -10
- package/src/shared/filereview/cas-progress.ts +170 -0
- package/src/shared/filereview/cas-substrate.ts +69 -24
- package/src/shared/filereview/command-provenance.ts +180 -0
- package/src/shared/filereview/git-substrate.ts +13 -3
- package/src/shared/filereview/index.ts +15 -1
- package/src/shared/filereview/progress.ts +171 -47
- package/src/shared/plan-mode-prompt.ts +18 -0
- package/src/shared/todos.ts +126 -0
- package/src/shared/tool-row.ts +34 -0
- package/src/shared/workspace/__tests__/git-identity.test.ts +124 -0
- package/src/shared/workspace/__tests__/stigmer-link.test.ts +173 -0
- package/src/shared/workspace/git-identity.ts +41 -0
- package/src/shared/workspace/local-backend.ts +6 -2
- package/src/shared/workspace/stigmer-link.ts +97 -0
- package/src/shared/workspace/types.ts +6 -4
- package/dist/activities/execute-cursor/stigmer-link.d.ts +0 -35
- package/dist/activities/execute-cursor/stigmer-link.js +0 -73
- package/dist/activities/execute-cursor/stigmer-link.js.map +0 -1
- package/src/activities/execute-cursor/stigmer-link.ts +0 -78
|
@@ -115,3 +115,19 @@ export declare function isToolCallRowHidden(tc: ToolCall): boolean;
|
|
|
115
115
|
* none; Cursor clones them in) — the snapshot reflects whatever is present.
|
|
116
116
|
*/
|
|
117
117
|
export declare function collectSubAgentToolCallIds(subAgents: readonly SubAgentExecution[]): Set<string>;
|
|
118
|
+
/**
|
|
119
|
+
* Collect the ids of tool-call rows that have already SETTLED (reached a terminal
|
|
120
|
+
* state: completed, failed, or skipped) in a transcript.
|
|
121
|
+
*
|
|
122
|
+
* The deep-agent turn-boundary provenance derivation (DD-28) snapshots this
|
|
123
|
+
* BEFORE a turn's stream to scope "this turn's tool calls" by identity: a call
|
|
124
|
+
* whose id is absent from the snapshot is this-turn's — either freshly streamed,
|
|
125
|
+
* or a prior gate that was WAITING_APPROVAL before the stream and executes now on
|
|
126
|
+
* resume (StatusBuilder updates the seeded row in place, so it keeps its id).
|
|
127
|
+
* Unlike the Cursor harness, the deep-agent cannot scope positionally — an
|
|
128
|
+
* approved command executes at its SEEDED position — so identity is the only
|
|
129
|
+
* correct scope, mirroring {@link collectSubAgentToolCallIds}. Terminal (not just
|
|
130
|
+
* completed) so a PRIOR turn's failed/skipped non-shell call is excluded and
|
|
131
|
+
* cannot spuriously disqualify this turn.
|
|
132
|
+
*/
|
|
133
|
+
export declare function collectSettledToolCallIds(messages: readonly AgentMessage[]): Set<string>;
|
package/dist/shared/tool-row.js
CHANGED
|
@@ -173,4 +173,35 @@ export function collectSubAgentToolCallIds(subAgents) {
|
|
|
173
173
|
}
|
|
174
174
|
return ids;
|
|
175
175
|
}
|
|
176
|
+
/** Terminal tool-call statuses — a row that has finished (however it finished). */
|
|
177
|
+
const TERMINAL_TOOL_CALL_STATUSES = new Set([
|
|
178
|
+
ToolCallStatus.TOOL_CALL_COMPLETED,
|
|
179
|
+
ToolCallStatus.TOOL_CALL_FAILED,
|
|
180
|
+
ToolCallStatus.TOOL_CALL_SKIPPED,
|
|
181
|
+
]);
|
|
182
|
+
/**
|
|
183
|
+
* Collect the ids of tool-call rows that have already SETTLED (reached a terminal
|
|
184
|
+
* state: completed, failed, or skipped) in a transcript.
|
|
185
|
+
*
|
|
186
|
+
* The deep-agent turn-boundary provenance derivation (DD-28) snapshots this
|
|
187
|
+
* BEFORE a turn's stream to scope "this turn's tool calls" by identity: a call
|
|
188
|
+
* whose id is absent from the snapshot is this-turn's — either freshly streamed,
|
|
189
|
+
* or a prior gate that was WAITING_APPROVAL before the stream and executes now on
|
|
190
|
+
* resume (StatusBuilder updates the seeded row in place, so it keeps its id).
|
|
191
|
+
* Unlike the Cursor harness, the deep-agent cannot scope positionally — an
|
|
192
|
+
* approved command executes at its SEEDED position — so identity is the only
|
|
193
|
+
* correct scope, mirroring {@link collectSubAgentToolCallIds}. Terminal (not just
|
|
194
|
+
* completed) so a PRIOR turn's failed/skipped non-shell call is excluded and
|
|
195
|
+
* cannot spuriously disqualify this turn.
|
|
196
|
+
*/
|
|
197
|
+
export function collectSettledToolCallIds(messages) {
|
|
198
|
+
const ids = new Set();
|
|
199
|
+
for (const msg of messages) {
|
|
200
|
+
for (const tc of msg.toolCalls) {
|
|
201
|
+
if (TERMINAL_TOOL_CALL_STATUSES.has(tc.status))
|
|
202
|
+
ids.add(tc.id);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return ids;
|
|
206
|
+
}
|
|
176
207
|
//# sourceMappingURL=tool-row.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-row.js","sourceRoot":"","sources":["../../src/shared/tool-row.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"tool-row.js","sourceRoot":"","sources":["../../src/shared/tool-row.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The public git identity for commits the agent authors on the user's behalf.
|
|
3
|
+
*
|
|
4
|
+
* Write-back commits (branch/commit/push/PR — see WriteBackCoordinator) land
|
|
5
|
+
* on real branches in the user's repository, so they carry a dedicated,
|
|
6
|
+
* recognizable agent identity in every mode — local and cloud alike. This is
|
|
7
|
+
* deliberate: a commit authored by the agent should never be silently
|
|
8
|
+
* attributed to whatever identity happens to live in the host's `~/.gitconfig`
|
|
9
|
+
* (local), and the cloud sandbox has no identity at all, which makes a bare
|
|
10
|
+
* `git commit` fail with "Author identity unknown".
|
|
11
|
+
*
|
|
12
|
+
* Distinct from the *internal* snapshot identity in
|
|
13
|
+
* `../filereview/git-substrate.ts` (`stigmer-runner <runner@stigmer.local>`):
|
|
14
|
+
* those commit objects are never on a branch and never pushed — they exist
|
|
15
|
+
* only to pin trees against GC. This identity is the public-facing one that
|
|
16
|
+
* appears in `git log`, on GitHub, and in pull requests.
|
|
17
|
+
*/
|
|
18
|
+
export declare const AGENT_GIT_AUTHOR_NAME = "Stigmer Agent";
|
|
19
|
+
export declare const AGENT_GIT_AUTHOR_EMAIL = "noreply@stigmer.ai";
|
|
20
|
+
/**
|
|
21
|
+
* `git -c` config flags that pin the agent identity for a single command.
|
|
22
|
+
*
|
|
23
|
+
* Per-command `-c` flags (rather than repo-local or global `git config`) keep
|
|
24
|
+
* the identity deterministic in every environment without mutating the user's
|
|
25
|
+
* repository config — the same never-mutate reasoning documented on
|
|
26
|
+
* `SNAPSHOT_IDENTITY_ENV` in `git-substrate.ts`. Env-var injection is not an
|
|
27
|
+
* option here: `WorkspaceBackend.execute()` takes no env parameter, and
|
|
28
|
+
* widening that contract for one caller would be a larger change than the
|
|
29
|
+
* problem deserves.
|
|
30
|
+
*/
|
|
31
|
+
export declare const AGENT_GIT_IDENTITY_FLAGS = "-c user.name='Stigmer Agent' -c user.email='noreply@stigmer.ai'";
|
|
32
|
+
/**
|
|
33
|
+
* Build a `git commit` command that is always authored by the agent identity,
|
|
34
|
+
* regardless of what identity (if any) the surrounding environment provides.
|
|
35
|
+
*/
|
|
36
|
+
export declare function gitCommitAsAgent(commitMsg: string): string;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The public git identity for commits the agent authors on the user's behalf.
|
|
3
|
+
*
|
|
4
|
+
* Write-back commits (branch/commit/push/PR — see WriteBackCoordinator) land
|
|
5
|
+
* on real branches in the user's repository, so they carry a dedicated,
|
|
6
|
+
* recognizable agent identity in every mode — local and cloud alike. This is
|
|
7
|
+
* deliberate: a commit authored by the agent should never be silently
|
|
8
|
+
* attributed to whatever identity happens to live in the host's `~/.gitconfig`
|
|
9
|
+
* (local), and the cloud sandbox has no identity at all, which makes a bare
|
|
10
|
+
* `git commit` fail with "Author identity unknown".
|
|
11
|
+
*
|
|
12
|
+
* Distinct from the *internal* snapshot identity in
|
|
13
|
+
* `../filereview/git-substrate.ts` (`stigmer-runner <runner@stigmer.local>`):
|
|
14
|
+
* those commit objects are never on a branch and never pushed — they exist
|
|
15
|
+
* only to pin trees against GC. This identity is the public-facing one that
|
|
16
|
+
* appears in `git log`, on GitHub, and in pull requests.
|
|
17
|
+
*/
|
|
18
|
+
export const AGENT_GIT_AUTHOR_NAME = "Stigmer Agent";
|
|
19
|
+
export const AGENT_GIT_AUTHOR_EMAIL = "noreply@stigmer.ai";
|
|
20
|
+
/**
|
|
21
|
+
* `git -c` config flags that pin the agent identity for a single command.
|
|
22
|
+
*
|
|
23
|
+
* Per-command `-c` flags (rather than repo-local or global `git config`) keep
|
|
24
|
+
* the identity deterministic in every environment without mutating the user's
|
|
25
|
+
* repository config — the same never-mutate reasoning documented on
|
|
26
|
+
* `SNAPSHOT_IDENTITY_ENV` in `git-substrate.ts`. Env-var injection is not an
|
|
27
|
+
* option here: `WorkspaceBackend.execute()` takes no env parameter, and
|
|
28
|
+
* widening that contract for one caller would be a larger change than the
|
|
29
|
+
* problem deserves.
|
|
30
|
+
*/
|
|
31
|
+
export const AGENT_GIT_IDENTITY_FLAGS = `-c user.name='${AGENT_GIT_AUTHOR_NAME}' -c user.email='${AGENT_GIT_AUTHOR_EMAIL}'`;
|
|
32
|
+
/**
|
|
33
|
+
* Build a `git commit` command that is always authored by the agent identity,
|
|
34
|
+
* regardless of what identity (if any) the surrounding environment provides.
|
|
35
|
+
*/
|
|
36
|
+
export function gitCommitAsAgent(commitMsg) {
|
|
37
|
+
return `git ${AGENT_GIT_IDENTITY_FLAGS} commit -m "${commitMsg}"`;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=git-identity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-identity.js","sourceRoot":"","sources":["../../../src/shared/workspace/git-identity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,eAAe,CAAC;AACrD,MAAM,CAAC,MAAM,sBAAsB,GAAG,oBAAoB,CAAC;AAE3D;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,wBAAwB,GACnC,iBAAiB,qBAAqB,oBAAoB,sBAAsB,GAAG,CAAC;AAEtF;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,SAAiB;IAChD,OAAO,OAAO,wBAAwB,eAAe,SAAS,GAAG,CAAC;AACpE,CAAC"}
|
|
@@ -6,8 +6,12 @@
|
|
|
6
6
|
* sandbox) backend will be added in Phase 3.
|
|
7
7
|
*
|
|
8
8
|
* When `platformDir` is provided, paths under `.stigmer/` are
|
|
9
|
-
* transparently routed to the platform directory
|
|
10
|
-
*
|
|
9
|
+
* transparently routed to the platform directory, keeping platform files
|
|
10
|
+
* out of the workspace tree. This routing serves the RUNNER's own I/O
|
|
11
|
+
* (skill/attachment materialization, `execute` command rewriting) — the
|
|
12
|
+
* agent's file tools do not go through this backend. Agent-visible reads
|
|
13
|
+
* of `.stigmer/…` reach the same physical files through the per-turn
|
|
14
|
+
* workspace symlink instead (see shared/workspace/stigmer-link.ts).
|
|
11
15
|
*/
|
|
12
16
|
import type { WorkspaceBackend } from "./types.js";
|
|
13
17
|
export declare class LocalWorkspaceBackend implements WorkspaceBackend {
|
|
@@ -6,8 +6,12 @@
|
|
|
6
6
|
* sandbox) backend will be added in Phase 3.
|
|
7
7
|
*
|
|
8
8
|
* When `platformDir` is provided, paths under `.stigmer/` are
|
|
9
|
-
* transparently routed to the platform directory
|
|
10
|
-
*
|
|
9
|
+
* transparently routed to the platform directory, keeping platform files
|
|
10
|
+
* out of the workspace tree. This routing serves the RUNNER's own I/O
|
|
11
|
+
* (skill/attachment materialization, `execute` command rewriting) — the
|
|
12
|
+
* agent's file tools do not go through this backend. Agent-visible reads
|
|
13
|
+
* of `.stigmer/…` reach the same physical files through the per-turn
|
|
14
|
+
* workspace symlink instead (see shared/workspace/stigmer-link.ts).
|
|
11
15
|
*/
|
|
12
16
|
import { execFile } from "node:child_process";
|
|
13
17
|
import { readFile, writeFile, access, mkdir } from "node:fs/promises";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local-backend.js","sourceRoot":"","sources":["../../../src/shared/workspace/local-backend.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"local-backend.js","sourceRoot":"","sources":["../../../src/shared/workspace/local-backend.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The workspace `.stigmer` symlink — the bridge from the session's workspace
|
|
3
|
+
* to its platform-managed directory (~/.stigmer/sessions/{id}/platform/, see
|
|
4
|
+
* platform-dir.ts), shared by BOTH harnesses.
|
|
5
|
+
*
|
|
6
|
+
* Platform-injected content (skills, attachment inputs, the approved plan)
|
|
7
|
+
* physically lives in the platform dir, outside the workspace, so a real repo
|
|
8
|
+
* is never polluted with Stigmer files (issue #173). But the agent reads from
|
|
9
|
+
* the workspace: the Cursor SDK resolves paths against the workspace CWD, and
|
|
10
|
+
* the native (deepagents) harness's file tools resolve against a
|
|
11
|
+
* `FilesystemBackend` rooted at the workspace. The symlink is what makes the
|
|
12
|
+
* `.stigmer/…` paths those agents are prompted with (skill locations,
|
|
13
|
+
* `.stigmer/inputs/…` attachments) actually resolve.
|
|
14
|
+
*
|
|
15
|
+
* Lifecycle contract (same for both harnesses):
|
|
16
|
+
* - Created per turn, under the workspace turn lock — the link is a
|
|
17
|
+
* working-tree mutation, and re-pointing it while another session's turn is
|
|
18
|
+
* running on a shared tree would redirect that turn's reads mid-flight.
|
|
19
|
+
* Cursor creates it in its skill/attachment resolvers (which run after lock
|
|
20
|
+
* acquisition); the native harness creates it right after acquiring the
|
|
21
|
+
* lock (execute-deep-agent/index.ts).
|
|
22
|
+
* - Removed at turn end ({@link removeStigmerSymlink} in the activity's
|
|
23
|
+
* cleanup), so a real repo is left untouched once the turn ends; a
|
|
24
|
+
* multi-turn session recreates the link on the next turn.
|
|
25
|
+
* - {@link ensureStigmerSymlink} is idempotent, so multiple populaters may
|
|
26
|
+
* run in any order within a turn.
|
|
27
|
+
*
|
|
28
|
+
* OWNERSHIP SHARP EDGE: the platform owns the `.stigmer` name inside a
|
|
29
|
+
* workspace. {@link ensureStigmerSymlink} REPLACES a real (non-symlink)
|
|
30
|
+
* `.stigmer` directory it finds there — deliberate, so a directory left
|
|
31
|
+
* behind by an older runner can never shadow the platform mount. (A user's
|
|
32
|
+
* own `.stigmer` content is unreachable anyway: the runner's
|
|
33
|
+
* `LocalWorkspaceBackend` routes every `.stigmer/…` path to the platform
|
|
34
|
+
* dir.) Turn-end removal is the conservative half: it only ever removes a
|
|
35
|
+
* SYMLINK.
|
|
36
|
+
*/
|
|
37
|
+
/** The workspace-visible name of the platform namespace. */
|
|
38
|
+
export declare const STIGMER_LOCAL_STATE_DIR = ".stigmer";
|
|
39
|
+
/**
|
|
40
|
+
* Ensure the workspace `.stigmer` symlink points to the platform dir.
|
|
41
|
+
* Idempotent: an existing correct link is kept; a stale link (or a non-link
|
|
42
|
+
* left behind by an older runner) is replaced.
|
|
43
|
+
*/
|
|
44
|
+
export declare function ensureStigmerSymlink(workspaceDir: string, platformDir: string): Promise<void>;
|
|
45
|
+
/**
|
|
46
|
+
* Remove the workspace `.stigmer` symlink created by
|
|
47
|
+
* {@link ensureStigmerSymlink}.
|
|
48
|
+
*
|
|
49
|
+
* Called in the activity's cleanup so attaching a real repo leaves no Stigmer
|
|
50
|
+
* symlink behind once the turn ends (issue #173). Only ever removes a
|
|
51
|
+
* SYMLINK — a real `.stigmer` directory (which would be the user's own, not
|
|
52
|
+
* ours) is left untouched. Best-effort.
|
|
53
|
+
*/
|
|
54
|
+
export declare function removeStigmerSymlink(workspaceDir: string): Promise<void>;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The workspace `.stigmer` symlink — the bridge from the session's workspace
|
|
3
|
+
* to its platform-managed directory (~/.stigmer/sessions/{id}/platform/, see
|
|
4
|
+
* platform-dir.ts), shared by BOTH harnesses.
|
|
5
|
+
*
|
|
6
|
+
* Platform-injected content (skills, attachment inputs, the approved plan)
|
|
7
|
+
* physically lives in the platform dir, outside the workspace, so a real repo
|
|
8
|
+
* is never polluted with Stigmer files (issue #173). But the agent reads from
|
|
9
|
+
* the workspace: the Cursor SDK resolves paths against the workspace CWD, and
|
|
10
|
+
* the native (deepagents) harness's file tools resolve against a
|
|
11
|
+
* `FilesystemBackend` rooted at the workspace. The symlink is what makes the
|
|
12
|
+
* `.stigmer/…` paths those agents are prompted with (skill locations,
|
|
13
|
+
* `.stigmer/inputs/…` attachments) actually resolve.
|
|
14
|
+
*
|
|
15
|
+
* Lifecycle contract (same for both harnesses):
|
|
16
|
+
* - Created per turn, under the workspace turn lock — the link is a
|
|
17
|
+
* working-tree mutation, and re-pointing it while another session's turn is
|
|
18
|
+
* running on a shared tree would redirect that turn's reads mid-flight.
|
|
19
|
+
* Cursor creates it in its skill/attachment resolvers (which run after lock
|
|
20
|
+
* acquisition); the native harness creates it right after acquiring the
|
|
21
|
+
* lock (execute-deep-agent/index.ts).
|
|
22
|
+
* - Removed at turn end ({@link removeStigmerSymlink} in the activity's
|
|
23
|
+
* cleanup), so a real repo is left untouched once the turn ends; a
|
|
24
|
+
* multi-turn session recreates the link on the next turn.
|
|
25
|
+
* - {@link ensureStigmerSymlink} is idempotent, so multiple populaters may
|
|
26
|
+
* run in any order within a turn.
|
|
27
|
+
*
|
|
28
|
+
* OWNERSHIP SHARP EDGE: the platform owns the `.stigmer` name inside a
|
|
29
|
+
* workspace. {@link ensureStigmerSymlink} REPLACES a real (non-symlink)
|
|
30
|
+
* `.stigmer` directory it finds there — deliberate, so a directory left
|
|
31
|
+
* behind by an older runner can never shadow the platform mount. (A user's
|
|
32
|
+
* own `.stigmer` content is unreachable anyway: the runner's
|
|
33
|
+
* `LocalWorkspaceBackend` routes every `.stigmer/…` path to the platform
|
|
34
|
+
* dir.) Turn-end removal is the conservative half: it only ever removes a
|
|
35
|
+
* SYMLINK.
|
|
36
|
+
*/
|
|
37
|
+
import { symlink, readlink, unlink, rm, lstat } from "node:fs/promises";
|
|
38
|
+
import { join } from "node:path";
|
|
39
|
+
/** The workspace-visible name of the platform namespace. */
|
|
40
|
+
export const STIGMER_LOCAL_STATE_DIR = ".stigmer";
|
|
41
|
+
/**
|
|
42
|
+
* Ensure the workspace `.stigmer` symlink points to the platform dir.
|
|
43
|
+
* Idempotent: an existing correct link is kept; a stale link (or a non-link
|
|
44
|
+
* left behind by an older runner) is replaced.
|
|
45
|
+
*/
|
|
46
|
+
export async function ensureStigmerSymlink(workspaceDir, platformDir) {
|
|
47
|
+
const linkPath = join(workspaceDir, STIGMER_LOCAL_STATE_DIR);
|
|
48
|
+
try {
|
|
49
|
+
const existing = await readlink(linkPath);
|
|
50
|
+
if (existing === platformDir)
|
|
51
|
+
return;
|
|
52
|
+
await unlink(linkPath);
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
if (err.code === "ENOENT") {
|
|
56
|
+
// No existing symlink
|
|
57
|
+
}
|
|
58
|
+
else if (err.code === "EINVAL") {
|
|
59
|
+
// Exists but is not a symlink — remove the directory
|
|
60
|
+
await rm(linkPath, { recursive: true, force: true });
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
throw err;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
await symlink(platformDir, linkPath, "dir");
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Remove the workspace `.stigmer` symlink created by
|
|
70
|
+
* {@link ensureStigmerSymlink}.
|
|
71
|
+
*
|
|
72
|
+
* Called in the activity's cleanup so attaching a real repo leaves no Stigmer
|
|
73
|
+
* symlink behind once the turn ends (issue #173). Only ever removes a
|
|
74
|
+
* SYMLINK — a real `.stigmer` directory (which would be the user's own, not
|
|
75
|
+
* ours) is left untouched. Best-effort.
|
|
76
|
+
*/
|
|
77
|
+
export async function removeStigmerSymlink(workspaceDir) {
|
|
78
|
+
const linkPath = join(workspaceDir, STIGMER_LOCAL_STATE_DIR);
|
|
79
|
+
try {
|
|
80
|
+
const stat = await lstat(linkPath);
|
|
81
|
+
if (stat.isSymbolicLink()) {
|
|
82
|
+
await unlink(linkPath);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
catch (err) {
|
|
86
|
+
if (err?.code !== "ENOENT") {
|
|
87
|
+
console.warn(`removeStigmerSymlink: failed to remove ${linkPath} (non-fatal): ` +
|
|
88
|
+
`${err instanceof Error ? err.message : err}`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=stigmer-link.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stigmer-link.js","sourceRoot":"","sources":["../../../src/shared/workspace/stigmer-link.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACxE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,4DAA4D;AAC5D,MAAM,CAAC,MAAM,uBAAuB,GAAG,UAAU,CAAC;AAElD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,YAAoB,EACpB,WAAmB;IAEnB,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,EAAE,uBAAuB,CAAC,CAAC;IAE7D,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAC1C,IAAI,QAAQ,KAAK,WAAW;YAAE,OAAO;QACrC,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC;IACzB,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC1B,sBAAsB;QACxB,CAAC;aAAM,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACjC,qDAAqD;YACrD,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACvD,CAAC;aAAM,CAAC;YACN,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;IAED,MAAM,OAAO,CAAC,WAAW,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;AAC9C,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,YAAoB;IAC7D,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,EAAE,uBAAuB,CAAC,CAAC;IAC7D,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,QAAQ,CAAC,CAAC;QACnC,IAAI,IAAI,CAAC,cAAc,EAAE,EAAE,CAAC;YAC1B,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC;QACzB,CAAC;IACH,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,IAAI,GAAG,EAAE,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC3B,OAAO,CAAC,IAAI,CACV,0CAA0C,QAAQ,gBAAgB;gBAClE,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAC9C,CAAC;QACJ,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -40,10 +40,12 @@ export declare class WorkspaceProvisionError extends Error {
|
|
|
40
40
|
* commands route through the Daytona sandbox proxy.
|
|
41
41
|
*
|
|
42
42
|
* When `platformDir` is set, paths under `.stigmer/` are transparently
|
|
43
|
-
* routed to the platform directory instead of the workspace root
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
* the agent
|
|
43
|
+
* routed to the platform directory instead of the workspace root, keeping
|
|
44
|
+
* platform files (skills, inputs) physically separate from the user's
|
|
45
|
+
* workspace. The routing covers the RUNNER's own reads/writes through
|
|
46
|
+
* this interface; the agent's file tools resolve against the workspace
|
|
47
|
+
* root and see the same files through the per-turn `.stigmer` symlink
|
|
48
|
+
* (see stigmer-link.ts).
|
|
47
49
|
*/
|
|
48
50
|
export interface WorkspaceBackend {
|
|
49
51
|
readonly rootDir: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stigmer/runner",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.5",
|
|
4
4
|
"description": "Embeddable Temporal worker for the Stigmer AI agent platform — handles agent execution, workflow orchestration, and MCP server management",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
"@opentelemetry/sdk-metrics": "^2.0.0",
|
|
86
86
|
"@opentelemetry/sdk-trace-base": "^2.0.0",
|
|
87
87
|
"@opentelemetry/sdk-trace-node": "^2.0.0",
|
|
88
|
-
"@stigmer/protos": "3.1.
|
|
88
|
+
"@stigmer/protos": "3.1.5",
|
|
89
89
|
"@temporalio/activity": "^1.11.0",
|
|
90
90
|
"@temporalio/client": "^1.11.0",
|
|
91
91
|
"@temporalio/common": "^1.11.0",
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
+
|
|
3
|
+
// Spy span/tracer, hoisted so the vi.mock factory (which runs before imports)
|
|
4
|
+
// can close over them without a temporal-dead-zone error.
|
|
5
|
+
const { spanEnd, spanSetAttribute, startSpan } = vi.hoisted(() => {
|
|
6
|
+
const spanEnd = vi.fn();
|
|
7
|
+
const spanSetAttribute = vi.fn();
|
|
8
|
+
const startSpan = vi.fn(() => ({ end: spanEnd, setAttribute: spanSetAttribute }));
|
|
9
|
+
return { spanEnd, spanSetAttribute, startSpan };
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
vi.mock("@opentelemetry/api", () => ({
|
|
13
|
+
trace: { getTracer: () => ({ startSpan }) },
|
|
14
|
+
}));
|
|
15
|
+
|
|
16
|
+
import {
|
|
17
|
+
startCursorTurnSpan,
|
|
18
|
+
ATTR_LLM_INPUT_TOKENS,
|
|
19
|
+
ATTR_LLM_OUTPUT_TOKENS,
|
|
20
|
+
} from "../otel.js";
|
|
21
|
+
|
|
22
|
+
const spanAttrs = { model: "gpt-x", mode: "local", sessionId: "sess-1" };
|
|
23
|
+
|
|
24
|
+
describe("startCursorTurnSpan", () => {
|
|
25
|
+
beforeEach(() => {
|
|
26
|
+
spanEnd.mockClear();
|
|
27
|
+
spanSetAttribute.mockClear();
|
|
28
|
+
startSpan.mockClear();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("records the input and output token attributes", async () => {
|
|
32
|
+
const span = await startCursorTurnSpan(spanAttrs);
|
|
33
|
+
span.setTokens(1200, 340);
|
|
34
|
+
expect(spanSetAttribute).toHaveBeenCalledWith(ATTR_LLM_INPUT_TOKENS, 1200);
|
|
35
|
+
expect(spanSetAttribute).toHaveBeenCalledWith(ATTR_LLM_OUTPUT_TOKENS, 340);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("omits zero-valued token attributes (no count = no attribute)", async () => {
|
|
39
|
+
const span = await startCursorTurnSpan(spanAttrs);
|
|
40
|
+
span.setTokens(0, 0);
|
|
41
|
+
expect(spanSetAttribute).not.toHaveBeenCalled();
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("ends the span exactly once even when end() is called repeatedly", async () => {
|
|
45
|
+
// finishTurnTelemetry is invoked from the activity's finally on every exit
|
|
46
|
+
// path; a second end() (e.g. a defensive double-invoke) must be a no-op so
|
|
47
|
+
// OTel never warns about ending an already-ended span.
|
|
48
|
+
const span = await startCursorTurnSpan(spanAttrs);
|
|
49
|
+
span.end();
|
|
50
|
+
span.end();
|
|
51
|
+
span.end();
|
|
52
|
+
expect(spanEnd).toHaveBeenCalledTimes(1);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("ignores setTokens after the span has ended (no late mutation)", async () => {
|
|
56
|
+
const span = await startCursorTurnSpan(spanAttrs);
|
|
57
|
+
span.end();
|
|
58
|
+
span.setTokens(1200, 340);
|
|
59
|
+
expect(spanSetAttribute).not.toHaveBeenCalled();
|
|
60
|
+
});
|
|
61
|
+
});
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for the Cursor mid-run progress substrate selection (DD-33) —
|
|
3
|
+
* `buildCursorProgressSubstrate`. This is the Cursor adapter's responsibility:
|
|
4
|
+
* pick git / non-git CAS / hybrid for the turn's workspace shape (the CAS + git
|
|
5
|
+
* capture behaviors themselves are covered in shared/filereview/__tests__).
|
|
6
|
+
*
|
|
7
|
+
* The chosen substrate is driven against a real temp workspace to prove WHICH
|
|
8
|
+
* kind was built: a git-only substrate surfaces the tracked change; a hybrid adds
|
|
9
|
+
* the (empty here) CAS slice; a non-git substrate reads the (empty) hook sidecar
|
|
10
|
+
* without touching git.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { execFile } from "node:child_process";
|
|
14
|
+
import { mkdtemp, mkdir, rm, writeFile } from "node:fs/promises";
|
|
15
|
+
import { tmpdir } from "node:os";
|
|
16
|
+
import { join } from "node:path";
|
|
17
|
+
import { promisify } from "node:util";
|
|
18
|
+
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
19
|
+
import { buildCursorProgressSubstrate } from "../capture-flow.js";
|
|
20
|
+
import { snapshotBaseline, dropCaptureRefs } from "../../../shared/filereview/git-substrate.js";
|
|
21
|
+
import { makeInMemoryArtifactStorage } from "../../../__test-utils__/fake-artifact-storage.js";
|
|
22
|
+
|
|
23
|
+
const execFileAsync = promisify(execFile);
|
|
24
|
+
const EXEC_ID = "exec-cursor-progress";
|
|
25
|
+
|
|
26
|
+
let repo: string;
|
|
27
|
+
let hitlDir: string;
|
|
28
|
+
|
|
29
|
+
async function git(args: string[]): Promise<void> {
|
|
30
|
+
await execFileAsync("git", args, { cwd: repo });
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function write(rel: string, content: string): Promise<void> {
|
|
34
|
+
await mkdir(join(repo, rel, ".."), { recursive: true });
|
|
35
|
+
await writeFile(join(repo, rel), content, "utf-8");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
beforeEach(async () => {
|
|
39
|
+
repo = await mkdtemp(join(tmpdir(), "cursor-progress-"));
|
|
40
|
+
hitlDir = await mkdtemp(join(tmpdir(), "cursor-progress-hitl-"));
|
|
41
|
+
await git(["init", "-q"]);
|
|
42
|
+
await git(["config", "user.email", "t@t.local"]);
|
|
43
|
+
await git(["config", "user.name", "t"]);
|
|
44
|
+
await write("src/main.ts", "export const x = 1;\n");
|
|
45
|
+
await git(["add", "-A"]);
|
|
46
|
+
await git(["commit", "-q", "-m", "initial"]);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
afterEach(async () => {
|
|
50
|
+
await dropCaptureRefs(repo, EXEC_ID).catch(() => {});
|
|
51
|
+
await rm(repo, { recursive: true, force: true });
|
|
52
|
+
await rm(hitlDir, { recursive: true, force: true });
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
describe("buildCursorProgressSubstrate — selection", () => {
|
|
56
|
+
it("returns undefined outside capture mode", () => {
|
|
57
|
+
const sub = buildCursorProgressSubstrate({
|
|
58
|
+
captureMode: false,
|
|
59
|
+
gitWorkspace: true,
|
|
60
|
+
workspaceRoot: repo,
|
|
61
|
+
baselineTree: "sha",
|
|
62
|
+
executionId: EXEC_ID,
|
|
63
|
+
hitlDir,
|
|
64
|
+
storage: undefined,
|
|
65
|
+
});
|
|
66
|
+
expect(sub).toBeUndefined();
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it("returns undefined with no workspace root", () => {
|
|
70
|
+
const sub = buildCursorProgressSubstrate({
|
|
71
|
+
captureMode: true,
|
|
72
|
+
gitWorkspace: true,
|
|
73
|
+
workspaceRoot: undefined,
|
|
74
|
+
baselineTree: "sha",
|
|
75
|
+
executionId: EXEC_ID,
|
|
76
|
+
hitlDir,
|
|
77
|
+
storage: undefined,
|
|
78
|
+
});
|
|
79
|
+
expect(sub).toBeUndefined();
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it("returns undefined for a git tree with no baseline tree yet", () => {
|
|
83
|
+
const sub = buildCursorProgressSubstrate({
|
|
84
|
+
captureMode: true,
|
|
85
|
+
gitWorkspace: true,
|
|
86
|
+
workspaceRoot: repo,
|
|
87
|
+
baselineTree: undefined,
|
|
88
|
+
executionId: EXEC_ID,
|
|
89
|
+
hitlDir,
|
|
90
|
+
storage: undefined,
|
|
91
|
+
});
|
|
92
|
+
expect(sub).toBeUndefined();
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it("returns undefined for a non-git workspace with no storage/sidecar", () => {
|
|
96
|
+
const sub = buildCursorProgressSubstrate({
|
|
97
|
+
captureMode: true,
|
|
98
|
+
gitWorkspace: false,
|
|
99
|
+
workspaceRoot: repo,
|
|
100
|
+
baselineTree: undefined,
|
|
101
|
+
executionId: EXEC_ID,
|
|
102
|
+
hitlDir: undefined,
|
|
103
|
+
storage: undefined,
|
|
104
|
+
});
|
|
105
|
+
expect(sub).toBeUndefined();
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it("builds a git-only substrate (no storage) that surfaces the tracked change", async () => {
|
|
109
|
+
const baselineTree = await snapshotBaseline(repo, EXEC_ID);
|
|
110
|
+
const sub = buildCursorProgressSubstrate({
|
|
111
|
+
captureMode: true,
|
|
112
|
+
gitWorkspace: true,
|
|
113
|
+
workspaceRoot: repo,
|
|
114
|
+
baselineTree,
|
|
115
|
+
executionId: EXEC_ID,
|
|
116
|
+
hitlDir,
|
|
117
|
+
storage: undefined,
|
|
118
|
+
});
|
|
119
|
+
expect(sub).toBeDefined();
|
|
120
|
+
|
|
121
|
+
await write("src/main.ts", "export const x = 2;\nexport const y = 3;\n");
|
|
122
|
+
const { delta, changed } = await sub!.capture();
|
|
123
|
+
expect(changed).toBe(true);
|
|
124
|
+
expect(delta.entries.some((e) => e.pathAfter === "src/main.ts")).toBe(true);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it("builds a hybrid substrate (git + storage) surfacing the git slice + empty CAS", async () => {
|
|
128
|
+
const baselineTree = await snapshotBaseline(repo, EXEC_ID);
|
|
129
|
+
const { storage } = makeInMemoryArtifactStorage();
|
|
130
|
+
const sub = buildCursorProgressSubstrate({
|
|
131
|
+
captureMode: true,
|
|
132
|
+
gitWorkspace: true,
|
|
133
|
+
workspaceRoot: repo,
|
|
134
|
+
baselineTree,
|
|
135
|
+
executionId: EXEC_ID,
|
|
136
|
+
hitlDir,
|
|
137
|
+
storage,
|
|
138
|
+
});
|
|
139
|
+
expect(sub).toBeDefined();
|
|
140
|
+
|
|
141
|
+
await write("src/main.ts", "export const x = 9;\n");
|
|
142
|
+
const { delta } = await sub!.capture();
|
|
143
|
+
// The git slice contributes the tracked change; the CAS sidecar is empty, so
|
|
144
|
+
// it adds nothing — total equals the git entries.
|
|
145
|
+
expect(delta.entries.some((e) => e.pathAfter === "src/main.ts")).toBe(true);
|
|
146
|
+
expect(delta.totalFilesChanged).toBe(delta.entries.length);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it("builds a non-git CAS substrate that reads the (empty) sidecar without git", async () => {
|
|
150
|
+
const { storage } = makeInMemoryArtifactStorage();
|
|
151
|
+
const sub = buildCursorProgressSubstrate({
|
|
152
|
+
captureMode: true,
|
|
153
|
+
gitWorkspace: false,
|
|
154
|
+
workspaceRoot: repo,
|
|
155
|
+
baselineTree: undefined,
|
|
156
|
+
executionId: EXEC_ID,
|
|
157
|
+
hitlDir,
|
|
158
|
+
storage,
|
|
159
|
+
});
|
|
160
|
+
expect(sub).toBeDefined();
|
|
161
|
+
|
|
162
|
+
// Even with a git change on disk, the non-git substrate ignores git entirely;
|
|
163
|
+
// the sidecar is empty, so it reports zero changed files.
|
|
164
|
+
await write("src/main.ts", "export const x = 42;\n");
|
|
165
|
+
const { delta } = await sub!.capture();
|
|
166
|
+
expect(delta.totalFilesChanged).toBe(0);
|
|
167
|
+
expect(delta.entries).toHaveLength(0);
|
|
168
|
+
});
|
|
169
|
+
});
|