zelari-code 1.42.0 → 1.43.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/dist/cli/main.bundled.js +1096 -680
- package/dist/cli/main.bundled.js.map +4 -4
- package/dist/cli/runHeadless.js +15 -0
- package/dist/cli/runHeadless.js.map +1 -1
- package/dist/cli/toolRegistry.js +16 -0
- package/dist/cli/toolRegistry.js.map +1 -1
- package/dist/cli/tools/planTaskTools.js +236 -0
- package/dist/cli/tools/planTaskTools.js.map +1 -0
- package/dist/cli/workspace/planStore.js +213 -0
- package/dist/cli/workspace/planStore.js.map +1 -0
- package/dist/cli/workspace/planStore.test.js +295 -0
- package/dist/cli/workspace/planStore.test.js.map +1 -0
- package/dist/cli/workspace/stubs.js +14 -4
- package/dist/cli/workspace/stubs.js.map +1 -1
- package/dist/cli/workspace/workspaceSummary.js +7 -1
- package/dist/cli/workspace/workspaceSummary.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/main.bundled.js
CHANGED
|
@@ -21063,6 +21063,12 @@ function isBrainMemberCostEvent(e) {
|
|
|
21063
21063
|
function isBrainCouncilModeEvent(e) {
|
|
21064
21064
|
return e.type === "council_mode";
|
|
21065
21065
|
}
|
|
21066
|
+
function isBrainTaskUpdateEvent(e) {
|
|
21067
|
+
return e.type === "task_update";
|
|
21068
|
+
}
|
|
21069
|
+
function isBrainTaskSnapshotEvent(e) {
|
|
21070
|
+
return e.type === "task_snapshot";
|
|
21071
|
+
}
|
|
21066
21072
|
function createBrainEvent(type, sessionId, data) {
|
|
21067
21073
|
return {
|
|
21068
21074
|
type,
|
|
@@ -28073,6 +28079,8 @@ __export(dist_exports, {
|
|
|
28073
28079
|
isBrainMessageStartEvent: () => isBrainMessageStartEvent,
|
|
28074
28080
|
isBrainQueueUpdateEvent: () => isBrainQueueUpdateEvent,
|
|
28075
28081
|
isBrainSessionCompactedEvent: () => isBrainSessionCompactedEvent,
|
|
28082
|
+
isBrainTaskSnapshotEvent: () => isBrainTaskSnapshotEvent,
|
|
28083
|
+
isBrainTaskUpdateEvent: () => isBrainTaskUpdateEvent,
|
|
28076
28084
|
isBrainThinkingDeltaEvent: () => isBrainThinkingDeltaEvent,
|
|
28077
28085
|
isBrainToolExecutionEndEvent: () => isBrainToolExecutionEndEvent,
|
|
28078
28086
|
isBrainToolExecutionStartEvent: () => isBrainToolExecutionStartEvent,
|
|
@@ -31026,6 +31034,771 @@ var init_todoTools = __esm({
|
|
|
31026
31034
|
}
|
|
31027
31035
|
});
|
|
31028
31036
|
|
|
31037
|
+
// src/cli/workspace/paths.ts
|
|
31038
|
+
import {
|
|
31039
|
+
mkdirSync as mkdirSync10,
|
|
31040
|
+
writeFileSync as writeFileSync12,
|
|
31041
|
+
existsSync as existsSync17,
|
|
31042
|
+
accessSync,
|
|
31043
|
+
constants,
|
|
31044
|
+
realpathSync
|
|
31045
|
+
} from "node:fs";
|
|
31046
|
+
import { join as join13, basename } from "node:path";
|
|
31047
|
+
import { homedir as homedir5 } from "node:os";
|
|
31048
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
31049
|
+
function resolveWorkspaceRoot(projectRoot = process.cwd()) {
|
|
31050
|
+
const candidates = [
|
|
31051
|
+
join13(projectRoot, ".zelari"),
|
|
31052
|
+
join13(homedir5(), ".zelari-code", "workspace", hashProject(projectRoot))
|
|
31053
|
+
];
|
|
31054
|
+
for (const candidate of candidates) {
|
|
31055
|
+
if (isWritableDir(projectRoot) || candidate !== candidates[0]) {
|
|
31056
|
+
ensureWorkspaceDir(candidate);
|
|
31057
|
+
return candidate;
|
|
31058
|
+
}
|
|
31059
|
+
}
|
|
31060
|
+
ensureWorkspaceDir(candidates[0]);
|
|
31061
|
+
return candidates[0];
|
|
31062
|
+
}
|
|
31063
|
+
function hashProject(projectPath) {
|
|
31064
|
+
return createHash4("sha1").update(realpathSync(projectPath)).digest("hex").slice(0, 12);
|
|
31065
|
+
}
|
|
31066
|
+
function isWritableDir(dir) {
|
|
31067
|
+
try {
|
|
31068
|
+
if (!existsSync17(dir)) return false;
|
|
31069
|
+
accessSync(dir, constants.W_OK);
|
|
31070
|
+
return true;
|
|
31071
|
+
} catch {
|
|
31072
|
+
return false;
|
|
31073
|
+
}
|
|
31074
|
+
}
|
|
31075
|
+
function ensureWorkspaceDir(workspaceDir) {
|
|
31076
|
+
mkdirSync10(workspaceDir, { recursive: true });
|
|
31077
|
+
if (workspaceDir.endsWith("/.zelari") && existsSync17(join13(workspaceDir, "..", ".git"))) {
|
|
31078
|
+
const gitignorePath = join13(workspaceDir, ".gitignore");
|
|
31079
|
+
if (!existsSync17(gitignorePath)) {
|
|
31080
|
+
writeFileSync12(gitignorePath, "*\n!.gitignore\n");
|
|
31081
|
+
}
|
|
31082
|
+
}
|
|
31083
|
+
}
|
|
31084
|
+
function workspaceFile(rootDir, kind) {
|
|
31085
|
+
switch (kind) {
|
|
31086
|
+
case "plan":
|
|
31087
|
+
return join13(rootDir, "plan.md");
|
|
31088
|
+
case "risks":
|
|
31089
|
+
return join13(rootDir, "risks.md");
|
|
31090
|
+
case "index":
|
|
31091
|
+
return join13(rootDir, "workspace.json");
|
|
31092
|
+
}
|
|
31093
|
+
}
|
|
31094
|
+
function workspaceArtifact(rootDir, subdir, slug) {
|
|
31095
|
+
return join13(rootDir, subdir, `${slug}.md`);
|
|
31096
|
+
}
|
|
31097
|
+
function projectName(projectRoot = process.cwd()) {
|
|
31098
|
+
return basename(realpathSync(projectRoot));
|
|
31099
|
+
}
|
|
31100
|
+
var init_paths2 = __esm({
|
|
31101
|
+
"src/cli/workspace/paths.ts"() {
|
|
31102
|
+
"use strict";
|
|
31103
|
+
}
|
|
31104
|
+
});
|
|
31105
|
+
|
|
31106
|
+
// src/cli/workspace/storage.ts
|
|
31107
|
+
var storage_exports = {};
|
|
31108
|
+
__export(storage_exports, {
|
|
31109
|
+
Storage: () => Storage,
|
|
31110
|
+
parseFrontmatter: () => parseFrontmatter,
|
|
31111
|
+
parseYaml: () => parseYaml,
|
|
31112
|
+
serializeFrontmatter: () => serializeFrontmatter,
|
|
31113
|
+
serializeYaml: () => serializeYaml,
|
|
31114
|
+
workspaceMutex: () => workspaceMutex
|
|
31115
|
+
});
|
|
31116
|
+
import {
|
|
31117
|
+
readFileSync as readFileSync16,
|
|
31118
|
+
writeFileSync as writeFileSync13,
|
|
31119
|
+
existsSync as existsSync18,
|
|
31120
|
+
mkdirSync as mkdirSync11,
|
|
31121
|
+
readdirSync as readdirSync4,
|
|
31122
|
+
renameSync as renameSync2
|
|
31123
|
+
} from "node:fs";
|
|
31124
|
+
import { dirname as dirname2, join as join14 } from "node:path";
|
|
31125
|
+
function parseFrontmatter(md) {
|
|
31126
|
+
const m = FRONTMATTER_RE.exec(md);
|
|
31127
|
+
if (!m) return { meta: {}, body: md };
|
|
31128
|
+
const meta3 = parseYaml(m[1]);
|
|
31129
|
+
const body = m[2];
|
|
31130
|
+
return { meta: meta3, body };
|
|
31131
|
+
}
|
|
31132
|
+
function serializeFrontmatter(meta3, body) {
|
|
31133
|
+
const yamlStr = serializeYaml(meta3);
|
|
31134
|
+
return `---
|
|
31135
|
+
${yamlStr}
|
|
31136
|
+
---
|
|
31137
|
+
${body}`;
|
|
31138
|
+
}
|
|
31139
|
+
function parseYaml(input) {
|
|
31140
|
+
const lines = input.split(/\r?\n/);
|
|
31141
|
+
const ctx = { lines, i: 0 };
|
|
31142
|
+
return parseNode(ctx, 0);
|
|
31143
|
+
}
|
|
31144
|
+
function parseNode(ctx, indent) {
|
|
31145
|
+
while (ctx.i < ctx.lines.length) {
|
|
31146
|
+
const line2 = ctx.lines[ctx.i];
|
|
31147
|
+
if (line2.trim() === "" || line2.trim().startsWith("#")) {
|
|
31148
|
+
ctx.i++;
|
|
31149
|
+
continue;
|
|
31150
|
+
}
|
|
31151
|
+
break;
|
|
31152
|
+
}
|
|
31153
|
+
if (ctx.i >= ctx.lines.length) return null;
|
|
31154
|
+
const line = ctx.lines[ctx.i];
|
|
31155
|
+
const lineIndent = countIndent(line);
|
|
31156
|
+
if (/^\s*-\s+/.test(line)) {
|
|
31157
|
+
return parseBlockSequence(ctx, indent);
|
|
31158
|
+
}
|
|
31159
|
+
if (/^\s*\[.*\]\s*$/.test(line)) {
|
|
31160
|
+
const flow = line.trim().replace(/^\[/, "").replace(/\]$/, "");
|
|
31161
|
+
return parseFlowSequence(flow);
|
|
31162
|
+
}
|
|
31163
|
+
if (/^\s*\{.*\}\s*$/.test(line)) {
|
|
31164
|
+
const flow = line.trim().replace(/^\{/, "").replace(/\}$/, "");
|
|
31165
|
+
return parseFlowMap(flow);
|
|
31166
|
+
}
|
|
31167
|
+
return parseBlockMap(ctx, indent);
|
|
31168
|
+
}
|
|
31169
|
+
function parseBlockMap(ctx, indent) {
|
|
31170
|
+
const out = {};
|
|
31171
|
+
while (ctx.i < ctx.lines.length) {
|
|
31172
|
+
const line = ctx.lines[ctx.i];
|
|
31173
|
+
if (line.trim() === "" || line.trim().startsWith("#")) {
|
|
31174
|
+
ctx.i++;
|
|
31175
|
+
continue;
|
|
31176
|
+
}
|
|
31177
|
+
const lineIndent = countIndent(line);
|
|
31178
|
+
if (lineIndent < indent) break;
|
|
31179
|
+
if (lineIndent > indent) {
|
|
31180
|
+
ctx.i++;
|
|
31181
|
+
continue;
|
|
31182
|
+
}
|
|
31183
|
+
const m = /^([^:]+):\s*(.*)$/.exec(line);
|
|
31184
|
+
if (!m) {
|
|
31185
|
+
ctx.i++;
|
|
31186
|
+
continue;
|
|
31187
|
+
}
|
|
31188
|
+
const key = m[1].trim();
|
|
31189
|
+
const valuePart = m[2].trim();
|
|
31190
|
+
if (valuePart === "" || valuePart === "|" || valuePart === ">") {
|
|
31191
|
+
ctx.i++;
|
|
31192
|
+
const nested = parseNode(ctx, indent + 2);
|
|
31193
|
+
out[key] = nested;
|
|
31194
|
+
} else {
|
|
31195
|
+
if (valuePart.startsWith("[")) {
|
|
31196
|
+
out[key] = parseFlowSequence(stripFlow(valuePart, "[", "]"));
|
|
31197
|
+
} else if (valuePart.startsWith("{")) {
|
|
31198
|
+
out[key] = parseFlowMap(stripFlow(valuePart, "{", "}"));
|
|
31199
|
+
} else {
|
|
31200
|
+
out[key] = parseScalar(valuePart);
|
|
31201
|
+
}
|
|
31202
|
+
ctx.i++;
|
|
31203
|
+
}
|
|
31204
|
+
}
|
|
31205
|
+
return out;
|
|
31206
|
+
}
|
|
31207
|
+
function parseBlockSequence(ctx, indent) {
|
|
31208
|
+
const out = [];
|
|
31209
|
+
while (ctx.i < ctx.lines.length) {
|
|
31210
|
+
const line = ctx.lines[ctx.i];
|
|
31211
|
+
if (line.trim() === "") {
|
|
31212
|
+
ctx.i++;
|
|
31213
|
+
continue;
|
|
31214
|
+
}
|
|
31215
|
+
const lineIndent = countIndent(line);
|
|
31216
|
+
if (lineIndent < indent) break;
|
|
31217
|
+
if (lineIndent > indent) break;
|
|
31218
|
+
const m = /^-\s*(.*)$/.exec(line);
|
|
31219
|
+
if (!m) break;
|
|
31220
|
+
const rest = m[1];
|
|
31221
|
+
if (rest === "") {
|
|
31222
|
+
ctx.i++;
|
|
31223
|
+
out.push(parseNode(ctx, indent + 2));
|
|
31224
|
+
} else if (rest.startsWith("[") || rest.startsWith("{")) {
|
|
31225
|
+
let buffer = rest;
|
|
31226
|
+
let depthSq = (buffer.match(/\[/g) || []).length - (buffer.match(/\]/g) || []).length;
|
|
31227
|
+
let depthCu = (buffer.match(/\{/g) || []).length - (buffer.match(/\}/g) || []).length;
|
|
31228
|
+
while ((depthSq > 0 || depthCu > 0) && ctx.i + 1 < ctx.lines.length) {
|
|
31229
|
+
ctx.i++;
|
|
31230
|
+
const next = ctx.lines[ctx.i].trim();
|
|
31231
|
+
buffer += " " + next;
|
|
31232
|
+
depthSq = (buffer.match(/\[/g) || []).length - (buffer.match(/\]/g) || []).length;
|
|
31233
|
+
depthCu = (buffer.match(/\{/g) || []).length - (buffer.match(/\}/g) || []).length;
|
|
31234
|
+
}
|
|
31235
|
+
if (buffer.startsWith("[")) {
|
|
31236
|
+
out.push(parseFlowSequence(buffer.slice(1).replace(/\]$/, "")));
|
|
31237
|
+
} else {
|
|
31238
|
+
out.push(parseFlowMap(buffer.slice(1).replace(/\}$/, "")));
|
|
31239
|
+
}
|
|
31240
|
+
ctx.i++;
|
|
31241
|
+
} else if (rest.includes(":")) {
|
|
31242
|
+
ctx.i++;
|
|
31243
|
+
const mapCtx = { lines: [" ".repeat(indent + 2) + rest, ...ctx.lines.slice(ctx.i)], i: 0 };
|
|
31244
|
+
const val = parseBlockMap(mapCtx, indent + 2);
|
|
31245
|
+
ctx.i += mapCtx.i - 1;
|
|
31246
|
+
out.push(val);
|
|
31247
|
+
} else {
|
|
31248
|
+
out.push(parseScalar(rest));
|
|
31249
|
+
ctx.i++;
|
|
31250
|
+
}
|
|
31251
|
+
}
|
|
31252
|
+
return out;
|
|
31253
|
+
}
|
|
31254
|
+
function parseFlowSequence(input) {
|
|
31255
|
+
const parts = splitFlow(input);
|
|
31256
|
+
return parts.map((p3) => {
|
|
31257
|
+
const trimmed = p3.trim();
|
|
31258
|
+
if (trimmed.startsWith("{")) {
|
|
31259
|
+
return parseFlowMap(stripFlow(trimmed, "{", "}"));
|
|
31260
|
+
}
|
|
31261
|
+
return parseScalar(trimmed);
|
|
31262
|
+
});
|
|
31263
|
+
}
|
|
31264
|
+
function stripFlow(s, open, close) {
|
|
31265
|
+
let out = s.trim();
|
|
31266
|
+
if (out.startsWith(open)) out = out.slice(1);
|
|
31267
|
+
if (out.endsWith(close)) out = out.slice(0, -1);
|
|
31268
|
+
return out;
|
|
31269
|
+
}
|
|
31270
|
+
function parseFlowMap(input) {
|
|
31271
|
+
const parts = splitFlow(input);
|
|
31272
|
+
const out = {};
|
|
31273
|
+
for (const p3 of parts) {
|
|
31274
|
+
const colonIdx = p3.indexOf(":");
|
|
31275
|
+
if (colonIdx < 0) continue;
|
|
31276
|
+
const key = p3.slice(0, colonIdx).trim();
|
|
31277
|
+
const value = p3.slice(colonIdx + 1).trim();
|
|
31278
|
+
out[key] = parseScalar(value);
|
|
31279
|
+
}
|
|
31280
|
+
return out;
|
|
31281
|
+
}
|
|
31282
|
+
function splitFlow(input) {
|
|
31283
|
+
const out = [];
|
|
31284
|
+
let depthSq = 0, depthCu = 0, depthQu = 0;
|
|
31285
|
+
let buffer = "";
|
|
31286
|
+
for (let i = 0; i < input.length; i++) {
|
|
31287
|
+
const c = input[i];
|
|
31288
|
+
if (c === '"' || c === "'") {
|
|
31289
|
+
depthQu = depthQu === 0 ? depthQu + 1 : 0;
|
|
31290
|
+
buffer += c;
|
|
31291
|
+
} else if (depthQu === 0) {
|
|
31292
|
+
if (c === "[") depthSq++;
|
|
31293
|
+
else if (c === "]") depthSq--;
|
|
31294
|
+
else if (c === "{") depthCu++;
|
|
31295
|
+
else if (c === "}") depthCu--;
|
|
31296
|
+
else if (c === "," && depthSq === 0 && depthCu === 0) {
|
|
31297
|
+
out.push(buffer);
|
|
31298
|
+
buffer = "";
|
|
31299
|
+
continue;
|
|
31300
|
+
}
|
|
31301
|
+
buffer += c;
|
|
31302
|
+
} else {
|
|
31303
|
+
buffer += c;
|
|
31304
|
+
}
|
|
31305
|
+
}
|
|
31306
|
+
if (buffer.trim()) out.push(buffer);
|
|
31307
|
+
return out;
|
|
31308
|
+
}
|
|
31309
|
+
function parseScalar(s) {
|
|
31310
|
+
if (s === "" || s === "null" || s === "~") return null;
|
|
31311
|
+
if (VALID_SCALARS.test(s)) return s.toLowerCase() === "true";
|
|
31312
|
+
if (/^-?\d+(\.\d+)?$/.test(s)) return Number(s);
|
|
31313
|
+
if (s.startsWith('"') && s.endsWith('"') || s.startsWith("'") && s.endsWith("'")) {
|
|
31314
|
+
return s.slice(1, -1);
|
|
31315
|
+
}
|
|
31316
|
+
return s;
|
|
31317
|
+
}
|
|
31318
|
+
function serializeYaml(value, indent = 0) {
|
|
31319
|
+
if (value === null || value === void 0) return "";
|
|
31320
|
+
if (typeof value === "string") {
|
|
31321
|
+
if (/[:#\n\[\]\{\},&*!|>'"%@`]/.test(value)) {
|
|
31322
|
+
return JSON.stringify(value);
|
|
31323
|
+
}
|
|
31324
|
+
return value;
|
|
31325
|
+
}
|
|
31326
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
31327
|
+
if (Array.isArray(value)) {
|
|
31328
|
+
if (value.length === 0) return "[]";
|
|
31329
|
+
if (value.every((v) => v === null || typeof v !== "object")) {
|
|
31330
|
+
return `[${value.map(serializeScalarInline).join(", ")}]`;
|
|
31331
|
+
}
|
|
31332
|
+
return `[${value.map((v) => "{" + serializeInlineObject(v) + "}").join(", ")}]`;
|
|
31333
|
+
}
|
|
31334
|
+
if (typeof value === "object") {
|
|
31335
|
+
const entries = Object.entries(value).filter(([, v]) => v !== void 0);
|
|
31336
|
+
return entries.map(([k, v]) => {
|
|
31337
|
+
if (v === null || v === void 0) return `${k}:`;
|
|
31338
|
+
if (typeof v === "string" || typeof v === "number" || typeof v === "boolean") {
|
|
31339
|
+
return `${k}: ${serializeScalarInline(v)}`;
|
|
31340
|
+
}
|
|
31341
|
+
if (Array.isArray(v)) {
|
|
31342
|
+
if (v.length === 0) return `${k}: []`;
|
|
31343
|
+
if (v.every((x) => x === null || typeof x !== "object")) {
|
|
31344
|
+
return `${k}: [${v.map(serializeScalarInline).join(", ")}]`;
|
|
31345
|
+
}
|
|
31346
|
+
return `${k}: [${v.map((x) => "{" + serializeInlineObject(x) + "}").join(", ")}]`;
|
|
31347
|
+
}
|
|
31348
|
+
return `${k}:
|
|
31349
|
+
${serializeYaml(v, indent + 2)}`;
|
|
31350
|
+
}).map((line) => `${" ".repeat(indent)}${line}`).join("\n");
|
|
31351
|
+
}
|
|
31352
|
+
return String(value);
|
|
31353
|
+
}
|
|
31354
|
+
function serializeScalarInline(v) {
|
|
31355
|
+
if (typeof v === "string" && /[:#\n\[\]\{\},&*!|>'"%@`]/.test(v)) return JSON.stringify(v);
|
|
31356
|
+
return String(v);
|
|
31357
|
+
}
|
|
31358
|
+
function serializeInlineObject(v) {
|
|
31359
|
+
if (v === null || typeof v !== "object" || Array.isArray(v)) {
|
|
31360
|
+
return serializeScalarInline(v);
|
|
31361
|
+
}
|
|
31362
|
+
const entries = Object.entries(v).filter(([, val]) => val !== void 0);
|
|
31363
|
+
return entries.map(([k, val]) => `${k}: ${serializeYaml(val)}`).join(", ");
|
|
31364
|
+
}
|
|
31365
|
+
function countIndent(line) {
|
|
31366
|
+
let i = 0;
|
|
31367
|
+
while (i < line.length && line[i] === " ") i++;
|
|
31368
|
+
return i;
|
|
31369
|
+
}
|
|
31370
|
+
var FRONTMATTER_RE, VALID_SCALARS, Storage, KeyedMutex, workspaceMutex;
|
|
31371
|
+
var init_storage = __esm({
|
|
31372
|
+
"src/cli/workspace/storage.ts"() {
|
|
31373
|
+
"use strict";
|
|
31374
|
+
FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/;
|
|
31375
|
+
VALID_SCALARS = /^(true|false|null|~)$/i;
|
|
31376
|
+
Storage = class {
|
|
31377
|
+
/** Read a Markdown file with frontmatter. Throws if not found. */
|
|
31378
|
+
read(path53) {
|
|
31379
|
+
if (!existsSync18(path53)) {
|
|
31380
|
+
throw new Error(`File not found: ${path53}`);
|
|
31381
|
+
}
|
|
31382
|
+
const md = readFileSync16(path53, "utf8");
|
|
31383
|
+
return parseFrontmatter(md);
|
|
31384
|
+
}
|
|
31385
|
+
/** Read a Markdown file; returns null if not found. */
|
|
31386
|
+
readIfExists(path53) {
|
|
31387
|
+
if (!existsSync18(path53)) return null;
|
|
31388
|
+
return this.read(path53);
|
|
31389
|
+
}
|
|
31390
|
+
/**
|
|
31391
|
+
* Write a Markdown file atomically (tmp + rename). Creates parent dirs.
|
|
31392
|
+
* The meta object is serialized as YAML frontmatter; body as Markdown.
|
|
31393
|
+
*/
|
|
31394
|
+
write(path53, meta3, body) {
|
|
31395
|
+
mkdirSync11(dirname2(path53), { recursive: true });
|
|
31396
|
+
const tmp = path53 + ".tmp-" + process.pid;
|
|
31397
|
+
const md = serializeFrontmatter(meta3, body);
|
|
31398
|
+
writeFileSync13(tmp, md, "utf8");
|
|
31399
|
+
renameSync2(tmp, path53);
|
|
31400
|
+
}
|
|
31401
|
+
/** List all .md files in a directory (non-recursive). */
|
|
31402
|
+
listMarkdown(dir) {
|
|
31403
|
+
if (!existsSync18(dir)) return [];
|
|
31404
|
+
return readdirSync4(dir).filter((f) => f.endsWith(".md") && !f.startsWith(".")).map((f) => join14(dir, f));
|
|
31405
|
+
}
|
|
31406
|
+
};
|
|
31407
|
+
KeyedMutex = class {
|
|
31408
|
+
chains = /* @__PURE__ */ new Map();
|
|
31409
|
+
async run(key, fn) {
|
|
31410
|
+
const prev2 = this.chains.get(key) ?? Promise.resolve();
|
|
31411
|
+
let release = () => {
|
|
31412
|
+
};
|
|
31413
|
+
const next = new Promise((resolve3) => {
|
|
31414
|
+
release = resolve3;
|
|
31415
|
+
});
|
|
31416
|
+
const chained = prev2.then(() => next);
|
|
31417
|
+
this.chains.set(key, chained);
|
|
31418
|
+
await prev2;
|
|
31419
|
+
try {
|
|
31420
|
+
return await fn();
|
|
31421
|
+
} finally {
|
|
31422
|
+
release();
|
|
31423
|
+
if (this.chains.get(key) === chained) {
|
|
31424
|
+
this.chains.delete(key);
|
|
31425
|
+
}
|
|
31426
|
+
}
|
|
31427
|
+
}
|
|
31428
|
+
};
|
|
31429
|
+
workspaceMutex = new KeyedMutex();
|
|
31430
|
+
}
|
|
31431
|
+
});
|
|
31432
|
+
|
|
31433
|
+
// src/cli/workspace/planStore.ts
|
|
31434
|
+
import {
|
|
31435
|
+
copyFileSync,
|
|
31436
|
+
existsSync as existsSync19,
|
|
31437
|
+
mkdirSync as mkdirSync12,
|
|
31438
|
+
readFileSync as readFileSync17,
|
|
31439
|
+
renameSync as renameSync3,
|
|
31440
|
+
writeFileSync as writeFileSync14
|
|
31441
|
+
} from "node:fs";
|
|
31442
|
+
import { dirname as dirname3, join as join15 } from "node:path";
|
|
31443
|
+
async function withPlanStore(projectRoot, fn) {
|
|
31444
|
+
const rootDir = resolveWorkspaceRoot(projectRoot);
|
|
31445
|
+
return workspaceMutex.run(`${rootDir}:plan`, () => {
|
|
31446
|
+
const handle = loadHandle(rootDir);
|
|
31447
|
+
const out = fn(handle);
|
|
31448
|
+
saveHandle(rootDir, handle);
|
|
31449
|
+
return out;
|
|
31450
|
+
});
|
|
31451
|
+
}
|
|
31452
|
+
function nextPlanTaskId(store4) {
|
|
31453
|
+
const maxExisting = store4.tasks.reduce((max, t) => {
|
|
31454
|
+
const m = /^t(\d+)$/.exec(t.id);
|
|
31455
|
+
return m ? Math.max(max, parseInt(m[1], 10)) : max;
|
|
31456
|
+
}, 0);
|
|
31457
|
+
store4.counter = Math.max(store4.counter, maxExisting) + 1;
|
|
31458
|
+
return `t${store4.counter}`;
|
|
31459
|
+
}
|
|
31460
|
+
function writePlanTaskArtifact(rootDir, task) {
|
|
31461
|
+
const path53 = join15(rootDir, "plan-tasks", `${task.id}.md`);
|
|
31462
|
+
mkdirSync12(dirname3(path53), { recursive: true });
|
|
31463
|
+
const meta3 = {
|
|
31464
|
+
kind: "task",
|
|
31465
|
+
id: task.id,
|
|
31466
|
+
name: task.title,
|
|
31467
|
+
phaseId: task.phaseId,
|
|
31468
|
+
status: task.status,
|
|
31469
|
+
priority: task.priority ?? "medium",
|
|
31470
|
+
updatedAt: task.updatedAt
|
|
31471
|
+
};
|
|
31472
|
+
const body = [
|
|
31473
|
+
`# Task ${task.id}: ${task.title}`,
|
|
31474
|
+
"",
|
|
31475
|
+
`- Status: **${task.status}**`,
|
|
31476
|
+
`- Priority: ${task.priority ?? "medium"}`,
|
|
31477
|
+
task.phaseId ? `- Phase: ${task.phaseId}` : null,
|
|
31478
|
+
task.agent ? `- Agent: ${task.agent}` : null,
|
|
31479
|
+
"",
|
|
31480
|
+
task.notes?.trim() ? task.notes.trim() : "_(no notes)_",
|
|
31481
|
+
""
|
|
31482
|
+
].filter((l) => l !== null).join("\n");
|
|
31483
|
+
new Storage().write(path53, meta3, body);
|
|
31484
|
+
}
|
|
31485
|
+
function loadHandle(rootDir) {
|
|
31486
|
+
const jsonPath = join15(rootDir, "plan.json");
|
|
31487
|
+
if (!existsSync19(jsonPath)) {
|
|
31488
|
+
return { rootDir, tasks: [], counter: 0, rootFields: {} };
|
|
31489
|
+
}
|
|
31490
|
+
let parsed;
|
|
31491
|
+
try {
|
|
31492
|
+
const raw = JSON.parse(readFileSync17(jsonPath, "utf8"));
|
|
31493
|
+
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
|
|
31494
|
+
throw new Error("root is not a JSON object");
|
|
31495
|
+
}
|
|
31496
|
+
parsed = raw;
|
|
31497
|
+
} catch {
|
|
31498
|
+
throw new PlanStoreError(
|
|
31499
|
+
`PLAN_CORRUPT: ${jsonPath} is not valid JSON \u2014 refusing to overwrite a possibly hand-edited or crashed write. Fix or remove the file (a .bak may exist), then retry.`,
|
|
31500
|
+
"PLAN_CORRUPT"
|
|
31501
|
+
);
|
|
31502
|
+
}
|
|
31503
|
+
const {
|
|
31504
|
+
tasks: rawTasks,
|
|
31505
|
+
counter,
|
|
31506
|
+
schemaVersion: _schemaVersion,
|
|
31507
|
+
...rootFields
|
|
31508
|
+
} = parsed;
|
|
31509
|
+
const tasks = (Array.isArray(rawTasks) ? rawTasks : []).map(normalizeTask).filter((t) => typeof t.id === "string" && t.id.length > 0);
|
|
31510
|
+
const numericCounter = typeof counter === "number" && Number.isFinite(counter) && counter >= 0 ? Math.floor(counter) : 0;
|
|
31511
|
+
return { rootDir, tasks, counter: numericCounter, rootFields };
|
|
31512
|
+
}
|
|
31513
|
+
function saveHandle(rootDir, handle) {
|
|
31514
|
+
if (handle.tasks.length > PLAN_MAX_TASKS) {
|
|
31515
|
+
throw new PlanStoreError(
|
|
31516
|
+
`PLAN_TOO_MANY_TASKS: plan.json would exceed ${PLAN_MAX_TASKS} tasks (${handle.tasks.length}) \u2014 cancel or complete tasks first.`,
|
|
31517
|
+
"PLAN_TOO_MANY_TASKS"
|
|
31518
|
+
);
|
|
31519
|
+
}
|
|
31520
|
+
const jsonPath = join15(rootDir, "plan.json");
|
|
31521
|
+
mkdirSync12(rootDir, { recursive: true });
|
|
31522
|
+
if (existsSync19(jsonPath)) {
|
|
31523
|
+
copyFileSync(jsonPath, `${jsonPath}.bak`);
|
|
31524
|
+
}
|
|
31525
|
+
const file2 = {
|
|
31526
|
+
...handle.rootFields,
|
|
31527
|
+
schemaVersion: PLAN_SCHEMA_VERSION,
|
|
31528
|
+
counter: handle.counter,
|
|
31529
|
+
tasks: handle.tasks
|
|
31530
|
+
};
|
|
31531
|
+
const tmp = `${jsonPath}.tmp-${process.pid}`;
|
|
31532
|
+
writeFileSync14(tmp, JSON.stringify(file2, null, 2) + "\n", "utf8");
|
|
31533
|
+
renameSync3(tmp, jsonPath);
|
|
31534
|
+
}
|
|
31535
|
+
function normalizeTask(raw) {
|
|
31536
|
+
const t = raw !== null && typeof raw === "object" ? { ...raw } : {};
|
|
31537
|
+
if (typeof t.id === "string") {
|
|
31538
|
+
t.id = t.id.trim().slice(0, 64);
|
|
31539
|
+
}
|
|
31540
|
+
const titleSource = firstString(t.title) ?? firstString(t.name) ?? firstString(t.description) ?? "";
|
|
31541
|
+
t.title = titleSource.slice(0, PLAN_TITLE_MAX);
|
|
31542
|
+
if (t.title && !firstString(t.name)) {
|
|
31543
|
+
t.name = t.title;
|
|
31544
|
+
}
|
|
31545
|
+
t.status = normalizeStatus(t.status);
|
|
31546
|
+
if (typeof t.notes === "string") {
|
|
31547
|
+
t.notes = t.notes.slice(0, PLAN_NOTES_MAX);
|
|
31548
|
+
}
|
|
31549
|
+
if (typeof t.phaseId === "string") {
|
|
31550
|
+
t.phaseId = t.phaseId.slice(0, PLAN_TAG_MAX);
|
|
31551
|
+
}
|
|
31552
|
+
if (typeof t.agent === "string") {
|
|
31553
|
+
t.agent = t.agent.slice(0, PLAN_TAG_MAX);
|
|
31554
|
+
}
|
|
31555
|
+
return t;
|
|
31556
|
+
}
|
|
31557
|
+
function normalizeStatus(raw) {
|
|
31558
|
+
const s = typeof raw === "string" ? raw.trim().toLowerCase() : "";
|
|
31559
|
+
switch (s) {
|
|
31560
|
+
case "in_progress":
|
|
31561
|
+
case "in-progress":
|
|
31562
|
+
case "doing":
|
|
31563
|
+
case "started":
|
|
31564
|
+
case "active":
|
|
31565
|
+
return "in_progress";
|
|
31566
|
+
case "completed":
|
|
31567
|
+
case "complete":
|
|
31568
|
+
case "done":
|
|
31569
|
+
case "finished":
|
|
31570
|
+
return "completed";
|
|
31571
|
+
case "cancelled":
|
|
31572
|
+
case "canceled":
|
|
31573
|
+
case "closed":
|
|
31574
|
+
return "cancelled";
|
|
31575
|
+
case "blocked":
|
|
31576
|
+
case "on-hold":
|
|
31577
|
+
case "on hold":
|
|
31578
|
+
return "blocked";
|
|
31579
|
+
default:
|
|
31580
|
+
return "pending";
|
|
31581
|
+
}
|
|
31582
|
+
}
|
|
31583
|
+
function firstString(v) {
|
|
31584
|
+
return typeof v === "string" && v.trim().length > 0 ? v : null;
|
|
31585
|
+
}
|
|
31586
|
+
var PLAN_SCHEMA_VERSION, PLAN_MAX_TASKS, PLAN_TITLE_MAX, PLAN_NOTES_MAX, PLAN_TAG_MAX, PlanStoreError;
|
|
31587
|
+
var init_planStore = __esm({
|
|
31588
|
+
"src/cli/workspace/planStore.ts"() {
|
|
31589
|
+
"use strict";
|
|
31590
|
+
init_paths2();
|
|
31591
|
+
init_storage();
|
|
31592
|
+
PLAN_SCHEMA_VERSION = 1;
|
|
31593
|
+
PLAN_MAX_TASKS = 100;
|
|
31594
|
+
PLAN_TITLE_MAX = 200;
|
|
31595
|
+
PLAN_NOTES_MAX = 2e3;
|
|
31596
|
+
PLAN_TAG_MAX = 64;
|
|
31597
|
+
PlanStoreError = class extends Error {
|
|
31598
|
+
constructor(message, code) {
|
|
31599
|
+
super(message);
|
|
31600
|
+
this.code = code;
|
|
31601
|
+
this.name = "PlanStoreError";
|
|
31602
|
+
}
|
|
31603
|
+
};
|
|
31604
|
+
}
|
|
31605
|
+
});
|
|
31606
|
+
|
|
31607
|
+
// src/cli/tools/planTaskTools.ts
|
|
31608
|
+
function taskSummaryLine(t) {
|
|
31609
|
+
return `- ${t.id}: ${t.title} (${t.status}${t.priority ? `, ${t.priority}` : ""})`;
|
|
31610
|
+
}
|
|
31611
|
+
function toTaskPayload(t) {
|
|
31612
|
+
return {
|
|
31613
|
+
id: t.id,
|
|
31614
|
+
title: t.title,
|
|
31615
|
+
status: t.status,
|
|
31616
|
+
phaseId: t.phaseId,
|
|
31617
|
+
priority: t.priority
|
|
31618
|
+
};
|
|
31619
|
+
}
|
|
31620
|
+
function safeEmit(sink, event) {
|
|
31621
|
+
if (!sink) return;
|
|
31622
|
+
try {
|
|
31623
|
+
sink(event);
|
|
31624
|
+
} catch {
|
|
31625
|
+
}
|
|
31626
|
+
}
|
|
31627
|
+
function createPlanTaskTools(opts) {
|
|
31628
|
+
const projectRoot = opts.projectRoot;
|
|
31629
|
+
const onTaskEvent = opts.onTaskEvent;
|
|
31630
|
+
const taskCreate = {
|
|
31631
|
+
name: "task_create",
|
|
31632
|
+
description: "Create a durable workspace task in .zelari/plan.json (multi-session, shared with the Desktop Live Tasks panel). Use for project work that must survive this session. For volatile per-session tracking use todo_write instead. Returns the assigned id (t<N>).",
|
|
31633
|
+
permissions: ["write"],
|
|
31634
|
+
timeoutMs: 5e3,
|
|
31635
|
+
inputSchema: CreateSchema,
|
|
31636
|
+
execute: async (input) => {
|
|
31637
|
+
try {
|
|
31638
|
+
const res = await withPlanStore(projectRoot, (store4) => {
|
|
31639
|
+
if (store4.tasks.length >= PLAN_MAX_TASKS) {
|
|
31640
|
+
return typedErr(
|
|
31641
|
+
`PLAN_TOO_MANY_TASKS: plan.json already holds ${store4.tasks.length} tasks (max ${PLAN_MAX_TASKS}).`
|
|
31642
|
+
);
|
|
31643
|
+
}
|
|
31644
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
31645
|
+
const id = nextPlanTaskId(store4);
|
|
31646
|
+
const task = {
|
|
31647
|
+
id,
|
|
31648
|
+
title: input.title.trim().slice(0, PLAN_TITLE_MAX),
|
|
31649
|
+
// council readers (buildPlanSummary) render `name` — keep the
|
|
31650
|
+
// alias in sync from creation, not just on reload.
|
|
31651
|
+
name: input.title.trim().slice(0, PLAN_TITLE_MAX),
|
|
31652
|
+
status: "pending",
|
|
31653
|
+
priority: input.priority,
|
|
31654
|
+
phaseId: input.phaseId?.trim().slice(0, 64),
|
|
31655
|
+
notes: input.notes?.trim().slice(0, PLAN_NOTES_MAX),
|
|
31656
|
+
createdAt: now,
|
|
31657
|
+
updatedAt: now
|
|
31658
|
+
};
|
|
31659
|
+
store4.tasks.push(task);
|
|
31660
|
+
writePlanTaskArtifact(store4.rootDir, task);
|
|
31661
|
+
return typedOk({ id, task });
|
|
31662
|
+
});
|
|
31663
|
+
if (res.ok) {
|
|
31664
|
+
safeEmit(onTaskEvent, {
|
|
31665
|
+
type: "task_update",
|
|
31666
|
+
source: "workspace_plan",
|
|
31667
|
+
task: toTaskPayload(res.value.task)
|
|
31668
|
+
});
|
|
31669
|
+
}
|
|
31670
|
+
return res;
|
|
31671
|
+
} catch (err) {
|
|
31672
|
+
return typedErr(planStoreErrorMessage(err, "task_create"));
|
|
31673
|
+
}
|
|
31674
|
+
}
|
|
31675
|
+
};
|
|
31676
|
+
const taskUpdate = {
|
|
31677
|
+
name: "task_update",
|
|
31678
|
+
description: "Update a durable workspace task in .zelari/plan.json (status, title, priority, phaseId, notes, or appendNote). Accepts council-created ids too (task_list shows them). Errors with PLAN_TASK_NOT_FOUND on unknown ids.",
|
|
31679
|
+
permissions: ["write"],
|
|
31680
|
+
timeoutMs: 5e3,
|
|
31681
|
+
inputSchema: UpdateSchema,
|
|
31682
|
+
execute: async (input) => {
|
|
31683
|
+
try {
|
|
31684
|
+
const res = await withPlanStore(projectRoot, (store4) => {
|
|
31685
|
+
const task = store4.tasks.find((t) => t.id === input.id);
|
|
31686
|
+
if (!task) {
|
|
31687
|
+
return typedErr(
|
|
31688
|
+
`PLAN_TASK_NOT_FOUND: no task with id "${input.id}" in .zelari/plan.json (call task_list for current ids).`
|
|
31689
|
+
);
|
|
31690
|
+
}
|
|
31691
|
+
if (input.title !== void 0) {
|
|
31692
|
+
task.title = input.title.trim().slice(0, PLAN_TITLE_MAX);
|
|
31693
|
+
task.name = task.title;
|
|
31694
|
+
}
|
|
31695
|
+
if (input.status !== void 0) task.status = input.status;
|
|
31696
|
+
if (input.priority !== void 0) task.priority = input.priority;
|
|
31697
|
+
if (input.phaseId !== void 0) task.phaseId = input.phaseId.slice(0, 64);
|
|
31698
|
+
if (input.notes !== void 0) {
|
|
31699
|
+
task.notes = input.notes.slice(0, PLAN_NOTES_MAX);
|
|
31700
|
+
}
|
|
31701
|
+
if (input.appendNote !== void 0) {
|
|
31702
|
+
const prev2 = typeof task.notes === "string" ? task.notes : "";
|
|
31703
|
+
const merged = prev2 ? `${prev2}
|
|
31704
|
+
${input.appendNote}` : input.appendNote;
|
|
31705
|
+
task.notes = merged.slice(-PLAN_NOTES_MAX);
|
|
31706
|
+
}
|
|
31707
|
+
task.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
31708
|
+
writePlanTaskArtifact(store4.rootDir, task);
|
|
31709
|
+
return typedOk({ task });
|
|
31710
|
+
});
|
|
31711
|
+
if (res.ok) {
|
|
31712
|
+
safeEmit(onTaskEvent, {
|
|
31713
|
+
type: "task_update",
|
|
31714
|
+
source: "workspace_plan",
|
|
31715
|
+
task: toTaskPayload(res.value.task)
|
|
31716
|
+
});
|
|
31717
|
+
}
|
|
31718
|
+
return res;
|
|
31719
|
+
} catch (err) {
|
|
31720
|
+
return typedErr(planStoreErrorMessage(err, "task_update"));
|
|
31721
|
+
}
|
|
31722
|
+
}
|
|
31723
|
+
};
|
|
31724
|
+
const taskList = {
|
|
31725
|
+
name: "task_list",
|
|
31726
|
+
description: "List durable workspace tasks from .zelari/plan.json (both t<N> agent tasks and council-created plan tasks). Optional status/phaseId filters. Use before task_update to discover ids.",
|
|
31727
|
+
permissions: ["read"],
|
|
31728
|
+
timeoutMs: 5e3,
|
|
31729
|
+
inputSchema: ListSchema,
|
|
31730
|
+
execute: async (input) => {
|
|
31731
|
+
try {
|
|
31732
|
+
let allPayloads = [];
|
|
31733
|
+
const res = await withPlanStore(projectRoot, (store4) => {
|
|
31734
|
+
allPayloads = store4.tasks.map(toTaskPayload);
|
|
31735
|
+
const filtered = store4.tasks.filter(
|
|
31736
|
+
(t) => (input.status === void 0 || t.status === input.status) && (input.phaseId === void 0 || t.phaseId === input.phaseId)
|
|
31737
|
+
);
|
|
31738
|
+
const done = store4.tasks.filter(
|
|
31739
|
+
(t) => t.status === "completed" || t.status === "cancelled"
|
|
31740
|
+
).length;
|
|
31741
|
+
const formatted = filtered.length === 0 ? "(no matching workspace tasks)" : filtered.map(taskSummaryLine).join("\n");
|
|
31742
|
+
return typedOk({
|
|
31743
|
+
tasks: filtered,
|
|
31744
|
+
total: store4.tasks.length,
|
|
31745
|
+
done,
|
|
31746
|
+
formatted: `${formatted}
|
|
31747
|
+
(done/total: ${done}/${store4.tasks.length})`
|
|
31748
|
+
});
|
|
31749
|
+
});
|
|
31750
|
+
if (res.ok) {
|
|
31751
|
+
safeEmit(onTaskEvent, {
|
|
31752
|
+
type: "task_snapshot",
|
|
31753
|
+
source: "workspace_plan",
|
|
31754
|
+
tasks: allPayloads
|
|
31755
|
+
});
|
|
31756
|
+
}
|
|
31757
|
+
return res;
|
|
31758
|
+
} catch (err) {
|
|
31759
|
+
return typedErr(planStoreErrorMessage(err, "task_list"));
|
|
31760
|
+
}
|
|
31761
|
+
}
|
|
31762
|
+
};
|
|
31763
|
+
return [taskCreate, taskUpdate, taskList];
|
|
31764
|
+
}
|
|
31765
|
+
function planStoreErrorMessage(err, tool) {
|
|
31766
|
+
if (err instanceof PlanStoreError) return err.message;
|
|
31767
|
+
return `[${tool}] ${err instanceof Error ? err.message : String(err)}`;
|
|
31768
|
+
}
|
|
31769
|
+
var StatusSchema2, PrioritySchema, CreateSchema, UpdateSchema, ListSchema;
|
|
31770
|
+
var init_planTaskTools = __esm({
|
|
31771
|
+
"src/cli/tools/planTaskTools.ts"() {
|
|
31772
|
+
"use strict";
|
|
31773
|
+
init_zod();
|
|
31774
|
+
init_toolTypes();
|
|
31775
|
+
init_planStore();
|
|
31776
|
+
StatusSchema2 = external_exports.enum(["pending", "in_progress", "completed", "cancelled", "blocked"]).describe(
|
|
31777
|
+
"blocked exists only here (session todos have no blocked); no rigid FSM \u2014 corrections like completed \u2192 in_progress are allowed"
|
|
31778
|
+
);
|
|
31779
|
+
PrioritySchema = external_exports.enum(["low", "medium", "high", "critical"]);
|
|
31780
|
+
CreateSchema = external_exports.object({
|
|
31781
|
+
title: external_exports.string().min(1).max(PLAN_TITLE_MAX).describe("Short task description"),
|
|
31782
|
+
priority: PrioritySchema.optional().describe("Default medium"),
|
|
31783
|
+
phaseId: external_exports.string().min(1).max(64).optional().describe("Existing plan phase id (see .zelari/plan.json phases)"),
|
|
31784
|
+
notes: external_exports.string().max(PLAN_NOTES_MAX).optional().describe("Optional context/acceptance notes")
|
|
31785
|
+
});
|
|
31786
|
+
UpdateSchema = external_exports.object({
|
|
31787
|
+
id: external_exports.string().min(1).max(64).describe("Task id from task_create/task_list"),
|
|
31788
|
+
status: StatusSchema2.optional(),
|
|
31789
|
+
title: external_exports.string().min(1).max(PLAN_TITLE_MAX).optional(),
|
|
31790
|
+
priority: PrioritySchema.optional(),
|
|
31791
|
+
phaseId: external_exports.string().min(1).max(64).optional(),
|
|
31792
|
+
notes: external_exports.string().max(PLAN_NOTES_MAX).optional(),
|
|
31793
|
+
appendNote: external_exports.string().max(PLAN_NOTES_MAX).optional().describe("Append to existing notes (kept within the size cap)")
|
|
31794
|
+
}).describe("At least one field besides id must be present");
|
|
31795
|
+
ListSchema = external_exports.object({
|
|
31796
|
+
status: StatusSchema2.optional().describe("Filter by status"),
|
|
31797
|
+
phaseId: external_exports.string().min(1).max(64).optional().describe("Filter by phase")
|
|
31798
|
+
});
|
|
31799
|
+
}
|
|
31800
|
+
});
|
|
31801
|
+
|
|
31029
31802
|
// src/cli/lsp/protocol.ts
|
|
31030
31803
|
function encodeMessage(message) {
|
|
31031
31804
|
const json2 = JSON.stringify(message);
|
|
@@ -31329,7 +32102,7 @@ var init_servers = __esm({
|
|
|
31329
32102
|
|
|
31330
32103
|
// src/cli/lsp/manager.ts
|
|
31331
32104
|
import { spawn as spawn4 } from "node:child_process";
|
|
31332
|
-
import { readFileSync as
|
|
32105
|
+
import { readFileSync as readFileSync18 } from "node:fs";
|
|
31333
32106
|
function processTransport(child) {
|
|
31334
32107
|
return {
|
|
31335
32108
|
send: (data) => {
|
|
@@ -31532,7 +32305,7 @@ var init_manager = __esm({
|
|
|
31532
32305
|
const uri = pathToUri(file2);
|
|
31533
32306
|
let text;
|
|
31534
32307
|
try {
|
|
31535
|
-
text =
|
|
32308
|
+
text = readFileSync18(file2, "utf8");
|
|
31536
32309
|
} catch {
|
|
31537
32310
|
text = "";
|
|
31538
32311
|
}
|
|
@@ -31854,13 +32627,13 @@ var init_store = __esm({
|
|
|
31854
32627
|
});
|
|
31855
32628
|
|
|
31856
32629
|
// src/cli/semantic/index.ts
|
|
31857
|
-
import { promises as fs12, existsSync as
|
|
31858
|
-
import { homedir as
|
|
32630
|
+
import { promises as fs12, existsSync as existsSync20, readFileSync as readFileSync19 } from "node:fs";
|
|
32631
|
+
import { homedir as homedir6 } from "node:os";
|
|
31859
32632
|
import path23 from "node:path";
|
|
31860
|
-
import { createHash as
|
|
32633
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
31861
32634
|
function getIndexPath(root) {
|
|
31862
|
-
const hash3 =
|
|
31863
|
-
return process.env.ZELARI_SEMANTIC_FILE ?? path23.join(
|
|
32635
|
+
const hash3 = createHash5("sha1").update(path23.resolve(root)).digest("hex").slice(0, 16);
|
|
32636
|
+
return process.env.ZELARI_SEMANTIC_FILE ?? path23.join(homedir6(), ".tmp", "zelari-code", "semantic", `${hash3}.json`);
|
|
31864
32637
|
}
|
|
31865
32638
|
async function collectSourceFiles(root, maxFiles = 1500) {
|
|
31866
32639
|
const out = [];
|
|
@@ -31938,9 +32711,9 @@ async function saveIndex(root, data) {
|
|
|
31938
32711
|
}
|
|
31939
32712
|
function loadIndex(root) {
|
|
31940
32713
|
const file2 = getIndexPath(root);
|
|
31941
|
-
if (!
|
|
32714
|
+
if (!existsSync20(file2)) return null;
|
|
31942
32715
|
try {
|
|
31943
|
-
const parsed = JSON.parse(
|
|
32716
|
+
const parsed = JSON.parse(readFileSync19(file2, "utf8"));
|
|
31944
32717
|
if (parsed && Array.isArray(parsed.chunks)) return parsed;
|
|
31945
32718
|
} catch {
|
|
31946
32719
|
}
|
|
@@ -32470,19 +33243,19 @@ __export(targets_exports, {
|
|
|
32470
33243
|
});
|
|
32471
33244
|
import {
|
|
32472
33245
|
chmodSync,
|
|
32473
|
-
existsSync as
|
|
32474
|
-
mkdirSync as
|
|
32475
|
-
readFileSync as
|
|
32476
|
-
writeFileSync as
|
|
33246
|
+
existsSync as existsSync21,
|
|
33247
|
+
mkdirSync as mkdirSync13,
|
|
33248
|
+
readFileSync as readFileSync20,
|
|
33249
|
+
writeFileSync as writeFileSync15
|
|
32477
33250
|
} from "node:fs";
|
|
32478
|
-
import { dirname as
|
|
32479
|
-
import { homedir as
|
|
33251
|
+
import { dirname as dirname4, join as join16 } from "node:path";
|
|
33252
|
+
import { homedir as homedir7 } from "node:os";
|
|
32480
33253
|
import { spawn as spawn5 } from "node:child_process";
|
|
32481
33254
|
function getSshTargetsPath() {
|
|
32482
|
-
return
|
|
33255
|
+
return join16(homedir7(), ".zelari-code", "ssh-targets.json");
|
|
32483
33256
|
}
|
|
32484
33257
|
function getSshSecretsPath() {
|
|
32485
|
-
return
|
|
33258
|
+
return join16(homedir7(), ".zelari-code", "ssh-secrets.json");
|
|
32486
33259
|
}
|
|
32487
33260
|
function normalizeAuth(auth) {
|
|
32488
33261
|
if (auth === "keyPath") return "keyPath";
|
|
@@ -32491,17 +33264,17 @@ function normalizeAuth(auth) {
|
|
|
32491
33264
|
}
|
|
32492
33265
|
function readSecrets() {
|
|
32493
33266
|
const path53 = getSshSecretsPath();
|
|
32494
|
-
if (!
|
|
33267
|
+
if (!existsSync21(path53)) return {};
|
|
32495
33268
|
try {
|
|
32496
|
-
return JSON.parse(
|
|
33269
|
+
return JSON.parse(readFileSync20(path53, "utf8"));
|
|
32497
33270
|
} catch {
|
|
32498
33271
|
return {};
|
|
32499
33272
|
}
|
|
32500
33273
|
}
|
|
32501
33274
|
function writeSecrets(data) {
|
|
32502
33275
|
const path53 = getSshSecretsPath();
|
|
32503
|
-
|
|
32504
|
-
|
|
33276
|
+
mkdirSync13(dirname4(path53), { recursive: true });
|
|
33277
|
+
writeFileSync15(path53, `${JSON.stringify(data, null, 2)}
|
|
32505
33278
|
`, "utf8");
|
|
32506
33279
|
try {
|
|
32507
33280
|
chmodSync(path53, 384);
|
|
@@ -32534,9 +33307,9 @@ function deleteSshPassword(id) {
|
|
|
32534
33307
|
}
|
|
32535
33308
|
function readStore2() {
|
|
32536
33309
|
const path53 = getSshTargetsPath();
|
|
32537
|
-
if (!
|
|
33310
|
+
if (!existsSync21(path53)) return [];
|
|
32538
33311
|
try {
|
|
32539
|
-
const parsed = JSON.parse(
|
|
33312
|
+
const parsed = JSON.parse(readFileSync20(path53, "utf8"));
|
|
32540
33313
|
const list = Array.isArray(parsed.targets) ? parsed.targets : [];
|
|
32541
33314
|
return list.filter(
|
|
32542
33315
|
(t) => t && typeof t.id === "string" && typeof t.host === "string" && typeof t.user === "string"
|
|
@@ -32552,9 +33325,9 @@ function readStore2() {
|
|
|
32552
33325
|
}
|
|
32553
33326
|
function writeStore2(targets) {
|
|
32554
33327
|
const path53 = getSshTargetsPath();
|
|
32555
|
-
|
|
33328
|
+
mkdirSync13(dirname4(path53), { recursive: true });
|
|
32556
33329
|
const clean = targets.map(({ hasPassword: _hp, ...t }) => t);
|
|
32557
|
-
|
|
33330
|
+
writeFileSync15(
|
|
32558
33331
|
path53,
|
|
32559
33332
|
`${JSON.stringify({ targets: clean }, null, 2)}
|
|
32560
33333
|
`,
|
|
@@ -32655,17 +33428,17 @@ function buildSshBaseArgs(target) {
|
|
|
32655
33428
|
return args;
|
|
32656
33429
|
}
|
|
32657
33430
|
function ensureAskpassHelper() {
|
|
32658
|
-
const dir =
|
|
32659
|
-
|
|
32660
|
-
const cjs =
|
|
32661
|
-
|
|
33431
|
+
const dir = join16(homedir7(), ".zelari-code", "ssh-helpers");
|
|
33432
|
+
mkdirSync13(dir, { recursive: true });
|
|
33433
|
+
const cjs = join16(dir, "askpass.cjs");
|
|
33434
|
+
writeFileSync15(
|
|
32662
33435
|
cjs,
|
|
32663
33436
|
"process.stdout.write(process.env.ZELARI_SSH_ASKPASS_PASS || '');\n",
|
|
32664
33437
|
"utf8"
|
|
32665
33438
|
);
|
|
32666
33439
|
if (process.platform === "win32") {
|
|
32667
|
-
const cmd =
|
|
32668
|
-
|
|
33440
|
+
const cmd = join16(dir, "askpass.cmd");
|
|
33441
|
+
writeFileSync15(
|
|
32669
33442
|
cmd,
|
|
32670
33443
|
`@echo off\r
|
|
32671
33444
|
node "%~dp0askpass.cjs"\r
|
|
@@ -32674,8 +33447,8 @@ node "%~dp0askpass.cjs"\r
|
|
|
32674
33447
|
);
|
|
32675
33448
|
return cmd;
|
|
32676
33449
|
}
|
|
32677
|
-
const sh =
|
|
32678
|
-
|
|
33450
|
+
const sh = join16(dir, "askpass.sh");
|
|
33451
|
+
writeFileSync15(
|
|
32679
33452
|
sh,
|
|
32680
33453
|
`#!/bin/sh
|
|
32681
33454
|
exec node "$(dirname "$0")/askpass.cjs"
|
|
@@ -32748,9 +33521,9 @@ function readSshPublicKey(keyOrPubPath) {
|
|
|
32748
33521
|
if (!raw) return { ok: false, error: "Empty path" };
|
|
32749
33522
|
const candidates = raw.endsWith(".pub") ? [raw] : [`${raw}.pub`, raw];
|
|
32750
33523
|
for (const p3 of candidates) {
|
|
32751
|
-
if (!
|
|
33524
|
+
if (!existsSync21(p3)) continue;
|
|
32752
33525
|
try {
|
|
32753
|
-
const content =
|
|
33526
|
+
const content = readFileSync20(p3, "utf8").trim();
|
|
32754
33527
|
if (!content) continue;
|
|
32755
33528
|
if (/BEGIN .*PRIVATE KEY/i.test(content)) {
|
|
32756
33529
|
return {
|
|
@@ -33320,11 +34093,11 @@ __export(folderTrust_exports, {
|
|
|
33320
34093
|
trustFolder: () => trustFolder,
|
|
33321
34094
|
untrustFolder: () => untrustFolder
|
|
33322
34095
|
});
|
|
33323
|
-
import { homedir as
|
|
33324
|
-
import { existsSync as
|
|
34096
|
+
import { homedir as homedir8 } from "node:os";
|
|
34097
|
+
import { existsSync as existsSync22, mkdirSync as mkdirSync14, readFileSync as readFileSync21, writeFileSync as writeFileSync16 } from "node:fs";
|
|
33325
34098
|
import path28 from "node:path";
|
|
33326
34099
|
function trustStorePath() {
|
|
33327
|
-
return _overrideStorePath ?? path28.join(
|
|
34100
|
+
return _overrideStorePath ?? path28.join(homedir8(), ".zelari-code", "trust.json");
|
|
33328
34101
|
}
|
|
33329
34102
|
function normalize(p3) {
|
|
33330
34103
|
const resolved = path28.resolve(p3);
|
|
@@ -33332,7 +34105,7 @@ function normalize(p3) {
|
|
|
33332
34105
|
}
|
|
33333
34106
|
function readStore3() {
|
|
33334
34107
|
try {
|
|
33335
|
-
const raw =
|
|
34108
|
+
const raw = readFileSync21(trustStorePath(), "utf8");
|
|
33336
34109
|
const parsed = JSON.parse(raw);
|
|
33337
34110
|
if (parsed && Array.isArray(parsed.folders)) return parsed;
|
|
33338
34111
|
return DEFAULT_STORE;
|
|
@@ -33343,8 +34116,8 @@ function readStore3() {
|
|
|
33343
34116
|
function writeStore3(store4) {
|
|
33344
34117
|
const p3 = trustStorePath();
|
|
33345
34118
|
try {
|
|
33346
|
-
|
|
33347
|
-
|
|
34119
|
+
mkdirSync14(path28.dirname(p3), { recursive: true });
|
|
34120
|
+
writeFileSync16(p3, JSON.stringify(store4, null, 2), "utf8");
|
|
33348
34121
|
} catch (err) {
|
|
33349
34122
|
throw new Error(
|
|
33350
34123
|
`failed to persist trust store ${p3}: ${err instanceof Error ? err.message : String(err)}`
|
|
@@ -33399,7 +34172,7 @@ function getTrustStorePath() {
|
|
|
33399
34172
|
return trustStorePath();
|
|
33400
34173
|
}
|
|
33401
34174
|
function hasTrustStore() {
|
|
33402
|
-
return
|
|
34175
|
+
return existsSync22(trustStorePath());
|
|
33403
34176
|
}
|
|
33404
34177
|
function _setTrustStorePathForTests(p3) {
|
|
33405
34178
|
_overrideStorePath = p3;
|
|
@@ -33414,21 +34187,21 @@ var init_folderTrust = __esm({
|
|
|
33414
34187
|
});
|
|
33415
34188
|
|
|
33416
34189
|
// src/cli/safety/lifecycleHooks.ts
|
|
33417
|
-
import { homedir as
|
|
33418
|
-
import { join as
|
|
33419
|
-
import { readdirSync as
|
|
34190
|
+
import { homedir as homedir9 } from "node:os";
|
|
34191
|
+
import { join as join17 } from "node:path";
|
|
34192
|
+
import { readdirSync as readdirSync5, statSync as statSync3 } from "node:fs";
|
|
33420
34193
|
function globalHooksDir() {
|
|
33421
|
-
return
|
|
34194
|
+
return join17(homedir9(), ".zelari-code", "hooks");
|
|
33422
34195
|
}
|
|
33423
34196
|
function projectHooksDir(projectRoot) {
|
|
33424
|
-
return
|
|
34197
|
+
return join17(projectRoot, ".zelari", "hooks");
|
|
33425
34198
|
}
|
|
33426
34199
|
function fingerprintHookDirs(dirs) {
|
|
33427
34200
|
const parts = [];
|
|
33428
34201
|
for (const dir of dirs) {
|
|
33429
34202
|
let names;
|
|
33430
34203
|
try {
|
|
33431
|
-
names =
|
|
34204
|
+
names = readdirSync5(dir).filter((f) => f.endsWith(".json")).sort();
|
|
33432
34205
|
} catch {
|
|
33433
34206
|
parts.push(`${dir}:missing`);
|
|
33434
34207
|
continue;
|
|
@@ -33442,7 +34215,7 @@ function fingerprintHookDirs(dirs) {
|
|
|
33442
34215
|
continue;
|
|
33443
34216
|
}
|
|
33444
34217
|
for (const name of names) {
|
|
33445
|
-
const full =
|
|
34218
|
+
const full = join17(dir, name);
|
|
33446
34219
|
try {
|
|
33447
34220
|
const st = statSync3(full);
|
|
33448
34221
|
parts.push(`${full}:${st.mtimeMs}:${st.size}`);
|
|
@@ -33483,7 +34256,7 @@ var init_lifecycleHooks = __esm({
|
|
|
33483
34256
|
});
|
|
33484
34257
|
|
|
33485
34258
|
// src/cli/toolResultCache.ts
|
|
33486
|
-
import { createHash as
|
|
34259
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
33487
34260
|
import { promises as fs14 } from "node:fs";
|
|
33488
34261
|
import path29 from "node:path";
|
|
33489
34262
|
function isToolCacheEnabled() {
|
|
@@ -33496,7 +34269,7 @@ function resolveToolCacheTtlMs() {
|
|
|
33496
34269
|
return Number.isFinite(n) && n >= 0 ? n : TOOL_CACHE_DEFAULT_TTL_MS;
|
|
33497
34270
|
}
|
|
33498
34271
|
function hashKey(parts) {
|
|
33499
|
-
return
|
|
34272
|
+
return createHash6("sha256").update(JSON.stringify(parts), "utf8").digest("hex");
|
|
33500
34273
|
}
|
|
33501
34274
|
function resultBytes(result) {
|
|
33502
34275
|
try {
|
|
@@ -33786,6 +34559,11 @@ function createBuiltinToolRegistry(options = {}) {
|
|
|
33786
34559
|
const todoRead = enableTodos ? withPerm(createTodoReadTool()) : null;
|
|
33787
34560
|
if (todoWrite) registry4.register(todoWrite);
|
|
33788
34561
|
if (todoRead) registry4.register(todoRead);
|
|
34562
|
+
const enablePlanTasks = options.enablePlanTasks !== false && options.readOnly !== true && (profile === "full" || options.planMode === true) && profile !== "explore" && profile !== "verify" && profile !== "general";
|
|
34563
|
+
const planTaskToolsWrapped = (enablePlanTasks ? createPlanTaskTools({ projectRoot: root, onTaskEvent: options.onTaskEvent }) : []).map((t) => withPerm(t));
|
|
34564
|
+
for (const t of planTaskToolsWrapped) {
|
|
34565
|
+
registry4.register(t);
|
|
34566
|
+
}
|
|
33789
34567
|
const summary = [
|
|
33790
34568
|
safeReadFile,
|
|
33791
34569
|
safeGrepContent,
|
|
@@ -33798,7 +34576,8 @@ function createBuiltinToolRegistry(options = {}) {
|
|
|
33798
34576
|
...askUserTool ? [askUserTool] : [],
|
|
33799
34577
|
...skillTool ? [skillTool] : [],
|
|
33800
34578
|
...todoWrite ? [todoWrite] : [],
|
|
33801
|
-
...todoRead ? [todoRead] : []
|
|
34579
|
+
...todoRead ? [todoRead] : [],
|
|
34580
|
+
...planTaskToolsWrapped.length > 0 ? planTaskToolsWrapped : []
|
|
33802
34581
|
];
|
|
33803
34582
|
const tools = summary.map((t) => ({
|
|
33804
34583
|
name: t.name,
|
|
@@ -34147,6 +34926,7 @@ var init_toolRegistry = __esm({
|
|
|
34147
34926
|
init_askUser();
|
|
34148
34927
|
init_skillTool();
|
|
34149
34928
|
init_todoTools();
|
|
34929
|
+
init_planTaskTools();
|
|
34150
34930
|
init_tools2();
|
|
34151
34931
|
init_manager();
|
|
34152
34932
|
init_tools3();
|
|
@@ -34177,7 +34957,7 @@ var init_toolRegistry = __esm({
|
|
|
34177
34957
|
});
|
|
34178
34958
|
|
|
34179
34959
|
// src/cli/state/fileStateStore.ts
|
|
34180
|
-
import { createHash as
|
|
34960
|
+
import { createHash as createHash7, randomUUID as randomUUID2 } from "node:crypto";
|
|
34181
34961
|
import { promises as fs15 } from "node:fs";
|
|
34182
34962
|
import * as path30 from "node:path";
|
|
34183
34963
|
function shortId() {
|
|
@@ -34229,7 +35009,7 @@ async function getStateStore(projectRoot, env = process.env) {
|
|
|
34229
35009
|
}
|
|
34230
35010
|
}
|
|
34231
35011
|
function hashStablePrompt(stable) {
|
|
34232
|
-
return
|
|
35012
|
+
return createHash7("sha256").update(stable, "utf8").digest("hex").slice(0, 16);
|
|
34233
35013
|
}
|
|
34234
35014
|
var DEFAULT_MATERIALIZE_CHARS, FileDurableStateStore, NoopDurableStateStore;
|
|
34235
35015
|
var init_fileStateStore = __esm({
|
|
@@ -34942,8 +35722,8 @@ __export(conversationContext_exports, {
|
|
|
34942
35722
|
setHistory: () => setHistory,
|
|
34943
35723
|
setLastClarification: () => setLastClarification
|
|
34944
35724
|
});
|
|
34945
|
-
import { existsSync as
|
|
34946
|
-
import { join as
|
|
35725
|
+
import { existsSync as existsSync23 } from "node:fs";
|
|
35726
|
+
import { join as join19 } from "node:path";
|
|
34947
35727
|
function getHistory() {
|
|
34948
35728
|
return history;
|
|
34949
35729
|
}
|
|
@@ -34951,7 +35731,7 @@ function setHistory(messages) {
|
|
|
34951
35731
|
history = [...messages];
|
|
34952
35732
|
}
|
|
34953
35733
|
function compactInPlace(cwd = process.cwd()) {
|
|
34954
|
-
const durableStatePresent =
|
|
35734
|
+
const durableStatePresent = existsSync23(join19(cwd, ".zelari", "state", "HEAD.json"));
|
|
34955
35735
|
history = compactHistory(history, { durableStatePresent });
|
|
34956
35736
|
}
|
|
34957
35737
|
function appendMessages(msgs) {
|
|
@@ -35466,14 +36246,14 @@ var init_claudeProvider = __esm({
|
|
|
35466
36246
|
});
|
|
35467
36247
|
|
|
35468
36248
|
// src/cli/workspace/projectInstructions.ts
|
|
35469
|
-
import { existsSync as
|
|
35470
|
-
import { join as
|
|
36249
|
+
import { existsSync as existsSync24, readFileSync as readFileSync22 } from "node:fs";
|
|
36250
|
+
import { join as join20 } from "node:path";
|
|
35471
36251
|
function loadProjectInstructions(projectRoot = process.cwd(), maxChars = MAX_CHARS) {
|
|
35472
36252
|
for (const name of CANDIDATES) {
|
|
35473
|
-
const full =
|
|
35474
|
-
if (!
|
|
36253
|
+
const full = join20(projectRoot, name);
|
|
36254
|
+
if (!existsSync24(full)) continue;
|
|
35475
36255
|
try {
|
|
35476
|
-
let raw =
|
|
36256
|
+
let raw = readFileSync22(full, "utf8");
|
|
35477
36257
|
raw = raw.replace(/\r\n/g, "\n").trim();
|
|
35478
36258
|
if (!raw) continue;
|
|
35479
36259
|
if (raw.length <= maxChars) {
|
|
@@ -35508,75 +36288,6 @@ var init_projectInstructions = __esm({
|
|
|
35508
36288
|
}
|
|
35509
36289
|
});
|
|
35510
36290
|
|
|
35511
|
-
// src/cli/workspace/paths.ts
|
|
35512
|
-
import {
|
|
35513
|
-
mkdirSync as mkdirSync12,
|
|
35514
|
-
writeFileSync as writeFileSync14,
|
|
35515
|
-
existsSync as existsSync22,
|
|
35516
|
-
accessSync,
|
|
35517
|
-
constants,
|
|
35518
|
-
realpathSync
|
|
35519
|
-
} from "node:fs";
|
|
35520
|
-
import { join as join18, basename } from "node:path";
|
|
35521
|
-
import { homedir as homedir9 } from "node:os";
|
|
35522
|
-
import { createHash as createHash7 } from "node:crypto";
|
|
35523
|
-
function resolveWorkspaceRoot(projectRoot = process.cwd()) {
|
|
35524
|
-
const candidates = [
|
|
35525
|
-
join18(projectRoot, ".zelari"),
|
|
35526
|
-
join18(homedir9(), ".zelari-code", "workspace", hashProject(projectRoot))
|
|
35527
|
-
];
|
|
35528
|
-
for (const candidate of candidates) {
|
|
35529
|
-
if (isWritableDir(projectRoot) || candidate !== candidates[0]) {
|
|
35530
|
-
ensureWorkspaceDir(candidate);
|
|
35531
|
-
return candidate;
|
|
35532
|
-
}
|
|
35533
|
-
}
|
|
35534
|
-
ensureWorkspaceDir(candidates[0]);
|
|
35535
|
-
return candidates[0];
|
|
35536
|
-
}
|
|
35537
|
-
function hashProject(projectPath) {
|
|
35538
|
-
return createHash7("sha1").update(realpathSync(projectPath)).digest("hex").slice(0, 12);
|
|
35539
|
-
}
|
|
35540
|
-
function isWritableDir(dir) {
|
|
35541
|
-
try {
|
|
35542
|
-
if (!existsSync22(dir)) return false;
|
|
35543
|
-
accessSync(dir, constants.W_OK);
|
|
35544
|
-
return true;
|
|
35545
|
-
} catch {
|
|
35546
|
-
return false;
|
|
35547
|
-
}
|
|
35548
|
-
}
|
|
35549
|
-
function ensureWorkspaceDir(workspaceDir) {
|
|
35550
|
-
mkdirSync12(workspaceDir, { recursive: true });
|
|
35551
|
-
if (workspaceDir.endsWith("/.zelari") && existsSync22(join18(workspaceDir, "..", ".git"))) {
|
|
35552
|
-
const gitignorePath = join18(workspaceDir, ".gitignore");
|
|
35553
|
-
if (!existsSync22(gitignorePath)) {
|
|
35554
|
-
writeFileSync14(gitignorePath, "*\n!.gitignore\n");
|
|
35555
|
-
}
|
|
35556
|
-
}
|
|
35557
|
-
}
|
|
35558
|
-
function workspaceFile(rootDir, kind) {
|
|
35559
|
-
switch (kind) {
|
|
35560
|
-
case "plan":
|
|
35561
|
-
return join18(rootDir, "plan.md");
|
|
35562
|
-
case "risks":
|
|
35563
|
-
return join18(rootDir, "risks.md");
|
|
35564
|
-
case "index":
|
|
35565
|
-
return join18(rootDir, "workspace.json");
|
|
35566
|
-
}
|
|
35567
|
-
}
|
|
35568
|
-
function workspaceArtifact(rootDir, subdir, slug) {
|
|
35569
|
-
return join18(rootDir, subdir, `${slug}.md`);
|
|
35570
|
-
}
|
|
35571
|
-
function projectName(projectRoot = process.cwd()) {
|
|
35572
|
-
return basename(realpathSync(projectRoot));
|
|
35573
|
-
}
|
|
35574
|
-
var init_paths2 = __esm({
|
|
35575
|
-
"src/cli/workspace/paths.ts"() {
|
|
35576
|
-
"use strict";
|
|
35577
|
-
}
|
|
35578
|
-
});
|
|
35579
|
-
|
|
35580
36291
|
// src/cli/workspace/workspaceSummary.ts
|
|
35581
36292
|
var workspaceSummary_exports = {};
|
|
35582
36293
|
__export(workspaceSummary_exports, {
|
|
@@ -35586,8 +36297,8 @@ __export(workspaceSummary_exports, {
|
|
|
35586
36297
|
buildWorkspaceSummary: () => buildWorkspaceSummary,
|
|
35587
36298
|
buildZelariReadHint: () => buildZelariReadHint
|
|
35588
36299
|
});
|
|
35589
|
-
import { existsSync as
|
|
35590
|
-
import { join as
|
|
36300
|
+
import { existsSync as existsSync25, readFileSync as readFileSync23, readdirSync as readdirSync6, statSync as statSync4 } from "node:fs";
|
|
36301
|
+
import { join as join21, relative } from "node:path";
|
|
35591
36302
|
function buildWorkspaceSummary(projectRoot = process.cwd(), options = {}) {
|
|
35592
36303
|
const { maxEntries = 30, maxChars = 3500, maxDeps = 24, maxScripts = 16 } = options;
|
|
35593
36304
|
const name = safeProjectName(projectRoot);
|
|
@@ -35620,11 +36331,11 @@ function formatTaskLine(t) {
|
|
|
35620
36331
|
}
|
|
35621
36332
|
function buildPlanSummary(projectRoot = process.cwd(), options) {
|
|
35622
36333
|
const zelariRoot = resolveWorkspaceRoot(projectRoot);
|
|
35623
|
-
const planPath =
|
|
35624
|
-
if (!
|
|
36334
|
+
const planPath = join21(zelariRoot, "plan.json");
|
|
36335
|
+
if (!existsSync25(planPath)) return null;
|
|
35625
36336
|
let plan;
|
|
35626
36337
|
try {
|
|
35627
|
-
plan = JSON.parse(
|
|
36338
|
+
plan = JSON.parse(readFileSync23(planPath, "utf8"));
|
|
35628
36339
|
} catch {
|
|
35629
36340
|
return null;
|
|
35630
36341
|
}
|
|
@@ -35638,7 +36349,10 @@ function buildPlanSummary(projectRoot = process.cwd(), options) {
|
|
|
35638
36349
|
"# Plan ops (DRAFT \u2014 .zelari/plan.json)",
|
|
35639
36350
|
"_This is operational task list from design, not product law. Ground every change in the real source tree._"
|
|
35640
36351
|
];
|
|
35641
|
-
const open = tasks.filter((t) =>
|
|
36352
|
+
const open = tasks.filter((t) => {
|
|
36353
|
+
const s = t.status;
|
|
36354
|
+
return s !== "done" && s !== "completed" && s !== "cancelled";
|
|
36355
|
+
});
|
|
35642
36356
|
const done = tasks.length - open.length;
|
|
35643
36357
|
const userMessage = options?.userMessage?.trim();
|
|
35644
36358
|
let scopedOpen = open;
|
|
@@ -35760,8 +36474,8 @@ function pickNextTask(open) {
|
|
|
35760
36474
|
)[0];
|
|
35761
36475
|
}
|
|
35762
36476
|
function buildZelariReadHint(projectRoot = process.cwd()) {
|
|
35763
|
-
const planPath =
|
|
35764
|
-
if (!
|
|
36477
|
+
const planPath = join21(resolveWorkspaceRoot(projectRoot), "plan.json");
|
|
36478
|
+
if (!existsSync25(planPath)) return "";
|
|
35765
36479
|
return [
|
|
35766
36480
|
"# Council workspace detected (.zelari/) \u2014 DRAFT vault",
|
|
35767
36481
|
"`.zelari/plan.json` and `.zelari/docs/` hold **design hypotheses**, not verified product state.",
|
|
@@ -35776,10 +36490,10 @@ function safeProjectName(root) {
|
|
|
35776
36490
|
}
|
|
35777
36491
|
}
|
|
35778
36492
|
function readPackageJson(projectRoot) {
|
|
35779
|
-
const p3 =
|
|
35780
|
-
if (!
|
|
36493
|
+
const p3 = join21(projectRoot, "package.json");
|
|
36494
|
+
if (!existsSync25(p3)) return null;
|
|
35781
36495
|
try {
|
|
35782
|
-
return JSON.parse(
|
|
36496
|
+
return JSON.parse(readFileSync23(p3, "utf8"));
|
|
35783
36497
|
} catch {
|
|
35784
36498
|
return null;
|
|
35785
36499
|
}
|
|
@@ -35820,7 +36534,7 @@ function readBuildScripts(projectRoot, maxScripts = 16) {
|
|
|
35820
36534
|
function listShallow(projectRoot, maxEntries) {
|
|
35821
36535
|
const out = [];
|
|
35822
36536
|
try {
|
|
35823
|
-
const top =
|
|
36537
|
+
const top = readdirSync6(projectRoot, { withFileTypes: true }).filter(
|
|
35824
36538
|
(e) => !e.name.startsWith(".") && e.name !== "node_modules" && e.name !== "dist"
|
|
35825
36539
|
).sort((a, b) => a.name.localeCompare(b.name));
|
|
35826
36540
|
let count = 0;
|
|
@@ -35829,11 +36543,11 @@ function listShallow(projectRoot, maxEntries) {
|
|
|
35829
36543
|
out.push(`\u2026 (+${top.length - count} more)`);
|
|
35830
36544
|
break;
|
|
35831
36545
|
}
|
|
35832
|
-
const rel2 = relative(projectRoot,
|
|
36546
|
+
const rel2 = relative(projectRoot, join21(projectRoot, entry.name));
|
|
35833
36547
|
if (entry.isDirectory()) {
|
|
35834
36548
|
let inner = "";
|
|
35835
36549
|
try {
|
|
35836
|
-
const sub =
|
|
36550
|
+
const sub = readdirSync6(join21(projectRoot, entry.name), {
|
|
35837
36551
|
withFileTypes: true
|
|
35838
36552
|
}).filter((e) => !e.name.startsWith(".")).slice(0, 4).map((e) => e.name);
|
|
35839
36553
|
if (sub.length > 0)
|
|
@@ -35881,12 +36595,12 @@ var init_workspaceSummary = __esm({
|
|
|
35881
36595
|
});
|
|
35882
36596
|
|
|
35883
36597
|
// src/cli/workspace/buildLessonsSummary.ts
|
|
35884
|
-
import { existsSync as
|
|
35885
|
-
import { join as
|
|
36598
|
+
import { existsSync as existsSync26 } from "node:fs";
|
|
36599
|
+
import { join as join22 } from "node:path";
|
|
35886
36600
|
function buildLessonsSummary(projectRoot = process.cwd(), taskText) {
|
|
35887
36601
|
if (process.env["ZELARI_LESSONS"] === "0") return null;
|
|
35888
36602
|
const zelariRoot = resolveWorkspaceRoot(projectRoot);
|
|
35889
|
-
if (!
|
|
36603
|
+
if (!existsSync26(join22(zelariRoot, "lessons.jsonl"))) return null;
|
|
35890
36604
|
const lessons = recallLessons(zelariRoot, {
|
|
35891
36605
|
maxLessons: 5,
|
|
35892
36606
|
maxBytes: 2048,
|
|
@@ -35907,8 +36621,8 @@ var composeContext_exports = {};
|
|
|
35907
36621
|
__export(composeContext_exports, {
|
|
35908
36622
|
composeProjectContext: () => composeProjectContext
|
|
35909
36623
|
});
|
|
35910
|
-
import { existsSync as
|
|
35911
|
-
import { join as
|
|
36624
|
+
import { existsSync as existsSync27, readdirSync as readdirSync7, readFileSync as readFileSync24 } from "node:fs";
|
|
36625
|
+
import { join as join23 } from "node:path";
|
|
35912
36626
|
function cap2(text, max, label) {
|
|
35913
36627
|
if (!text || text.length <= max) return { text: text || "", truncated: false };
|
|
35914
36628
|
return {
|
|
@@ -35920,19 +36634,19 @@ function cap2(text, max, label) {
|
|
|
35920
36634
|
}
|
|
35921
36635
|
function buildDesignIndex(projectRoot, maxChars) {
|
|
35922
36636
|
const root = resolveWorkspaceRoot(projectRoot);
|
|
35923
|
-
if (!
|
|
36637
|
+
if (!existsSync27(root)) return "";
|
|
35924
36638
|
const lines = [
|
|
35925
36639
|
"# Design vault index (.zelari/) \u2014 HYPOTHESES only",
|
|
35926
36640
|
"Full design docs are NOT product source of truth. Open with list_files / read_file / searchDocuments if needed."
|
|
35927
36641
|
];
|
|
35928
|
-
const docsDir =
|
|
35929
|
-
if (
|
|
36642
|
+
const docsDir = join23(root, "docs");
|
|
36643
|
+
if (existsSync27(docsDir)) {
|
|
35930
36644
|
try {
|
|
35931
|
-
const docs =
|
|
36645
|
+
const docs = readdirSync7(docsDir).filter((n) => n.endsWith(".md")).slice(0, 12);
|
|
35932
36646
|
if (docs.length > 0) {
|
|
35933
36647
|
lines.push("", "## docs/ (titles only)");
|
|
35934
36648
|
for (const d of docs) lines.push(`- .zelari/docs/${d}`);
|
|
35935
|
-
if (
|
|
36649
|
+
if (readdirSync7(docsDir).filter((n) => n.endsWith(".md")).length > 12) {
|
|
35936
36650
|
lines.push("- \u2026 (more under .zelari/docs/)");
|
|
35937
36651
|
}
|
|
35938
36652
|
}
|
|
@@ -35940,14 +36654,14 @@ function buildDesignIndex(projectRoot, maxChars) {
|
|
|
35940
36654
|
}
|
|
35941
36655
|
}
|
|
35942
36656
|
for (const name of ["risks.md", "plan.json", "nfr-spec.json"]) {
|
|
35943
|
-
if (
|
|
36657
|
+
if (existsSync27(join23(root, name))) {
|
|
35944
36658
|
lines.push(`- .zelari/${name} present`);
|
|
35945
36659
|
}
|
|
35946
36660
|
}
|
|
35947
|
-
const decisionsDir =
|
|
35948
|
-
if (
|
|
36661
|
+
const decisionsDir = join23(root, "decisions");
|
|
36662
|
+
if (existsSync27(decisionsDir)) {
|
|
35949
36663
|
try {
|
|
35950
|
-
const n =
|
|
36664
|
+
const n = readdirSync7(decisionsDir).filter((f) => f.endsWith(".md")).length;
|
|
35951
36665
|
if (n > 0) lines.push(`- .zelari/decisions/ (${n} ADR file(s) \u2014 treat proposed as non-binding)`);
|
|
35952
36666
|
} catch {
|
|
35953
36667
|
}
|
|
@@ -36046,17 +36760,17 @@ function composeProjectContext(input) {
|
|
|
36046
36760
|
}
|
|
36047
36761
|
function readDurableHeadSync(projectRoot) {
|
|
36048
36762
|
try {
|
|
36049
|
-
const headPath =
|
|
36050
|
-
if (!
|
|
36051
|
-
const head = JSON.parse(
|
|
36763
|
+
const headPath = join23(projectRoot, ".zelari", "state", "HEAD.json");
|
|
36764
|
+
if (!existsSync27(headPath)) return "";
|
|
36765
|
+
const head = JSON.parse(readFileSync24(headPath, "utf8"));
|
|
36052
36766
|
if (!head?.id) return "";
|
|
36053
|
-
const metaPath =
|
|
36054
|
-
if (!
|
|
36055
|
-
const meta3 = JSON.parse(
|
|
36056
|
-
const discPath = meta3.artifactDir ?
|
|
36767
|
+
const metaPath = join23(projectRoot, ".zelari", "state", "commits", `${head.id}.json`);
|
|
36768
|
+
if (!existsSync27(metaPath)) return "";
|
|
36769
|
+
const meta3 = JSON.parse(readFileSync24(metaPath, "utf8"));
|
|
36770
|
+
const discPath = meta3.artifactDir ? join23(projectRoot, ".zelari", "state", meta3.artifactDir, "discoveries.json") : join23(projectRoot, ".zelari", "state", "artifacts", head.id, "discoveries.json");
|
|
36057
36771
|
let discoveries = [];
|
|
36058
|
-
if (
|
|
36059
|
-
discoveries = JSON.parse(
|
|
36772
|
+
if (existsSync27(discPath)) {
|
|
36773
|
+
discoveries = JSON.parse(readFileSync24(discPath, "utf8"));
|
|
36060
36774
|
}
|
|
36061
36775
|
const reusable = discoveries.filter((d) => d.reusable !== false);
|
|
36062
36776
|
const lines = [
|
|
@@ -36089,13 +36803,13 @@ var planDetect_exports = {};
|
|
|
36089
36803
|
__export(planDetect_exports, {
|
|
36090
36804
|
hasWorkspacePlan: () => hasWorkspacePlan
|
|
36091
36805
|
});
|
|
36092
|
-
import { existsSync as
|
|
36093
|
-
import { join as
|
|
36806
|
+
import { existsSync as existsSync28, readFileSync as readFileSync25 } from "node:fs";
|
|
36807
|
+
import { join as join24 } from "node:path";
|
|
36094
36808
|
function hasWorkspacePlan(projectRoot = process.cwd()) {
|
|
36095
|
-
const planPath =
|
|
36096
|
-
if (!
|
|
36809
|
+
const planPath = join24(resolveWorkspaceRoot(projectRoot), "plan.json");
|
|
36810
|
+
if (!existsSync28(planPath)) return false;
|
|
36097
36811
|
try {
|
|
36098
|
-
const parsed = JSON.parse(
|
|
36812
|
+
const parsed = JSON.parse(readFileSync25(planPath, "utf8"));
|
|
36099
36813
|
return Array.isArray(parsed.phases) && parsed.phases.length > 0;
|
|
36100
36814
|
} catch {
|
|
36101
36815
|
return false;
|
|
@@ -36144,333 +36858,6 @@ var init_loadDurableContext = __esm({
|
|
|
36144
36858
|
}
|
|
36145
36859
|
});
|
|
36146
36860
|
|
|
36147
|
-
// src/cli/workspace/storage.ts
|
|
36148
|
-
var storage_exports = {};
|
|
36149
|
-
__export(storage_exports, {
|
|
36150
|
-
Storage: () => Storage,
|
|
36151
|
-
parseFrontmatter: () => parseFrontmatter,
|
|
36152
|
-
parseYaml: () => parseYaml,
|
|
36153
|
-
serializeFrontmatter: () => serializeFrontmatter,
|
|
36154
|
-
serializeYaml: () => serializeYaml,
|
|
36155
|
-
workspaceMutex: () => workspaceMutex
|
|
36156
|
-
});
|
|
36157
|
-
import {
|
|
36158
|
-
readFileSync as readFileSync24,
|
|
36159
|
-
writeFileSync as writeFileSync15,
|
|
36160
|
-
existsSync as existsSync27,
|
|
36161
|
-
mkdirSync as mkdirSync13,
|
|
36162
|
-
readdirSync as readdirSync7,
|
|
36163
|
-
renameSync as renameSync2
|
|
36164
|
-
} from "node:fs";
|
|
36165
|
-
import { dirname as dirname4, join as join23 } from "node:path";
|
|
36166
|
-
function parseFrontmatter(md) {
|
|
36167
|
-
const m = FRONTMATTER_RE.exec(md);
|
|
36168
|
-
if (!m) return { meta: {}, body: md };
|
|
36169
|
-
const meta3 = parseYaml(m[1]);
|
|
36170
|
-
const body = m[2];
|
|
36171
|
-
return { meta: meta3, body };
|
|
36172
|
-
}
|
|
36173
|
-
function serializeFrontmatter(meta3, body) {
|
|
36174
|
-
const yamlStr = serializeYaml(meta3);
|
|
36175
|
-
return `---
|
|
36176
|
-
${yamlStr}
|
|
36177
|
-
---
|
|
36178
|
-
${body}`;
|
|
36179
|
-
}
|
|
36180
|
-
function parseYaml(input) {
|
|
36181
|
-
const lines = input.split(/\r?\n/);
|
|
36182
|
-
const ctx = { lines, i: 0 };
|
|
36183
|
-
return parseNode(ctx, 0);
|
|
36184
|
-
}
|
|
36185
|
-
function parseNode(ctx, indent) {
|
|
36186
|
-
while (ctx.i < ctx.lines.length) {
|
|
36187
|
-
const line2 = ctx.lines[ctx.i];
|
|
36188
|
-
if (line2.trim() === "" || line2.trim().startsWith("#")) {
|
|
36189
|
-
ctx.i++;
|
|
36190
|
-
continue;
|
|
36191
|
-
}
|
|
36192
|
-
break;
|
|
36193
|
-
}
|
|
36194
|
-
if (ctx.i >= ctx.lines.length) return null;
|
|
36195
|
-
const line = ctx.lines[ctx.i];
|
|
36196
|
-
const lineIndent = countIndent(line);
|
|
36197
|
-
if (/^\s*-\s+/.test(line)) {
|
|
36198
|
-
return parseBlockSequence(ctx, indent);
|
|
36199
|
-
}
|
|
36200
|
-
if (/^\s*\[.*\]\s*$/.test(line)) {
|
|
36201
|
-
const flow = line.trim().replace(/^\[/, "").replace(/\]$/, "");
|
|
36202
|
-
return parseFlowSequence(flow);
|
|
36203
|
-
}
|
|
36204
|
-
if (/^\s*\{.*\}\s*$/.test(line)) {
|
|
36205
|
-
const flow = line.trim().replace(/^\{/, "").replace(/\}$/, "");
|
|
36206
|
-
return parseFlowMap(flow);
|
|
36207
|
-
}
|
|
36208
|
-
return parseBlockMap(ctx, indent);
|
|
36209
|
-
}
|
|
36210
|
-
function parseBlockMap(ctx, indent) {
|
|
36211
|
-
const out = {};
|
|
36212
|
-
while (ctx.i < ctx.lines.length) {
|
|
36213
|
-
const line = ctx.lines[ctx.i];
|
|
36214
|
-
if (line.trim() === "" || line.trim().startsWith("#")) {
|
|
36215
|
-
ctx.i++;
|
|
36216
|
-
continue;
|
|
36217
|
-
}
|
|
36218
|
-
const lineIndent = countIndent(line);
|
|
36219
|
-
if (lineIndent < indent) break;
|
|
36220
|
-
if (lineIndent > indent) {
|
|
36221
|
-
ctx.i++;
|
|
36222
|
-
continue;
|
|
36223
|
-
}
|
|
36224
|
-
const m = /^([^:]+):\s*(.*)$/.exec(line);
|
|
36225
|
-
if (!m) {
|
|
36226
|
-
ctx.i++;
|
|
36227
|
-
continue;
|
|
36228
|
-
}
|
|
36229
|
-
const key = m[1].trim();
|
|
36230
|
-
const valuePart = m[2].trim();
|
|
36231
|
-
if (valuePart === "" || valuePart === "|" || valuePart === ">") {
|
|
36232
|
-
ctx.i++;
|
|
36233
|
-
const nested = parseNode(ctx, indent + 2);
|
|
36234
|
-
out[key] = nested;
|
|
36235
|
-
} else {
|
|
36236
|
-
if (valuePart.startsWith("[")) {
|
|
36237
|
-
out[key] = parseFlowSequence(stripFlow(valuePart, "[", "]"));
|
|
36238
|
-
} else if (valuePart.startsWith("{")) {
|
|
36239
|
-
out[key] = parseFlowMap(stripFlow(valuePart, "{", "}"));
|
|
36240
|
-
} else {
|
|
36241
|
-
out[key] = parseScalar(valuePart);
|
|
36242
|
-
}
|
|
36243
|
-
ctx.i++;
|
|
36244
|
-
}
|
|
36245
|
-
}
|
|
36246
|
-
return out;
|
|
36247
|
-
}
|
|
36248
|
-
function parseBlockSequence(ctx, indent) {
|
|
36249
|
-
const out = [];
|
|
36250
|
-
while (ctx.i < ctx.lines.length) {
|
|
36251
|
-
const line = ctx.lines[ctx.i];
|
|
36252
|
-
if (line.trim() === "") {
|
|
36253
|
-
ctx.i++;
|
|
36254
|
-
continue;
|
|
36255
|
-
}
|
|
36256
|
-
const lineIndent = countIndent(line);
|
|
36257
|
-
if (lineIndent < indent) break;
|
|
36258
|
-
if (lineIndent > indent) break;
|
|
36259
|
-
const m = /^-\s*(.*)$/.exec(line);
|
|
36260
|
-
if (!m) break;
|
|
36261
|
-
const rest = m[1];
|
|
36262
|
-
if (rest === "") {
|
|
36263
|
-
ctx.i++;
|
|
36264
|
-
out.push(parseNode(ctx, indent + 2));
|
|
36265
|
-
} else if (rest.startsWith("[") || rest.startsWith("{")) {
|
|
36266
|
-
let buffer = rest;
|
|
36267
|
-
let depthSq = (buffer.match(/\[/g) || []).length - (buffer.match(/\]/g) || []).length;
|
|
36268
|
-
let depthCu = (buffer.match(/\{/g) || []).length - (buffer.match(/\}/g) || []).length;
|
|
36269
|
-
while ((depthSq > 0 || depthCu > 0) && ctx.i + 1 < ctx.lines.length) {
|
|
36270
|
-
ctx.i++;
|
|
36271
|
-
const next = ctx.lines[ctx.i].trim();
|
|
36272
|
-
buffer += " " + next;
|
|
36273
|
-
depthSq = (buffer.match(/\[/g) || []).length - (buffer.match(/\]/g) || []).length;
|
|
36274
|
-
depthCu = (buffer.match(/\{/g) || []).length - (buffer.match(/\}/g) || []).length;
|
|
36275
|
-
}
|
|
36276
|
-
if (buffer.startsWith("[")) {
|
|
36277
|
-
out.push(parseFlowSequence(buffer.slice(1).replace(/\]$/, "")));
|
|
36278
|
-
} else {
|
|
36279
|
-
out.push(parseFlowMap(buffer.slice(1).replace(/\}$/, "")));
|
|
36280
|
-
}
|
|
36281
|
-
ctx.i++;
|
|
36282
|
-
} else if (rest.includes(":")) {
|
|
36283
|
-
ctx.i++;
|
|
36284
|
-
const mapCtx = { lines: [" ".repeat(indent + 2) + rest, ...ctx.lines.slice(ctx.i)], i: 0 };
|
|
36285
|
-
const val = parseBlockMap(mapCtx, indent + 2);
|
|
36286
|
-
ctx.i += mapCtx.i - 1;
|
|
36287
|
-
out.push(val);
|
|
36288
|
-
} else {
|
|
36289
|
-
out.push(parseScalar(rest));
|
|
36290
|
-
ctx.i++;
|
|
36291
|
-
}
|
|
36292
|
-
}
|
|
36293
|
-
return out;
|
|
36294
|
-
}
|
|
36295
|
-
function parseFlowSequence(input) {
|
|
36296
|
-
const parts = splitFlow(input);
|
|
36297
|
-
return parts.map((p3) => {
|
|
36298
|
-
const trimmed = p3.trim();
|
|
36299
|
-
if (trimmed.startsWith("{")) {
|
|
36300
|
-
return parseFlowMap(stripFlow(trimmed, "{", "}"));
|
|
36301
|
-
}
|
|
36302
|
-
return parseScalar(trimmed);
|
|
36303
|
-
});
|
|
36304
|
-
}
|
|
36305
|
-
function stripFlow(s, open, close) {
|
|
36306
|
-
let out = s.trim();
|
|
36307
|
-
if (out.startsWith(open)) out = out.slice(1);
|
|
36308
|
-
if (out.endsWith(close)) out = out.slice(0, -1);
|
|
36309
|
-
return out;
|
|
36310
|
-
}
|
|
36311
|
-
function parseFlowMap(input) {
|
|
36312
|
-
const parts = splitFlow(input);
|
|
36313
|
-
const out = {};
|
|
36314
|
-
for (const p3 of parts) {
|
|
36315
|
-
const colonIdx = p3.indexOf(":");
|
|
36316
|
-
if (colonIdx < 0) continue;
|
|
36317
|
-
const key = p3.slice(0, colonIdx).trim();
|
|
36318
|
-
const value = p3.slice(colonIdx + 1).trim();
|
|
36319
|
-
out[key] = parseScalar(value);
|
|
36320
|
-
}
|
|
36321
|
-
return out;
|
|
36322
|
-
}
|
|
36323
|
-
function splitFlow(input) {
|
|
36324
|
-
const out = [];
|
|
36325
|
-
let depthSq = 0, depthCu = 0, depthQu = 0;
|
|
36326
|
-
let buffer = "";
|
|
36327
|
-
for (let i = 0; i < input.length; i++) {
|
|
36328
|
-
const c = input[i];
|
|
36329
|
-
if (c === '"' || c === "'") {
|
|
36330
|
-
depthQu = depthQu === 0 ? depthQu + 1 : 0;
|
|
36331
|
-
buffer += c;
|
|
36332
|
-
} else if (depthQu === 0) {
|
|
36333
|
-
if (c === "[") depthSq++;
|
|
36334
|
-
else if (c === "]") depthSq--;
|
|
36335
|
-
else if (c === "{") depthCu++;
|
|
36336
|
-
else if (c === "}") depthCu--;
|
|
36337
|
-
else if (c === "," && depthSq === 0 && depthCu === 0) {
|
|
36338
|
-
out.push(buffer);
|
|
36339
|
-
buffer = "";
|
|
36340
|
-
continue;
|
|
36341
|
-
}
|
|
36342
|
-
buffer += c;
|
|
36343
|
-
} else {
|
|
36344
|
-
buffer += c;
|
|
36345
|
-
}
|
|
36346
|
-
}
|
|
36347
|
-
if (buffer.trim()) out.push(buffer);
|
|
36348
|
-
return out;
|
|
36349
|
-
}
|
|
36350
|
-
function parseScalar(s) {
|
|
36351
|
-
if (s === "" || s === "null" || s === "~") return null;
|
|
36352
|
-
if (VALID_SCALARS.test(s)) return s.toLowerCase() === "true";
|
|
36353
|
-
if (/^-?\d+(\.\d+)?$/.test(s)) return Number(s);
|
|
36354
|
-
if (s.startsWith('"') && s.endsWith('"') || s.startsWith("'") && s.endsWith("'")) {
|
|
36355
|
-
return s.slice(1, -1);
|
|
36356
|
-
}
|
|
36357
|
-
return s;
|
|
36358
|
-
}
|
|
36359
|
-
function serializeYaml(value, indent = 0) {
|
|
36360
|
-
if (value === null || value === void 0) return "";
|
|
36361
|
-
if (typeof value === "string") {
|
|
36362
|
-
if (/[:#\n\[\]\{\},&*!|>'"%@`]/.test(value)) {
|
|
36363
|
-
return JSON.stringify(value);
|
|
36364
|
-
}
|
|
36365
|
-
return value;
|
|
36366
|
-
}
|
|
36367
|
-
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
36368
|
-
if (Array.isArray(value)) {
|
|
36369
|
-
if (value.length === 0) return "[]";
|
|
36370
|
-
if (value.every((v) => v === null || typeof v !== "object")) {
|
|
36371
|
-
return `[${value.map(serializeScalarInline).join(", ")}]`;
|
|
36372
|
-
}
|
|
36373
|
-
return `[${value.map((v) => "{" + serializeInlineObject(v) + "}").join(", ")}]`;
|
|
36374
|
-
}
|
|
36375
|
-
if (typeof value === "object") {
|
|
36376
|
-
const entries = Object.entries(value).filter(([, v]) => v !== void 0);
|
|
36377
|
-
return entries.map(([k, v]) => {
|
|
36378
|
-
if (v === null || v === void 0) return `${k}:`;
|
|
36379
|
-
if (typeof v === "string" || typeof v === "number" || typeof v === "boolean") {
|
|
36380
|
-
return `${k}: ${serializeScalarInline(v)}`;
|
|
36381
|
-
}
|
|
36382
|
-
if (Array.isArray(v)) {
|
|
36383
|
-
if (v.length === 0) return `${k}: []`;
|
|
36384
|
-
if (v.every((x) => x === null || typeof x !== "object")) {
|
|
36385
|
-
return `${k}: [${v.map(serializeScalarInline).join(", ")}]`;
|
|
36386
|
-
}
|
|
36387
|
-
return `${k}: [${v.map((x) => "{" + serializeInlineObject(x) + "}").join(", ")}]`;
|
|
36388
|
-
}
|
|
36389
|
-
return `${k}:
|
|
36390
|
-
${serializeYaml(v, indent + 2)}`;
|
|
36391
|
-
}).map((line) => `${" ".repeat(indent)}${line}`).join("\n");
|
|
36392
|
-
}
|
|
36393
|
-
return String(value);
|
|
36394
|
-
}
|
|
36395
|
-
function serializeScalarInline(v) {
|
|
36396
|
-
if (typeof v === "string" && /[:#\n\[\]\{\},&*!|>'"%@`]/.test(v)) return JSON.stringify(v);
|
|
36397
|
-
return String(v);
|
|
36398
|
-
}
|
|
36399
|
-
function serializeInlineObject(v) {
|
|
36400
|
-
if (v === null || typeof v !== "object" || Array.isArray(v)) {
|
|
36401
|
-
return serializeScalarInline(v);
|
|
36402
|
-
}
|
|
36403
|
-
const entries = Object.entries(v).filter(([, val]) => val !== void 0);
|
|
36404
|
-
return entries.map(([k, val]) => `${k}: ${serializeYaml(val)}`).join(", ");
|
|
36405
|
-
}
|
|
36406
|
-
function countIndent(line) {
|
|
36407
|
-
let i = 0;
|
|
36408
|
-
while (i < line.length && line[i] === " ") i++;
|
|
36409
|
-
return i;
|
|
36410
|
-
}
|
|
36411
|
-
var FRONTMATTER_RE, VALID_SCALARS, Storage, KeyedMutex, workspaceMutex;
|
|
36412
|
-
var init_storage = __esm({
|
|
36413
|
-
"src/cli/workspace/storage.ts"() {
|
|
36414
|
-
"use strict";
|
|
36415
|
-
FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/;
|
|
36416
|
-
VALID_SCALARS = /^(true|false|null|~)$/i;
|
|
36417
|
-
Storage = class {
|
|
36418
|
-
/** Read a Markdown file with frontmatter. Throws if not found. */
|
|
36419
|
-
read(path53) {
|
|
36420
|
-
if (!existsSync27(path53)) {
|
|
36421
|
-
throw new Error(`File not found: ${path53}`);
|
|
36422
|
-
}
|
|
36423
|
-
const md = readFileSync24(path53, "utf8");
|
|
36424
|
-
return parseFrontmatter(md);
|
|
36425
|
-
}
|
|
36426
|
-
/** Read a Markdown file; returns null if not found. */
|
|
36427
|
-
readIfExists(path53) {
|
|
36428
|
-
if (!existsSync27(path53)) return null;
|
|
36429
|
-
return this.read(path53);
|
|
36430
|
-
}
|
|
36431
|
-
/**
|
|
36432
|
-
* Write a Markdown file atomically (tmp + rename). Creates parent dirs.
|
|
36433
|
-
* The meta object is serialized as YAML frontmatter; body as Markdown.
|
|
36434
|
-
*/
|
|
36435
|
-
write(path53, meta3, body) {
|
|
36436
|
-
mkdirSync13(dirname4(path53), { recursive: true });
|
|
36437
|
-
const tmp = path53 + ".tmp-" + process.pid;
|
|
36438
|
-
const md = serializeFrontmatter(meta3, body);
|
|
36439
|
-
writeFileSync15(tmp, md, "utf8");
|
|
36440
|
-
renameSync2(tmp, path53);
|
|
36441
|
-
}
|
|
36442
|
-
/** List all .md files in a directory (non-recursive). */
|
|
36443
|
-
listMarkdown(dir) {
|
|
36444
|
-
if (!existsSync27(dir)) return [];
|
|
36445
|
-
return readdirSync7(dir).filter((f) => f.endsWith(".md") && !f.startsWith(".")).map((f) => join23(dir, f));
|
|
36446
|
-
}
|
|
36447
|
-
};
|
|
36448
|
-
KeyedMutex = class {
|
|
36449
|
-
chains = /* @__PURE__ */ new Map();
|
|
36450
|
-
async run(key, fn) {
|
|
36451
|
-
const prev2 = this.chains.get(key) ?? Promise.resolve();
|
|
36452
|
-
let release = () => {
|
|
36453
|
-
};
|
|
36454
|
-
const next = new Promise((resolve3) => {
|
|
36455
|
-
release = resolve3;
|
|
36456
|
-
});
|
|
36457
|
-
const chained = prev2.then(() => next);
|
|
36458
|
-
this.chains.set(key, chained);
|
|
36459
|
-
await prev2;
|
|
36460
|
-
try {
|
|
36461
|
-
return await fn();
|
|
36462
|
-
} finally {
|
|
36463
|
-
release();
|
|
36464
|
-
if (this.chains.get(key) === chained) {
|
|
36465
|
-
this.chains.delete(key);
|
|
36466
|
-
}
|
|
36467
|
-
}
|
|
36468
|
-
}
|
|
36469
|
-
};
|
|
36470
|
-
workspaceMutex = new KeyedMutex();
|
|
36471
|
-
}
|
|
36472
|
-
});
|
|
36473
|
-
|
|
36474
36861
|
// src/cli/workspace/stubs.ts
|
|
36475
36862
|
var stubs_exports = {};
|
|
36476
36863
|
__export(stubs_exports, {
|
|
@@ -36481,14 +36868,14 @@ __export(stubs_exports, {
|
|
|
36481
36868
|
resolveWorkspaceRoot: () => resolveWorkspaceRoot
|
|
36482
36869
|
});
|
|
36483
36870
|
import {
|
|
36484
|
-
existsSync as
|
|
36871
|
+
existsSync as existsSync29,
|
|
36485
36872
|
readdirSync as readdirSync8,
|
|
36486
|
-
writeFileSync as
|
|
36487
|
-
readFileSync as
|
|
36488
|
-
mkdirSync as
|
|
36489
|
-
renameSync as
|
|
36873
|
+
writeFileSync as writeFileSync17,
|
|
36874
|
+
readFileSync as readFileSync26,
|
|
36875
|
+
mkdirSync as mkdirSync15,
|
|
36876
|
+
renameSync as renameSync4
|
|
36490
36877
|
} from "node:fs";
|
|
36491
|
-
import { join as
|
|
36878
|
+
import { join as join25, basename as basename2, dirname as dirname6, relative as relative2 } from "node:path";
|
|
36492
36879
|
function createWorkspaceContext(projectRoot = process.cwd()) {
|
|
36493
36880
|
const rootDir = resolveWorkspaceRoot(projectRoot);
|
|
36494
36881
|
return {
|
|
@@ -36498,19 +36885,21 @@ function createWorkspaceContext(projectRoot = process.cwd()) {
|
|
|
36498
36885
|
};
|
|
36499
36886
|
}
|
|
36500
36887
|
function planJsonPath(ctx) {
|
|
36501
|
-
return
|
|
36888
|
+
return join25(ctx.rootDir, "plan.json");
|
|
36502
36889
|
}
|
|
36503
36890
|
function readPlan(ctx) {
|
|
36504
36891
|
const jsonPath = planJsonPath(ctx);
|
|
36505
|
-
if (
|
|
36892
|
+
if (existsSync29(jsonPath)) {
|
|
36506
36893
|
try {
|
|
36507
36894
|
const parsed = JSON.parse(
|
|
36508
|
-
|
|
36895
|
+
readFileSync26(jsonPath, "utf8")
|
|
36509
36896
|
);
|
|
36897
|
+
const { phases, tasks, milestones, ...root } = parsed;
|
|
36510
36898
|
return {
|
|
36511
|
-
phases: Array.isArray(
|
|
36512
|
-
tasks: Array.isArray(
|
|
36513
|
-
milestones: Array.isArray(
|
|
36899
|
+
phases: Array.isArray(phases) ? phases : [],
|
|
36900
|
+
tasks: Array.isArray(tasks) ? tasks : [],
|
|
36901
|
+
milestones: Array.isArray(milestones) ? milestones : [],
|
|
36902
|
+
root
|
|
36514
36903
|
};
|
|
36515
36904
|
} catch {
|
|
36516
36905
|
}
|
|
@@ -36527,10 +36916,23 @@ function readPlan(ctx) {
|
|
|
36527
36916
|
}
|
|
36528
36917
|
function writePlan(ctx, summary) {
|
|
36529
36918
|
const jsonPath = planJsonPath(ctx);
|
|
36530
|
-
|
|
36919
|
+
mkdirSync15(dirname6(jsonPath), { recursive: true });
|
|
36531
36920
|
const tmp = jsonPath + ".tmp-" + process.pid;
|
|
36532
|
-
|
|
36533
|
-
|
|
36921
|
+
writeFileSync17(
|
|
36922
|
+
tmp,
|
|
36923
|
+
JSON.stringify(
|
|
36924
|
+
{
|
|
36925
|
+
...summary.root ?? {},
|
|
36926
|
+
phases: summary.phases,
|
|
36927
|
+
tasks: summary.tasks,
|
|
36928
|
+
milestones: summary.milestones
|
|
36929
|
+
},
|
|
36930
|
+
null,
|
|
36931
|
+
2
|
|
36932
|
+
),
|
|
36933
|
+
"utf8"
|
|
36934
|
+
);
|
|
36935
|
+
renameSync4(tmp, jsonPath);
|
|
36534
36936
|
const mdPath = workspaceFile(ctx.rootDir, "plan");
|
|
36535
36937
|
const summaryMeta = {
|
|
36536
36938
|
kind: "plan-summary",
|
|
@@ -36596,8 +36998,8 @@ function renderPlanBody(summary) {
|
|
|
36596
36998
|
return lines.join("\n");
|
|
36597
36999
|
}
|
|
36598
37000
|
function nextAdrId(ctx) {
|
|
36599
|
-
const decisionsDir =
|
|
36600
|
-
if (!
|
|
37001
|
+
const decisionsDir = join25(ctx.rootDir, "decisions");
|
|
37002
|
+
if (!existsSync29(decisionsDir)) return "001";
|
|
36601
37003
|
const existing = readdirSync8(decisionsDir).filter((f) => f.endsWith(".md")).map((f) => f.match(/^(\d+)-/)).filter((m) => !!m).map((m) => parseInt(m[1], 10));
|
|
36602
37004
|
const max = existing.length === 0 ? 0 : Math.max(...existing);
|
|
36603
37005
|
return String(max + 1).padStart(3, "0");
|
|
@@ -36639,7 +37041,7 @@ function addTaskRecord(ctx, summary, phaseId, t, options) {
|
|
|
36639
37041
|
status: "pending",
|
|
36640
37042
|
priority: t.priority
|
|
36641
37043
|
});
|
|
36642
|
-
const taskPath =
|
|
37044
|
+
const taskPath = join25(ctx.rootDir, "plan-tasks", `${id}.md`);
|
|
36643
37045
|
const meta3 = {
|
|
36644
37046
|
kind: "task",
|
|
36645
37047
|
id,
|
|
@@ -36681,7 +37083,7 @@ function addMilestoneRecord(ctx, summary, input) {
|
|
|
36681
37083
|
dueDate: input.dueDate,
|
|
36682
37084
|
targetVersion: version2
|
|
36683
37085
|
});
|
|
36684
|
-
const path53 =
|
|
37086
|
+
const path53 = join25(ctx.rootDir, "milestones", `${id}.md`);
|
|
36685
37087
|
const meta3 = {
|
|
36686
37088
|
kind: "milestone",
|
|
36687
37089
|
id,
|
|
@@ -36979,8 +37381,8 @@ function createNfrSpecStub(ctx) {
|
|
|
36979
37381
|
},
|
|
36980
37382
|
planFeatureKeywords: Array.isArray(args["planFeatureKeywords"]) ? args["planFeatureKeywords"] : void 0
|
|
36981
37383
|
};
|
|
36982
|
-
const outPath =
|
|
36983
|
-
|
|
37384
|
+
const outPath = join25(ctx.rootDir, "nfr-spec.json");
|
|
37385
|
+
writeFileSync17(outPath, JSON.stringify(spec, null, 2), "utf8");
|
|
36984
37386
|
return `NFR spec written to nfr-spec.json (${targets.length} target(s)).`;
|
|
36985
37387
|
});
|
|
36986
37388
|
}
|
|
@@ -37043,18 +37445,18 @@ function searchDocumentsStub(ctx) {
|
|
|
37043
37445
|
(w) => w.length >= 3 && w !== "or" && w !== "and" && w !== "the"
|
|
37044
37446
|
);
|
|
37045
37447
|
const files = [
|
|
37046
|
-
...ctx.storage.listMarkdown(
|
|
37047
|
-
...ctx.storage.listMarkdown(
|
|
37048
|
-
...ctx.storage.listMarkdown(
|
|
37049
|
-
...ctx.storage.listMarkdown(
|
|
37050
|
-
...ctx.storage.listMarkdown(
|
|
37448
|
+
...ctx.storage.listMarkdown(join25(ctx.rootDir, "decisions")),
|
|
37449
|
+
...ctx.storage.listMarkdown(join25(ctx.rootDir, "docs")),
|
|
37450
|
+
...ctx.storage.listMarkdown(join25(ctx.rootDir, "reviews")),
|
|
37451
|
+
...ctx.storage.listMarkdown(join25(ctx.rootDir, "plan-tasks")),
|
|
37452
|
+
...ctx.storage.listMarkdown(join25(ctx.rootDir, "milestones")),
|
|
37051
37453
|
workspaceFile(ctx.rootDir, "plan"),
|
|
37052
37454
|
workspaceFile(ctx.rootDir, "risks")
|
|
37053
37455
|
];
|
|
37054
37456
|
const results = [];
|
|
37055
37457
|
for (const file2 of files) {
|
|
37056
|
-
if (!
|
|
37057
|
-
const raw =
|
|
37458
|
+
if (!existsSync29(file2)) continue;
|
|
37459
|
+
const raw = readFileSync26(file2, "utf8");
|
|
37058
37460
|
const content = raw.toLowerCase();
|
|
37059
37461
|
let idx = -1;
|
|
37060
37462
|
let matchLen = 0;
|
|
@@ -37105,9 +37507,9 @@ function linkDocumentsStub(ctx) {
|
|
|
37105
37507
|
const toId = args["toId"] ?? args["targetId"] ?? args["targetPathOrTitle"];
|
|
37106
37508
|
if (!fromId || !toId) return "linkDocuments requires fromId and toId.";
|
|
37107
37509
|
const allFiles = [
|
|
37108
|
-
...ctx.storage.listMarkdown(
|
|
37109
|
-
...ctx.storage.listMarkdown(
|
|
37110
|
-
...ctx.storage.listMarkdown(
|
|
37510
|
+
...ctx.storage.listMarkdown(join25(ctx.rootDir, "decisions")),
|
|
37511
|
+
...ctx.storage.listMarkdown(join25(ctx.rootDir, "docs")),
|
|
37512
|
+
...ctx.storage.listMarkdown(join25(ctx.rootDir, "reviews"))
|
|
37111
37513
|
];
|
|
37112
37514
|
const source = allFiles.find((f) => {
|
|
37113
37515
|
try {
|
|
@@ -37138,9 +37540,9 @@ function getDocumentBacklinksStub(ctx) {
|
|
|
37138
37540
|
const targetId = args["targetId"] ?? args["id"];
|
|
37139
37541
|
if (!targetId) return "getDocumentBacklinks requires targetId.";
|
|
37140
37542
|
const allFiles = [
|
|
37141
|
-
...ctx.storage.listMarkdown(
|
|
37142
|
-
...ctx.storage.listMarkdown(
|
|
37143
|
-
...ctx.storage.listMarkdown(
|
|
37543
|
+
...ctx.storage.listMarkdown(join25(ctx.rootDir, "decisions")),
|
|
37544
|
+
...ctx.storage.listMarkdown(join25(ctx.rootDir, "docs")),
|
|
37545
|
+
...ctx.storage.listMarkdown(join25(ctx.rootDir, "reviews"))
|
|
37144
37546
|
];
|
|
37145
37547
|
const backlinks = [];
|
|
37146
37548
|
for (const file2 of allFiles) {
|
|
@@ -37235,7 +37637,7 @@ __export(updater_exports, {
|
|
|
37235
37637
|
});
|
|
37236
37638
|
import { createRequire as createRequire2 } from "node:module";
|
|
37237
37639
|
import { spawn as spawn8 } from "node:child_process";
|
|
37238
|
-
import { existsSync as
|
|
37640
|
+
import { existsSync as existsSync30 } from "node:fs";
|
|
37239
37641
|
import path31 from "node:path";
|
|
37240
37642
|
import { fileURLToPath } from "node:url";
|
|
37241
37643
|
function resolveBundledNpmCli(execPath = process.execPath) {
|
|
@@ -37248,7 +37650,7 @@ function resolveBundledNpmCli(execPath = process.execPath) {
|
|
|
37248
37650
|
];
|
|
37249
37651
|
for (const candidate of candidates) {
|
|
37250
37652
|
try {
|
|
37251
|
-
if (
|
|
37653
|
+
if (existsSync30(candidate)) return candidate;
|
|
37252
37654
|
} catch {
|
|
37253
37655
|
}
|
|
37254
37656
|
}
|
|
@@ -37548,23 +37950,23 @@ var init_mcpClient = __esm({
|
|
|
37548
37950
|
|
|
37549
37951
|
// src/cli/mcp/mcpConfigIo.ts
|
|
37550
37952
|
import {
|
|
37551
|
-
existsSync as
|
|
37552
|
-
mkdirSync as
|
|
37553
|
-
readFileSync as
|
|
37554
|
-
writeFileSync as
|
|
37953
|
+
existsSync as existsSync31,
|
|
37954
|
+
mkdirSync as mkdirSync16,
|
|
37955
|
+
readFileSync as readFileSync27,
|
|
37956
|
+
writeFileSync as writeFileSync18
|
|
37555
37957
|
} from "node:fs";
|
|
37556
|
-
import { dirname as
|
|
37958
|
+
import { dirname as dirname7, join as join26 } from "node:path";
|
|
37557
37959
|
import { homedir as homedir10 } from "node:os";
|
|
37558
37960
|
function getUserMcpPath() {
|
|
37559
|
-
return
|
|
37961
|
+
return join26(homedir10(), ".zelari-code", "mcp.json");
|
|
37560
37962
|
}
|
|
37561
37963
|
function getProjectMcpPath(projectRoot) {
|
|
37562
|
-
return
|
|
37964
|
+
return join26(projectRoot, ".zelari", "mcp.json");
|
|
37563
37965
|
}
|
|
37564
37966
|
function readFile2(path53) {
|
|
37565
|
-
if (!
|
|
37967
|
+
if (!existsSync31(path53)) return {};
|
|
37566
37968
|
try {
|
|
37567
|
-
const parsed = JSON.parse(
|
|
37969
|
+
const parsed = JSON.parse(readFileSync27(path53, "utf8"));
|
|
37568
37970
|
const out = {};
|
|
37569
37971
|
for (const [name, cfg] of Object.entries(parsed.mcpServers ?? {})) {
|
|
37570
37972
|
if (!cfg || typeof cfg.command !== "string" || !cfg.command.trim()) continue;
|
|
@@ -37581,9 +37983,9 @@ function readFile2(path53) {
|
|
|
37581
37983
|
}
|
|
37582
37984
|
}
|
|
37583
37985
|
function writeFile(path53, servers) {
|
|
37584
|
-
|
|
37986
|
+
mkdirSync16(dirname7(path53), { recursive: true });
|
|
37585
37987
|
const body = { mcpServers: servers };
|
|
37586
|
-
|
|
37988
|
+
writeFileSync18(path53, `${JSON.stringify(body, null, 2)}
|
|
37587
37989
|
`, "utf8");
|
|
37588
37990
|
}
|
|
37589
37991
|
function listMcpServers(projectRoot) {
|
|
@@ -37792,22 +38194,22 @@ __export(mcpManager_exports, {
|
|
|
37792
38194
|
readMcpConfig: () => readMcpConfig,
|
|
37793
38195
|
registerMcpTools: () => registerMcpTools
|
|
37794
38196
|
});
|
|
37795
|
-
import { existsSync as
|
|
37796
|
-
import { join as
|
|
38197
|
+
import { existsSync as existsSync32, readFileSync as readFileSync28 } from "node:fs";
|
|
38198
|
+
import { join as join27 } from "node:path";
|
|
37797
38199
|
import { homedir as homedir11 } from "node:os";
|
|
37798
38200
|
function readMcpConfig(projectRoot = process.cwd(), opts) {
|
|
37799
38201
|
const merged = {};
|
|
37800
38202
|
const paths = [];
|
|
37801
38203
|
if (process.env["ZELARI_MCP_USER"] !== "0") {
|
|
37802
|
-
paths.push(
|
|
38204
|
+
paths.push(join27(homedir11(), ".zelari-code", "mcp.json"));
|
|
37803
38205
|
}
|
|
37804
38206
|
if (!opts?.skipProjectMcp) {
|
|
37805
|
-
paths.push(
|
|
38207
|
+
paths.push(join27(projectRoot, ".zelari", "mcp.json"));
|
|
37806
38208
|
}
|
|
37807
38209
|
for (const p3 of paths) {
|
|
37808
|
-
if (!
|
|
38210
|
+
if (!existsSync32(p3)) continue;
|
|
37809
38211
|
try {
|
|
37810
|
-
const parsed = JSON.parse(
|
|
38212
|
+
const parsed = JSON.parse(readFileSync28(p3, "utf8"));
|
|
37811
38213
|
for (const [name, cfg] of Object.entries(parsed.mcpServers ?? {})) {
|
|
37812
38214
|
if (!cfg || typeof cfg.command !== "string" || cfg.command.length === 0) continue;
|
|
37813
38215
|
merged[name] = cfg;
|
|
@@ -37821,7 +38223,7 @@ async function ensureLoaded(projectRoot) {
|
|
|
37821
38223
|
if (state2.loaded) return;
|
|
37822
38224
|
state2.loaded = true;
|
|
37823
38225
|
const trusted = isFolderTrusted(projectRoot);
|
|
37824
|
-
if (!trusted &&
|
|
38226
|
+
if (!trusted && existsSync32(join27(projectRoot, ".zelari", "mcp.json"))) {
|
|
37825
38227
|
state2.warnings.push(
|
|
37826
38228
|
"[mcp] project .zelari/mcp.json ignored \u2014 folder not trusted (run /trust or `zelari-code --trust` to enable project MCP)"
|
|
37827
38229
|
);
|
|
@@ -38046,13 +38448,13 @@ __export(agentsMd_exports, {
|
|
|
38046
38448
|
serializeAgentsMd: () => serializeAgentsMd,
|
|
38047
38449
|
updateAgentsMd: () => updateAgentsMd
|
|
38048
38450
|
});
|
|
38049
|
-
import { existsSync as
|
|
38451
|
+
import { existsSync as existsSync33, readFileSync as readFileSync29, writeFileSync as writeFileSync19 } from "node:fs";
|
|
38050
38452
|
import { createHash as createHash8 } from "node:crypto";
|
|
38051
|
-
import { join as
|
|
38453
|
+
import { join as join28 } from "node:path";
|
|
38052
38454
|
import { readFile as readFile3 } from "node:fs/promises";
|
|
38053
38455
|
async function readPackageJson2(projectRoot) {
|
|
38054
|
-
const path53 =
|
|
38055
|
-
if (!
|
|
38456
|
+
const path53 = join28(projectRoot, "package.json");
|
|
38457
|
+
if (!existsSync33(path53)) return null;
|
|
38056
38458
|
try {
|
|
38057
38459
|
return JSON.parse(await readFile3(path53, "utf8"));
|
|
38058
38460
|
} catch {
|
|
@@ -38076,8 +38478,8 @@ async function genTechStack(ctx) {
|
|
|
38076
38478
|
].join("\n");
|
|
38077
38479
|
}
|
|
38078
38480
|
async function genDecisions(ctx) {
|
|
38079
|
-
const decisionsDir =
|
|
38080
|
-
if (!
|
|
38481
|
+
const decisionsDir = join28(ctx.rootDir, "decisions");
|
|
38482
|
+
if (!existsSync33(decisionsDir)) return "_No ADRs yet._";
|
|
38081
38483
|
const files = ctx.storage.listMarkdown(decisionsDir).sort();
|
|
38082
38484
|
const accepted = [];
|
|
38083
38485
|
const proposed = [];
|
|
@@ -38102,9 +38504,9 @@ async function genDecisions(ctx) {
|
|
|
38102
38504
|
}
|
|
38103
38505
|
async function genConventions(ctx) {
|
|
38104
38506
|
const lines = [];
|
|
38105
|
-
const claudeMd =
|
|
38106
|
-
if (
|
|
38107
|
-
const content =
|
|
38507
|
+
const claudeMd = join28(ctx.projectRoot, "CLAUDE.MD");
|
|
38508
|
+
if (existsSync33(claudeMd)) {
|
|
38509
|
+
const content = readFileSync29(claudeMd, "utf8");
|
|
38108
38510
|
const match = content.match(/## Architecture rules[\s\S]+?(?=\n## |\n*$)/);
|
|
38109
38511
|
if (match) {
|
|
38110
38512
|
lines.push('<!-- Extracted from CLAUDE.MD "Architecture rules" -->');
|
|
@@ -38136,9 +38538,9 @@ async function genBuild(ctx) {
|
|
|
38136
38538
|
].join("\n");
|
|
38137
38539
|
}
|
|
38138
38540
|
async function genOpenQuestions(ctx) {
|
|
38139
|
-
const path53 =
|
|
38140
|
-
if (!
|
|
38141
|
-
const content =
|
|
38541
|
+
const path53 = join28(ctx.rootDir, "risks.md");
|
|
38542
|
+
if (!existsSync33(path53)) return "_No open questions._";
|
|
38543
|
+
const content = readFileSync29(path53, "utf8");
|
|
38142
38544
|
const lines = content.split("\n");
|
|
38143
38545
|
const questions = [];
|
|
38144
38546
|
let currentTitle = "";
|
|
@@ -38212,9 +38614,9 @@ function titleCase(id) {
|
|
|
38212
38614
|
return id.split("-").map((w) => w[0].toUpperCase() + w.slice(1)).join(" ");
|
|
38213
38615
|
}
|
|
38214
38616
|
async function updateAgentsMd(ctx, projectRoot) {
|
|
38215
|
-
const agentsPath =
|
|
38216
|
-
if (
|
|
38217
|
-
const content =
|
|
38617
|
+
const agentsPath = join28(projectRoot, "AGENTS.MD");
|
|
38618
|
+
if (existsSync33(agentsPath)) {
|
|
38619
|
+
const content = readFileSync29(agentsPath, "utf8");
|
|
38218
38620
|
const hasAnyMarker = AUTO_SECTIONS.some((id) => content.includes(MARKER_OPEN(id)));
|
|
38219
38621
|
if (!hasAnyMarker) {
|
|
38220
38622
|
return {
|
|
@@ -38229,8 +38631,8 @@ async function updateAgentsMd(ctx, projectRoot) {
|
|
|
38229
38631
|
newSections.set(id, await GENERATORS[id](ctx));
|
|
38230
38632
|
}
|
|
38231
38633
|
let manualContent = "";
|
|
38232
|
-
if (
|
|
38233
|
-
const { manualBlocks } = parseAgentsMd(
|
|
38634
|
+
if (existsSync33(agentsPath)) {
|
|
38635
|
+
const { manualBlocks } = parseAgentsMd(readFileSync29(agentsPath, "utf8"));
|
|
38234
38636
|
manualContent = manualBlocks.after;
|
|
38235
38637
|
} else {
|
|
38236
38638
|
const projectName2 = projectName(projectRoot);
|
|
@@ -38246,7 +38648,7 @@ async function updateAgentsMd(ctx, projectRoot) {
|
|
|
38246
38648
|
""
|
|
38247
38649
|
].join("\n");
|
|
38248
38650
|
}
|
|
38249
|
-
const oldContent =
|
|
38651
|
+
const oldContent = existsSync33(agentsPath) ? readFileSync29(agentsPath, "utf8") : "";
|
|
38250
38652
|
const { sections: oldSections } = parseAgentsMd(oldContent);
|
|
38251
38653
|
const changedSections = [];
|
|
38252
38654
|
for (const id of AUTO_SECTIONS) {
|
|
@@ -38258,7 +38660,7 @@ async function updateAgentsMd(ctx, projectRoot) {
|
|
|
38258
38660
|
return { changed: false, sections: [] };
|
|
38259
38661
|
}
|
|
38260
38662
|
const newContent = serializeAgentsMd(manualContent, newSections);
|
|
38261
|
-
|
|
38663
|
+
writeFileSync19(agentsPath, newContent, "utf8");
|
|
38262
38664
|
return { changed: true, sections: changedSections };
|
|
38263
38665
|
}
|
|
38264
38666
|
function hash2(s) {
|
|
@@ -38384,8 +38786,8 @@ var init_completeDesign = __esm({
|
|
|
38384
38786
|
|
|
38385
38787
|
// src/cli/workspace/projectSmoke.ts
|
|
38386
38788
|
import { spawn as spawn10 } from "node:child_process";
|
|
38387
|
-
import { existsSync as
|
|
38388
|
-
import { join as
|
|
38789
|
+
import { existsSync as existsSync34, readFileSync as readFileSync30 } from "node:fs";
|
|
38790
|
+
import { join as join29 } from "node:path";
|
|
38389
38791
|
function pickSmokeScript(scripts) {
|
|
38390
38792
|
if (!scripts) return null;
|
|
38391
38793
|
for (const name of SMOKE_SCRIPT_PRIORITY) {
|
|
@@ -38397,13 +38799,13 @@ async function runProjectSmoke(projectRoot, timeoutMs = DEFAULT_TIMEOUT_MS2) {
|
|
|
38397
38799
|
if (process.env["ZELARI_SMOKE"] === "0") {
|
|
38398
38800
|
return { ran: false, reason: "ZELARI_SMOKE=0 (disabled)" };
|
|
38399
38801
|
}
|
|
38400
|
-
const pkgPath =
|
|
38401
|
-
if (!
|
|
38802
|
+
const pkgPath = join29(projectRoot, "package.json");
|
|
38803
|
+
if (!existsSync34(pkgPath)) {
|
|
38402
38804
|
return { ran: false, reason: "no package.json (skipped)" };
|
|
38403
38805
|
}
|
|
38404
38806
|
let scripts = {};
|
|
38405
38807
|
try {
|
|
38406
|
-
const pkg = JSON.parse(
|
|
38808
|
+
const pkg = JSON.parse(readFileSync30(pkgPath, "utf8"));
|
|
38407
38809
|
scripts = pkg.scripts ?? {};
|
|
38408
38810
|
} catch {
|
|
38409
38811
|
return { ran: false, reason: "package.json unreadable (skipped)" };
|
|
@@ -38491,8 +38893,8 @@ __export(postCouncilHook_exports, {
|
|
|
38491
38893
|
runPostCouncilHook: () => runPostCouncilHook
|
|
38492
38894
|
});
|
|
38493
38895
|
import { spawn as spawn11 } from "node:child_process";
|
|
38494
|
-
import { existsSync as
|
|
38495
|
-
import { join as
|
|
38896
|
+
import { existsSync as existsSync35, readFileSync as readFileSync31 } from "node:fs";
|
|
38897
|
+
import { join as join30 } from "node:path";
|
|
38496
38898
|
async function runCompleteDesignPostProcessor(ctx, options) {
|
|
38497
38899
|
if (options?.runMode === "implementation") {
|
|
38498
38900
|
return {
|
|
@@ -38503,9 +38905,9 @@ async function runCompleteDesignPostProcessor(ctx, options) {
|
|
|
38503
38905
|
if (process.env["ZELARI_COMPLETE_DESIGN"] === "0") {
|
|
38504
38906
|
return { ran: false, reason: "ZELARI_COMPLETE_DESIGN=0 (disabled)" };
|
|
38505
38907
|
}
|
|
38506
|
-
const planJsonPath2 =
|
|
38507
|
-
const scriptPath =
|
|
38508
|
-
if (!
|
|
38908
|
+
const planJsonPath2 = join30(ctx.rootDir, "plan.json");
|
|
38909
|
+
const scriptPath = join30(ctx.projectRoot, "complete-design.mjs");
|
|
38910
|
+
if (!existsSync35(planJsonPath2)) {
|
|
38509
38911
|
return {
|
|
38510
38912
|
ran: false,
|
|
38511
38913
|
reason: ".zelari/plan.json missing (not design-phase)"
|
|
@@ -38513,7 +38915,7 @@ async function runCompleteDesignPostProcessor(ctx, options) {
|
|
|
38513
38915
|
}
|
|
38514
38916
|
let phaseCount = 0;
|
|
38515
38917
|
try {
|
|
38516
|
-
const parsed = JSON.parse(
|
|
38918
|
+
const parsed = JSON.parse(readFileSync31(planJsonPath2, "utf8"));
|
|
38517
38919
|
phaseCount = Array.isArray(parsed.phases) ? parsed.phases.length : 0;
|
|
38518
38920
|
} catch {
|
|
38519
38921
|
return { ran: false, reason: ".zelari/plan.json corrupt" };
|
|
@@ -38521,7 +38923,7 @@ async function runCompleteDesignPostProcessor(ctx, options) {
|
|
|
38521
38923
|
if (phaseCount === 0) {
|
|
38522
38924
|
return { ran: false, reason: ".zelari/plan.json has no phases" };
|
|
38523
38925
|
}
|
|
38524
|
-
if (!
|
|
38926
|
+
if (!existsSync35(scriptPath)) {
|
|
38525
38927
|
try {
|
|
38526
38928
|
const builtin = await runBuiltinCompleteDesign(ctx);
|
|
38527
38929
|
return {
|
|
@@ -38744,10 +39146,10 @@ __export(councilFeedback_exports, {
|
|
|
38744
39146
|
});
|
|
38745
39147
|
import {
|
|
38746
39148
|
promises as fs16,
|
|
38747
|
-
existsSync as
|
|
38748
|
-
readFileSync as
|
|
38749
|
-
writeFileSync as
|
|
38750
|
-
mkdirSync as
|
|
39149
|
+
existsSync as existsSync36,
|
|
39150
|
+
readFileSync as readFileSync32,
|
|
39151
|
+
writeFileSync as writeFileSync20,
|
|
39152
|
+
mkdirSync as mkdirSync17
|
|
38751
39153
|
} from "node:fs";
|
|
38752
39154
|
import path32 from "node:path";
|
|
38753
39155
|
import os9 from "node:os";
|
|
@@ -38853,9 +39255,9 @@ var init_councilFeedback = __esm({
|
|
|
38853
39255
|
}
|
|
38854
39256
|
// --- persistence ---------------------------------------------------------
|
|
38855
39257
|
load() {
|
|
38856
|
-
if (!
|
|
39258
|
+
if (!existsSync36(this.file)) return;
|
|
38857
39259
|
try {
|
|
38858
|
-
const raw =
|
|
39260
|
+
const raw = readFileSync32(this.file, "utf-8");
|
|
38859
39261
|
const parsed = JSON.parse(raw);
|
|
38860
39262
|
if (parsed && Array.isArray(parsed.entries)) {
|
|
38861
39263
|
this.entries = parsed.entries.filter(
|
|
@@ -38866,8 +39268,8 @@ var init_councilFeedback = __esm({
|
|
|
38866
39268
|
}
|
|
38867
39269
|
}
|
|
38868
39270
|
save() {
|
|
38869
|
-
|
|
38870
|
-
|
|
39271
|
+
mkdirSync17(path32.dirname(this.file), { recursive: true });
|
|
39272
|
+
writeFileSync20(
|
|
38871
39273
|
this.file,
|
|
38872
39274
|
JSON.stringify({ entries: this.entries }, null, 2),
|
|
38873
39275
|
{ encoding: "utf-8", mode: 384 }
|
|
@@ -41293,7 +41695,7 @@ __export(executor_exports, {
|
|
|
41293
41695
|
resolveNodeTimeoutMs: () => resolveNodeTimeoutMs,
|
|
41294
41696
|
thoroughnessForKind: () => thoroughnessForKind
|
|
41295
41697
|
});
|
|
41296
|
-
import { existsSync as
|
|
41698
|
+
import { existsSync as existsSync37 } from "node:fs";
|
|
41297
41699
|
import path40 from "node:path";
|
|
41298
41700
|
function resolveMaxParallel(env = process.env) {
|
|
41299
41701
|
const raw = env.ZELARI_KRAKEN_MAX_PARALLEL;
|
|
@@ -41352,7 +41754,7 @@ function isWorldModelGateEnabled(cwd, env = process.env, checksExists = defaultC
|
|
|
41352
41754
|
}
|
|
41353
41755
|
function defaultChecksExists(cwd) {
|
|
41354
41756
|
try {
|
|
41355
|
-
return
|
|
41757
|
+
return existsSync37(path40.join(cwd, ".zelari", "world", "checks.json"));
|
|
41356
41758
|
} catch {
|
|
41357
41759
|
return false;
|
|
41358
41760
|
}
|
|
@@ -42319,8 +42721,8 @@ __export(prereqChecks_exports, {
|
|
|
42319
42721
|
runPrereqChecks: () => runPrereqChecks
|
|
42320
42722
|
});
|
|
42321
42723
|
import { execSync, spawnSync as spawnSync2 } from "node:child_process";
|
|
42322
|
-
import { existsSync as
|
|
42323
|
-
import { dirname as
|
|
42724
|
+
import { existsSync as existsSync38 } from "node:fs";
|
|
42725
|
+
import { dirname as dirname8 } from "node:path";
|
|
42324
42726
|
function isWslBashPath2(p3) {
|
|
42325
42727
|
if (!p3 || typeof p3 !== "string") return false;
|
|
42326
42728
|
const n = p3.replace(/\//g, "\\").toLowerCase();
|
|
@@ -42426,7 +42828,7 @@ function resolveAgentShellSync() {
|
|
|
42426
42828
|
function agentProbeEnv() {
|
|
42427
42829
|
const env = { ...process.env };
|
|
42428
42830
|
try {
|
|
42429
|
-
const nodeDir =
|
|
42831
|
+
const nodeDir = dirname8(process.execPath);
|
|
42430
42832
|
if (!nodeDir) return env;
|
|
42431
42833
|
const sep2 = process.platform === "win32" ? ";" : ":";
|
|
42432
42834
|
const current = env.PATH ?? env.Path ?? "";
|
|
@@ -42443,7 +42845,7 @@ function agentProbeEnv() {
|
|
|
42443
42845
|
}
|
|
42444
42846
|
function existsSyncSafe2(p3) {
|
|
42445
42847
|
try {
|
|
42446
|
-
return
|
|
42848
|
+
return existsSync38(p3);
|
|
42447
42849
|
} catch {
|
|
42448
42850
|
return false;
|
|
42449
42851
|
}
|
|
@@ -42690,7 +43092,7 @@ var init_prereqChecks = __esm({
|
|
|
42690
43092
|
});
|
|
42691
43093
|
|
|
42692
43094
|
// src/cli/plugins/prefs.ts
|
|
42693
|
-
import { existsSync as
|
|
43095
|
+
import { existsSync as existsSync39, readFileSync as readFileSync33, writeFileSync as writeFileSync21, mkdirSync as mkdirSync18 } from "node:fs";
|
|
42694
43096
|
import path43 from "node:path";
|
|
42695
43097
|
import os10 from "node:os";
|
|
42696
43098
|
function getPluginPrefsPath() {
|
|
@@ -42699,8 +43101,8 @@ function getPluginPrefsPath() {
|
|
|
42699
43101
|
function getPluginPrefs() {
|
|
42700
43102
|
const file2 = getPluginPrefsPath();
|
|
42701
43103
|
try {
|
|
42702
|
-
if (!
|
|
42703
|
-
const raw =
|
|
43104
|
+
if (!existsSync39(file2)) return { ...DEFAULTS2, dontAskAgain: {} };
|
|
43105
|
+
const raw = readFileSync33(file2, "utf-8");
|
|
42704
43106
|
const parsed = JSON.parse(raw);
|
|
42705
43107
|
if (parsed && typeof parsed === "object" && parsed.dontAskAgain && typeof parsed.dontAskAgain === "object") {
|
|
42706
43108
|
const clean = {};
|
|
@@ -42715,8 +43117,8 @@ function getPluginPrefs() {
|
|
|
42715
43117
|
}
|
|
42716
43118
|
function writePluginPrefs(prefs) {
|
|
42717
43119
|
const file2 = getPluginPrefsPath();
|
|
42718
|
-
|
|
42719
|
-
|
|
43120
|
+
mkdirSync18(path43.dirname(file2), { recursive: true });
|
|
43121
|
+
writeFileSync21(file2, JSON.stringify(prefs, null, 2), {
|
|
42720
43122
|
encoding: "utf-8",
|
|
42721
43123
|
mode: 384
|
|
42722
43124
|
});
|
|
@@ -42751,7 +43153,7 @@ __export(registry_exports, {
|
|
|
42751
43153
|
findPlugin: () => findPlugin,
|
|
42752
43154
|
isBinaryOnPath: () => isBinaryOnPath
|
|
42753
43155
|
});
|
|
42754
|
-
import { existsSync as
|
|
43156
|
+
import { existsSync as existsSync40 } from "node:fs";
|
|
42755
43157
|
import path44 from "node:path";
|
|
42756
43158
|
function detectLocalBin(bin) {
|
|
42757
43159
|
return (cwd) => {
|
|
@@ -42768,7 +43170,7 @@ function isBinaryOnPath(bin, opts = {}) {
|
|
|
42768
43170
|
return false;
|
|
42769
43171
|
}
|
|
42770
43172
|
const platform = opts.platform ?? process.platform;
|
|
42771
|
-
const exists = opts.exists ??
|
|
43173
|
+
const exists = opts.exists ?? existsSync40;
|
|
42772
43174
|
const pathEnv = opts.pathEnv ?? process.env.PATH ?? "";
|
|
42773
43175
|
const pathMod = platform === "win32" ? path44.win32 : path44.posix;
|
|
42774
43176
|
const sep2 = platform === "win32" ? ";" : ":";
|
|
@@ -43502,7 +43904,7 @@ __export(atMentions_exports, {
|
|
|
43502
43904
|
extractAtMentions: () => extractAtMentions,
|
|
43503
43905
|
hasAtMentions: () => hasAtMentions
|
|
43504
43906
|
});
|
|
43505
|
-
import { existsSync as
|
|
43907
|
+
import { existsSync as existsSync43, readFileSync as readFileSync35, statSync as statSync7 } from "node:fs";
|
|
43506
43908
|
import { basename as basename3, isAbsolute as isAbsolute2, relative as relative3, resolve, sep } from "node:path";
|
|
43507
43909
|
function isImagePath(abs) {
|
|
43508
43910
|
const ext = abs.split(".").pop()?.toLowerCase() ?? "";
|
|
@@ -43556,7 +43958,7 @@ function resolveMention(token, cwd) {
|
|
|
43556
43958
|
note: "outside project root \u2014 skipped"
|
|
43557
43959
|
};
|
|
43558
43960
|
}
|
|
43559
|
-
if (!
|
|
43961
|
+
if (!existsSync43(abs)) {
|
|
43560
43962
|
return {
|
|
43561
43963
|
raw: token,
|
|
43562
43964
|
path: token,
|
|
@@ -43608,7 +44010,7 @@ function resolveMention(token, cwd) {
|
|
|
43608
44010
|
note: `image too large (${Math.round(st.size / 1024)} KB) \u2014 path only`
|
|
43609
44011
|
};
|
|
43610
44012
|
}
|
|
43611
|
-
const dataBase64 =
|
|
44013
|
+
const dataBase64 = readFileSync35(abs).toString("base64");
|
|
43612
44014
|
return {
|
|
43613
44015
|
raw: token,
|
|
43614
44016
|
path: rel2,
|
|
@@ -43619,7 +44021,7 @@ function resolveMention(token, cwd) {
|
|
|
43619
44021
|
};
|
|
43620
44022
|
}
|
|
43621
44023
|
try {
|
|
43622
|
-
const buf =
|
|
44024
|
+
const buf = readFileSync35(abs);
|
|
43623
44025
|
const head = buf.subarray(0, 800).toString("utf8");
|
|
43624
44026
|
if (!isProbablyText(abs, head)) {
|
|
43625
44027
|
return {
|
|
@@ -44116,14 +44518,14 @@ var init_skillCategories = __esm({
|
|
|
44116
44518
|
|
|
44117
44519
|
// src/cli/skillConfigIo.ts
|
|
44118
44520
|
import {
|
|
44119
|
-
existsSync as
|
|
44120
|
-
mkdirSync as
|
|
44521
|
+
existsSync as existsSync45,
|
|
44522
|
+
mkdirSync as mkdirSync21,
|
|
44121
44523
|
readdirSync as readdirSync9,
|
|
44122
|
-
readFileSync as
|
|
44524
|
+
readFileSync as readFileSync37,
|
|
44123
44525
|
rmSync as rmSync4,
|
|
44124
|
-
writeFileSync as
|
|
44526
|
+
writeFileSync as writeFileSync23
|
|
44125
44527
|
} from "node:fs";
|
|
44126
|
-
import { dirname as
|
|
44528
|
+
import { dirname as dirname10, join as join36 } from "node:path";
|
|
44127
44529
|
import { homedir as homedir12 } from "node:os";
|
|
44128
44530
|
function ensureBuiltinSkillsLoadedSync() {
|
|
44129
44531
|
if (builtinsLoaded) return;
|
|
@@ -44135,13 +44537,13 @@ function ensureBuiltinSkillsLoadedSync() {
|
|
|
44135
44537
|
}
|
|
44136
44538
|
}
|
|
44137
44539
|
function getUserSkillsDir() {
|
|
44138
|
-
return
|
|
44540
|
+
return join36(homedir12(), ".zelari-code", "skills");
|
|
44139
44541
|
}
|
|
44140
44542
|
function getProjectSkillsDir(projectRoot) {
|
|
44141
|
-
return
|
|
44543
|
+
return join36(projectRoot, ".zelari", "skills");
|
|
44142
44544
|
}
|
|
44143
44545
|
function skillFilePath(dir, name) {
|
|
44144
|
-
return
|
|
44546
|
+
return join36(dir, name, "SKILL.md");
|
|
44145
44547
|
}
|
|
44146
44548
|
function classifyScope(skillPath, projectRoot) {
|
|
44147
44549
|
const userDir = getUserSkillsDir().replace(/\\/g, "/");
|
|
@@ -44190,7 +44592,7 @@ function entryFromBuiltin(skill) {
|
|
|
44190
44592
|
};
|
|
44191
44593
|
}
|
|
44192
44594
|
function scanSkillsDir(dir, projectRoot, seen, out) {
|
|
44193
|
-
if (!
|
|
44595
|
+
if (!existsSync45(dir)) return;
|
|
44194
44596
|
let entries;
|
|
44195
44597
|
try {
|
|
44196
44598
|
entries = readdirSync9(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
@@ -44199,9 +44601,9 @@ function scanSkillsDir(dir, projectRoot, seen, out) {
|
|
|
44199
44601
|
}
|
|
44200
44602
|
for (const entry of entries) {
|
|
44201
44603
|
const skillPath = skillFilePath(dir, entry);
|
|
44202
|
-
if (!
|
|
44604
|
+
if (!existsSync45(skillPath)) continue;
|
|
44203
44605
|
try {
|
|
44204
|
-
const parsed = parseSkillMd(
|
|
44606
|
+
const parsed = parseSkillMd(readFileSync37(skillPath, "utf8"), skillPath);
|
|
44205
44607
|
if (!parsed) continue;
|
|
44206
44608
|
if (seen.has(parsed.name)) continue;
|
|
44207
44609
|
seen.add(parsed.name);
|
|
@@ -44217,9 +44619,9 @@ function listSkillsSnapshot(projectRoot) {
|
|
|
44217
44619
|
const skills = [];
|
|
44218
44620
|
const seen = /* @__PURE__ */ new Set();
|
|
44219
44621
|
if (root) {
|
|
44220
|
-
scanSkillsDir(
|
|
44221
|
-
scanSkillsDir(
|
|
44222
|
-
scanSkillsDir(
|
|
44622
|
+
scanSkillsDir(join36(root, ".zelari", "skills"), root, seen, skills);
|
|
44623
|
+
scanSkillsDir(join36(root, ".claude", "skills"), root, seen, skills);
|
|
44624
|
+
scanSkillsDir(join36(root, ".opencode", "skills"), root, seen, skills);
|
|
44223
44625
|
}
|
|
44224
44626
|
scanSkillsDir(userSkillsDir, root, seen, skills);
|
|
44225
44627
|
for (const s of listCodingSkills()) {
|
|
@@ -44298,8 +44700,8 @@ function upsertSkill(opts) {
|
|
|
44298
44700
|
if (!parsed) {
|
|
44299
44701
|
return { ok: false, error: "Generated SKILL.md failed validation" };
|
|
44300
44702
|
}
|
|
44301
|
-
|
|
44302
|
-
|
|
44703
|
+
mkdirSync21(dirname10(path53), { recursive: true });
|
|
44704
|
+
writeFileSync23(path53, content, "utf8");
|
|
44303
44705
|
return { ok: true, path: path53 };
|
|
44304
44706
|
}
|
|
44305
44707
|
function removeSkill(opts) {
|
|
@@ -44317,9 +44719,9 @@ function removeSkill(opts) {
|
|
|
44317
44719
|
}
|
|
44318
44720
|
dir = getProjectSkillsDir(root);
|
|
44319
44721
|
}
|
|
44320
|
-
const skillDir =
|
|
44722
|
+
const skillDir = join36(dir, name);
|
|
44321
44723
|
const path53 = skillFilePath(dir, name);
|
|
44322
|
-
if (!
|
|
44724
|
+
if (!existsSync45(path53) && !existsSync45(skillDir)) {
|
|
44323
44725
|
return { ok: false, error: `Skill "${name}" not found in ${dir}` };
|
|
44324
44726
|
}
|
|
44325
44727
|
try {
|
|
@@ -44624,36 +45026,36 @@ var init_permissionCli = __esm({
|
|
|
44624
45026
|
|
|
44625
45027
|
// src/cli/companion/config.ts
|
|
44626
45028
|
import {
|
|
44627
|
-
existsSync as
|
|
44628
|
-
mkdirSync as
|
|
44629
|
-
readFileSync as
|
|
44630
|
-
writeFileSync as
|
|
45029
|
+
existsSync as existsSync46,
|
|
45030
|
+
mkdirSync as mkdirSync22,
|
|
45031
|
+
readFileSync as readFileSync38,
|
|
45032
|
+
writeFileSync as writeFileSync24
|
|
44631
45033
|
} from "node:fs";
|
|
44632
|
-
import { join as
|
|
45034
|
+
import { join as join37 } from "node:path";
|
|
44633
45035
|
import { homedir as homedir13 } from "node:os";
|
|
44634
45036
|
import { createHash as createHash9, randomBytes as randomBytes5, timingSafeEqual } from "node:crypto";
|
|
44635
45037
|
function getZelariHome() {
|
|
44636
|
-
return
|
|
45038
|
+
return join37(homedir13(), ".zelari-code");
|
|
44637
45039
|
}
|
|
44638
45040
|
function getCompanionConfigPath() {
|
|
44639
|
-
return
|
|
45041
|
+
return join37(getZelariHome(), "companion.json");
|
|
44640
45042
|
}
|
|
44641
45043
|
function getCompanionTokenPath() {
|
|
44642
|
-
return
|
|
45044
|
+
return join37(getZelariHome(), "companion.token");
|
|
44643
45045
|
}
|
|
44644
45046
|
function ensureHome() {
|
|
44645
45047
|
const home = getZelariHome();
|
|
44646
|
-
if (!
|
|
44647
|
-
|
|
45048
|
+
if (!existsSync46(home)) {
|
|
45049
|
+
mkdirSync22(home, { recursive: true });
|
|
44648
45050
|
}
|
|
44649
45051
|
}
|
|
44650
45052
|
function loadCompanionConfig() {
|
|
44651
45053
|
const path53 = getCompanionConfigPath();
|
|
44652
|
-
if (!
|
|
45054
|
+
if (!existsSync46(path53)) {
|
|
44653
45055
|
return { projects: [] };
|
|
44654
45056
|
}
|
|
44655
45057
|
try {
|
|
44656
|
-
const raw = JSON.parse(
|
|
45058
|
+
const raw = JSON.parse(readFileSync38(path53, "utf8"));
|
|
44657
45059
|
const projects = Array.isArray(raw.projects) ? raw.projects.filter(
|
|
44658
45060
|
(p3) => p3 && typeof p3.path === "string" && p3.path.trim() && typeof (p3.id ?? p3.name) === "string"
|
|
44659
45061
|
).map((p3) => ({
|
|
@@ -44672,7 +45074,7 @@ function loadCompanionConfig() {
|
|
|
44672
45074
|
}
|
|
44673
45075
|
function saveCompanionConfig(cfg) {
|
|
44674
45076
|
ensureHome();
|
|
44675
|
-
|
|
45077
|
+
writeFileSync24(
|
|
44676
45078
|
getCompanionConfigPath(),
|
|
44677
45079
|
JSON.stringify(
|
|
44678
45080
|
{
|
|
@@ -44692,12 +45094,12 @@ function loadOrCreateToken(explicit) {
|
|
|
44692
45094
|
}
|
|
44693
45095
|
ensureHome();
|
|
44694
45096
|
const path53 = getCompanionTokenPath();
|
|
44695
|
-
if (
|
|
44696
|
-
const t =
|
|
45097
|
+
if (existsSync46(path53)) {
|
|
45098
|
+
const t = readFileSync38(path53, "utf8").trim();
|
|
44697
45099
|
if (t) return { token: t, created: false };
|
|
44698
45100
|
}
|
|
44699
45101
|
const token = randomBytes5(24).toString("base64url");
|
|
44700
|
-
|
|
45102
|
+
writeFileSync24(path53, token + "\n", "utf8");
|
|
44701
45103
|
try {
|
|
44702
45104
|
const fs31 = __require("node:fs");
|
|
44703
45105
|
fs31.chmodSync?.(path53, 384);
|
|
@@ -44786,8 +45188,8 @@ var init_config = __esm({
|
|
|
44786
45188
|
import { spawn as spawn13 } from "node:child_process";
|
|
44787
45189
|
import { createInterface as createInterface2 } from "node:readline";
|
|
44788
45190
|
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
44789
|
-
import { writeFileSync as
|
|
44790
|
-
import { join as
|
|
45191
|
+
import { writeFileSync as writeFileSync25, unlinkSync as unlinkSync3 } from "node:fs";
|
|
45192
|
+
import { join as join38 } from "node:path";
|
|
44791
45193
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
44792
45194
|
var RunManager;
|
|
44793
45195
|
var init_runManager = __esm({
|
|
@@ -44891,9 +45293,9 @@ var init_runManager = __esm({
|
|
|
44891
45293
|
}
|
|
44892
45294
|
let historyFile;
|
|
44893
45295
|
if (args.history && Array.isArray(args.history) && args.history.length > 0) {
|
|
44894
|
-
historyFile =
|
|
45296
|
+
historyFile = join38(tmpdir3(), `zelari-companion-hist-${id}.json`);
|
|
44895
45297
|
try {
|
|
44896
|
-
|
|
45298
|
+
writeFileSync25(historyFile, JSON.stringify(args.history), "utf8");
|
|
44897
45299
|
argv.push("--history-file", historyFile);
|
|
44898
45300
|
} catch {
|
|
44899
45301
|
historyFile = void 0;
|
|
@@ -45018,7 +45420,7 @@ __export(serve_exports, {
|
|
|
45018
45420
|
runCompanionServe: () => runCompanionServe
|
|
45019
45421
|
});
|
|
45020
45422
|
import { createServer as createServer3 } from "node:http";
|
|
45021
|
-
import { existsSync as
|
|
45423
|
+
import { existsSync as existsSync47 } from "node:fs";
|
|
45022
45424
|
import { resolve as resolve2 } from "node:path";
|
|
45023
45425
|
function readBody(req, max = 2e6) {
|
|
45024
45426
|
return new Promise((resolveBody, reject) => {
|
|
@@ -45066,7 +45468,7 @@ async function runCompanionServe(opts = {}) {
|
|
|
45066
45468
|
let projects = mergeProjects(fileCfg, opts.projects ?? []);
|
|
45067
45469
|
projects = projects.filter((p3) => {
|
|
45068
45470
|
const abs = resolve2(p3.path);
|
|
45069
|
-
if (!
|
|
45471
|
+
if (!existsSync47(abs)) {
|
|
45070
45472
|
process.stderr.write(
|
|
45071
45473
|
`[zelari-code serve] skip missing project path: ${p3.path}
|
|
45072
45474
|
`
|
|
@@ -45388,7 +45790,7 @@ __export(doctor_exports, {
|
|
|
45388
45790
|
runDoctor: () => runDoctor
|
|
45389
45791
|
});
|
|
45390
45792
|
import { execSync as execSync2 } from "node:child_process";
|
|
45391
|
-
import { existsSync as
|
|
45793
|
+
import { existsSync as existsSync48, readFileSync as readFileSync39, readlinkSync, statSync as statSync8 } from "node:fs";
|
|
45392
45794
|
import { createRequire as createRequire3 } from "node:module";
|
|
45393
45795
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
45394
45796
|
import path51 from "node:path";
|
|
@@ -45396,9 +45798,9 @@ function findPackageRoot(start) {
|
|
|
45396
45798
|
let dir = start;
|
|
45397
45799
|
for (let i = 0; i < 6; i += 1) {
|
|
45398
45800
|
const candidate = path51.join(dir, "package.json");
|
|
45399
|
-
if (
|
|
45801
|
+
if (existsSync48(candidate)) {
|
|
45400
45802
|
try {
|
|
45401
|
-
const pkg = JSON.parse(
|
|
45803
|
+
const pkg = JSON.parse(readFileSync39(candidate, "utf8"));
|
|
45402
45804
|
if (pkg.name === "zelari-code") return dir;
|
|
45403
45805
|
} catch {
|
|
45404
45806
|
}
|
|
@@ -45422,7 +45824,7 @@ function tryExec(cmd) {
|
|
|
45422
45824
|
function readPackageJson3() {
|
|
45423
45825
|
try {
|
|
45424
45826
|
const pkgPath = path51.join(packageRoot, "package.json");
|
|
45425
|
-
return JSON.parse(
|
|
45827
|
+
return JSON.parse(readFileSync39(pkgPath, "utf8"));
|
|
45426
45828
|
} catch {
|
|
45427
45829
|
return null;
|
|
45428
45830
|
}
|
|
@@ -45438,7 +45840,7 @@ function checkShim(pkgName) {
|
|
|
45438
45840
|
const isWin = process.platform === "win32";
|
|
45439
45841
|
const shimName = isWin ? "zelari-code.cmd" : "zelari-code";
|
|
45440
45842
|
const shimPath = path51.join(prefix, shimName);
|
|
45441
|
-
if (!
|
|
45843
|
+
if (!existsSync48(shimPath)) {
|
|
45442
45844
|
return FAIL(
|
|
45443
45845
|
`shim not found at ${shimPath}
|
|
45444
45846
|
fix: npm install -g ${pkgName}@latest --force`
|
|
@@ -45447,7 +45849,7 @@ function checkShim(pkgName) {
|
|
|
45447
45849
|
try {
|
|
45448
45850
|
const st = statSync8(shimPath);
|
|
45449
45851
|
if (isWin) {
|
|
45450
|
-
const content =
|
|
45852
|
+
const content = readFileSync39(shimPath, "utf8");
|
|
45451
45853
|
if (content.includes(`${pkgName}\\bin\\`) || content.includes(`${pkgName}/bin/`)) {
|
|
45452
45854
|
return OK(`shim OK at ${shimPath} (${st.size} bytes)`);
|
|
45453
45855
|
}
|
|
@@ -45506,7 +45908,7 @@ function checkNode(pkg) {
|
|
|
45506
45908
|
}
|
|
45507
45909
|
function checkBundle() {
|
|
45508
45910
|
const bundle = path51.join(packageRoot, "dist", "cli", "main.bundled.js");
|
|
45509
|
-
if (!
|
|
45911
|
+
if (!existsSync48(bundle)) {
|
|
45510
45912
|
return FAIL(
|
|
45511
45913
|
`dist/cli/main.bundled.js missing at ${bundle}
|
|
45512
45914
|
fix: npm run build:cli (then reinstall or run via tsx)`
|
|
@@ -45887,7 +46289,7 @@ __export(inspect_exports, {
|
|
|
45887
46289
|
runInspect: () => runInspect
|
|
45888
46290
|
});
|
|
45889
46291
|
import path52 from "node:path";
|
|
45890
|
-
import { existsSync as
|
|
46292
|
+
import { existsSync as existsSync49, readFileSync as readFileSync40, readdirSync as readdirSync10 } from "node:fs";
|
|
45891
46293
|
import { homedir as homedir14 } from "node:os";
|
|
45892
46294
|
async function collectInspectReport(cwd = process.cwd()) {
|
|
45893
46295
|
ensureBuiltinSkillsLoadedSync();
|
|
@@ -45920,11 +46322,11 @@ async function collectInspectReport(cwd = process.cwd()) {
|
|
|
45920
46322
|
folders: listTrustedFolders()
|
|
45921
46323
|
},
|
|
45922
46324
|
configSources: [
|
|
45923
|
-
{ path: userMcpPath, exists:
|
|
45924
|
-
{ path: projectMcpPath, exists:
|
|
45925
|
-
{ path: path52.join(homedir14(), ".zelari-code", "provider.json"), exists:
|
|
45926
|
-
{ path: path52.join(cwd, ".zelari", "AGENTS.md"), exists:
|
|
45927
|
-
{ path: path52.join(cwd, "AGENTS.md"), exists:
|
|
46325
|
+
{ path: userMcpPath, exists: existsSync49(userMcpPath) },
|
|
46326
|
+
{ path: projectMcpPath, exists: existsSync49(projectMcpPath) },
|
|
46327
|
+
{ path: path52.join(homedir14(), ".zelari-code", "provider.json"), exists: existsSync49(path52.join(homedir14(), ".zelari-code", "provider.json")) },
|
|
46328
|
+
{ path: path52.join(cwd, ".zelari", "AGENTS.md"), exists: existsSync49(path52.join(cwd, ".zelari", "AGENTS.md")) },
|
|
46329
|
+
{ path: path52.join(cwd, "AGENTS.md"), exists: existsSync49(path52.join(cwd, "AGENTS.md")) }
|
|
45928
46330
|
],
|
|
45929
46331
|
skills: {
|
|
45930
46332
|
total: snap.skills.length,
|
|
@@ -45937,7 +46339,7 @@ async function collectInspectReport(cwd = process.cwd()) {
|
|
|
45937
46339
|
user: mcp.servers.filter((s) => s.scope === "user").map((s) => ({ name: s.name, enabled: s.enabled !== false })),
|
|
45938
46340
|
project: mcp.servers.filter((s) => s.scope === "project").map((s) => ({ name: s.name, enabled: s.enabled !== false })),
|
|
45939
46341
|
projectTrusted,
|
|
45940
|
-
projectConfigExists:
|
|
46342
|
+
projectConfigExists: existsSync49(projectMcpPath)
|
|
45941
46343
|
},
|
|
45942
46344
|
hooks: {
|
|
45943
46345
|
global: {
|
|
@@ -45969,9 +46371,9 @@ function findAgentsMd(cwd) {
|
|
|
45969
46371
|
];
|
|
45970
46372
|
const found = [];
|
|
45971
46373
|
for (const c of candidates) {
|
|
45972
|
-
if (
|
|
46374
|
+
if (existsSync49(c)) {
|
|
45973
46375
|
try {
|
|
45974
|
-
const text =
|
|
46376
|
+
const text = readFileSync40(c, "utf8");
|
|
45975
46377
|
found.push(`${c} (${text.length} bytes)`);
|
|
45976
46378
|
} catch {
|
|
45977
46379
|
found.push(`${c} (unreadable)`);
|
|
@@ -53165,7 +53567,7 @@ async function handlePromoteMember(ctx, memberId) {
|
|
|
53165
53567
|
}
|
|
53166
53568
|
|
|
53167
53569
|
// src/cli/branchManager.ts
|
|
53168
|
-
import { promises as fs26, existsSync as
|
|
53570
|
+
import { promises as fs26, existsSync as existsSync41, readFileSync as readFileSync34, writeFileSync as writeFileSync22, mkdirSync as mkdirSync19, statSync as statSync5, rmSync as rmSync3 } from "node:fs";
|
|
53169
53571
|
import path46 from "node:path";
|
|
53170
53572
|
import os12 from "node:os";
|
|
53171
53573
|
var META_FILENAME = "meta.json";
|
|
@@ -53187,11 +53589,11 @@ function sessionsPathFor(name, baseDir) {
|
|
|
53187
53589
|
}
|
|
53188
53590
|
function readBranchMeta(name, baseDir) {
|
|
53189
53591
|
const metaPath = metaPathFor(name, baseDir);
|
|
53190
|
-
if (!
|
|
53592
|
+
if (!existsSync41(metaPath)) {
|
|
53191
53593
|
throw new BranchNotFoundError(`Branch "${name}" not found`);
|
|
53192
53594
|
}
|
|
53193
53595
|
try {
|
|
53194
|
-
const raw =
|
|
53596
|
+
const raw = readFileSync34(metaPath, "utf-8");
|
|
53195
53597
|
const parsed = JSON.parse(raw);
|
|
53196
53598
|
if (!parsed || typeof parsed !== "object" || typeof parsed.name !== "string" || typeof parsed.createdAt !== "number" || typeof parsed.fromSessionId !== "string") {
|
|
53197
53599
|
throw new BranchCorruptError(`Branch "${name}" meta.json is malformed`);
|
|
@@ -53208,8 +53610,8 @@ function readBranchMeta(name, baseDir) {
|
|
|
53208
53610
|
}
|
|
53209
53611
|
function writeBranchMeta(name, baseDir, meta3) {
|
|
53210
53612
|
const metaPath = metaPathFor(name, baseDir);
|
|
53211
|
-
|
|
53212
|
-
|
|
53613
|
+
mkdirSync19(path46.dirname(metaPath), { recursive: true });
|
|
53614
|
+
writeFileSync22(metaPath, JSON.stringify(meta3, null, 2), "utf-8");
|
|
53213
53615
|
}
|
|
53214
53616
|
async function countSessions(name, baseDir) {
|
|
53215
53617
|
const sessionsPath = sessionsPathFor(name, baseDir);
|
|
@@ -53247,7 +53649,7 @@ var SessionNotFoundError = class extends Error {
|
|
|
53247
53649
|
};
|
|
53248
53650
|
function branchExists(name, baseDir = getBranchesBaseDir()) {
|
|
53249
53651
|
const bp = branchPathFor(name, baseDir);
|
|
53250
|
-
return
|
|
53652
|
+
return existsSync41(bp) && existsSync41(metaPathFor(name, baseDir));
|
|
53251
53653
|
}
|
|
53252
53654
|
async function createBranch(name, fromSessionId, baseDir = getBranchesBaseDir(), sessionsBaseDir = getSessionsBaseDir()) {
|
|
53253
53655
|
if (!name || name.trim().length === 0) {
|
|
@@ -53260,12 +53662,12 @@ async function createBranch(name, fromSessionId, baseDir = getBranchesBaseDir(),
|
|
|
53260
53662
|
throw new BranchAlreadyExistsError(name);
|
|
53261
53663
|
}
|
|
53262
53664
|
const sourcePath = path46.join(sessionsBaseDir, `${fromSessionId}.jsonl`);
|
|
53263
|
-
if (!
|
|
53665
|
+
if (!existsSync41(sourcePath)) {
|
|
53264
53666
|
throw new SessionNotFoundError(`Source session "${fromSessionId}" not found at ${sourcePath}`);
|
|
53265
53667
|
}
|
|
53266
53668
|
const branchPath = branchPathFor(name, baseDir);
|
|
53267
53669
|
const branchSessionsPath = sessionsPathFor(name, baseDir);
|
|
53268
|
-
|
|
53670
|
+
mkdirSync19(branchSessionsPath, { recursive: true });
|
|
53269
53671
|
const destPath = path46.join(branchSessionsPath, `${fromSessionId}.jsonl`);
|
|
53270
53672
|
await fs26.copyFile(sourcePath, destPath);
|
|
53271
53673
|
const meta3 = {
|
|
@@ -53293,7 +53695,7 @@ async function listBranches(baseDir = getBranchesBaseDir()) {
|
|
|
53293
53695
|
const results = [];
|
|
53294
53696
|
for (const entry of entries) {
|
|
53295
53697
|
const metaPath = metaPathFor(entry, baseDir);
|
|
53296
|
-
if (!
|
|
53698
|
+
if (!existsSync41(metaPath)) continue;
|
|
53297
53699
|
try {
|
|
53298
53700
|
const meta3 = readBranchMeta(entry, baseDir);
|
|
53299
53701
|
const sessionCount = await countSessions(entry, baseDir);
|
|
@@ -53484,7 +53886,7 @@ import path48 from "node:path";
|
|
|
53484
53886
|
import os13 from "node:os";
|
|
53485
53887
|
|
|
53486
53888
|
// src/cli/skillHistory.ts
|
|
53487
|
-
import { promises as fs28, existsSync as
|
|
53889
|
+
import { promises as fs28, existsSync as existsSync42, statSync as statSync6, renameSync as renameSync5, appendFileSync as appendFileSync4, mkdirSync as mkdirSync20 } from "node:fs";
|
|
53488
53890
|
var SKILL_HISTORY_ROTATE_BYTES = 10 * 1024 * 1024;
|
|
53489
53891
|
async function readSkillHistory(file2) {
|
|
53490
53892
|
let raw = "";
|
|
@@ -54812,9 +55214,9 @@ function ContinueKey({ onContinue }) {
|
|
|
54812
55214
|
init_providerConfig();
|
|
54813
55215
|
|
|
54814
55216
|
// src/cli/wizard/firstRun.ts
|
|
54815
|
-
import { existsSync as
|
|
55217
|
+
import { existsSync as existsSync44 } from "node:fs";
|
|
54816
55218
|
function shouldRunWizard(input) {
|
|
54817
|
-
const exists = input.exists ??
|
|
55219
|
+
const exists = input.exists ?? existsSync44;
|
|
54818
55220
|
if (input.hasResetConfigFlag) {
|
|
54819
55221
|
return { shouldRun: true, reason: "--reset-config flag forced wizard" };
|
|
54820
55222
|
}
|
|
@@ -55099,7 +55501,7 @@ init_keyStore();
|
|
|
55099
55501
|
init_providerConfig();
|
|
55100
55502
|
init_openai_compatible();
|
|
55101
55503
|
init_phase();
|
|
55102
|
-
import { readFileSync as
|
|
55504
|
+
import { readFileSync as readFileSync36 } from "node:fs";
|
|
55103
55505
|
function parseHeadlessFlags(argv) {
|
|
55104
55506
|
if (!argv.includes("--headless")) {
|
|
55105
55507
|
return { options: null };
|
|
@@ -55172,7 +55574,7 @@ function parseHeadlessFlags(argv) {
|
|
|
55172
55574
|
let raw = null;
|
|
55173
55575
|
if (arg === "--history-file") {
|
|
55174
55576
|
try {
|
|
55175
|
-
raw =
|
|
55577
|
+
raw = readFileSync36(next, "utf-8");
|
|
55176
55578
|
} catch {
|
|
55177
55579
|
raw = null;
|
|
55178
55580
|
}
|
|
@@ -55659,6 +56061,20 @@ async function runHeadlessSingle(opts, provider, model, providerStream) {
|
|
|
55659
56061
|
const sessionId = crypto.randomUUID();
|
|
55660
56062
|
const { registry: toolRegistry } = createBuiltinToolRegistry({
|
|
55661
56063
|
planMode: planModeFromOpts(opts),
|
|
56064
|
+
// ADR-0018 3b: upgrade plan-task domain events to first-class NDJSON
|
|
56065
|
+
// BrainEvents. Rust envelopes every stdout line with runId/conversationId,
|
|
56066
|
+
// so task events ride the same multiplexed channel as the rest.
|
|
56067
|
+
onTaskEvent: (ev) => {
|
|
56068
|
+
if (opts.output !== "json") return;
|
|
56069
|
+
emitEvent({
|
|
56070
|
+
type: ev.type,
|
|
56071
|
+
id: crypto.randomUUID(),
|
|
56072
|
+
ts: Date.now(),
|
|
56073
|
+
sessionId,
|
|
56074
|
+
source: ev.source,
|
|
56075
|
+
...ev.type === "task_update" ? { task: ev.task } : { tasks: ev.tasks }
|
|
56076
|
+
});
|
|
56077
|
+
},
|
|
55662
56078
|
permissionPolicy: {
|
|
55663
56079
|
read: "allow",
|
|
55664
56080
|
write: "allow",
|