@planweave-ai/runtime 0.1.2 → 0.1.7
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/autoRun/claudeCodeIntegration.d.ts.map +1 -1
- package/dist/autoRun/claudeCodeIntegration.js +4 -2
- package/dist/autoRun/claudeCodeIntegration.js.map +1 -1
- package/dist/autoRun/codexExecutor.d.ts +2 -0
- package/dist/autoRun/codexExecutor.d.ts.map +1 -1
- package/dist/autoRun/codexExecutor.js +10 -2
- package/dist/autoRun/codexExecutor.js.map +1 -1
- package/dist/autoRun/codexIntegration.d.ts.map +1 -1
- package/dist/autoRun/codexIntegration.js +4 -2
- package/dist/autoRun/codexIntegration.js.map +1 -1
- package/dist/autoRun/executorIntegration.d.ts +1 -0
- package/dist/autoRun/executorIntegration.d.ts.map +1 -1
- package/dist/autoRun/executorIntegration.js.map +1 -1
- package/dist/autoRun/localReviewExecutor.d.ts +2 -0
- package/dist/autoRun/localReviewExecutor.d.ts.map +1 -1
- package/dist/autoRun/localReviewExecutor.js +9 -2
- package/dist/autoRun/localReviewExecutor.js.map +1 -1
- package/dist/autoRun/localReviewIntegration.d.ts.map +1 -1
- package/dist/autoRun/localReviewIntegration.js +4 -2
- package/dist/autoRun/localReviewIntegration.js.map +1 -1
- package/dist/autoRun/opencodeExecutor.d.ts +2 -0
- package/dist/autoRun/opencodeExecutor.d.ts.map +1 -1
- package/dist/autoRun/opencodeExecutor.js +9 -2
- package/dist/autoRun/opencodeExecutor.js.map +1 -1
- package/dist/autoRun/opencodeIntegration.d.ts.map +1 -1
- package/dist/autoRun/opencodeIntegration.js +4 -2
- package/dist/autoRun/opencodeIntegration.js.map +1 -1
- package/dist/autoRun/piIntegration.d.ts.map +1 -1
- package/dist/autoRun/piIntegration.js +4 -2
- package/dist/autoRun/piIntegration.js.map +1 -1
- package/dist/autoRun/terminalAgentExecutor.d.ts +2 -0
- package/dist/autoRun/terminalAgentExecutor.d.ts.map +1 -1
- package/dist/autoRun/terminalAgentExecutor.js +9 -2
- package/dist/autoRun/terminalAgentExecutor.js.map +1 -1
- package/dist/autoRun/tmuxExecutor.d.ts +3 -0
- package/dist/autoRun/tmuxExecutor.d.ts.map +1 -1
- package/dist/autoRun/tmuxExecutor.js +19 -3
- package/dist/autoRun/tmuxExecutor.js.map +1 -1
- package/dist/desktop/canvasApi.d.ts.map +1 -1
- package/dist/desktop/canvasApi.js +45 -22
- package/dist/desktop/canvasApi.js.map +1 -1
- package/dist/desktop/canvasGraphApi.d.ts.map +1 -1
- package/dist/desktop/canvasGraphApi.js +24 -33
- package/dist/desktop/canvasGraphApi.js.map +1 -1
- package/dist/desktop/canvasSelectionApi.d.ts +2 -0
- package/dist/desktop/canvasSelectionApi.d.ts.map +1 -0
- package/dist/desktop/canvasSelectionApi.js +18 -0
- package/dist/desktop/canvasSelectionApi.js.map +1 -0
- package/dist/desktop/canvasSelectionStore.d.ts +6 -0
- package/dist/desktop/canvasSelectionStore.d.ts.map +1 -0
- package/dist/desktop/canvasSelectionStore.js +88 -0
- package/dist/desktop/canvasSelectionStore.js.map +1 -0
- package/dist/desktop/fileSyncApi.d.ts.map +1 -1
- package/dist/desktop/fileSyncApi.js +77 -16
- package/dist/desktop/fileSyncApi.js.map +1 -1
- package/dist/desktop/graph/editModel.d.ts +18 -6
- package/dist/desktop/graph/editModel.d.ts.map +1 -1
- package/dist/desktop/graph/editModel.js +157 -69
- package/dist/desktop/graph/editModel.js.map +1 -1
- package/dist/desktop/graph/projectProjectionModel.d.ts.map +1 -1
- package/dist/desktop/graph/projectProjectionModel.js +255 -77
- package/dist/desktop/graph/projectProjectionModel.js.map +1 -1
- package/dist/desktop/graph/readModel.d.ts.map +1 -1
- package/dist/desktop/graph/readModel.js +33 -59
- package/dist/desktop/graph/readModel.js.map +1 -1
- package/dist/desktop/graph/resultsFileIndex.d.ts +6 -0
- package/dist/desktop/graph/resultsFileIndex.d.ts.map +1 -1
- package/dist/desktop/graph/resultsFileIndex.js +83 -50
- package/dist/desktop/graph/resultsFileIndex.js.map +1 -1
- package/dist/desktop/graph/searchIndexModel.d.ts +10 -1
- package/dist/desktop/graph/searchIndexModel.d.ts.map +1 -1
- package/dist/desktop/graph/searchIndexModel.js +143 -81
- package/dist/desktop/graph/searchIndexModel.js.map +1 -1
- package/dist/desktop/graph/statisticsIndexModel.d.ts.map +1 -1
- package/dist/desktop/graph/statisticsIndexModel.js +35 -103
- package/dist/desktop/graph/statisticsIndexModel.js.map +1 -1
- package/dist/desktop/graph/todoModel.d.ts +6 -17
- package/dist/desktop/graph/todoModel.d.ts.map +1 -1
- package/dist/desktop/graph/todoModel.js +30 -102
- package/dist/desktop/graph/todoModel.js.map +1 -1
- package/dist/desktop/graphApi.d.ts +1 -1
- package/dist/desktop/graphApi.d.ts.map +1 -1
- package/dist/desktop/graphApi.js +1 -1
- package/dist/desktop/graphApi.js.map +1 -1
- package/dist/desktop/index.d.ts +4 -1
- package/dist/desktop/index.d.ts.map +1 -1
- package/dist/desktop/index.js +3 -1
- package/dist/desktop/index.js.map +1 -1
- package/dist/desktop/layoutApi.d.ts +5 -6
- package/dist/desktop/layoutApi.d.ts.map +1 -1
- package/dist/desktop/layoutApi.js +31 -185
- package/dist/desktop/layoutApi.js.map +1 -1
- package/dist/desktop/layoutStore.d.ts +10 -0
- package/dist/desktop/layoutStore.d.ts.map +1 -0
- package/dist/desktop/layoutStore.js +158 -0
- package/dist/desktop/layoutStore.js.map +1 -0
- package/dist/desktop/projectGraphEditApi.d.ts +12 -0
- package/dist/desktop/projectGraphEditApi.d.ts.map +1 -0
- package/dist/desktop/projectGraphEditApi.js +32 -0
- package/dist/desktop/projectGraphEditApi.js.map +1 -0
- package/dist/desktop/reviewPipelineApi.d.ts.map +1 -1
- package/dist/desktop/reviewPipelineApi.js +28 -28
- package/dist/desktop/reviewPipelineApi.js.map +1 -1
- package/dist/desktop/runApi.d.ts.map +1 -1
- package/dist/desktop/runApi.js +4 -3
- package/dist/desktop/runApi.js.map +1 -1
- package/dist/desktop/types/bridgeTypes.d.ts +12 -4
- package/dist/desktop/types/bridgeTypes.d.ts.map +1 -1
- package/dist/desktop/types/graphTypes.d.ts +12 -0
- package/dist/desktop/types/graphTypes.d.ts.map +1 -1
- package/dist/errors.d.ts +13 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +24 -0
- package/dist/errors.js.map +1 -0
- package/dist/graph/fieldEditMutation.d.ts +2 -0
- package/dist/graph/fieldEditMutation.d.ts.map +1 -1
- package/dist/graph/fieldEditMutation.js +18 -0
- package/dist/graph/fieldEditMutation.js.map +1 -1
- package/dist/index.d.ts +11 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -6
- package/dist/index.js.map +1 -1
- package/dist/package/loadPackage.d.ts.map +1 -1
- package/dist/package/loadPackage.js +4 -0
- package/dist/package/loadPackage.js.map +1 -1
- package/dist/package/manifestEdit.d.ts.map +1 -1
- package/dist/package/manifestEdit.js +112 -31
- package/dist/package/manifestEdit.js.map +1 -1
- package/dist/paths.d.ts.map +1 -1
- package/dist/paths.js +2 -10
- package/dist/paths.js.map +1 -1
- package/dist/plangraph/adapters.d.ts +3 -0
- package/dist/plangraph/adapters.d.ts.map +1 -0
- package/dist/plangraph/adapters.js +13 -0
- package/dist/plangraph/adapters.js.map +1 -0
- package/dist/plangraph/commands.d.ts +191 -0
- package/dist/plangraph/commands.d.ts.map +1 -0
- package/dist/plangraph/commands.js +4 -0
- package/dist/plangraph/commands.js.map +1 -0
- package/dist/plangraph/domain/buildPlanGraph.d.ts +14 -0
- package/dist/plangraph/domain/buildPlanGraph.d.ts.map +1 -0
- package/dist/plangraph/domain/buildPlanGraph.js +91 -0
- package/dist/plangraph/domain/buildPlanGraph.js.map +1 -0
- package/dist/plangraph/domain/selectors.d.ts +11 -0
- package/dist/plangraph/domain/selectors.d.ts.map +1 -0
- package/dist/plangraph/domain/selectors.js +54 -0
- package/dist/plangraph/domain/selectors.js.map +1 -0
- package/dist/plangraph/domain/types.d.ts +56 -0
- package/dist/plangraph/domain/types.d.ts.map +1 -0
- package/dist/plangraph/domain/types.js +2 -0
- package/dist/plangraph/domain/types.js.map +1 -0
- package/dist/plangraph/executeCommand.d.ts +19 -0
- package/dist/plangraph/executeCommand.d.ts.map +1 -0
- package/dist/plangraph/executeCommand.js +809 -0
- package/dist/plangraph/executeCommand.js.map +1 -0
- package/dist/plangraph/hash.d.ts +4 -0
- package/dist/plangraph/hash.d.ts.map +1 -0
- package/dist/plangraph/hash.js +21 -0
- package/dist/plangraph/hash.js.map +1 -0
- package/dist/plangraph/index.d.ts +15 -0
- package/dist/plangraph/index.d.ts.map +1 -0
- package/dist/plangraph/index.js +9 -0
- package/dist/plangraph/index.js.map +1 -0
- package/dist/plangraph/packageRepository.d.ts +19 -0
- package/dist/plangraph/packageRepository.d.ts.map +1 -0
- package/dist/plangraph/packageRepository.js +114 -0
- package/dist/plangraph/packageRepository.js.map +1 -0
- package/dist/plangraph/ports.d.ts +73 -0
- package/dist/plangraph/ports.d.ts.map +1 -0
- package/dist/plangraph/ports.js +2 -0
- package/dist/plangraph/ports.js.map +1 -0
- package/dist/plangraph/projectGraphCommand.d.ts +16 -0
- package/dist/plangraph/projectGraphCommand.d.ts.map +1 -0
- package/dist/plangraph/projectGraphCommand.js +203 -0
- package/dist/plangraph/projectGraphCommand.js.map +1 -0
- package/dist/plangraph/projections/agentContextProjection.d.ts +8 -0
- package/dist/plangraph/projections/agentContextProjection.d.ts.map +1 -0
- package/dist/plangraph/projections/agentContextProjection.js +50 -0
- package/dist/plangraph/projections/agentContextProjection.js.map +1 -0
- package/dist/plangraph/projections/canvasMapProjection.d.ts +13 -0
- package/dist/plangraph/projections/canvasMapProjection.d.ts.map +1 -0
- package/dist/plangraph/projections/canvasMapProjection.js +40 -0
- package/dist/plangraph/projections/canvasMapProjection.js.map +1 -0
- package/dist/plangraph/projections/graphViewProjection.d.ts +16 -0
- package/dist/plangraph/projections/graphViewProjection.d.ts.map +1 -0
- package/dist/plangraph/projections/graphViewProjection.js +125 -0
- package/dist/plangraph/projections/graphViewProjection.js.map +1 -0
- package/dist/plangraph/projections/index.d.ts +10 -0
- package/dist/plangraph/projections/index.d.ts.map +1 -0
- package/dist/plangraph/projections/index.js +6 -0
- package/dist/plangraph/projections/index.js.map +1 -0
- package/dist/plangraph/projections/reviewProjection.d.ts +25 -0
- package/dist/plangraph/projections/reviewProjection.d.ts.map +1 -0
- package/dist/plangraph/projections/reviewProjection.js +27 -0
- package/dist/plangraph/projections/reviewProjection.js.map +1 -0
- package/dist/plangraph/projections/statisticsProjection.d.ts +15 -0
- package/dist/plangraph/projections/statisticsProjection.d.ts.map +1 -0
- package/dist/plangraph/projections/statisticsProjection.js +113 -0
- package/dist/plangraph/projections/statisticsProjection.js.map +1 -0
- package/dist/plangraph/projections/todoProjection.d.ts +43 -0
- package/dist/plangraph/projections/todoProjection.d.ts.map +1 -0
- package/dist/plangraph/projections/todoProjection.js +97 -0
- package/dist/plangraph/projections/todoProjection.js.map +1 -0
- package/dist/plangraph/sqliteIndex.d.ts +11 -0
- package/dist/plangraph/sqliteIndex.d.ts.map +1 -0
- package/dist/plangraph/sqliteIndex.js +655 -0
- package/dist/plangraph/sqliteIndex.js.map +1 -0
- package/dist/project.d.ts +1 -0
- package/dist/project.d.ts.map +1 -1
- package/dist/project.js +11 -0
- package/dist/project.js.map +1 -1
- package/dist/projectGraph/canvasWorkspaceRecovery.d.ts +40 -0
- package/dist/projectGraph/canvasWorkspaceRecovery.d.ts.map +1 -0
- package/dist/projectGraph/canvasWorkspaceRecovery.js +213 -0
- package/dist/projectGraph/canvasWorkspaceRecovery.js.map +1 -0
- package/dist/projectGraph/compileProjectGraph.d.ts.map +1 -1
- package/dist/projectGraph/compileProjectGraph.js +110 -50
- package/dist/projectGraph/compileProjectGraph.js.map +1 -1
- package/dist/projectGraph/index.d.ts +1 -1
- package/dist/projectGraph/index.d.ts.map +1 -1
- package/dist/projectGraph/index.js +1 -1
- package/dist/projectGraph/index.js.map +1 -1
- package/dist/projectGraph/schema.d.ts +1 -0
- package/dist/projectGraph/schema.d.ts.map +1 -1
- package/dist/projectGraph/schema.js +4 -4
- package/dist/projectGraph/schema.js.map +1 -1
- package/dist/projectGraph/types.d.ts +5 -0
- package/dist/projectGraph/types.d.ts.map +1 -1
- package/dist/schema/manifest.d.ts +4 -3
- package/dist/schema/manifest.d.ts.map +1 -1
- package/dist/schema/manifest.js +14 -12
- package/dist/schema/manifest.js.map +1 -1
- package/dist/schemaDocs/index.d.ts +7 -0
- package/dist/schemaDocs/index.d.ts.map +1 -0
- package/dist/schemaDocs/index.js +10 -0
- package/dist/schemaDocs/index.js.map +1 -0
- package/dist/schemaDocs/manifest.d.ts +3 -0
- package/dist/schemaDocs/manifest.d.ts.map +1 -0
- package/dist/schemaDocs/manifest.js +111 -0
- package/dist/schemaDocs/manifest.js.map +1 -0
- package/dist/schemaDocs/project.d.ts +3 -0
- package/dist/schemaDocs/project.d.ts.map +1 -0
- package/dist/schemaDocs/project.js +39 -0
- package/dist/schemaDocs/project.js.map +1 -0
- package/dist/schemaDocs/types.d.ts +11 -0
- package/dist/schemaDocs/types.d.ts.map +1 -0
- package/dist/schemaDocs/types.js +2 -0
- package/dist/schemaDocs/types.js.map +1 -0
- package/dist/taskManager/autoRun.d.ts +1 -0
- package/dist/taskManager/autoRun.d.ts.map +1 -1
- package/dist/taskManager/autoRun.js +2 -2
- package/dist/taskManager/autoRun.js.map +1 -1
- package/dist/taskManager/doctor.d.ts.map +1 -1
- package/dist/taskManager/doctor.js.map +1 -1
- package/dist/taskManager/index.d.ts +1 -0
- package/dist/taskManager/index.d.ts.map +1 -1
- package/dist/taskManager/index.js +1 -0
- package/dist/taskManager/index.js.map +1 -1
- package/dist/taskManager/projectDoctor.d.ts +6 -0
- package/dist/taskManager/projectDoctor.d.ts.map +1 -0
- package/dist/taskManager/projectDoctor.js +192 -0
- package/dist/taskManager/projectDoctor.js.map +1 -0
- package/dist/taskManager/projectDoctorCanvas.d.ts +14 -0
- package/dist/taskManager/projectDoctorCanvas.d.ts.map +1 -0
- package/dist/taskManager/projectDoctorCanvas.js +181 -0
- package/dist/taskManager/projectDoctorCanvas.js.map +1 -0
- package/dist/taskManager/promptRenderer.d.ts.map +1 -1
- package/dist/taskManager/promptRenderer.js +10 -0
- package/dist/taskManager/promptRenderer.js.map +1 -1
- package/dist/taskManager/reviewHook.d.ts +17 -0
- package/dist/taskManager/reviewHook.d.ts.map +1 -1
- package/dist/taskManager/reviewHook.js +113 -25
- package/dist/taskManager/reviewHook.js.map +1 -1
- package/dist/types/autoRun.d.ts +125 -0
- package/dist/types/autoRun.d.ts.map +1 -0
- package/dist/types/autoRun.js +2 -0
- package/dist/types/autoRun.js.map +1 -0
- package/dist/types/executor.d.ts +118 -0
- package/dist/types/executor.d.ts.map +1 -0
- package/dist/types/executor.js +17 -0
- package/dist/types/executor.js.map +1 -0
- package/dist/types/graph.d.ts +100 -0
- package/dist/types/graph.d.ts.map +1 -0
- package/dist/types/graph.js +2 -0
- package/dist/types/graph.js.map +1 -0
- package/dist/types/manifest.d.ts +86 -0
- package/dist/types/manifest.d.ts.map +1 -0
- package/dist/types/manifest.js +6 -0
- package/dist/types/manifest.js.map +1 -0
- package/dist/types/packageFiles.d.ts +26 -0
- package/dist/types/packageFiles.d.ts.map +1 -0
- package/dist/types/packageFiles.js +2 -0
- package/dist/types/packageFiles.js.map +1 -0
- package/dist/types/results.d.ts +24 -0
- package/dist/types/results.d.ts.map +1 -0
- package/dist/types/results.js +4 -0
- package/dist/types/results.js.map +1 -0
- package/dist/types/state.d.ts +38 -0
- package/dist/types/state.d.ts.map +1 -0
- package/dist/types/state.js +5 -0
- package/dist/types/state.js.map +1 -0
- package/dist/types/taskManager.d.ts +259 -0
- package/dist/types/taskManager.d.ts.map +1 -0
- package/dist/types/taskManager.js +2 -0
- package/dist/types/taskManager.js.map +1 -0
- package/dist/types/validation.d.ts +11 -0
- package/dist/types/validation.d.ts.map +1 -0
- package/dist/types/validation.js +2 -0
- package/dist/types/validation.js.map +1 -0
- package/dist/types/workspace.d.ts +55 -0
- package/dist/types/workspace.d.ts.map +1 -0
- package/dist/types/workspace.js +2 -0
- package/dist/types/workspace.js.map +1 -0
- package/dist/types.d.ts +10 -775
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +10 -10
- package/dist/types.js.map +1 -1
- package/dist/validatePackage.d.ts.map +1 -1
- package/dist/validatePackage.js +1 -1
- package/dist/validatePackage.js.map +1 -1
- package/dist/validation/desktopLayoutValidation.d.ts +6 -0
- package/dist/validation/desktopLayoutValidation.d.ts.map +1 -0
- package/dist/validation/desktopLayoutValidation.js +154 -0
- package/dist/validation/desktopLayoutValidation.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,809 @@
|
|
|
1
|
+
import { buildPlanPackageManifestChangeMutation, buildPlanPackageGraphMutation, writePromptSideEffects } from "../graph/mutation.js";
|
|
2
|
+
import { buildPlanPackageBlockFieldEditMutation, buildPlanPackageTaskFieldEditMutation } from "../graph/fieldEditMutation.js";
|
|
3
|
+
import { parseBlockRef } from "../graph/compileTaskGraph.js";
|
|
4
|
+
import { defaultPlanGraphCommandDependencies } from "./adapters.js";
|
|
5
|
+
import { stableJson } from "./hash.js";
|
|
6
|
+
import { applyProjectGraphHistoryCommand, executeProjectGraphCommand, isProjectGraphCommand } from "./projectGraphCommand.js";
|
|
7
|
+
import { emptyAffectedRefs } from "./commands.js";
|
|
8
|
+
function diagnostic(code, message, path) {
|
|
9
|
+
return { code, message, path };
|
|
10
|
+
}
|
|
11
|
+
function fail(options) {
|
|
12
|
+
return {
|
|
13
|
+
ok: false,
|
|
14
|
+
command: options.command,
|
|
15
|
+
graphVersion: options.graphVersion,
|
|
16
|
+
packageFingerprint: options.packageFingerprint,
|
|
17
|
+
affected: emptyAffectedRefs(),
|
|
18
|
+
changedPaths: [],
|
|
19
|
+
diagnostics: options.diagnostics
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function sameEdge(left, right) {
|
|
23
|
+
return left.from === right.from && left.to === right.to && left.type === right.type;
|
|
24
|
+
}
|
|
25
|
+
function taskFromManifest(manifest, taskId) {
|
|
26
|
+
return manifest.nodes.find((node) => node.type === "task" && node.id === taskId);
|
|
27
|
+
}
|
|
28
|
+
function blockFromManifest(manifest, blockRef) {
|
|
29
|
+
const { taskId, blockId } = parseBlockRef(blockRef);
|
|
30
|
+
const task = taskFromManifest(manifest, taskId);
|
|
31
|
+
const block = task?.blocks.find((candidate) => candidate.id === blockId);
|
|
32
|
+
return task && block ? { task, block } : undefined;
|
|
33
|
+
}
|
|
34
|
+
function promptMarkdown(loaded, packagePath) {
|
|
35
|
+
return loaded.promptMarkdownByPath.get(packagePath);
|
|
36
|
+
}
|
|
37
|
+
function readTaskSnapshot(loaded, taskId) {
|
|
38
|
+
const task = taskFromManifest(loaded.manifest, taskId);
|
|
39
|
+
if (!task) {
|
|
40
|
+
return diagnostic("task_missing", `Task '${taskId}' does not exist.`, taskId);
|
|
41
|
+
}
|
|
42
|
+
const insertIndex = loaded.manifest.nodes.findIndex((node) => node.type === "task" && node.id === taskId);
|
|
43
|
+
const taskPromptMarkdown = promptMarkdown(loaded, task.prompt);
|
|
44
|
+
if (taskPromptMarkdown === undefined) {
|
|
45
|
+
return diagnostic("prompt_missing", `Prompt '${task.prompt}' is not indexed.`, task.prompt);
|
|
46
|
+
}
|
|
47
|
+
const blockPromptMarkdown = [];
|
|
48
|
+
for (const block of task.blocks) {
|
|
49
|
+
const markdown = promptMarkdown(loaded, block.prompt);
|
|
50
|
+
if (markdown === undefined) {
|
|
51
|
+
return diagnostic("prompt_missing", `Prompt '${block.prompt}' is not indexed.`, block.prompt);
|
|
52
|
+
}
|
|
53
|
+
blockPromptMarkdown.push({ blockId: block.id, markdown });
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
task: structuredClone(task),
|
|
57
|
+
taskPromptMarkdown,
|
|
58
|
+
blockPromptMarkdown,
|
|
59
|
+
insertIndex: insertIndex >= 0 ? insertIndex : null,
|
|
60
|
+
affectedTaskEdges: loaded.manifest.edges.filter((edge) => edge.from === taskId || edge.to === taskId).map((edge) => structuredClone(edge))
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
function readBlockSnapshot(loaded, blockRef) {
|
|
64
|
+
const current = blockFromManifest(loaded.manifest, blockRef);
|
|
65
|
+
if (!current) {
|
|
66
|
+
return diagnostic("block_missing", `Block '${blockRef}' does not exist.`, blockRef);
|
|
67
|
+
}
|
|
68
|
+
const { blockId } = parseBlockRef(blockRef);
|
|
69
|
+
const insertIndex = current.task.blocks.findIndex((candidate) => candidate.id === blockId);
|
|
70
|
+
const markdown = promptMarkdown(loaded, current.block.prompt);
|
|
71
|
+
if (markdown === undefined) {
|
|
72
|
+
return diagnostic("prompt_missing", `Prompt '${current.block.prompt}' is not indexed.`, current.block.prompt);
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
taskId: current.task.id,
|
|
76
|
+
block: structuredClone(current.block),
|
|
77
|
+
promptMarkdown: markdown,
|
|
78
|
+
insertIndex: insertIndex >= 0 ? insertIndex : null,
|
|
79
|
+
affectedDependsOn: current.task.blocks
|
|
80
|
+
.filter((block) => block.depends_on.includes(blockId))
|
|
81
|
+
.map((block) => ({
|
|
82
|
+
blockRef: `${current.task.id}#${block.id}`,
|
|
83
|
+
dependsOn: [...block.depends_on]
|
|
84
|
+
}))
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function commandPromptHash(loaded, command) {
|
|
88
|
+
if (command.type === "updateTaskPrompt" || (command.type === "updateTaskFields" && command.fields.promptMarkdown !== undefined)) {
|
|
89
|
+
return loaded.graph.tasks.get(command.taskId)?.promptRef.contentHash;
|
|
90
|
+
}
|
|
91
|
+
if (command.type === "updateBlockPrompt" || (command.type === "updateBlockFields" && command.fields.promptMarkdown !== undefined)) {
|
|
92
|
+
return loaded.graph.blocks.get(command.blockRef)?.promptRef.contentHash;
|
|
93
|
+
}
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
96
|
+
function commandBasePromptHash(command) {
|
|
97
|
+
if (command.type === "updateTaskPrompt" || command.type === "updateBlockPrompt") {
|
|
98
|
+
return command.basePromptHash;
|
|
99
|
+
}
|
|
100
|
+
if (command.type === "updateTaskFields" || command.type === "updateBlockFields") {
|
|
101
|
+
return command.fields.basePromptHash;
|
|
102
|
+
}
|
|
103
|
+
return undefined;
|
|
104
|
+
}
|
|
105
|
+
function commandPromptTarget(command) {
|
|
106
|
+
if (command.type === "updateTaskPrompt" || (command.type === "updateTaskFields" && command.fields.promptMarkdown !== undefined)) {
|
|
107
|
+
return command.taskId;
|
|
108
|
+
}
|
|
109
|
+
if (command.type === "updateBlockPrompt" || (command.type === "updateBlockFields" && command.fields.promptMarkdown !== undefined)) {
|
|
110
|
+
return command.blockRef;
|
|
111
|
+
}
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
function validateBaseVersion(loaded, command) {
|
|
115
|
+
if (!command.baseGraphVersion || command.baseGraphVersion === loaded.graph.graphVersion) {
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
const promptTarget = commandPromptTarget(command);
|
|
119
|
+
if (promptTarget) {
|
|
120
|
+
const currentPromptHash = commandPromptHash(loaded, command);
|
|
121
|
+
const basePromptHash = commandBasePromptHash(command);
|
|
122
|
+
if (basePromptHash && currentPromptHash === basePromptHash) {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
return diagnostic("graph_version_conflict", "Prompt changed after the command base graph version; refusing to overwrite newer prompt content.", promptTarget);
|
|
126
|
+
}
|
|
127
|
+
return diagnostic("graph_version_conflict", "Plan graph changed after the command base graph version; re-read the graph before applying this structural command.");
|
|
128
|
+
}
|
|
129
|
+
function validateDependencyCommand(manifest, command) {
|
|
130
|
+
if (command.type !== "addTaskDependency" && command.type !== "removeTaskDependency" && command.type !== "reconnectTaskDependency") {
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
const fromTaskIds = command.type === "reconnectTaskDependency" ? [command.fromTaskId, command.newFromTaskId ?? command.fromTaskId] : [command.fromTaskId];
|
|
134
|
+
const toTaskIds = command.type === "reconnectTaskDependency" ? [command.oldToTaskId, command.newToTaskId] : [command.toTaskId];
|
|
135
|
+
for (const fromTaskId of fromTaskIds) {
|
|
136
|
+
if (!taskFromManifest(manifest, fromTaskId)) {
|
|
137
|
+
return diagnostic("task_missing", `Task '${fromTaskId}' does not exist.`, fromTaskId);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
for (const toTaskId of toTaskIds) {
|
|
141
|
+
if (!taskFromManifest(manifest, toTaskId)) {
|
|
142
|
+
return diagnostic("task_missing", `Task '${toTaskId}' does not exist.`, toTaskId);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
function dependencyEdge(fromTaskId, toTaskId) {
|
|
148
|
+
return { from: fromTaskId, to: toTaskId, type: "depends_on" };
|
|
149
|
+
}
|
|
150
|
+
function reconnectDependencyMutation(manifest, command) {
|
|
151
|
+
const oldEdge = dependencyEdge(command.fromTaskId, command.oldToTaskId);
|
|
152
|
+
const newEdge = dependencyEdge(command.newFromTaskId ?? command.fromTaskId, command.newToTaskId);
|
|
153
|
+
if (sameEdge(oldEdge, newEdge)) {
|
|
154
|
+
return buildPlanPackageManifestChangeMutation(manifest, manifest, { affectedTasks: [command.fromTaskId] });
|
|
155
|
+
}
|
|
156
|
+
if (!manifest.edges.some((edge) => sameEdge(edge, oldEdge))) {
|
|
157
|
+
return diagnostic("edge_missing", "Task dependency edge does not exist.", "edges");
|
|
158
|
+
}
|
|
159
|
+
if (manifest.edges.some((edge) => sameEdge(edge, newEdge))) {
|
|
160
|
+
return diagnostic("edge_duplicate", "Task dependency edge already exists.", "edges");
|
|
161
|
+
}
|
|
162
|
+
return buildPlanPackageManifestChangeMutation(manifest, {
|
|
163
|
+
...manifest,
|
|
164
|
+
edges: [...manifest.edges.filter((edge) => !sameEdge(edge, oldEdge)), newEdge]
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
function mutationForCommand(loaded, command) {
|
|
168
|
+
const baseVersionDiagnostic = validateBaseVersion(loaded, command);
|
|
169
|
+
if (baseVersionDiagnostic) {
|
|
170
|
+
return baseVersionDiagnostic;
|
|
171
|
+
}
|
|
172
|
+
const dependencyDiagnostic = validateDependencyCommand(loaded.manifest, command);
|
|
173
|
+
if (dependencyDiagnostic) {
|
|
174
|
+
return dependencyDiagnostic;
|
|
175
|
+
}
|
|
176
|
+
if (command.type === "addTaskDependency") {
|
|
177
|
+
const edge = dependencyEdge(command.fromTaskId, command.toTaskId);
|
|
178
|
+
if (loaded.manifest.edges.some((candidate) => sameEdge(candidate, edge))) {
|
|
179
|
+
return diagnostic("edge_duplicate", "Task dependency edge already exists.", "edges");
|
|
180
|
+
}
|
|
181
|
+
return buildPlanPackageGraphMutation(loaded.manifest, { kind: "addEdge", edge });
|
|
182
|
+
}
|
|
183
|
+
if (command.type === "removeTaskDependency") {
|
|
184
|
+
const edge = dependencyEdge(command.fromTaskId, command.toTaskId);
|
|
185
|
+
if (!loaded.manifest.edges.some((candidate) => sameEdge(candidate, edge))) {
|
|
186
|
+
return diagnostic("edge_missing", "Task dependency edge does not exist.", "edges");
|
|
187
|
+
}
|
|
188
|
+
return buildPlanPackageGraphMutation(loaded.manifest, { kind: "removeEdge", edge });
|
|
189
|
+
}
|
|
190
|
+
if (command.type === "reconnectTaskDependency") {
|
|
191
|
+
return reconnectDependencyMutation(loaded.manifest, command);
|
|
192
|
+
}
|
|
193
|
+
if (command.type === "updateTaskPrompt") {
|
|
194
|
+
return buildPlanPackageTaskFieldEditMutation(loaded.manifest, {
|
|
195
|
+
taskId: command.taskId,
|
|
196
|
+
promptMarkdown: command.promptMarkdown
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
if (command.type === "updateBlockPrompt") {
|
|
200
|
+
return buildPlanPackageBlockFieldEditMutation(loaded.manifest, {
|
|
201
|
+
blockRef: command.blockRef,
|
|
202
|
+
promptMarkdown: command.promptMarkdown
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
if (command.type === "updateTaskFields") {
|
|
206
|
+
return buildPlanPackageTaskFieldEditMutation(loaded.manifest, {
|
|
207
|
+
taskId: command.taskId,
|
|
208
|
+
title: command.fields.title,
|
|
209
|
+
promptMarkdown: command.fields.promptMarkdown,
|
|
210
|
+
executor: command.fields.executor,
|
|
211
|
+
acceptance: command.fields.acceptance
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
if (command.type === "updateBlockFields") {
|
|
215
|
+
return buildPlanPackageBlockFieldEditMutation(loaded.manifest, {
|
|
216
|
+
blockRef: command.blockRef,
|
|
217
|
+
title: command.fields.title,
|
|
218
|
+
promptMarkdown: command.fields.promptMarkdown,
|
|
219
|
+
executor: command.fields.executor,
|
|
220
|
+
dependsOn: command.fields.dependsOn,
|
|
221
|
+
parallelSafe: command.fields.parallelSafe,
|
|
222
|
+
parallelLocks: command.fields.parallelLocks,
|
|
223
|
+
reviewRequired: command.fields.reviewRequired,
|
|
224
|
+
maxFeedbackCycles: command.fields.maxFeedbackCycles,
|
|
225
|
+
reviewHook: command.fields.reviewHook
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
if (command.type === "addTask" || command.type === "restoreTask") {
|
|
229
|
+
if (taskFromManifest(loaded.manifest, command.snapshot.task.id)) {
|
|
230
|
+
return diagnostic("task_duplicate", `Task '${command.snapshot.task.id}' already exists.`, command.snapshot.task.id);
|
|
231
|
+
}
|
|
232
|
+
const addTaskMutation = buildPlanPackageGraphMutation(loaded.manifest, {
|
|
233
|
+
kind: "addTaskNode",
|
|
234
|
+
node: command.snapshot.task,
|
|
235
|
+
taskPromptMarkdown: command.snapshot.taskPromptMarkdown,
|
|
236
|
+
blockPromptMarkdown: command.snapshot.blockPromptMarkdown
|
|
237
|
+
});
|
|
238
|
+
if (command.type !== "restoreTask") {
|
|
239
|
+
return addTaskMutation;
|
|
240
|
+
}
|
|
241
|
+
const insertIndex = command.snapshot.insertIndex === null
|
|
242
|
+
? loaded.manifest.nodes.length
|
|
243
|
+
: Math.max(0, Math.min(command.snapshot.insertIndex, loaded.manifest.nodes.length));
|
|
244
|
+
const existingEdges = new Set(loaded.manifest.edges.map((edge) => `${edge.type}:${edge.from}:${edge.to}`));
|
|
245
|
+
const restoredEdges = command.snapshot.affectedTaskEdges.filter((edge) => !existingEdges.has(`${edge.type}:${edge.from}:${edge.to}`));
|
|
246
|
+
return buildPlanPackageManifestChangeMutation(loaded.manifest, {
|
|
247
|
+
...loaded.manifest,
|
|
248
|
+
nodes: [
|
|
249
|
+
...loaded.manifest.nodes.slice(0, insertIndex),
|
|
250
|
+
command.snapshot.task,
|
|
251
|
+
...loaded.manifest.nodes.slice(insertIndex)
|
|
252
|
+
],
|
|
253
|
+
edges: [...loaded.manifest.edges, ...restoredEdges]
|
|
254
|
+
}, { affectedTasks: [...addTaskMutation.affectedTasks, command.snapshot.task.id], sideEffects: addTaskMutation.sideEffects });
|
|
255
|
+
}
|
|
256
|
+
if (command.type === "removeTask") {
|
|
257
|
+
if (!taskFromManifest(loaded.manifest, command.taskId)) {
|
|
258
|
+
return diagnostic("task_missing", `Task '${command.taskId}' does not exist.`, command.taskId);
|
|
259
|
+
}
|
|
260
|
+
return buildPlanPackageGraphMutation(loaded.manifest, {
|
|
261
|
+
kind: "removeNode",
|
|
262
|
+
nodeId: command.taskId,
|
|
263
|
+
removeTaskDirectory: true
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
if (command.type === "addBlock" || command.type === "restoreBlock") {
|
|
267
|
+
const task = taskFromManifest(loaded.manifest, command.snapshot.taskId);
|
|
268
|
+
if (!task) {
|
|
269
|
+
return diagnostic("task_missing", `Task '${command.snapshot.taskId}' does not exist.`, command.snapshot.taskId);
|
|
270
|
+
}
|
|
271
|
+
if (task.blocks.some((block) => block.id === command.snapshot.block.id)) {
|
|
272
|
+
return diagnostic("block_duplicate", `Block '${command.snapshot.taskId}#${command.snapshot.block.id}' already exists.`, command.snapshot.block.id);
|
|
273
|
+
}
|
|
274
|
+
if (command.type === "restoreBlock") {
|
|
275
|
+
const insertIndex = command.snapshot.insertIndex === null
|
|
276
|
+
? task.blocks.length
|
|
277
|
+
: Math.max(0, Math.min(command.snapshot.insertIndex, task.blocks.length));
|
|
278
|
+
const blocksWithRestoredBlock = [
|
|
279
|
+
...task.blocks.slice(0, insertIndex),
|
|
280
|
+
command.snapshot.block,
|
|
281
|
+
...task.blocks.slice(insertIndex)
|
|
282
|
+
];
|
|
283
|
+
const nextTask = {
|
|
284
|
+
...task,
|
|
285
|
+
blocks: blocksWithRestoredBlock.map((block) => {
|
|
286
|
+
const ref = `${task.id}#${block.id}`;
|
|
287
|
+
const affected = command.snapshot.affectedDependsOn.find((item) => item.blockRef === ref);
|
|
288
|
+
return affected ? { ...block, depends_on: [...affected.dependsOn] } : block;
|
|
289
|
+
})
|
|
290
|
+
};
|
|
291
|
+
return buildPlanPackageManifestChangeMutation(loaded.manifest, {
|
|
292
|
+
...loaded.manifest,
|
|
293
|
+
nodes: loaded.manifest.nodes.map((node) => (node.type === "task" && node.id === task.id ? nextTask : node))
|
|
294
|
+
}, { affectedTasks: [task.id], sideEffects: writePromptSideEffects(command.snapshot.block.prompt, command.snapshot.promptMarkdown) });
|
|
295
|
+
}
|
|
296
|
+
return buildPlanPackageGraphMutation(loaded.manifest, {
|
|
297
|
+
kind: "addBlock",
|
|
298
|
+
taskId: command.snapshot.taskId,
|
|
299
|
+
block: command.snapshot.block,
|
|
300
|
+
promptMarkdown: command.snapshot.promptMarkdown
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
if (command.type === "removeBlock") {
|
|
304
|
+
if (!blockFromManifest(loaded.manifest, command.blockRef)) {
|
|
305
|
+
return diagnostic("block_missing", `Block '${command.blockRef}' does not exist.`, command.blockRef);
|
|
306
|
+
}
|
|
307
|
+
return buildPlanPackageGraphMutation(loaded.manifest, { kind: "removeBlock", blockRef: command.blockRef });
|
|
308
|
+
}
|
|
309
|
+
if (command.type === "updateReviewPipeline") {
|
|
310
|
+
const task = taskFromManifest(loaded.manifest, command.taskId);
|
|
311
|
+
if (!task) {
|
|
312
|
+
return diagnostic("task_missing", `Task '${command.taskId}' does not exist.`, command.taskId);
|
|
313
|
+
}
|
|
314
|
+
const reviewPromptPaths = new Set(command.reviewBlocks.map((block) => block.prompt));
|
|
315
|
+
const removedPrompts = task.blocks
|
|
316
|
+
.filter((block) => block.type === "review" && !reviewPromptPaths.has(block.prompt))
|
|
317
|
+
.map((block) => ({ kind: "removePrompt", packagePath: block.prompt }));
|
|
318
|
+
const promptMarkdownByBlockId = new Map(command.promptMarkdownByBlockId.map((item) => [item.blockId, item.markdown]));
|
|
319
|
+
const sideEffects = [
|
|
320
|
+
...removedPrompts,
|
|
321
|
+
...command.reviewBlocks.flatMap((block) => writePromptSideEffects(block.prompt, promptMarkdownByBlockId.get(block.id) ?? ""))
|
|
322
|
+
];
|
|
323
|
+
const nextTask = {
|
|
324
|
+
...task,
|
|
325
|
+
blocks: [...task.blocks.filter((block) => block.type !== "review"), ...command.reviewBlocks]
|
|
326
|
+
};
|
|
327
|
+
return buildPlanPackageManifestChangeMutation(loaded.manifest, {
|
|
328
|
+
...loaded.manifest,
|
|
329
|
+
review: { ...command.packageDefaults },
|
|
330
|
+
nodes: loaded.manifest.nodes.map((node) => (node.type === "task" && node.id === command.taskId ? nextTask : node))
|
|
331
|
+
}, { affectedTasks: [command.taskId], sideEffects });
|
|
332
|
+
}
|
|
333
|
+
return diagnostic("layout_command_not_handled", "PlanGraph layout commands are defined here but still written by the existing layout API.");
|
|
334
|
+
}
|
|
335
|
+
function inverseForCommand(loaded, command) {
|
|
336
|
+
if (command.type === "addTaskDependency") {
|
|
337
|
+
return { type: "removeTaskDependency", fromTaskId: command.fromTaskId, toTaskId: command.toTaskId };
|
|
338
|
+
}
|
|
339
|
+
if (command.type === "removeTaskDependency") {
|
|
340
|
+
return { type: "addTaskDependency", fromTaskId: command.fromTaskId, toTaskId: command.toTaskId };
|
|
341
|
+
}
|
|
342
|
+
if (command.type === "reconnectTaskDependency") {
|
|
343
|
+
return {
|
|
344
|
+
type: "reconnectTaskDependency",
|
|
345
|
+
fromTaskId: command.newFromTaskId ?? command.fromTaskId,
|
|
346
|
+
oldToTaskId: command.newToTaskId,
|
|
347
|
+
newFromTaskId: command.fromTaskId,
|
|
348
|
+
newToTaskId: command.oldToTaskId
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
if (command.type === "updateTaskPrompt") {
|
|
352
|
+
const task = taskFromManifest(loaded.manifest, command.taskId);
|
|
353
|
+
const markdown = task ? promptMarkdown(loaded, task.prompt) : undefined;
|
|
354
|
+
return markdown === undefined
|
|
355
|
+
? diagnostic("prompt_missing", `Prompt for task '${command.taskId}' is not indexed.`, command.taskId)
|
|
356
|
+
: {
|
|
357
|
+
type: "updateTaskPrompt",
|
|
358
|
+
taskId: command.taskId,
|
|
359
|
+
promptMarkdown: markdown
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
if (command.type === "updateBlockPrompt") {
|
|
363
|
+
const current = blockFromManifest(loaded.manifest, command.blockRef);
|
|
364
|
+
const markdown = current ? promptMarkdown(loaded, current.block.prompt) : undefined;
|
|
365
|
+
return markdown === undefined
|
|
366
|
+
? diagnostic("prompt_missing", `Prompt for block '${command.blockRef}' is not indexed.`, command.blockRef)
|
|
367
|
+
: {
|
|
368
|
+
type: "updateBlockPrompt",
|
|
369
|
+
blockRef: command.blockRef,
|
|
370
|
+
promptMarkdown: markdown
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
if (command.type === "updateTaskFields") {
|
|
374
|
+
const task = taskFromManifest(loaded.manifest, command.taskId);
|
|
375
|
+
if (!task) {
|
|
376
|
+
return diagnostic("task_missing", `Task '${command.taskId}' does not exist.`, command.taskId);
|
|
377
|
+
}
|
|
378
|
+
const fields = {};
|
|
379
|
+
if (command.fields.title !== undefined) {
|
|
380
|
+
fields.title = task.title;
|
|
381
|
+
}
|
|
382
|
+
if (command.fields.promptMarkdown !== undefined) {
|
|
383
|
+
const markdown = promptMarkdown(loaded, task.prompt);
|
|
384
|
+
if (markdown === undefined) {
|
|
385
|
+
return diagnostic("prompt_missing", `Prompt for task '${command.taskId}' is not indexed.`, command.taskId);
|
|
386
|
+
}
|
|
387
|
+
fields.promptMarkdown = markdown;
|
|
388
|
+
}
|
|
389
|
+
if (command.fields.executor !== undefined) {
|
|
390
|
+
fields.executor = task.executor ?? null;
|
|
391
|
+
}
|
|
392
|
+
if (command.fields.acceptance !== undefined) {
|
|
393
|
+
fields.acceptance = [...task.acceptance];
|
|
394
|
+
}
|
|
395
|
+
const inverse = { type: "updateTaskFields", taskId: command.taskId, fields };
|
|
396
|
+
if (command.fields.executor === undefined) {
|
|
397
|
+
return inverse;
|
|
398
|
+
}
|
|
399
|
+
const blockExecutorRestores = task.blocks
|
|
400
|
+
.filter((block) => block.executor !== undefined)
|
|
401
|
+
.map((block) => ({
|
|
402
|
+
type: "updateBlockFields",
|
|
403
|
+
blockRef: `${task.id}#${block.id}`,
|
|
404
|
+
fields: { executor: block.executor ?? null }
|
|
405
|
+
}));
|
|
406
|
+
return blockExecutorRestores.length === 0 ? inverse : [inverse, ...blockExecutorRestores];
|
|
407
|
+
}
|
|
408
|
+
if (command.type === "updateBlockFields") {
|
|
409
|
+
const current = blockFromManifest(loaded.manifest, command.blockRef);
|
|
410
|
+
if (!current) {
|
|
411
|
+
return diagnostic("block_missing", `Block '${command.blockRef}' does not exist.`, command.blockRef);
|
|
412
|
+
}
|
|
413
|
+
const fields = {};
|
|
414
|
+
if (command.fields.title !== undefined) {
|
|
415
|
+
fields.title = current.block.title;
|
|
416
|
+
}
|
|
417
|
+
if (command.fields.promptMarkdown !== undefined) {
|
|
418
|
+
const markdown = promptMarkdown(loaded, current.block.prompt);
|
|
419
|
+
if (markdown === undefined) {
|
|
420
|
+
return diagnostic("prompt_missing", `Prompt for block '${command.blockRef}' is not indexed.`, command.blockRef);
|
|
421
|
+
}
|
|
422
|
+
fields.promptMarkdown = markdown;
|
|
423
|
+
}
|
|
424
|
+
if (command.fields.executor !== undefined) {
|
|
425
|
+
fields.executor = current.block.executor ?? null;
|
|
426
|
+
}
|
|
427
|
+
if (command.fields.dependsOn !== undefined) {
|
|
428
|
+
fields.dependsOn = [...current.block.depends_on];
|
|
429
|
+
}
|
|
430
|
+
if (current.block.type === "implementation") {
|
|
431
|
+
if (command.fields.parallelSafe !== undefined) {
|
|
432
|
+
fields.parallelSafe = current.block.parallel.safe;
|
|
433
|
+
}
|
|
434
|
+
if (command.fields.parallelLocks !== undefined) {
|
|
435
|
+
fields.parallelLocks = [...current.block.parallel.locks];
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
else {
|
|
439
|
+
if (command.fields.reviewRequired !== undefined) {
|
|
440
|
+
fields.reviewRequired = current.block.review.required;
|
|
441
|
+
}
|
|
442
|
+
if (command.fields.maxFeedbackCycles !== undefined) {
|
|
443
|
+
fields.maxFeedbackCycles = current.block.review.maxFeedbackCycles;
|
|
444
|
+
}
|
|
445
|
+
if (command.fields.reviewHook !== undefined) {
|
|
446
|
+
fields.reviewHook = current.block.review.hook;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
return { type: "updateBlockFields", blockRef: command.blockRef, fields };
|
|
450
|
+
}
|
|
451
|
+
if (command.type === "addTask" || command.type === "restoreTask") {
|
|
452
|
+
return { type: "removeTask", taskId: command.snapshot.task.id };
|
|
453
|
+
}
|
|
454
|
+
if (command.type === "removeTask") {
|
|
455
|
+
return snapshotOrDiagnostic(readTaskSnapshot(loaded, command.taskId), (snapshot) => ({
|
|
456
|
+
type: "restoreTask",
|
|
457
|
+
snapshot: { ...snapshot, layoutNode: command.layoutNode ?? snapshot.layoutNode ?? null }
|
|
458
|
+
}));
|
|
459
|
+
}
|
|
460
|
+
if (command.type === "addBlock" || command.type === "restoreBlock") {
|
|
461
|
+
return { type: "removeBlock", blockRef: `${command.snapshot.taskId}#${command.snapshot.block.id}` };
|
|
462
|
+
}
|
|
463
|
+
if (command.type === "removeBlock") {
|
|
464
|
+
return snapshotOrDiagnostic(readBlockSnapshot(loaded, command.blockRef), (snapshot) => ({ type: "restoreBlock", snapshot }));
|
|
465
|
+
}
|
|
466
|
+
if (command.type === "updateReviewPipeline") {
|
|
467
|
+
const task = taskFromManifest(loaded.manifest, command.taskId);
|
|
468
|
+
if (!task) {
|
|
469
|
+
return diagnostic("task_missing", `Task '${command.taskId}' does not exist.`, command.taskId);
|
|
470
|
+
}
|
|
471
|
+
const promptMarkdownByBlockId = [];
|
|
472
|
+
for (const block of task.blocks) {
|
|
473
|
+
if (block.type !== "review") {
|
|
474
|
+
continue;
|
|
475
|
+
}
|
|
476
|
+
const markdown = promptMarkdown(loaded, block.prompt);
|
|
477
|
+
if (markdown === undefined) {
|
|
478
|
+
return diagnostic("prompt_missing", `Prompt for block '${command.taskId}#${block.id}' is not indexed.`, block.prompt);
|
|
479
|
+
}
|
|
480
|
+
promptMarkdownByBlockId.push({ blockId: block.id, markdown });
|
|
481
|
+
}
|
|
482
|
+
return {
|
|
483
|
+
type: "updateReviewPipeline",
|
|
484
|
+
taskId: command.taskId,
|
|
485
|
+
packageDefaults: { ...loaded.manifest.review },
|
|
486
|
+
reviewBlocks: task.blocks.filter((block) => block.type === "review").map((block) => structuredClone(block)),
|
|
487
|
+
promptMarkdownByBlockId
|
|
488
|
+
};
|
|
489
|
+
}
|
|
490
|
+
return diagnostic("layout_command_not_handled", "PlanGraph layout commands are not undoable here.");
|
|
491
|
+
}
|
|
492
|
+
function snapshotOrDiagnostic(value, build) {
|
|
493
|
+
return isPlanGraphCommandDiagnostic(value) ? value : build(value);
|
|
494
|
+
}
|
|
495
|
+
function isPlanGraphCommandDiagnostic(value) {
|
|
496
|
+
return value !== null && typeof value === "object" && "code" in value && "message" in value;
|
|
497
|
+
}
|
|
498
|
+
function commandTouchedRefs(command, loaded) {
|
|
499
|
+
if (command.type === "addTaskDependency" || command.type === "removeTaskDependency") {
|
|
500
|
+
return { tasks: [command.fromTaskId], blocks: [] };
|
|
501
|
+
}
|
|
502
|
+
if (command.type === "reconnectTaskDependency") {
|
|
503
|
+
return { tasks: [command.fromTaskId, command.newFromTaskId ?? command.fromTaskId], blocks: [] };
|
|
504
|
+
}
|
|
505
|
+
if (command.type === "updateTaskPrompt" || command.type === "updateTaskFields" || command.type === "removeTask") {
|
|
506
|
+
return { tasks: [command.taskId], blocks: [] };
|
|
507
|
+
}
|
|
508
|
+
if (command.type === "updateBlockPrompt" || command.type === "updateBlockFields" || command.type === "removeBlock") {
|
|
509
|
+
const { taskId, blockId } = parseBlockRef(command.blockRef);
|
|
510
|
+
const task = taskFromManifest(loaded.manifest, taskId);
|
|
511
|
+
const dependentBlocks = task?.blocks
|
|
512
|
+
.filter((block) => block.depends_on.includes(blockId))
|
|
513
|
+
.map((block) => `${taskId}#${block.id}`) ?? [];
|
|
514
|
+
return { tasks: [taskId], blocks: [command.blockRef, ...dependentBlocks] };
|
|
515
|
+
}
|
|
516
|
+
if (command.type === "addTask" || command.type === "restoreTask") {
|
|
517
|
+
return { tasks: [command.snapshot.task.id], blocks: command.snapshot.task.blocks.map((block) => `${command.snapshot.task.id}#${block.id}`) };
|
|
518
|
+
}
|
|
519
|
+
if (command.type === "addBlock" || command.type === "restoreBlock") {
|
|
520
|
+
return {
|
|
521
|
+
tasks: [command.snapshot.taskId],
|
|
522
|
+
blocks: [`${command.snapshot.taskId}#${command.snapshot.block.id}`, ...command.snapshot.affectedDependsOn.map((item) => item.blockRef)]
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
if (command.type === "updateReviewPipeline") {
|
|
526
|
+
return {
|
|
527
|
+
tasks: [command.taskId],
|
|
528
|
+
blocks: command.reviewBlocks.map((block) => `${command.taskId}#${block.id}`)
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
return { tasks: [], blocks: [] };
|
|
532
|
+
}
|
|
533
|
+
function affectedRefs(command, mutation, loaded) {
|
|
534
|
+
const touched = commandTouchedRefs(command, loaded);
|
|
535
|
+
const prompts = mutation.sideEffects
|
|
536
|
+
.filter((sideEffect) => sideEffect.kind === "writePrompt" || sideEffect.kind === "removePrompt")
|
|
537
|
+
.map((sideEffect) => sideEffect.packagePath);
|
|
538
|
+
return {
|
|
539
|
+
canvases: [],
|
|
540
|
+
tasks: [...new Set([...mutation.affectedTasks, ...touched.tasks])],
|
|
541
|
+
blocks: [...new Set(touched.blocks)],
|
|
542
|
+
prompts: [...new Set(prompts)],
|
|
543
|
+
packageFiles: [...new Set([...(mutation.nextManifest ? ["manifest.json"] : []), ...prompts])]
|
|
544
|
+
};
|
|
545
|
+
}
|
|
546
|
+
function changedPaths(repository, loaded, affected) {
|
|
547
|
+
return affected.packageFiles.map((path) => repository.packageFilePath(loaded, path));
|
|
548
|
+
}
|
|
549
|
+
function isNoopMutation(loaded, mutation) {
|
|
550
|
+
return mutation.sideEffects.length === 0 && JSON.stringify(mutation.nextManifest) === JSON.stringify(loaded.manifest);
|
|
551
|
+
}
|
|
552
|
+
function isDiagnostic(value) {
|
|
553
|
+
return isPlanGraphCommandDiagnostic(value);
|
|
554
|
+
}
|
|
555
|
+
async function executeLayoutCommand(options, dependencies) {
|
|
556
|
+
const command = options.command;
|
|
557
|
+
if (command.type !== "updateLayout") {
|
|
558
|
+
throw new Error("executeLayoutCommand requires an updateLayout command.");
|
|
559
|
+
}
|
|
560
|
+
const recordOperation = options.recordOperation ?? true;
|
|
561
|
+
const loaded = await dependencies.repository.load(options.projectRoot);
|
|
562
|
+
let previousLayout;
|
|
563
|
+
try {
|
|
564
|
+
previousLayout = await dependencies.layoutStore.read(options.projectRoot, command.layoutScope);
|
|
565
|
+
}
|
|
566
|
+
catch (caught) {
|
|
567
|
+
return fail({
|
|
568
|
+
command,
|
|
569
|
+
diagnostics: [diagnostic("layout_read_failed", caught instanceof Error ? caught.message : String(caught), command.layoutScope)],
|
|
570
|
+
graphVersion: loaded.graph.graphVersion,
|
|
571
|
+
packageFingerprint: loaded.graph.packageFingerprint
|
|
572
|
+
});
|
|
573
|
+
}
|
|
574
|
+
const inverse = {
|
|
575
|
+
type: "updateLayout",
|
|
576
|
+
layoutScope: command.layoutScope,
|
|
577
|
+
layout: previousLayout
|
|
578
|
+
};
|
|
579
|
+
if (stableJson(previousLayout) === stableJson(command.layout)) {
|
|
580
|
+
return {
|
|
581
|
+
ok: true,
|
|
582
|
+
workspaceRef: loaded.workspace,
|
|
583
|
+
graphVersion: loaded.graph.graphVersion,
|
|
584
|
+
packageFingerprint: loaded.graph.packageFingerprint,
|
|
585
|
+
command,
|
|
586
|
+
inverse,
|
|
587
|
+
affected: emptyAffectedRefs(),
|
|
588
|
+
changedPaths: [],
|
|
589
|
+
diagnostics: []
|
|
590
|
+
};
|
|
591
|
+
}
|
|
592
|
+
try {
|
|
593
|
+
await dependencies.layoutStore.write(options.projectRoot, command.layoutScope, command.layout);
|
|
594
|
+
}
|
|
595
|
+
catch (caught) {
|
|
596
|
+
return fail({
|
|
597
|
+
command,
|
|
598
|
+
diagnostics: [diagnostic("layout_write_failed", caught instanceof Error ? caught.message : String(caught), command.layoutScope)],
|
|
599
|
+
graphVersion: loaded.graph.graphVersion,
|
|
600
|
+
packageFingerprint: loaded.graph.packageFingerprint
|
|
601
|
+
});
|
|
602
|
+
}
|
|
603
|
+
const store = await dependencies.createIndexStore({ projectRoot: options.projectRoot, indexPath: options.indexPath });
|
|
604
|
+
const affected = {
|
|
605
|
+
...emptyAffectedRefs(),
|
|
606
|
+
packageFiles: command.layoutScope === "desktop" ? ["desktop/layout.json"] : ["desktop/canvases.json"]
|
|
607
|
+
};
|
|
608
|
+
const result = {
|
|
609
|
+
ok: true,
|
|
610
|
+
workspaceRef: loaded.workspace,
|
|
611
|
+
graphVersion: loaded.graph.graphVersion,
|
|
612
|
+
packageFingerprint: loaded.graph.packageFingerprint,
|
|
613
|
+
command,
|
|
614
|
+
inverse,
|
|
615
|
+
affected,
|
|
616
|
+
changedPaths: affected.packageFiles,
|
|
617
|
+
diagnostics: []
|
|
618
|
+
};
|
|
619
|
+
if (recordOperation) {
|
|
620
|
+
result.operationId = await store.log.append({
|
|
621
|
+
workspaceRef: loaded.workspace,
|
|
622
|
+
graphVersionBefore: loaded.graph.graphVersion,
|
|
623
|
+
graphVersionAfter: loaded.graph.graphVersion,
|
|
624
|
+
command,
|
|
625
|
+
inverse,
|
|
626
|
+
affected
|
|
627
|
+
});
|
|
628
|
+
}
|
|
629
|
+
return result;
|
|
630
|
+
}
|
|
631
|
+
export async function executePlanGraphCommand(options) {
|
|
632
|
+
const dependencies = {
|
|
633
|
+
...defaultPlanGraphCommandDependencies,
|
|
634
|
+
...options.dependencies
|
|
635
|
+
};
|
|
636
|
+
if (isProjectGraphCommand(options.command)) {
|
|
637
|
+
return executeProjectGraphCommand({
|
|
638
|
+
projectRoot: options.projectRoot,
|
|
639
|
+
command: options.command,
|
|
640
|
+
indexPath: options.indexPath,
|
|
641
|
+
recordOperation: options.recordOperation
|
|
642
|
+
}, dependencies);
|
|
643
|
+
}
|
|
644
|
+
if (options.command.type === "updateLayout") {
|
|
645
|
+
return executeLayoutCommand(options, dependencies);
|
|
646
|
+
}
|
|
647
|
+
const recordOperation = options.recordOperation ?? true;
|
|
648
|
+
const loaded = await dependencies.repository.load(options.projectRoot);
|
|
649
|
+
const inverse = inverseForCommand(loaded, options.command);
|
|
650
|
+
if (isDiagnostic(inverse)) {
|
|
651
|
+
return fail({
|
|
652
|
+
command: options.command,
|
|
653
|
+
diagnostics: [inverse],
|
|
654
|
+
graphVersion: loaded.graph.graphVersion,
|
|
655
|
+
packageFingerprint: loaded.graph.packageFingerprint
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
let mutation;
|
|
659
|
+
try {
|
|
660
|
+
mutation = mutationForCommand(loaded, options.command);
|
|
661
|
+
}
|
|
662
|
+
catch (caught) {
|
|
663
|
+
return fail({
|
|
664
|
+
command: options.command,
|
|
665
|
+
diagnostics: [
|
|
666
|
+
diagnostic("command_validation_failed", caught instanceof Error ? caught.message : String(caught))
|
|
667
|
+
],
|
|
668
|
+
graphVersion: loaded.graph.graphVersion,
|
|
669
|
+
packageFingerprint: loaded.graph.packageFingerprint
|
|
670
|
+
});
|
|
671
|
+
}
|
|
672
|
+
if (isDiagnostic(mutation)) {
|
|
673
|
+
return fail({
|
|
674
|
+
command: options.command,
|
|
675
|
+
diagnostics: [mutation],
|
|
676
|
+
graphVersion: loaded.graph.graphVersion,
|
|
677
|
+
packageFingerprint: loaded.graph.packageFingerprint
|
|
678
|
+
});
|
|
679
|
+
}
|
|
680
|
+
if (isNoopMutation(loaded, mutation)) {
|
|
681
|
+
return {
|
|
682
|
+
ok: true,
|
|
683
|
+
workspaceRef: loaded.workspace,
|
|
684
|
+
graphVersion: loaded.graph.graphVersion,
|
|
685
|
+
packageFingerprint: loaded.graph.packageFingerprint,
|
|
686
|
+
command: options.command,
|
|
687
|
+
inverse,
|
|
688
|
+
affected: emptyAffectedRefs(),
|
|
689
|
+
changedPaths: [],
|
|
690
|
+
diagnostics: []
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
const commitDiagnostics = await dependencies.repository.commit({ projectRoot: options.projectRoot, mutation });
|
|
694
|
+
if (commitDiagnostics.length > 0) {
|
|
695
|
+
return fail({
|
|
696
|
+
command: options.command,
|
|
697
|
+
diagnostics: commitDiagnostics,
|
|
698
|
+
graphVersion: loaded.graph.graphVersion,
|
|
699
|
+
packageFingerprint: loaded.graph.packageFingerprint
|
|
700
|
+
});
|
|
701
|
+
}
|
|
702
|
+
const store = await dependencies.createIndexStore({ projectRoot: options.projectRoot, indexPath: options.indexPath });
|
|
703
|
+
const graph = await store.rebuild();
|
|
704
|
+
const affected = affectedRefs(options.command, mutation, loaded);
|
|
705
|
+
const result = {
|
|
706
|
+
ok: true,
|
|
707
|
+
workspaceRef: loaded.workspace,
|
|
708
|
+
graphVersion: graph.graphVersion,
|
|
709
|
+
packageFingerprint: graph.packageFingerprint,
|
|
710
|
+
command: options.command,
|
|
711
|
+
inverse,
|
|
712
|
+
affected,
|
|
713
|
+
changedPaths: changedPaths(dependencies.repository, loaded, affected),
|
|
714
|
+
diagnostics: []
|
|
715
|
+
};
|
|
716
|
+
if (recordOperation) {
|
|
717
|
+
result.operationId = await store.log.append({
|
|
718
|
+
workspaceRef: loaded.workspace,
|
|
719
|
+
graphVersionBefore: loaded.graph.graphVersion,
|
|
720
|
+
graphVersionAfter: graph.graphVersion,
|
|
721
|
+
command: options.command,
|
|
722
|
+
inverse,
|
|
723
|
+
affected
|
|
724
|
+
});
|
|
725
|
+
}
|
|
726
|
+
return result;
|
|
727
|
+
}
|
|
728
|
+
async function applyHistoryCommand(options, command, expectedGraphVersion, workspaceRef) {
|
|
729
|
+
const dependencies = {
|
|
730
|
+
...defaultPlanGraphCommandDependencies,
|
|
731
|
+
...options.dependencies
|
|
732
|
+
};
|
|
733
|
+
if (!Array.isArray(command) && isProjectGraphCommand(command)) {
|
|
734
|
+
return applyProjectGraphHistoryCommand({ indexPath: options.indexPath }, dependencies, command, expectedGraphVersion, workspaceRef);
|
|
735
|
+
}
|
|
736
|
+
const loaded = await dependencies.repository.load(workspaceRef);
|
|
737
|
+
if (loaded.graph.graphVersion !== expectedGraphVersion) {
|
|
738
|
+
return fail({
|
|
739
|
+
command: Array.isArray(command) ? command[0] ?? { type: "updateLayout", layoutScope: "desktop", layout: null } : command,
|
|
740
|
+
diagnostics: [
|
|
741
|
+
diagnostic("graph_version_conflict", "Plan graph changed after this history entry was recorded; refusing to apply stale undo/redo.")
|
|
742
|
+
],
|
|
743
|
+
graphVersion: loaded.graph.graphVersion,
|
|
744
|
+
packageFingerprint: loaded.graph.packageFingerprint
|
|
745
|
+
});
|
|
746
|
+
}
|
|
747
|
+
const commands = Array.isArray(command) ? command : [command];
|
|
748
|
+
let latest = null;
|
|
749
|
+
for (const item of commands) {
|
|
750
|
+
latest = await executePlanGraphCommand({
|
|
751
|
+
...options,
|
|
752
|
+
projectRoot: workspaceRef,
|
|
753
|
+
command: commandForHistoryReplay(item),
|
|
754
|
+
recordOperation: false,
|
|
755
|
+
dependencies
|
|
756
|
+
});
|
|
757
|
+
if (!latest.ok) {
|
|
758
|
+
return latest;
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
if (!latest) {
|
|
762
|
+
return fail({ command: { type: "updateLayout", layoutScope: "desktop", layout: null }, diagnostics: [diagnostic("history_empty", "No command to apply.")] });
|
|
763
|
+
}
|
|
764
|
+
return latest;
|
|
765
|
+
}
|
|
766
|
+
function commandForHistoryReplay(command) {
|
|
767
|
+
const replayCommand = structuredClone(command);
|
|
768
|
+
delete replayCommand.baseGraphVersion;
|
|
769
|
+
if (replayCommand.type === "updateTaskPrompt" || replayCommand.type === "updateBlockPrompt") {
|
|
770
|
+
delete replayCommand.basePromptHash;
|
|
771
|
+
}
|
|
772
|
+
if (replayCommand.type === "updateTaskFields" || replayCommand.type === "updateBlockFields") {
|
|
773
|
+
delete replayCommand.fields.basePromptHash;
|
|
774
|
+
}
|
|
775
|
+
return replayCommand;
|
|
776
|
+
}
|
|
777
|
+
export async function undoPlanGraphCommand(options) {
|
|
778
|
+
const dependencies = {
|
|
779
|
+
...defaultPlanGraphCommandDependencies,
|
|
780
|
+
...options.dependencies
|
|
781
|
+
};
|
|
782
|
+
const store = await dependencies.createIndexStore(options);
|
|
783
|
+
const entry = await store.log.latestUndoable();
|
|
784
|
+
if (!entry) {
|
|
785
|
+
return fail({ command: { type: "updateLayout", layoutScope: "desktop", layout: null }, diagnostics: [diagnostic("history_empty", "No command to undo.")] });
|
|
786
|
+
}
|
|
787
|
+
const result = await applyHistoryCommand(options, entry.inverse, entry.graphVersionAfter, entry.workspaceRef);
|
|
788
|
+
if (result.ok) {
|
|
789
|
+
await store.log.markUndone(entry.id);
|
|
790
|
+
}
|
|
791
|
+
return result;
|
|
792
|
+
}
|
|
793
|
+
export async function redoPlanGraphCommand(options) {
|
|
794
|
+
const dependencies = {
|
|
795
|
+
...defaultPlanGraphCommandDependencies,
|
|
796
|
+
...options.dependencies
|
|
797
|
+
};
|
|
798
|
+
const store = await dependencies.createIndexStore(options);
|
|
799
|
+
const entry = await store.log.latestRedoable();
|
|
800
|
+
if (!entry) {
|
|
801
|
+
return fail({ command: { type: "updateLayout", layoutScope: "desktop", layout: null }, diagnostics: [diagnostic("history_empty", "No command to redo.")] });
|
|
802
|
+
}
|
|
803
|
+
const result = await applyHistoryCommand(options, entry.command, entry.graphVersionBefore, entry.workspaceRef);
|
|
804
|
+
if (result.ok) {
|
|
805
|
+
await store.log.markRedone(entry.id);
|
|
806
|
+
}
|
|
807
|
+
return result;
|
|
808
|
+
}
|
|
809
|
+
//# sourceMappingURL=executeCommand.js.map
|