@caupulican/pi-adaptative 0.81.35 → 0.81.38
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/CHANGELOG.md +36 -0
- package/README.md +1 -1
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +10 -8
- package/dist/cli/args.js.map +1 -1
- package/dist/core/agent-session.d.ts +5 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +17 -0
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/autonomy/approval-gate.d.ts.map +1 -1
- package/dist/core/autonomy/approval-gate.js +2 -0
- package/dist/core/autonomy/approval-gate.js.map +1 -1
- package/dist/core/autonomy/foreground-envelope.d.ts.map +1 -1
- package/dist/core/autonomy/foreground-envelope.js +2 -0
- package/dist/core/autonomy/foreground-envelope.js.map +1 -1
- package/dist/core/autonomy/gates.d.ts.map +1 -1
- package/dist/core/autonomy/gates.js +9 -2
- package/dist/core/autonomy/gates.js.map +1 -1
- package/dist/core/autonomy/risk-assessment.d.ts.map +1 -1
- package/dist/core/autonomy/risk-assessment.js +2 -0
- package/dist/core/autonomy/risk-assessment.js.map +1 -1
- package/dist/core/background-lane-controller.d.ts.map +1 -1
- package/dist/core/background-lane-controller.js +1 -1
- package/dist/core/background-lane-controller.js.map +1 -1
- package/dist/core/bash-execution-controller.d.ts +9 -4
- package/dist/core/bash-execution-controller.d.ts.map +1 -1
- package/dist/core/bash-execution-controller.js +7 -6
- package/dist/core/bash-execution-controller.js.map +1 -1
- package/dist/core/bash-executor.d.ts +2 -0
- package/dist/core/bash-executor.d.ts.map +1 -1
- package/dist/core/bash-executor.js +3 -2
- package/dist/core/bash-executor.js.map +1 -1
- package/dist/core/context/sqlite-runtime-index.d.ts.map +1 -1
- package/dist/core/context/sqlite-runtime-index.js +13 -7
- package/dist/core/context/sqlite-runtime-index.js.map +1 -1
- package/dist/core/default-tool-surface.d.ts +7 -0
- package/dist/core/default-tool-surface.d.ts.map +1 -1
- package/dist/core/default-tool-surface.js +29 -10
- package/dist/core/default-tool-surface.js.map +1 -1
- package/dist/core/delegation/worker-actions.d.ts.map +1 -1
- package/dist/core/delegation/worker-actions.js +1 -1
- package/dist/core/delegation/worker-actions.js.map +1 -1
- package/dist/core/doctor.d.ts +10 -10
- package/dist/core/doctor.d.ts.map +1 -1
- package/dist/core/doctor.js +30 -20
- package/dist/core/doctor.js.map +1 -1
- package/dist/core/exec.d.ts +2 -0
- package/dist/core/exec.d.ts.map +1 -1
- package/dist/core/exec.js +1 -0
- package/dist/core/exec.js.map +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +3 -7
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/types.d.ts +13 -3
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js +3 -0
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/memory/memory-manager.d.ts.map +1 -1
- package/dist/core/memory/memory-manager.js +1 -0
- package/dist/core/memory/memory-manager.js.map +1 -1
- package/dist/core/model-capability.d.ts.map +1 -1
- package/dist/core/model-capability.js +2 -0
- package/dist/core/model-capability.js.map +1 -1
- package/dist/core/model-router/tool-escalation.d.ts.map +1 -1
- package/dist/core/model-router/tool-escalation.js +17 -3
- package/dist/core/model-router/tool-escalation.js.map +1 -1
- package/dist/core/models/local-runtime.d.ts.map +1 -1
- package/dist/core/models/local-runtime.js +4 -3
- package/dist/core/models/local-runtime.js.map +1 -1
- package/dist/core/python-runtime.d.ts +46 -0
- package/dist/core/python-runtime.d.ts.map +1 -0
- package/dist/core/python-runtime.js +157 -0
- package/dist/core/python-runtime.js.map +1 -0
- package/dist/core/runtime-builder.d.ts +4 -0
- package/dist/core/runtime-builder.d.ts.map +1 -1
- package/dist/core/runtime-builder.js +31 -9
- package/dist/core/runtime-builder.js.map +1 -1
- package/dist/core/security/untrusted-boundary.d.ts +2 -2
- package/dist/core/security/untrusted-boundary.d.ts.map +1 -1
- package/dist/core/security/untrusted-boundary.js +4 -3
- package/dist/core/security/untrusted-boundary.js.map +1 -1
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +2 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +8 -0
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +13 -2
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tasks/session-task-state.d.ts +10 -0
- package/dist/core/tasks/session-task-state.d.ts.map +1 -0
- package/dist/core/tasks/session-task-state.js +29 -0
- package/dist/core/tasks/session-task-state.js.map +1 -0
- package/dist/core/tasks/task-command.d.ts +30 -0
- package/dist/core/tasks/task-command.d.ts.map +1 -0
- package/dist/core/tasks/task-command.js +79 -0
- package/dist/core/tasks/task-command.js.map +1 -0
- package/dist/core/tasks/task-state.d.ts +71 -0
- package/dist/core/tasks/task-state.d.ts.map +1 -0
- package/dist/core/tasks/task-state.js +372 -0
- package/dist/core/tasks/task-state.js.map +1 -0
- package/dist/core/tool-selection/tool-selection-controller.d.ts.map +1 -1
- package/dist/core/tool-selection/tool-selection-controller.js +1 -1
- package/dist/core/tool-selection/tool-selection-controller.js.map +1 -1
- package/dist/core/tools/bash.d.ts +20 -2
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +124 -199
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js +55 -44
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +8 -4
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/index.d.ts +9 -6
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +24 -9
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/python.d.ts +64 -0
- package/dist/core/tools/python.d.ts.map +1 -0
- package/dist/core/tools/python.js +241 -0
- package/dist/core/tools/python.js.map +1 -0
- package/dist/core/tools/render-utils.d.ts.map +1 -1
- package/dist/core/tools/render-utils.js +1 -1
- package/dist/core/tools/render-utils.js.map +1 -1
- package/dist/core/tools/shell-contract-router.d.ts +13 -0
- package/dist/core/tools/shell-contract-router.d.ts.map +1 -0
- package/dist/core/tools/shell-contract-router.js +330 -0
- package/dist/core/tools/shell-contract-router.js.map +1 -0
- package/dist/core/tools/task-steps.d.ts +46 -0
- package/dist/core/tools/task-steps.d.ts.map +1 -0
- package/dist/core/tools/task-steps.js +160 -0
- package/dist/core/tools/task-steps.js.map +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +12 -0
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/session-flow-commands.d.ts +10 -0
- package/dist/modes/interactive/session-flow-commands.d.ts.map +1 -1
- package/dist/modes/interactive/session-flow-commands.js +43 -0
- package/dist/modes/interactive/session-flow-commands.js.map +1 -1
- package/dist/utils/shell.d.ts +6 -8
- package/dist/utils/shell.d.ts.map +1 -1
- package/dist/utils/shell.js +75 -69
- package/dist/utils/shell.js.map +1 -1
- package/dist/utils/tools-manager.d.ts +23 -3
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js +94 -11
- package/dist/utils/tools-manager.js.map +1 -1
- package/docs/development.md +2 -0
- package/docs/index.md +2 -0
- package/docs/packages.md +1 -1
- package/docs/python.md +43 -0
- package/docs/settings.md +9 -5
- package/docs/task-steps.md +90 -0
- package/docs/termux.md +7 -0
- package/docs/usage.md +5 -6
- package/docs/windows.md +15 -12
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +32 -37
- package/package.json +9 -7
- package/scripts/postinstall-python-runtime.mjs +20 -0
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
const BLOCKED_NESTED_SHELLS = new Set([
|
|
2
|
+
"bash",
|
|
3
|
+
"sh",
|
|
4
|
+
"zsh",
|
|
5
|
+
"fish",
|
|
6
|
+
"cmd",
|
|
7
|
+
"cmd.exe",
|
|
8
|
+
"powershell",
|
|
9
|
+
"powershell.exe",
|
|
10
|
+
"pwsh",
|
|
11
|
+
"pwsh.exe",
|
|
12
|
+
"wsl",
|
|
13
|
+
"wsl.exe",
|
|
14
|
+
]);
|
|
15
|
+
const UNSUPPORTED_OPERATOR_MESSAGE = "Unsupported Bash construct on Windows. Use one simple command per call; pipelines, redirection, command substitution, variable expansion, shell chaining, and nested shells are not translated.";
|
|
16
|
+
function tokenizePortableCommand(command) {
|
|
17
|
+
const argv = [];
|
|
18
|
+
let token = "";
|
|
19
|
+
let tokenStarted = false;
|
|
20
|
+
let quote;
|
|
21
|
+
let escaping = false;
|
|
22
|
+
const finishToken = () => {
|
|
23
|
+
if (!tokenStarted)
|
|
24
|
+
return;
|
|
25
|
+
argv.push(token);
|
|
26
|
+
token = "";
|
|
27
|
+
tokenStarted = false;
|
|
28
|
+
};
|
|
29
|
+
const source = command.trim();
|
|
30
|
+
for (let index = 0; index < source.length; index++) {
|
|
31
|
+
const character = source[index];
|
|
32
|
+
const nextCharacter = source[index + 1];
|
|
33
|
+
if (escaping) {
|
|
34
|
+
token += character;
|
|
35
|
+
tokenStarted = true;
|
|
36
|
+
escaping = false;
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
if (quote === "single") {
|
|
40
|
+
if (character === "'")
|
|
41
|
+
quote = undefined;
|
|
42
|
+
else
|
|
43
|
+
token += character;
|
|
44
|
+
tokenStarted = true;
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
if (quote === "double") {
|
|
48
|
+
if (character === '"') {
|
|
49
|
+
quote = undefined;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (character === "\\") {
|
|
53
|
+
if (nextCharacter && '"$`\\'.includes(nextCharacter)) {
|
|
54
|
+
token += nextCharacter;
|
|
55
|
+
tokenStarted = true;
|
|
56
|
+
index++;
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
token += character;
|
|
60
|
+
tokenStarted = true;
|
|
61
|
+
}
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
if (character === "$" || character === "`") {
|
|
65
|
+
return { ok: false, error: UNSUPPORTED_OPERATOR_MESSAGE };
|
|
66
|
+
}
|
|
67
|
+
token += character;
|
|
68
|
+
tokenStarted = true;
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (character === "'") {
|
|
72
|
+
quote = "single";
|
|
73
|
+
tokenStarted = true;
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
if (character === '"') {
|
|
77
|
+
quote = "double";
|
|
78
|
+
tokenStarted = true;
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
if (character === "\\") {
|
|
82
|
+
if (/^[A-Za-z]:/u.test(token) || token.startsWith("\\\\")) {
|
|
83
|
+
token += character;
|
|
84
|
+
tokenStarted = true;
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
if (token === "" && nextCharacter === "\\") {
|
|
88
|
+
token = "\\\\";
|
|
89
|
+
tokenStarted = true;
|
|
90
|
+
index++;
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
escaping = true;
|
|
94
|
+
tokenStarted = true;
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
if (/\s/u.test(character)) {
|
|
98
|
+
finishToken();
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
if ("|><&;\n\r$`(){}*?[]".includes(character) || character === "#" || (character === "~" && token === "")) {
|
|
102
|
+
return { ok: false, error: UNSUPPORTED_OPERATOR_MESSAGE };
|
|
103
|
+
}
|
|
104
|
+
token += character;
|
|
105
|
+
tokenStarted = true;
|
|
106
|
+
}
|
|
107
|
+
if (escaping)
|
|
108
|
+
return { ok: false, error: "Unsupported trailing escape in Bash-like command." };
|
|
109
|
+
if (quote)
|
|
110
|
+
return { ok: false, error: "Unclosed quote in Bash-like command." };
|
|
111
|
+
finishToken();
|
|
112
|
+
return argv.length > 0 ? { ok: true, argv } : { ok: false, error: "Shell command is empty." };
|
|
113
|
+
}
|
|
114
|
+
function quotePowerShell(value) {
|
|
115
|
+
return `'${value.replaceAll("'", "''")}'`;
|
|
116
|
+
}
|
|
117
|
+
function powershellArray(values) {
|
|
118
|
+
return `@(${values.map(quotePowerShell).join(", ")})`;
|
|
119
|
+
}
|
|
120
|
+
function externalCommand(argv) {
|
|
121
|
+
const invocation = `& ${argv.map(quotePowerShell).join(" ")}`;
|
|
122
|
+
return `${invocation}\nif ($null -ne $LASTEXITCODE) { exit $LASTEXITCODE }\nif (-not $?) { exit 1 }`;
|
|
123
|
+
}
|
|
124
|
+
function parseFlags(argv, allowedFlags) {
|
|
125
|
+
const flags = new Set();
|
|
126
|
+
const operands = [];
|
|
127
|
+
let optionsEnded = false;
|
|
128
|
+
for (const value of argv) {
|
|
129
|
+
if (!optionsEnded && value === "--") {
|
|
130
|
+
optionsEnded = true;
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
if (!optionsEnded && value.startsWith("-") && value !== "-") {
|
|
134
|
+
if (!allowedFlags.has(value))
|
|
135
|
+
return undefined;
|
|
136
|
+
flags.add(value);
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
operands.push(value);
|
|
140
|
+
}
|
|
141
|
+
return { flags, operands };
|
|
142
|
+
}
|
|
143
|
+
function routeLs(argv) {
|
|
144
|
+
const parsed = parseFlags(argv.slice(1), new Set(["-a", "-A", "-l", "-1", "-la", "-al"]));
|
|
145
|
+
if (!parsed || parsed.operands.length > 1)
|
|
146
|
+
return undefined;
|
|
147
|
+
const target = parsed.operands[0] ?? ".";
|
|
148
|
+
const includeHidden = [...parsed.flags].some((flag) => flag.includes("a") || flag.includes("A"));
|
|
149
|
+
const hiddenFilter = includeHidden ? "" : " | Where-Object { -not $_.Name.StartsWith('.') }";
|
|
150
|
+
return `[string[]]$items = @(Get-ChildItem -LiteralPath ${quotePowerShell(target)}${includeHidden ? " -Force" : ""} -ErrorAction Stop${hiddenFilter} | ForEach-Object { if ($_.PSIsContainer) { $_.Name + '/' } else { $_.Name } }); [Array]::Sort($items, [StringComparer]::Ordinal); $items`;
|
|
151
|
+
}
|
|
152
|
+
function routeCat(argv) {
|
|
153
|
+
const parsed = parseFlags(argv.slice(1), new Set(["--"]));
|
|
154
|
+
if (!parsed || parsed.operands.length === 0)
|
|
155
|
+
return undefined;
|
|
156
|
+
return `foreach ($path in ${powershellArray(parsed.operands)}) { [Console]::Out.Write([IO.File]::ReadAllText($path)) }`;
|
|
157
|
+
}
|
|
158
|
+
function routeHeadOrTail(argv, tail) {
|
|
159
|
+
let count = 10;
|
|
160
|
+
let operands = argv.slice(1);
|
|
161
|
+
if (operands[0] === "-n") {
|
|
162
|
+
const parsedCount = Number(operands[1]);
|
|
163
|
+
if (!Number.isInteger(parsedCount) || parsedCount < 0)
|
|
164
|
+
return undefined;
|
|
165
|
+
count = parsedCount;
|
|
166
|
+
operands = operands.slice(2);
|
|
167
|
+
}
|
|
168
|
+
if (operands.length !== 1 || operands[0].startsWith("-"))
|
|
169
|
+
return undefined;
|
|
170
|
+
return `Get-Content -LiteralPath ${quotePowerShell(operands[0])} ${tail ? "-Tail" : "-TotalCount"} ${count} -ErrorAction Stop`;
|
|
171
|
+
}
|
|
172
|
+
function routeGrep(argv) {
|
|
173
|
+
if (argv.length !== 3 || argv[1].startsWith("-") || argv[2].startsWith("-"))
|
|
174
|
+
return undefined;
|
|
175
|
+
return `[string[]]$matches = @(Select-String -LiteralPath ${quotePowerShell(argv[2])} -Pattern ${quotePowerShell(argv[1])} -CaseSensitive -ErrorAction Stop | ForEach-Object { $_.Line }); if ($matches.Count -eq 0) { exit 1 }; $matches`;
|
|
176
|
+
}
|
|
177
|
+
function routeFind(argv) {
|
|
178
|
+
let searchPath = ".";
|
|
179
|
+
let type;
|
|
180
|
+
let filter;
|
|
181
|
+
let index = 1;
|
|
182
|
+
if (argv[index] && !argv[index].startsWith("-"))
|
|
183
|
+
searchPath = argv[index++];
|
|
184
|
+
while (index < argv.length) {
|
|
185
|
+
const option = argv[index++];
|
|
186
|
+
if (option === "-type" && (argv[index] === "f" || argv[index] === "d")) {
|
|
187
|
+
type = argv[index++] === "f" ? "File" : "Directory";
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
if (option === "-name" && argv[index]) {
|
|
191
|
+
filter = argv[index++];
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
return undefined;
|
|
195
|
+
}
|
|
196
|
+
const typeFlag = type ? ` -${type}` : "";
|
|
197
|
+
const filterFlag = filter ? ` -Filter ${quotePowerShell(filter)}` : "";
|
|
198
|
+
return `[string[]]$paths = @(Get-ChildItem -LiteralPath ${quotePowerShell(searchPath)} -Recurse -Force${typeFlag}${filterFlag} -ErrorAction Stop | ForEach-Object { $_.FullName.Replace('\\', '/') }); [Array]::Sort($paths, [StringComparer]::Ordinal); $paths`;
|
|
199
|
+
}
|
|
200
|
+
function routeRemove(argv) {
|
|
201
|
+
const parsed = parseFlags(argv.slice(1), new Set(["-f", "-r", "-rf", "-fr"]));
|
|
202
|
+
if (!parsed || parsed.operands.length === 0)
|
|
203
|
+
return undefined;
|
|
204
|
+
const recursive = [...parsed.flags].some((flag) => flag.includes("r"));
|
|
205
|
+
const force = [...parsed.flags].some((flag) => flag.includes("f"));
|
|
206
|
+
return `foreach ($path in ${powershellArray(parsed.operands)}) { if (Test-Path -LiteralPath $path) { Remove-Item -LiteralPath $path -Force${recursive ? " -Recurse" : ""} -ErrorAction Stop }${force ? "" : ' else { throw "rm: path not found: $path" }'} }`;
|
|
207
|
+
}
|
|
208
|
+
function routeCopyOrMove(argv, move) {
|
|
209
|
+
const parsed = parseFlags(argv.slice(1), move ? new Set() : new Set(["-r", "-R"]));
|
|
210
|
+
if (!parsed || parsed.operands.length !== 2)
|
|
211
|
+
return undefined;
|
|
212
|
+
const [source, destination] = parsed.operands;
|
|
213
|
+
const recurse = !move && parsed.flags.size > 0 ? " -Recurse" : "";
|
|
214
|
+
const rejectDirectoryWithoutRecursion = !move && parsed.flags.size === 0
|
|
215
|
+
? `$sourceItem = Get-Item -LiteralPath ${quotePowerShell(source)} -Force -ErrorAction Stop; if ($sourceItem.PSIsContainer) { throw 'cp: source is a directory; use -r' }; `
|
|
216
|
+
: "";
|
|
217
|
+
return `${rejectDirectoryWithoutRecursion}${move ? "Move-Item" : "Copy-Item"} -LiteralPath ${quotePowerShell(source)} -Destination ${quotePowerShell(destination)}${recurse} -ErrorAction Stop`;
|
|
218
|
+
}
|
|
219
|
+
function routeMkdir(argv) {
|
|
220
|
+
const parsed = parseFlags(argv.slice(1), new Set(["-p"]));
|
|
221
|
+
if (!parsed || parsed.operands.length === 0)
|
|
222
|
+
return undefined;
|
|
223
|
+
return `${powershellArray(parsed.operands)} | ForEach-Object { New-Item -ItemType Directory -Path $_${parsed.flags.has("-p") ? " -Force" : ""} -ErrorAction Stop | Out-Null }`;
|
|
224
|
+
}
|
|
225
|
+
function routeTouch(argv) {
|
|
226
|
+
const parsed = parseFlags(argv.slice(1), new Set());
|
|
227
|
+
if (!parsed || parsed.operands.length === 0)
|
|
228
|
+
return undefined;
|
|
229
|
+
return `${powershellArray(parsed.operands)} | ForEach-Object { if (Test-Path -LiteralPath $_) { (Get-Item -LiteralPath $_ -ErrorAction Stop).LastWriteTime = Get-Date } else { New-Item -ItemType File -Path $_ -ErrorAction Stop | Out-Null } }`;
|
|
230
|
+
}
|
|
231
|
+
function routeBuiltIn(argv) {
|
|
232
|
+
const command = argv[0].toLowerCase();
|
|
233
|
+
if (command === "pwd" && argv.length === 1)
|
|
234
|
+
return "(Get-Location).Path";
|
|
235
|
+
if (command === "echo") {
|
|
236
|
+
let valueIndex = 1;
|
|
237
|
+
while (/^-n+$/u.test(argv[valueIndex] ?? ""))
|
|
238
|
+
valueIndex++;
|
|
239
|
+
if (/^-[neE]+$/u.test(argv[valueIndex] ?? "") && /[eE]/u.test(argv[valueIndex] ?? ""))
|
|
240
|
+
return undefined;
|
|
241
|
+
const method = valueIndex > 1 ? "Write" : "WriteLine";
|
|
242
|
+
return `[Console]::Out.${method}((${powershellArray(argv.slice(valueIndex))} -join ' '))`;
|
|
243
|
+
}
|
|
244
|
+
if (command === "true" && argv.length === 1)
|
|
245
|
+
return "exit 0";
|
|
246
|
+
if (command === "false" && argv.length === 1)
|
|
247
|
+
return "exit 1";
|
|
248
|
+
if (command === "which" && argv.length === 2) {
|
|
249
|
+
return `(Get-Command -Name ${quotePowerShell(argv[1])} -CommandType Application -ErrorAction Stop).Source`;
|
|
250
|
+
}
|
|
251
|
+
if (command === "ls")
|
|
252
|
+
return routeLs(argv);
|
|
253
|
+
if (command === "cat")
|
|
254
|
+
return routeCat(argv);
|
|
255
|
+
if (command === "head")
|
|
256
|
+
return routeHeadOrTail(argv, false);
|
|
257
|
+
if (command === "tail")
|
|
258
|
+
return routeHeadOrTail(argv, true);
|
|
259
|
+
if (command === "grep")
|
|
260
|
+
return routeGrep(argv);
|
|
261
|
+
if (command === "find")
|
|
262
|
+
return routeFind(argv);
|
|
263
|
+
if (command === "rm")
|
|
264
|
+
return routeRemove(argv);
|
|
265
|
+
if (command === "cp")
|
|
266
|
+
return routeCopyOrMove(argv, false);
|
|
267
|
+
if (command === "mv")
|
|
268
|
+
return routeCopyOrMove(argv, true);
|
|
269
|
+
if (command === "mkdir")
|
|
270
|
+
return routeMkdir(argv);
|
|
271
|
+
if (command === "touch")
|
|
272
|
+
return routeTouch(argv);
|
|
273
|
+
return undefined;
|
|
274
|
+
}
|
|
275
|
+
const ROUTED_BUILTIN_NAMES = new Set([
|
|
276
|
+
"pwd",
|
|
277
|
+
"echo",
|
|
278
|
+
"true",
|
|
279
|
+
"false",
|
|
280
|
+
"which",
|
|
281
|
+
"ls",
|
|
282
|
+
"cat",
|
|
283
|
+
"head",
|
|
284
|
+
"tail",
|
|
285
|
+
"grep",
|
|
286
|
+
"find",
|
|
287
|
+
"rm",
|
|
288
|
+
"cp",
|
|
289
|
+
"mv",
|
|
290
|
+
"mkdir",
|
|
291
|
+
"touch",
|
|
292
|
+
]);
|
|
293
|
+
export function routeShellContract(command, platform = process.platform) {
|
|
294
|
+
if (platform !== "win32")
|
|
295
|
+
return { kind: "passthrough", command };
|
|
296
|
+
const tokenized = tokenizePortableCommand(command);
|
|
297
|
+
if (!tokenized.ok || !tokenized.argv)
|
|
298
|
+
return { kind: "unsupported", error: tokenized.error ?? UNSUPPORTED_OPERATOR_MESSAGE };
|
|
299
|
+
const argv = tokenized.argv;
|
|
300
|
+
const commandName = argv[0].toLowerCase();
|
|
301
|
+
if (/^[A-Za-z_][A-Za-z0-9_]*=/u.test(argv[0])) {
|
|
302
|
+
return {
|
|
303
|
+
kind: "unsupported",
|
|
304
|
+
error: "Inline environment assignments are not supported. Configure the environment outside the shell command.",
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
if (BLOCKED_NESTED_SHELLS.has(commandName)) {
|
|
308
|
+
return {
|
|
309
|
+
kind: "unsupported",
|
|
310
|
+
error: "Nested shell execution is not supported by the Windows shell contract router.",
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
const builtIn = routeBuiltIn(argv);
|
|
314
|
+
if (builtIn)
|
|
315
|
+
return { kind: "powershell", command: builtIn, argv };
|
|
316
|
+
if (ROUTED_BUILTIN_NAMES.has(commandName)) {
|
|
317
|
+
return {
|
|
318
|
+
kind: "unsupported",
|
|
319
|
+
error: `Unsupported ${argv[0]} form on Windows. Use a simpler Bash-like form or Pi's dedicated read/search/edit tools.`,
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
if (commandName.endsWith(".sh") || commandName.includes("/bin/")) {
|
|
323
|
+
return {
|
|
324
|
+
kind: "unsupported",
|
|
325
|
+
error: "POSIX shell scripts are not supported by the Windows shell contract router.",
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
return { kind: "powershell", command: externalCommand(argv), argv };
|
|
329
|
+
}
|
|
330
|
+
//# sourceMappingURL=shell-contract-router.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shell-contract-router.js","sourceRoot":"","sources":["../../../src/core/tools/shell-contract-router.ts"],"names":[],"mappings":"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","sourcesContent":["export type ShellContractRoute =\n\t| { kind: \"passthrough\"; command: string }\n\t| { kind: \"powershell\"; command: string; argv: readonly string[] }\n\t| { kind: \"unsupported\"; error: string };\n\ninterface TokenizeResult {\n\tok: boolean;\n\targv?: string[];\n\terror?: string;\n}\n\nconst BLOCKED_NESTED_SHELLS = new Set([\n\t\"bash\",\n\t\"sh\",\n\t\"zsh\",\n\t\"fish\",\n\t\"cmd\",\n\t\"cmd.exe\",\n\t\"powershell\",\n\t\"powershell.exe\",\n\t\"pwsh\",\n\t\"pwsh.exe\",\n\t\"wsl\",\n\t\"wsl.exe\",\n]);\nconst UNSUPPORTED_OPERATOR_MESSAGE =\n\t\"Unsupported Bash construct on Windows. Use one simple command per call; pipelines, redirection, command substitution, variable expansion, shell chaining, and nested shells are not translated.\";\n\nfunction tokenizePortableCommand(command: string): TokenizeResult {\n\tconst argv: string[] = [];\n\tlet token = \"\";\n\tlet tokenStarted = false;\n\tlet quote: \"single\" | \"double\" | undefined;\n\tlet escaping = false;\n\n\tconst finishToken = () => {\n\t\tif (!tokenStarted) return;\n\t\targv.push(token);\n\t\ttoken = \"\";\n\t\ttokenStarted = false;\n\t};\n\n\tconst source = command.trim();\n\tfor (let index = 0; index < source.length; index++) {\n\t\tconst character = source[index];\n\t\tconst nextCharacter = source[index + 1];\n\t\tif (escaping) {\n\t\t\ttoken += character;\n\t\t\ttokenStarted = true;\n\t\t\tescaping = false;\n\t\t\tcontinue;\n\t\t}\n\t\tif (quote === \"single\") {\n\t\t\tif (character === \"'\") quote = undefined;\n\t\t\telse token += character;\n\t\t\ttokenStarted = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (quote === \"double\") {\n\t\t\tif (character === '\"') {\n\t\t\t\tquote = undefined;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (character === \"\\\\\") {\n\t\t\t\tif (nextCharacter && '\"$`\\\\'.includes(nextCharacter)) {\n\t\t\t\t\ttoken += nextCharacter;\n\t\t\t\t\ttokenStarted = true;\n\t\t\t\t\tindex++;\n\t\t\t\t} else {\n\t\t\t\t\ttoken += character;\n\t\t\t\t\ttokenStarted = true;\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (character === \"$\" || character === \"`\") {\n\t\t\t\treturn { ok: false, error: UNSUPPORTED_OPERATOR_MESSAGE };\n\t\t\t}\n\t\t\ttoken += character;\n\t\t\ttokenStarted = true;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (character === \"'\") {\n\t\t\tquote = \"single\";\n\t\t\ttokenStarted = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (character === '\"') {\n\t\t\tquote = \"double\";\n\t\t\ttokenStarted = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (character === \"\\\\\") {\n\t\t\tif (/^[A-Za-z]:/u.test(token) || token.startsWith(\"\\\\\\\\\")) {\n\t\t\t\ttoken += character;\n\t\t\t\ttokenStarted = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (token === \"\" && nextCharacter === \"\\\\\") {\n\t\t\t\ttoken = \"\\\\\\\\\";\n\t\t\t\ttokenStarted = true;\n\t\t\t\tindex++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tescaping = true;\n\t\t\ttokenStarted = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (/\\s/u.test(character)) {\n\t\t\tfinishToken();\n\t\t\tcontinue;\n\t\t}\n\t\tif (\"|><&;\\n\\r$`(){}*?[]\".includes(character) || character === \"#\" || (character === \"~\" && token === \"\")) {\n\t\t\treturn { ok: false, error: UNSUPPORTED_OPERATOR_MESSAGE };\n\t\t}\n\t\ttoken += character;\n\t\ttokenStarted = true;\n\t}\n\n\tif (escaping) return { ok: false, error: \"Unsupported trailing escape in Bash-like command.\" };\n\tif (quote) return { ok: false, error: \"Unclosed quote in Bash-like command.\" };\n\tfinishToken();\n\treturn argv.length > 0 ? { ok: true, argv } : { ok: false, error: \"Shell command is empty.\" };\n}\n\nfunction quotePowerShell(value: string): string {\n\treturn `'${value.replaceAll(\"'\", \"''\")}'`;\n}\n\nfunction powershellArray(values: readonly string[]): string {\n\treturn `@(${values.map(quotePowerShell).join(\", \")})`;\n}\n\nfunction externalCommand(argv: readonly string[]): string {\n\tconst invocation = `& ${argv.map(quotePowerShell).join(\" \")}`;\n\treturn `${invocation}\\nif ($null -ne $LASTEXITCODE) { exit $LASTEXITCODE }\\nif (-not $?) { exit 1 }`;\n}\n\nfunction parseFlags(\n\targv: readonly string[],\n\tallowedFlags: ReadonlySet<string>,\n): { flags: Set<string>; operands: string[] } | undefined {\n\tconst flags = new Set<string>();\n\tconst operands: string[] = [];\n\tlet optionsEnded = false;\n\tfor (const value of argv) {\n\t\tif (!optionsEnded && value === \"--\") {\n\t\t\toptionsEnded = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (!optionsEnded && value.startsWith(\"-\") && value !== \"-\") {\n\t\t\tif (!allowedFlags.has(value)) return undefined;\n\t\t\tflags.add(value);\n\t\t\tcontinue;\n\t\t}\n\t\toperands.push(value);\n\t}\n\treturn { flags, operands };\n}\n\nfunction routeLs(argv: readonly string[]): string | undefined {\n\tconst parsed = parseFlags(argv.slice(1), new Set([\"-a\", \"-A\", \"-l\", \"-1\", \"-la\", \"-al\"]));\n\tif (!parsed || parsed.operands.length > 1) return undefined;\n\tconst target = parsed.operands[0] ?? \".\";\n\tconst includeHidden = [...parsed.flags].some((flag) => flag.includes(\"a\") || flag.includes(\"A\"));\n\tconst hiddenFilter = includeHidden ? \"\" : \" | Where-Object { -not $_.Name.StartsWith('.') }\";\n\treturn `[string[]]$items = @(Get-ChildItem -LiteralPath ${quotePowerShell(target)}${includeHidden ? \" -Force\" : \"\"} -ErrorAction Stop${hiddenFilter} | ForEach-Object { if ($_.PSIsContainer) { $_.Name + '/' } else { $_.Name } }); [Array]::Sort($items, [StringComparer]::Ordinal); $items`;\n}\n\nfunction routeCat(argv: readonly string[]): string | undefined {\n\tconst parsed = parseFlags(argv.slice(1), new Set([\"--\"]));\n\tif (!parsed || parsed.operands.length === 0) return undefined;\n\treturn `foreach ($path in ${powershellArray(parsed.operands)}) { [Console]::Out.Write([IO.File]::ReadAllText($path)) }`;\n}\n\nfunction routeHeadOrTail(argv: readonly string[], tail: boolean): string | undefined {\n\tlet count = 10;\n\tlet operands = argv.slice(1);\n\tif (operands[0] === \"-n\") {\n\t\tconst parsedCount = Number(operands[1]);\n\t\tif (!Number.isInteger(parsedCount) || parsedCount < 0) return undefined;\n\t\tcount = parsedCount;\n\t\toperands = operands.slice(2);\n\t}\n\tif (operands.length !== 1 || operands[0].startsWith(\"-\")) return undefined;\n\treturn `Get-Content -LiteralPath ${quotePowerShell(operands[0])} ${tail ? \"-Tail\" : \"-TotalCount\"} ${count} -ErrorAction Stop`;\n}\n\nfunction routeGrep(argv: readonly string[]): string | undefined {\n\tif (argv.length !== 3 || argv[1].startsWith(\"-\") || argv[2].startsWith(\"-\")) return undefined;\n\treturn `[string[]]$matches = @(Select-String -LiteralPath ${quotePowerShell(argv[2])} -Pattern ${quotePowerShell(argv[1])} -CaseSensitive -ErrorAction Stop | ForEach-Object { $_.Line }); if ($matches.Count -eq 0) { exit 1 }; $matches`;\n}\n\nfunction routeFind(argv: readonly string[]): string | undefined {\n\tlet searchPath = \".\";\n\tlet type: \"File\" | \"Directory\" | undefined;\n\tlet filter: string | undefined;\n\tlet index = 1;\n\tif (argv[index] && !argv[index].startsWith(\"-\")) searchPath = argv[index++];\n\twhile (index < argv.length) {\n\t\tconst option = argv[index++];\n\t\tif (option === \"-type\" && (argv[index] === \"f\" || argv[index] === \"d\")) {\n\t\t\ttype = argv[index++] === \"f\" ? \"File\" : \"Directory\";\n\t\t\tcontinue;\n\t\t}\n\t\tif (option === \"-name\" && argv[index]) {\n\t\t\tfilter = argv[index++];\n\t\t\tcontinue;\n\t\t}\n\t\treturn undefined;\n\t}\n\tconst typeFlag = type ? ` -${type}` : \"\";\n\tconst filterFlag = filter ? ` -Filter ${quotePowerShell(filter)}` : \"\";\n\treturn `[string[]]$paths = @(Get-ChildItem -LiteralPath ${quotePowerShell(searchPath)} -Recurse -Force${typeFlag}${filterFlag} -ErrorAction Stop | ForEach-Object { $_.FullName.Replace('\\\\', '/') }); [Array]::Sort($paths, [StringComparer]::Ordinal); $paths`;\n}\n\nfunction routeRemove(argv: readonly string[]): string | undefined {\n\tconst parsed = parseFlags(argv.slice(1), new Set([\"-f\", \"-r\", \"-rf\", \"-fr\"]));\n\tif (!parsed || parsed.operands.length === 0) return undefined;\n\tconst recursive = [...parsed.flags].some((flag) => flag.includes(\"r\"));\n\tconst force = [...parsed.flags].some((flag) => flag.includes(\"f\"));\n\treturn `foreach ($path in ${powershellArray(parsed.operands)}) { if (Test-Path -LiteralPath $path) { Remove-Item -LiteralPath $path -Force${recursive ? \" -Recurse\" : \"\"} -ErrorAction Stop }${force ? \"\" : ' else { throw \"rm: path not found: $path\" }'} }`;\n}\n\nfunction routeCopyOrMove(argv: readonly string[], move: boolean): string | undefined {\n\tconst parsed = parseFlags(argv.slice(1), move ? new Set<string>() : new Set([\"-r\", \"-R\"]));\n\tif (!parsed || parsed.operands.length !== 2) return undefined;\n\tconst [source, destination] = parsed.operands;\n\tconst recurse = !move && parsed.flags.size > 0 ? \" -Recurse\" : \"\";\n\tconst rejectDirectoryWithoutRecursion =\n\t\t!move && parsed.flags.size === 0\n\t\t\t? `$sourceItem = Get-Item -LiteralPath ${quotePowerShell(source)} -Force -ErrorAction Stop; if ($sourceItem.PSIsContainer) { throw 'cp: source is a directory; use -r' }; `\n\t\t\t: \"\";\n\treturn `${rejectDirectoryWithoutRecursion}${move ? \"Move-Item\" : \"Copy-Item\"} -LiteralPath ${quotePowerShell(source)} -Destination ${quotePowerShell(destination)}${recurse} -ErrorAction Stop`;\n}\n\nfunction routeMkdir(argv: readonly string[]): string | undefined {\n\tconst parsed = parseFlags(argv.slice(1), new Set([\"-p\"]));\n\tif (!parsed || parsed.operands.length === 0) return undefined;\n\treturn `${powershellArray(parsed.operands)} | ForEach-Object { New-Item -ItemType Directory -Path $_${parsed.flags.has(\"-p\") ? \" -Force\" : \"\"} -ErrorAction Stop | Out-Null }`;\n}\n\nfunction routeTouch(argv: readonly string[]): string | undefined {\n\tconst parsed = parseFlags(argv.slice(1), new Set());\n\tif (!parsed || parsed.operands.length === 0) return undefined;\n\treturn `${powershellArray(parsed.operands)} | ForEach-Object { if (Test-Path -LiteralPath $_) { (Get-Item -LiteralPath $_ -ErrorAction Stop).LastWriteTime = Get-Date } else { New-Item -ItemType File -Path $_ -ErrorAction Stop | Out-Null } }`;\n}\n\nfunction routeBuiltIn(argv: readonly string[]): string | undefined {\n\tconst command = argv[0].toLowerCase();\n\tif (command === \"pwd\" && argv.length === 1) return \"(Get-Location).Path\";\n\tif (command === \"echo\") {\n\t\tlet valueIndex = 1;\n\t\twhile (/^-n+$/u.test(argv[valueIndex] ?? \"\")) valueIndex++;\n\t\tif (/^-[neE]+$/u.test(argv[valueIndex] ?? \"\") && /[eE]/u.test(argv[valueIndex] ?? \"\")) return undefined;\n\t\tconst method = valueIndex > 1 ? \"Write\" : \"WriteLine\";\n\t\treturn `[Console]::Out.${method}((${powershellArray(argv.slice(valueIndex))} -join ' '))`;\n\t}\n\tif (command === \"true\" && argv.length === 1) return \"exit 0\";\n\tif (command === \"false\" && argv.length === 1) return \"exit 1\";\n\tif (command === \"which\" && argv.length === 2) {\n\t\treturn `(Get-Command -Name ${quotePowerShell(argv[1])} -CommandType Application -ErrorAction Stop).Source`;\n\t}\n\tif (command === \"ls\") return routeLs(argv);\n\tif (command === \"cat\") return routeCat(argv);\n\tif (command === \"head\") return routeHeadOrTail(argv, false);\n\tif (command === \"tail\") return routeHeadOrTail(argv, true);\n\tif (command === \"grep\") return routeGrep(argv);\n\tif (command === \"find\") return routeFind(argv);\n\tif (command === \"rm\") return routeRemove(argv);\n\tif (command === \"cp\") return routeCopyOrMove(argv, false);\n\tif (command === \"mv\") return routeCopyOrMove(argv, true);\n\tif (command === \"mkdir\") return routeMkdir(argv);\n\tif (command === \"touch\") return routeTouch(argv);\n\treturn undefined;\n}\n\nconst ROUTED_BUILTIN_NAMES = new Set([\n\t\"pwd\",\n\t\"echo\",\n\t\"true\",\n\t\"false\",\n\t\"which\",\n\t\"ls\",\n\t\"cat\",\n\t\"head\",\n\t\"tail\",\n\t\"grep\",\n\t\"find\",\n\t\"rm\",\n\t\"cp\",\n\t\"mv\",\n\t\"mkdir\",\n\t\"touch\",\n]);\n\nexport function routeShellContract(command: string, platform: NodeJS.Platform = process.platform): ShellContractRoute {\n\tif (platform !== \"win32\") return { kind: \"passthrough\", command };\n\tconst tokenized = tokenizePortableCommand(command);\n\tif (!tokenized.ok || !tokenized.argv)\n\t\treturn { kind: \"unsupported\", error: tokenized.error ?? UNSUPPORTED_OPERATOR_MESSAGE };\n\tconst argv = tokenized.argv;\n\tconst commandName = argv[0].toLowerCase();\n\tif (/^[A-Za-z_][A-Za-z0-9_]*=/u.test(argv[0])) {\n\t\treturn {\n\t\t\tkind: \"unsupported\",\n\t\t\terror: \"Inline environment assignments are not supported. Configure the environment outside the shell command.\",\n\t\t};\n\t}\n\tif (BLOCKED_NESTED_SHELLS.has(commandName)) {\n\t\treturn {\n\t\t\tkind: \"unsupported\",\n\t\t\terror: \"Nested shell execution is not supported by the Windows shell contract router.\",\n\t\t};\n\t}\n\tconst builtIn = routeBuiltIn(argv);\n\tif (builtIn) return { kind: \"powershell\", command: builtIn, argv };\n\tif (ROUTED_BUILTIN_NAMES.has(commandName)) {\n\t\treturn {\n\t\t\tkind: \"unsupported\",\n\t\t\terror: `Unsupported ${argv[0]} form on Windows. Use a simpler Bash-like form or Pi's dedicated read/search/edit tools.`,\n\t\t};\n\t}\n\tif (commandName.endsWith(\".sh\") || commandName.includes(\"/bin/\")) {\n\t\treturn {\n\t\t\tkind: \"unsupported\",\n\t\t\terror: \"POSIX shell scripts are not supported by the Windows shell contract router.\",\n\t\t};\n\t}\n\treturn { kind: \"powershell\", command: externalCommand(argv), argv };\n}\n"]}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { type Static, Type } from "typebox";
|
|
2
|
+
import type { ToolDefinition } from "../extensions/types.ts";
|
|
3
|
+
import { type TaskStepsState } from "../tasks/task-state.ts";
|
|
4
|
+
declare const taskStepsSchema: Type.TObject<{
|
|
5
|
+
action: Type.TUnion<[Type.TLiteral<"set">, Type.TLiteral<"add">, Type.TLiteral<"update">, Type.TLiteral<"list">, Type.TLiteral<"clear">, Type.TLiteral<"compact">, Type.TLiteral<"intake">]>;
|
|
6
|
+
steps: Type.TOptional<Type.TArray<Type.TObject<{
|
|
7
|
+
content: Type.TString;
|
|
8
|
+
activeForm: Type.TOptional<Type.TString>;
|
|
9
|
+
status: Type.TOptional<Type.TUnion<[Type.TLiteral<"pending">, Type.TLiteral<"in_progress">, Type.TLiteral<"completed">, Type.TLiteral<"blocked">, Type.TLiteral<"cancelled">]>>;
|
|
10
|
+
priority: Type.TOptional<Type.TUnion<[Type.TLiteral<"low">, Type.TLiteral<"normal">, Type.TLiteral<"high">]>>;
|
|
11
|
+
owner: Type.TOptional<Type.TString>;
|
|
12
|
+
note: Type.TOptional<Type.TString>;
|
|
13
|
+
evidence: Type.TOptional<Type.TArray<Type.TString>>;
|
|
14
|
+
}>>>;
|
|
15
|
+
id: Type.TOptional<Type.TString>;
|
|
16
|
+
content: Type.TOptional<Type.TString>;
|
|
17
|
+
activeForm: Type.TOptional<Type.TString>;
|
|
18
|
+
status: Type.TOptional<Type.TUnion<[Type.TLiteral<"pending">, Type.TLiteral<"in_progress">, Type.TLiteral<"completed">, Type.TLiteral<"blocked">, Type.TLiteral<"cancelled">]>>;
|
|
19
|
+
priority: Type.TOptional<Type.TUnion<[Type.TLiteral<"low">, Type.TLiteral<"normal">, Type.TLiteral<"high">]>>;
|
|
20
|
+
owner: Type.TOptional<Type.TString>;
|
|
21
|
+
note: Type.TOptional<Type.TString>;
|
|
22
|
+
evidence: Type.TOptional<Type.TArray<Type.TString>>;
|
|
23
|
+
clearCompleted: Type.TOptional<Type.TBoolean>;
|
|
24
|
+
showCompleted: Type.TOptional<Type.TBoolean>;
|
|
25
|
+
maxItems: Type.TOptional<Type.TInteger>;
|
|
26
|
+
}>;
|
|
27
|
+
export type TaskStepsToolInput = Static<typeof taskStepsSchema>;
|
|
28
|
+
export type TaskStepsAction = TaskStepsToolInput["action"];
|
|
29
|
+
export interface TaskStepsToolDetails {
|
|
30
|
+
action: TaskStepsAction;
|
|
31
|
+
applied: boolean;
|
|
32
|
+
error?: string;
|
|
33
|
+
state?: TaskStepsState;
|
|
34
|
+
stepCount?: number;
|
|
35
|
+
openStepCount?: number;
|
|
36
|
+
verificationNudgeNeeded?: boolean;
|
|
37
|
+
showCompleted?: boolean;
|
|
38
|
+
}
|
|
39
|
+
export interface TaskStepsToolDependencies {
|
|
40
|
+
getTaskStepsState: () => TaskStepsState | undefined;
|
|
41
|
+
saveTaskStepsState: (state: TaskStepsState) => void;
|
|
42
|
+
now?: () => string;
|
|
43
|
+
}
|
|
44
|
+
export declare function createTaskStepsToolDefinition(deps: TaskStepsToolDependencies): ToolDefinition;
|
|
45
|
+
export {};
|
|
46
|
+
//# sourceMappingURL=task-steps.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-steps.d.ts","sourceRoot":"","sources":["../../../src/core/tools/task-steps.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,EASN,KAAK,cAAc,EAEnB,MAAM,wBAAwB,CAAC;AA2BhC,QAAA,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;EAuCpB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC,OAAO,eAAe,CAAC,CAAC;AAChE,MAAM,MAAM,eAAe,GAAG,kBAAkB,CAAC,QAAQ,CAAC,CAAC;AAE3D,MAAM,WAAW,oBAAoB;IACpC,MAAM,EAAE,eAAe,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,aAAa,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,yBAAyB;IACzC,iBAAiB,EAAE,MAAM,cAAc,GAAG,SAAS,CAAC;IACpD,kBAAkB,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IACpD,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACnB;AAkCD,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,yBAAyB,GAAG,cAAc,CA4F7F","sourcesContent":["import { type Static, Type } from \"typebox\";\nimport type { ToolDefinition } from \"../extensions/types.ts\";\nimport {\n\taddTaskStep,\n\tclearTaskSteps,\n\tcompactTaskSteps,\n\tcreateTaskStepsState,\n\tformatTaskSteps,\n\tMAX_TASK_STEPS,\n\tsetTaskSteps,\n\ttype TaskStepInput,\n\ttype TaskStepsState,\n\tupdateTaskStep,\n} from \"../tasks/task-state.ts\";\n\nconst statusSchema = Type.Union([\n\tType.Literal(\"pending\"),\n\tType.Literal(\"in_progress\"),\n\tType.Literal(\"completed\"),\n\tType.Literal(\"blocked\"),\n\tType.Literal(\"cancelled\"),\n]);\n\nconst prioritySchema = Type.Union([Type.Literal(\"low\"), Type.Literal(\"normal\"), Type.Literal(\"high\")]);\n\nconst stepInputSchema = Type.Object(\n\t{\n\t\tcontent: Type.String({ minLength: 1, maxLength: 2_000, description: \"Imperative task step text.\" }),\n\t\tactiveForm: Type.Optional(\n\t\t\tType.String({ minLength: 1, maxLength: 2_000, description: \"Short present-progress label for active UI.\" }),\n\t\t),\n\t\tstatus: Type.Optional(statusSchema),\n\t\tpriority: Type.Optional(prioritySchema),\n\t\towner: Type.Optional(Type.String({ maxLength: 200 })),\n\t\tnote: Type.Optional(Type.String({ maxLength: 4_000 })),\n\t\tevidence: Type.Optional(Type.Array(Type.String({ minLength: 1, maxLength: 2_000 }), { maxItems: 32 })),\n\t},\n\t{ additionalProperties: false },\n);\n\nconst taskStepsSchema = Type.Object(\n\t{\n\t\taction: Type.Union(\n\t\t\t[\n\t\t\t\tType.Literal(\"set\"),\n\t\t\t\tType.Literal(\"add\"),\n\t\t\t\tType.Literal(\"update\"),\n\t\t\t\tType.Literal(\"list\"),\n\t\t\t\tType.Literal(\"clear\"),\n\t\t\t\tType.Literal(\"compact\"),\n\t\t\t\tType.Literal(\"intake\"),\n\t\t\t],\n\t\t\t{ description: \"Checklist action. Use list to read without mutation.\" },\n\t\t),\n\t\tsteps: Type.Optional(\n\t\t\tType.Array(stepInputSchema, {\n\t\t\t\tmaxItems: MAX_TASK_STEPS,\n\t\t\t\tdescription: \"Complete replacement list for set/intake. Intake preserves every supplied item in order.\",\n\t\t\t}),\n\t\t),\n\t\tid: Type.Optional(\n\t\t\tType.String({\n\t\t\t\tdescription: \"For update: current/active, exact step id, unique id prefix, or unique content selector.\",\n\t\t\t}),\n\t\t),\n\t\tcontent: Type.Optional(Type.String({ minLength: 1, maxLength: 2_000 })),\n\t\tactiveForm: Type.Optional(Type.String({ maxLength: 2_000 })),\n\t\tstatus: Type.Optional(statusSchema),\n\t\tpriority: Type.Optional(prioritySchema),\n\t\towner: Type.Optional(Type.String({ maxLength: 200 })),\n\t\tnote: Type.Optional(Type.String({ maxLength: 4_000 })),\n\t\tevidence: Type.Optional(Type.Array(Type.String({ minLength: 1, maxLength: 2_000 }), { maxItems: 32 })),\n\t\tclearCompleted: Type.Optional(\n\t\t\tType.Boolean({ description: \"For list: compact completed and cancelled steps before rendering.\" }),\n\t\t),\n\t\tshowCompleted: Type.Optional(Type.Boolean({ description: \"Include completed and cancelled steps in output.\" })),\n\t\tmaxItems: Type.Optional(Type.Integer({ minimum: 1, maximum: MAX_TASK_STEPS })),\n\t},\n\t{ additionalProperties: false },\n);\n\nexport type TaskStepsToolInput = Static<typeof taskStepsSchema>;\nexport type TaskStepsAction = TaskStepsToolInput[\"action\"];\n\nexport interface TaskStepsToolDetails {\n\taction: TaskStepsAction;\n\tapplied: boolean;\n\terror?: string;\n\tstate?: TaskStepsState;\n\tstepCount?: number;\n\topenStepCount?: number;\n\tverificationNudgeNeeded?: boolean;\n\tshowCompleted?: boolean;\n}\n\nexport interface TaskStepsToolDependencies {\n\tgetTaskStepsState: () => TaskStepsState | undefined;\n\tsaveTaskStepsState: (state: TaskStepsState) => void;\n\tnow?: () => string;\n}\n\nfunction toTaskStepInput(input: TaskStepsToolInput): TaskStepInput {\n\treturn {\n\t\tcontent: input.content ?? \"\",\n\t\tactiveForm: input.activeForm,\n\t\tstatus: input.status,\n\t\tpriority: input.priority,\n\t\towner: input.owner,\n\t\tnote: input.note,\n\t\tevidence: input.evidence,\n\t};\n}\n\nfunction counts(\n\tstate: TaskStepsState,\n): Pick<TaskStepsToolDetails, \"stepCount\" | \"openStepCount\" | \"verificationNudgeNeeded\"> {\n\tconst openStepCount = state.steps.filter(\n\t\t(step) => step.status !== \"completed\" && step.status !== \"cancelled\",\n\t).length;\n\treturn {\n\t\tstepCount: state.steps.length,\n\t\topenStepCount,\n\t\tverificationNudgeNeeded: state.steps.some((step) => step.status === \"completed\" && step.evidence.length === 0),\n\t};\n}\n\nfunction errorResult(action: TaskStepsAction, error: string, state?: TaskStepsState) {\n\treturn {\n\t\tcontent: [{ type: \"text\" as const, text: `task_steps ${action} failed: ${error}` }],\n\t\tdetails: { action, applied: false, error, state, ...(state ? counts(state) : {}) } satisfies TaskStepsToolDetails,\n\t};\n}\n\nexport function createTaskStepsToolDefinition(deps: TaskStepsToolDependencies): ToolDefinition {\n\tconst now = deps.now ?? (() => new Date().toISOString());\n\treturn {\n\t\tname: \"task_steps\",\n\t\tlabel: \"Task Steps\",\n\t\tdescription:\n\t\t\t\"Maintain the current session's native ordered checklist for multi-step work. Supports pending, in_progress, completed, blocked, and cancelled steps with notes and evidence. State is isolated to and persisted with the active session; use native goal for durable outcome requirements and native delegate/delegate_status for background workers.\",\n\t\tpromptSnippet: \"Track and drain multi-step work with a native session checklist.\",\n\t\tpromptGuidelines: [\n\t\t\t\"Use task_steps for complex work, explicit task-tracking requests, and harness/self-improvement work; keep exactly one step in_progress while actively working.\",\n\t\t\t\"Always address the first open task step before unrelated work: start it, complete/block/cancel it with evidence, ask one clarifying question, or explicitly defer or reorder it.\",\n\t\t\t\"Mark steps completed as soon as evidence is gathered, and attach concise evidence or a blocker reason through update.\",\n\t\t\t\"Use action=intake with a complete steps array when preserving a raw multi-item dump; retain every item and do not silently drop entries.\",\n\t\t\t\"Drain task_steps before final responses: leave no stale in_progress step, and explicitly discuss or defer remaining pending or blocked work.\",\n\t\t\t\"Use goal for the durable goal ledger and delegate/delegate_status for worker lanes; do not emulate background execution inside task_steps.\",\n\t\t],\n\t\tparameters: taskStepsSchema,\n\t\tasync execute(_toolCallId, input: TaskStepsToolInput) {\n\t\t\tconst timestamp = now();\n\t\t\tconst current = deps.getTaskStepsState();\n\t\t\tlet state = current ?? createTaskStepsState(timestamp);\n\t\t\ttry {\n\t\t\t\tswitch (input.action) {\n\t\t\t\t\tcase \"set\":\n\t\t\t\t\t\tif (!input.steps) return errorResult(input.action, \"set requires steps[].\", current);\n\t\t\t\t\t\tstate = setTaskSteps(state, input.steps, timestamp);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"intake\":\n\t\t\t\t\t\tif (!input.steps)\n\t\t\t\t\t\t\treturn errorResult(input.action, \"intake requires a complete steps[] list.\", current);\n\t\t\t\t\t\tstate = setTaskSteps(state, input.steps, timestamp);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"add\":\n\t\t\t\t\t\tstate = addTaskStep(state, toTaskStepInput(input), timestamp);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"update\":\n\t\t\t\t\t\tif (!input.id?.trim())\n\t\t\t\t\t\t\treturn errorResult(input.action, \"update requires id or a unique selector.\", current);\n\t\t\t\t\t\tstate = updateTaskStep(\n\t\t\t\t\t\t\tstate,\n\t\t\t\t\t\t\tinput.id,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tcontent: input.content,\n\t\t\t\t\t\t\t\tactiveForm: input.activeForm,\n\t\t\t\t\t\t\t\tstatus: input.status,\n\t\t\t\t\t\t\t\tpriority: input.priority,\n\t\t\t\t\t\t\t\towner: input.owner,\n\t\t\t\t\t\t\t\tnote: input.note,\n\t\t\t\t\t\t\t\tevidence: input.evidence,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\ttimestamp,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"clear\":\n\t\t\t\t\t\tstate = clearTaskSteps(state, timestamp);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"compact\":\n\t\t\t\t\t\tstate = compactTaskSteps(state, timestamp);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"list\":\n\t\t\t\t\t\tif (input.clearCompleted) state = compactTaskSteps(state, timestamp);\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tconst mutated = input.action !== \"list\" || input.clearCompleted === true;\n\t\t\t\tif (mutated) deps.saveTaskStepsState(state);\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\" as const,\n\t\t\t\t\t\t\ttext: `${input.action === \"list\" ? \"\" : `task_steps ${input.action} recorded.\\n`}${formatTaskSteps(\n\t\t\t\t\t\t\t\tstate,\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tincludeTerminal: input.showCompleted,\n\t\t\t\t\t\t\t\t\tmaxItems: input.maxItems,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t)}`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\taction: input.action,\n\t\t\t\t\t\tapplied: true,\n\t\t\t\t\t\tstate,\n\t\t\t\t\t\t...counts(state),\n\t\t\t\t\t\tshowCompleted: input.showCompleted,\n\t\t\t\t\t} satisfies TaskStepsToolDetails,\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\treturn errorResult(input.action, error instanceof Error ? error.message : String(error), current);\n\t\t\t}\n\t\t},\n\t};\n}\n"]}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { Type } from "typebox";
|
|
2
|
+
import { addTaskStep, clearTaskSteps, compactTaskSteps, createTaskStepsState, formatTaskSteps, MAX_TASK_STEPS, setTaskSteps, updateTaskStep, } from "../tasks/task-state.js";
|
|
3
|
+
const statusSchema = Type.Union([
|
|
4
|
+
Type.Literal("pending"),
|
|
5
|
+
Type.Literal("in_progress"),
|
|
6
|
+
Type.Literal("completed"),
|
|
7
|
+
Type.Literal("blocked"),
|
|
8
|
+
Type.Literal("cancelled"),
|
|
9
|
+
]);
|
|
10
|
+
const prioritySchema = Type.Union([Type.Literal("low"), Type.Literal("normal"), Type.Literal("high")]);
|
|
11
|
+
const stepInputSchema = Type.Object({
|
|
12
|
+
content: Type.String({ minLength: 1, maxLength: 2_000, description: "Imperative task step text." }),
|
|
13
|
+
activeForm: Type.Optional(Type.String({ minLength: 1, maxLength: 2_000, description: "Short present-progress label for active UI." })),
|
|
14
|
+
status: Type.Optional(statusSchema),
|
|
15
|
+
priority: Type.Optional(prioritySchema),
|
|
16
|
+
owner: Type.Optional(Type.String({ maxLength: 200 })),
|
|
17
|
+
note: Type.Optional(Type.String({ maxLength: 4_000 })),
|
|
18
|
+
evidence: Type.Optional(Type.Array(Type.String({ minLength: 1, maxLength: 2_000 }), { maxItems: 32 })),
|
|
19
|
+
}, { additionalProperties: false });
|
|
20
|
+
const taskStepsSchema = Type.Object({
|
|
21
|
+
action: Type.Union([
|
|
22
|
+
Type.Literal("set"),
|
|
23
|
+
Type.Literal("add"),
|
|
24
|
+
Type.Literal("update"),
|
|
25
|
+
Type.Literal("list"),
|
|
26
|
+
Type.Literal("clear"),
|
|
27
|
+
Type.Literal("compact"),
|
|
28
|
+
Type.Literal("intake"),
|
|
29
|
+
], { description: "Checklist action. Use list to read without mutation." }),
|
|
30
|
+
steps: Type.Optional(Type.Array(stepInputSchema, {
|
|
31
|
+
maxItems: MAX_TASK_STEPS,
|
|
32
|
+
description: "Complete replacement list for set/intake. Intake preserves every supplied item in order.",
|
|
33
|
+
})),
|
|
34
|
+
id: Type.Optional(Type.String({
|
|
35
|
+
description: "For update: current/active, exact step id, unique id prefix, or unique content selector.",
|
|
36
|
+
})),
|
|
37
|
+
content: Type.Optional(Type.String({ minLength: 1, maxLength: 2_000 })),
|
|
38
|
+
activeForm: Type.Optional(Type.String({ maxLength: 2_000 })),
|
|
39
|
+
status: Type.Optional(statusSchema),
|
|
40
|
+
priority: Type.Optional(prioritySchema),
|
|
41
|
+
owner: Type.Optional(Type.String({ maxLength: 200 })),
|
|
42
|
+
note: Type.Optional(Type.String({ maxLength: 4_000 })),
|
|
43
|
+
evidence: Type.Optional(Type.Array(Type.String({ minLength: 1, maxLength: 2_000 }), { maxItems: 32 })),
|
|
44
|
+
clearCompleted: Type.Optional(Type.Boolean({ description: "For list: compact completed and cancelled steps before rendering." })),
|
|
45
|
+
showCompleted: Type.Optional(Type.Boolean({ description: "Include completed and cancelled steps in output." })),
|
|
46
|
+
maxItems: Type.Optional(Type.Integer({ minimum: 1, maximum: MAX_TASK_STEPS })),
|
|
47
|
+
}, { additionalProperties: false });
|
|
48
|
+
function toTaskStepInput(input) {
|
|
49
|
+
return {
|
|
50
|
+
content: input.content ?? "",
|
|
51
|
+
activeForm: input.activeForm,
|
|
52
|
+
status: input.status,
|
|
53
|
+
priority: input.priority,
|
|
54
|
+
owner: input.owner,
|
|
55
|
+
note: input.note,
|
|
56
|
+
evidence: input.evidence,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
function counts(state) {
|
|
60
|
+
const openStepCount = state.steps.filter((step) => step.status !== "completed" && step.status !== "cancelled").length;
|
|
61
|
+
return {
|
|
62
|
+
stepCount: state.steps.length,
|
|
63
|
+
openStepCount,
|
|
64
|
+
verificationNudgeNeeded: state.steps.some((step) => step.status === "completed" && step.evidence.length === 0),
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
function errorResult(action, error, state) {
|
|
68
|
+
return {
|
|
69
|
+
content: [{ type: "text", text: `task_steps ${action} failed: ${error}` }],
|
|
70
|
+
details: { action, applied: false, error, state, ...(state ? counts(state) : {}) },
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
export function createTaskStepsToolDefinition(deps) {
|
|
74
|
+
const now = deps.now ?? (() => new Date().toISOString());
|
|
75
|
+
return {
|
|
76
|
+
name: "task_steps",
|
|
77
|
+
label: "Task Steps",
|
|
78
|
+
description: "Maintain the current session's native ordered checklist for multi-step work. Supports pending, in_progress, completed, blocked, and cancelled steps with notes and evidence. State is isolated to and persisted with the active session; use native goal for durable outcome requirements and native delegate/delegate_status for background workers.",
|
|
79
|
+
promptSnippet: "Track and drain multi-step work with a native session checklist.",
|
|
80
|
+
promptGuidelines: [
|
|
81
|
+
"Use task_steps for complex work, explicit task-tracking requests, and harness/self-improvement work; keep exactly one step in_progress while actively working.",
|
|
82
|
+
"Always address the first open task step before unrelated work: start it, complete/block/cancel it with evidence, ask one clarifying question, or explicitly defer or reorder it.",
|
|
83
|
+
"Mark steps completed as soon as evidence is gathered, and attach concise evidence or a blocker reason through update.",
|
|
84
|
+
"Use action=intake with a complete steps array when preserving a raw multi-item dump; retain every item and do not silently drop entries.",
|
|
85
|
+
"Drain task_steps before final responses: leave no stale in_progress step, and explicitly discuss or defer remaining pending or blocked work.",
|
|
86
|
+
"Use goal for the durable goal ledger and delegate/delegate_status for worker lanes; do not emulate background execution inside task_steps.",
|
|
87
|
+
],
|
|
88
|
+
parameters: taskStepsSchema,
|
|
89
|
+
async execute(_toolCallId, input) {
|
|
90
|
+
const timestamp = now();
|
|
91
|
+
const current = deps.getTaskStepsState();
|
|
92
|
+
let state = current ?? createTaskStepsState(timestamp);
|
|
93
|
+
try {
|
|
94
|
+
switch (input.action) {
|
|
95
|
+
case "set":
|
|
96
|
+
if (!input.steps)
|
|
97
|
+
return errorResult(input.action, "set requires steps[].", current);
|
|
98
|
+
state = setTaskSteps(state, input.steps, timestamp);
|
|
99
|
+
break;
|
|
100
|
+
case "intake":
|
|
101
|
+
if (!input.steps)
|
|
102
|
+
return errorResult(input.action, "intake requires a complete steps[] list.", current);
|
|
103
|
+
state = setTaskSteps(state, input.steps, timestamp);
|
|
104
|
+
break;
|
|
105
|
+
case "add":
|
|
106
|
+
state = addTaskStep(state, toTaskStepInput(input), timestamp);
|
|
107
|
+
break;
|
|
108
|
+
case "update":
|
|
109
|
+
if (!input.id?.trim())
|
|
110
|
+
return errorResult(input.action, "update requires id or a unique selector.", current);
|
|
111
|
+
state = updateTaskStep(state, input.id, {
|
|
112
|
+
content: input.content,
|
|
113
|
+
activeForm: input.activeForm,
|
|
114
|
+
status: input.status,
|
|
115
|
+
priority: input.priority,
|
|
116
|
+
owner: input.owner,
|
|
117
|
+
note: input.note,
|
|
118
|
+
evidence: input.evidence,
|
|
119
|
+
}, timestamp);
|
|
120
|
+
break;
|
|
121
|
+
case "clear":
|
|
122
|
+
state = clearTaskSteps(state, timestamp);
|
|
123
|
+
break;
|
|
124
|
+
case "compact":
|
|
125
|
+
state = compactTaskSteps(state, timestamp);
|
|
126
|
+
break;
|
|
127
|
+
case "list":
|
|
128
|
+
if (input.clearCompleted)
|
|
129
|
+
state = compactTaskSteps(state, timestamp);
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
const mutated = input.action !== "list" || input.clearCompleted === true;
|
|
133
|
+
if (mutated)
|
|
134
|
+
deps.saveTaskStepsState(state);
|
|
135
|
+
return {
|
|
136
|
+
content: [
|
|
137
|
+
{
|
|
138
|
+
type: "text",
|
|
139
|
+
text: `${input.action === "list" ? "" : `task_steps ${input.action} recorded.\n`}${formatTaskSteps(state, {
|
|
140
|
+
includeTerminal: input.showCompleted,
|
|
141
|
+
maxItems: input.maxItems,
|
|
142
|
+
})}`,
|
|
143
|
+
},
|
|
144
|
+
],
|
|
145
|
+
details: {
|
|
146
|
+
action: input.action,
|
|
147
|
+
applied: true,
|
|
148
|
+
state,
|
|
149
|
+
...counts(state),
|
|
150
|
+
showCompleted: input.showCompleted,
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
return errorResult(input.action, error instanceof Error ? error.message : String(error), current);
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
//# sourceMappingURL=task-steps.js.map
|