zelari-code 0.7.5 → 0.7.8
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/bin/zelari-code.js +1 -1
- package/dist/agents/councilApi.js +7 -7
- package/dist/agents/councilApi.js.map +1 -1
- package/dist/agents/councilDirectives.js +3 -3
- package/dist/agents/promoteMember.js +2 -2
- package/dist/agents/roles.js +32 -50
- package/dist/agents/roles.js.map +1 -1
- package/dist/agents/skills/builtin/debugging.js +4 -4
- package/dist/agents/skills/builtin/debugging.js.map +1 -1
- package/dist/agents/skills/builtin/docs.js +13 -23
- package/dist/agents/skills/builtin/docs.js.map +1 -1
- package/dist/agents/skills/builtin/git-ops.js +3 -3
- package/dist/agents/skills/builtin/git-ops.js.map +1 -1
- package/dist/agents/skills/builtin/planning.js +4 -4
- package/dist/agents/skills/builtin/planning.js.map +1 -1
- package/dist/agents/skills/builtin/refactoring.js +3 -3
- package/dist/agents/skills/builtin/refactoring.js.map +1 -1
- package/dist/agents/skills/builtin/review.js +9 -9
- package/dist/agents/skills/builtin/review.js.map +1 -1
- package/dist/agents/skills/builtin/testing.js +3 -3
- package/dist/agents/skills/builtin/testing.js.map +1 -1
- package/dist/agents/tools.js +9 -2
- package/dist/agents/tools.js.map +1 -1
- package/dist/cli/app.js +2 -1
- package/dist/cli/app.js.map +1 -1
- package/dist/cli/components/CollapsibleToolOutput.js +26 -8
- package/dist/cli/components/CollapsibleToolOutput.js.map +1 -1
- package/dist/cli/components/Header.js +18 -6
- package/dist/cli/components/Header.js.map +1 -1
- package/dist/cli/components/Sidebar.js +31 -33
- package/dist/cli/components/Sidebar.js.map +1 -1
- package/dist/cli/components/SplashScreen.js +158 -0
- package/dist/cli/components/SplashScreen.js.map +1 -0
- package/dist/cli/councilDispatcher.js +20 -0
- package/dist/cli/councilDispatcher.js.map +1 -1
- package/dist/cli/main.bundled.js +983 -171
- package/dist/cli/main.bundled.js.map +4 -4
- package/dist/cli/main.js +9 -2
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/mcp/mcpClient.js +1 -1
- package/dist/cli/oauthCallbackServer.js +207 -0
- package/dist/cli/oauthCallbackServer.js.map +1 -0
- package/dist/cli/wizard/index.js +1 -1
- package/dist/cli/wizard/index.js.map +1 -1
- package/dist/cli/workspace/completeDesign.js +128 -0
- package/dist/cli/workspace/completeDesign.js.map +1 -0
- package/dist/cli/workspace/postCouncilHook.js +146 -20
- package/dist/cli/workspace/postCouncilHook.js.map +1 -1
- package/dist/cli/workspace/stubs.js +231 -95
- package/dist/cli/workspace/stubs.js.map +1 -1
- package/dist/main/core/AgentHarness.js +7 -36
- package/dist/main/core/AgentHarness.js.map +1 -1
- package/dist/main/core/tools/builtin/_walk.js +129 -0
- package/dist/main/core/tools/builtin/_walk.js.map +1 -0
- package/dist/main/core/tools/builtin/diff.js +477 -0
- package/dist/main/core/tools/builtin/diff.js.map +1 -0
- package/dist/main/core/tools/builtin/listFiles.js +5 -43
- package/dist/main/core/tools/builtin/listFiles.js.map +1 -1
- package/dist/main/core/tools/builtin/search.js +120 -28
- package/dist/main/core/tools/builtin/search.js.map +1 -1
- package/package.json +2 -2
package/dist/cli/main.bundled.js
CHANGED
|
@@ -141,12 +141,13 @@ var init_skills = __esm({
|
|
|
141
141
|
color: "#10b981",
|
|
142
142
|
enabledByDefault: true,
|
|
143
143
|
builtin: true,
|
|
144
|
-
requiredTools: ["createTask", "createPhase", "createMilestone", "updateTask"],
|
|
144
|
+
requiredTools: ["createPlan", "createTask", "createPhase", "createMilestone", "updateTask"],
|
|
145
145
|
systemPromptFragment: `You plan projects hierarchically.
|
|
146
146
|
- Decompose work into phases, then tasks within phases.
|
|
147
147
|
- For each task include: title, description, priority (low|medium|high|critical), and optional tags/subtasks.
|
|
148
148
|
- Define milestones to mark key deliverables.
|
|
149
|
-
- When relevant, reference file paths and acceptance criteria
|
|
149
|
+
- When relevant, reference file paths and acceptance criteria.
|
|
150
|
+
- Prefer ONE createPlan call (phases with nested tasks + milestone) over many itemized createPhase/createTask calls.`
|
|
150
151
|
},
|
|
151
152
|
{
|
|
152
153
|
id: "idea-synthesizer",
|
|
@@ -17043,6 +17044,61 @@ var init_toolSchemas = __esm({
|
|
|
17043
17044
|
"use strict";
|
|
17044
17045
|
init_tools();
|
|
17045
17046
|
PARAM_SCHEMAS = {
|
|
17047
|
+
createPlan: {
|
|
17048
|
+
type: "object",
|
|
17049
|
+
properties: {
|
|
17050
|
+
phases: {
|
|
17051
|
+
type: "array",
|
|
17052
|
+
description: "Ordered list of plan phases, each with its tasks nested (aim for 3 tasks per phase)",
|
|
17053
|
+
items: {
|
|
17054
|
+
type: "object",
|
|
17055
|
+
properties: {
|
|
17056
|
+
name: { type: "string", description: "Phase name" },
|
|
17057
|
+
description: { type: "string", description: "What this phase delivers and its exit criterion" },
|
|
17058
|
+
order: { type: "number", description: "Position of the phase in the plan (1-based)" },
|
|
17059
|
+
color: { type: "string", description: 'Hex color, e.g. "#3b82f6"' },
|
|
17060
|
+
tasks: {
|
|
17061
|
+
type: "array",
|
|
17062
|
+
description: "Concrete tasks for this phase",
|
|
17063
|
+
items: {
|
|
17064
|
+
type: "object",
|
|
17065
|
+
properties: {
|
|
17066
|
+
title: { type: "string", description: "Concise verb-led task title" },
|
|
17067
|
+
description: { type: "string", description: "2-3 sentences of context" },
|
|
17068
|
+
fileRefs: {
|
|
17069
|
+
type: "array",
|
|
17070
|
+
items: { type: "string" },
|
|
17071
|
+
description: 'File paths with line ranges, e.g. "src/App.tsx:L10-L40"'
|
|
17072
|
+
},
|
|
17073
|
+
acceptance: {
|
|
17074
|
+
type: "array",
|
|
17075
|
+
items: { type: "string" },
|
|
17076
|
+
description: "Concrete, testable acceptance criteria"
|
|
17077
|
+
},
|
|
17078
|
+
qaScenario: { type: "string", description: "Step-by-step manual QA scenario" },
|
|
17079
|
+
priority: { type: "string", enum: ["low", "medium", "high", "critical"] }
|
|
17080
|
+
},
|
|
17081
|
+
required: ["title"]
|
|
17082
|
+
}
|
|
17083
|
+
}
|
|
17084
|
+
},
|
|
17085
|
+
required: ["name"]
|
|
17086
|
+
}
|
|
17087
|
+
},
|
|
17088
|
+
milestone: {
|
|
17089
|
+
type: "object",
|
|
17090
|
+
description: "The milestone this plan ships (e.g. the design-complete milestone)",
|
|
17091
|
+
properties: {
|
|
17092
|
+
title: { type: "string", description: "Milestone title" },
|
|
17093
|
+
description: { type: "string", description: "Milestone description" },
|
|
17094
|
+
targetVersion: { type: "string", description: 'Target version, e.g. "v0.1.0"' },
|
|
17095
|
+
dueDate: { type: "string", description: "Due date (ISO string)" }
|
|
17096
|
+
},
|
|
17097
|
+
required: ["title"]
|
|
17098
|
+
}
|
|
17099
|
+
},
|
|
17100
|
+
required: ["phases"]
|
|
17101
|
+
},
|
|
17046
17102
|
createTask: {
|
|
17047
17103
|
type: "object",
|
|
17048
17104
|
properties: {
|
|
@@ -17051,6 +17107,17 @@ var init_toolSchemas = __esm({
|
|
|
17051
17107
|
priority: { type: "string", enum: ["low", "medium", "high", "critical"] },
|
|
17052
17108
|
phaseId: { type: "string", description: "ID of the phase this task belongs to" },
|
|
17053
17109
|
parentId: { type: "string", description: "ID of the parent task, if nested" },
|
|
17110
|
+
fileRefs: {
|
|
17111
|
+
type: "array",
|
|
17112
|
+
items: { type: "string" },
|
|
17113
|
+
description: 'File paths with line ranges where the work lands, e.g. "src/App.tsx:L10-L40"'
|
|
17114
|
+
},
|
|
17115
|
+
acceptance: {
|
|
17116
|
+
type: "array",
|
|
17117
|
+
items: { type: "string" },
|
|
17118
|
+
description: "Concrete, testable acceptance criteria"
|
|
17119
|
+
},
|
|
17120
|
+
qaScenario: { type: "string", description: "Step-by-step manual QA scenario" },
|
|
17054
17121
|
tags: { type: "array", items: { type: "string" } },
|
|
17055
17122
|
subtasks: { type: "array", items: { type: "string" }, description: "Subtask titles" }
|
|
17056
17123
|
},
|
|
@@ -17180,6 +17247,7 @@ var init_toolSchemas = __esm({
|
|
|
17180
17247
|
properties: {
|
|
17181
17248
|
title: { type: "string", description: "Milestone title" },
|
|
17182
17249
|
description: { type: "string", description: "Milestone description" },
|
|
17250
|
+
targetVersion: { type: "string", description: 'Target version this milestone ships, e.g. "v0.1.0"' },
|
|
17183
17251
|
dueDate: { type: "string", description: "Due date (ISO string)" }
|
|
17184
17252
|
},
|
|
17185
17253
|
required: ["title"]
|
|
@@ -17543,7 +17611,7 @@ async function refreshGrokToken(options) {
|
|
|
17543
17611
|
return parseTokenResponseBody(obj, accessToken);
|
|
17544
17612
|
}
|
|
17545
17613
|
async function openBrowser(url2) {
|
|
17546
|
-
const { spawn:
|
|
17614
|
+
const { spawn: spawn5 } = await import("node:child_process");
|
|
17547
17615
|
const cmd = (() => {
|
|
17548
17616
|
switch (process.platform) {
|
|
17549
17617
|
case "darwin":
|
|
@@ -17556,7 +17624,7 @@ async function openBrowser(url2) {
|
|
|
17556
17624
|
})();
|
|
17557
17625
|
return new Promise((resolve, reject) => {
|
|
17558
17626
|
try {
|
|
17559
|
-
const child =
|
|
17627
|
+
const child = spawn5(cmd.bin, cmd.args, {
|
|
17560
17628
|
stdio: "ignore",
|
|
17561
17629
|
detached: true
|
|
17562
17630
|
});
|
|
@@ -19202,6 +19270,7 @@ __export(stubs_exports, {
|
|
|
19202
19270
|
createWorkspaceContext: () => createWorkspaceContext,
|
|
19203
19271
|
createWorkspaceStubs: () => createWorkspaceStubs,
|
|
19204
19272
|
deriveProjectName: () => projectName,
|
|
19273
|
+
readPlanSummary: () => readPlanSummary,
|
|
19205
19274
|
resolveWorkspaceRoot: () => resolveWorkspaceRoot
|
|
19206
19275
|
});
|
|
19207
19276
|
import { existsSync as existsSync9, readdirSync as readdirSync3, writeFileSync as writeFileSync6, readFileSync as readFileSync6, mkdirSync as mkdirSync7, renameSync as renameSync3 } from "node:fs";
|
|
@@ -19316,8 +19385,108 @@ function nextAdrId(ctx) {
|
|
|
19316
19385
|
function slugify2(s) {
|
|
19317
19386
|
return s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 60);
|
|
19318
19387
|
}
|
|
19388
|
+
function addPhaseRecord(summary, input) {
|
|
19389
|
+
const id = slugify2(input.name) || `phase-${input.order}`;
|
|
19390
|
+
if (summary.phases.some((p3) => p3.id === id)) {
|
|
19391
|
+
return { id, created: false };
|
|
19392
|
+
}
|
|
19393
|
+
summary.phases.push({
|
|
19394
|
+
kind: "phase",
|
|
19395
|
+
id,
|
|
19396
|
+
name: input.name,
|
|
19397
|
+
description: input.description,
|
|
19398
|
+
order: input.order,
|
|
19399
|
+
color: input.color
|
|
19400
|
+
});
|
|
19401
|
+
return { id, created: true };
|
|
19402
|
+
}
|
|
19403
|
+
function addTaskRecord(ctx, summary, phaseId, t, options) {
|
|
19404
|
+
const slug = slugify2(t.title);
|
|
19405
|
+
if (options.dedupe) {
|
|
19406
|
+
const existing = summary.tasks.find(
|
|
19407
|
+
(k) => k.phaseId === phaseId && k.id.replace(/-\d+$/, "") === `${phaseId}-${slug}`
|
|
19408
|
+
);
|
|
19409
|
+
if (existing) return { id: existing.id, created: false };
|
|
19410
|
+
}
|
|
19411
|
+
const id = `${phaseId}-${slug}-${summary.tasks.filter((k) => k.phaseId === phaseId).length + 1}`;
|
|
19412
|
+
summary.tasks.push({
|
|
19413
|
+
kind: "task",
|
|
19414
|
+
id,
|
|
19415
|
+
// v0.7.3: keep the human-readable title in plan.json so
|
|
19416
|
+
// buildPlanSummary can render it in the system prompt.
|
|
19417
|
+
name: t.title,
|
|
19418
|
+
phaseId,
|
|
19419
|
+
status: "pending",
|
|
19420
|
+
priority: t.priority
|
|
19421
|
+
});
|
|
19422
|
+
const taskPath = join4(ctx.rootDir, "plan-tasks", `${id}.md`);
|
|
19423
|
+
const meta3 = {
|
|
19424
|
+
kind: "task",
|
|
19425
|
+
id,
|
|
19426
|
+
phaseId,
|
|
19427
|
+
status: "pending",
|
|
19428
|
+
priority: t.priority,
|
|
19429
|
+
tags: t.fileRefs
|
|
19430
|
+
};
|
|
19431
|
+
const body = [
|
|
19432
|
+
`# ${t.title}`,
|
|
19433
|
+
"",
|
|
19434
|
+
t.description,
|
|
19435
|
+
"",
|
|
19436
|
+
`## File references`,
|
|
19437
|
+
...t.fileRefs.map((f) => `- \`${f}\``),
|
|
19438
|
+
"",
|
|
19439
|
+
`## Acceptance criteria`,
|
|
19440
|
+
...t.acceptance.map((a) => `- ${a}`),
|
|
19441
|
+
"",
|
|
19442
|
+
`## QA scenario`,
|
|
19443
|
+
"",
|
|
19444
|
+
t.qaScenario || "_(not specified)_",
|
|
19445
|
+
""
|
|
19446
|
+
].join("\n");
|
|
19447
|
+
ctx.storage.write(taskPath, meta3, body);
|
|
19448
|
+
return { id, created: true };
|
|
19449
|
+
}
|
|
19450
|
+
function addMilestoneRecord(ctx, summary, input) {
|
|
19451
|
+
const id = `m-${slugify2(input.title)}`;
|
|
19452
|
+
if (summary.milestones.some((m) => m.id === id)) {
|
|
19453
|
+
return { id, created: false };
|
|
19454
|
+
}
|
|
19455
|
+
const version2 = input.targetVersion ?? input.dueDate ?? "TBD";
|
|
19456
|
+
summary.milestones.push({
|
|
19457
|
+
kind: "milestone",
|
|
19458
|
+
id,
|
|
19459
|
+
name: input.title,
|
|
19460
|
+
description: input.description,
|
|
19461
|
+
dueDate: input.dueDate,
|
|
19462
|
+
targetVersion: version2
|
|
19463
|
+
});
|
|
19464
|
+
const path22 = join4(ctx.rootDir, "milestones", `${id}.md`);
|
|
19465
|
+
const meta3 = {
|
|
19466
|
+
kind: "milestone",
|
|
19467
|
+
id,
|
|
19468
|
+
name: input.title,
|
|
19469
|
+
description: input.description,
|
|
19470
|
+
dueDate: input.dueDate,
|
|
19471
|
+
targetVersion: version2
|
|
19472
|
+
};
|
|
19473
|
+
const body = [
|
|
19474
|
+
`# Milestone: ${input.title}`,
|
|
19475
|
+
"",
|
|
19476
|
+
input.description,
|
|
19477
|
+
"",
|
|
19478
|
+
`Target version: ${version2}`,
|
|
19479
|
+
""
|
|
19480
|
+
].join("\n");
|
|
19481
|
+
ctx.storage.write(path22, meta3, body);
|
|
19482
|
+
return { id, created: true };
|
|
19483
|
+
}
|
|
19484
|
+
function readPlanSummary(ctx) {
|
|
19485
|
+
return readPlan(ctx);
|
|
19486
|
+
}
|
|
19319
19487
|
function createWorkspaceStubs(ctx) {
|
|
19320
19488
|
return [
|
|
19489
|
+
createPlanStub(ctx),
|
|
19321
19490
|
createPhaseStub(ctx),
|
|
19322
19491
|
createTaskStub(ctx),
|
|
19323
19492
|
updateTaskStub(ctx),
|
|
@@ -19329,6 +19498,67 @@ function createWorkspaceStubs(ctx) {
|
|
|
19329
19498
|
getDocumentBacklinksStub(ctx)
|
|
19330
19499
|
];
|
|
19331
19500
|
}
|
|
19501
|
+
function createPlanStub(ctx) {
|
|
19502
|
+
return {
|
|
19503
|
+
name: "createPlan",
|
|
19504
|
+
description: "Create the FULL project plan in one call: all phases, the tasks nested under each phase, and the target milestone. Preferred over itemized createPhase/createTask/createMilestone calls \u2014 one createPlan call persists everything atomically.",
|
|
19505
|
+
category: "project",
|
|
19506
|
+
parameters: [],
|
|
19507
|
+
execute: async (args) => {
|
|
19508
|
+
return workspaceMutex.run(`${ctx.rootDir}:plan`, () => {
|
|
19509
|
+
const rawPhases = Array.isArray(args["phases"]) ? args["phases"] : [];
|
|
19510
|
+
if (rawPhases.length === 0) {
|
|
19511
|
+
return 'createPlan requires a non-empty "phases" array (each phase: { name, description, order, color, tasks: [{ title, description, fileRefs, acceptance, qaScenario, priority }] }).';
|
|
19512
|
+
}
|
|
19513
|
+
const summary = readPlan(ctx);
|
|
19514
|
+
let phasesCreated = 0;
|
|
19515
|
+
let tasksCreated = 0;
|
|
19516
|
+
const phaseIds = [];
|
|
19517
|
+
rawPhases.forEach((rawPhase, idx) => {
|
|
19518
|
+
const { id: phaseId, created } = addPhaseRecord(summary, {
|
|
19519
|
+
name: rawPhase["name"] ?? `Phase ${idx + 1}`,
|
|
19520
|
+
description: rawPhase["description"] ?? "",
|
|
19521
|
+
order: rawPhase["order"] ?? idx + 1,
|
|
19522
|
+
color: rawPhase["color"] ?? "#3b82f6"
|
|
19523
|
+
});
|
|
19524
|
+
if (created) phasesCreated += 1;
|
|
19525
|
+
phaseIds.push(phaseId);
|
|
19526
|
+
const rawTasks = Array.isArray(rawPhase["tasks"]) ? rawPhase["tasks"] : [];
|
|
19527
|
+
for (const rawTask of rawTasks) {
|
|
19528
|
+
const { created: taskCreated } = addTaskRecord(
|
|
19529
|
+
ctx,
|
|
19530
|
+
summary,
|
|
19531
|
+
phaseId,
|
|
19532
|
+
{
|
|
19533
|
+
title: rawTask["title"] ?? "New Task",
|
|
19534
|
+
description: rawTask["description"] ?? "",
|
|
19535
|
+
fileRefs: rawTask["fileRefs"] ?? rawTask["files"] ?? [],
|
|
19536
|
+
acceptance: rawTask["acceptance"] ?? [],
|
|
19537
|
+
qaScenario: rawTask["qaScenario"] ?? rawTask["qa"] ?? "",
|
|
19538
|
+
priority: rawTask["priority"] ?? "medium"
|
|
19539
|
+
},
|
|
19540
|
+
{ dedupe: true }
|
|
19541
|
+
);
|
|
19542
|
+
if (taskCreated) tasksCreated += 1;
|
|
19543
|
+
}
|
|
19544
|
+
});
|
|
19545
|
+
let milestonesCreated = 0;
|
|
19546
|
+
const rawMilestone = args["milestone"];
|
|
19547
|
+
if (rawMilestone && typeof rawMilestone === "object") {
|
|
19548
|
+
const { created } = addMilestoneRecord(ctx, summary, {
|
|
19549
|
+
title: rawMilestone["title"] ?? "v0.1.0 design-complete",
|
|
19550
|
+
description: rawMilestone["description"] ?? "",
|
|
19551
|
+
dueDate: rawMilestone["dueDate"],
|
|
19552
|
+
targetVersion: rawMilestone["targetVersion"]
|
|
19553
|
+
});
|
|
19554
|
+
if (created) milestonesCreated += 1;
|
|
19555
|
+
}
|
|
19556
|
+
writePlan(ctx, summary);
|
|
19557
|
+
return `Plan created: ${phasesCreated} phases, ${tasksCreated} tasks, ${milestonesCreated} milestone(s). Phase ids: ${phaseIds.join(", ")}.`;
|
|
19558
|
+
});
|
|
19559
|
+
}
|
|
19560
|
+
};
|
|
19561
|
+
}
|
|
19332
19562
|
function createPhaseStub(ctx) {
|
|
19333
19563
|
return {
|
|
19334
19564
|
name: "createPhase",
|
|
@@ -19338,22 +19568,17 @@ function createPhaseStub(ctx) {
|
|
|
19338
19568
|
execute: async (args) => {
|
|
19339
19569
|
return workspaceMutex.run(`${ctx.rootDir}:plan`, () => {
|
|
19340
19570
|
const name = args["name"] ?? "New Phase";
|
|
19341
|
-
const description = args["description"] ?? "";
|
|
19342
19571
|
const order = args["order"] ?? 0;
|
|
19343
|
-
const color = args["color"] ?? "#3b82f6";
|
|
19344
|
-
const id = slugify2(name) || `phase-${order}`;
|
|
19345
19572
|
const summary = readPlan(ctx);
|
|
19346
|
-
|
|
19347
|
-
return `Phase "${id}" already exists.`;
|
|
19348
|
-
}
|
|
19349
|
-
summary.phases.push({
|
|
19350
|
-
kind: "phase",
|
|
19351
|
-
id,
|
|
19573
|
+
const { id, created } = addPhaseRecord(summary, {
|
|
19352
19574
|
name,
|
|
19353
|
-
description,
|
|
19575
|
+
description: args["description"] ?? "",
|
|
19354
19576
|
order,
|
|
19355
|
-
color
|
|
19577
|
+
color: args["color"] ?? "#3b82f6"
|
|
19356
19578
|
});
|
|
19579
|
+
if (!created) {
|
|
19580
|
+
return `Phase "${id}" already exists.`;
|
|
19581
|
+
}
|
|
19357
19582
|
writePlan(ctx, summary);
|
|
19358
19583
|
return `Phase "${name}" created (id: ${id}, order: ${order}).`;
|
|
19359
19584
|
});
|
|
@@ -19370,54 +19595,26 @@ function createTaskStub(ctx) {
|
|
|
19370
19595
|
return workspaceMutex.run(`${ctx.rootDir}:plan`, () => {
|
|
19371
19596
|
const phaseId = args["phaseId"] ?? args["phase"];
|
|
19372
19597
|
const title = args["title"] ?? "New Task";
|
|
19373
|
-
const description = args["description"] ?? "";
|
|
19374
|
-
const fileRefs = args["fileRefs"] ?? args["files"] ?? [];
|
|
19375
|
-
const acceptance = args["acceptance"] ?? [];
|
|
19376
|
-
const qaScenario = args["qaScenario"] ?? args["qa"] ?? "";
|
|
19377
|
-
const priority = args["priority"] ?? "medium";
|
|
19378
19598
|
if (!phaseId) return "Task requires a phaseId.";
|
|
19379
19599
|
const summary = readPlan(ctx);
|
|
19380
19600
|
if (!summary.phases.some((p3) => p3.id === phaseId)) {
|
|
19381
19601
|
return `Phase "${phaseId}" not found. Create it first via /createPhase.`;
|
|
19382
19602
|
}
|
|
19383
|
-
const id =
|
|
19384
|
-
|
|
19385
|
-
|
|
19386
|
-
id,
|
|
19387
|
-
// v0.7.3: keep the human-readable title in plan.json so
|
|
19388
|
-
// buildPlanSummary can render it in the system prompt.
|
|
19389
|
-
name: title,
|
|
19603
|
+
const { id } = addTaskRecord(
|
|
19604
|
+
ctx,
|
|
19605
|
+
summary,
|
|
19390
19606
|
phaseId,
|
|
19391
|
-
|
|
19392
|
-
|
|
19393
|
-
|
|
19607
|
+
{
|
|
19608
|
+
title,
|
|
19609
|
+
description: args["description"] ?? "",
|
|
19610
|
+
fileRefs: args["fileRefs"] ?? args["files"] ?? [],
|
|
19611
|
+
acceptance: args["acceptance"] ?? [],
|
|
19612
|
+
qaScenario: args["qaScenario"] ?? args["qa"] ?? "",
|
|
19613
|
+
priority: args["priority"] ?? "medium"
|
|
19614
|
+
},
|
|
19615
|
+
{ dedupe: false }
|
|
19616
|
+
);
|
|
19394
19617
|
writePlan(ctx, summary);
|
|
19395
|
-
const taskPath = join4(ctx.rootDir, "plan-tasks", `${id}.md`);
|
|
19396
|
-
const meta3 = {
|
|
19397
|
-
kind: "task",
|
|
19398
|
-
id,
|
|
19399
|
-
phaseId,
|
|
19400
|
-
status: "pending",
|
|
19401
|
-
priority,
|
|
19402
|
-
tags: fileRefs
|
|
19403
|
-
};
|
|
19404
|
-
const body = [
|
|
19405
|
-
`# ${title}`,
|
|
19406
|
-
"",
|
|
19407
|
-
description,
|
|
19408
|
-
"",
|
|
19409
|
-
`## File references`,
|
|
19410
|
-
...fileRefs.map((f) => `- \`${f}\``),
|
|
19411
|
-
"",
|
|
19412
|
-
`## Acceptance criteria`,
|
|
19413
|
-
...acceptance.map((a) => `- ${a}`),
|
|
19414
|
-
"",
|
|
19415
|
-
`## QA scenario`,
|
|
19416
|
-
"",
|
|
19417
|
-
qaScenario || "_(not specified)_",
|
|
19418
|
-
""
|
|
19419
|
-
].join("\n");
|
|
19420
|
-
ctx.storage.write(taskPath, meta3, body);
|
|
19421
19618
|
return `Task "${title}" created (id: ${id}) under phase "${phaseId}".`;
|
|
19422
19619
|
});
|
|
19423
19620
|
}
|
|
@@ -19523,39 +19720,16 @@ function createMilestoneStub(ctx) {
|
|
|
19523
19720
|
execute: async (args) => {
|
|
19524
19721
|
return workspaceMutex.run(`${ctx.rootDir}:plan`, () => {
|
|
19525
19722
|
const title = args["title"] ?? "New Milestone";
|
|
19526
|
-
const description = args["description"] ?? "";
|
|
19527
|
-
const dueDate = args["dueDate"];
|
|
19528
|
-
const id = `m-${slugify2(title)}`;
|
|
19529
19723
|
const summary = readPlan(ctx);
|
|
19530
|
-
|
|
19531
|
-
|
|
19532
|
-
|
|
19533
|
-
|
|
19534
|
-
|
|
19535
|
-
name: title,
|
|
19536
|
-
description,
|
|
19537
|
-
dueDate,
|
|
19538
|
-
targetVersion: version2
|
|
19724
|
+
const { id, created } = addMilestoneRecord(ctx, summary, {
|
|
19725
|
+
title,
|
|
19726
|
+
description: args["description"] ?? "",
|
|
19727
|
+
dueDate: args["dueDate"],
|
|
19728
|
+
targetVersion: args["targetVersion"]
|
|
19539
19729
|
});
|
|
19730
|
+
if (!created) return `Milestone "${id}" already exists.`;
|
|
19540
19731
|
writePlan(ctx, summary);
|
|
19541
|
-
const
|
|
19542
|
-
const meta3 = {
|
|
19543
|
-
kind: "milestone",
|
|
19544
|
-
id,
|
|
19545
|
-
name: title,
|
|
19546
|
-
description,
|
|
19547
|
-
dueDate,
|
|
19548
|
-
targetVersion: version2
|
|
19549
|
-
};
|
|
19550
|
-
const body = [
|
|
19551
|
-
`# Milestone: ${title}`,
|
|
19552
|
-
"",
|
|
19553
|
-
description,
|
|
19554
|
-
"",
|
|
19555
|
-
`Target version: ${version2}`,
|
|
19556
|
-
""
|
|
19557
|
-
].join("\n");
|
|
19558
|
-
ctx.storage.write(path22, meta3, body);
|
|
19732
|
+
const version2 = summary.milestones.find((m) => m.id === id)?.targetVersion ?? "TBD";
|
|
19559
19733
|
return `Milestone "${title}" created (id: ${id}, version: ${version2}).`;
|
|
19560
19734
|
});
|
|
19561
19735
|
}
|
|
@@ -19572,7 +19746,8 @@ function createDocumentStub(ctx) {
|
|
|
19572
19746
|
const title = args["title"] ?? "New Document";
|
|
19573
19747
|
const content = args["content"] ?? "";
|
|
19574
19748
|
const tags = args["tags"] ?? [];
|
|
19575
|
-
const
|
|
19749
|
+
const normalizedTitle = title.replace(/\.(md|markdown)\s*$/i, "");
|
|
19750
|
+
const id = slugify2(normalizedTitle) || `doc-${Date.now()}`;
|
|
19576
19751
|
const path22 = workspaceArtifact(ctx.rootDir, "docs", id);
|
|
19577
19752
|
const meta3 = {
|
|
19578
19753
|
kind: "doc",
|
|
@@ -19658,8 +19833,8 @@ function linkDocumentsStub(ctx) {
|
|
|
19658
19833
|
parameters: [],
|
|
19659
19834
|
execute: async (args) => {
|
|
19660
19835
|
return workspaceMutex.run(`${ctx.rootDir}:link`, () => {
|
|
19661
|
-
const fromId = args["fromId"];
|
|
19662
|
-
const toId = args["toId"];
|
|
19836
|
+
const fromId = args["fromId"] ?? args["sourceId"];
|
|
19837
|
+
const toId = args["toId"] ?? args["targetId"] ?? args["targetPathOrTitle"];
|
|
19663
19838
|
if (!fromId || !toId) return "linkDocuments requires fromId and toId.";
|
|
19664
19839
|
const allFiles = [
|
|
19665
19840
|
...ctx.storage.listMarkdown(join4(ctx.rootDir, "decisions")),
|
|
@@ -19692,7 +19867,7 @@ function getDocumentBacklinksStub(ctx) {
|
|
|
19692
19867
|
category: "analysis",
|
|
19693
19868
|
parameters: [],
|
|
19694
19869
|
execute: async (args) => {
|
|
19695
|
-
const targetId = args["targetId"];
|
|
19870
|
+
const targetId = args["targetId"] ?? args["id"];
|
|
19696
19871
|
if (!targetId) return "getDocumentBacklinks requires targetId.";
|
|
19697
19872
|
const allFiles = [
|
|
19698
19873
|
...ctx.storage.listMarkdown(join4(ctx.rootDir, "decisions")),
|
|
@@ -19820,7 +19995,7 @@ var init_mcpClient = __esm({
|
|
|
19820
19995
|
{
|
|
19821
19996
|
protocolVersion: MCP_PROTOCOL_VERSION,
|
|
19822
19997
|
capabilities: {},
|
|
19823
|
-
clientInfo: { name: "zelari-code", version: "0.7.
|
|
19998
|
+
clientInfo: { name: "zelari-code", version: "0.7.8" }
|
|
19824
19999
|
},
|
|
19825
20000
|
INIT_TIMEOUT_MS
|
|
19826
20001
|
);
|
|
@@ -20135,7 +20310,40 @@ Example format:
|
|
|
20135
20310
|
- Make dependencies explicit (task B depends on task A).
|
|
20136
20311
|
- If the stack/platform is unknown, ask ONCE (see clarification protocol) rather than guessing.
|
|
20137
20312
|
|
|
20138
|
-
Keep plans hierarchical and practical. Stay under 250 words.${CLARIFICATION_PROTOCOL8}
|
|
20313
|
+
Keep plans hierarchical and practical. Stay under 250 words.${CLARIFICATION_PROTOCOL8}
|
|
20314
|
+
|
|
20315
|
+
## Design-phase mandatory plan artifact
|
|
20316
|
+
In design-phase mode (TASK mentions design/architecture/spec, no existing codebase to edit), you MUST persist the plan through workspace tools. The plan exists ONLY if it was persisted via a tool call \u2014 prose does not count, and the post-run check will flag your run if the plan is missing.
|
|
20317
|
+
|
|
20318
|
+
PREFERRED \u2014 emit ONE single \`createPlan\` call containing the whole plan: 4 phases, 12 concrete tasks (3 per phase), and 1 milestone, all in the same call:
|
|
20319
|
+
|
|
20320
|
+
\`\`\`
|
|
20321
|
+
createPlan({
|
|
20322
|
+
phases: [
|
|
20323
|
+
{
|
|
20324
|
+
name: "Foundation & Technical Blueprint",
|
|
20325
|
+
description: "Lock the stack and the non-negotiable quality budget. Exit: baseline builds green.",
|
|
20326
|
+
order: 1,
|
|
20327
|
+
color: "#3b82f6",
|
|
20328
|
+
tasks: [
|
|
20329
|
+
{ title: "Lock stack baseline", description: "2-3 sentences of context", fileRefs: ["src/main.tsx:L1-L40"], acceptance: ["App boots with strict TS", "CI build green"], qaScenario: "Run npm run build and confirm zero errors", priority: "high" },
|
|
20330
|
+
{ title: "Define NFR budget", description: "...", fileRefs: ["docs/nfr.md"], acceptance: ["LCP/WCAG/Lighthouse targets documented"], qaScenario: "...", priority: "high" },
|
|
20331
|
+
{ title: "Document design-phase exit criteria", description: "...", fileRefs: ["docs/exit-criteria.md"], acceptance: ["Each phase has a testable exit row"], qaScenario: "...", priority: "medium" }
|
|
20332
|
+
]
|
|
20333
|
+
},
|
|
20334
|
+
{ name: "...", order: 2, tasks: [ /* 3 tasks */ ] },
|
|
20335
|
+
{ name: "...", order: 3, tasks: [ /* 3 tasks */ ] },
|
|
20336
|
+
{ name: "...", order: 4, tasks: [ /* 3 tasks */ ] }
|
|
20337
|
+
],
|
|
20338
|
+
milestone: { title: "v0.1.0 design-complete", description: "All design artifacts exist and the green-light checklist passes.", targetVersion: "v0.1.0" }
|
|
20339
|
+
})
|
|
20340
|
+
\`\`\`
|
|
20341
|
+
|
|
20342
|
+
Every task MUST include fileRefs, acceptance, and qaScenario \u2014 the QA scenario proves the task is verifiable.
|
|
20343
|
+
|
|
20344
|
+
FALLBACK \u2014 only if you cannot batch, use the itemized tools: \`createPhase\` once per phase; each createPhase response returns the new phase id \u2014 use that exact id as \`phaseId\` in the 3 \`createTask\` calls for that phase; finish with one \`createMilestone\` ({ title, description, targetVersion }). If you forget an id, call \`searchDocuments\` (limit 1) to look it up, then continue.
|
|
20345
|
+
|
|
20346
|
+
Do NOT output tasks as prose. The system will refuse any task that does not pass a valid phaseId.`,
|
|
20139
20347
|
// v0.7.2: read/search the codebase to ground the plan in reality.
|
|
20140
20348
|
tools: ["list_files", "read_file", "grep_content"],
|
|
20141
20349
|
skills: ["project-planner", "vault-manager"]
|
|
@@ -20166,7 +20374,18 @@ Keep plans hierarchical and practical. Stay under 250 words.${CLARIFICATION_PROT
|
|
|
20166
20374
|
## Themes
|
|
20167
20375
|
## Top picks (with feasibility/novelty + de-risk note)
|
|
20168
20376
|
|
|
20169
|
-
Stay under 200 words.${CLARIFICATION_PROTOCOL8}
|
|
20377
|
+
Stay under 200 words.${CLARIFICATION_PROTOCOL8}
|
|
20378
|
+
|
|
20379
|
+
## Design-phase artifact (mandatory when running council in design-phase mode)
|
|
20380
|
+
If the council is in design-phase mode (TASK mentions design/architecture/spec, no existing codebase to edit), you MUST also persist your ideation output as workspace documents via the \`createDocument\` tool. Emit AT LEAST 3 separate \`createDocument\` calls, each tagged with one of these categories:
|
|
20381
|
+
|
|
20382
|
+
- \`customer-journey-map\` \u2014 2-3 personas (give them names, demographics, goals), journey table (stage \u2192 action \u2192 touchpoint \u2192 emotion), pain points per stage. This is a customer journey deliverable.
|
|
20383
|
+
- \`information-architecture\` \u2014 site map tree (root \u2192 section \u2192 page), navigation model (primary nav, breadcrumbs, footer), URL patterns. This is an information architecture deliverable.
|
|
20384
|
+
- \`design-tokens\` \u2014 color palette (semantic + hex), typography scale, spacing scale, motion principles. This is a design tokens deliverable.
|
|
20385
|
+
|
|
20386
|
+
You may optionally add a 4th design system doc if the project warrants it.
|
|
20387
|
+
|
|
20388
|
+
Pass the tool call as: \`createDocument({ title: "<category>", content: "<markdown body>" })\`. Do NOT summarize these into prose \u2014 they are the deliverable.`,
|
|
20170
20389
|
// v0.7.2: explore the codebase to ground ideas in what exists.
|
|
20171
20390
|
tools: ["list_files", "read_file"],
|
|
20172
20391
|
skills: ["idea-synthesizer", "mind-mapper", "document-writer"]
|
|
@@ -20226,7 +20445,19 @@ Describe the proposed structure (root \u2192 branches \u2192 leaves) in text and
|
|
|
20226
20445
|
## Contradictions
|
|
20227
20446
|
## Top improvements
|
|
20228
20447
|
|
|
20229
|
-
Stay under 200 words
|
|
20448
|
+
Stay under 200 words.${CLARIFICATION_PROTOCOL8}
|
|
20449
|
+
|
|
20450
|
+
## Design-phase risks artifact (mandatory when running council in design-phase mode)
|
|
20451
|
+
When the council is in design-phase mode (TASK mentions design/architecture/spec, no existing codebase to edit), you ALSO write a \`risks\` document via the \`createDocument\` tool. This is your one allowed artifact emission. Pass the tool call as:
|
|
20452
|
+
|
|
20453
|
+
\`\`\`
|
|
20454
|
+
createDocument({
|
|
20455
|
+
title: "risks",
|
|
20456
|
+
content: \`# Risks\\n\\n## 1. <Risk title>\\n- Impact: <high|medium|low>\\n- Likelihood: <high|medium|low>\\n- Mitigation: <one-line mitigation>\\n\\n## 2. ...\`
|
|
20457
|
+
})
|
|
20458
|
+
\`\`\`
|
|
20459
|
+
|
|
20460
|
+
Include AT LEAST 5 risks, each scored on Impact and Likelihood, with a one-line mitigation. Cover: technical (e.g. stack risk), product (e.g. scope creep), accessibility, performance, security. Do NOT emit other workspace artifacts \u2014 your role is to evaluate, not to build.`,
|
|
20230
20461
|
tools: [],
|
|
20231
20462
|
skills: ["research-analyst"]
|
|
20232
20463
|
},
|
|
@@ -20251,7 +20482,19 @@ Stay under 200 words. (You do not create workspace artifacts, so you do not emit
|
|
|
20251
20482
|
- Apply Minosse's highest-value improvements; drop descoped items.
|
|
20252
20483
|
- After making changes, verify they work (compile, run tests, etc.) when feasible.
|
|
20253
20484
|
|
|
20254
|
-
Use the tools available to you (read_file, write_file, edit_file, bash, list_files) directly as tool calls \u2014 the harness handles execution.${CLARIFICATION_PROTOCOL8}
|
|
20485
|
+
Use the tools available to you (read_file, write_file, edit_file, bash, list_files) directly as tool calls \u2014 the harness handles execution.${CLARIFICATION_PROTOCOL8}
|
|
20486
|
+
|
|
20487
|
+
## Design-phase synthesis artifact (mandatory when running council in design-phase mode)
|
|
20488
|
+
When the council is in design-phase mode (TASK mentions design/architecture/spec, no existing codebase to edit), your final deliverable is a \`synthesis\` document via the \`createDocument\` tool (NOT \`write_file\` and NOT \`list_files\`):
|
|
20489
|
+
|
|
20490
|
+
\`\`\`
|
|
20491
|
+
createDocument({
|
|
20492
|
+
title: "synthesis",
|
|
20493
|
+
content: \`# Council Synthesis\\n\\n## Executive summary\\n<2-3 paragraphs>\\n\\n## Stack and key decisions\\n- <ADR-by-ADR summary>\\n\\n## Phases\\n<1-2 line summary per phase>\\n\\n## Top risks\\n<top 3 risks from Minosse>\\n\\n## Green-light checklist\\n- [ ] All ADRs accepted\\n- [ ] Risks have mitigations\\n- [ ] Tasks have acceptance criteria\`
|
|
20494
|
+
})
|
|
20495
|
+
\`\`\`
|
|
20496
|
+
|
|
20497
|
+
DO NOT call \`list_files\` \u2014 it is NOT a workspace tool. Use \`searchDocuments\` if you need to look something up (limit 2-3 searches, then act on the results). Your deliverable is the synthesis document; emit it via \`createDocument\`, not via prose.`,
|
|
20255
20498
|
// v0.7.2: implementation tools — the synthesizer writes/edits files and runs commands.
|
|
20256
20499
|
tools: ["read_file", "write_file", "edit_file", "bash", "list_files"],
|
|
20257
20500
|
skills: ["vault-manager", "project-planner", "idea-synthesizer"]
|
|
@@ -20707,8 +20950,14 @@ async function* runCouncilPure(userMessage, config2, callbacks = {}) {
|
|
|
20707
20950
|
};
|
|
20708
20951
|
callbacks.onMemberCost?.(cost);
|
|
20709
20952
|
};
|
|
20710
|
-
const
|
|
20711
|
-
const
|
|
20953
|
+
const executorToolNames = config2.tools ? config2.tools.list() : [];
|
|
20954
|
+
const executableNames = config2.tools ? new Set(executorToolNames) : null;
|
|
20955
|
+
const filterExecutable = (names) => {
|
|
20956
|
+
if (!executableNames)
|
|
20957
|
+
return names;
|
|
20958
|
+
const merged = Array.from(/* @__PURE__ */ new Set([...names, ...executorToolNames]));
|
|
20959
|
+
return merged.filter((n) => executableNames.has(n));
|
|
20960
|
+
};
|
|
20712
20961
|
const allSpecialists = agents.filter((a) => a.id !== "lucifer" && a.id !== "minos");
|
|
20713
20962
|
const specialists = config2.feedbackStore ? config2.feedbackStore.ranked(allSpecialists) : allSpecialists;
|
|
20714
20963
|
const oracle = agents.find((a) => a.id === "minos");
|
|
@@ -20751,12 +21000,14 @@ async function* runCouncilPure(userMessage, config2, callbacks = {}) {
|
|
|
20751
21000
|
let toolCalls = 0;
|
|
20752
21001
|
let usage = null;
|
|
20753
21002
|
let errored = false;
|
|
21003
|
+
const emittedToolNames = [];
|
|
20754
21004
|
const memberStart = Date.now();
|
|
20755
21005
|
try {
|
|
20756
21006
|
for await (const event of harness.run()) {
|
|
20757
21007
|
yield event;
|
|
20758
21008
|
if (event.type === "tool_execution_start") {
|
|
20759
21009
|
toolCalls += 1;
|
|
21010
|
+
emittedToolNames.push(event.toolName);
|
|
20760
21011
|
}
|
|
20761
21012
|
if (event.type === "message_end" && event.usage) {
|
|
20762
21013
|
usage = event.usage;
|
|
@@ -20774,6 +21025,27 @@ async function* runCouncilPure(userMessage, config2, callbacks = {}) {
|
|
|
20774
21025
|
fullText = `Error: ${err instanceof Error ? err.message : "Unknown"}`;
|
|
20775
21026
|
errored = true;
|
|
20776
21027
|
}
|
|
21028
|
+
if (!errored && !NON_RETRY_AGENTS.has(agent.id)) {
|
|
21029
|
+
const specialistCheck = enforceDesignPhaseToolEmissions(agent.id, emittedToolNames);
|
|
21030
|
+
yield* applyRetryIfMissing({
|
|
21031
|
+
agent,
|
|
21032
|
+
check: specialistCheck,
|
|
21033
|
+
requirements: DESIGN_PHASE_REQUIREMENTS[agent.id],
|
|
21034
|
+
emittedToolNames,
|
|
21035
|
+
executableNames,
|
|
21036
|
+
sessionId,
|
|
21037
|
+
userMessage,
|
|
21038
|
+
agentOutputs,
|
|
21039
|
+
config: config2,
|
|
21040
|
+
effectiveProvider,
|
|
21041
|
+
effectiveModel,
|
|
21042
|
+
onToolCall: () => {
|
|
21043
|
+
toolCalls += 1;
|
|
21044
|
+
}
|
|
21045
|
+
});
|
|
21046
|
+
} else {
|
|
21047
|
+
enforceDesignPhaseToolEmissions(agent.id, emittedToolNames);
|
|
21048
|
+
}
|
|
20777
21049
|
const memberDuration = Date.now() - memberStart;
|
|
20778
21050
|
emitMemberCost({
|
|
20779
21051
|
memberId: agent.id,
|
|
@@ -20819,7 +21091,7 @@ async function* runCouncilPure(userMessage, config2, callbacks = {}) {
|
|
|
20819
21091
|
});
|
|
20820
21092
|
}
|
|
20821
21093
|
}
|
|
20822
|
-
if (
|
|
21094
|
+
if (oracle && !completedIds.has(oracle.id)) {
|
|
20823
21095
|
callbacks.onAgentStart?.(oracle);
|
|
20824
21096
|
const override = config2.agentModels?.[oracle.id];
|
|
20825
21097
|
const effectiveProvider = override?.providerId ?? config2.provider ?? "minimax";
|
|
@@ -20852,12 +21124,14 @@ async function* runCouncilPure(userMessage, config2, callbacks = {}) {
|
|
|
20852
21124
|
let toolCalls = 0;
|
|
20853
21125
|
let usage = null;
|
|
20854
21126
|
let errored = false;
|
|
21127
|
+
const emittedToolNames = [];
|
|
20855
21128
|
const memberStart = Date.now();
|
|
20856
21129
|
try {
|
|
20857
21130
|
for await (const event of harness.run()) {
|
|
20858
21131
|
yield event;
|
|
20859
21132
|
if (event.type === "tool_execution_start") {
|
|
20860
21133
|
toolCalls += 1;
|
|
21134
|
+
emittedToolNames.push(event.toolName);
|
|
20861
21135
|
}
|
|
20862
21136
|
if (event.type === "message_end" && event.usage) {
|
|
20863
21137
|
usage = event.usage;
|
|
@@ -20875,6 +21149,27 @@ async function* runCouncilPure(userMessage, config2, callbacks = {}) {
|
|
|
20875
21149
|
fullText = `Review error: ${err instanceof Error ? err.message : "Unknown"}`;
|
|
20876
21150
|
errored = true;
|
|
20877
21151
|
}
|
|
21152
|
+
if (!errored) {
|
|
21153
|
+
const oracleCheck = enforceDesignPhaseToolEmissions(oracle.id, emittedToolNames);
|
|
21154
|
+
yield* applyRetryIfMissing({
|
|
21155
|
+
agent: oracle,
|
|
21156
|
+
check: oracleCheck,
|
|
21157
|
+
requirements: DESIGN_PHASE_REQUIREMENTS[oracle.id],
|
|
21158
|
+
emittedToolNames,
|
|
21159
|
+
executableNames,
|
|
21160
|
+
sessionId,
|
|
21161
|
+
userMessage: `Review these proposals for: "${userMessage}"`,
|
|
21162
|
+
agentOutputs,
|
|
21163
|
+
config: config2,
|
|
21164
|
+
effectiveProvider,
|
|
21165
|
+
effectiveModel,
|
|
21166
|
+
onToolCall: () => {
|
|
21167
|
+
toolCalls += 1;
|
|
21168
|
+
}
|
|
21169
|
+
});
|
|
21170
|
+
} else {
|
|
21171
|
+
enforceDesignPhaseToolEmissions(oracle.id, emittedToolNames);
|
|
21172
|
+
}
|
|
20878
21173
|
const memberDuration = Date.now() - memberStart;
|
|
20879
21174
|
emitMemberCost({
|
|
20880
21175
|
memberId: oracle.id,
|
|
@@ -20948,12 +21243,14 @@ async function* runCouncilPure(userMessage, config2, callbacks = {}) {
|
|
|
20948
21243
|
let usage = null;
|
|
20949
21244
|
let errored = false;
|
|
20950
21245
|
let lastErrorMessage = "";
|
|
21246
|
+
const emittedToolNames = [];
|
|
20951
21247
|
const memberStart = Date.now();
|
|
20952
21248
|
try {
|
|
20953
21249
|
for await (const event of chairmanHarness.run()) {
|
|
20954
21250
|
yield event;
|
|
20955
21251
|
if (event.type === "tool_execution_start") {
|
|
20956
21252
|
toolCalls += 1;
|
|
21253
|
+
emittedToolNames.push(event.toolName);
|
|
20957
21254
|
}
|
|
20958
21255
|
if (event.type === "message_end" && event.usage) {
|
|
20959
21256
|
usage = event.usage;
|
|
@@ -20975,6 +21272,27 @@ async function* runCouncilPure(userMessage, config2, callbacks = {}) {
|
|
|
20975
21272
|
errored = true;
|
|
20976
21273
|
lastErrorMessage = err instanceof Error ? err.message : String(err);
|
|
20977
21274
|
}
|
|
21275
|
+
if (!errored) {
|
|
21276
|
+
const chairmanCheck = enforceDesignPhaseToolEmissions(chairman.id, emittedToolNames);
|
|
21277
|
+
yield* applyRetryIfMissing({
|
|
21278
|
+
agent: chairman,
|
|
21279
|
+
check: chairmanCheck,
|
|
21280
|
+
requirements: DESIGN_PHASE_REQUIREMENTS[chairman.id],
|
|
21281
|
+
emittedToolNames,
|
|
21282
|
+
executableNames,
|
|
21283
|
+
sessionId,
|
|
21284
|
+
userMessage,
|
|
21285
|
+
agentOutputs,
|
|
21286
|
+
config: config2,
|
|
21287
|
+
effectiveProvider,
|
|
21288
|
+
effectiveModel,
|
|
21289
|
+
onToolCall: () => {
|
|
21290
|
+
toolCalls += 1;
|
|
21291
|
+
}
|
|
21292
|
+
});
|
|
21293
|
+
} else {
|
|
21294
|
+
enforceDesignPhaseToolEmissions(chairman.id, emittedToolNames);
|
|
21295
|
+
}
|
|
20978
21296
|
const memberDuration = Date.now() - memberStart;
|
|
20979
21297
|
const finalSynthesis = errored && fullText.length === 0 ? `[Chairman synthesis failed: ${lastErrorMessage || "unknown error"}]` : fullText;
|
|
20980
21298
|
callbacks.onSynthesisDone?.(finalSynthesis, void 0, void 0);
|
|
@@ -21008,7 +21326,142 @@ async function* runCouncilPure(userMessage, config2, callbacks = {}) {
|
|
|
21008
21326
|
durationMs: 0
|
|
21009
21327
|
};
|
|
21010
21328
|
}
|
|
21011
|
-
|
|
21329
|
+
function checkMemberToolEmissions(_memberId, emittedToolNames, requirements) {
|
|
21330
|
+
if (requirements.length === 0) {
|
|
21331
|
+
return { ok: true, missing: [] };
|
|
21332
|
+
}
|
|
21333
|
+
const counts = /* @__PURE__ */ new Map();
|
|
21334
|
+
for (const name of emittedToolNames) {
|
|
21335
|
+
counts.set(name, (counts.get(name) ?? 0) + 1);
|
|
21336
|
+
}
|
|
21337
|
+
const missing = [];
|
|
21338
|
+
for (const req of requirements) {
|
|
21339
|
+
const got = counts.get(req.name) ?? 0;
|
|
21340
|
+
if (got < req.min) {
|
|
21341
|
+
missing.push(`${req.name} (got ${got}, need >= ${req.min})`);
|
|
21342
|
+
}
|
|
21343
|
+
}
|
|
21344
|
+
return { ok: missing.length === 0, missing };
|
|
21345
|
+
}
|
|
21346
|
+
function checkMemberToolEmissionSets(memberId, emittedToolNames, sets) {
|
|
21347
|
+
if (sets.length === 0) {
|
|
21348
|
+
return { ok: true, missing: [] };
|
|
21349
|
+
}
|
|
21350
|
+
const results = sets.map((set2) => checkMemberToolEmissions(memberId, emittedToolNames, set2));
|
|
21351
|
+
if (results.some((r) => r.ok)) {
|
|
21352
|
+
return { ok: true, missing: [] };
|
|
21353
|
+
}
|
|
21354
|
+
return results[0];
|
|
21355
|
+
}
|
|
21356
|
+
function enforceDesignPhaseToolEmissions(memberId, emittedToolNames) {
|
|
21357
|
+
const sets = DESIGN_PHASE_REQUIREMENT_SETS[memberId];
|
|
21358
|
+
if (!sets || sets.length === 0) {
|
|
21359
|
+
return { ok: true, missing: [] };
|
|
21360
|
+
}
|
|
21361
|
+
const result = checkMemberToolEmissionSets(memberId, emittedToolNames, sets);
|
|
21362
|
+
if (!result.ok) {
|
|
21363
|
+
console.warn(`[council] member "${memberId}" did not emit required tools: ${result.missing.join(", ")}. The downstream .zelari/ deliverable may be incomplete. (A forced retry turn scoped to the missing tools follows; the deterministic complete-design fallback covers any remaining gap.)`);
|
|
21364
|
+
}
|
|
21365
|
+
return result;
|
|
21366
|
+
}
|
|
21367
|
+
function shouldRetryMember(missingToolNames, attemptsSoFar) {
|
|
21368
|
+
if (missingToolNames.length === 0)
|
|
21369
|
+
return false;
|
|
21370
|
+
if (attemptsSoFar >= MAX_RETRY_PER_MEMBER)
|
|
21371
|
+
return false;
|
|
21372
|
+
return true;
|
|
21373
|
+
}
|
|
21374
|
+
function buildRetryPrompt(missingToolNames) {
|
|
21375
|
+
const names = missingToolNames.join(", ");
|
|
21376
|
+
return `You did not emit the required workspace tools: ${names}. Call ${names} NOW with concrete arguments. No prose. No search.`;
|
|
21377
|
+
}
|
|
21378
|
+
async function* runRetryTurnForMember(args) {
|
|
21379
|
+
const executableMissing = args.executableTools ? args.missingToolNames.filter((n) => args.executableTools.has(n)) : args.missingToolNames;
|
|
21380
|
+
if (executableMissing.length === 0) {
|
|
21381
|
+
return [];
|
|
21382
|
+
}
|
|
21383
|
+
const retryToolNames = executableMissing;
|
|
21384
|
+
const retryToolSpecs = getProviderTools(retryToolNames).map((t) => ({
|
|
21385
|
+
name: t.function.name,
|
|
21386
|
+
description: t.function.description,
|
|
21387
|
+
parameters: t.function.parameters
|
|
21388
|
+
}));
|
|
21389
|
+
const baseMessages = buildAgentMessages(args.agent, args.userMessage, args.ragContext, args.workspaceContext, args.priorOutputs, args.aiConfig, args.executableTools);
|
|
21390
|
+
const retryMessages = [
|
|
21391
|
+
...baseMessages,
|
|
21392
|
+
{ role: "user", content: buildRetryPrompt(executableMissing) }
|
|
21393
|
+
];
|
|
21394
|
+
const maxToolCalls = args.minPerTool !== void 0 ? Object.entries(args.minPerTool).filter(([name]) => executableMissing.includes(name)).reduce((sum, [, min]) => sum + min, 0) : retryToolNames.length;
|
|
21395
|
+
const retryHarness = new AgentHarness({
|
|
21396
|
+
model: args.effectiveModel,
|
|
21397
|
+
provider: args.effectiveProvider,
|
|
21398
|
+
sessionId: args.sessionId,
|
|
21399
|
+
messages: retryMessages,
|
|
21400
|
+
tools: retryToolSpecs,
|
|
21401
|
+
eventBus: args.eventBus,
|
|
21402
|
+
toolRegistry: args.toolRegistry,
|
|
21403
|
+
// Budget the retry so the model can satisfy every requirement in
|
|
21404
|
+
// ONE tool_calls turn. For createTask min:12 this needs 12 calls.
|
|
21405
|
+
maxToolCallsPerTurn: maxToolCalls,
|
|
21406
|
+
memberId: args.agent.id,
|
|
21407
|
+
memberName: args.agent.name,
|
|
21408
|
+
providerStream: (params) => args.providerStream(params)
|
|
21409
|
+
});
|
|
21410
|
+
const retryEmitted = [];
|
|
21411
|
+
for await (const event of retryHarness.run()) {
|
|
21412
|
+
if (event.type === "tool_execution_start") {
|
|
21413
|
+
retryEmitted.push(event.toolName);
|
|
21414
|
+
}
|
|
21415
|
+
yield event;
|
|
21416
|
+
}
|
|
21417
|
+
return retryEmitted;
|
|
21418
|
+
}
|
|
21419
|
+
async function* applyRetryIfMissing(args) {
|
|
21420
|
+
if (args.check.ok)
|
|
21421
|
+
return;
|
|
21422
|
+
const missingToolNames = args.check.missing.map((m) => m.split(" ")[0]);
|
|
21423
|
+
if (!shouldRetryMember(missingToolNames, 0))
|
|
21424
|
+
return;
|
|
21425
|
+
console.warn(`[council] ${args.agent.id} retrying missing tools: ${missingToolNames.join(", ")}`);
|
|
21426
|
+
const minPerTool = {};
|
|
21427
|
+
if (args.requirements) {
|
|
21428
|
+
for (const req of args.requirements) {
|
|
21429
|
+
if (missingToolNames.includes(req.name)) {
|
|
21430
|
+
minPerTool[req.name] = req.min;
|
|
21431
|
+
}
|
|
21432
|
+
}
|
|
21433
|
+
}
|
|
21434
|
+
try {
|
|
21435
|
+
const retryGenerator = runRetryTurnForMember({
|
|
21436
|
+
agent: args.agent,
|
|
21437
|
+
missingToolNames,
|
|
21438
|
+
minPerTool,
|
|
21439
|
+
executableTools: args.executableNames,
|
|
21440
|
+
userMessage: args.userMessage,
|
|
21441
|
+
ragContext: args.config.ragContext,
|
|
21442
|
+
workspaceContext: args.config.workspaceContext,
|
|
21443
|
+
priorOutputs: args.agentOutputs,
|
|
21444
|
+
aiConfig: args.config.aiConfig,
|
|
21445
|
+
sessionId: args.sessionId,
|
|
21446
|
+
effectiveModel: args.effectiveModel,
|
|
21447
|
+
effectiveProvider: args.effectiveProvider,
|
|
21448
|
+
eventBus: args.config.eventBus,
|
|
21449
|
+
toolRegistry: args.config.tools,
|
|
21450
|
+
providerStream: args.config.providerStream
|
|
21451
|
+
});
|
|
21452
|
+
for await (const event of retryGenerator) {
|
|
21453
|
+
if (event.type === "tool_execution_start") {
|
|
21454
|
+
args.onToolCall();
|
|
21455
|
+
args.emittedToolNames.push(event.toolName);
|
|
21456
|
+
}
|
|
21457
|
+
yield event;
|
|
21458
|
+
}
|
|
21459
|
+
} catch (retryErr) {
|
|
21460
|
+
console.error(`[council] ${args.agent.id} retry failed:`, retryErr);
|
|
21461
|
+
}
|
|
21462
|
+
enforceDesignPhaseToolEmissions(args.agent.id, args.emittedToolNames);
|
|
21463
|
+
}
|
|
21464
|
+
var NON_RETRY_AGENTS, QUESTION_MARKER, QUESTION_END_MARKER, DESIGN_PHASE_REQUIREMENT_SETS, DESIGN_PHASE_REQUIREMENTS, MAX_RETRY_PER_MEMBER;
|
|
21012
21465
|
var init_councilApi = __esm({
|
|
21013
21466
|
"packages/core/dist/agents/councilApi.js"() {
|
|
21014
21467
|
"use strict";
|
|
@@ -21018,8 +21471,30 @@ var init_councilApi = __esm({
|
|
|
21018
21471
|
init_tools();
|
|
21019
21472
|
init_events();
|
|
21020
21473
|
init_AgentHarness();
|
|
21474
|
+
NON_RETRY_AGENTS = /* @__PURE__ */ new Set([]);
|
|
21021
21475
|
QUESTION_MARKER = "---QUESTION---";
|
|
21022
21476
|
QUESTION_END_MARKER = "---END---";
|
|
21477
|
+
DESIGN_PHASE_REQUIREMENT_SETS = {
|
|
21478
|
+
nettun: [
|
|
21479
|
+
[{ name: "createPlan", min: 1 }],
|
|
21480
|
+
[
|
|
21481
|
+
{ name: "createPhase", min: 3 },
|
|
21482
|
+
{ name: "createTask", min: 6 },
|
|
21483
|
+
{ name: "createMilestone", min: 1 }
|
|
21484
|
+
]
|
|
21485
|
+
],
|
|
21486
|
+
geryon: [
|
|
21487
|
+
[{ name: "createDocument", min: 3 }]
|
|
21488
|
+
],
|
|
21489
|
+
minos: [
|
|
21490
|
+
[{ name: "createDocument", min: 1 }]
|
|
21491
|
+
],
|
|
21492
|
+
lucifer: [
|
|
21493
|
+
[{ name: "createDocument", min: 1 }]
|
|
21494
|
+
]
|
|
21495
|
+
};
|
|
21496
|
+
DESIGN_PHASE_REQUIREMENTS = Object.fromEntries(Object.entries(DESIGN_PHASE_REQUIREMENT_SETS).map(([id, sets]) => [id, sets[0]]));
|
|
21497
|
+
MAX_RETRY_PER_MEMBER = 1;
|
|
21023
21498
|
}
|
|
21024
21499
|
});
|
|
21025
21500
|
|
|
@@ -21186,16 +21661,25 @@ var council_exports = {};
|
|
|
21186
21661
|
__export(council_exports, {
|
|
21187
21662
|
AGENT_ROLES: () => AGENT_ROLES,
|
|
21188
21663
|
COLLABORATION_DIRECTIVE: () => COLLABORATION_DIRECTIVE,
|
|
21664
|
+
DESIGN_PHASE_REQUIREMENTS: () => DESIGN_PHASE_REQUIREMENTS,
|
|
21665
|
+
DESIGN_PHASE_REQUIREMENT_SETS: () => DESIGN_PHASE_REQUIREMENT_SETS,
|
|
21666
|
+
MAX_RETRY_PER_MEMBER: () => MAX_RETRY_PER_MEMBER,
|
|
21667
|
+
NON_RETRY_AGENTS: () => NON_RETRY_AGENTS,
|
|
21189
21668
|
OUTPUT_QUALITY_DIRECTIVE: () => OUTPUT_QUALITY_DIRECTIVE,
|
|
21190
21669
|
PROMPT_MODULES: () => PROMPT_MODULES,
|
|
21191
21670
|
STRUCTURED_REASONING_DIRECTIVE: () => STRUCTURED_REASONING_DIRECTIVE,
|
|
21192
21671
|
TOOL_USE_PROTOCOL_DIRECTIVE: () => TOOL_USE_PROTOCOL_DIRECTIVE,
|
|
21193
21672
|
UnknownMemberError: () => UnknownMemberError,
|
|
21673
|
+
applyRetryIfMissing: () => applyRetryIfMissing,
|
|
21674
|
+
buildRetryPrompt: () => buildRetryPrompt,
|
|
21194
21675
|
buildSkillDefinition: () => buildSkillDefinition,
|
|
21195
21676
|
buildSystemPrompt: () => buildSystemPrompt,
|
|
21677
|
+
checkMemberToolEmissionSets: () => checkMemberToolEmissionSets,
|
|
21678
|
+
checkMemberToolEmissions: () => checkMemberToolEmissions,
|
|
21196
21679
|
cleanAgentContent: () => cleanAgentContent,
|
|
21197
21680
|
computeAgentSkills: () => computeAgentSkills,
|
|
21198
21681
|
computeAgentTools: () => computeAgentTools,
|
|
21682
|
+
enforceDesignPhaseToolEmissions: () => enforceDesignPhaseToolEmissions,
|
|
21199
21683
|
getAgent: () => getAgent,
|
|
21200
21684
|
getBasePromptModules: () => getBasePromptModules,
|
|
21201
21685
|
getCouncilAgents: () => getCouncilAgents,
|
|
@@ -21207,6 +21691,8 @@ __export(council_exports, {
|
|
|
21207
21691
|
promoteMember: () => promoteMember,
|
|
21208
21692
|
renderSkillMarkdown: () => renderSkillMarkdown,
|
|
21209
21693
|
runCouncilPure: () => runCouncilPure,
|
|
21694
|
+
runRetryTurnForMember: () => runRetryTurnForMember,
|
|
21695
|
+
shouldRetryMember: () => shouldRetryMember,
|
|
21210
21696
|
slugify: () => slugify3,
|
|
21211
21697
|
stripClarificationProtocol: () => stripClarificationProtocol,
|
|
21212
21698
|
swapMembers: () => swapMembers
|
|
@@ -21256,6 +21742,12 @@ async function* dispatchCouncil(userMessage, options) {
|
|
|
21256
21742
|
maxToolCallsPerTurn: options.maxToolCallsPerTurn,
|
|
21257
21743
|
feedbackStore: options.feedbackStore
|
|
21258
21744
|
};
|
|
21745
|
+
if (!options.disableWorkspaceTools) {
|
|
21746
|
+
const { setWorkspaceStubs: setWorkspaceStubs2 } = await Promise.resolve().then(() => (init_skills2(), skills_exports));
|
|
21747
|
+
const { createWorkspaceContext: buildCtx, createWorkspaceStubs: buildStubs } = await Promise.resolve().then(() => (init_stubs(), stubs_exports));
|
|
21748
|
+
const wsCtx = options.workspaceRoot ? buildCtx(options.workspaceRoot) : buildCtx();
|
|
21749
|
+
setWorkspaceStubs2(buildStubs(wsCtx));
|
|
21750
|
+
}
|
|
21259
21751
|
yield* runCouncilPure(userMessage, config2, {});
|
|
21260
21752
|
}
|
|
21261
21753
|
var CouncilDispatchError;
|
|
@@ -21524,36 +22016,220 @@ var init_agentsMd = __esm({
|
|
|
21524
22016
|
}
|
|
21525
22017
|
});
|
|
21526
22018
|
|
|
22019
|
+
// src/cli/workspace/completeDesign.ts
|
|
22020
|
+
function curatedTasksForPhase(phase) {
|
|
22021
|
+
const label = (phase.name ?? phase.id).trim();
|
|
22022
|
+
const scope = phase.description?.trim() ? ` Scope: ${phase.description.trim()}` : "";
|
|
22023
|
+
return [
|
|
22024
|
+
{
|
|
22025
|
+
title: `Specify ${label} deliverables`,
|
|
22026
|
+
description: `Turn the council documents for "${label}" into a concrete specification: enumerate deliverables, interfaces, constraints, and open decisions, grounding each item in the ADRs and design docs already present in .zelari/.${scope}`,
|
|
22027
|
+
fileRefs: [".zelari/docs/", ".zelari/decisions/"],
|
|
22028
|
+
acceptance: [
|
|
22029
|
+
`A written spec for "${label}" exists and references at least one ADR or design doc`,
|
|
22030
|
+
"Every deliverable in the spec has an owner artifact (file, doc, or component) named"
|
|
22031
|
+
],
|
|
22032
|
+
qaScenario: `Open the spec for "${label}" and confirm each deliverable maps to a concrete artifact and no open decision is left unresolved.`,
|
|
22033
|
+
priority: "high"
|
|
22034
|
+
},
|
|
22035
|
+
{
|
|
22036
|
+
title: `Implement ${label} deliverables`,
|
|
22037
|
+
description: `Produce the artifacts the "${label}" phase promises, following the spec task of this phase and the decisions recorded in .zelari/decisions/.${scope}`,
|
|
22038
|
+
fileRefs: ["src/"],
|
|
22039
|
+
acceptance: [
|
|
22040
|
+
`Every deliverable listed in the "${label}" spec exists and builds/renders without errors`,
|
|
22041
|
+
"No implementation contradicts an accepted ADR"
|
|
22042
|
+
],
|
|
22043
|
+
qaScenario: `Walk the "${label}" spec top to bottom and check each deliverable off against the produced artifact.`,
|
|
22044
|
+
priority: "high"
|
|
22045
|
+
},
|
|
22046
|
+
{
|
|
22047
|
+
title: `Verify ${label} exit criteria`,
|
|
22048
|
+
description: `Run the QA pass for "${label}": execute the QA scenarios of the phase tasks, check the phase row in the synthesis green-light checklist, and record any gaps as follow-up tasks.${scope}`,
|
|
22049
|
+
fileRefs: [".zelari/docs/synthesis.md"],
|
|
22050
|
+
acceptance: [
|
|
22051
|
+
`The "${label}" row of the synthesis green-light checklist passes`,
|
|
22052
|
+
"All QA scenarios of this phase have been executed with recorded outcomes"
|
|
22053
|
+
],
|
|
22054
|
+
qaScenario: `Open .zelari/docs/synthesis.md, locate the "${label}" checklist row, and confirm every criterion is checked with evidence.`,
|
|
22055
|
+
priority: "medium"
|
|
22056
|
+
}
|
|
22057
|
+
];
|
|
22058
|
+
}
|
|
22059
|
+
async function runBuiltinCompleteDesign(ctx) {
|
|
22060
|
+
const summary = readPlanSummary(ctx);
|
|
22061
|
+
if (summary.phases.length === 0) {
|
|
22062
|
+
return { ran: false, tasksAdded: 0, milestonesAdded: 0, reason: "plan has no phases" };
|
|
22063
|
+
}
|
|
22064
|
+
const stubs = createWorkspaceStubs(ctx);
|
|
22065
|
+
const createTask = stubs.find((s) => s.name === "createTask");
|
|
22066
|
+
const createMilestone = stubs.find((s) => s.name === "createMilestone");
|
|
22067
|
+
const stubCtx = ctx;
|
|
22068
|
+
let tasksAdded = 0;
|
|
22069
|
+
for (const phase of summary.phases) {
|
|
22070
|
+
const existingTasks = summary.tasks.filter((t) => t.phaseId === phase.id);
|
|
22071
|
+
if (existingTasks.length >= MIN_TASKS_PER_PHASE) continue;
|
|
22072
|
+
const existingTitles = new Set(existingTasks.map((t) => t.name ?? ""));
|
|
22073
|
+
const templates = curatedTasksForPhase(phase).filter((t) => !existingTitles.has(t.title)).slice(0, MIN_TASKS_PER_PHASE - existingTasks.length);
|
|
22074
|
+
for (const t of templates) {
|
|
22075
|
+
await createTask.execute(
|
|
22076
|
+
{
|
|
22077
|
+
phaseId: phase.id,
|
|
22078
|
+
title: t.title,
|
|
22079
|
+
description: t.description,
|
|
22080
|
+
fileRefs: t.fileRefs,
|
|
22081
|
+
acceptance: t.acceptance,
|
|
22082
|
+
qaScenario: t.qaScenario,
|
|
22083
|
+
priority: t.priority
|
|
22084
|
+
},
|
|
22085
|
+
stubCtx
|
|
22086
|
+
);
|
|
22087
|
+
tasksAdded += 1;
|
|
22088
|
+
}
|
|
22089
|
+
}
|
|
22090
|
+
let milestonesAdded = 0;
|
|
22091
|
+
if (summary.milestones.length === 0) {
|
|
22092
|
+
await createMilestone.execute(
|
|
22093
|
+
{
|
|
22094
|
+
title: "v0.1.0 design-complete",
|
|
22095
|
+
description: "All design-phase artifacts (phases, tasks, ADRs, design docs, risks, synthesis) exist and the green-light checklist passes.",
|
|
22096
|
+
targetVersion: "v0.1.0"
|
|
22097
|
+
},
|
|
22098
|
+
stubCtx
|
|
22099
|
+
);
|
|
22100
|
+
milestonesAdded = 1;
|
|
22101
|
+
}
|
|
22102
|
+
return { ran: true, tasksAdded, milestonesAdded };
|
|
22103
|
+
}
|
|
22104
|
+
var MIN_TASKS_PER_PHASE;
|
|
22105
|
+
var init_completeDesign = __esm({
|
|
22106
|
+
"src/cli/workspace/completeDesign.ts"() {
|
|
22107
|
+
"use strict";
|
|
22108
|
+
init_stubs();
|
|
22109
|
+
MIN_TASKS_PER_PHASE = 3;
|
|
22110
|
+
}
|
|
22111
|
+
});
|
|
22112
|
+
|
|
21527
22113
|
// src/cli/workspace/postCouncilHook.ts
|
|
21528
22114
|
var postCouncilHook_exports = {};
|
|
21529
22115
|
__export(postCouncilHook_exports, {
|
|
22116
|
+
runCompleteDesignPostProcessor: () => runCompleteDesignPostProcessor,
|
|
21530
22117
|
runPostCouncilHook: () => runPostCouncilHook
|
|
21531
22118
|
});
|
|
21532
|
-
|
|
21533
|
-
|
|
21534
|
-
|
|
22119
|
+
import { spawn as spawn3 } from "node:child_process";
|
|
22120
|
+
import { existsSync as existsSync12, readFileSync as readFileSync9 } from "node:fs";
|
|
22121
|
+
import { join as join7 } from "node:path";
|
|
22122
|
+
async function runCompleteDesignPostProcessor(ctx) {
|
|
22123
|
+
if (process.env["ZELARI_COMPLETE_DESIGN"] === "0") {
|
|
22124
|
+
return { ran: false, reason: "ZELARI_COMPLETE_DESIGN=0 (disabled)" };
|
|
22125
|
+
}
|
|
22126
|
+
const planJsonPath2 = join7(ctx.rootDir, "plan.json");
|
|
22127
|
+
const scriptPath = join7(ctx.projectRoot, "complete-design.mjs");
|
|
22128
|
+
if (!existsSync12(planJsonPath2)) {
|
|
22129
|
+
return { ran: false, reason: ".zelari/plan.json missing (not design-phase)" };
|
|
21535
22130
|
}
|
|
22131
|
+
let phaseCount = 0;
|
|
21536
22132
|
try {
|
|
21537
|
-
const
|
|
21538
|
-
|
|
21539
|
-
|
|
21540
|
-
|
|
21541
|
-
|
|
21542
|
-
|
|
21543
|
-
};
|
|
21544
|
-
}
|
|
21545
|
-
|
|
22133
|
+
const parsed = JSON.parse(readFileSync9(planJsonPath2, "utf8"));
|
|
22134
|
+
phaseCount = Array.isArray(parsed.phases) ? parsed.phases.length : 0;
|
|
22135
|
+
} catch {
|
|
22136
|
+
return { ran: false, reason: ".zelari/plan.json corrupt" };
|
|
22137
|
+
}
|
|
22138
|
+
if (phaseCount === 0) {
|
|
22139
|
+
return { ran: false, reason: ".zelari/plan.json has no phases" };
|
|
22140
|
+
}
|
|
22141
|
+
if (!existsSync12(scriptPath)) {
|
|
22142
|
+
try {
|
|
22143
|
+
const builtin = await runBuiltinCompleteDesign(ctx);
|
|
22144
|
+
return {
|
|
22145
|
+
ran: builtin.ran,
|
|
22146
|
+
...builtin.ran ? { exitCode: 0 } : {},
|
|
22147
|
+
output: `builtin complete-design: +${builtin.tasksAdded} tasks, +${builtin.milestonesAdded} milestones`,
|
|
22148
|
+
...builtin.reason ? { reason: builtin.reason } : {}
|
|
22149
|
+
};
|
|
22150
|
+
} catch (err) {
|
|
22151
|
+
return {
|
|
22152
|
+
ran: true,
|
|
22153
|
+
exitCode: -1,
|
|
22154
|
+
reason: `builtin complete-design error: ${err instanceof Error ? err.message : String(err)}`
|
|
22155
|
+
};
|
|
22156
|
+
}
|
|
22157
|
+
}
|
|
22158
|
+
return await new Promise((resolveRun) => {
|
|
22159
|
+
const child = spawn3(process.execPath, [scriptPath], {
|
|
22160
|
+
cwd: ctx.projectRoot,
|
|
22161
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
22162
|
+
env: process.env
|
|
22163
|
+
});
|
|
22164
|
+
let stdout = "";
|
|
22165
|
+
let stderr = "";
|
|
22166
|
+
child.stdout?.on("data", (chunk) => {
|
|
22167
|
+
stdout += chunk.toString("utf8");
|
|
22168
|
+
});
|
|
22169
|
+
child.stderr?.on("data", (chunk) => {
|
|
22170
|
+
stderr += chunk.toString("utf8");
|
|
22171
|
+
});
|
|
22172
|
+
child.on("error", (err) => {
|
|
22173
|
+
resolveRun({
|
|
22174
|
+
ran: true,
|
|
22175
|
+
exitCode: -1,
|
|
22176
|
+
output: stderr,
|
|
22177
|
+
reason: `spawn error: ${err.message}`
|
|
22178
|
+
});
|
|
22179
|
+
});
|
|
22180
|
+
child.on("close", (code) => {
|
|
22181
|
+
const exitCode = code ?? -1;
|
|
22182
|
+
const ok = exitCode === 0;
|
|
22183
|
+
resolveRun({
|
|
22184
|
+
ran: true,
|
|
22185
|
+
exitCode,
|
|
22186
|
+
output: stdout + stderr,
|
|
22187
|
+
...ok ? {} : { reason: `complete-design exited with code ${exitCode}` }
|
|
22188
|
+
});
|
|
22189
|
+
});
|
|
22190
|
+
});
|
|
22191
|
+
}
|
|
22192
|
+
async function runPostCouncilHook(ctx) {
|
|
22193
|
+
let agentsMdResult;
|
|
22194
|
+
if (process.env["ZELARI_AGENTS_MD"] === "0") {
|
|
22195
|
+
agentsMdResult = {
|
|
21546
22196
|
ran: false,
|
|
21547
22197
|
changed: false,
|
|
21548
22198
|
sections: [],
|
|
21549
|
-
reason:
|
|
22199
|
+
reason: "ZELARI_AGENTS_MD=0 (disabled)"
|
|
21550
22200
|
};
|
|
22201
|
+
} else {
|
|
22202
|
+
try {
|
|
22203
|
+
const result = await updateAgentsMd(ctx, ctx.projectRoot);
|
|
22204
|
+
agentsMdResult = {
|
|
22205
|
+
ran: true,
|
|
22206
|
+
changed: result.changed,
|
|
22207
|
+
sections: result.sections,
|
|
22208
|
+
...result.reason ? { reason: result.reason } : {}
|
|
22209
|
+
};
|
|
22210
|
+
} catch (err) {
|
|
22211
|
+
agentsMdResult = {
|
|
22212
|
+
ran: false,
|
|
22213
|
+
changed: false,
|
|
22214
|
+
sections: [],
|
|
22215
|
+
reason: `error: ${err instanceof Error ? err.message : String(err)}`
|
|
22216
|
+
};
|
|
22217
|
+
}
|
|
21551
22218
|
}
|
|
22219
|
+
const completeDesign = await runCompleteDesignPostProcessor(ctx);
|
|
22220
|
+
return {
|
|
22221
|
+
ran: agentsMdResult.ran || completeDesign.ran,
|
|
22222
|
+
changed: agentsMdResult.changed,
|
|
22223
|
+
sections: agentsMdResult.sections,
|
|
22224
|
+
...agentsMdResult.reason ? { reason: agentsMdResult.reason } : {},
|
|
22225
|
+
completeDesign
|
|
22226
|
+
};
|
|
21552
22227
|
}
|
|
21553
22228
|
var init_postCouncilHook = __esm({
|
|
21554
22229
|
"src/cli/workspace/postCouncilHook.ts"() {
|
|
21555
22230
|
"use strict";
|
|
21556
22231
|
init_agentsMd();
|
|
22232
|
+
init_completeDesign();
|
|
21557
22233
|
}
|
|
21558
22234
|
});
|
|
21559
22235
|
|
|
@@ -21564,8 +22240,8 @@ __export(councilFeedback_exports, {
|
|
|
21564
22240
|
});
|
|
21565
22241
|
import {
|
|
21566
22242
|
promises as fs11,
|
|
21567
|
-
existsSync as
|
|
21568
|
-
readFileSync as
|
|
22243
|
+
existsSync as existsSync13,
|
|
22244
|
+
readFileSync as readFileSync10,
|
|
21569
22245
|
writeFileSync as writeFileSync8,
|
|
21570
22246
|
mkdirSync as mkdirSync8
|
|
21571
22247
|
} from "node:fs";
|
|
@@ -21673,9 +22349,9 @@ var init_councilFeedback = __esm({
|
|
|
21673
22349
|
}
|
|
21674
22350
|
// --- persistence ---------------------------------------------------------
|
|
21675
22351
|
load() {
|
|
21676
|
-
if (!
|
|
22352
|
+
if (!existsSync13(this.file)) return;
|
|
21677
22353
|
try {
|
|
21678
|
-
const raw =
|
|
22354
|
+
const raw = readFileSync10(this.file, "utf-8");
|
|
21679
22355
|
const parsed = JSON.parse(raw);
|
|
21680
22356
|
if (parsed && Array.isArray(parsed.entries)) {
|
|
21681
22357
|
this.entries = parsed.entries.filter(
|
|
@@ -21721,7 +22397,7 @@ __export(updater_exports, {
|
|
|
21721
22397
|
performUpdate: () => performUpdate
|
|
21722
22398
|
});
|
|
21723
22399
|
import { createRequire } from "node:module";
|
|
21724
|
-
import { spawn as
|
|
22400
|
+
import { spawn as spawn4 } from "node:child_process";
|
|
21725
22401
|
import path16 from "node:path";
|
|
21726
22402
|
import { fileURLToPath } from "node:url";
|
|
21727
22403
|
function getCurrentVersion() {
|
|
@@ -21786,7 +22462,7 @@ async function checkForUpdate(fetcher = fetch, registryUrl) {
|
|
|
21786
22462
|
updateAvailable: cmp < 0
|
|
21787
22463
|
};
|
|
21788
22464
|
}
|
|
21789
|
-
async function performUpdate(packageName = "zelari-code", executor =
|
|
22465
|
+
async function performUpdate(packageName = "zelari-code", executor = spawn4) {
|
|
21790
22466
|
return new Promise((resolve) => {
|
|
21791
22467
|
const args = ["install", "-g", `${packageName}@latest`];
|
|
21792
22468
|
let stdout = "";
|
|
@@ -21831,7 +22507,7 @@ var init_updater = __esm({
|
|
|
21831
22507
|
});
|
|
21832
22508
|
|
|
21833
22509
|
// src/cli/main.ts
|
|
21834
|
-
import
|
|
22510
|
+
import React10 from "react";
|
|
21835
22511
|
import { render } from "ink";
|
|
21836
22512
|
|
|
21837
22513
|
// src/cli/app.tsx
|
|
@@ -26651,7 +27327,7 @@ async function handlePromoteMember(ctx, memberId) {
|
|
|
26651
27327
|
}
|
|
26652
27328
|
|
|
26653
27329
|
// src/cli/branchManager.ts
|
|
26654
|
-
import { promises as fs13, existsSync as
|
|
27330
|
+
import { promises as fs13, existsSync as existsSync14, readFileSync as readFileSync11, writeFileSync as writeFileSync9, mkdirSync as mkdirSync9, statSync as statSync4, rmSync } from "node:fs";
|
|
26655
27331
|
import path18 from "node:path";
|
|
26656
27332
|
import os9 from "node:os";
|
|
26657
27333
|
var META_FILENAME = "meta.json";
|
|
@@ -26673,11 +27349,11 @@ function sessionsPathFor(name, baseDir) {
|
|
|
26673
27349
|
}
|
|
26674
27350
|
function readBranchMeta(name, baseDir) {
|
|
26675
27351
|
const metaPath = metaPathFor(name, baseDir);
|
|
26676
|
-
if (!
|
|
27352
|
+
if (!existsSync14(metaPath)) {
|
|
26677
27353
|
throw new BranchNotFoundError(`Branch "${name}" not found`);
|
|
26678
27354
|
}
|
|
26679
27355
|
try {
|
|
26680
|
-
const raw =
|
|
27356
|
+
const raw = readFileSync11(metaPath, "utf-8");
|
|
26681
27357
|
const parsed = JSON.parse(raw);
|
|
26682
27358
|
if (!parsed || typeof parsed !== "object" || typeof parsed.name !== "string" || typeof parsed.createdAt !== "number" || typeof parsed.fromSessionId !== "string") {
|
|
26683
27359
|
throw new BranchCorruptError(`Branch "${name}" meta.json is malformed`);
|
|
@@ -26733,7 +27409,7 @@ var SessionNotFoundError = class extends Error {
|
|
|
26733
27409
|
};
|
|
26734
27410
|
function branchExists(name, baseDir = getBranchesBaseDir()) {
|
|
26735
27411
|
const bp = branchPathFor(name, baseDir);
|
|
26736
|
-
return
|
|
27412
|
+
return existsSync14(bp) && existsSync14(metaPathFor(name, baseDir));
|
|
26737
27413
|
}
|
|
26738
27414
|
async function createBranch(name, fromSessionId, baseDir = getBranchesBaseDir(), sessionsBaseDir = getSessionsBaseDir()) {
|
|
26739
27415
|
if (!name || name.trim().length === 0) {
|
|
@@ -26746,7 +27422,7 @@ async function createBranch(name, fromSessionId, baseDir = getBranchesBaseDir(),
|
|
|
26746
27422
|
throw new BranchAlreadyExistsError(name);
|
|
26747
27423
|
}
|
|
26748
27424
|
const sourcePath = path18.join(sessionsBaseDir, `${fromSessionId}.jsonl`);
|
|
26749
|
-
if (!
|
|
27425
|
+
if (!existsSync14(sourcePath)) {
|
|
26750
27426
|
throw new SessionNotFoundError(`Source session "${fromSessionId}" not found at ${sourcePath}`);
|
|
26751
27427
|
}
|
|
26752
27428
|
const branchPath = branchPathFor(name, baseDir);
|
|
@@ -26779,7 +27455,7 @@ async function listBranches(baseDir = getBranchesBaseDir()) {
|
|
|
26779
27455
|
const results = [];
|
|
26780
27456
|
for (const entry of entries) {
|
|
26781
27457
|
const metaPath = metaPathFor(entry, baseDir);
|
|
26782
|
-
if (!
|
|
27458
|
+
if (!existsSync14(metaPath)) continue;
|
|
26783
27459
|
try {
|
|
26784
27460
|
const meta3 = readBranchMeta(entry, baseDir);
|
|
26785
27461
|
const sessionCount = await countSessions(entry, baseDir);
|
|
@@ -27017,7 +27693,7 @@ async function validateApiKey(providerId, apiKey, options = {}) {
|
|
|
27017
27693
|
init_providerConfig();
|
|
27018
27694
|
|
|
27019
27695
|
// src/cli/modelDiscovery.ts
|
|
27020
|
-
import { promises as fs15, existsSync as
|
|
27696
|
+
import { promises as fs15, existsSync as existsSync15, readFileSync as readFileSync12 } from "node:fs";
|
|
27021
27697
|
import { homedir as homedir3 } from "node:os";
|
|
27022
27698
|
import path20 from "node:path";
|
|
27023
27699
|
var PROVIDER_BASE_URLS = {
|
|
@@ -27033,9 +27709,9 @@ function getModelsFilePath() {
|
|
|
27033
27709
|
return defaultModelsFilePath();
|
|
27034
27710
|
}
|
|
27035
27711
|
function loadModelsRegistry(file2 = getModelsFilePath()) {
|
|
27036
|
-
if (!
|
|
27712
|
+
if (!existsSync15(file2)) return {};
|
|
27037
27713
|
try {
|
|
27038
|
-
const raw =
|
|
27714
|
+
const raw = readFileSync12(file2, "utf-8");
|
|
27039
27715
|
const parsed = JSON.parse(raw);
|
|
27040
27716
|
if (!parsed || typeof parsed !== "object") return {};
|
|
27041
27717
|
return parsed;
|
|
@@ -27395,7 +28071,7 @@ import path21 from "node:path";
|
|
|
27395
28071
|
import os10 from "node:os";
|
|
27396
28072
|
|
|
27397
28073
|
// src/cli/skillHistory.ts
|
|
27398
|
-
import { promises as fs16, existsSync as
|
|
28074
|
+
import { promises as fs16, existsSync as existsSync16, statSync as statSync5, renameSync as renameSync4, appendFileSync as appendFileSync2, mkdirSync as mkdirSync11 } from "node:fs";
|
|
27399
28075
|
var SKILL_HISTORY_ROTATE_BYTES = 10 * 1024 * 1024;
|
|
27400
28076
|
async function readSkillHistory(file2) {
|
|
27401
28077
|
let raw = "";
|
|
@@ -28019,7 +28695,7 @@ function App() {
|
|
|
28019
28695
|
id: "banner-once",
|
|
28020
28696
|
role: "system",
|
|
28021
28697
|
ts: 0,
|
|
28022
|
-
content: `zelari-code
|
|
28698
|
+
content: `zelari-code v${VERSION} \u2014 ${activeProviderSpec.id}/${activeModel}
|
|
28023
28699
|
${skills.length} skills available. Type /help for the list, or /skill <name>.
|
|
28024
28700
|
\u2500\u2500 skills \u2500\u2500
|
|
28025
28701
|
${skillList}`
|
|
@@ -28050,13 +28726,147 @@ ${skillList}`
|
|
|
28050
28726
|
)));
|
|
28051
28727
|
}
|
|
28052
28728
|
|
|
28729
|
+
// src/cli/components/SplashScreen.tsx
|
|
28730
|
+
import React7, { useEffect as useEffect4, useState as useState5 } from "react";
|
|
28731
|
+
import { Box as Box7, Text as Text7, useInput, useStdin } from "ink";
|
|
28732
|
+
var SPLASH_DURATION_MS = 2e3;
|
|
28733
|
+
var EMBLEM_LARGE = ` =%@*-
|
|
28734
|
+
=%@@@@@#:
|
|
28735
|
+
*%%%%%%@@%-
|
|
28736
|
+
:#%%%%%%%%%@@*
|
|
28737
|
+
:*%%%%%%%%%%%%%@%*.
|
|
28738
|
+
=%%%%%%%%%%%%%%%%@@%.
|
|
28739
|
+
=%%%%%%%%%%%%%%%%%%%@%-
|
|
28740
|
+
*%%%%%%%%%%%%%%%%%%%%%@@=
|
|
28741
|
+
.#%%%%%%%%@@@@@@@@%%%%%%@@@+
|
|
28742
|
+
:#%%%%%%@@@@@@@@@@@@@@@%%%%@@+
|
|
28743
|
+
-%%%%%@@@@@@@@@@@@@@@@@@@@@%%@@#.
|
|
28744
|
+
-%%%%%@@@@@@@@@@@@@@@@@@@@@@@%%@@%:
|
|
28745
|
+
=%%%%@@@@@@@@@@@@@@@@@@@@@@@@@@@%@@%.
|
|
28746
|
+
+%%%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%@@%:
|
|
28747
|
+
=%%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@-
|
|
28748
|
+
-%%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%:
|
|
28749
|
+
:%%%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%
|
|
28750
|
+
#%%%%%@@@@@@@@@@@@@@@%--#%@@@@@@@@@@@@@%%@@@=
|
|
28751
|
+
#@@%%%%@@@@@@@@@@@@@@%: -*@@@@@@@@@@@%%@@@@=
|
|
28752
|
+
#@@%%%%@@@@@@@@@@@@@%: .. -#@@@@@@@%%%%@@@=
|
|
28753
|
+
+@@@%%%@@@@@@@@@@@@%: :#= =%@@@@%%%@@@%-
|
|
28754
|
+
=@@@@%%%@@@@@@@@@@%: -%%*: +%@@%%@@@#
|
|
28755
|
+
+%@@@@%%@@@@@@@@@%: -%@@%*=.:+#@@@@#:
|
|
28756
|
+
.+*@@@@@@@@@%%%@@@@@@%: -%@@@@@#- +@@@@@@*=
|
|
28757
|
+
=*%%%%@@@@@@@@@@@%%@@@@%: -#@@@@@@@*: :*@@@@@@%+=
|
|
28758
|
+
-*%%%%%%%%%%@@@@@@@@@@@@@@@: -%@@@@@@@@#- -#@@@@@@@@*
|
|
28759
|
+
#%%%%%%%%%%%%%@@@@@@@@@@@@@: -#@@@@@%+-::. *@@@@@@@@=
|
|
28760
|
+
=%%%%%%%%%%%%%%%@@@@@@@@@@@@: :*+--=%#. :+++++*@@@@@@@@%
|
|
28761
|
+
#@%%%%%%%%%%%%%@@@@@@@@@@@@%: .. - -## *@@@@@@@@@@@@@@=
|
|
28762
|
+
:@@%%%%%%%%%%%%@@@@@@@@@@@@@%: .**= *%= :%@@@@@@@@@@@@@%
|
|
28763
|
+
#@@@%%%%%%%%%%%@@@@@@@@@@@@@@- =#@@%- :**: =%@@@@@@@@@@@@@+
|
|
28764
|
+
=@@@@@%%%@@%%%%@@@@@@@@@@@@@@@@@@@@@@%- :: .-#@@@@@@@@@@@@@%.
|
|
28765
|
+
:@@@@@@%%@@@%%@@@@@@@@@@@@@@@@@@@@@@@@@%==*%%@@@@@@@@@@@@@@@@#
|
|
28766
|
+
*@@@@@@@%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@:
|
|
28767
|
+
:@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+
|
|
28768
|
+
=##########*######**##**#*********##**#*#######################*`;
|
|
28769
|
+
var EMBLEM_SMALL = ` =%%*:
|
|
28770
|
+
:#%%@@@+
|
|
28771
|
+
=%%%%%%%@#.
|
|
28772
|
+
.*%%%%%%%%%@%-
|
|
28773
|
+
=%%%%%%%%%%%%%@*.
|
|
28774
|
+
+%%%%%%@@@@@%%%%@%:
|
|
28775
|
+
*%%%%@@@@@@@@@@@%%@%:
|
|
28776
|
+
*%%%@@@@@@@@@@@@@@@%@%-
|
|
28777
|
+
:#%%@@@@@@@@@@@@@@@@@@@@@+
|
|
28778
|
+
:%%%@@@@@@@@@@@@@@@@@@@@@@@+
|
|
28779
|
+
#%%@@@@@@@@@@@@@@@@@@@@@@@@@-
|
|
28780
|
+
+%%@@@@@@@@@@@@#@@@@@@@@@@@@@%:
|
|
28781
|
+
%%%%@@@@@@@@@@%::*@@@@@@@@@%@@=
|
|
28782
|
+
-%@%%@@@@@@@@@%:.::*@@@@@%%@@*.
|
|
28783
|
+
:%@@%%@@@@@@@%.:%#::*@@%@@@-
|
|
28784
|
+
:#@@@%@@@@@@%.:%@%+.-#@@@=
|
|
28785
|
+
:+#@@@@@@@%@@@@%.:%@@@%=.+@@@%*-
|
|
28786
|
+
.*#%%%%%%@@@@@@@@@@.:%@@@@@*:.+%@@@@#-
|
|
28787
|
+
+%%%%%%%%%%@@@@@@@@::##*%* :----%@@@@%.
|
|
28788
|
+
.@%%%%%%%%%@@@@@@@@@:.-..-#=:%@@@@@@@@@+
|
|
28789
|
+
*@@%%%%%%%%@@@@@@@@@: =#+ +#.-@@@@@@@@@@.
|
|
28790
|
+
-@@@%%%%%%%@@@@@@@@@@#%@@@- -.:*@@@@@@@@@*
|
|
28791
|
+
%@@@@%@@%@@@@@@@@@@@@@@@@@%**%@@@@@@@@@@@@:
|
|
28792
|
+
=@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*`;
|
|
28793
|
+
var FOOTER_ROWS = 5;
|
|
28794
|
+
function measure(art) {
|
|
28795
|
+
const lines = art.split("\n");
|
|
28796
|
+
return {
|
|
28797
|
+
art,
|
|
28798
|
+
width: Math.max(...lines.map((l) => l.length)),
|
|
28799
|
+
height: lines.length
|
|
28800
|
+
};
|
|
28801
|
+
}
|
|
28802
|
+
var VARIANTS = [measure(EMBLEM_LARGE), measure(EMBLEM_SMALL)];
|
|
28803
|
+
function pickSplashArt(columns, rows) {
|
|
28804
|
+
for (const v of VARIANTS) {
|
|
28805
|
+
if (v.width <= columns - 2 && v.height + FOOTER_ROWS <= rows) return v;
|
|
28806
|
+
}
|
|
28807
|
+
return null;
|
|
28808
|
+
}
|
|
28809
|
+
function shouldShowSplash(opts) {
|
|
28810
|
+
if (!opts.isTTY) return false;
|
|
28811
|
+
if (opts.env["ZELARI_NO_SPLASH"] === "1") return false;
|
|
28812
|
+
return pickSplashArt(opts.columns, opts.rows) !== null;
|
|
28813
|
+
}
|
|
28814
|
+
function Splash({ onDone, version: version2 }) {
|
|
28815
|
+
const { isRawModeSupported } = useStdin();
|
|
28816
|
+
const columns = process.stdout.columns ?? 80;
|
|
28817
|
+
const rows = process.stdout.rows ?? 24;
|
|
28818
|
+
const picked = pickSplashArt(columns, rows);
|
|
28819
|
+
useEffect4(() => {
|
|
28820
|
+
const t = setTimeout(onDone, SPLASH_DURATION_MS);
|
|
28821
|
+
return () => clearTimeout(t);
|
|
28822
|
+
}, [onDone]);
|
|
28823
|
+
useInput(
|
|
28824
|
+
() => {
|
|
28825
|
+
onDone();
|
|
28826
|
+
},
|
|
28827
|
+
{ isActive: isRawModeSupported === true }
|
|
28828
|
+
);
|
|
28829
|
+
if (!picked) return null;
|
|
28830
|
+
return /* @__PURE__ */ React7.createElement(
|
|
28831
|
+
Box7,
|
|
28832
|
+
{
|
|
28833
|
+
flexDirection: "column",
|
|
28834
|
+
alignItems: "center",
|
|
28835
|
+
justifyContent: "center",
|
|
28836
|
+
width: columns,
|
|
28837
|
+
height: rows - 1
|
|
28838
|
+
},
|
|
28839
|
+
/* @__PURE__ */ React7.createElement(Text7, { color: "cyan" }, picked.art),
|
|
28840
|
+
/* @__PURE__ */ React7.createElement(Box7, { marginTop: 1 }, /* @__PURE__ */ React7.createElement(Text7, { bold: true, color: "white" }, "Z E L A R I C O D E")),
|
|
28841
|
+
/* @__PURE__ */ React7.createElement(Text7, { dimColor: true }, `${version2 ? `v${version2} \u2014 ` : ""}N-THEM Studio`),
|
|
28842
|
+
/* @__PURE__ */ React7.createElement(Text7, { dimColor: true, italic: true }, "press any key to skip")
|
|
28843
|
+
);
|
|
28844
|
+
}
|
|
28845
|
+
function SplashGate({
|
|
28846
|
+
children,
|
|
28847
|
+
version: version2
|
|
28848
|
+
}) {
|
|
28849
|
+
const [show, setShow] = useState5(
|
|
28850
|
+
() => shouldShowSplash({
|
|
28851
|
+
isTTY: process.stdout.isTTY === true,
|
|
28852
|
+
env: process.env,
|
|
28853
|
+
columns: process.stdout.columns ?? 80,
|
|
28854
|
+
rows: process.stdout.rows ?? 24
|
|
28855
|
+
})
|
|
28856
|
+
);
|
|
28857
|
+
if (show) {
|
|
28858
|
+
return /* @__PURE__ */ React7.createElement(Splash, { onDone: () => setShow(false), version: version2 });
|
|
28859
|
+
}
|
|
28860
|
+
return /* @__PURE__ */ React7.createElement(React7.Fragment, null, children);
|
|
28861
|
+
}
|
|
28862
|
+
|
|
28053
28863
|
// src/cli/main.ts
|
|
28054
28864
|
init_providerConfig();
|
|
28055
28865
|
|
|
28056
28866
|
// src/cli/wizard/firstRun.ts
|
|
28057
|
-
import { existsSync as
|
|
28867
|
+
import { existsSync as existsSync17 } from "node:fs";
|
|
28058
28868
|
function shouldRunWizard(input) {
|
|
28059
|
-
const exists = input.exists ??
|
|
28869
|
+
const exists = input.exists ?? existsSync17;
|
|
28060
28870
|
if (input.hasResetConfigFlag) {
|
|
28061
28871
|
return { shouldRun: true, reason: "--reset-config flag forced wizard" };
|
|
28062
28872
|
}
|
|
@@ -28091,15 +28901,15 @@ function parseWizardFlags(argv) {
|
|
|
28091
28901
|
}
|
|
28092
28902
|
|
|
28093
28903
|
// src/cli/wizard/runWizard.tsx
|
|
28094
|
-
import
|
|
28095
|
-
import { Box as
|
|
28096
|
-
import { useInput } from "ink";
|
|
28904
|
+
import React9, { useEffect as useEffect5, useState as useState6 } from "react";
|
|
28905
|
+
import { Box as Box9, Text as Text9 } from "ink";
|
|
28906
|
+
import { useInput as useInput2 } from "ink";
|
|
28097
28907
|
init_keyStore();
|
|
28098
28908
|
init_providerConfig();
|
|
28099
28909
|
|
|
28100
28910
|
// src/cli/wizard/index.tsx
|
|
28101
|
-
import
|
|
28102
|
-
import { Box as
|
|
28911
|
+
import React8 from "react";
|
|
28912
|
+
import { Box as Box8, Text as Text8 } from "ink";
|
|
28103
28913
|
|
|
28104
28914
|
// src/cli/wizard/useWizardState.ts
|
|
28105
28915
|
init_providerConfig();
|
|
@@ -28214,18 +29024,17 @@ function createWizardState(opts) {
|
|
|
28214
29024
|
var API_KEY_OPTIONS = ["env", "keystore", "skip"];
|
|
28215
29025
|
|
|
28216
29026
|
// src/cli/wizard/index.tsx
|
|
28217
|
-
var VERSION = "0.7.2";
|
|
28218
29027
|
function Frame({ children }) {
|
|
28219
|
-
return /* @__PURE__ */
|
|
29028
|
+
return /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1 }, children);
|
|
28220
29029
|
}
|
|
28221
29030
|
function Step(props) {
|
|
28222
|
-
return /* @__PURE__ */
|
|
29031
|
+
return /* @__PURE__ */ React8.createElement(Box8, null, /* @__PURE__ */ React8.createElement(Text8, { color: props.active ? "cyan" : "gray", inverse: props.active }, " ", props.index, "/", props.total, " ", props.name, " "));
|
|
28223
29032
|
}
|
|
28224
29033
|
function renderProviderList(providers, cursor) {
|
|
28225
|
-
return /* @__PURE__ */
|
|
29034
|
+
return /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column" }, providers.map((p3, i) => {
|
|
28226
29035
|
const arrow = i === cursor ? "\u279C " : " ";
|
|
28227
29036
|
const color = i === cursor ? "cyan" : void 0;
|
|
28228
|
-
return /* @__PURE__ */
|
|
29037
|
+
return /* @__PURE__ */ React8.createElement(Text8, { key: p3.id, color }, arrow, p3.displayName, " ", /* @__PURE__ */ React8.createElement(Text8, { color: "gray" }, "(", p3.id, ", uses env ", p3.envVar, ")"));
|
|
28229
29038
|
}));
|
|
28230
29039
|
}
|
|
28231
29040
|
function renderApiKeyOptions(cursor) {
|
|
@@ -28234,37 +29043,37 @@ function renderApiKeyOptions(cursor) {
|
|
|
28234
29043
|
keystore: "Save to local keyStore (encrypted)",
|
|
28235
29044
|
skip: "Skip for now (chat will fail until key is set)"
|
|
28236
29045
|
};
|
|
28237
|
-
return /* @__PURE__ */
|
|
29046
|
+
return /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column" }, API_KEY_OPTIONS.map((choice, i) => {
|
|
28238
29047
|
const arrow = i === cursor ? "\u279C " : " ";
|
|
28239
29048
|
const color = i === cursor ? "cyan" : void 0;
|
|
28240
|
-
return /* @__PURE__ */
|
|
29049
|
+
return /* @__PURE__ */ React8.createElement(Text8, { key: choice, color }, arrow, labels[choice]);
|
|
28241
29050
|
}));
|
|
28242
29051
|
}
|
|
28243
29052
|
function Wizard({ state: state2, providers }) {
|
|
28244
29053
|
const s = state2.state;
|
|
28245
29054
|
if (s.committed) {
|
|
28246
|
-
return /* @__PURE__ */
|
|
29055
|
+
return /* @__PURE__ */ React8.createElement(Frame, null, /* @__PURE__ */ React8.createElement(Text8, { color: "green" }, "\u2713 Setup complete!"), /* @__PURE__ */ React8.createElement(Text8, null, "Provider: ", /* @__PURE__ */ React8.createElement(Text8, { color: "cyan" }, s.providerId), " | ", "Model: ", /* @__PURE__ */ React8.createElement(Text8, { color: "cyan" }, s.model), " | ", "API key: ", /* @__PURE__ */ React8.createElement(Text8, { color: "cyan" }, s.apiKeyChoice ?? "n/a")), /* @__PURE__ */ React8.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(Text8, { color: "gray" }, "Launching zelari-code\u2026 (press any key)")));
|
|
28247
29056
|
}
|
|
28248
|
-
return /* @__PURE__ */
|
|
29057
|
+
return /* @__PURE__ */ React8.createElement(Frame, null, /* @__PURE__ */ React8.createElement(Text8, { color: "cyan", bold: true }, "zelari-code v", VERSION, " \u2014 first-time setup"), /* @__PURE__ */ React8.createElement(Box8, { marginTop: 1, marginBottom: 1, flexDirection: "row" }, /* @__PURE__ */ React8.createElement(Step, { index: 1, total: 5, name: "welcome", active: s.step === "welcome" }), /* @__PURE__ */ React8.createElement(Step, { index: 2, total: 5, name: "provider", active: s.step === "provider" }), /* @__PURE__ */ React8.createElement(Step, { index: 3, total: 5, name: "model", active: s.step === "model" }), /* @__PURE__ */ React8.createElement(Step, { index: 4, total: 5, name: "apikey", active: s.step === "apikey" }), /* @__PURE__ */ React8.createElement(Step, { index: 5, total: 5, name: "confirm", active: s.step === "confirm" })), s.step === "welcome" && /* @__PURE__ */ React8.createElement(React8.Fragment, null, /* @__PURE__ */ React8.createElement(Text8, null, "Welcome! Let's get you coding in under two minutes."), /* @__PURE__ */ React8.createElement(Text8, { color: "gray" }, "We'll pick a provider, default model, and how to handle your API key."), /* @__PURE__ */ React8.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(Text8, null, "Press "), /* @__PURE__ */ React8.createElement(Text8, { color: "cyan", inverse: true }, " Enter "), /* @__PURE__ */ React8.createElement(Text8, null, " to continue, or "), /* @__PURE__ */ React8.createElement(Text8, { color: "red", inverse: true }, " Q "), /* @__PURE__ */ React8.createElement(Text8, null, " to quit (re-run with "), /* @__PURE__ */ React8.createElement(Text8, { color: "gray" }, "--no-wizard"), /* @__PURE__ */ React8.createElement(Text8, null, " to skip later)."))), s.step === "provider" && /* @__PURE__ */ React8.createElement(React8.Fragment, null, /* @__PURE__ */ React8.createElement(Text8, null, "Choose your LLM provider:"), /* @__PURE__ */ React8.createElement(Box8, { marginTop: 1 }, renderProviderList(providers, s.providerCursor)), /* @__PURE__ */ React8.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(Text8, { color: "gray" }, "\u2191/\u2193 to move, Enter to confirm"))), s.step === "model" && /* @__PURE__ */ React8.createElement(React8.Fragment, null, /* @__PURE__ */ React8.createElement(Text8, null, "Model for ", /* @__PURE__ */ React8.createElement(Text8, { color: "cyan" }, s.providerId), ":"), /* @__PURE__ */ React8.createElement(Box8, { marginTop: 1, borderStyle: "single", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React8.createElement(Text8, null, s.model ?? "(empty)")), /* @__PURE__ */ React8.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(Text8, null, "Press ", /* @__PURE__ */ React8.createElement(Text8, { color: "cyan", inverse: true }, " Enter "), "to accept, or type a new name. ", /* @__PURE__ */ React8.createElement(Text8, { color: "gray" }, "(default kept on empty input)")))), s.step === "apikey" && /* @__PURE__ */ React8.createElement(React8.Fragment, null, /* @__PURE__ */ React8.createElement(Text8, null, "How should we handle the API key?"), /* @__PURE__ */ React8.createElement(Box8, { marginTop: 1 }, renderApiKeyOptions(s.apiKeyCursor)), /* @__PURE__ */ React8.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(Text8, { color: "gray" }, "\u2191/\u2193 to move, Enter to confirm"))), s.step === "confirm" && /* @__PURE__ */ React8.createElement(React8.Fragment, null, /* @__PURE__ */ React8.createElement(Text8, null, "Confirm your setup:"), /* @__PURE__ */ React8.createElement(Box8, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React8.createElement(Text8, null, "Provider: ", /* @__PURE__ */ React8.createElement(Text8, { color: "cyan" }, s.providerId)), /* @__PURE__ */ React8.createElement(Text8, null, "Model: ", /* @__PURE__ */ React8.createElement(Text8, { color: "cyan" }, s.model)), /* @__PURE__ */ React8.createElement(Text8, null, "API key: ", /* @__PURE__ */ React8.createElement(Text8, { color: "cyan" }, s.apiKeyChoice ?? "(unset)"))), /* @__PURE__ */ React8.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(Text8, null, "Press ", /* @__PURE__ */ React8.createElement(Text8, { color: "green", inverse: true }, " Enter "), "to save and launch, or ", /* @__PURE__ */ React8.createElement(Text8, { color: "yellow", inverse: true }, " B "), "to go back."))));
|
|
28249
29058
|
}
|
|
28250
29059
|
|
|
28251
29060
|
// src/cli/wizard/runWizard.tsx
|
|
28252
29061
|
function RunWizard(_props) {
|
|
28253
|
-
const [wiz] =
|
|
29062
|
+
const [wiz] = useState6(
|
|
28254
29063
|
() => createWizardState({
|
|
28255
29064
|
providers: PROVIDERS,
|
|
28256
29065
|
defaultModelFor: (id) => getModelForProvider(id)
|
|
28257
29066
|
})
|
|
28258
29067
|
);
|
|
28259
|
-
const [, force] =
|
|
28260
|
-
|
|
29068
|
+
const [, force] = useState6(0);
|
|
29069
|
+
useEffect5(() => {
|
|
28261
29070
|
if (typeof wiz.subscribe === "function") {
|
|
28262
29071
|
const sub = wiz.subscribe(() => force((n) => n + 1));
|
|
28263
29072
|
return () => sub();
|
|
28264
29073
|
}
|
|
28265
29074
|
return void 0;
|
|
28266
29075
|
}, [wiz]);
|
|
28267
|
-
|
|
29076
|
+
useInput2((input, key) => {
|
|
28268
29077
|
if (wiz.state.committed) return;
|
|
28269
29078
|
const s = wiz.state;
|
|
28270
29079
|
if (key.escape) {
|
|
@@ -28321,20 +29130,20 @@ function RunWizard(_props) {
|
|
|
28321
29130
|
}
|
|
28322
29131
|
});
|
|
28323
29132
|
if (wiz.state.committed) {
|
|
28324
|
-
return /* @__PURE__ */
|
|
29133
|
+
return /* @__PURE__ */ React9.createElement(PostCommitBridge, null);
|
|
28325
29134
|
}
|
|
28326
|
-
return /* @__PURE__ */
|
|
29135
|
+
return /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React9.createElement(Wizard, { state: wiz, providers: PROVIDERS }));
|
|
28327
29136
|
}
|
|
28328
29137
|
function PostCommitBridge() {
|
|
28329
|
-
const [showApp, setShowApp] =
|
|
28330
|
-
|
|
29138
|
+
const [showApp, setShowApp] = useState6(false);
|
|
29139
|
+
useEffect5(() => {
|
|
28331
29140
|
const t = setTimeout(() => setShowApp(true), 1200);
|
|
28332
29141
|
return () => clearTimeout(t);
|
|
28333
29142
|
}, []);
|
|
28334
29143
|
if (showApp) {
|
|
28335
|
-
return /* @__PURE__ */
|
|
29144
|
+
return /* @__PURE__ */ React9.createElement(App, null);
|
|
28336
29145
|
}
|
|
28337
|
-
return /* @__PURE__ */
|
|
29146
|
+
return /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React9.createElement(Box9, { borderStyle: "round", borderColor: "green", paddingX: 2, paddingY: 1, flexDirection: "column" }, /* @__PURE__ */ React9.createElement(Text9, { color: "green", bold: true }, "\u2713 Setup complete! Launching zelari-code\u2026"), /* @__PURE__ */ React9.createElement(Text9, { color: "gray" }, "Press Ctrl+C any time to exit.")));
|
|
28338
29147
|
}
|
|
28339
29148
|
|
|
28340
29149
|
// src/cli/headless.ts
|
|
@@ -28546,8 +29355,8 @@ async function runHeadlessCouncil(opts, provider, model, providerStream) {
|
|
|
28546
29355
|
|
|
28547
29356
|
// src/cli/skillsMd.ts
|
|
28548
29357
|
init_skills2();
|
|
28549
|
-
import { existsSync as
|
|
28550
|
-
import { join as
|
|
29358
|
+
import { existsSync as existsSync18, readdirSync as readdirSync4, readFileSync as readFileSync13 } from "node:fs";
|
|
29359
|
+
import { join as join8 } from "node:path";
|
|
28551
29360
|
import { homedir as homedir4 } from "node:os";
|
|
28552
29361
|
var CODING_CATEGORIES = /* @__PURE__ */ new Set([
|
|
28553
29362
|
"plan",
|
|
@@ -28563,10 +29372,10 @@ var CODING_CATEGORIES = /* @__PURE__ */ new Set([
|
|
|
28563
29372
|
]);
|
|
28564
29373
|
function skillMdSearchDirs(projectRoot = process.cwd()) {
|
|
28565
29374
|
return [
|
|
28566
|
-
|
|
28567
|
-
|
|
28568
|
-
|
|
28569
|
-
|
|
29375
|
+
join8(projectRoot, ".zelari", "skills"),
|
|
29376
|
+
join8(projectRoot, ".claude", "skills"),
|
|
29377
|
+
join8(projectRoot, ".opencode", "skills"),
|
|
29378
|
+
join8(homedir4(), ".zelari-code", "skills")
|
|
28570
29379
|
];
|
|
28571
29380
|
}
|
|
28572
29381
|
function parseSkillMd(content, sourcePath) {
|
|
@@ -28624,7 +29433,7 @@ function loadSkillMdSkills(projectRoot = process.cwd(), options = {}) {
|
|
|
28624
29433
|
const summary = { loaded: [], skipped: [] };
|
|
28625
29434
|
const seen = new Set(options.existingIds ?? []);
|
|
28626
29435
|
for (const dir of skillMdSearchDirs(projectRoot)) {
|
|
28627
|
-
if (!
|
|
29436
|
+
if (!existsSync18(dir)) continue;
|
|
28628
29437
|
let entries;
|
|
28629
29438
|
try {
|
|
28630
29439
|
entries = readdirSync4(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
@@ -28632,10 +29441,10 @@ function loadSkillMdSkills(projectRoot = process.cwd(), options = {}) {
|
|
|
28632
29441
|
continue;
|
|
28633
29442
|
}
|
|
28634
29443
|
for (const entry of entries) {
|
|
28635
|
-
const skillPath =
|
|
28636
|
-
if (!
|
|
29444
|
+
const skillPath = join8(dir, entry, "SKILL.md");
|
|
29445
|
+
if (!existsSync18(skillPath)) continue;
|
|
28637
29446
|
try {
|
|
28638
|
-
const parsed = parseSkillMd(
|
|
29447
|
+
const parsed = parseSkillMd(readFileSync13(skillPath, "utf8"), skillPath);
|
|
28639
29448
|
if (!parsed) {
|
|
28640
29449
|
summary.skipped.push({ path: skillPath, reason: "missing/invalid frontmatter (name, description) or empty body" });
|
|
28641
29450
|
continue;
|
|
@@ -28657,7 +29466,7 @@ function loadSkillMdSkills(projectRoot = process.cwd(), options = {}) {
|
|
|
28657
29466
|
|
|
28658
29467
|
// src/cli/main.ts
|
|
28659
29468
|
init_skills2();
|
|
28660
|
-
var
|
|
29469
|
+
var VERSION = "0.7.8";
|
|
28661
29470
|
async function backgroundUpdateCheck() {
|
|
28662
29471
|
if (process.env.ANATHEMA_DEV === "1") return;
|
|
28663
29472
|
await new Promise((resolve) => setTimeout(resolve, 3e3));
|
|
@@ -28687,7 +29496,7 @@ async function shutdown() {
|
|
|
28687
29496
|
function pickRootComponent() {
|
|
28688
29497
|
const argv = process.argv.slice(2);
|
|
28689
29498
|
if (argv.includes("--version") || argv.includes("-v")) {
|
|
28690
|
-
console.log(`zelari-code v${
|
|
29499
|
+
console.log(`zelari-code v${VERSION}`);
|
|
28691
29500
|
process.exit(0);
|
|
28692
29501
|
}
|
|
28693
29502
|
if (argv.includes("--help") || argv.includes("-h")) {
|
|
@@ -28713,9 +29522,12 @@ function pickRootComponent() {
|
|
|
28713
29522
|
});
|
|
28714
29523
|
if (decision.shouldRun) {
|
|
28715
29524
|
console.error(`[zelari-code] starting wizard: ${decision.reason}`);
|
|
28716
|
-
return { kind: "wizard", element:
|
|
29525
|
+
return { kind: "wizard", element: React10.createElement(RunWizard) };
|
|
28717
29526
|
}
|
|
28718
|
-
return {
|
|
29527
|
+
return {
|
|
29528
|
+
kind: "app",
|
|
29529
|
+
element: React10.createElement(SplashGate, { version: VERSION }, React10.createElement(App))
|
|
29530
|
+
};
|
|
28719
29531
|
}
|
|
28720
29532
|
function loadUserSkills() {
|
|
28721
29533
|
try {
|
|
@@ -28758,6 +29570,6 @@ function main() {
|
|
|
28758
29570
|
}
|
|
28759
29571
|
main();
|
|
28760
29572
|
export {
|
|
28761
|
-
|
|
29573
|
+
VERSION
|
|
28762
29574
|
};
|
|
28763
29575
|
//# sourceMappingURL=main.bundled.js.map
|