u-foo 2.5.14 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/agents/prompts/native/environment.js +20 -8
- package/src/code/agent.js +517 -112
- package/src/code/commands.js +77 -0
- package/src/code/context/artifactGc.js +292 -0
- package/src/code/context/artifactIndex.js +161 -0
- package/src/code/context/artifacts.js +183 -0
- package/src/code/context/assembler.js +703 -0
- package/src/code/context/executionSegment.js +292 -0
- package/src/code/context/index.js +28 -0
- package/src/code/context/planGraph.js +1410 -0
- package/src/code/context/planGraphService.js +857 -0
- package/src/code/context/planMode.js +398 -0
- package/src/code/context/planProjection.js +432 -0
- package/src/code/context/projectSnapshot.js +201 -0
- package/src/code/context/promptLayers.js +175 -0
- package/src/code/context/reducers.js +328 -0
- package/src/code/context/stableJson.js +29 -0
- package/src/code/context/stateCommit.js +414 -0
- package/src/code/context/toolRuntime.js +172 -0
- package/src/code/context/transcript.js +182 -0
- package/src/code/context/transcriptSync.js +106 -0
- package/src/code/context/userInteraction.js +457 -0
- package/src/code/context/userNudge.js +116 -0
- package/src/code/context/workingSet.js +323 -0
- package/src/code/dispatch.js +20 -1
- package/src/code/index.js +8 -0
- package/src/code/modelCommand.js +87 -0
- package/src/code/nativeRunner.js +625 -34
- package/src/code/repl.js +196 -50
- package/src/code/runtime/agentWakeup.js +58 -0
- package/src/code/runtime/graphOwner.js +41 -0
- package/src/code/runtime/graphYieldRouter.js +42 -0
- package/src/code/runtime/index.js +15 -0
- package/src/code/runtime/loopMailbox.js +124 -0
- package/src/code/runtime/runtimeEvents.js +39 -0
- package/src/code/runtime/taskControl.js +565 -0
- package/src/code/runtime/taskFocus.js +165 -0
- package/src/code/runtime/taskLoop.js +383 -0
- package/src/code/runtime/taskRun.js +187 -0
- package/src/code/runtime/toolProvenance.js +70 -0
- package/src/code/runtime/workspaceLease.js +208 -0
- package/src/code/sessionStore.js +217 -15
- package/src/code/skills/index.js +10 -0
- package/src/code/skills/injection.js +66 -3
- package/src/code/skills/loader.js +21 -0
- package/src/code/skills/manifest.js +87 -0
- package/src/code/skills/render.js +15 -1
- package/src/code/taskDecomposer.js +56 -2
- package/src/code/tools/artifactRead.js +40 -0
- package/src/code/tools/askUser.js +11 -0
- package/src/code/tools/planGraph.js +29 -0
- package/src/code/tui.js +2 -0
- package/src/code/usageStore.js +15 -0
- package/src/ui/format/index.js +285 -45
- package/src/ui/format/markdownRenderer.js +436 -71
- package/src/ui/ink/ChatApp.js +39 -8
- package/src/ui/ink/UcodeApp.js +592 -43
- package/src/ui/ink/chatLogModel.js +102 -21
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const crypto = require("crypto");
|
|
6
|
+
const { randomUUID } = require("crypto");
|
|
7
|
+
|
|
8
|
+
function getArtifactsDir(workspaceRoot = process.cwd(), sessionId = "") {
|
|
9
|
+
const root = path.resolve(workspaceRoot || process.cwd());
|
|
10
|
+
const id = String(sessionId || "").trim();
|
|
11
|
+
if (!id) return path.join(root, ".ufoo", "agent", "ucode", "artifacts");
|
|
12
|
+
return path.join(root, ".ufoo", "agent", "ucode", "artifacts", id);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function createArtifactId(prefix = "artifact") {
|
|
16
|
+
const safe = String(prefix || "artifact").trim().replace(/[^a-zA-Z0-9_-]+/g, "") || "artifact";
|
|
17
|
+
return `${safe}_${Date.now().toString(36)}_${randomUUID().slice(0, 8)}`;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function hashContent(value = "") {
|
|
21
|
+
return crypto.createHash("sha256").update(String(value || ""), "utf8").digest("hex").slice(0, 16);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function getArtifactFilePath(workspaceRoot = process.cwd(), sessionId = "", artifactId = "") {
|
|
25
|
+
const id = String(artifactId || "").trim();
|
|
26
|
+
if (!id) return "";
|
|
27
|
+
return path.join(getArtifactsDir(workspaceRoot, sessionId), `${id}.json`);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function buildArtifactRecord({
|
|
31
|
+
artifactId = "",
|
|
32
|
+
type = "tool_result",
|
|
33
|
+
source = "",
|
|
34
|
+
tool = "",
|
|
35
|
+
args = {},
|
|
36
|
+
raw = null,
|
|
37
|
+
summary = "",
|
|
38
|
+
index = {},
|
|
39
|
+
createdBy = "",
|
|
40
|
+
cold = false,
|
|
41
|
+
coldAt = "",
|
|
42
|
+
createdAt = "",
|
|
43
|
+
hash = "",
|
|
44
|
+
sizeBytes = null,
|
|
45
|
+
} = {}) {
|
|
46
|
+
const rawText = typeof raw === "string" ? raw : JSON.stringify(raw);
|
|
47
|
+
const { buildArtifactIndex } = require("./artifactIndex");
|
|
48
|
+
const computedIndex = index && typeof index === "object" && Object.keys(index).length > 0
|
|
49
|
+
? index
|
|
50
|
+
: buildArtifactIndex({ tool, raw, args });
|
|
51
|
+
return {
|
|
52
|
+
artifactId: artifactId || createArtifactId(),
|
|
53
|
+
type: String(type || "tool_result"),
|
|
54
|
+
source: String(source || ""),
|
|
55
|
+
tool: String(tool || ""),
|
|
56
|
+
args: args && typeof args === "object" ? args : {},
|
|
57
|
+
hash: hash || hashContent(rawText),
|
|
58
|
+
sizeBytes: Number.isFinite(sizeBytes) ? sizeBytes : Buffer.byteLength(rawText, "utf8"),
|
|
59
|
+
createdAt: String(createdAt || "") || new Date().toISOString(),
|
|
60
|
+
createdBy: String(createdBy || tool || ""),
|
|
61
|
+
summary: String(summary || ""),
|
|
62
|
+
index: computedIndex && typeof computedIndex === "object" ? computedIndex : {},
|
|
63
|
+
cold: Boolean(cold),
|
|
64
|
+
coldAt: cold ? String(coldAt || new Date().toISOString()) : "",
|
|
65
|
+
raw,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function saveArtifact(workspaceRoot = process.cwd(), sessionId = "", record = {}) {
|
|
70
|
+
const payload = buildArtifactRecord(record);
|
|
71
|
+
const filePath = getArtifactFilePath(workspaceRoot, sessionId, payload.artifactId);
|
|
72
|
+
if (!filePath) {
|
|
73
|
+
return { ok: false, error: "invalid artifact id", artifact: null };
|
|
74
|
+
}
|
|
75
|
+
try {
|
|
76
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
77
|
+
fs.writeFileSync(filePath, `${JSON.stringify(payload, null, 2)}\n`, "utf8");
|
|
78
|
+
return { ok: true, error: "", artifact: payload, filePath };
|
|
79
|
+
} catch (err) {
|
|
80
|
+
return {
|
|
81
|
+
ok: false,
|
|
82
|
+
error: err && err.message ? err.message : "failed to save artifact",
|
|
83
|
+
artifact: payload,
|
|
84
|
+
filePath,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function loadArtifact(workspaceRoot = process.cwd(), sessionId = "", artifactId = "") {
|
|
90
|
+
const filePath = getArtifactFilePath(workspaceRoot, sessionId, artifactId);
|
|
91
|
+
if (!filePath || !fs.existsSync(filePath)) {
|
|
92
|
+
return { ok: false, error: `artifact not found: ${artifactId}`, artifact: null, filePath };
|
|
93
|
+
}
|
|
94
|
+
try {
|
|
95
|
+
const parsed = JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
96
|
+
return { ok: true, error: "", artifact: parsed, filePath };
|
|
97
|
+
} catch (err) {
|
|
98
|
+
return {
|
|
99
|
+
ok: false,
|
|
100
|
+
error: err && err.message ? err.message : "failed to load artifact",
|
|
101
|
+
artifact: null,
|
|
102
|
+
filePath,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function readArtifactSlice(artifact = null, selector = {}) {
|
|
108
|
+
const record = artifact && typeof artifact === "object" ? artifact : null;
|
|
109
|
+
if (!record) return { ok: false, error: "missing artifact", content: "" };
|
|
110
|
+
const raw = record.raw;
|
|
111
|
+
const sel = selector && typeof selector === "object" ? selector : {};
|
|
112
|
+
|
|
113
|
+
if (record.type === "source_file" || record.tool === "read") {
|
|
114
|
+
const content = raw && typeof raw === "object" ? String(raw.content || "") : String(raw || "");
|
|
115
|
+
const startLine = Number(sel.startLine || sel.start || 0);
|
|
116
|
+
const endLine = Number(sel.endLine || sel.end || 0);
|
|
117
|
+
if (startLine > 0 && endLine >= startLine) {
|
|
118
|
+
const lines = content.split(/\r?\n/);
|
|
119
|
+
const slice = lines.slice(startLine - 1, endLine).join("\n");
|
|
120
|
+
return { ok: true, error: "", content: slice, range: `${startLine}-${endLine}` };
|
|
121
|
+
}
|
|
122
|
+
const maxChars = Number(sel.maxChars || 8000);
|
|
123
|
+
if (content.length > maxChars) {
|
|
124
|
+
return {
|
|
125
|
+
ok: true,
|
|
126
|
+
error: "",
|
|
127
|
+
content: `${content.slice(0, maxChars)}\n...[truncated]`,
|
|
128
|
+
truncated: true,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
return { ok: true, error: "", content };
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (record.tool === "bash") {
|
|
135
|
+
const stdout = raw && typeof raw === "object" ? String(raw.stdout || "") : "";
|
|
136
|
+
const stderr = raw && typeof raw === "object" ? String(raw.stderr || "") : "";
|
|
137
|
+
const tail = Number(sel.tailLines || 40);
|
|
138
|
+
const tailStdout = stdout.split(/\r?\n/).slice(-tail).join("\n");
|
|
139
|
+
const tailStderr = stderr.split(/\r?\n/).slice(-tail).join("\n");
|
|
140
|
+
return {
|
|
141
|
+
ok: true,
|
|
142
|
+
error: "",
|
|
143
|
+
content: JSON.stringify({
|
|
144
|
+
exitCode: raw && typeof raw === "object" ? raw.code : null,
|
|
145
|
+
stdout: tailStdout,
|
|
146
|
+
stderr: tailStderr,
|
|
147
|
+
}, null, 2),
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const text = typeof raw === "string" ? raw : JSON.stringify(raw, null, 2);
|
|
152
|
+
const maxChars = Number(sel.maxChars || 12000);
|
|
153
|
+
if (text.length > maxChars) {
|
|
154
|
+
return { ok: true, error: "", content: `${text.slice(0, maxChars)}\n...[truncated]`, truncated: true };
|
|
155
|
+
}
|
|
156
|
+
return { ok: true, error: "", content: text };
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function deleteSessionArtifacts(workspaceRoot = process.cwd(), sessionId = "") {
|
|
160
|
+
const dir = getArtifactsDir(workspaceRoot, sessionId);
|
|
161
|
+
if (!fs.existsSync(dir)) return { ok: true, error: "" };
|
|
162
|
+
try {
|
|
163
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
164
|
+
return { ok: true, error: "" };
|
|
165
|
+
} catch (err) {
|
|
166
|
+
return {
|
|
167
|
+
ok: false,
|
|
168
|
+
error: err && err.message ? err.message : "failed to delete artifacts",
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
module.exports = {
|
|
174
|
+
getArtifactsDir,
|
|
175
|
+
createArtifactId,
|
|
176
|
+
hashContent,
|
|
177
|
+
getArtifactFilePath,
|
|
178
|
+
buildArtifactRecord,
|
|
179
|
+
saveArtifact,
|
|
180
|
+
loadArtifact,
|
|
181
|
+
readArtifactSlice,
|
|
182
|
+
deleteSessionArtifacts,
|
|
183
|
+
};
|