@stringsync/splates 0.0.0-stage → 0.0.45
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 +21 -0
- package/README.md +308 -2
- package/acp-extensions.d.ts +82 -0
- package/add.d.ts +53 -0
- package/adherence.d.ts +49 -0
- package/age.d.ts +2 -0
- package/agent-connection.d.ts +171 -0
- package/agent-errors.d.ts +2 -0
- package/agent-process.d.ts +65 -0
- package/agent-stream.d.ts +91 -0
- package/agents.d.ts +15 -0
- package/artifact-room.d.ts +47 -0
- package/artifact-viewers.d.ts +6 -0
- package/artifact.d.ts +30 -0
- package/artifacts.d.ts +161 -0
- package/asked.d.ts +146 -0
- package/asked.js +7 -0
- package/assumed.d.ts +34 -0
- package/attach.d.ts +30 -0
- package/attachments.d.ts +43 -0
- package/baselines.d.ts +55 -0
- package/claim.d.ts +17 -0
- package/cloudflare-api.d.ts +25 -0
- package/cloudflare-error.d.ts +5 -0
- package/cloudflared-tunnel-provider.d.ts +27 -0
- package/codex-limits.d.ts +19 -0
- package/compaction.d.ts +17 -0
- package/config-source.d.ts +13 -0
- package/config.d.ts +98 -0
- package/config.js +7 -0
- package/conversation-archive.d.ts +6 -0
- package/conversation-background.d.ts +21 -0
- package/conversation-choice.d.ts +4 -0
- package/conversation-files.d.ts +51 -0
- package/conversation-given.d.ts +8 -0
- package/conversation-host.d.ts +102 -0
- package/conversation-listing.d.ts +15 -0
- package/conversation-log.d.ts +301 -0
- package/conversation-messages.d.ts +18 -0
- package/conversation-name.d.ts +28 -0
- package/conversation-options.d.ts +73 -0
- package/conversation-reference.d.ts +2 -0
- package/conversation-state.d.ts +472 -0
- package/conversation-turns.d.ts +115 -0
- package/conversation.d.ts +209 -0
- package/conversations.d.ts +140 -0
- package/coordinator-state.d.ts +28 -0
- package/creds.d.ts +123 -0
- package/darwin-temperature.d.ts +7 -0
- package/decided.d.ts +18 -0
- package/demo.d.ts +29 -0
- package/dev/api.d.ts +209 -0
- package/dev/assets.d.ts +24 -0
- package/dev/conversation-address.d.ts +47 -0
- package/dev/conversation-feed.d.ts +166 -0
- package/dev/live-stream.d.ts +29 -0
- package/dev/worker.d.ts +33 -0
- package/dev-access.d.ts +61 -0
- package/dev-artifacts.d.ts +22 -0
- package/dev-budgets.d.ts +18 -0
- package/dev-conversation-events.d.ts +39 -0
- package/dev-conversation-routes.d.ts +90 -0
- package/dev-creds.d.ts +17 -0
- package/dev-dictation-connection.d.ts +18 -0
- package/dev-dictation.d.ts +17 -0
- package/dev-http.d.ts +76 -0
- package/dev-open.d.ts +15 -0
- package/dev-options.d.ts +133 -0
- package/dev-outcomes.d.ts +21 -0
- package/dev-pages.d.ts +16 -0
- package/dev-picker.d.ts +57 -0
- package/dev-port-socket.d.ts +26 -0
- package/dev-ports.d.ts +11 -0
- package/dev-project-watch.d.ts +44 -0
- package/dev-project.d.ts +168 -0
- package/dev-push.d.ts +59 -0
- package/dev-restart.d.ts +141 -0
- package/dev-servers.d.ts +30 -0
- package/dev-setup-native.d.ts +23 -0
- package/dev-setup-opencode.d.ts +29 -0
- package/dev-setup.d.ts +16 -0
- package/dev-shell.d.ts +70 -0
- package/dev-slot.d.ts +28 -0
- package/dev-sockets.d.ts +13 -0
- package/dev-task-ports.d.ts +73 -0
- package/dev-tasks.d.ts +20 -0
- package/dev-terminal-connection.d.ts +19 -0
- package/dev-terminal.d.ts +42 -0
- package/dev-todos.d.ts +35 -0
- package/dev-transcriber.d.ts +15 -0
- package/dev-tunnel.d.ts +38 -0
- package/dev-versions.d.ts +53 -0
- package/dev-workers.d.ts +55 -0
- package/dev.d.ts +24 -0
- package/diff.d.ts +29 -0
- package/dispatched.d.ts +16 -0
- package/editors.d.ts +22 -0
- package/escalate.d.ts +27 -0
- package/events.d.ts +311 -0
- package/everywhere.d.ts +41 -0
- package/exhibit.d.ts +21 -0
- package/exit.d.ts +54 -0
- package/fact-todos.d.ts +18 -0
- package/fake-agent.d.ts +107 -0
- package/fake-agent.js +284 -0
- package/finding-facts.d.ts +38 -0
- package/findings.d.ts +84 -0
- package/fold.d.ts +43 -0
- package/follow.d.ts +41 -0
- package/format.d.ts +68 -0
- package/git.d.ts +112 -0
- package/handed-out.d.ts +79 -0
- package/handoff.d.ts +23 -0
- package/heavy-run.d.ts +12 -0
- package/heavy.d.ts +28 -0
- package/heavy.js +16 -0
- package/held.d.ts +22 -0
- package/index-0tfvy823.js +272 -0
- package/index-43pq33n4.js +157 -0
- package/index-4776671w.js +698 -0
- package/index-d4hjrzaq.js +464 -0
- package/index-gcfq7awr.js +740 -0
- package/index-k73tsw5g.js +101 -0
- package/index-kaa44k7q.js +59 -0
- package/index-vcv9m93e.js +1265 -0
- package/index-xmfmy729.js +249 -0
- package/index.d.ts +2 -0
- package/index.js +26928 -0
- package/init.d.ts +28 -0
- package/journal.d.ts +57 -0
- package/landed.d.ts +14 -0
- package/lane-todos.d.ts +44 -0
- package/lane.d.ts +55 -0
- package/lanes-from-tags.d.ts +17 -0
- package/lanes.d.ts +96 -0
- package/legacy-names.d.ts +70 -0
- package/legacy-ps.d.ts +31 -0
- package/limits.d.ts +32 -0
- package/list.d.ts +18 -0
- package/load-config.d.ts +44 -0
- package/log.d.ts +14 -0
- package/machine.d.ts +42 -0
- package/merge.d.ts +35 -0
- package/migrate-config.d.ts +31 -0
- package/models.d.ts +24 -0
- package/needs.d.ts +115 -0
- package/notices.d.ts +39 -0
- package/offered.d.ts +39 -0
- package/opencode-usage.d.ts +37 -0
- package/outcomes.d.ts +114 -0
- package/package.json +74 -5
- package/path.d.ts +13 -0
- package/plan.d.ts +236 -0
- package/port-forward.d.ts +22 -0
- package/port-pipe.d.ts +36 -0
- package/ports-list.d.ts +19 -0
- package/probe-runtime.d.ts +5 -0
- package/probe-runtime.js +13 -0
- package/project-reaches.d.ts +23 -0
- package/projects.d.ts +136 -0
- package/prompts.d.ts +128 -0
- package/pty.d.ts +39 -0
- package/pulse.d.ts +8 -0
- package/recommend.d.ts +31 -0
- package/release.d.ts +41 -0
- package/remote-process.d.ts +26 -0
- package/remote-pty.d.ts +29 -0
- package/remote-worker.d.ts +77 -0
- package/remove.d.ts +31 -0
- package/repository.d.ts +91 -0
- package/retry.d.ts +34 -0
- package/roster.d.ts +63 -0
- package/saved-ports-host.d.ts +25 -0
- package/saved-tunnel.d.ts +44 -0
- package/server-worker-socket.d.ts +21 -0
- package/setup-areas.d.ts +7 -0
- package/setup-opencode-model-error.d.ts +3 -0
- package/setup-opencode-models.d.ts +54 -0
- package/setup-opencode-recipe.d.ts +26 -0
- package/setup-opencode.d.ts +46 -0
- package/setup.d.ts +102 -0
- package/shared-browser.d.ts +50 -0
- package/shell.d.ts +17 -0
- package/show.d.ts +106 -0
- package/skill-checks.d.ts +73 -0
- package/skill-checks.js +10 -0
- package/skills.d.ts +16 -0
- package/slot-tunnel.d.ts +27 -0
- package/slots.d.ts +135 -0
- package/snapshot.d.ts +75 -0
- package/splates-artifact.d.ts +3 -0
- package/splates-creds.d.ts +3 -0
- package/splates-dev.d.ts +22 -0
- package/splates-flags.d.ts +34 -0
- package/splates-lane.d.ts +3 -0
- package/splates-projects.d.ts +3 -0
- package/splates-setup.d.ts +17 -0
- package/splates-slots.d.ts +3 -0
- package/splates-todo.d.ts +3 -0
- package/splates-tunnel.d.ts +3 -0
- package/splates-worker.d.ts +3 -0
- package/splates.d.ts +28 -0
- package/stats.d.ts +186 -0
- package/supervise.d.ts +50 -0
- package/system-changes.d.ts +67 -0
- package/system.d.ts +28 -0
- package/systems.d.ts +119 -0
- package/systems.js +21 -0
- package/table.d.ts +5 -0
- package/task-log.d.ts +35 -0
- package/task-ports.d.ts +25 -0
- package/tell.d.ts +47 -0
- package/todo-edit.d.ts +60 -0
- package/todo-file.d.ts +6 -0
- package/todo-lanes.d.ts +82 -0
- package/todo-list.d.ts +26 -0
- package/todo-take.d.ts +27 -0
- package/todo.d.ts +146 -0
- package/todos.d.ts +157 -0
- package/tool-calls.d.ts +18 -0
- package/tunnel-provider.d.ts +37 -0
- package/tunnel-provider.js +0 -0
- package/tunnel-remove.d.ts +28 -0
- package/tunnel-setup.d.ts +104 -0
- package/unix-worker-listener.d.ts +23 -0
- package/unix-worker-socket.d.ts +30 -0
- package/update.d.ts +29 -0
- package/update.js +10 -0
- package/vocabulary.d.ts +9 -0
- package/wait.d.ts +36 -0
- package/watch.d.ts +46 -0
- package/watched.d.ts +43 -0
- package/websocket-worker-socket.d.ts +18 -0
- package/worker-call-host.d.ts +51 -0
- package/worker-channel.d.ts +83 -0
- package/worker-connection.d.ts +24 -0
- package/worker-daemon.d.ts +64 -0
- package/worker-git.d.ts +18 -0
- package/worker-list.d.ts +49 -0
- package/worker-machine.d.ts +34 -0
- package/worker-port-host.d.ts +21 -0
- package/worker-process-host.d.ts +29 -0
- package/worker-protocol.d.ts +104 -0
- package/worker-pty-host.d.ts +34 -0
- package/worker-registry.d.ts +68 -0
- package/worker-replay.d.ts +25 -0
- package/worker-run.d.ts +20 -0
- package/worker-session.d.ts +189 -0
- package/worker-socket.d.ts +15 -0
- package/worktree-service.d.ts +113 -0
- package/worktree.d.ts +232 -0
|
@@ -0,0 +1,698 @@
|
|
|
1
|
+
import {
|
|
2
|
+
legacyWarnings,
|
|
3
|
+
legacyFile
|
|
4
|
+
} from "./index-k73tsw5g.js";
|
|
5
|
+
import {
|
|
6
|
+
fail
|
|
7
|
+
} from "./index-kaa44k7q.js";
|
|
8
|
+
|
|
9
|
+
// systems.ts
|
|
10
|
+
import { NodeFs as NodeFs3, NodeGlob } from "webappwiz/system";
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
|
|
13
|
+
// load-config.ts
|
|
14
|
+
import { realpath } from "node:fs/promises";
|
|
15
|
+
import { basename as basename3, resolve as resolve3 } from "node:path";
|
|
16
|
+
import { NodeFs as NodeFs2 } from "webappwiz/system";
|
|
17
|
+
|
|
18
|
+
// artifacts.ts
|
|
19
|
+
import { basename as basename2, dirname, resolve as resolve2 } from "node:path";
|
|
20
|
+
import { UuidProvider as UuidProvider2 } from "webappwiz/id";
|
|
21
|
+
|
|
22
|
+
// attachments.ts
|
|
23
|
+
import { basename, resolve } from "node:path";
|
|
24
|
+
import { UuidProvider } from "webappwiz/id";
|
|
25
|
+
class Attachments {
|
|
26
|
+
dir;
|
|
27
|
+
fs;
|
|
28
|
+
ids;
|
|
29
|
+
constructor(dir, fs, ids = new UuidProvider) {
|
|
30
|
+
this.dir = dir;
|
|
31
|
+
this.fs = fs;
|
|
32
|
+
this.ids = ids;
|
|
33
|
+
}
|
|
34
|
+
async store(files) {
|
|
35
|
+
if (files.length === 0) {
|
|
36
|
+
return [];
|
|
37
|
+
}
|
|
38
|
+
await this.fs.mkdir(this.dir);
|
|
39
|
+
const stored = [];
|
|
40
|
+
for (const file of files) {
|
|
41
|
+
const path = `${this.dir}/${this.ids.next()}-${safe(file.name)}`;
|
|
42
|
+
await this.fs.writeBytes(path, file.bytes);
|
|
43
|
+
stored.push(path);
|
|
44
|
+
}
|
|
45
|
+
return stored;
|
|
46
|
+
}
|
|
47
|
+
async held() {
|
|
48
|
+
const names = await this.fs.readdir(this.dir).catch(() => []);
|
|
49
|
+
const held = [];
|
|
50
|
+
for (const name of names.sort()) {
|
|
51
|
+
const path = `${this.dir}/${name}`;
|
|
52
|
+
held.push({ path, bytes: (await this.fs.stat(path)).size });
|
|
53
|
+
}
|
|
54
|
+
return held;
|
|
55
|
+
}
|
|
56
|
+
owns(path) {
|
|
57
|
+
return resolve(path).startsWith(`${resolve(this.dir)}/`);
|
|
58
|
+
}
|
|
59
|
+
async remove(paths) {
|
|
60
|
+
for (const path of paths.filter((path) => this.owns(path))) {
|
|
61
|
+
await this.fs.rm(path, { force: true });
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
async clear() {
|
|
65
|
+
await this.fs.rm(this.dir, { recursive: true, force: true });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
async function readFiles({ fs, ps }, paths) {
|
|
69
|
+
const read = [];
|
|
70
|
+
for (const given of paths) {
|
|
71
|
+
const path = resolve(ps.cwd(), given);
|
|
72
|
+
const bytes = await fs.readBytes(path).catch(() => null);
|
|
73
|
+
if (bytes === null) {
|
|
74
|
+
fail("usage", `cannot read ${path}: nothing was changed`, {
|
|
75
|
+
file: path
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
read.push({ name: basename(path), bytes });
|
|
79
|
+
}
|
|
80
|
+
return read;
|
|
81
|
+
}
|
|
82
|
+
function safe(name) {
|
|
83
|
+
return basename(name).replace(/[^\w.-]+/g, "-") || "attachment";
|
|
84
|
+
}
|
|
85
|
+
async function folderBytes(fs, dir) {
|
|
86
|
+
let total = 0;
|
|
87
|
+
for (const name of await fs.readdir(dir).catch(() => [])) {
|
|
88
|
+
const path = `${dir}/${name}`;
|
|
89
|
+
const found = await fs.stat(path);
|
|
90
|
+
total += found.isDirectory() ? await folderBytes(fs, path) : found.size;
|
|
91
|
+
}
|
|
92
|
+
return total;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// artifacts.ts
|
|
96
|
+
class Artifacts {
|
|
97
|
+
deps;
|
|
98
|
+
dir;
|
|
99
|
+
conversations;
|
|
100
|
+
ids;
|
|
101
|
+
queue = Promise.resolve();
|
|
102
|
+
constructor(log, deps) {
|
|
103
|
+
this.deps = deps;
|
|
104
|
+
this.dir = `${resolve2(log.replace(/\.jsonl$/, ""))}/artifacts`;
|
|
105
|
+
this.conversations = dirname(resolve2(log));
|
|
106
|
+
this.ids = deps.ids ?? new UuidProvider2;
|
|
107
|
+
}
|
|
108
|
+
get held() {
|
|
109
|
+
return this.deps.held();
|
|
110
|
+
}
|
|
111
|
+
add(file) {
|
|
112
|
+
const { room } = this.deps;
|
|
113
|
+
if (room === undefined) {
|
|
114
|
+
return this.serially(async () => {
|
|
115
|
+
const size = await this.admit(file);
|
|
116
|
+
const { fs, limits } = this.deps;
|
|
117
|
+
const project = await projectBytes(fs, this.conversations) + size;
|
|
118
|
+
if (project > limits.project) {
|
|
119
|
+
tooLarge("the project", file.name.trim(), project, limits.project);
|
|
120
|
+
}
|
|
121
|
+
return this.keep(file);
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
return room.hold(async () => {
|
|
125
|
+
await room.make(await this.admit(file), file.name.trim());
|
|
126
|
+
return this.serially(() => this.keep(file));
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
remove(name) {
|
|
130
|
+
return this.serially(async () => {
|
|
131
|
+
const artifact = this.find(name);
|
|
132
|
+
if (artifact.removedAt !== null) {
|
|
133
|
+
fail("not_found", `artifact '${name}' is already removed`, { name });
|
|
134
|
+
}
|
|
135
|
+
await this.deps.record({ type: "remove", name, at: this.deps.now() });
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
delete(name, version, why) {
|
|
139
|
+
return this.serially(async () => {
|
|
140
|
+
const kept = this.find(name).versions.find((each) => each.version === version);
|
|
141
|
+
if (kept === undefined) {
|
|
142
|
+
fail("not_found", `artifact '${name}' has no version ${version}`, {
|
|
143
|
+
name,
|
|
144
|
+
version
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
if (kept.gone === null) {
|
|
148
|
+
await this.drop(name, kept, why);
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
archive() {
|
|
153
|
+
return this.serially(async () => {
|
|
154
|
+
for (const artifact of this.deps.held()) {
|
|
155
|
+
for (const version of artifact.versions) {
|
|
156
|
+
if (version.gone === null && !shown(artifact, version)) {
|
|
157
|
+
await this.drop(artifact.name, version, "archived");
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
async read(name, version) {
|
|
164
|
+
const artifact = this.deps.held().find((each) => each.name === name);
|
|
165
|
+
const wanted = version ?? artifact?.current;
|
|
166
|
+
const kept = artifact?.versions.find((each) => each.version === wanted);
|
|
167
|
+
if (kept === undefined || kept.gone !== null) {
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
const bytes = await this.deps.fs.readBytes(`${this.dir}/${kept.file}`).catch(() => null);
|
|
171
|
+
return bytes === null ? null : { bytes, mimeType: kept.mimeType };
|
|
172
|
+
}
|
|
173
|
+
async admit(file) {
|
|
174
|
+
const name = file.name.trim();
|
|
175
|
+
if (name === "") {
|
|
176
|
+
fail("usage", "an artifact needs a name: nothing was changed");
|
|
177
|
+
}
|
|
178
|
+
const size = file.bytes.length;
|
|
179
|
+
const { limits } = this.deps;
|
|
180
|
+
if (size > limits.file) {
|
|
181
|
+
fail("too_large", `'${name}' is ${megabytes(size)}, past the ${megabytes(limits.file)} an artifact may be: nothing was changed`, { name, bytes: size, capacity: limits.file });
|
|
182
|
+
}
|
|
183
|
+
const attached = await folderBytes(this.deps.fs, `${dirname(this.dir)}/attached`);
|
|
184
|
+
const conversation = kept(this.deps.held()) + attached + size;
|
|
185
|
+
if (conversation > limits.conversation) {
|
|
186
|
+
tooLarge("this conversation", name, conversation, limits.conversation);
|
|
187
|
+
}
|
|
188
|
+
return size;
|
|
189
|
+
}
|
|
190
|
+
async keep(file) {
|
|
191
|
+
const name = file.name.trim();
|
|
192
|
+
const stored = `${this.ids.next()}-${safe2(name)}`;
|
|
193
|
+
await this.deps.fs.mkdir(this.dir);
|
|
194
|
+
await this.deps.fs.writeBytes(`${this.dir}/${stored}`, file.bytes);
|
|
195
|
+
await this.deps.record({
|
|
196
|
+
type: "add",
|
|
197
|
+
name,
|
|
198
|
+
file: stored,
|
|
199
|
+
mimeType: file.mimeType,
|
|
200
|
+
bytes: file.bytes.length,
|
|
201
|
+
addedAt: this.deps.now()
|
|
202
|
+
});
|
|
203
|
+
const added = this.find(name);
|
|
204
|
+
return added.versions[added.versions.length - 1];
|
|
205
|
+
}
|
|
206
|
+
async drop(name, version, why) {
|
|
207
|
+
await this.deps.fs.rm(`${this.dir}/${version.file}`, { force: true });
|
|
208
|
+
await this.deps.record({
|
|
209
|
+
type: "gone",
|
|
210
|
+
name,
|
|
211
|
+
version: version.version,
|
|
212
|
+
at: this.deps.now(),
|
|
213
|
+
why
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
find(name) {
|
|
217
|
+
const artifact = this.deps.held().find((each) => each.name === name);
|
|
218
|
+
if (artifact === undefined) {
|
|
219
|
+
fail("not_found", `this conversation holds no artifact '${name}'`, {
|
|
220
|
+
name
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
return artifact;
|
|
224
|
+
}
|
|
225
|
+
serially(work) {
|
|
226
|
+
const next = this.queue.then(work);
|
|
227
|
+
this.queue = next.catch(() => {});
|
|
228
|
+
return next;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
var ARTIFACT_LIMITS = {
|
|
232
|
+
file: 50 * 1024 * 1024,
|
|
233
|
+
conversation: 250 * 1024 * 1024,
|
|
234
|
+
project: 2 * 1024 * 1024 * 1024
|
|
235
|
+
};
|
|
236
|
+
function artifactLimits(config) {
|
|
237
|
+
return {
|
|
238
|
+
file: config.artifactFileCapacity,
|
|
239
|
+
conversation: config.artifactConversationCapacity,
|
|
240
|
+
project: config.artifactProjectCapacity
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
function applyArtifact(artifacts, change) {
|
|
244
|
+
const artifact = artifacts.find((each) => each.name === change.name);
|
|
245
|
+
if (change.type === "add") {
|
|
246
|
+
const { type: _, name, ...added } = change;
|
|
247
|
+
const version = (artifact?.versions.length ?? 0) + 1;
|
|
248
|
+
const kept = { version, ...added, gone: null };
|
|
249
|
+
if (artifact === undefined) {
|
|
250
|
+
artifacts.push({
|
|
251
|
+
name,
|
|
252
|
+
current: version,
|
|
253
|
+
versions: [kept],
|
|
254
|
+
removedAt: null
|
|
255
|
+
});
|
|
256
|
+
} else {
|
|
257
|
+
artifact.versions.push(kept);
|
|
258
|
+
artifact.current = version;
|
|
259
|
+
artifact.removedAt = null;
|
|
260
|
+
}
|
|
261
|
+
} else if (change.type === "remove") {
|
|
262
|
+
if (artifact !== undefined) {
|
|
263
|
+
artifact.removedAt = change.at;
|
|
264
|
+
}
|
|
265
|
+
} else {
|
|
266
|
+
const version = artifact?.versions.find((each) => each.version === change.version);
|
|
267
|
+
if (version !== undefined) {
|
|
268
|
+
version.gone = { at: change.at, why: change.why };
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
function kept(artifacts) {
|
|
273
|
+
return artifacts.flatMap((each) => each.versions).filter((each) => each.gone === null).reduce((sum, each) => sum + each.bytes, 0);
|
|
274
|
+
}
|
|
275
|
+
function shown(artifact, version) {
|
|
276
|
+
return artifact.removedAt === null && version.version === artifact.current;
|
|
277
|
+
}
|
|
278
|
+
async function projectBytes(fs, dir) {
|
|
279
|
+
let total = 0;
|
|
280
|
+
for (const entry of await fs.readdir(dir).catch(() => [])) {
|
|
281
|
+
total += await folderBytes(fs, `${dir}/${entry}/artifacts`);
|
|
282
|
+
total += await folderBytes(fs, `${dir}/${entry}/attached`);
|
|
283
|
+
}
|
|
284
|
+
return total;
|
|
285
|
+
}
|
|
286
|
+
function tooLarge(what, name, bytes, capacity) {
|
|
287
|
+
fail("too_large", `that would have ${what} hold ${megabytes(bytes)} of artifacts, past its ${megabytes(capacity)}: nothing was changed`, { name, bytes, capacity });
|
|
288
|
+
}
|
|
289
|
+
function safe2(name) {
|
|
290
|
+
return basename2(name).replace(/[^\w.-]+/g, "-") || "artifact";
|
|
291
|
+
}
|
|
292
|
+
function megabytes(bytes) {
|
|
293
|
+
return `${(bytes / 1024 / 1024).toFixed(1)} MB`;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// git.ts
|
|
297
|
+
import { NodeFs, NodePs } from "webappwiz/system";
|
|
298
|
+
|
|
299
|
+
class Git {
|
|
300
|
+
root;
|
|
301
|
+
ps;
|
|
302
|
+
fs;
|
|
303
|
+
constructor(root, opts = {}) {
|
|
304
|
+
this.root = root;
|
|
305
|
+
this.ps = opts.ps ?? new NodePs;
|
|
306
|
+
this.fs = opts.fs ?? new NodeFs;
|
|
307
|
+
}
|
|
308
|
+
async run(cwd, ...args) {
|
|
309
|
+
const { exitCode, stdout, stderr } = await this.ps.spawnCapture([
|
|
310
|
+
"git",
|
|
311
|
+
"--no-optional-locks",
|
|
312
|
+
"-C",
|
|
313
|
+
cwd,
|
|
314
|
+
...args
|
|
315
|
+
]);
|
|
316
|
+
return { code: exitCode, stdout: stdout.trim(), stderr: stderr.trim() };
|
|
317
|
+
}
|
|
318
|
+
async out(cwd, ...args) {
|
|
319
|
+
const result = await this.run(cwd, ...args);
|
|
320
|
+
if (result.code !== 0) {
|
|
321
|
+
throw new Error(`git ${args.join(" ")}: ${result.stderr || result.stdout}`);
|
|
322
|
+
}
|
|
323
|
+
return result.stdout;
|
|
324
|
+
}
|
|
325
|
+
async branchExists(branch) {
|
|
326
|
+
const { code } = await this.run(this.root, "rev-parse", "--verify", "--quiet", `refs/heads/${branch}`);
|
|
327
|
+
return code === 0;
|
|
328
|
+
}
|
|
329
|
+
async defaultBranch() {
|
|
330
|
+
const { code, stdout } = await this.run(this.root, "symbolic-ref", "--short", "refs/remotes/origin/HEAD");
|
|
331
|
+
return code === 0 ? stdout.replace(/^origin\//, "") || null : null;
|
|
332
|
+
}
|
|
333
|
+
async currentBranch(cwd) {
|
|
334
|
+
const { code, stdout, stderr } = await this.run(cwd, "symbolic-ref", "--quiet", "--short", "HEAD");
|
|
335
|
+
if (code === 0) {
|
|
336
|
+
return stdout;
|
|
337
|
+
}
|
|
338
|
+
if (code === 1 || stderr.includes("not a git repository")) {
|
|
339
|
+
return null;
|
|
340
|
+
}
|
|
341
|
+
throw new Error(`git symbolic-ref HEAD: ${stderr || stdout}`);
|
|
342
|
+
}
|
|
343
|
+
head(cwd) {
|
|
344
|
+
return this.out(cwd, "rev-parse", "HEAD");
|
|
345
|
+
}
|
|
346
|
+
shortHead(cwd) {
|
|
347
|
+
return this.out(cwd, "rev-parse", "--short", "HEAD");
|
|
348
|
+
}
|
|
349
|
+
async porcelain(cwd) {
|
|
350
|
+
return lines(await this.out(cwd, "status", "--porcelain"));
|
|
351
|
+
}
|
|
352
|
+
async conflictedPaths(cwd) {
|
|
353
|
+
const out = await this.out(cwd, "diff", "--name-only", "--diff-filter=U").catch(() => "");
|
|
354
|
+
return lines(out);
|
|
355
|
+
}
|
|
356
|
+
async commitsAhead(trunk, branch) {
|
|
357
|
+
const result = await this.run(this.root, "rev-list", "--count", `${trunk}..${branch}`);
|
|
358
|
+
return result.code === 0 ? Number(result.stdout) : null;
|
|
359
|
+
}
|
|
360
|
+
async committedAt(ref) {
|
|
361
|
+
const { code, stdout } = await this.run(this.root, "log", "-1", "--format=%cI", ref, "--");
|
|
362
|
+
return code === 0 && stdout.trim() !== "" ? stdout.trim() : null;
|
|
363
|
+
}
|
|
364
|
+
async commitMessages(trunk, branch) {
|
|
365
|
+
const result = await this.run(this.root, "log", "--reverse", "--format=%B%x00", `${trunk}..${branch}`);
|
|
366
|
+
return result.code === 0 ? result.stdout.split("\x00").map((each) => each.trim()).filter(Boolean) : null;
|
|
367
|
+
}
|
|
368
|
+
async diff(trunk, branch, worktree) {
|
|
369
|
+
const base = await this.run(this.root, "merge-base", trunk, branch);
|
|
370
|
+
if (base.code !== 0) {
|
|
371
|
+
return null;
|
|
372
|
+
}
|
|
373
|
+
const raw = (cwd, ...args) => this.ps.spawnCapture([
|
|
374
|
+
"git",
|
|
375
|
+
"--no-optional-locks",
|
|
376
|
+
"-C",
|
|
377
|
+
cwd,
|
|
378
|
+
"diff",
|
|
379
|
+
"--no-color",
|
|
380
|
+
"--no-ext-diff",
|
|
381
|
+
...args
|
|
382
|
+
]);
|
|
383
|
+
const { exitCode, stdout } = await raw(worktree ?? this.root, base.stdout, ...worktree === null ? [branch] : []);
|
|
384
|
+
if (exitCode !== 0) {
|
|
385
|
+
return null;
|
|
386
|
+
}
|
|
387
|
+
if (worktree === null) {
|
|
388
|
+
return { text: stdout, uncommitted: [] };
|
|
389
|
+
}
|
|
390
|
+
const edited = await this.run(worktree, "diff", "--name-only", "HEAD");
|
|
391
|
+
const untracked = await this.run(worktree, "ls-files", "--others", "--exclude-standard");
|
|
392
|
+
if (edited.code !== 0 || untracked.code !== 0) {
|
|
393
|
+
return null;
|
|
394
|
+
}
|
|
395
|
+
let text = stdout;
|
|
396
|
+
for (const path of lines(untracked.stdout)) {
|
|
397
|
+
const added = await raw(worktree, "--no-index", "--", "/dev/null", path);
|
|
398
|
+
text += added.stdout;
|
|
399
|
+
}
|
|
400
|
+
return {
|
|
401
|
+
text,
|
|
402
|
+
uncommitted: [
|
|
403
|
+
...new Set([...lines(edited.stdout), ...lines(untracked.stdout)])
|
|
404
|
+
]
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
async changedFiles(trunk, branch, worktree) {
|
|
408
|
+
const committed = await this.run(this.root, "diff", "--name-only", `${trunk}...${branch}`);
|
|
409
|
+
if (committed.code !== 0) {
|
|
410
|
+
return null;
|
|
411
|
+
}
|
|
412
|
+
const paths = lines(committed.stdout);
|
|
413
|
+
if (worktree !== null) {
|
|
414
|
+
const edited = await this.run(worktree, "diff", "--name-only", "HEAD");
|
|
415
|
+
const added = await this.run(worktree, "ls-files", "--others", "--exclude-standard");
|
|
416
|
+
paths.push(...lines(edited.stdout), ...lines(added.stdout));
|
|
417
|
+
}
|
|
418
|
+
return [...new Set(paths)].sort();
|
|
419
|
+
}
|
|
420
|
+
async paths(cwd) {
|
|
421
|
+
const files = lines(await this.out(cwd, "ls-files", "--cached", "--others", "--exclude-standard"));
|
|
422
|
+
const found = new Set(files);
|
|
423
|
+
for (const file of files) {
|
|
424
|
+
const parts = file.split("/");
|
|
425
|
+
for (let depth = 1;depth < parts.length; depth++) {
|
|
426
|
+
found.add(`${parts.slice(0, depth).join("/")}/`);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
return [...found].sort();
|
|
430
|
+
}
|
|
431
|
+
async log(ref, count) {
|
|
432
|
+
const { code, stdout } = await this.run(this.root, "log", `-${count}`, "--name-only", "--format=%x1e%H%x1f%aI%x1f%an%x1f%s", ref, "--");
|
|
433
|
+
if (code !== 0) {
|
|
434
|
+
return [];
|
|
435
|
+
}
|
|
436
|
+
return stdout.split("\x1E").filter((record) => record.trim() !== "").map((record) => {
|
|
437
|
+
const [head = "", ...files] = record.trim().split(`
|
|
438
|
+
`);
|
|
439
|
+
const [hash = "", at = "", author = "", subject = ""] = head.split("\x1F");
|
|
440
|
+
return {
|
|
441
|
+
hash,
|
|
442
|
+
at,
|
|
443
|
+
author,
|
|
444
|
+
subject,
|
|
445
|
+
files: files.filter((file) => file !== "")
|
|
446
|
+
};
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
async files(ref) {
|
|
450
|
+
const { code, stdout } = await this.run(this.root, "ls-tree", "-r", "--name-only", ref);
|
|
451
|
+
return code === 0 ? lines(stdout) : [];
|
|
452
|
+
}
|
|
453
|
+
rebase(cwd, onto) {
|
|
454
|
+
return this.run(cwd, "rebase", onto);
|
|
455
|
+
}
|
|
456
|
+
resetHard(cwd, commit) {
|
|
457
|
+
return this.run(cwd, "reset", "--hard", commit);
|
|
458
|
+
}
|
|
459
|
+
checkout(branch) {
|
|
460
|
+
return this.run(this.root, "checkout", branch);
|
|
461
|
+
}
|
|
462
|
+
mergeFfOnly(cwd, branch) {
|
|
463
|
+
return this.run(cwd, "merge", "--ff-only", branch);
|
|
464
|
+
}
|
|
465
|
+
async worktreeFor(branch) {
|
|
466
|
+
const listing = await this.out(this.root, "worktree", "list", "--porcelain");
|
|
467
|
+
let path = null;
|
|
468
|
+
for (const line of listing.split(`
|
|
469
|
+
`)) {
|
|
470
|
+
if (line.startsWith("worktree ")) {
|
|
471
|
+
path = line.slice("worktree ".length);
|
|
472
|
+
} else if (line === `branch refs/heads/${branch}`) {
|
|
473
|
+
return path;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
return null;
|
|
477
|
+
}
|
|
478
|
+
addWorktree(branch, path, from) {
|
|
479
|
+
return this.run(this.root, "worktree", "add", "-b", branch, path, from);
|
|
480
|
+
}
|
|
481
|
+
removeWorktree(path) {
|
|
482
|
+
return this.run(this.root, "worktree", "remove", path, "--force");
|
|
483
|
+
}
|
|
484
|
+
pruneWorktrees() {
|
|
485
|
+
return this.run(this.root, "worktree", "prune");
|
|
486
|
+
}
|
|
487
|
+
deleteBranch(branch) {
|
|
488
|
+
return this.run(this.root, "branch", "-D", branch);
|
|
489
|
+
}
|
|
490
|
+
commonDir() {
|
|
491
|
+
return this.out(this.root, "rev-parse", "--path-format=absolute", "--git-common-dir");
|
|
492
|
+
}
|
|
493
|
+
async worktreeGitDir(worktree) {
|
|
494
|
+
const raw = await this.fs.read(`${worktree}/.git`).catch(() => null);
|
|
495
|
+
return raw?.trim().replace(/^gitdir:\s*/, "") ?? null;
|
|
496
|
+
}
|
|
497
|
+
async interruptedOps(worktree) {
|
|
498
|
+
const dir = await this.worktreeGitDir(worktree);
|
|
499
|
+
if (dir === null) {
|
|
500
|
+
return [];
|
|
501
|
+
}
|
|
502
|
+
const checks = [
|
|
503
|
+
["rebase-merge", "rebase in progress"],
|
|
504
|
+
["rebase-apply", "rebase in progress"],
|
|
505
|
+
["MERGE_HEAD", "merge in progress"],
|
|
506
|
+
["CHERRY_PICK_HEAD", "cherry-pick in progress"]
|
|
507
|
+
];
|
|
508
|
+
const found = [];
|
|
509
|
+
for (const [entry, description] of checks) {
|
|
510
|
+
if (await this.fs.exists(`${dir}/${entry}`)) {
|
|
511
|
+
found.push(description);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
return [...new Set(found)];
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
function lines(out) {
|
|
518
|
+
return out === "" ? [] : out.split(`
|
|
519
|
+
`);
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
// load-config.ts
|
|
523
|
+
var CONFIG_FILE = "splates.config.ts";
|
|
524
|
+
async function loadConfig(root, opts = {}) {
|
|
525
|
+
const found = await new ConfigFiles(opts.fs).read(root);
|
|
526
|
+
const trunk = found.trunk ?? await (opts.git ?? new Git(root)).defaultBranch() ?? "main";
|
|
527
|
+
return { ...defaults(root, trunk), ...found };
|
|
528
|
+
}
|
|
529
|
+
function defaults(root, trunk) {
|
|
530
|
+
return {
|
|
531
|
+
trunk,
|
|
532
|
+
worktreeRoot: resolve3(root, "..", `${basename3(root)}-splates.noindex`),
|
|
533
|
+
postCheckout: null,
|
|
534
|
+
postRewrite: null,
|
|
535
|
+
preMerge: null,
|
|
536
|
+
leaseStalenessMs: 90000,
|
|
537
|
+
agentsPerAgent: 15,
|
|
538
|
+
mergeRetryCount: 3,
|
|
539
|
+
removedCapacity: 50,
|
|
540
|
+
logCapacity: 1000,
|
|
541
|
+
todoStalenessMs: 30 * 24 * 60 * 60 * 1000,
|
|
542
|
+
attachmentCapacity: 100 * 1024 * 1024,
|
|
543
|
+
artifactFileCapacity: ARTIFACT_LIMITS.file,
|
|
544
|
+
artifactConversationCapacity: ARTIFACT_LIMITS.conversation,
|
|
545
|
+
artifactProjectCapacity: ARTIFACT_LIMITS.project,
|
|
546
|
+
wiz: "bunx @webappwiz/cli",
|
|
547
|
+
tunnel: null
|
|
548
|
+
};
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
class ConfigFiles {
|
|
552
|
+
fs;
|
|
553
|
+
constructor(fs = new NodeFs2) {
|
|
554
|
+
this.fs = fs;
|
|
555
|
+
}
|
|
556
|
+
async read(root) {
|
|
557
|
+
const { systems: _, ...config } = await this.importConfig(root);
|
|
558
|
+
return config;
|
|
559
|
+
}
|
|
560
|
+
importConfig(root) {
|
|
561
|
+
return this.importDefault(root, CONFIG_FILE);
|
|
562
|
+
}
|
|
563
|
+
async found(root, file) {
|
|
564
|
+
const path = `${root}/${file}`;
|
|
565
|
+
if (await this.fs.exists(path)) {
|
|
566
|
+
return path;
|
|
567
|
+
}
|
|
568
|
+
const old = legacyFile(file);
|
|
569
|
+
if (old === null || !await this.fs.exists(`${root}/${old}`)) {
|
|
570
|
+
return null;
|
|
571
|
+
}
|
|
572
|
+
legacyWarnings.once(old, `${file}: run \`splates update\``);
|
|
573
|
+
return `${root}/${old}`;
|
|
574
|
+
}
|
|
575
|
+
async importDefault(root, file) {
|
|
576
|
+
const path = await this.found(root, file);
|
|
577
|
+
if (path === null) {
|
|
578
|
+
return {};
|
|
579
|
+
}
|
|
580
|
+
const version = Bun.hash(await this.fs.read(path)).toString(36);
|
|
581
|
+
const real = await realpath(path).catch(() => path);
|
|
582
|
+
const mod = await import(`${real}?v=${version}`).catch((cause) => {
|
|
583
|
+
throw new Error(`could not load ${path}: ${cause}. Its imports may be stale: try \`bun install\` in ${root}.`, { cause });
|
|
584
|
+
});
|
|
585
|
+
return mod.default ?? {};
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
// systems.ts
|
|
590
|
+
var SYSTEMS_FILE2 = "splates.systems.ts";
|
|
591
|
+
|
|
592
|
+
class Systems2 {
|
|
593
|
+
named;
|
|
594
|
+
glob;
|
|
595
|
+
constructor(named, glob) {
|
|
596
|
+
this.named = named;
|
|
597
|
+
this.glob = glob;
|
|
598
|
+
}
|
|
599
|
+
static async at(root, opts = {}) {
|
|
600
|
+
return Systems2.of(await readSystems2(root, opts.fs), opts.glob);
|
|
601
|
+
}
|
|
602
|
+
static of(systems, glob = new NodeGlob) {
|
|
603
|
+
return new Systems2(Object.entries(systems).map(([name, system]) => ({ name, ...system })), glob);
|
|
604
|
+
}
|
|
605
|
+
all() {
|
|
606
|
+
return this.named;
|
|
607
|
+
}
|
|
608
|
+
find(name) {
|
|
609
|
+
return this.named.find((system) => system.name === name || (system.aliases ?? []).includes(name)) ?? null;
|
|
610
|
+
}
|
|
611
|
+
touchedBy(paths) {
|
|
612
|
+
return this.named.filter((system) => paths.some((path) => this.contains(system, path)));
|
|
613
|
+
}
|
|
614
|
+
within(system, paths) {
|
|
615
|
+
return paths.filter((path) => this.contains(system, path));
|
|
616
|
+
}
|
|
617
|
+
unmatched(system, paths) {
|
|
618
|
+
return system.globs.filter((pattern) => !paths.some((path) => this.glob.matches(pattern, path)));
|
|
619
|
+
}
|
|
620
|
+
mentioned(text) {
|
|
621
|
+
const found = [];
|
|
622
|
+
for (const [, , called = ""] of text.matchAll(MENTION)) {
|
|
623
|
+
const system = this.find(called);
|
|
624
|
+
if (system !== null && !found.includes(system)) {
|
|
625
|
+
found.push(system);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
return found;
|
|
629
|
+
}
|
|
630
|
+
unknown(text) {
|
|
631
|
+
return hashed2(text).filter((called) => !/^\d+$/.test(called) && this.find(called) === null);
|
|
632
|
+
}
|
|
633
|
+
contains(system, path) {
|
|
634
|
+
const matches = (pattern) => this.glob.matches(pattern, path);
|
|
635
|
+
return system.globs.some(matches) && !(system.ignore ?? []).some(matches);
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
var MENTION = /(^|\s)#([^\s#]*[^\s#.,;:!?)\]'"-])/g;
|
|
639
|
+
function hashed2(text) {
|
|
640
|
+
const prose = text.replace(/```[\s\S]*?(```|$)|`[^`\n]*`/g, " ");
|
|
641
|
+
const found = [];
|
|
642
|
+
for (const [, , called = ""] of prose.matchAll(MENTION)) {
|
|
643
|
+
if (!found.includes(called)) {
|
|
644
|
+
found.push(called);
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
return found;
|
|
648
|
+
}
|
|
649
|
+
function mentionLine2(system) {
|
|
650
|
+
const aliases = system.aliases ?? [];
|
|
651
|
+
const ignore = system.ignore ?? [];
|
|
652
|
+
return [
|
|
653
|
+
`#${system.name}`,
|
|
654
|
+
aliases.length > 0 ? ` (${aliases.join(", ")})` : "",
|
|
655
|
+
": ",
|
|
656
|
+
system.description === undefined ? "" : `${system.description.replace(/\.$/, "")}. Made of `,
|
|
657
|
+
system.globs.join(", "),
|
|
658
|
+
ignore.length > 0 ? `; not ${ignore.join(", ")}` : ""
|
|
659
|
+
].join("");
|
|
660
|
+
}
|
|
661
|
+
function unknownLine2(name) {
|
|
662
|
+
return `#${name} names no system: find the code it means, and offer to name it as the splates skill's Systems section says.`;
|
|
663
|
+
}
|
|
664
|
+
var DESCRIPTION_MAX2 = 80;
|
|
665
|
+
var SYSTEMS = z.record(z.string().min(1), z.strictObject({
|
|
666
|
+
description: z.string().min(1).max(DESCRIPTION_MAX2).refine((text) => !text.includes(`
|
|
667
|
+
`), "must be one line").optional(),
|
|
668
|
+
aliases: z.array(z.string().min(1)).max(2).optional(),
|
|
669
|
+
globs: z.array(z.string().min(1)).min(1),
|
|
670
|
+
ignore: z.array(z.string().min(1)).optional()
|
|
671
|
+
}));
|
|
672
|
+
async function readSystems2(root, fs = new NodeFs3) {
|
|
673
|
+
const files = new ConfigFiles(fs);
|
|
674
|
+
if ((await files.importConfig(root)).systems !== undefined) {
|
|
675
|
+
throw new Error(`${root}/${CONFIG_FILE} names systems, which splates now reads from ${SYSTEMS_FILE2}: run \`splates update\` to move them`);
|
|
676
|
+
}
|
|
677
|
+
return checkSystems2(`${root}/${SYSTEMS_FILE2}`, await files.importDefault(root, SYSTEMS_FILE2));
|
|
678
|
+
}
|
|
679
|
+
function checkSystems2(path, systems) {
|
|
680
|
+
const parsed = SYSTEMS.safeParse(systems);
|
|
681
|
+
if (!parsed.success) {
|
|
682
|
+
const issue = parsed.error.issues[0];
|
|
683
|
+
throw new Error(`${path}: ${issue?.path.join(".")}: ${issue?.message}`);
|
|
684
|
+
}
|
|
685
|
+
const owners = new Map;
|
|
686
|
+
for (const [name, system] of Object.entries(parsed.data)) {
|
|
687
|
+
for (const called of [name, ...system.aliases ?? []]) {
|
|
688
|
+
const owner = owners.get(called);
|
|
689
|
+
if (owner !== undefined) {
|
|
690
|
+
throw new Error(`${path}: systems '${owner}' and '${name}' both answer to '${called}': give each its own names`);
|
|
691
|
+
}
|
|
692
|
+
owners.set(called, name);
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
return parsed.data;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
export { Attachments, readFiles, folderBytes, Artifacts, ARTIFACT_LIMITS, artifactLimits, applyArtifact, shown, projectBytes, tooLarge, Git, CONFIG_FILE, loadConfig, ConfigFiles, SYSTEMS_FILE2, Systems2, hashed2, mentionLine2, unknownLine2, DESCRIPTION_MAX2, readSystems2, checkSystems2 };
|