@datename/fastcode-termux 0.1.6-beta → 0.1.8-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +4 -0
- package/README.md +50 -17
- package/dist/agent/approval-json.d.ts +43 -0
- package/dist/agent/approval-json.js +69 -0
- package/dist/agent/approval-native.d.ts +3 -0
- package/dist/agent/approval-native.js +165 -0
- package/dist/agent/approval-store.d.ts +16 -0
- package/dist/agent/approval-store.js +21 -0
- package/dist/agent/approval.d.ts +33 -0
- package/dist/agent/approval.js +40 -5
- package/dist/agent/compaction.d.ts +2 -0
- package/dist/agent/compaction.js +60 -17
- package/dist/agent/guards.d.ts +16 -16
- package/dist/agent/guards.js +978 -24
- package/dist/agent/policy/defaults.d.ts +16 -0
- package/dist/agent/policy/defaults.js +17 -0
- package/dist/agent/policy/egress.d.ts +32 -0
- package/dist/agent/policy/egress.js +280 -0
- package/dist/agent/process-tree.d.ts +20 -0
- package/dist/agent/process-tree.js +81 -10
- package/dist/agent/protocol.d.ts +20 -1
- package/dist/agent/protocol.js +165 -38
- package/dist/agent/registry.d.ts +3 -1
- package/dist/agent/registry.js +168 -11
- package/dist/agent/runner.d.ts +21 -0
- package/dist/agent/runner.js +44 -5
- package/dist/agent/shell-ast.d.ts +11 -0
- package/dist/agent/shell-ast.js +204 -0
- package/dist/agent/shell-session.d.ts +14 -0
- package/dist/agent/shell-session.js +251 -40
- package/dist/agent/tool-schemas.js +26 -7
- package/dist/agent/tools/append_file.js +3 -1
- package/dist/agent/tools/apply_patch.js +44 -4
- package/dist/agent/tools/copy_file.js +26 -3
- package/dist/agent/tools/delete_file.js +22 -3
- package/dist/agent/tools/grep.js +35 -4
- package/dist/agent/tools/make_dir.js +3 -1
- package/dist/agent/tools/move_path.d.ts +7 -0
- package/dist/agent/tools/move_path.js +31 -5
- package/dist/agent/tools/read_file.js +63 -3
- package/dist/agent/tools/read_many.js +21 -3
- package/dist/agent/tools/readers.d.ts +53 -1
- package/dist/agent/tools/readers.js +236 -26
- package/dist/agent/tools/replace_in_file.js +38 -5
- package/dist/agent/tools/shell.js +2 -2
- package/dist/agent/tools/types.d.ts +26 -0
- package/dist/agent/tools/validate.d.ts +15 -2
- package/dist/agent/tools/validate.js +66 -3
- package/dist/agent/tools/write_file.js +3 -1
- package/dist/app.d.ts +2 -1
- package/dist/app.js +526 -85
- package/dist/cli-main.js +363 -0
- package/dist/cli.js +397 -337
- package/dist/commands/about.js +1 -1
- package/dist/commands/clear.d.ts +1 -0
- package/dist/commands/clear.js +1 -1
- package/dist/commands/compact.d.ts +12 -0
- package/dist/commands/compact.js +14 -2
- package/dist/commands/context.js +5 -4
- package/dist/commands/index.js +2 -0
- package/dist/commands/jobs.js +3 -2
- package/dist/commands/kill.js +3 -1
- package/dist/commands/login.d.ts +2 -2
- package/dist/commands/login.js +15 -15
- package/dist/commands/model.d.ts +1 -13
- package/dist/commands/model.js +6 -38
- package/dist/commands/provider.d.ts +1 -15
- package/dist/commands/provider.js +4 -22
- package/dist/commands/skills.js +34 -4
- package/dist/commands/threads.d.ts +9 -0
- package/dist/commands/threads.js +26 -0
- package/dist/config/store.d.ts +21 -0
- package/dist/config/store.js +47 -9
- package/dist/config/trust.d.ts +9 -0
- package/dist/config/trust.js +41 -2
- package/dist/headless.d.ts +7 -0
- package/dist/headless.js +213 -0
- package/dist/index.js +19 -3
- package/dist/lib/debug.d.ts +2 -0
- package/dist/lib/debug.js +22 -0
- package/dist/lib/diagnostics.d.ts +19 -0
- package/dist/lib/diagnostics.js +32 -6
- package/dist/lib/highlight-subset.d.ts +21 -0
- package/dist/lib/highlight-subset.js +88 -0
- package/dist/lib/lifecycle.d.ts +5 -0
- package/dist/lib/lifecycle.js +62 -0
- package/dist/lib/markdown.js +22 -4
- package/dist/providers/deepseek.js +1 -1
- package/dist/providers/openaiCompatible.d.ts +24 -2
- package/dist/providers/openaiCompatible.js +20 -6
- package/dist/providers/spec.d.ts +12 -0
- package/dist/providers/spec.js +29 -0
- package/dist/session/log.d.ts +14 -2
- package/dist/session/log.js +56 -27
- package/dist/session/projection.d.ts +34 -1
- package/dist/session/projection.js +315 -46
- package/dist/skills/manager.d.ts +15 -0
- package/dist/skills/manager.js +135 -18
- package/dist/types.d.ts +15 -0
- package/dist/ui/StatusBar.js +1 -1
- package/package.json +3 -2
- package/src/agent/approval-json.ts +103 -0
- package/src/agent/approval-native.ts +168 -0
- package/src/agent/approval-store.ts +38 -0
- package/src/agent/approval.ts +58 -11
- package/src/agent/compaction.ts +62 -17
- package/src/agent/guards.ts +1049 -25
- package/src/agent/policy/defaults.ts +34 -0
- package/src/agent/policy/egress.ts +335 -0
- package/src/agent/process-tree.ts +105 -23
- package/src/agent/protocol.ts +187 -39
- package/src/agent/registry.ts +186 -14
- package/src/agent/runner.ts +50 -7
- package/src/agent/shell-ast.ts +227 -0
- package/src/agent/shell-session.ts +265 -41
- package/src/agent/tool-schemas.ts +26 -7
- package/src/agent/tools/append_file.ts +3 -1
- package/src/agent/tools/apply_patch.ts +45 -4
- package/src/agent/tools/copy_file.ts +27 -3
- package/src/agent/tools/delete_file.ts +22 -3
- package/src/agent/tools/grep.ts +36 -4
- package/src/agent/tools/make_dir.ts +3 -1
- package/src/agent/tools/move_path.ts +38 -5
- package/src/agent/tools/read_file.ts +64 -3
- package/src/agent/tools/read_many.ts +21 -3
- package/src/agent/tools/readers.ts +289 -26
- package/src/agent/tools/replace_in_file.ts +39 -5
- package/src/agent/tools/shell.ts +2 -2
- package/src/agent/tools/types.ts +43 -1
- package/src/agent/tools/validate.ts +73 -4
- package/src/agent/tools/write_file.ts +3 -1
- package/src/app.ts +533 -82
- package/src/{cli.ts → cli-main.ts} +34 -6
- package/src/commands/about.ts +1 -1
- package/src/commands/clear.ts +1 -1
- package/src/commands/compact.ts +14 -2
- package/src/commands/context.ts +5 -4
- package/src/commands/index.ts +2 -0
- package/src/commands/jobs.ts +3 -2
- package/src/commands/kill.ts +3 -1
- package/src/commands/login.ts +15 -15
- package/src/commands/model.ts +6 -38
- package/src/commands/provider.ts +4 -22
- package/src/commands/skills.ts +34 -4
- package/src/commands/threads.ts +28 -0
- package/src/config/store.ts +47 -9
- package/src/config/trust.ts +45 -2
- package/src/headless.ts +225 -0
- package/src/index.ts +19 -3
- package/src/lib/debug.ts +24 -0
- package/src/lib/diagnostics.ts +32 -6
- package/src/lib/highlight-subset.ts +93 -0
- package/src/lib/lifecycle.ts +69 -0
- package/src/lib/markdown.ts +22 -4
- package/src/providers/deepseek.ts +1 -1
- package/src/providers/openaiCompatible.ts +47 -10
- package/src/providers/spec.ts +42 -0
- package/src/session/log.ts +70 -27
- package/src/session/projection.ts +360 -47
- package/src/skills/manager.ts +140 -18
- package/src/types/highlight-shims.d.ts +14 -0
- package/src/types.ts +16 -1
- package/src/ui/StatusBar.ts +1 -1
- package/tsconfig.json +1 -0
- /package/dist/{cli.d.ts → cli-main.d.ts} +0 -0
package/src/agent/approval.ts
CHANGED
|
@@ -17,10 +17,10 @@ export type ApprovalPreview =
|
|
|
17
17
|
| { kind: "choices"; items: ChoiceItem[] };
|
|
18
18
|
|
|
19
19
|
export type ApprovalOption =
|
|
20
|
-
| { kind: "allow"; scope: ApprovalScope; label: string }
|
|
21
|
-
| { kind: "deny"; label: string }
|
|
22
|
-
| { kind: "choose"; label: string; value: string }
|
|
23
|
-
| { kind: "feedback"; label: string; prompt: string };
|
|
20
|
+
| { kind: "allow"; id?: string; scope: ApprovalScope; label: string }
|
|
21
|
+
| { kind: "deny"; id?: string; label: string }
|
|
22
|
+
| { kind: "choose"; id?: string; label: string; value: string; meta?: { recommended?: boolean; risk?: string; files?: number; reason?: string } }
|
|
23
|
+
| { kind: "feedback"; id?: string; label: string; prompt: string };
|
|
24
24
|
|
|
25
25
|
export interface ApprovalRequest {
|
|
26
26
|
id: string;
|
|
@@ -29,19 +29,66 @@ export interface ApprovalRequest {
|
|
|
29
29
|
reason: ApprovalReason;
|
|
30
30
|
options: ApprovalOption[];
|
|
31
31
|
preview?: ApprovalPreview;
|
|
32
|
+
tier?: 0 | 1 | 2 | 3;
|
|
33
|
+
prompt?: string;
|
|
34
|
+
source?: "system" | "ai" | "free";
|
|
35
|
+
defaultIndex?: number;
|
|
36
|
+
timeoutMs?: number;
|
|
37
|
+
freeInput?: { enabled: true; prompt: string; hint?: string };
|
|
32
38
|
}
|
|
33
39
|
|
|
34
40
|
export type ApprovalDecision =
|
|
35
41
|
| { kind: "allow"; scope: ApprovalScope }
|
|
36
|
-
| { kind: "deny"; reason?: string; feedback?: string }
|
|
37
|
-
| { kind: "pending"; request: ApprovalRequest }
|
|
42
|
+
| { kind: "deny"; reason?: string; feedback?: string; code?: string; target?: string }
|
|
43
|
+
| { kind: "pending"; request: ApprovalRequest }
|
|
44
|
+
| { kind: "choose"; value: string; input?: string }
|
|
45
|
+
| { kind: "feedback"; text: string };
|
|
38
46
|
|
|
39
47
|
export type ApprovalResolver = (request: ApprovalRequest) => ApprovalDecision | Promise<ApprovalDecision>;
|
|
40
48
|
|
|
41
49
|
export const DEFAULT_ALLOW_OPTIONS: ApprovalOption[] = [
|
|
42
|
-
{ kind: "allow", scope: "once", label: "Allow once" },
|
|
43
|
-
{ kind: "allow", scope: "session", label: "Allow for this session" },
|
|
44
|
-
{ kind: "allow", scope: "always", label: "Always allow" },
|
|
45
|
-
{ kind: "deny", label: "Deny" },
|
|
46
|
-
{ kind: "feedback", label: "Deny with feedback", prompt: "Why should this be denied?" },
|
|
50
|
+
{ kind: "allow", id: "allow-once", scope: "once", label: "Allow once" },
|
|
51
|
+
{ kind: "allow", id: "allow-session", scope: "session", label: "Allow for this session" },
|
|
52
|
+
{ kind: "allow", id: "allow-always", scope: "always", label: "Always allow" },
|
|
53
|
+
{ kind: "deny", id: "deny", label: "Deny" },
|
|
54
|
+
{ kind: "feedback", id: "feedback", label: "Deny with feedback", prompt: "Why should this be denied?" },
|
|
47
55
|
];
|
|
56
|
+
|
|
57
|
+
export function approvalRequestId(): string {
|
|
58
|
+
return "ap_" + Date.now().toString(36) + "_" + Math.random().toString(36).slice(2, 7);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function approvalOptionForDecision(request: ApprovalRequest, decision: ApprovalDecision): ApprovalOption | undefined {
|
|
62
|
+
if (decision.kind === "allow")
|
|
63
|
+
return request.options.find((option) => option.kind === "allow" && option.scope === decision.scope);
|
|
64
|
+
if (decision.kind === "deny")
|
|
65
|
+
return request.options.find((option) => option.kind === "deny");
|
|
66
|
+
if (decision.kind === "choose")
|
|
67
|
+
return request.options.find((option) => option.kind === "choose" && option.value === decision.value);
|
|
68
|
+
if (decision.kind === "feedback")
|
|
69
|
+
return request.options.find((option) => option.kind === "feedback");
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function parseApprovalChoice(request: ApprovalRequest, text: string): ApprovalOption | undefined {
|
|
74
|
+
const index = Number(String(text ?? "").trim()) - 1;
|
|
75
|
+
if (!Number.isInteger(index) || index < 0 || index >= request.options.length)
|
|
76
|
+
return undefined;
|
|
77
|
+
return request.options[index];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function decisionForOption(option: ApprovalOption, input?: string): ApprovalDecision {
|
|
81
|
+
if (option.kind === "allow")
|
|
82
|
+
return { kind: "allow", scope: option.scope };
|
|
83
|
+
if (option.kind === "choose")
|
|
84
|
+
return { kind: "choose", value: option.value };
|
|
85
|
+
if (option.kind === "feedback") {
|
|
86
|
+
const text = typeof input === "string" ? input.trim() : "";
|
|
87
|
+
// The option's prompt is the question, not the user's answer. Without an
|
|
88
|
+
// actual answer, fail closed instead of sending the prompt back to the model.
|
|
89
|
+
return text
|
|
90
|
+
? { kind: "feedback", text }
|
|
91
|
+
: { kind: "deny", reason: "feedback was required but not provided (fail closed)" };
|
|
92
|
+
}
|
|
93
|
+
return { kind: "deny", reason: "denied by user" };
|
|
94
|
+
}
|
package/src/agent/compaction.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { mkdirSync, writeFileSync } from "node:fs";
|
|
2
|
-
import { join } from "node:path";
|
|
1
|
+
import { mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { basename, join, resolve, sep } from "node:path";
|
|
3
3
|
import { estMessagesTokens, estTokens } from "../lib/model-meta.js";
|
|
4
4
|
import { getPaths } from "../config/paths.js";
|
|
5
5
|
import type { ChatMessage } from "../types.js";
|
|
@@ -57,6 +57,15 @@ export function compactionConfigFromEnv(): CompactionConfig {
|
|
|
57
57
|
const heap = Number(process.env["FASTCODE_HEAP_LIMIT_MB"]);
|
|
58
58
|
if (Number.isFinite(heap) && heap > 0)
|
|
59
59
|
config.heapLimitMb = heap;
|
|
60
|
+
const ratio = Number(process.env["FASTCODE_COMPACTION_RATIO"]);
|
|
61
|
+
if (Number.isFinite(ratio) && ratio > 0 && ratio < 1)
|
|
62
|
+
config.localThresholdRatio = ratio;
|
|
63
|
+
const keepTurns = Number(process.env["FASTCODE_COMPACTION_KEEP_TURNS"]);
|
|
64
|
+
if (Number.isFinite(keepTurns) && keepTurns > 0)
|
|
65
|
+
config.keepTurns = Math.floor(keepTurns);
|
|
66
|
+
const summaryTokens = Number(process.env["FASTCODE_COMPACTION_SUMMARY_TOKENS"]);
|
|
67
|
+
if (Number.isFinite(summaryTokens) && summaryTokens > 0)
|
|
68
|
+
config.maxSummaryTokens = Math.floor(summaryTokens);
|
|
60
69
|
const server = (process.env["FASTCODE_SERVER_COMPACTION"] ?? "").trim().toLowerCase();
|
|
61
70
|
if (["1", "true", "yes", "on"].includes(server))
|
|
62
71
|
config.serverCompactionAware = true;
|
|
@@ -176,7 +185,7 @@ export function buildSummary(messages: ChatMessage[], config: CompactionConfig,
|
|
|
176
185
|
continue;
|
|
177
186
|
}
|
|
178
187
|
if (message.role === "assistant") {
|
|
179
|
-
const calls = parseToolCalls(message.content);
|
|
188
|
+
const calls = parseToolCalls(message.content).calls;
|
|
180
189
|
for (const call of calls)
|
|
181
190
|
actions.push(describeCall(call));
|
|
182
191
|
const visible = stripToolCalls(message.content);
|
|
@@ -192,23 +201,31 @@ export function buildSummary(messages: ChatMessage[], config: CompactionConfig,
|
|
|
192
201
|
}
|
|
193
202
|
collectFiles(message.content, files);
|
|
194
203
|
}
|
|
204
|
+
const fileList = Array.from(files);
|
|
195
205
|
const sections = [
|
|
196
206
|
"# Session summary",
|
|
197
207
|
"",
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
"",
|
|
201
|
-
"
|
|
202
|
-
...limitLines(actions, 20).map((line) => `- ${line}`),
|
|
208
|
+
// Conclusions first: when the token budget runs out, keep what the
|
|
209
|
+
// session decided rather than the oldest requests.
|
|
210
|
+
"## Notes",
|
|
211
|
+
...limitLines(notes, 10, "notes").map((line) => `- ${line}`),
|
|
203
212
|
"",
|
|
204
213
|
"## Outcomes",
|
|
205
|
-
...limitLines(outcomes, 10).map((line) => `- ${line}`),
|
|
214
|
+
...limitLines(outcomes, 10, "outcomes").map((line) => `- ${line}`),
|
|
206
215
|
"",
|
|
207
216
|
"## Files touched",
|
|
208
|
-
...(
|
|
217
|
+
...(fileList.length > 0
|
|
218
|
+
? [
|
|
219
|
+
...fileList.slice(0, 40).map((file) => `- ${file}`),
|
|
220
|
+
...(fileList.length > 40 ? [`- (${fileList.length - 40} more files not listed)`] : []),
|
|
221
|
+
]
|
|
222
|
+
: ["- (none recorded)"]),
|
|
209
223
|
"",
|
|
210
|
-
"##
|
|
211
|
-
...limitLines(
|
|
224
|
+
"## Requests",
|
|
225
|
+
...limitLines(requests, 8, "requests").map((line) => `- ${line}`),
|
|
226
|
+
"",
|
|
227
|
+
"## Actions",
|
|
228
|
+
...limitLines(actions, 20, "actions").map((line) => `- ${line}`),
|
|
212
229
|
];
|
|
213
230
|
const budget = Math.max(200, Math.floor(config.maxSummaryTokens));
|
|
214
231
|
const kept: string[] = [];
|
|
@@ -243,9 +260,7 @@ function collectFiles(text: string, files: Set<string>): void {
|
|
|
243
260
|
if (!matches)
|
|
244
261
|
return;
|
|
245
262
|
for (const match of matches) {
|
|
246
|
-
if (match
|
|
247
|
-
continue;
|
|
248
|
-
if (/^\d+(\.\d+)+$/.test(match))
|
|
263
|
+
if (!looksLikeProjectFile(match))
|
|
249
264
|
continue;
|
|
250
265
|
files.add(match);
|
|
251
266
|
if (files.size >= 200)
|
|
@@ -253,8 +268,20 @@ function collectFiles(text: string, files: Set<string>): void {
|
|
|
253
268
|
}
|
|
254
269
|
}
|
|
255
270
|
|
|
256
|
-
function
|
|
257
|
-
|
|
271
|
+
function looksLikeProjectFile(value: string): boolean {
|
|
272
|
+
if (value.length <= 3 || value.length > 240)
|
|
273
|
+
return false;
|
|
274
|
+
if (/^summary-\d/.test(value) || value.includes("//") || value.includes("\\.") || value.startsWith("s/"))
|
|
275
|
+
return false;
|
|
276
|
+
if (/^\d+(\.\d+)+$/.test(value))
|
|
277
|
+
return false;
|
|
278
|
+
return /\.(ts|tsx|js|jsx|mjs|cjs|json|md|txt|py|rs|go|java|kt|kts|c|cc|cpp|h|hpp|sh|bash|zsh|fish|yml|yaml|toml|ini|conf|cfg|env|lock|sql|html|css|scss|sass|less|vue|svelte|rb|php|swift|dart|xml|gradle|properties)$/i.test(value);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function limitLines(lines: string[], max: number, label: string): string[] {
|
|
282
|
+
if (lines.length <= max)
|
|
283
|
+
return lines;
|
|
284
|
+
return [...lines.slice(0, max), `(${lines.length - max} more ${label} not listed)`];
|
|
258
285
|
}
|
|
259
286
|
|
|
260
287
|
function clip(text: string, max: number): string {
|
|
@@ -262,6 +289,24 @@ function clip(text: string, max: number): string {
|
|
|
262
289
|
return oneLine.length > max ? oneLine.slice(0, max) + "…" : oneLine;
|
|
263
290
|
}
|
|
264
291
|
|
|
292
|
+
/** Delete a summary file only when it is one of our summary-*.md artifacts. */
|
|
293
|
+
export function removeSummaryFile(file?: string): void {
|
|
294
|
+
if (!file)
|
|
295
|
+
return;
|
|
296
|
+
const name = basename(file);
|
|
297
|
+
if (!/^summary-\d+.*\.md$/i.test(name))
|
|
298
|
+
return;
|
|
299
|
+
const sessions = resolve(getPaths().sessions) + sep;
|
|
300
|
+
if (!resolve(file).startsWith(sessions))
|
|
301
|
+
return;
|
|
302
|
+
try {
|
|
303
|
+
rmSync(file, { force: true });
|
|
304
|
+
}
|
|
305
|
+
catch {
|
|
306
|
+
// Best effort; an orphan summary is not worth failing compaction.
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
265
310
|
function writeSummaryFile(summary: string): string | undefined {
|
|
266
311
|
try {
|
|
267
312
|
const dir = getPaths().sessions;
|