@mikode13/harness 4.0.1 → 5.0.0
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/README.md +278 -16
- package/dist/agent/domain/agent.d.ts +12 -0
- package/dist/agent/domain/agent.js.map +1 -1
- package/dist/agent/domain/approval.d.ts +9 -0
- package/dist/agent/domain/approval.js.map +1 -1
- package/dist/agent/domain/runContext.d.ts +31 -0
- package/dist/agent/domain/runContext.js +47 -0
- package/dist/agent/domain/runContext.js.map +1 -0
- package/dist/diff/domain/unifiedDiff.d.ts +19 -0
- package/dist/diff/domain/unifiedDiff.js +166 -0
- package/dist/diff/domain/unifiedDiff.js.map +1 -0
- package/dist/engines/domain/model/historyFollower.d.ts +41 -0
- package/dist/engines/domain/model/historyFollower.js +158 -0
- package/dist/engines/domain/model/historyFollower.js.map +1 -0
- package/dist/engines/domain/model/llmAgent.d.ts +42 -4
- package/dist/engines/domain/model/llmAgent.js +223 -23
- package/dist/engines/domain/model/llmAgent.js.map +1 -1
- package/dist/factory/infrastructure/agentFactory.d.ts +14 -0
- package/dist/factory/infrastructure/agentFactory.js +20 -2
- package/dist/factory/infrastructure/agentFactory.js.map +1 -1
- package/dist/factory/infrastructure/agentLLMFactory.d.ts +119 -14
- package/dist/factory/infrastructure/agentLLMFactory.js +284 -57
- package/dist/factory/infrastructure/agentLLMFactory.js.map +1 -1
- package/dist/index.d.ts +11 -3
- package/dist/index.js +5 -2
- package/dist/index.js.map +1 -1
- package/dist/llm/domain/conversation.d.ts +44 -4
- package/dist/llm/domain/conversation.js +56 -7
- package/dist/llm/domain/conversation.js.map +1 -1
- package/dist/llm/domain/llm.d.ts +3 -1
- package/dist/llm/domain/llm.js.map +1 -1
- package/dist/llm/domain/tool.d.ts +13 -0
- package/dist/llm/domain/tool.js +12 -1
- package/dist/llm/domain/tool.js.map +1 -1
- package/dist/llm/infrastructure/claudeLLMClient.d.ts +3 -2
- package/dist/llm/infrastructure/claudeLLMClient.js +38 -10
- package/dist/llm/infrastructure/claudeLLMClient.js.map +1 -1
- package/dist/llm/infrastructure/openAILLMClient.d.ts +2 -1
- package/dist/llm/infrastructure/openAILLMClient.js +66 -16
- package/dist/llm/infrastructure/openAILLMClient.js.map +1 -1
- package/dist/orchestration/domain/model/orchestratorAgent.d.ts +11 -2
- package/dist/orchestration/domain/model/orchestratorAgent.js +43 -4
- package/dist/orchestration/domain/model/orchestratorAgent.js.map +1 -1
- package/dist/recovery/domain/fileChanges.d.ts +31 -0
- package/dist/recovery/domain/fileChanges.js +48 -0
- package/dist/recovery/domain/fileChanges.js.map +1 -0
- package/dist/recovery/domain/history.d.ts +114 -0
- package/dist/recovery/domain/history.js +62 -0
- package/dist/recovery/domain/history.js.map +1 -0
- package/dist/recovery/domain/recoveryStore.d.ts +233 -0
- package/dist/recovery/domain/recoveryStore.js +32 -0
- package/dist/recovery/domain/recoveryStore.js.map +1 -0
- package/dist/recovery/domain/retention.d.ts +33 -0
- package/dist/recovery/domain/retention.js +90 -0
- package/dist/recovery/domain/retention.js.map +1 -0
- package/dist/recovery/domain/runChanges.d.ts +37 -0
- package/dist/recovery/domain/runChanges.js +109 -0
- package/dist/recovery/domain/runChanges.js.map +1 -0
- package/dist/recovery/domain/runTree.d.ts +32 -0
- package/dist/recovery/domain/runTree.js +90 -0
- package/dist/recovery/domain/runTree.js.map +1 -0
- package/dist/recovery/infrastructure/createHistory.d.ts +11 -0
- package/dist/recovery/infrastructure/createHistory.js +17 -0
- package/dist/recovery/infrastructure/createHistory.js.map +1 -0
- package/dist/recovery/infrastructure/fileRecoveryStore.d.ts +133 -0
- package/dist/recovery/infrastructure/fileRecoveryStore.js +1043 -0
- package/dist/recovery/infrastructure/fileRecoveryStore.js.map +1 -0
- package/dist/recovery/infrastructure/workspaceFiles.d.ts +30 -0
- package/dist/recovery/infrastructure/workspaceFiles.js +125 -0
- package/dist/recovery/infrastructure/workspaceFiles.js.map +1 -0
- package/dist/tools/domain/accessPolicy.d.ts +30 -0
- package/dist/tools/domain/accessPolicy.js +11 -0
- package/dist/tools/domain/accessPolicy.js.map +1 -0
- package/dist/tools/domain/commands.d.ts +93 -0
- package/dist/tools/domain/commands.js +191 -0
- package/dist/tools/domain/commands.js.map +1 -0
- package/dist/tools/domain/editResponse.d.ts +14 -0
- package/dist/tools/domain/editResponse.js +79 -0
- package/dist/tools/domain/editResponse.js.map +1 -0
- package/dist/tools/domain/fileEdits.d.ts +64 -0
- package/dist/tools/domain/fileEdits.js +21 -0
- package/dist/tools/domain/fileEdits.js.map +1 -0
- package/dist/tools/domain/lineLength.d.ts +7 -0
- package/dist/tools/domain/lineLength.js +26 -0
- package/dist/tools/domain/lineLength.js.map +1 -0
- package/dist/tools/domain/preparedCall.d.ts +31 -0
- package/dist/tools/domain/preparedCall.js +14 -0
- package/dist/tools/domain/preparedCall.js.map +1 -0
- package/dist/tools/domain/readRegistry.d.ts +46 -0
- package/dist/tools/domain/readRegistry.js +62 -0
- package/dist/tools/domain/readRegistry.js.map +1 -0
- package/dist/tools/domain/textLines.d.ts +26 -0
- package/dist/tools/domain/textLines.js +44 -0
- package/dist/tools/domain/textLines.js.map +1 -0
- package/dist/tools/domain/v4aPatch.d.ts +17 -0
- package/dist/tools/domain/v4aPatch.js +236 -0
- package/dist/tools/domain/v4aPatch.js.map +1 -0
- package/dist/tools/infrastructure/boundedWorkspace.d.ts +11 -2
- package/dist/tools/infrastructure/boundedWorkspace.js +9 -1
- package/dist/tools/infrastructure/boundedWorkspace.js.map +1 -1
- package/dist/tools/infrastructure/commandCheckpoint.d.ts +55 -0
- package/dist/tools/infrastructure/commandCheckpoint.js +178 -0
- package/dist/tools/infrastructure/commandCheckpoint.js.map +1 -0
- package/dist/tools/infrastructure/commandProcess.d.ts +47 -0
- package/dist/tools/infrastructure/commandProcess.js +217 -0
- package/dist/tools/infrastructure/commandProcess.js.map +1 -0
- package/dist/tools/infrastructure/commandTool.d.ts +36 -0
- package/dist/tools/infrastructure/commandTool.js +254 -0
- package/dist/tools/infrastructure/commandTool.js.map +1 -0
- package/dist/tools/infrastructure/createWorkspace.d.ts +10 -0
- package/dist/tools/infrastructure/createWorkspace.js +11 -3
- package/dist/tools/infrastructure/createWorkspace.js.map +1 -1
- package/dist/tools/infrastructure/defineTool.d.ts +14 -0
- package/dist/tools/infrastructure/defineTool.js +28 -5
- package/dist/tools/infrastructure/defineTool.js.map +1 -1
- package/dist/tools/infrastructure/editFormats.d.ts +22 -0
- package/dist/tools/infrastructure/editFormats.js +211 -0
- package/dist/tools/infrastructure/editFormats.js.map +1 -0
- package/dist/tools/infrastructure/fileEditor.d.ts +64 -0
- package/dist/tools/infrastructure/fileEditor.js +306 -0
- package/dist/tools/infrastructure/fileEditor.js.map +1 -0
- package/dist/tools/infrastructure/fileTools.d.ts +81 -0
- package/dist/tools/infrastructure/fileTools.js +152 -0
- package/dist/tools/infrastructure/fileTools.js.map +1 -0
- package/dist/tools/infrastructure/gitIgnoreRules.d.ts +15 -0
- package/dist/tools/infrastructure/gitIgnoreRules.js +74 -0
- package/dist/tools/infrastructure/gitIgnoreRules.js.map +1 -0
- package/dist/tools/infrastructure/gitWorkspace.d.ts +1 -1
- package/dist/tools/infrastructure/gitWorkspace.js +1 -1
- package/dist/tools/infrastructure/gitWorkspace.js.map +1 -1
- package/dist/tools/infrastructure/ignoreFileChanges.d.ts +14 -0
- package/dist/tools/infrastructure/ignoreFileChanges.js +62 -0
- package/dist/tools/infrastructure/ignoreFileChanges.js.map +1 -0
- package/dist/tools/infrastructure/policyWorkspace.d.ts +52 -0
- package/dist/tools/infrastructure/policyWorkspace.js +32 -0
- package/dist/tools/infrastructure/policyWorkspace.js.map +1 -0
- package/dist/tools/infrastructure/ripgrepWorkspace.d.ts +2 -1
- package/dist/tools/infrastructure/ripgrepWorkspace.js +1 -1
- package/dist/tools/infrastructure/ripgrepWorkspace.js.map +1 -1
- package/dist/tools/infrastructure/rootsAccessPolicy.d.ts +100 -0
- package/dist/tools/infrastructure/rootsAccessPolicy.js +301 -0
- package/dist/tools/infrastructure/rootsAccessPolicy.js.map +1 -0
- package/dist/tools/infrastructure/runProcess.d.ts +4 -1
- package/dist/tools/infrastructure/runProcess.js +4 -2
- package/dist/tools/infrastructure/runProcess.js.map +1 -1
- package/dist/tools/infrastructure/secretPaths.d.ts +8 -0
- package/dist/tools/infrastructure/secretPaths.js +76 -0
- package/dist/tools/infrastructure/secretPaths.js.map +1 -0
- package/dist/tools/infrastructure/showChangesTool.d.ts +12 -0
- package/dist/tools/infrastructure/showChangesTool.js +43 -0
- package/dist/tools/infrastructure/showChangesTool.js.map +1 -0
- package/dist/tools/infrastructure/trackedEdits.d.ts +33 -0
- package/dist/tools/infrastructure/trackedEdits.js +70 -0
- package/dist/tools/infrastructure/trackedEdits.js.map +1 -0
- package/dist/tools/infrastructure/trackedReadFile.d.ts +21 -0
- package/dist/tools/infrastructure/trackedReadFile.js +78 -0
- package/dist/tools/infrastructure/trackedReadFile.js.map +1 -0
- package/dist/tools/infrastructure/workspaceTools.d.ts +28 -0
- package/dist/tools/infrastructure/workspaceTools.js +53 -40
- package/dist/tools/infrastructure/workspaceTools.js.map +1 -1
- package/dist/tools/infrastructure/workspaceWrites.d.ts +23 -0
- package/dist/tools/infrastructure/workspaceWrites.js +42 -0
- package/dist/tools/infrastructure/workspaceWrites.js.map +1 -0
- package/dist/tools/infrastructure/writeSession.d.ts +35 -0
- package/dist/tools/infrastructure/writeSession.js +81 -0
- package/dist/tools/infrastructure/writeSession.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { RunContext } from '#src/agent/domain/runContext';
|
|
2
|
+
import type { RecoveryStore } from '#src/recovery/domain/recoveryStore';
|
|
3
|
+
import type { AccessPolicy } from '../domain/accessPolicy.ts';
|
|
4
|
+
import { FileEditor } from './fileEditor.ts';
|
|
5
|
+
import { WriteSession } from './writeSession.ts';
|
|
6
|
+
/**
|
|
7
|
+
* The writing side of a workspace, shared by every write tool built over it: one policy and
|
|
8
|
+
* one recovery store, and one `WriteSession` per run, ended with that run. A session lives
|
|
9
|
+
* only as long as its run's context, so nothing here outlives a run.
|
|
10
|
+
*/
|
|
11
|
+
export declare class WorkspaceWrites {
|
|
12
|
+
private readonly policy;
|
|
13
|
+
private readonly store;
|
|
14
|
+
private readonly sessions;
|
|
15
|
+
constructor({ policy, store }: {
|
|
16
|
+
policy: AccessPolicy;
|
|
17
|
+
store: RecoveryStore;
|
|
18
|
+
});
|
|
19
|
+
/** An editor over this run's session, created on the run's first write tool call. */
|
|
20
|
+
editorFor(context: RunContext): FileEditor;
|
|
21
|
+
/** Everything this run writes, its commands' changes included, created on its first write. */
|
|
22
|
+
sessionFor(context: RunContext): WriteSession;
|
|
23
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { FileEditor } from "./fileEditor.js";
|
|
2
|
+
import { WriteSession } from "./writeSession.js";
|
|
3
|
+
/**
|
|
4
|
+
* The writing side of a workspace, shared by every write tool built over it: one policy and
|
|
5
|
+
* one recovery store, and one `WriteSession` per run, ended with that run. A session lives
|
|
6
|
+
* only as long as its run's context, so nothing here outlives a run.
|
|
7
|
+
*/
|
|
8
|
+
export class WorkspaceWrites {
|
|
9
|
+
policy;
|
|
10
|
+
store;
|
|
11
|
+
sessions = new WeakMap();
|
|
12
|
+
constructor({ policy, store }) {
|
|
13
|
+
this.policy = policy;
|
|
14
|
+
this.store = store;
|
|
15
|
+
}
|
|
16
|
+
/** An editor over this run's session, created on the run's first write tool call. */
|
|
17
|
+
editorFor(context) {
|
|
18
|
+
return new FileEditor({ policy: this.policy, session: this.sessionFor(context) });
|
|
19
|
+
}
|
|
20
|
+
/** Everything this run writes, its commands' changes included, created on its first write. */
|
|
21
|
+
sessionFor(context) {
|
|
22
|
+
let session = this.sessions.get(context);
|
|
23
|
+
if (!session) {
|
|
24
|
+
const created = new WriteSession({
|
|
25
|
+
store: this.store,
|
|
26
|
+
// So every turn of the run, in every role, can be tied to what it wrote.
|
|
27
|
+
onStart: runId => {
|
|
28
|
+
context.historyRun.runId = runId;
|
|
29
|
+
},
|
|
30
|
+
// A run that changed nothing is not in the history, so its turns wrote nothing.
|
|
31
|
+
onDiscard: () => {
|
|
32
|
+
delete context.historyRun.runId;
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
context.onFinish(end => created.finish(end));
|
|
36
|
+
this.sessions.set(context, created);
|
|
37
|
+
session = created;
|
|
38
|
+
}
|
|
39
|
+
return session;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=workspaceWrites.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspaceWrites.js","sourceRoot":"","sources":["../../../src/tools/infrastructure/workspaceWrites.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD;;;;GAIG;AACH,MAAM,OAAO,eAAe;IACV,MAAM,CAAe;IACrB,KAAK,CAAgB;IACrB,QAAQ,GAAG,IAAI,OAAO,EAA4B,CAAC;IAEpE,YAAY,EAAE,MAAM,EAAE,KAAK,EAAkD;QAC5E,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACpB,CAAC;IAED,qFAAqF;IACrF,SAAS,CAAC,OAAmB;QAC5B,OAAO,IAAI,UAAU,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACnF,CAAC;IAED,8FAA8F;IAC9F,UAAU,CAAC,OAAmB;QAC7B,IAAI,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACzC,IAAI,CAAC,OAAO,EAAE,CAAC;YACd,MAAM,OAAO,GAAG,IAAI,YAAY,CAAC;gBAChC,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,yEAAyE;gBACzE,OAAO,EAAE,KAAK,CAAC,EAAE;oBAChB,OAAO,CAAC,UAAU,CAAC,KAAK,GAAG,KAAK,CAAC;gBAClC,CAAC;gBACD,gFAAgF;gBAChF,SAAS,EAAE,GAAG,EAAE;oBACf,OAAO,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC;gBACjC,CAAC;aACD,CAAC,CAAC;YACH,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YAC7C,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YACpC,OAAO,GAAG,OAAO,CAAC;QACnB,CAAC;QACD,OAAO,OAAO,CAAC;IAChB,CAAC;CACD","sourcesContent":["import type { RunContext } from '#src/agent/domain/runContext';\nimport type { RecoveryStore } from '#src/recovery/domain/recoveryStore';\nimport type { AccessPolicy } from '../domain/accessPolicy.ts';\nimport { FileEditor } from './fileEditor.ts';\nimport { WriteSession } from './writeSession.ts';\n\n/**\n * The writing side of a workspace, shared by every write tool built over it: one policy and\n * one recovery store, and one `WriteSession` per run, ended with that run. A session lives\n * only as long as its run's context, so nothing here outlives a run.\n */\nexport class WorkspaceWrites {\n\tprivate readonly policy: AccessPolicy;\n\tprivate readonly store: RecoveryStore;\n\tprivate readonly sessions = new WeakMap<RunContext, WriteSession>();\n\n\tconstructor({ policy, store }: { policy: AccessPolicy; store: RecoveryStore }) {\n\t\tthis.policy = policy;\n\t\tthis.store = store;\n\t}\n\n\t/** An editor over this run's session, created on the run's first write tool call. */\n\teditorFor(context: RunContext): FileEditor {\n\t\treturn new FileEditor({ policy: this.policy, session: this.sessionFor(context) });\n\t}\n\n\t/** Everything this run writes, its commands' changes included, created on its first write. */\n\tsessionFor(context: RunContext): WriteSession {\n\t\tlet session = this.sessions.get(context);\n\t\tif (!session) {\n\t\t\tconst created = new WriteSession({\n\t\t\t\tstore: this.store,\n\t\t\t\t// So every turn of the run, in every role, can be tied to what it wrote.\n\t\t\t\tonStart: runId => {\n\t\t\t\t\tcontext.historyRun.runId = runId;\n\t\t\t\t},\n\t\t\t\t// A run that changed nothing is not in the history, so its turns wrote nothing.\n\t\t\t\tonDiscard: () => {\n\t\t\t\t\tdelete context.historyRun.runId;\n\t\t\t\t},\n\t\t\t});\n\t\t\tcontext.onFinish(end => created.finish(end));\n\t\t\tthis.sessions.set(context, created);\n\t\t\tsession = created;\n\t\t}\n\t\treturn session;\n\t}\n}\n"]}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type RecoveryStore, type RunJournal, type RunStatus } from '#src/recovery/domain/recoveryStore';
|
|
2
|
+
/**
|
|
3
|
+
* Everything one top-level run writes, across all its roles and rounds. Its journal starts on
|
|
4
|
+
* the first write, so a run that only reads never holds the workspace, and ends with the run.
|
|
5
|
+
* Once a change could not be confirmed, the session refuses every further write: the record of
|
|
6
|
+
* what the run did must stay complete.
|
|
7
|
+
*/
|
|
8
|
+
export declare class WriteSession {
|
|
9
|
+
private readonly store;
|
|
10
|
+
private readonly maxChanges;
|
|
11
|
+
private readonly onStart;
|
|
12
|
+
private readonly onDiscard;
|
|
13
|
+
private journal;
|
|
14
|
+
private changes;
|
|
15
|
+
private stopped;
|
|
16
|
+
constructor({ store, maxChanges, onStart, onDiscard, }: {
|
|
17
|
+
store: RecoveryStore;
|
|
18
|
+
maxChanges?: number;
|
|
19
|
+
/** Told the run's id once its journal has started, before its first change is recorded. */
|
|
20
|
+
onStart?: (runId: string) => void;
|
|
21
|
+
/** Told when the run ended having changed nothing, so the history no longer has it. */
|
|
22
|
+
onDiscard?: () => void;
|
|
23
|
+
});
|
|
24
|
+
/** The journal for one more change, counted against the run's limit. */
|
|
25
|
+
journalForChange(): Promise<RunJournal>;
|
|
26
|
+
/** Refuses every further write, for this reason. The first reason given is kept. */
|
|
27
|
+
stop(reason: string): void;
|
|
28
|
+
/** The run's id once it has written, which is what an undo needs. */
|
|
29
|
+
runId(): Promise<string | undefined>;
|
|
30
|
+
/**
|
|
31
|
+
* Ends the run's record and releases the workspace. A run that never wrote has nothing to end,
|
|
32
|
+
* and one whose every change was abandoned leaves the history.
|
|
33
|
+
*/
|
|
34
|
+
finish(status: Exclude<RunStatus, 'running' | 'interrupted'>): Promise<void>;
|
|
35
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { WorkspaceBusyError, } from '#src/recovery/domain/recoveryStore';
|
|
2
|
+
import { EditRefusedError } from "../domain/fileEdits.js";
|
|
3
|
+
// Far more than a task needs; a run past it is more likely looping than working.
|
|
4
|
+
const defaultMaxChanges = 500;
|
|
5
|
+
/**
|
|
6
|
+
* Everything one top-level run writes, across all its roles and rounds. Its journal starts on
|
|
7
|
+
* the first write, so a run that only reads never holds the workspace, and ends with the run.
|
|
8
|
+
* Once a change could not be confirmed, the session refuses every further write: the record of
|
|
9
|
+
* what the run did must stay complete.
|
|
10
|
+
*/
|
|
11
|
+
export class WriteSession {
|
|
12
|
+
store;
|
|
13
|
+
maxChanges;
|
|
14
|
+
onStart;
|
|
15
|
+
onDiscard;
|
|
16
|
+
journal;
|
|
17
|
+
changes = 0;
|
|
18
|
+
stopped;
|
|
19
|
+
constructor({ store, maxChanges = defaultMaxChanges, onStart, onDiscard, }) {
|
|
20
|
+
this.store = store;
|
|
21
|
+
this.maxChanges = maxChanges;
|
|
22
|
+
this.onStart = onStart;
|
|
23
|
+
this.onDiscard = onDiscard;
|
|
24
|
+
}
|
|
25
|
+
/** The journal for one more change, counted against the run's limit. */
|
|
26
|
+
async journalForChange() {
|
|
27
|
+
if (this.stopped !== undefined)
|
|
28
|
+
throw new EditRefusedError(this.stopped);
|
|
29
|
+
if (this.changes >= this.maxChanges) {
|
|
30
|
+
throw new EditRefusedError(`This run has made ${String(this.maxChanges)} changes, the most one run may make`);
|
|
31
|
+
}
|
|
32
|
+
this.journal ??= this.store.startRun().then(started => {
|
|
33
|
+
this.onStart?.(started.runId);
|
|
34
|
+
return started;
|
|
35
|
+
});
|
|
36
|
+
let journal;
|
|
37
|
+
try {
|
|
38
|
+
journal = await this.journal;
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
// A failed start is not kept, so the next change tries again.
|
|
42
|
+
this.journal = undefined;
|
|
43
|
+
if (error instanceof WorkspaceBusyError) {
|
|
44
|
+
throw new EditRefusedError('Another run, or a move through its history, holds this workspace, so nothing was changed', {
|
|
45
|
+
cause: error,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
throw new EditRefusedError('The harness could not start recording this run, so nothing was changed', { cause: error });
|
|
49
|
+
}
|
|
50
|
+
this.changes++;
|
|
51
|
+
return journal;
|
|
52
|
+
}
|
|
53
|
+
/** Refuses every further write, for this reason. The first reason given is kept. */
|
|
54
|
+
stop(reason) {
|
|
55
|
+
this.stopped ??= reason;
|
|
56
|
+
}
|
|
57
|
+
/** The run's id once it has written, which is what an undo needs. */
|
|
58
|
+
async runId() {
|
|
59
|
+
const journal = await this.journal?.catch(() => undefined);
|
|
60
|
+
return journal?.runId;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Ends the run's record and releases the workspace. A run that never wrote has nothing to end,
|
|
64
|
+
* and one whose every change was abandoned leaves the history.
|
|
65
|
+
*/
|
|
66
|
+
async finish(status) {
|
|
67
|
+
const journal = await this.journal?.catch(() => undefined);
|
|
68
|
+
this.journal = undefined;
|
|
69
|
+
if (!journal)
|
|
70
|
+
return;
|
|
71
|
+
try {
|
|
72
|
+
await journal.finish(status);
|
|
73
|
+
}
|
|
74
|
+
finally {
|
|
75
|
+
// Even when finishing failed: a run that changed nothing is out of the history either way.
|
|
76
|
+
if (!journal.changed)
|
|
77
|
+
this.onDiscard?.();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=writeSession.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"writeSession.js","sourceRoot":"","sources":["../../../src/tools/infrastructure/writeSession.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\ttype RecoveryStore,\n\ttype RunJournal,\n\ttype RunStatus,\n\tWorkspaceBusyError,\n} from '#src/recovery/domain/recoveryStore';\nimport { EditRefusedError } from '../domain/fileEdits.ts';\n\n// Far more than a task needs; a run past it is more likely looping than working.\nconst defaultMaxChanges = 500;\n\n/**\n * Everything one top-level run writes, across all its roles and rounds. Its journal starts on\n * the first write, so a run that only reads never holds the workspace, and ends with the run.\n * Once a change could not be confirmed, the session refuses every further write: the record of\n * what the run did must stay complete.\n */\nexport class WriteSession {\n\tprivate readonly store: RecoveryStore;\n\tprivate readonly maxChanges: number;\n\tprivate readonly onStart: ((runId: string) => void) | undefined;\n\tprivate readonly onDiscard: (() => void) | undefined;\n\tprivate journal: Promise<RunJournal> | undefined;\n\tprivate changes = 0;\n\tprivate stopped: string | undefined;\n\n\tconstructor({\n\t\tstore,\n\t\tmaxChanges = defaultMaxChanges,\n\t\tonStart,\n\t\tonDiscard,\n\t}: {\n\t\tstore: RecoveryStore;\n\t\tmaxChanges?: number;\n\t\t/** Told the run's id once its journal has started, before its first change is recorded. */\n\t\tonStart?: (runId: string) => void;\n\t\t/** Told when the run ended having changed nothing, so the history no longer has it. */\n\t\tonDiscard?: () => void;\n\t}) {\n\t\tthis.store = store;\n\t\tthis.maxChanges = maxChanges;\n\t\tthis.onStart = onStart;\n\t\tthis.onDiscard = onDiscard;\n\t}\n\n\t/** The journal for one more change, counted against the run's limit. */\n\tasync journalForChange(): Promise<RunJournal> {\n\t\tif (this.stopped !== undefined) throw new EditRefusedError(this.stopped);\n\t\tif (this.changes >= this.maxChanges) {\n\t\t\tthrow new EditRefusedError(\n\t\t\t\t`This run has made ${String(this.maxChanges)} changes, the most one run may make`,\n\t\t\t);\n\t\t}\n\n\t\tthis.journal ??= this.store.startRun().then(started => {\n\t\t\tthis.onStart?.(started.runId);\n\t\t\treturn started;\n\t\t});\n\t\tlet journal: RunJournal;\n\t\ttry {\n\t\t\tjournal = await this.journal;\n\t\t} catch (error) {\n\t\t\t// A failed start is not kept, so the next change tries again.\n\t\t\tthis.journal = undefined;\n\t\t\tif (error instanceof WorkspaceBusyError) {\n\t\t\t\tthrow new EditRefusedError(\n\t\t\t\t\t'Another run, or a move through its history, holds this workspace, so nothing was changed',\n\t\t\t\t\t{\n\t\t\t\t\t\tcause: error,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\t\t\tthrow new EditRefusedError(\n\t\t\t\t'The harness could not start recording this run, so nothing was changed',\n\t\t\t\t{ cause: error },\n\t\t\t);\n\t\t}\n\t\tthis.changes++;\n\t\treturn journal;\n\t}\n\n\t/** Refuses every further write, for this reason. The first reason given is kept. */\n\tstop(reason: string): void {\n\t\tthis.stopped ??= reason;\n\t}\n\n\t/** The run's id once it has written, which is what an undo needs. */\n\tasync runId(): Promise<string | undefined> {\n\t\tconst journal = await this.journal?.catch(() => undefined);\n\t\treturn journal?.runId;\n\t}\n\n\t/**\n\t * Ends the run's record and releases the workspace. A run that never wrote has nothing to end,\n\t * and one whose every change was abandoned leaves the history.\n\t */\n\tasync finish(status: Exclude<RunStatus, 'running' | 'interrupted'>): Promise<void> {\n\t\tconst journal = await this.journal?.catch(() => undefined);\n\t\tthis.journal = undefined;\n\t\tif (!journal) return;\n\t\ttry {\n\t\t\tawait journal.finish(status);\n\t\t} finally {\n\t\t\t// Even when finishing failed: a run that changed nothing is out of the history either way.\n\t\t\tif (!journal.changed) this.onDiscard?.();\n\t\t}\n\t}\n}\n"]}
|