dsh-plugin-local-infer 0.1.2 → 0.1.4
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 +32 -6
- package/cordis.patch.yml +7 -0
- package/docs/zh/README.md +24 -4
- package/dsh/client.js +4200 -4049
- package/package.json +33 -11
- package/packages/core/lib/adapter.d.ts +177 -11
- package/packages/core/lib/adapter.js +74 -1
- package/packages/core/lib/config.d.ts +1 -1
- package/packages/core/lib/config.js +1 -1
- package/packages/core/lib/debug.d.ts +1 -1
- package/packages/core/lib/debug.js +1 -1
- package/packages/core/lib/defaults.d.ts +1 -1
- package/packages/core/lib/defaults.js +1 -1
- package/packages/core/lib/deps.d.ts +48 -20
- package/packages/core/lib/deps.js +24 -8
- package/packages/core/lib/estimator.d.ts +1 -1
- package/packages/core/lib/estimator.js +1 -1
- package/packages/core/lib/guideline.d.ts +1 -1
- package/packages/core/lib/guideline.js +1 -1
- package/packages/core/lib/hardware.d.ts +1 -1
- package/packages/core/lib/hardware.js +1 -1
- package/packages/core/lib/hf-cache.d.ts +70 -0
- package/packages/core/lib/hf-cache.js +83 -0
- package/packages/core/lib/index.d.ts +16 -9
- package/packages/core/lib/index.js +10 -6
- package/packages/core/lib/infer-cache.d.ts +39 -0
- package/packages/core/lib/infer-cache.js +53 -0
- package/packages/core/lib/launch-command.d.ts +8 -4
- package/packages/core/lib/launch-command.js +13 -6
- package/packages/core/lib/launch-record.d.ts +1 -1
- package/packages/core/lib/launch-record.js +1 -1
- package/packages/core/lib/logs.d.ts +8 -1
- package/packages/core/lib/logs.js +12 -4
- package/packages/core/lib/models.d.ts +120 -14
- package/packages/core/lib/models.js +209 -17
- package/packages/core/lib/parameter.d.ts +31 -3
- package/packages/core/lib/parameter.js +1 -1
- package/packages/core/lib/progress.d.ts +54 -0
- package/packages/core/lib/progress.js +120 -0
- package/packages/core/lib/registrar.d.ts +25 -14
- package/packages/core/lib/registrar.js +30 -10
- package/packages/core/lib/reserve.d.ts +11 -3
- package/packages/core/lib/reserve.js +6 -4
- package/packages/core/lib/status.d.ts +12 -6
- package/packages/core/lib/status.js +21 -10
- package/packages/core/lib/sudo.d.ts +80 -0
- package/packages/core/lib/sudo.js +78 -0
- package/packages/core/package.json +1 -1
- package/packages/orchestrator/lib/config.d.ts +63 -0
- package/packages/orchestrator/lib/config.js +111 -0
- package/packages/orchestrator/lib/index.d.ts +51 -0
- package/packages/orchestrator/lib/index.js +73 -0
- package/packages/orchestrator/lib/route.d.ts +60 -0
- package/packages/orchestrator/lib/route.js +159 -0
- package/packages/orchestrator/locale/en.json +6 -0
- package/packages/orchestrator/package.json +39 -0
- package/packages/orchestrator/prompt.md +87 -0
- package/packages/providers/lib/acquire.d.ts +95 -15
- package/packages/providers/lib/acquire.js +239 -40
- package/packages/providers/lib/adapters.d.ts +155 -221
- package/packages/providers/lib/adapters.js +589 -935
- package/packages/providers/lib/debug.d.ts +1 -1
- package/packages/providers/lib/debug.js +1 -1
- package/packages/providers/lib/deps.d.ts +31 -212
- package/packages/providers/lib/deps.js +71 -205
- package/packages/providers/lib/engines/basalt/basalt.d.ts +130 -0
- package/packages/providers/lib/engines/basalt/basalt.js +304 -0
- package/packages/providers/lib/engines/basalt/basaltAdapter.d.ts +85 -0
- package/packages/providers/lib/engines/basalt/basaltAdapter.js +439 -0
- package/packages/providers/lib/engines/basalt/basaltLinux.d.ts +23 -0
- package/packages/providers/lib/engines/basalt/basaltLinux.js +47 -0
- package/packages/providers/lib/engines/basalt/basaltMacOS.d.ts +17 -0
- package/packages/providers/lib/engines/basalt/basaltMacOS.js +19 -0
- package/packages/providers/lib/engines/basalt/basaltWindows.d.ts +24 -0
- package/packages/providers/lib/engines/basalt/basaltWindows.js +49 -0
- package/packages/providers/lib/engines/engineOs.d.ts +24 -0
- package/packages/providers/lib/engines/engineOs.js +17 -0
- package/packages/providers/lib/{hyperqwen.d.ts → engines/hyperqwen/hyperqwen.d.ts} +2 -2
- package/packages/providers/lib/{hyperqwen.js → engines/hyperqwen/hyperqwen.js} +14 -2
- package/packages/providers/lib/engines/hyperqwen/hyperqwenAdapter.d.ts +38 -0
- package/packages/providers/lib/engines/hyperqwen/hyperqwenAdapter.js +115 -0
- package/packages/providers/lib/engines/hyperqwen/hyperqwenArch.d.ts +9 -0
- package/packages/providers/lib/engines/hyperqwen/hyperqwenArch.js +9 -0
- package/packages/providers/lib/engines/hyperqwen/hyperqwenDebian.d.ts +9 -0
- package/packages/providers/lib/engines/hyperqwen/hyperqwenDebian.js +9 -0
- package/packages/providers/lib/engines/hyperqwen/hyperqwenFedora.d.ts +9 -0
- package/packages/providers/lib/engines/hyperqwen/hyperqwenFedora.js +9 -0
- package/packages/providers/lib/engines/hyperqwen/hyperqwenLinux.d.ts +10 -0
- package/packages/providers/lib/engines/hyperqwen/hyperqwenLinux.js +14 -0
- package/packages/providers/lib/engines/hyperqwen/hyperqwenMacOS.d.ts +9 -0
- package/packages/providers/lib/engines/hyperqwen/hyperqwenMacOS.js +9 -0
- package/packages/providers/lib/engines/hyperqwen/hyperqwenWindows.d.ts +9 -0
- package/packages/providers/lib/engines/hyperqwen/hyperqwenWindows.js +9 -0
- package/packages/providers/lib/{infernix.d.ts → engines/infernix/infernix.d.ts} +7 -4
- package/packages/providers/lib/{infernix.js → engines/infernix/infernix.js} +53 -8
- package/packages/providers/lib/engines/infernix/infernixAdapter.d.ts +52 -0
- package/packages/providers/lib/engines/infernix/infernixAdapter.js +235 -0
- package/packages/providers/lib/engines/infernix/infernixArch.d.ts +9 -0
- package/packages/providers/lib/engines/infernix/infernixArch.js +9 -0
- package/packages/providers/lib/engines/infernix/infernixDebian.d.ts +9 -0
- package/packages/providers/lib/engines/infernix/infernixDebian.js +9 -0
- package/packages/providers/lib/engines/infernix/infernixFedora.d.ts +9 -0
- package/packages/providers/lib/engines/infernix/infernixFedora.js +9 -0
- package/packages/providers/lib/engines/infernix/infernixLinux.d.ts +17 -0
- package/packages/providers/lib/engines/infernix/infernixLinux.js +35 -0
- package/packages/providers/lib/engines/infernix/infernixMacOS.d.ts +16 -0
- package/packages/providers/lib/engines/infernix/infernixMacOS.js +18 -0
- package/packages/providers/lib/engines/infernix/infernixWindows.d.ts +16 -0
- package/packages/providers/lib/engines/infernix/infernixWindows.js +34 -0
- package/packages/providers/lib/{llamacpp.d.ts → engines/llamacpp/llamacpp.d.ts} +2 -2
- package/packages/providers/lib/{llamacpp.js → engines/llamacpp/llamacpp.js} +12 -2
- package/packages/providers/lib/engines/llamacpp/llamacppAdapter.d.ts +50 -0
- package/packages/providers/lib/engines/llamacpp/llamacppAdapter.js +274 -0
- package/packages/providers/lib/engines/llamacpp/llamacppArch.d.ts +9 -0
- package/packages/providers/lib/engines/llamacpp/llamacppArch.js +9 -0
- package/packages/providers/lib/engines/llamacpp/llamacppDebian.d.ts +9 -0
- package/packages/providers/lib/engines/llamacpp/llamacppDebian.js +9 -0
- package/packages/providers/lib/engines/llamacpp/llamacppFedora.d.ts +9 -0
- package/packages/providers/lib/engines/llamacpp/llamacppFedora.js +9 -0
- package/packages/providers/lib/engines/llamacpp/llamacppLinux.d.ts +17 -0
- package/packages/providers/lib/engines/llamacpp/llamacppLinux.js +28 -0
- package/packages/providers/lib/engines/llamacpp/llamacppMacOS.d.ts +15 -0
- package/packages/providers/lib/engines/llamacpp/llamacppMacOS.js +17 -0
- package/packages/providers/lib/engines/llamacpp/llamacppWindows.d.ts +15 -0
- package/packages/providers/lib/engines/llamacpp/llamacppWindows.js +26 -0
- package/packages/providers/lib/{ninfer.d.ts → engines/ninfer/ninfer.d.ts} +2 -2
- package/packages/providers/lib/{ninfer.js → engines/ninfer/ninfer.js} +25 -3
- package/packages/providers/lib/engines/ninfer/ninferAdapter.d.ts +81 -0
- package/packages/providers/lib/engines/ninfer/ninferAdapter.js +392 -0
- package/packages/providers/lib/engines/ninfer/ninferArch.d.ts +9 -0
- package/packages/providers/lib/engines/ninfer/ninferArch.js +9 -0
- package/packages/providers/lib/engines/ninfer/ninferDebian.d.ts +9 -0
- package/packages/providers/lib/engines/ninfer/ninferDebian.js +9 -0
- package/packages/providers/lib/engines/ninfer/ninferFedora.d.ts +9 -0
- package/packages/providers/lib/engines/ninfer/ninferFedora.js +9 -0
- package/packages/providers/lib/engines/ninfer/ninferLinux.d.ts +17 -0
- package/packages/providers/lib/engines/ninfer/ninferLinux.js +37 -0
- package/packages/providers/lib/engines/ninfer/ninferMacOS.d.ts +15 -0
- package/packages/providers/lib/engines/ninfer/ninferMacOS.js +17 -0
- package/packages/providers/lib/engines/ninfer/ninferWindows.d.ts +29 -0
- package/packages/providers/lib/engines/ninfer/ninferWindows.js +59 -0
- package/packages/providers/lib/engines/strata/strata.d.ts +1 -0
- package/packages/providers/lib/engines/strata/strata.js +264 -0
- package/packages/providers/lib/engines/strata/strataAdapter.d.ts +97 -0
- package/packages/providers/lib/engines/strata/strataAdapter.js +463 -0
- package/packages/providers/lib/engines/strata/strataArch.d.ts +9 -0
- package/packages/providers/lib/engines/strata/strataArch.js +9 -0
- package/packages/providers/lib/engines/strata/strataDebian.d.ts +9 -0
- package/packages/providers/lib/engines/strata/strataDebian.js +9 -0
- package/packages/providers/lib/engines/strata/strataFedora.d.ts +9 -0
- package/packages/providers/lib/engines/strata/strataFedora.js +9 -0
- package/packages/providers/lib/engines/strata/strataLinux.d.ts +21 -0
- package/packages/providers/lib/engines/strata/strataLinux.js +30 -0
- package/packages/providers/lib/engines/strata/strataMacOS.d.ts +16 -0
- package/packages/providers/lib/engines/strata/strataMacOS.js +17 -0
- package/packages/providers/lib/engines/strata/strataWindows.d.ts +27 -0
- package/packages/providers/lib/engines/strata/strataWindows.js +37 -0
- package/packages/providers/lib/engines.d.ts +8 -5
- package/packages/providers/lib/engines.js +22 -11
- package/packages/providers/lib/guidelines.d.ts +5 -4
- package/packages/providers/lib/guidelines.js +18 -5
- package/packages/providers/lib/index.d.ts +33 -24
- package/packages/providers/lib/index.js +46 -24
- package/packages/providers/lib/model-defaults.d.ts +10 -5
- package/packages/providers/lib/model-defaults.js +47 -5
- package/packages/providers/lib/platform.d.ts +8 -5
- package/packages/providers/lib/platform.js +27 -7
- package/packages/providers/lib/presets.d.ts +6 -4
- package/packages/providers/lib/presets.js +53 -5
- package/packages/providers/lib/systemDeps.d.ts +313 -0
- package/packages/providers/lib/systemDeps.js +284 -0
- package/packages/providers/lib/vram.d.ts +34 -8
- package/packages/providers/lib/vram.js +81 -8
- package/packages/providers/package.json +2 -2
- package/packages/service/lib/index.d.ts +187 -23
- package/packages/service/lib/index.js +667 -90
- package/packages/service/lib/launch-target.d.ts +19 -0
- package/packages/service/lib/launch-target.js +28 -0
- package/packages/service/lib/run-logs.d.ts +72 -0
- package/packages/service/lib/run-logs.js +125 -0
- package/packages/service/lib/types.d.ts +166 -8
- package/packages/service/lib/types.js +1 -1
- package/packages/service/package.json +2 -2
- package/packages/tool/lib/index.d.ts +1 -1
- package/packages/tool/lib/index.js +1 -1
- package/packages/tool/package.json +2 -2
- package/packages/ui/lib/config.d.ts +89 -0
- package/packages/ui/lib/config.js +251 -0
- package/packages/ui/lib/deps.d.ts +4 -4
- package/packages/ui/lib/deps.js +1 -1
- package/packages/ui/lib/form.d.ts +1 -1
- package/packages/ui/lib/form.js +1 -1
- package/packages/ui/lib/index.d.ts +7 -1
- package/packages/ui/lib/index.js +12 -2
- package/packages/ui/lib/meter.d.ts +1 -1
- package/packages/ui/lib/meter.js +1 -1
- package/packages/ui/lib/ops/engine.d.ts +216 -0
- package/packages/ui/lib/ops/engine.js +697 -0
- package/packages/ui/lib/ops/get-steps.d.ts +98 -0
- package/packages/ui/lib/ops/get-steps.js +359 -0
- package/packages/ui/lib/ops/hf.d.ts +42 -0
- package/packages/ui/lib/ops/hf.js +150 -0
- package/packages/ui/lib/ops/logs.d.ts +78 -0
- package/packages/ui/lib/ops/logs.js +119 -0
- package/packages/ui/lib/ops/model.d.ts +71 -0
- package/packages/ui/lib/ops/model.js +123 -0
- package/packages/ui/lib/request.d.ts +106 -0
- package/packages/ui/lib/request.js +80 -0
- package/packages/ui/lib/route.d.ts +106 -422
- package/packages/ui/lib/route.js +136 -1845
- package/packages/ui/lib/routes/chat-template.d.ts +1 -0
- package/packages/ui/lib/routes/chat-template.js +1 -0
- package/packages/ui/lib/routes/deps.d.ts +1 -0
- package/packages/ui/lib/routes/deps.js +1 -0
- package/packages/ui/lib/routes/download.d.ts +1 -0
- package/packages/ui/lib/routes/download.js +1 -0
- package/packages/ui/lib/routes/get.d.ts +1 -0
- package/packages/ui/lib/routes/get.js +106 -0
- package/packages/ui/lib/routes/install.d.ts +16 -0
- package/packages/ui/lib/routes/install.js +36 -0
- package/packages/ui/lib/routes/launch.d.ts +24 -0
- package/packages/ui/lib/routes/launch.js +74 -0
- package/packages/ui/lib/routes/logs.d.ts +57 -0
- package/packages/ui/lib/routes/logs.js +117 -0
- package/packages/ui/lib/routes/provider-delete.d.ts +15 -0
- package/packages/ui/lib/routes/provider-delete.js +37 -0
- package/packages/ui/lib/routes/register.d.ts +16 -0
- package/packages/ui/lib/routes/register.js +28 -0
- package/packages/ui/lib/routes/save.d.ts +18 -0
- package/packages/ui/lib/routes/save.js +159 -0
- package/packages/ui/lib/routes/stop.d.ts +19 -0
- package/packages/ui/lib/routes/stop.js +32 -0
- package/packages/ui/lib/routes/stream.d.ts +40 -0
- package/packages/ui/lib/routes/stream.js +68 -0
- package/packages/ui/lib/routes/summary.d.ts +15 -0
- package/packages/ui/lib/routes/summary.js +26 -0
- package/packages/ui/lib/routes/unregister.d.ts +14 -0
- package/packages/ui/lib/routes/unregister.js +26 -0
- package/packages/ui/lib/viewmodels/deps.d.ts +1 -0
- package/packages/ui/lib/viewmodels/deps.js +1 -0
- package/packages/ui/lib/viewmodels/depsHelpers.d.ts +1 -0
- package/packages/ui/lib/viewmodels/depsHelpers.js +94 -0
- package/packages/ui/lib/viewmodels/summary.d.ts +145 -0
- package/packages/ui/lib/viewmodels/summary.js +245 -0
- package/packages/ui/lib/viewmodels/summaryHelpers.d.ts +30 -0
- package/packages/ui/lib/viewmodels/summaryHelpers.js +42 -0
- package/packages/ui/lib/warnings.d.ts +1 -1
- package/packages/ui/lib/warnings.js +1 -1
- package/packages/ui/package.json +4 -4
- package/packages/providers/lib/strata.d.ts +0 -15
- package/packages/providers/lib/strata.js +0 -14
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Orchestrator prompt store: the saved prompt file under
|
|
3
|
+
* ~/.dsh/local-infer/orchestrator.json, the shipped prompt.md default, and
|
|
4
|
+
* the in-memory holder the system-prompt section and the settings routes
|
|
5
|
+
* share. Every read sanitizes the file, so a by-hand edit never poisons the
|
|
6
|
+
* injected prompt. Mirrors the sanitize-on-read discipline of
|
|
7
|
+
* packages/ui/src/config.ts.
|
|
8
|
+
* @module dsh-plugin-local-infer/orchestrator/config
|
|
9
|
+
*/
|
|
10
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
11
|
+
import { homedir } from 'node:os';
|
|
12
|
+
import { dirname, join } from 'node:path';
|
|
13
|
+
/**
|
|
14
|
+
* orchestratorConfigPath names the file this package owns. It sits in the
|
|
15
|
+
* shared local-infer dir beside the ui config so one place holds everything
|
|
16
|
+
* the plugin persists.
|
|
17
|
+
*/
|
|
18
|
+
export function orchestratorConfigPath() {
|
|
19
|
+
return join(homedir(), '.dsh', 'local-infer', 'orchestrator.json');
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* readOrchestratorConfig reads the saved prompt. A missing or broken file,
|
|
23
|
+
* or a prompt field that is not a string, reads as no saved prompt (empty),
|
|
24
|
+
* so a first open and a by-hand edit both land on the default instead of
|
|
25
|
+
* throwing.
|
|
26
|
+
*/
|
|
27
|
+
export function readOrchestratorConfig() {
|
|
28
|
+
const path = orchestratorConfigPath();
|
|
29
|
+
if (!existsSync(path)) {
|
|
30
|
+
return { prompt: '' };
|
|
31
|
+
}
|
|
32
|
+
try {
|
|
33
|
+
const parsed = JSON.parse(readFileSync(path, 'utf8'));
|
|
34
|
+
return { prompt: typeof parsed.prompt === 'string' ? parsed.prompt : '' };
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return { prompt: '' };
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* writeOrchestratorConfig persists the prompt, creating the directory tree
|
|
42
|
+
* on first write the same way the ui config write does.
|
|
43
|
+
*/
|
|
44
|
+
export function writeOrchestratorConfig(config) {
|
|
45
|
+
const path = orchestratorConfigPath();
|
|
46
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
47
|
+
writeFileSync(path, JSON.stringify({ prompt: config.prompt }, null, 2));
|
|
48
|
+
}
|
|
49
|
+
// Cache of the shipped prompt.md text: the file never changes while the
|
|
50
|
+
// process runs, so only a successful read is kept and a failed read retries
|
|
51
|
+
// on the next call instead of locking in the empty fallback.
|
|
52
|
+
let defaultPromptCache;
|
|
53
|
+
/**
|
|
54
|
+
* defaultOrchestratorPrompt returns the shipped prompt.md text read from the
|
|
55
|
+
* package root. The URL hop is relative to this module, so src/ and lib/
|
|
56
|
+
* depths both resolve one level up to the package root. The read is cached;
|
|
57
|
+
* an unreadable file yields '' without throwing.
|
|
58
|
+
*/
|
|
59
|
+
export function defaultOrchestratorPrompt() {
|
|
60
|
+
if (defaultPromptCache === undefined) {
|
|
61
|
+
try {
|
|
62
|
+
defaultPromptCache = readFileSync(new URL('../prompt.md', import.meta.url), 'utf8');
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return '';
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return defaultPromptCache;
|
|
69
|
+
}
|
|
70
|
+
// The effective prompt holder: null until the first read refreshes it from
|
|
71
|
+
// the file, then the saved value or the default until the setter persists a
|
|
72
|
+
// new one.
|
|
73
|
+
let effectivePrompt = null;
|
|
74
|
+
/**
|
|
75
|
+
* getOrchestratorPrompt returns the effective prompt: the saved value when a
|
|
76
|
+
* non-empty one exists, otherwise the shipped default. The first call reads
|
|
77
|
+
* the file once and caches, so the system-prompt section pays no per-message
|
|
78
|
+
* disk read.
|
|
79
|
+
*/
|
|
80
|
+
export function getOrchestratorPrompt() {
|
|
81
|
+
if (effectivePrompt === null) {
|
|
82
|
+
effectivePrompt = toEffective(readOrchestratorConfig().prompt);
|
|
83
|
+
}
|
|
84
|
+
return effectivePrompt;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* setOrchestratorPrompt persists the prompt and refreshes the holder, so the
|
|
88
|
+
* injected section picks the new text up without another file read. An empty
|
|
89
|
+
* save means "no saved prompt" and falls back to the default.
|
|
90
|
+
*/
|
|
91
|
+
export function setOrchestratorPrompt(prompt) {
|
|
92
|
+
writeOrchestratorConfig({ prompt });
|
|
93
|
+
effectivePrompt = toEffective(prompt);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* hasSavedOrchestratorPrompt reports whether the file holds a saved prompt
|
|
97
|
+
* override. The empty string is the store's sentinel for "no saved prompt",
|
|
98
|
+
* so the settings routes read the flag through here instead of re-deriving
|
|
99
|
+
* the sentinel rule the holder already applies.
|
|
100
|
+
*/
|
|
101
|
+
export function hasSavedOrchestratorPrompt() {
|
|
102
|
+
return readOrchestratorConfig().prompt !== '';
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* toEffective resolves one saved value against the default: an empty saved
|
|
106
|
+
* prompt reads as no saved prompt.
|
|
107
|
+
*/
|
|
108
|
+
function toEffective(saved) {
|
|
109
|
+
return saved === '' ? defaultOrchestratorPrompt() : saved;
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Orchestrator capability: an editable "Orchestrator Prompt" persisted
|
|
3
|
+
* under `~/.dsh/local-infer`, defaulted from the shipped `prompt.md`, and
|
|
4
|
+
* injected into the system prompt while the component is enabled.
|
|
5
|
+
*
|
|
6
|
+
* The prompt store (saved file, shipped default, effective-prompt holder)
|
|
7
|
+
* lives in ./config.js and is re-exported here as the single source of truth
|
|
8
|
+
* the system-prompt seam (TASK-003) and the settings routes (TASK-004) pull
|
|
9
|
+
* from.
|
|
10
|
+
* @module dsh-plugin-local-infer/orchestrator
|
|
11
|
+
*/
|
|
12
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
13
|
+
export { defaultOrchestratorPrompt, getOrchestratorPrompt, hasSavedOrchestratorPrompt, orchestratorConfigPath, readOrchestratorConfig, setOrchestratorPrompt, writeOrchestratorConfig, } from './config.js';
|
|
14
|
+
export type { StoredOrchestratorConfig } from './config.js';
|
|
15
|
+
export declare const name = "local-infer-orchestrator";
|
|
16
|
+
export declare const inject: string[];
|
|
17
|
+
/**
|
|
18
|
+
* SystemPromptService narrows the dsh-system-prompt service to the one
|
|
19
|
+
* member this package uses. That package augments the cordis Context with
|
|
20
|
+
* `systemPrompt` and is not a dependency here, so the scoped inject casts
|
|
21
|
+
* the scope locally (same shape as the ui's WebServerService narrowing).
|
|
22
|
+
*/
|
|
23
|
+
export interface SystemPromptService {
|
|
24
|
+
/**
|
|
25
|
+
* Registers one ordered prompt section in the calling scope and returns
|
|
26
|
+
* the Cordis effect disposer. `text` may be a provider re-evaluated at
|
|
27
|
+
* each assembly.
|
|
28
|
+
*/
|
|
29
|
+
section(section: {
|
|
30
|
+
name: string;
|
|
31
|
+
order: number;
|
|
32
|
+
text: string | (() => string);
|
|
33
|
+
interpolate?: boolean;
|
|
34
|
+
}): () => void;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Mount the Orchestrator prompt. The scoped `systemPrompt` inject registers
|
|
38
|
+
* the one global `orchestrator` section where the seam exists; the effect
|
|
39
|
+
* scope ties the registration to the plugin, so it unregisters with the
|
|
40
|
+
* plugin. The scoped `webServer` inject registers the /local-infer/
|
|
41
|
+
* orchestrator settings routes where that seam exists, so a headless profile
|
|
42
|
+
* keeps no routes.
|
|
43
|
+
*/
|
|
44
|
+
export declare function apply(ctx: Context): void;
|
|
45
|
+
declare const plugin: {
|
|
46
|
+
name: string;
|
|
47
|
+
inject: string[];
|
|
48
|
+
apply: typeof apply;
|
|
49
|
+
};
|
|
50
|
+
export default plugin;
|
|
51
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Orchestrator capability: an editable "Orchestrator Prompt" persisted
|
|
3
|
+
* under `~/.dsh/local-infer`, defaulted from the shipped `prompt.md`, and
|
|
4
|
+
* injected into the system prompt while the component is enabled.
|
|
5
|
+
*
|
|
6
|
+
* The prompt store (saved file, shipped default, effective-prompt holder)
|
|
7
|
+
* lives in ./config.js and is re-exported here as the single source of truth
|
|
8
|
+
* the system-prompt seam (TASK-003) and the settings routes (TASK-004) pull
|
|
9
|
+
* from.
|
|
10
|
+
* @module dsh-plugin-local-infer/orchestrator
|
|
11
|
+
*/
|
|
12
|
+
import { getOrchestratorPrompt } from './config.js';
|
|
13
|
+
import { registerOrchestratorRoutes } from './route.js';
|
|
14
|
+
export { defaultOrchestratorPrompt, getOrchestratorPrompt, hasSavedOrchestratorPrompt, orchestratorConfigPath, readOrchestratorConfig, setOrchestratorPrompt, writeOrchestratorConfig, } from './config.js';
|
|
15
|
+
export const name = 'local-infer-orchestrator';
|
|
16
|
+
// No required top-level services: the `systemPrompt` and `webServer` seams
|
|
17
|
+
// are pulled with scoped injects in their own effects, so the component
|
|
18
|
+
// stays loadable in profiles that lack either service.
|
|
19
|
+
export const inject = [];
|
|
20
|
+
// The section placement: the deployment persona prefix sits at 0 and the
|
|
21
|
+
// first centrally allocated policy section (PLAN_POLICY) at 500, so 100
|
|
22
|
+
// puts the Orchestrator instructions just after the persona and ahead of
|
|
23
|
+
// first-party guidance. dsh-system-prompt allocates nothing between 0 and
|
|
24
|
+
// 500, and external contributions may pick any finite order.
|
|
25
|
+
const orchestratorSectionOrder = 100;
|
|
26
|
+
/**
|
|
27
|
+
* mountSeam pulls one optional service through a scoped inject and mounts
|
|
28
|
+
* the half that needs it. A profile without the seam never runs the
|
|
29
|
+
* callback, and a mount failure is logged and swallowed so the component
|
|
30
|
+
* still loads without that half. `skipped` names the half in the catch log.
|
|
31
|
+
*/
|
|
32
|
+
function mountSeam(ctx, service, skipped, mount) {
|
|
33
|
+
ctx.inject([service], (scope) => {
|
|
34
|
+
try {
|
|
35
|
+
mount(scope);
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
console.error(`[local-infer] orchestrator ${skipped}: ${error}`);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Mount the Orchestrator prompt. The scoped `systemPrompt` inject registers
|
|
44
|
+
* the one global `orchestrator` section where the seam exists; the effect
|
|
45
|
+
* scope ties the registration to the plugin, so it unregisters with the
|
|
46
|
+
* plugin. The scoped `webServer` inject registers the /local-infer/
|
|
47
|
+
* orchestrator settings routes where that seam exists, so a headless profile
|
|
48
|
+
* keeps no routes.
|
|
49
|
+
*/
|
|
50
|
+
export function apply(ctx) {
|
|
51
|
+
if (typeof ctx.inject !== 'function') {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
mountSeam(ctx, 'systemPrompt', 'prompt section skipped', (scope) => {
|
|
55
|
+
const systemPrompt = scope.systemPrompt;
|
|
56
|
+
systemPrompt.section({
|
|
57
|
+
name: 'orchestrator',
|
|
58
|
+
order: orchestratorSectionOrder,
|
|
59
|
+
// The prompt is user-editable text: a stray {{var}} stays literal
|
|
60
|
+
// instead of failing every later prompt assembly.
|
|
61
|
+
interpolate: false,
|
|
62
|
+
// Provider form re-reads the holder per assembly, so a settings
|
|
63
|
+
// Save reaches the next assembly without a host restart.
|
|
64
|
+
text: () => getOrchestratorPrompt(),
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
mountSeam(ctx, 'webServer', 'settings routes skipped', (scope) => {
|
|
68
|
+
registerOrchestratorRoutes(scope);
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
const plugin = { name, inject, apply };
|
|
72
|
+
export default plugin;
|
|
73
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Orchestrator settings routes the Web card talks to: GET
|
|
3
|
+
* /local-infer/orchestrator answers { prompt, defaultPrompt, saved } (the
|
|
4
|
+
* effective prompt, the shipped prompt.md default, and whether the effective
|
|
5
|
+
* prompt is a saved value), and POST /local-infer/orchestrator/save persists
|
|
6
|
+
* { prompt } through the config setter (an empty string clears the saved
|
|
7
|
+
* override back to the default) and answers with the same payload. The routes
|
|
8
|
+
* are held by an effect, so they go when the component does.
|
|
9
|
+
*
|
|
10
|
+
* The HTTP plumbing is a minimal local mirror of the ui package's defineRoute
|
|
11
|
+
* template (method guard 405, bounded body 413, JSON answer). The ui package
|
|
12
|
+
* does export its template, but this package deliberately keeps no dependency
|
|
13
|
+
* on ui: importing ui's route module would load its whole route graph (the
|
|
14
|
+
* service, providers, and core packages) into a component that ships disabled
|
|
15
|
+
* and must stay loadable headless, so the shared shape is copied rather than
|
|
16
|
+
* imported, and the two copies change together by hand. The stream helpers
|
|
17
|
+
* the ui template carries are dropped; these two routes only ever answer with
|
|
18
|
+
* one JSON body.
|
|
19
|
+
* @module dsh-plugin-local-infer/orchestrator/route
|
|
20
|
+
*/
|
|
21
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
22
|
+
/**
|
|
23
|
+
* OrchestratorRoute is one webServer route definition the register step holds
|
|
24
|
+
* by an effect: the stable name, the exact-match path, and the handler the web
|
|
25
|
+
* server invokes per request.
|
|
26
|
+
*/
|
|
27
|
+
export interface OrchestratorRoute {
|
|
28
|
+
name: string;
|
|
29
|
+
kind: 'exact';
|
|
30
|
+
path: string;
|
|
31
|
+
handler: (req: IncomingLike, res: OutgoingLike) => void | Promise<void>;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The webServer service is dsh-specific and absent from the cordis Context
|
|
35
|
+
* type, so the route narrows the scoped context to the one member it needs
|
|
36
|
+
* (same shape as the ui's WebServerService narrowing).
|
|
37
|
+
*/
|
|
38
|
+
export interface WebServerService {
|
|
39
|
+
register(route: OrchestratorRoute): () => void;
|
|
40
|
+
}
|
|
41
|
+
interface IncomingLike extends AsyncIterable<Buffer> {
|
|
42
|
+
method: string;
|
|
43
|
+
url: string;
|
|
44
|
+
destroy(): void;
|
|
45
|
+
}
|
|
46
|
+
interface OutgoingLike {
|
|
47
|
+
writeHead(status: number, headers?: Record<string, string>): OutgoingLike;
|
|
48
|
+
end(body?: string): void;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* registerOrchestratorRoutes registers the GET and save routes on the web
|
|
52
|
+
* server and holds them by an effect, so a component switch off removes them
|
|
53
|
+
* before the next switch on re-registers. The scoped context carries the
|
|
54
|
+
* webServer.
|
|
55
|
+
*/
|
|
56
|
+
export declare function registerOrchestratorRoutes(scope: Context & {
|
|
57
|
+
webServer: WebServerService;
|
|
58
|
+
}): void;
|
|
59
|
+
export {};
|
|
60
|
+
//# sourceMappingURL=route.d.ts.map
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Orchestrator settings routes the Web card talks to: GET
|
|
3
|
+
* /local-infer/orchestrator answers { prompt, defaultPrompt, saved } (the
|
|
4
|
+
* effective prompt, the shipped prompt.md default, and whether the effective
|
|
5
|
+
* prompt is a saved value), and POST /local-infer/orchestrator/save persists
|
|
6
|
+
* { prompt } through the config setter (an empty string clears the saved
|
|
7
|
+
* override back to the default) and answers with the same payload. The routes
|
|
8
|
+
* are held by an effect, so they go when the component does.
|
|
9
|
+
*
|
|
10
|
+
* The HTTP plumbing is a minimal local mirror of the ui package's defineRoute
|
|
11
|
+
* template (method guard 405, bounded body 413, JSON answer). The ui package
|
|
12
|
+
* does export its template, but this package deliberately keeps no dependency
|
|
13
|
+
* on ui: importing ui's route module would load its whole route graph (the
|
|
14
|
+
* service, providers, and core packages) into a component that ships disabled
|
|
15
|
+
* and must stay loadable headless, so the shared shape is copied rather than
|
|
16
|
+
* imported, and the two copies change together by hand. The stream helpers
|
|
17
|
+
* the ui template carries are dropped; these two routes only ever answer with
|
|
18
|
+
* one JSON body.
|
|
19
|
+
* @module dsh-plugin-local-infer/orchestrator/route
|
|
20
|
+
*/
|
|
21
|
+
import { defaultOrchestratorPrompt, getOrchestratorPrompt, hasSavedOrchestratorPrompt, setOrchestratorPrompt, } from './config.js';
|
|
22
|
+
/**
|
|
23
|
+
* RouteError is a route failure that carries its own HTTP status, so a
|
|
24
|
+
* handler can answer a validation rejection with its own code instead of the
|
|
25
|
+
* spec's failStatus.
|
|
26
|
+
*/
|
|
27
|
+
class RouteError extends Error {
|
|
28
|
+
status;
|
|
29
|
+
constructor(status, message) {
|
|
30
|
+
super(message);
|
|
31
|
+
this.name = 'RouteError';
|
|
32
|
+
this.status = status;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* The request body size cap the save route enforces: a prompt is a few
|
|
37
|
+
* kilobytes at most, so a body past 64 KiB is a client bug, not a prompt.
|
|
38
|
+
* Deliberately mirrors the cap in packages/ui/src/route.ts (ui is not a
|
|
39
|
+
* dependency here): one malformed client misbehaves the same on every
|
|
40
|
+
* /local-infer route, so edit the two together.
|
|
41
|
+
*/
|
|
42
|
+
const MAX_BODY_BYTES = 64 * 1024;
|
|
43
|
+
/**
|
|
44
|
+
* readJsonBody collects a bounded JSON request body: chunks up to the cap,
|
|
45
|
+
* then parses. A body past the cap destroys the request and throws a 413
|
|
46
|
+
* RouteError carrying the route's own message, so the answer names the route
|
|
47
|
+
* that rejected the body.
|
|
48
|
+
*/
|
|
49
|
+
async function readJsonBody(req, tooLargeMessage) {
|
|
50
|
+
const chunks = [];
|
|
51
|
+
let total = 0;
|
|
52
|
+
for await (const chunk of req) {
|
|
53
|
+
total += chunk.length;
|
|
54
|
+
if (total > MAX_BODY_BYTES) {
|
|
55
|
+
req.destroy();
|
|
56
|
+
throw new RouteError(413, tooLargeMessage);
|
|
57
|
+
}
|
|
58
|
+
chunks.push(chunk);
|
|
59
|
+
}
|
|
60
|
+
return JSON.parse(Buffer.concat(chunks).toString('utf8'));
|
|
61
|
+
}
|
|
62
|
+
/** Writes one JSON answer (status head plus body) on the response. */
|
|
63
|
+
function writeJson(res, status, body) {
|
|
64
|
+
res.writeHead(status, { 'content-type': 'application/json' });
|
|
65
|
+
res.end(JSON.stringify(body));
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* defineRoute is the local template both route specs build on: it guards the
|
|
69
|
+
* method (405), reads the bounded body (413, POST only), and maps the
|
|
70
|
+
* handler's answer to a status: a RouteError carries its own status, any
|
|
71
|
+
* other failure answers with the spec's failStatus.
|
|
72
|
+
*/
|
|
73
|
+
function defineRoute(spec) {
|
|
74
|
+
return {
|
|
75
|
+
name: spec.name,
|
|
76
|
+
kind: 'exact',
|
|
77
|
+
path: spec.path,
|
|
78
|
+
handler: async (req, res) => {
|
|
79
|
+
if (req.method !== spec.method) {
|
|
80
|
+
res.writeHead(405).end();
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
try {
|
|
84
|
+
const body = spec.method === 'POST' ? await readJsonBody(req, spec.tooLargeMessage) : {};
|
|
85
|
+
await spec.run({ url: new URL(req.url, 'http://localhost'), body }, (status, answer) => writeJson(res, status, answer));
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
if (error instanceof RouteError) {
|
|
89
|
+
writeJson(res, error.status, { error: error.message });
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
writeJson(res, spec.failStatus, { error: String(error?.message ?? error) });
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
function orchestratorPayload() {
|
|
98
|
+
return {
|
|
99
|
+
prompt: getOrchestratorPrompt(),
|
|
100
|
+
defaultPrompt: defaultOrchestratorPrompt(),
|
|
101
|
+
saved: hasSavedOrchestratorPrompt(),
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* orchestratorGetRoute builds the GET /local-infer/orchestrator route. The
|
|
106
|
+
* client treats any non-404 answer as proof the route is mounted, so the
|
|
107
|
+
* payload answers 200 even before anything is saved.
|
|
108
|
+
*/
|
|
109
|
+
function orchestratorGetRoute() {
|
|
110
|
+
return defineRoute({
|
|
111
|
+
name: 'local-infer-orchestrator',
|
|
112
|
+
path: '/local-infer/orchestrator',
|
|
113
|
+
method: 'GET',
|
|
114
|
+
failStatus: 500,
|
|
115
|
+
run: async (_input, json) => {
|
|
116
|
+
json(200, orchestratorPayload());
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* orchestratorSaveRoute builds the POST /local-infer/orchestrator/save route:
|
|
122
|
+
* a string prompt persists through setOrchestratorPrompt (an empty string
|
|
123
|
+
* clears the saved override back to the default) and the answer carries the
|
|
124
|
+
* GET payload shape so the card re-renders from one response.
|
|
125
|
+
*/
|
|
126
|
+
function orchestratorSaveRoute() {
|
|
127
|
+
return defineRoute({
|
|
128
|
+
name: 'local-infer-orchestrator-save',
|
|
129
|
+
path: '/local-infer/orchestrator/save',
|
|
130
|
+
method: 'POST',
|
|
131
|
+
failStatus: 400,
|
|
132
|
+
tooLargeMessage: 'orchestrator prompt payload too large',
|
|
133
|
+
run: async ({ body }, json) => {
|
|
134
|
+
if (typeof body.prompt !== 'string') {
|
|
135
|
+
throw new RouteError(400, 'prompt must be a string');
|
|
136
|
+
}
|
|
137
|
+
setOrchestratorPrompt(body.prompt);
|
|
138
|
+
json(200, orchestratorPayload());
|
|
139
|
+
},
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* registerOrchestratorRoutes registers the GET and save routes on the web
|
|
144
|
+
* server and holds them by an effect, so a component switch off removes them
|
|
145
|
+
* before the next switch on re-registers. The scoped context carries the
|
|
146
|
+
* webServer.
|
|
147
|
+
*/
|
|
148
|
+
export function registerOrchestratorRoutes(scope) {
|
|
149
|
+
const routes = [orchestratorGetRoute(), orchestratorSaveRoute()];
|
|
150
|
+
scope.effect(() => {
|
|
151
|
+
const disposers = routes.map((route) => scope.webServer.register(route));
|
|
152
|
+
return () => {
|
|
153
|
+
for (const dispose of disposers) {
|
|
154
|
+
dispose();
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
}, 'local-infer-orchestrator: settings routes');
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=route.js.map
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dsh-plugin-local-infer-orchestrator",
|
|
3
|
+
"version": "0.1.4",
|
|
4
|
+
"description": "Orchestrator component for the dsh local-inference plugin: an editable Orchestrator Prompt persisted under ~/.dsh/local-infer, defaulted from the shipped prompt.md, injected into the system prompt while the component is enabled",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"dsh",
|
|
7
|
+
"dsh-plugin",
|
|
8
|
+
"deepseek-harness",
|
|
9
|
+
"local-inference",
|
|
10
|
+
"orchestrator",
|
|
11
|
+
"system-prompt"
|
|
12
|
+
],
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"type": "module",
|
|
15
|
+
"main": "lib/index.js",
|
|
16
|
+
"types": "lib/index.d.ts",
|
|
17
|
+
"exports": {
|
|
18
|
+
".": {
|
|
19
|
+
"types": "./lib/index.d.ts",
|
|
20
|
+
"default": "./lib/index.js"
|
|
21
|
+
},
|
|
22
|
+
"./package.json": "./package.json"
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"lib/**/*.js",
|
|
26
|
+
"lib/**/*.d.ts",
|
|
27
|
+
"prompt.md",
|
|
28
|
+
"locale/en.json"
|
|
29
|
+
],
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"access": "public"
|
|
32
|
+
},
|
|
33
|
+
"peerDependencies": {
|
|
34
|
+
"@deepseek-ai/cordis": ">=4.0.1"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@deepseek-ai/cordis": "^4.0.6-alpha.2"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Role & Core Objective
|
|
2
|
+
You are an advanced software engineering orchestration agent.
|
|
3
|
+
Your goal is to systematically plan, execute, and finalize user requests using micro-tasks and subagents.
|
|
4
|
+
Always adhere strictly to the following execution sequence.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Step 1: Initialization & Planning
|
|
9
|
+
1. **Gather Context**: Analyze the user request.
|
|
10
|
+
2. **Initialize Plan**: Execute the `todo_write` tool. Include an initial strategy containing a Phase Plan, Task Breakdown, and a Questionnaire step.
|
|
11
|
+
Do not include individual tasks at this time.
|
|
12
|
+
3. **Generate Plan File**: Create a Markdown file named `PLAN-{{1OR2WORD-SLUG}}.md` in the root directory containing:
|
|
13
|
+
- A short description of the objective at the very top.
|
|
14
|
+
- Verification guidelines (Do not duplicate any rules found in `AGENTS.md`).
|
|
15
|
+
- A sequential list of open questions for the user.
|
|
16
|
+
- An ordered list of micro-tasks, group logically by Phase.
|
|
17
|
+
Each task must represent the smallest possible unit of work with a concrete, verifiable "Definition of Done".
|
|
18
|
+
4. **Review Plan File**: Remove any duplicative context so that each statement
|
|
19
|
+
the single source of truth. Remove reasoning notes about task ordering,
|
|
20
|
+
replacing with a clear Markdown list of task dependencies.
|
|
21
|
+
|
|
22
|
+
## Step 2: Refactoring Tasks Injection
|
|
23
|
+
Where appropriate, insert specialized tasks starting with `Refactor:` into your task sequence.
|
|
24
|
+
These tasks must contain the exact following instruction block,
|
|
25
|
+
with the `{{N}}` count template replaced by the number of Tasks in the Phase:
|
|
26
|
+
```text
|
|
27
|
+
Review the files touched by the previous {{N}} commits and identify the following code risks:
|
|
28
|
+
- **Multiple Sources of Truth**: Same calculations done in multiple places.
|
|
29
|
+
- **Duplicate Code**: Nearly-identical code in multiple methods.
|
|
30
|
+
- **Bloaters**: Too many things done in a single method or class.
|
|
31
|
+
- **Data Clumps**: Single variables that travel in a group for multiple methods.
|
|
32
|
+
- **Shotgun Edits**: Commits with singular changes that touch multiple files.
|
|
33
|
+
- **Feature Envy**: Method where over 50% of the code manipulates a different class.
|
|
34
|
+
- **Magic Numbers**: Literals without context in method bodies.
|
|
35
|
+
Then address and resolve each risk.
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Step 3: Architecture-Dependent Architecture Selection
|
|
39
|
+
Count the total number of sequential tasks generated. Execute branch **A** or **B** based on the count:
|
|
40
|
+
|
|
41
|
+
### Branch A: High-Complexity Architecture (5 or More Tasks)
|
|
42
|
+
1. **Deconstruct Plan**: Extract each task body out of the main index file.
|
|
43
|
+
2. **Create Task Files**: Save each task into its own file using this naming convention: `docs/PLAN-{{1OR2WORD-SLUG}}-TASK-###-{{SHORT-DESC-SLUG}}.md`.
|
|
44
|
+
3. **Update Main Index**: Ensure `PLAN-{{1OR2WORD-SLUG}}.md` becomes a slim index where tasks are grouped logically by section and linked using exact Markdown checklist syntax:
|
|
45
|
+
` - [ ] [TASK-###-{{SHORT-DESC-SLUG}}](docs/PLAN-{{1OR2WORD-SLUG}}-TASK-###-{{SHORT-DESC-SLUG}}.md)`
|
|
46
|
+
4. **Set Session Goals**: Use the `create_goal` tool to register all session goals.
|
|
47
|
+
|
|
48
|
+
### Branch B: Low-Complexity Architecture (Less Than 5 Tasks)
|
|
49
|
+
1. **Deconstruct Tasks**: Break down each task into a series of todos.
|
|
50
|
+
In Step 4, when writing each task to the global todo list, include the
|
|
51
|
+
series of todos for each task as an individual todo between tasks.
|
|
52
|
+
|
|
53
|
+
## Step 4: Questionnaire & Baseline Commit
|
|
54
|
+
1. **Append To-Dos**: Use the `todo_write` tool to insert your tasks directly into the global todo list.
|
|
55
|
+
2. **Add Finalizer To-Do**: Append a final `Finalize` item to the end of that list.
|
|
56
|
+
3. **Interview User**: For every open question identified in Step 1, invoke the `ask_user_question` tool individually.
|
|
57
|
+
Provide at least one recommended answer and leave a spot open for the user to answer with their own input.
|
|
58
|
+
4. **Persist Answers**: As answers arrive, write them directly into `PLAN-{{1OR2WORD-SLUG}}.md` (or the specific task file if using Branch A).
|
|
59
|
+
5. **Close Questionnaire**: Mark the Questionnaire task as complete.
|
|
60
|
+
6. **Commit Blueprint**: If on Branch A (High-Complexity), commit the created `PLAN` file (and accompanying `docs/` task files if applicable) to repository version control.
|
|
61
|
+
|
|
62
|
+
## Step 5: Subagent Execution Loop
|
|
63
|
+
Loop through the tasks sequentially. For **each** incomplete task:
|
|
64
|
+
1. **Launch Subagent**: Trigger the `subagent` tool with this exact prompt,
|
|
65
|
+
replacing the PLAN filename template:
|
|
66
|
+
```text
|
|
67
|
+
1. Complete the next Task in @PLAN-{{1OR2WORD-SLUG}}.md .
|
|
68
|
+
2. Use the `todo_write` tool to plan your work.
|
|
69
|
+
3. Check ('[x]') the task in the file when done, then commit the completed work.
|
|
70
|
+
4. List any discovered pre-existing issues for the parent agent to review.
|
|
71
|
+
5. Then you are finished; resolve remaining todos and end the turn.
|
|
72
|
+
```
|
|
73
|
+
2. **Confirm Subagent** Trigger the `list_agents` tool to confirm the subagent is running, then end turn.
|
|
74
|
+
3. **Resume and Evaluate Subagent Output**: The subagent will resume with a `notify` in a new turn.
|
|
75
|
+
If the subagent discovers pre-existing codebase issues, insert new tasks immediately after the current task in the appropriate execution order.
|
|
76
|
+
4. **Sync State**: Invoke the `todo_write` tool to check off progress.
|
|
77
|
+
5. **Repeat**: Proceed to the next task until all items in the plan are checked `[x]`.
|
|
78
|
+
|
|
79
|
+
## Step 6: Finalization & Handoff
|
|
80
|
+
1. **Cleanup Artifacts**: Delete all generated `PLAN-{{1OR2WORD-SLUG}}.md` and `docs/PLAN-{{1OR2WORD-SLUG}}-TASK*` files.
|
|
81
|
+
Remove all memory and file references, restoring the repo development to a stateless condition.
|
|
82
|
+
2. **Commit Cleanup**: Commit these deletions to repository version control.
|
|
83
|
+
3. **Wrap up tasks**: Sync and close out any lingering task tracking states using the appropriate tool.
|
|
84
|
+
4. **Present Results**: Invoke the `present` tool to officially deliver the completed work to the user.
|
|
85
|
+
5. **Complete**: End the turn.
|
|
86
|
+
|
|
87
|
+
---
|