@appsforgood/next-supabase-kit 0.1.4 → 0.1.6
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/CHANGELOG.md +12 -0
- package/DOGFOOD.md +24 -0
- package/LOOP_CODING.md +107 -0
- package/MAINTAINER_RELEASE.md +100 -0
- package/README.md +40 -4
- package/REPOSITORY_SETTINGS.md +7 -3
- package/SUPPLY_CHAIN.md +5 -5
- package/UPGRADE.md +2 -1
- package/antigravity/commands/accessibility-pass.toml +16 -0
- package/antigravity/commands/browser-qa.toml +18 -0
- package/antigravity/commands/distinctiveness-pass.toml +16 -0
- package/antigravity/commands/frontend.toml +5 -4
- package/antigravity/commands/layout-cleanup.toml +16 -0
- package/antigravity/commands/responsive-cleanup.toml +16 -0
- package/antigravity/commands/screenshot-critique.toml +16 -0
- package/antigravity/commands/ui-audit.toml +17 -0
- package/antigravity/commands/ui-polish.toml +17 -0
- package/antigravity/plugin.json +9 -0
- package/checklists/ui-acceptance-rubric.md +58 -0
- package/checklists/ui-detectors.md +75 -0
- package/dist/index.js +1090 -411
- package/dist/index.js.map +1 -1
- package/dist/studio/office/assets/office.css +188 -29
- package/dist/studio/office/assets/office.js +72 -50
- package/dist/studio/wizard/assets/wizard.css +157 -26
- package/dist/studio/wizard/assets/wizard.js +78 -70
- package/examples/next-supabase-installed/.agent-kit/agent-roster.json +7 -3
- package/examples/next-supabase-installed/.agent-kit/manifest.json +13 -11
- package/examples/next-supabase-installed/audit-output.json +22 -2
- package/examples/next-supabase-installed/tree.txt +1 -0
- package/package.json +28 -7
- package/prompts/ui-command-index.md +124 -0
- package/research/summaries/agentic-engineering-maturity-levels.md +54 -0
- package/rosters/next-supabase-default-council.json +37 -12
- package/runtime-skills/ui-improvement-harness/SKILL.md +12 -0
- package/schemas/agentic-level.schema.json +47 -0
- package/schemas/onboarding-state.schema.json +4 -1
- package/skills/ui-improvement-harness.md +96 -0
- package/templates/next-supabase/AGENT_ROSTER.md +6 -3
- package/templates/next-supabase/ASSISTANT_ADAPTERS.md +3 -1
- package/templates/next-supabase/DECISIONS.md +14 -0
- package/templates/next-supabase/DESIGN.md +3 -0
- package/templates/next-supabase/DOCS.md +7 -1
- package/templates/next-supabase/LOOP_CODING.md +98 -0
- package/templates/next-supabase/QUALITY_GATES.md +4 -2
- package/templates/next-supabase/SKILLS.md +14 -0
- package/templates/next-supabase/SPEC.md +5 -1
- package/templates/next-supabase/STYLE_GUIDE.md +3 -1
- package/templates/next-supabase/TESTING.md +14 -0
package/dist/index.js
CHANGED
|
@@ -1,23 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/cli/index.ts
|
|
4
|
+
import { existsSync as existsSync23, readFileSync as readFileSync24, writeFileSync as writeFileSync2 } from "fs";
|
|
5
|
+
import { join as join27 } from "path";
|
|
4
6
|
import { Command } from "commander";
|
|
5
7
|
|
|
6
8
|
// src/install/add-skill.ts
|
|
7
|
-
import { existsSync as existsSync3 } from "fs";
|
|
9
|
+
import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
|
|
8
10
|
import { join as join3 } from "path";
|
|
9
11
|
|
|
10
12
|
// src/utils/fs.ts
|
|
11
13
|
import { createHash } from "crypto";
|
|
12
|
-
import {
|
|
13
|
-
cpSync,
|
|
14
|
-
existsSync,
|
|
15
|
-
lstatSync,
|
|
16
|
-
mkdirSync,
|
|
17
|
-
readFileSync,
|
|
18
|
-
readdirSync,
|
|
19
|
-
writeFileSync
|
|
20
|
-
} from "fs";
|
|
14
|
+
import { cpSync, existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "fs";
|
|
21
15
|
import { basename, dirname, isAbsolute, join, relative, resolve } from "path";
|
|
22
16
|
function ensureDir(path) {
|
|
23
17
|
mkdirSync(path, { recursive: true });
|
|
@@ -133,20 +127,30 @@ function addSkill(cwd, skillName, options = {}) {
|
|
|
133
127
|
const available = listSkills().join(", ");
|
|
134
128
|
throw new Error(`Unknown skill "${skillName}". Available skills: ${available}`);
|
|
135
129
|
}
|
|
136
|
-
const
|
|
130
|
+
const targetRelativePath = join3(".agent-kit", "skills", normalized);
|
|
131
|
+
if (options.dryRun) {
|
|
132
|
+
const existing = readTextIfExists(join3(cwd, targetRelativePath));
|
|
133
|
+
const sourceContent = readFileSync2(sourcePath, "utf8");
|
|
134
|
+
let action;
|
|
135
|
+
if (existing === null) action = "created";
|
|
136
|
+
else if (sha256(existing) === sha256(sourceContent)) action = "unchanged";
|
|
137
|
+
else action = options.force ? "overwritten" : "conflict";
|
|
138
|
+
return { action, target: targetRelativePath, dryRun: true };
|
|
139
|
+
}
|
|
140
|
+
const result = copyTextWithConflict(sourcePath, cwd, targetRelativePath, {
|
|
137
141
|
force: Boolean(options.force),
|
|
138
142
|
conflictRoot: join3(cwd, ".agent-kit", "conflicts")
|
|
139
143
|
});
|
|
140
|
-
return
|
|
144
|
+
return { ...result, dryRun: false };
|
|
141
145
|
}
|
|
142
146
|
|
|
143
147
|
// src/install/adapter-validate.ts
|
|
144
|
-
import { existsSync as existsSync12, readFileSync as
|
|
148
|
+
import { existsSync as existsSync12, readFileSync as readFileSync10 } from "fs";
|
|
145
149
|
import { join as join12, normalize } from "path";
|
|
146
150
|
|
|
147
151
|
// src/config/defaults.ts
|
|
148
152
|
var PACKAGE_NAME = "@appsforgood/next-supabase-kit";
|
|
149
|
-
var PACKAGE_VERSION = "0.1.
|
|
153
|
+
var PACKAGE_VERSION = "0.1.6";
|
|
150
154
|
var DEFAULT_CONFIG = {
|
|
151
155
|
stack: "next-supabase",
|
|
152
156
|
projectType: "saas",
|
|
@@ -185,6 +189,7 @@ var ROOT_DOCS = [
|
|
|
185
189
|
"STYLE_GUIDE.md",
|
|
186
190
|
"SECURITY.md",
|
|
187
191
|
"TESTING.md",
|
|
192
|
+
"LOOP_CODING.md",
|
|
188
193
|
"DEPLOYMENT.md",
|
|
189
194
|
"UPGRADE.md"
|
|
190
195
|
];
|
|
@@ -263,7 +268,7 @@ var CI_TEMPLATE_FILES = [
|
|
|
263
268
|
];
|
|
264
269
|
|
|
265
270
|
// src/studio/shared.ts
|
|
266
|
-
import { appendFileSync, existsSync as existsSync4, readFileSync as
|
|
271
|
+
import { appendFileSync, existsSync as existsSync4, readFileSync as readFileSync3 } from "fs";
|
|
267
272
|
import { basename as basename2, dirname as dirname3, join as join4 } from "path";
|
|
268
273
|
var AGENT_KIT_DIR = ".agent-kit";
|
|
269
274
|
var CONTEXT_JSON = ".agent-kit/project-context.json";
|
|
@@ -314,7 +319,7 @@ function ensureStudioDirs(cwd) {
|
|
|
314
319
|
function readJsonFile(cwd, relativePath) {
|
|
315
320
|
const path = resolveInside(cwd, relativePath);
|
|
316
321
|
if (!existsSync4(path)) return null;
|
|
317
|
-
return JSON.parse(
|
|
322
|
+
return JSON.parse(readFileSync3(path, "utf8"));
|
|
318
323
|
}
|
|
319
324
|
function writeJsonFile(cwd, relativePath, value) {
|
|
320
325
|
writeText(resolveInside(cwd, relativePath), `${JSON.stringify(value, null, 2)}
|
|
@@ -329,7 +334,7 @@ function appendJsonLine(cwd, relativePath, value) {
|
|
|
329
334
|
function readJsonLines(cwd, relativePath) {
|
|
330
335
|
const text = readTextIfExists(resolveInside(cwd, relativePath));
|
|
331
336
|
if (!text) return [];
|
|
332
|
-
return text.split(/\r?\n/).filter((
|
|
337
|
+
return text.split(/\r?\n/).filter((line2) => line2.trim().length > 0).map((line2) => JSON.parse(line2));
|
|
333
338
|
}
|
|
334
339
|
function writeTextFile(cwd, relativePath, content) {
|
|
335
340
|
writeText(resolveInside(cwd, relativePath), content);
|
|
@@ -359,7 +364,7 @@ function unique(values) {
|
|
|
359
364
|
}
|
|
360
365
|
|
|
361
366
|
// src/install/audit.ts
|
|
362
|
-
import { existsSync as existsSync11, readFileSync as
|
|
367
|
+
import { existsSync as existsSync11, readFileSync as readFileSync9, statSync } from "fs";
|
|
363
368
|
import { join as join11 } from "path";
|
|
364
369
|
|
|
365
370
|
// src/config/contracts.ts
|
|
@@ -629,6 +634,8 @@ var SessionEventContract = z.object({
|
|
|
629
634
|
context2.addIssue({ code: z.ZodIssueCode.custom, message: "required output events require outputName and outputStatus", path: ["outputName"] });
|
|
630
635
|
}
|
|
631
636
|
});
|
|
637
|
+
var AgenticLevelCore = z.union([z.literal(3), z.literal(4), z.literal(5), z.literal(6)]);
|
|
638
|
+
var AgenticLevelTarget = z.union([z.literal(3), z.literal(4), z.literal(5), z.literal(6), z.literal(7), z.literal(8)]);
|
|
632
639
|
var OnboardingStateContract = z.object({
|
|
633
640
|
schemaVersion: z.literal(1),
|
|
634
641
|
depth: z.enum(["quick", "standard", "complete", "undecided"]),
|
|
@@ -642,7 +649,27 @@ var OnboardingStateContract = z.object({
|
|
|
642
649
|
wizardVersion: z.string(),
|
|
643
650
|
ideSurface: z.enum(["cursor", "copilot", "claude", "codex", "other"]).optional(),
|
|
644
651
|
ideVerifiedAt: z.string().datetime().optional(),
|
|
645
|
-
visualQaTier: z.enum(["baseline", "strong", "mature"]).optional()
|
|
652
|
+
visualQaTier: z.enum(["baseline", "strong", "mature"]).optional(),
|
|
653
|
+
targetAgenticLevel: AgenticLevelTarget.optional(),
|
|
654
|
+
lastAgenticLevel: AgenticLevelCore.optional(),
|
|
655
|
+
lastAgenticComputedAt: z.string().datetime().optional()
|
|
656
|
+
}).strict();
|
|
657
|
+
var AgenticLevelSignalContract = z.object({
|
|
658
|
+
id: z.string().min(1),
|
|
659
|
+
level: AgenticLevelCore,
|
|
660
|
+
label: z.string().min(1),
|
|
661
|
+
pass: z.boolean(),
|
|
662
|
+
evidence: z.string().min(1),
|
|
663
|
+
remediation: z.string().min(1)
|
|
664
|
+
}).strict();
|
|
665
|
+
var AgenticLevelContract = z.object({
|
|
666
|
+
currentLevel: AgenticLevelCore,
|
|
667
|
+
targetLevel: AgenticLevelTarget,
|
|
668
|
+
maintainerProfile: z.boolean(),
|
|
669
|
+
computedAt: z.string().datetime(),
|
|
670
|
+
maintainerNote: z.string().optional(),
|
|
671
|
+
signals: z.array(AgenticLevelSignalContract),
|
|
672
|
+
climbSteps: z.array(AgenticLevelSignalContract)
|
|
646
673
|
}).strict();
|
|
647
674
|
function formatContractIssues(error) {
|
|
648
675
|
return error.issues.map((issue) => {
|
|
@@ -656,12 +683,12 @@ import { existsSync as existsSync6 } from "fs";
|
|
|
656
683
|
import { join as join6 } from "path";
|
|
657
684
|
|
|
658
685
|
// src/studio/context.ts
|
|
659
|
-
import { existsSync as existsSync5, readFileSync as
|
|
686
|
+
import { existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
|
|
660
687
|
import { join as join5 } from "path";
|
|
661
688
|
function readPackageJson(cwd) {
|
|
662
689
|
const path = join5(cwd, "package.json");
|
|
663
690
|
if (!existsSync5(path)) return null;
|
|
664
|
-
return JSON.parse(
|
|
691
|
+
return JSON.parse(readFileSync4(path, "utf8"));
|
|
665
692
|
}
|
|
666
693
|
function detectPackageManager(cwd) {
|
|
667
694
|
if (existsSync5(join5(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
@@ -680,7 +707,7 @@ function detectFromDependencies(packageJson, names) {
|
|
|
680
707
|
function readEnvExampleKeys(cwd) {
|
|
681
708
|
const envText = readTextIfExists(join5(cwd, ".env.example")) ?? "";
|
|
682
709
|
return unique(
|
|
683
|
-
envText.split(/\r?\n/).map((
|
|
710
|
+
envText.split(/\r?\n/).map((line2) => line2.trim()).filter((line2) => line2 && !line2.startsWith("#") && line2.includes("=")).map((line2) => line2.split("=")[0]?.trim() ?? "").filter(Boolean)
|
|
684
711
|
);
|
|
685
712
|
}
|
|
686
713
|
function inferOpenQuestions(context2) {
|
|
@@ -1114,19 +1141,19 @@ function onboardingStateExists(cwd) {
|
|
|
1114
1141
|
}
|
|
1115
1142
|
|
|
1116
1143
|
// src/install/install.ts
|
|
1117
|
-
import { existsSync as existsSync10, readFileSync as
|
|
1144
|
+
import { existsSync as existsSync10, readFileSync as readFileSync8 } from "fs";
|
|
1118
1145
|
import { join as join10 } from "path";
|
|
1119
1146
|
|
|
1120
1147
|
// src/install/ide-activate.ts
|
|
1121
|
-
import { existsSync as existsSync9, readFileSync as
|
|
1148
|
+
import { existsSync as existsSync9, readFileSync as readFileSync7 } from "fs";
|
|
1122
1149
|
import { join as join9 } from "path";
|
|
1123
1150
|
|
|
1124
1151
|
// src/install/roster-adapters.ts
|
|
1125
|
-
import { existsSync as existsSync8, readFileSync as
|
|
1152
|
+
import { existsSync as existsSync8, readFileSync as readFileSync6, readdirSync as readdirSync2 } from "fs";
|
|
1126
1153
|
import { join as join8 } from "path";
|
|
1127
1154
|
|
|
1128
1155
|
// src/studio/wizard/roster.ts
|
|
1129
|
-
import { existsSync as existsSync7, readFileSync as
|
|
1156
|
+
import { existsSync as existsSync7, readFileSync as readFileSync5 } from "fs";
|
|
1130
1157
|
import { join as join7 } from "path";
|
|
1131
1158
|
var AGENT_ROSTER_JSON = ".agent-kit/agent-roster.json";
|
|
1132
1159
|
var FALLBACK_SUMMARIES = {
|
|
@@ -1146,7 +1173,7 @@ function readPurposeFromAgentFile(cwd, relPath) {
|
|
|
1146
1173
|
if (!relPath) return null;
|
|
1147
1174
|
const path = join7(cwd, relPath);
|
|
1148
1175
|
if (!existsSync7(path)) return null;
|
|
1149
|
-
const text =
|
|
1176
|
+
const text = readFileSync5(path, "utf8");
|
|
1150
1177
|
const match = text.match(/## Purpose\s*\n+\s*([^\n#]+)/);
|
|
1151
1178
|
return match?.[1]?.trim() ?? null;
|
|
1152
1179
|
}
|
|
@@ -1186,20 +1213,18 @@ function buildAgentWizardSteps(cwd) {
|
|
|
1186
1213
|
depth: depths,
|
|
1187
1214
|
optional: true
|
|
1188
1215
|
},
|
|
1189
|
-
...agents.map(
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
})
|
|
1202
|
-
)
|
|
1216
|
+
...agents.map((agent) => ({
|
|
1217
|
+
id: `brief-${agent.id}`,
|
|
1218
|
+
section: "team",
|
|
1219
|
+
title: `Brief ${agent.name}`,
|
|
1220
|
+
why: `${agent.roleSummary} What should they know about this project that is not obvious from the repo?`,
|
|
1221
|
+
fields: [`agentBrief_${agent.id}`],
|
|
1222
|
+
agentId: agent.id,
|
|
1223
|
+
agentName: agent.name,
|
|
1224
|
+
roleSummary: agent.roleSummary,
|
|
1225
|
+
depth: depths,
|
|
1226
|
+
optional: true
|
|
1227
|
+
}))
|
|
1203
1228
|
];
|
|
1204
1229
|
}
|
|
1205
1230
|
function agentBriefFieldName(agentId) {
|
|
@@ -1208,8 +1233,8 @@ function agentBriefFieldName(agentId) {
|
|
|
1208
1233
|
|
|
1209
1234
|
// src/install/assistant-adapters-table.ts
|
|
1210
1235
|
function extractAssistantAdapterRow(adaptersDoc, toolLabel) {
|
|
1211
|
-
for (const
|
|
1212
|
-
const trimmed =
|
|
1236
|
+
for (const line2 of adaptersDoc.split("\n")) {
|
|
1237
|
+
const trimmed = line2.trim();
|
|
1213
1238
|
if (!trimmed.startsWith("|")) continue;
|
|
1214
1239
|
const cells = trimmed.split("|").map((cell) => cell.trim()).filter((cell) => cell.length > 0);
|
|
1215
1240
|
if (cells[0] === toolLabel) return trimmed;
|
|
@@ -1284,7 +1309,7 @@ Record meaningful decisions, risks, handoffs, human corrections, artifacts, evid
|
|
|
1284
1309
|
function writeGeneratedAgentFile(cwd, relativePath, content, force, result) {
|
|
1285
1310
|
const targetPath = join8(cwd, relativePath);
|
|
1286
1311
|
if (!force && existsSync8(targetPath)) {
|
|
1287
|
-
const existing =
|
|
1312
|
+
const existing = readFileSync6(targetPath, "utf8");
|
|
1288
1313
|
if (existing === content) {
|
|
1289
1314
|
result.unchanged.push(relativePath);
|
|
1290
1315
|
return;
|
|
@@ -1333,7 +1358,7 @@ function loadAgentReasoningEffortMap(cwd) {
|
|
|
1333
1358
|
const map = /* @__PURE__ */ new Map();
|
|
1334
1359
|
if (!existsSync8(path)) return map;
|
|
1335
1360
|
try {
|
|
1336
|
-
const parsed = JSON.parse(
|
|
1361
|
+
const parsed = JSON.parse(readFileSync6(path, "utf8"));
|
|
1337
1362
|
const profileEffort = /* @__PURE__ */ new Map();
|
|
1338
1363
|
for (const profile of parsed.profiles ?? []) {
|
|
1339
1364
|
if (profile.id && profile.reasoningEffort) {
|
|
@@ -1417,7 +1442,7 @@ function generateCursorSkillsFromKit(cwd, force, result) {
|
|
|
1417
1442
|
if (!existsSync8(skillsRoot)) return;
|
|
1418
1443
|
for (const file of readdirSync2(skillsRoot).filter((name) => name.endsWith(".md"))) {
|
|
1419
1444
|
const skillId = file.replace(/\.md$/, "");
|
|
1420
|
-
const kitMarkdown =
|
|
1445
|
+
const kitMarkdown = readFileSync6(join8(skillsRoot, file), "utf8");
|
|
1421
1446
|
const relativePath = `.cursor/skills/${skillId}/SKILL.md`;
|
|
1422
1447
|
writeGeneratedAgentFile(cwd, relativePath, kitSkillToCursorSkill(skillId, kitMarkdown), force, result);
|
|
1423
1448
|
}
|
|
@@ -1464,27 +1489,13 @@ function installAntigravityAdapter(cwd, packageRoot, force, result) {
|
|
|
1464
1489
|
for (const file of ANTIGRAVITY_PLUGIN_FILES) {
|
|
1465
1490
|
copyAdapterFile(cwd, packageRoot, file.source, file.target, force, result);
|
|
1466
1491
|
}
|
|
1467
|
-
copyDirectoryAsConflicts(
|
|
1468
|
-
|
|
1469
|
-
packageRoot,
|
|
1470
|
-
ANTIGRAVITY_COMMANDS_SOURCE_DIR,
|
|
1471
|
-
ANTIGRAVITY_COMMANDS_TARGET_DIR,
|
|
1472
|
-
force,
|
|
1473
|
-
result
|
|
1474
|
-
);
|
|
1475
|
-
copyDirectoryAsConflicts(
|
|
1476
|
-
cwd,
|
|
1477
|
-
packageRoot,
|
|
1478
|
-
RUNTIME_SKILLS_SOURCE_DIR,
|
|
1479
|
-
ANTIGRAVITY_RUNTIME_SKILLS_TARGET_DIR,
|
|
1480
|
-
force,
|
|
1481
|
-
result
|
|
1482
|
-
);
|
|
1492
|
+
copyDirectoryAsConflicts(cwd, packageRoot, ANTIGRAVITY_COMMANDS_SOURCE_DIR, ANTIGRAVITY_COMMANDS_TARGET_DIR, force, result);
|
|
1493
|
+
copyDirectoryAsConflicts(cwd, packageRoot, RUNTIME_SKILLS_SOURCE_DIR, ANTIGRAVITY_RUNTIME_SKILLS_TARGET_DIR, force, result);
|
|
1483
1494
|
}
|
|
1484
1495
|
function updateAssistantAdaptersTable(cwd, activated) {
|
|
1485
1496
|
const path = join9(cwd, "ASSISTANT_ADAPTERS.md");
|
|
1486
1497
|
if (!existsSync9(path)) return;
|
|
1487
|
-
let content =
|
|
1498
|
+
let content = readFileSync7(path, "utf8");
|
|
1488
1499
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
1489
1500
|
if (activated.has("cursor") && content.includes("| Cursor |")) {
|
|
1490
1501
|
content = content.replace(
|
|
@@ -1595,7 +1606,7 @@ function initProject(options) {
|
|
|
1595
1606
|
const templateHashes = {};
|
|
1596
1607
|
for (const doc of ROOT_DOCS) {
|
|
1597
1608
|
const templatePath = join10(templateRoot, doc);
|
|
1598
|
-
templateHashes[doc] = sha256(
|
|
1609
|
+
templateHashes[doc] = sha256(readFileSync8(templatePath, "utf8"));
|
|
1599
1610
|
const copyResult = copyTextWithConflict(templatePath, cwd, doc, {
|
|
1600
1611
|
force: Boolean(options.force),
|
|
1601
1612
|
conflictRoot: join10(cwd, ".agent-kit", "conflicts")
|
|
@@ -1685,7 +1696,7 @@ function initProject(options) {
|
|
|
1685
1696
|
function readManifest(cwd) {
|
|
1686
1697
|
const manifestPath = join10(cwd, ".agent-kit", "manifest.json");
|
|
1687
1698
|
if (!existsSync10(manifestPath)) return null;
|
|
1688
|
-
return JSON.parse(
|
|
1699
|
+
return JSON.parse(readFileSync8(manifestPath, "utf8"));
|
|
1689
1700
|
}
|
|
1690
1701
|
|
|
1691
1702
|
// src/install/audit.ts
|
|
@@ -1715,6 +1726,7 @@ var REQUIRED_SKILL_IDS = [
|
|
|
1715
1726
|
"frontend-distinctiveness-benchmark",
|
|
1716
1727
|
"frontend-product-quality-rubric",
|
|
1717
1728
|
"frontend-design-system",
|
|
1729
|
+
"ui-improvement-harness",
|
|
1718
1730
|
"visual-regression-qa",
|
|
1719
1731
|
"positioning-messaging",
|
|
1720
1732
|
"conversion-copywriting",
|
|
@@ -1735,7 +1747,8 @@ var REQUIRED_SCHEMA_FILES = [
|
|
|
1735
1747
|
"correction-rules.schema.json",
|
|
1736
1748
|
"session-event.schema.json",
|
|
1737
1749
|
"studio-session.schema.json",
|
|
1738
|
-
"onboarding-state.schema.json"
|
|
1750
|
+
"onboarding-state.schema.json",
|
|
1751
|
+
"agentic-level.schema.json"
|
|
1739
1752
|
];
|
|
1740
1753
|
var COUNCIL_SESSION_DIR = ".agent-kit/council-sessions";
|
|
1741
1754
|
var READINESS_ORDER = ["needs-setup", "baseline-setup", "needs-improvement", "best-practice-candidate"];
|
|
@@ -1755,13 +1768,13 @@ function includesAll(text, values) {
|
|
|
1755
1768
|
}
|
|
1756
1769
|
function readDoc(cwd, file) {
|
|
1757
1770
|
const path = join11(cwd, file);
|
|
1758
|
-
return existsSync11(path) ?
|
|
1771
|
+
return existsSync11(path) ? readFileSync9(path, "utf8") : "";
|
|
1759
1772
|
}
|
|
1760
1773
|
function isPackageRepository(cwd) {
|
|
1761
1774
|
const packagePath = join11(cwd, "package.json");
|
|
1762
1775
|
if (!existsSync11(packagePath)) return false;
|
|
1763
1776
|
try {
|
|
1764
|
-
const packageJson = JSON.parse(
|
|
1777
|
+
const packageJson = JSON.parse(readFileSync9(packagePath, "utf8"));
|
|
1765
1778
|
return packageJson.name === "@appsforgood/next-supabase-kit" && existsSync11(join11(cwd, "src", "cli", "index.ts")) && existsSync11(join11(cwd, "templates", "next-supabase")) && existsSync11(join11(cwd, "rosters", "next-supabase-default-council.json"));
|
|
1766
1779
|
} catch {
|
|
1767
1780
|
return false;
|
|
@@ -1771,7 +1784,7 @@ function readOverrides(cwd) {
|
|
|
1771
1784
|
const path = join11(cwd, ".agent-kit", "overrides.json");
|
|
1772
1785
|
if (!existsSync11(path)) return {};
|
|
1773
1786
|
try {
|
|
1774
|
-
const parsed = JSON.parse(
|
|
1787
|
+
const parsed = JSON.parse(readFileSync9(path, "utf8"));
|
|
1775
1788
|
const templates = parsed.templates ?? {};
|
|
1776
1789
|
return Object.fromEntries(
|
|
1777
1790
|
Object.entries(templates).map(([file, override]) => [
|
|
@@ -1785,7 +1798,7 @@ function readOverrides(cwd) {
|
|
|
1785
1798
|
}
|
|
1786
1799
|
function readTemplate(stack, file) {
|
|
1787
1800
|
const path = join11(findPackageRoot(), "templates", stack, file);
|
|
1788
|
-
return existsSync11(path) ?
|
|
1801
|
+
return existsSync11(path) ? readFileSync9(path, "utf8") : null;
|
|
1789
1802
|
}
|
|
1790
1803
|
function asStringArray(value) {
|
|
1791
1804
|
if (!Array.isArray(value)) return [];
|
|
@@ -1807,7 +1820,7 @@ function addAgentRosterFindings(cwd, findings, rosterRelativePath = DEFAULT_AGEN
|
|
|
1807
1820
|
}
|
|
1808
1821
|
let roster;
|
|
1809
1822
|
try {
|
|
1810
|
-
const parsed = JSON.parse(
|
|
1823
|
+
const parsed = JSON.parse(readFileSync9(rosterPath, "utf8"));
|
|
1811
1824
|
if (!isRecord(parsed)) throw new Error("Roster must be a JSON object.");
|
|
1812
1825
|
const contractResult = AgentRosterContract.safeParse(parsed);
|
|
1813
1826
|
if (!contractResult.success) {
|
|
@@ -2002,7 +2015,7 @@ function addCouncilSessionRecordFindings(cwd, findings) {
|
|
|
2002
2015
|
for (const sessionFile of sessionFiles) {
|
|
2003
2016
|
const displayPath = `${COUNCIL_SESSION_DIR}/${sessionFile}`;
|
|
2004
2017
|
try {
|
|
2005
|
-
const parsed = JSON.parse(
|
|
2018
|
+
const parsed = JSON.parse(readFileSync9(join11(sessionsRoot, sessionFile), "utf8"));
|
|
2006
2019
|
const contractResult = CouncilSessionContract.safeParse(parsed);
|
|
2007
2020
|
if (!contractResult.success) {
|
|
2008
2021
|
invalidCount += 1;
|
|
@@ -2044,7 +2057,7 @@ function addSchemaFindings(cwd, findings, schemaRootRelativePath = ".agent-kit/s
|
|
|
2044
2057
|
continue;
|
|
2045
2058
|
}
|
|
2046
2059
|
try {
|
|
2047
|
-
const parsed = JSON.parse(
|
|
2060
|
+
const parsed = JSON.parse(readFileSync9(schemaPath, "utf8"));
|
|
2048
2061
|
if (!isRecord(parsed) || typeof parsed.$schema !== "string" || !isRecord(parsed.properties)) {
|
|
2049
2062
|
throw new Error("Schema file is missing JSON Schema metadata.");
|
|
2050
2063
|
}
|
|
@@ -2074,7 +2087,7 @@ function addAgentStudioFindings(cwd, findings) {
|
|
|
2074
2087
|
});
|
|
2075
2088
|
} else {
|
|
2076
2089
|
try {
|
|
2077
|
-
const parsed = JSON.parse(
|
|
2090
|
+
const parsed = JSON.parse(readFileSync9(contextPath, "utf8"));
|
|
2078
2091
|
const result = ProjectContextContract.safeParse(parsed);
|
|
2079
2092
|
if (!result.success) {
|
|
2080
2093
|
findings.push({
|
|
@@ -2151,7 +2164,7 @@ function addAgentStudioFindings(cwd, findings) {
|
|
|
2151
2164
|
const path = join11(cwd, relativePath);
|
|
2152
2165
|
if (!existsSync11(path)) continue;
|
|
2153
2166
|
try {
|
|
2154
|
-
const parsed = JSON.parse(
|
|
2167
|
+
const parsed = JSON.parse(readFileSync9(path, "utf8"));
|
|
2155
2168
|
const result = CorrectionRulesContract.safeParse(parsed);
|
|
2156
2169
|
if (!result.success) {
|
|
2157
2170
|
findings.push({
|
|
@@ -2178,7 +2191,7 @@ function addAgentStudioFindings(cwd, findings) {
|
|
|
2178
2191
|
}
|
|
2179
2192
|
const studioExportPath = join11(cwd, STUDIO_EXPORT_HTML);
|
|
2180
2193
|
if (existsSync11(studioExportPath)) {
|
|
2181
|
-
const exportHtml =
|
|
2194
|
+
const exportHtml = readFileSync9(studioExportPath, "utf8");
|
|
2182
2195
|
if (containsLikelySecret(exportHtml)) {
|
|
2183
2196
|
findings.push({
|
|
2184
2197
|
level: "fail",
|
|
@@ -2211,12 +2224,10 @@ function addAgentStudioFindings(cwd, findings) {
|
|
|
2211
2224
|
const sessionDir2 = sessionFile.replace(/[\\/]session\.json$/, "");
|
|
2212
2225
|
const normalizedSessionDir = sessionDir2.replace(/\\/g, "/");
|
|
2213
2226
|
const eventsRelative = `${COUNCIL_SESSION_DIR}/${normalizedSessionDir}/events.jsonl`;
|
|
2214
|
-
const indexRelative = `${COUNCIL_SESSION_DIR}/${normalizedSessionDir}/index.md`;
|
|
2215
|
-
const transcriptRelative = `${COUNCIL_SESSION_DIR}/${normalizedSessionDir}/transcript.md`;
|
|
2216
2227
|
const sessionDirPath = join11(sessionsRoot, sessionDir2);
|
|
2217
2228
|
let sessionResult = null;
|
|
2218
2229
|
try {
|
|
2219
|
-
sessionResult = StudioSessionContract.safeParse(JSON.parse(
|
|
2230
|
+
sessionResult = StudioSessionContract.safeParse(JSON.parse(readFileSync9(join11(sessionDirPath, "session.json"), "utf8")));
|
|
2220
2231
|
if (!sessionResult.success) {
|
|
2221
2232
|
findings.push({
|
|
2222
2233
|
level: "fail",
|
|
@@ -2245,7 +2256,7 @@ function addAgentStudioFindings(cwd, findings) {
|
|
|
2245
2256
|
});
|
|
2246
2257
|
continue;
|
|
2247
2258
|
}
|
|
2248
|
-
const eventText =
|
|
2259
|
+
const eventText = readFileSync9(eventsPath2, "utf8");
|
|
2249
2260
|
if (containsLikelySecret(eventText)) {
|
|
2250
2261
|
findings.push({
|
|
2251
2262
|
level: "fail",
|
|
@@ -2254,12 +2265,12 @@ function addAgentStudioFindings(cwd, findings) {
|
|
|
2254
2265
|
remediation: "Redact tokens, database URLs, env values, and private customer data from session logs."
|
|
2255
2266
|
});
|
|
2256
2267
|
}
|
|
2257
|
-
const eventLines = eventText.split(/\r?\n/).filter((
|
|
2268
|
+
const eventLines = eventText.split(/\r?\n/).filter((line2) => line2.trim().length > 0);
|
|
2258
2269
|
let validEvents = 0;
|
|
2259
2270
|
let verificationCount = 0;
|
|
2260
|
-
for (const [index,
|
|
2271
|
+
for (const [index, line2] of eventLines.entries()) {
|
|
2261
2272
|
try {
|
|
2262
|
-
const result = SessionEventContract.safeParse(JSON.parse(
|
|
2273
|
+
const result = SessionEventContract.safeParse(JSON.parse(line2));
|
|
2263
2274
|
if (!result.success) {
|
|
2264
2275
|
findings.push({
|
|
2265
2276
|
level: "fail",
|
|
@@ -2288,8 +2299,8 @@ function addAgentStudioFindings(cwd, findings) {
|
|
|
2288
2299
|
remediation: "Run agent-kit session render so humans can inspect the current agent transcript and handoffs."
|
|
2289
2300
|
});
|
|
2290
2301
|
} else {
|
|
2291
|
-
const indexText =
|
|
2292
|
-
const transcriptText =
|
|
2302
|
+
const indexText = readFileSync9(join11(sessionDirPath, "index.md"), "utf8");
|
|
2303
|
+
const transcriptText = readFileSync9(join11(sessionDirPath, "transcript.md"), "utf8");
|
|
2293
2304
|
if (containsLikelySecret(indexText) || containsLikelySecret(transcriptText)) {
|
|
2294
2305
|
findings.push({
|
|
2295
2306
|
level: "fail",
|
|
@@ -2446,7 +2457,7 @@ function addModelRoutingFindings(cwd, findings, routingRelativePath = DEFAULT_MO
|
|
|
2446
2457
|
}
|
|
2447
2458
|
let routing;
|
|
2448
2459
|
try {
|
|
2449
|
-
routing = JSON.parse(
|
|
2460
|
+
routing = JSON.parse(readFileSync9(routingPath, "utf8"));
|
|
2450
2461
|
} catch {
|
|
2451
2462
|
findings.push({
|
|
2452
2463
|
level: "warn",
|
|
@@ -2508,7 +2519,7 @@ function addTemplateHashFindings(cwd, findings) {
|
|
|
2508
2519
|
if (!existsSync11(targetPath)) continue;
|
|
2509
2520
|
const currentTemplate = readTemplate(manifest.stack, doc);
|
|
2510
2521
|
if (!currentTemplate) continue;
|
|
2511
|
-
const targetHash = sha256(
|
|
2522
|
+
const targetHash = sha256(readFileSync9(targetPath, "utf8"));
|
|
2512
2523
|
const currentTemplateHash = sha256(currentTemplate);
|
|
2513
2524
|
const installedTemplateHash = manifest.templateHashes?.[doc];
|
|
2514
2525
|
const override = overrides[doc];
|
|
@@ -2735,14 +2746,7 @@ function addUpgradeFindings(cwd, findings) {
|
|
|
2735
2746
|
});
|
|
2736
2747
|
}
|
|
2737
2748
|
}
|
|
2738
|
-
var STARTER_EVIDENCE_PATTERNS = [
|
|
2739
|
-
/\bTBD\b/i,
|
|
2740
|
-
/replace with real/i,
|
|
2741
|
-
/example_table/i,
|
|
2742
|
-
/describe the product/i,
|
|
2743
|
-
/document required/i,
|
|
2744
|
-
/pass\/fail\/skipped/i
|
|
2745
|
-
];
|
|
2749
|
+
var STARTER_EVIDENCE_PATTERNS = [/\bTBD\b/i, /replace with real/i, /example_table/i, /describe the product/i, /document required/i, /pass\/fail\/skipped/i];
|
|
2746
2750
|
var EVIDENCE_DOCS = [
|
|
2747
2751
|
"COUNCIL.md",
|
|
2748
2752
|
"SPEC.md",
|
|
@@ -2913,7 +2917,7 @@ function readPackageJson2(cwd) {
|
|
|
2913
2917
|
const path = join11(cwd, "package.json");
|
|
2914
2918
|
if (!existsSync11(path)) return null;
|
|
2915
2919
|
try {
|
|
2916
|
-
return JSON.parse(
|
|
2920
|
+
return JSON.parse(readFileSync9(path, "utf8"));
|
|
2917
2921
|
} catch {
|
|
2918
2922
|
return null;
|
|
2919
2923
|
}
|
|
@@ -2939,7 +2943,7 @@ function addProjectRealityFindings(cwd, findings, options = {}) {
|
|
|
2939
2943
|
});
|
|
2940
2944
|
} else {
|
|
2941
2945
|
const rlsFiles = sqlFiles.filter((file) => {
|
|
2942
|
-
const content =
|
|
2946
|
+
const content = readFileSync9(join11(migrationsDir, file), "utf8");
|
|
2943
2947
|
return /enable\s+row\s+level\s+security/i.test(content);
|
|
2944
2948
|
});
|
|
2945
2949
|
if (rlsFiles.length === 0) {
|
|
@@ -2989,7 +2993,7 @@ function addProjectRealityFindings(cwd, findings, options = {}) {
|
|
|
2989
2993
|
return /\.(ts|tsx|js|jsx|env|json)$/.test(file);
|
|
2990
2994
|
});
|
|
2991
2995
|
const secretHits = trackedSourceFiles.map((file) => {
|
|
2992
|
-
const content =
|
|
2996
|
+
const content = readFileSync9(join11(cwd, file), "utf8");
|
|
2993
2997
|
return containsLikelySecretForAudit(file, content) ? file : null;
|
|
2994
2998
|
}).filter((file) => file !== null).slice(0, 5);
|
|
2995
2999
|
if (secretHits.length > 0) {
|
|
@@ -3064,7 +3068,25 @@ function createAuditReport(cwd) {
|
|
|
3064
3068
|
}
|
|
3065
3069
|
|
|
3066
3070
|
// src/install/adapter-validate.ts
|
|
3067
|
-
var REQUIRED_COMMANDS = [
|
|
3071
|
+
var REQUIRED_COMMANDS = [
|
|
3072
|
+
"setup",
|
|
3073
|
+
"audit",
|
|
3074
|
+
"plan",
|
|
3075
|
+
"handoff",
|
|
3076
|
+
"frontend",
|
|
3077
|
+
"ui-audit",
|
|
3078
|
+
"ui-polish",
|
|
3079
|
+
"layout-cleanup",
|
|
3080
|
+
"responsive-cleanup",
|
|
3081
|
+
"accessibility-pass",
|
|
3082
|
+
"distinctiveness-pass",
|
|
3083
|
+
"screenshot-critique",
|
|
3084
|
+
"browser-qa",
|
|
3085
|
+
"security",
|
|
3086
|
+
"copy",
|
|
3087
|
+
"ship",
|
|
3088
|
+
"upgrade"
|
|
3089
|
+
];
|
|
3068
3090
|
var REQUIRED_SOURCE_REFERENCES = ["AGENTS.md", ".agent-kit/agent-roster.json", "QUALITY_GATES.md"];
|
|
3069
3091
|
function summary(findings) {
|
|
3070
3092
|
return {
|
|
@@ -3078,7 +3100,7 @@ function report(target, findings) {
|
|
|
3078
3100
|
}
|
|
3079
3101
|
function readJson(path) {
|
|
3080
3102
|
try {
|
|
3081
|
-
return JSON.parse(
|
|
3103
|
+
return JSON.parse(readFileSync10(path, "utf8"));
|
|
3082
3104
|
} catch {
|
|
3083
3105
|
return null;
|
|
3084
3106
|
}
|
|
@@ -3139,11 +3161,11 @@ function validateAntigravityCommands(layout, findings) {
|
|
|
3139
3161
|
level: "fail",
|
|
3140
3162
|
area: "commands",
|
|
3141
3163
|
message: `Missing Antigravity command ${relativePath}.`,
|
|
3142
|
-
remediation: "Restore the full native command set
|
|
3164
|
+
remediation: "Restore the full native command set, including frontend and UI improvement commands."
|
|
3143
3165
|
});
|
|
3144
3166
|
continue;
|
|
3145
3167
|
}
|
|
3146
|
-
const text =
|
|
3168
|
+
const text = readFileSync10(path, "utf8");
|
|
3147
3169
|
addSecretFinding(relativePath, text, findings);
|
|
3148
3170
|
const name = commandField(text, "name");
|
|
3149
3171
|
const description = commandField(text, "description");
|
|
@@ -3232,10 +3254,11 @@ function validateAntigravityPlugin(layout, findings) {
|
|
|
3232
3254
|
for (const entry of [...commands, ...skills]) {
|
|
3233
3255
|
const path = typeof entry.path === "string" ? entry.path : "";
|
|
3234
3256
|
if (!path || !isSafeRelativePath(path)) {
|
|
3257
|
+
const entryName = typeof entry.name === "string" ? entry.name : "unknown";
|
|
3235
3258
|
findings.push({
|
|
3236
3259
|
level: "fail",
|
|
3237
3260
|
area: "manifest",
|
|
3238
|
-
message: `plugin.json has an unsafe or missing relative path for ${
|
|
3261
|
+
message: `plugin.json has an unsafe or missing relative path for ${entryName}.`,
|
|
3239
3262
|
remediation: "Use relative paths that stay inside the plugin/runtime skill bundle."
|
|
3240
3263
|
});
|
|
3241
3264
|
continue;
|
|
@@ -3250,7 +3273,7 @@ function validateAntigravityPlugin(layout, findings) {
|
|
|
3250
3273
|
});
|
|
3251
3274
|
}
|
|
3252
3275
|
}
|
|
3253
|
-
const pluginText =
|
|
3276
|
+
const pluginText = readFileSync10(pluginPath, "utf8");
|
|
3254
3277
|
addSecretFinding("plugin.json", pluginText, findings);
|
|
3255
3278
|
if (Array.isArray(plugin.sourceOfTruth) && plugin.sourceOfTruth.includes("AGENTS.md") && plugin.sourceOfTruth.includes(".agent-kit/agent-roster.json")) {
|
|
3256
3279
|
findings.push({
|
|
@@ -3283,7 +3306,7 @@ function validateRuntimeSkills(cwd, layout, findings) {
|
|
|
3283
3306
|
});
|
|
3284
3307
|
continue;
|
|
3285
3308
|
}
|
|
3286
|
-
const text =
|
|
3309
|
+
const text = readFileSync10(runtimePath, "utf8");
|
|
3287
3310
|
addSecretFinding(`${skillName}/SKILL.md`, text, findings);
|
|
3288
3311
|
if (!/^---\nname: .+\ndescription: .+\n---/m.test(text)) {
|
|
3289
3312
|
findings.push({
|
|
@@ -3332,7 +3355,7 @@ function validateAntigravity(cwd) {
|
|
|
3332
3355
|
}
|
|
3333
3356
|
]);
|
|
3334
3357
|
}
|
|
3335
|
-
const adapterDoc = existsSync12(layout.adapterDocPath) ?
|
|
3358
|
+
const adapterDoc = existsSync12(layout.adapterDocPath) ? readFileSync10(layout.adapterDocPath, "utf8") : "";
|
|
3336
3359
|
if (!adapterDoc) {
|
|
3337
3360
|
findings.push({
|
|
3338
3361
|
level: "fail",
|
|
@@ -3408,7 +3431,7 @@ function validateBasicAdapter(cwd, target) {
|
|
|
3408
3431
|
});
|
|
3409
3432
|
continue;
|
|
3410
3433
|
}
|
|
3411
|
-
const text =
|
|
3434
|
+
const text = readFileSync10(path, "utf8");
|
|
3412
3435
|
addSecretFinding(relativePath, text, findings);
|
|
3413
3436
|
if (!text.includes("AGENTS.md") && !text.includes("MODEL_ROUTING.md")) {
|
|
3414
3437
|
findings.push({
|
|
@@ -3433,7 +3456,7 @@ function validateBasicAdapter(cwd, target) {
|
|
|
3433
3456
|
}
|
|
3434
3457
|
function readAssistantAdaptersDoc(cwd) {
|
|
3435
3458
|
const path = join12(cwd, "ASSISTANT_ADAPTERS.md");
|
|
3436
|
-
return existsSync12(path) ?
|
|
3459
|
+
return existsSync12(path) ? readFileSync10(path, "utf8") : "";
|
|
3437
3460
|
}
|
|
3438
3461
|
function adaptersRowIsActive(doc, toolLabel) {
|
|
3439
3462
|
return assistantAdapterRowIsActive(doc, toolLabel);
|
|
@@ -3451,7 +3474,7 @@ function validateInstalledIdeAdapter(cwd, target) {
|
|
|
3451
3474
|
remediation: "Run agent-kit init or agent-kit init --activate cursor."
|
|
3452
3475
|
});
|
|
3453
3476
|
} else {
|
|
3454
|
-
addSecretFinding(".cursor/rules/cursor-agent-kit.mdc",
|
|
3477
|
+
addSecretFinding(".cursor/rules/cursor-agent-kit.mdc", readFileSync10(rulesPath, "utf8"), findings);
|
|
3455
3478
|
}
|
|
3456
3479
|
const plannerAgent = join12(cwd, ".cursor/agents/planner.md");
|
|
3457
3480
|
if (existsSync12(plannerAgent)) {
|
|
@@ -3554,7 +3577,7 @@ function validatePackage(cwd) {
|
|
|
3554
3577
|
findings.push(...validateAntigravity(cwd).findings);
|
|
3555
3578
|
for (const doc of ["README.md", "DOCS.md", "SPEC.md", "DECISIONS.md", "QUALITY_GATES.md", "TESTING.md", "UPGRADE.md"]) {
|
|
3556
3579
|
const path = join12(cwd, doc);
|
|
3557
|
-
const text = existsSync12(path) ?
|
|
3580
|
+
const text = existsSync12(path) ? readFileSync10(path, "utf8") : "";
|
|
3558
3581
|
const lower = text.toLowerCase();
|
|
3559
3582
|
if (!lower.includes("antigravity") && !lower.includes("runtime command") && !lower.includes("runtime adapter")) {
|
|
3560
3583
|
findings.push({
|
|
@@ -3606,12 +3629,12 @@ function validatePackage(cwd) {
|
|
|
3606
3629
|
}
|
|
3607
3630
|
|
|
3608
3631
|
// src/install/diff.ts
|
|
3609
|
-
import { existsSync as existsSync13, readFileSync as
|
|
3632
|
+
import { existsSync as existsSync13, readFileSync as readFileSync11 } from "fs";
|
|
3610
3633
|
import { join as join13 } from "path";
|
|
3611
3634
|
function statusForTextFile(target, template) {
|
|
3612
3635
|
if (!existsSync13(target)) return "missing";
|
|
3613
|
-
const targetHash = sha256(
|
|
3614
|
-
const templateHash = sha256(
|
|
3636
|
+
const targetHash = sha256(readFileSync11(target, "utf8"));
|
|
3637
|
+
const templateHash = sha256(readFileSync11(template, "utf8"));
|
|
3615
3638
|
return targetHash === templateHash ? "unchanged" : "changed";
|
|
3616
3639
|
}
|
|
3617
3640
|
function diffProject(cwd, stack = "next-supabase") {
|
|
@@ -3680,10 +3703,176 @@ function diffProject(cwd, stack = "next-supabase") {
|
|
|
3680
3703
|
return result;
|
|
3681
3704
|
}
|
|
3682
3705
|
|
|
3706
|
+
// src/install/update.ts
|
|
3707
|
+
import { existsSync as existsSync14, readFileSync as readFileSync12 } from "fs";
|
|
3708
|
+
import { join as join14, relative as relative2 } from "path";
|
|
3709
|
+
function planFileUpdate(cwd, input) {
|
|
3710
|
+
const sourceContent = readFileSync12(input.sourcePath, "utf8");
|
|
3711
|
+
const sourceHash = sha256(sourceContent);
|
|
3712
|
+
const targetPath = resolveInside(cwd, input.target);
|
|
3713
|
+
if (!existsSync14(targetPath)) {
|
|
3714
|
+
return { target: input.target, action: "created", reason: "File is missing locally.", sourceContent };
|
|
3715
|
+
}
|
|
3716
|
+
const localHash = sha256(readFileSync12(targetPath, "utf8"));
|
|
3717
|
+
if (localHash === sourceHash) {
|
|
3718
|
+
return { target: input.target, action: "unchanged", reason: "File already matches the current template.", sourceContent };
|
|
3719
|
+
}
|
|
3720
|
+
if (input.installedHash && localHash === input.installedHash) {
|
|
3721
|
+
return { target: input.target, action: "updated", reason: "File was unmodified since install; applied the newer template.", sourceContent };
|
|
3722
|
+
}
|
|
3723
|
+
if (input.force) {
|
|
3724
|
+
return { target: input.target, action: "overwritten", reason: "Local changes overwritten because --force was used.", sourceContent };
|
|
3725
|
+
}
|
|
3726
|
+
if (input.installedHash && input.installedHash === sourceHash) {
|
|
3727
|
+
return { target: input.target, action: "kept-local", reason: "File is locally customized and the template has not changed.", sourceContent };
|
|
3728
|
+
}
|
|
3729
|
+
return {
|
|
3730
|
+
target: input.target,
|
|
3731
|
+
action: "conflict",
|
|
3732
|
+
reason: "File is locally customized and the bundled template changed; review the conflict copy.",
|
|
3733
|
+
sourceContent
|
|
3734
|
+
};
|
|
3735
|
+
}
|
|
3736
|
+
function writeConflictCopy(cwd, target, content) {
|
|
3737
|
+
const conflictRoot = join14(cwd, ".agent-kit", "conflicts");
|
|
3738
|
+
const safeName = `${Date.now()}-${target.replace(/[^a-zA-Z0-9_.-]/g, "_")}`;
|
|
3739
|
+
const conflictPath = join14(conflictRoot, safeName);
|
|
3740
|
+
writeText(conflictPath, content);
|
|
3741
|
+
return relative2(cwd, conflictPath).replace(/\\/g, "/");
|
|
3742
|
+
}
|
|
3743
|
+
function updateProject(options) {
|
|
3744
|
+
const cwd = options.cwd;
|
|
3745
|
+
const force = Boolean(options.force);
|
|
3746
|
+
const dryRun = Boolean(options.dryRun);
|
|
3747
|
+
const manifest = readManifest(cwd);
|
|
3748
|
+
if (!manifest) {
|
|
3749
|
+
if (dryRun) {
|
|
3750
|
+
throw new Error("No .agent-kit/manifest.json found. Run agent-kit init first (or run update without --dry-run to install).");
|
|
3751
|
+
}
|
|
3752
|
+
const initResult = initProject({ cwd, force });
|
|
3753
|
+
const files2 = [
|
|
3754
|
+
...initResult.copied.map((target) => ({ target, action: "created", reason: "Installed by init fallback." })),
|
|
3755
|
+
...initResult.unchanged.map((target) => ({ target, action: "unchanged", reason: "Already matched the template." })),
|
|
3756
|
+
...initResult.overwritten.map((target) => ({ target, action: "overwritten", reason: "Overwritten by init --force fallback." })),
|
|
3757
|
+
...initResult.conflicts.map((entry) => {
|
|
3758
|
+
const [target, conflictPath] = entry.split(" -> ");
|
|
3759
|
+
return {
|
|
3760
|
+
target: target ?? entry,
|
|
3761
|
+
action: "conflict",
|
|
3762
|
+
reason: "Local file differed from the template during init fallback.",
|
|
3763
|
+
...conflictPath ? { conflictPath } : {}
|
|
3764
|
+
};
|
|
3765
|
+
})
|
|
3766
|
+
];
|
|
3767
|
+
return {
|
|
3768
|
+
dryRun,
|
|
3769
|
+
files: files2,
|
|
3770
|
+
libraryFoldersRefreshed: [...LIBRARY_FOLDERS],
|
|
3771
|
+
manifestPath: ".agent-kit/manifest.json",
|
|
3772
|
+
summary: summarize(files2)
|
|
3773
|
+
};
|
|
3774
|
+
}
|
|
3775
|
+
const packageRoot = findPackageRoot();
|
|
3776
|
+
const stack = manifest.stack ?? "next-supabase";
|
|
3777
|
+
const templateRoot = join14(packageRoot, "templates", stack);
|
|
3778
|
+
if (!existsSync14(templateRoot)) {
|
|
3779
|
+
throw new Error(`Unsupported stack profile in manifest: ${stack}`);
|
|
3780
|
+
}
|
|
3781
|
+
const files = [];
|
|
3782
|
+
const templateHashes = {};
|
|
3783
|
+
const plans = [];
|
|
3784
|
+
for (const doc of ROOT_DOCS) {
|
|
3785
|
+
const sourcePath = join14(templateRoot, doc);
|
|
3786
|
+
templateHashes[doc] = sha256(readFileSync12(sourcePath, "utf8"));
|
|
3787
|
+
plans.push(
|
|
3788
|
+
planFileUpdate(cwd, {
|
|
3789
|
+
target: doc,
|
|
3790
|
+
sourcePath,
|
|
3791
|
+
installedHash: manifest.templateHashes?.[doc],
|
|
3792
|
+
force
|
|
3793
|
+
})
|
|
3794
|
+
);
|
|
3795
|
+
}
|
|
3796
|
+
for (const adapter2 of CURSOR_ADAPTER_FILES) {
|
|
3797
|
+
plans.push(
|
|
3798
|
+
planFileUpdate(cwd, {
|
|
3799
|
+
target: adapter2.target,
|
|
3800
|
+
sourcePath: join14(packageRoot, adapter2.source),
|
|
3801
|
+
installedHash: void 0,
|
|
3802
|
+
force
|
|
3803
|
+
})
|
|
3804
|
+
);
|
|
3805
|
+
}
|
|
3806
|
+
plans.push(
|
|
3807
|
+
planFileUpdate(cwd, {
|
|
3808
|
+
target: DEFAULT_AGENT_ROSTER_TARGET,
|
|
3809
|
+
sourcePath: join14(packageRoot, DEFAULT_AGENT_ROSTER_SOURCE),
|
|
3810
|
+
installedHash: void 0,
|
|
3811
|
+
force
|
|
3812
|
+
}),
|
|
3813
|
+
planFileUpdate(cwd, {
|
|
3814
|
+
target: DEFAULT_MODEL_ROUTING_TARGET,
|
|
3815
|
+
sourcePath: join14(packageRoot, DEFAULT_MODEL_ROUTING_SOURCE),
|
|
3816
|
+
installedHash: void 0,
|
|
3817
|
+
force
|
|
3818
|
+
})
|
|
3819
|
+
);
|
|
3820
|
+
for (const plan of plans) {
|
|
3821
|
+
const { sourceContent, ...fileResult } = plan;
|
|
3822
|
+
if (!dryRun) {
|
|
3823
|
+
if (plan.action === "created" || plan.action === "updated" || plan.action === "overwritten") {
|
|
3824
|
+
writeText(resolveInside(cwd, plan.target), sourceContent);
|
|
3825
|
+
} else if (plan.action === "conflict") {
|
|
3826
|
+
fileResult.conflictPath = writeConflictCopy(cwd, plan.target, sourceContent);
|
|
3827
|
+
}
|
|
3828
|
+
}
|
|
3829
|
+
files.push(fileResult);
|
|
3830
|
+
}
|
|
3831
|
+
if (!dryRun) {
|
|
3832
|
+
ensureDir(join14(cwd, ".agent-kit"));
|
|
3833
|
+
for (const folder of LIBRARY_FOLDERS) {
|
|
3834
|
+
copyDirectory(join14(packageRoot, folder), join14(cwd, ".agent-kit", folder));
|
|
3835
|
+
}
|
|
3836
|
+
const updatedManifest = {
|
|
3837
|
+
packageName: PACKAGE_NAME,
|
|
3838
|
+
packageVersion: PACKAGE_VERSION,
|
|
3839
|
+
stack,
|
|
3840
|
+
installedAt: manifest.installedAt,
|
|
3841
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3842
|
+
docs: [...ROOT_DOCS],
|
|
3843
|
+
libraryFolders: [...LIBRARY_FOLDERS],
|
|
3844
|
+
agentRoster: DEFAULT_AGENT_ROSTER_TARGET,
|
|
3845
|
+
modelRouting: DEFAULT_MODEL_ROUTING_TARGET,
|
|
3846
|
+
templateHashes
|
|
3847
|
+
};
|
|
3848
|
+
writeText(join14(cwd, ".agent-kit", "manifest.json"), `${JSON.stringify(updatedManifest, null, 2)}
|
|
3849
|
+
`);
|
|
3850
|
+
}
|
|
3851
|
+
return {
|
|
3852
|
+
dryRun,
|
|
3853
|
+
files,
|
|
3854
|
+
libraryFoldersRefreshed: [...LIBRARY_FOLDERS],
|
|
3855
|
+
manifestPath: ".agent-kit/manifest.json",
|
|
3856
|
+
summary: summarize(files)
|
|
3857
|
+
};
|
|
3858
|
+
}
|
|
3859
|
+
function summarize(files) {
|
|
3860
|
+
const summary2 = {
|
|
3861
|
+
created: 0,
|
|
3862
|
+
updated: 0,
|
|
3863
|
+
unchanged: 0,
|
|
3864
|
+
"kept-local": 0,
|
|
3865
|
+
conflict: 0,
|
|
3866
|
+
overwritten: 0
|
|
3867
|
+
};
|
|
3868
|
+
for (const file of files) summary2[file.action] += 1;
|
|
3869
|
+
return summary2;
|
|
3870
|
+
}
|
|
3871
|
+
|
|
3683
3872
|
// src/research/discover.ts
|
|
3684
3873
|
import { Octokit } from "@octokit/rest";
|
|
3685
|
-
import { readFileSync as
|
|
3686
|
-
import { join as
|
|
3874
|
+
import { readFileSync as readFileSync13 } from "fs";
|
|
3875
|
+
import { join as join15 } from "path";
|
|
3687
3876
|
|
|
3688
3877
|
// src/research/config.ts
|
|
3689
3878
|
import { z as z2 } from "zod";
|
|
@@ -3708,8 +3897,8 @@ var researchConfigSchema = z2.object({
|
|
|
3708
3897
|
// src/research/discover.ts
|
|
3709
3898
|
async function discoverRepos(options) {
|
|
3710
3899
|
const packageRoot = findPackageRoot();
|
|
3711
|
-
const configPath =
|
|
3712
|
-
const config = researchConfigSchema.parse(JSON.parse(
|
|
3900
|
+
const configPath = join15(packageRoot, "research", "scan-config.json");
|
|
3901
|
+
const config = researchConfigSchema.parse(JSON.parse(readFileSync13(configPath, "utf8")));
|
|
3713
3902
|
const token = options.token ?? process.env.GITHUB_TOKEN;
|
|
3714
3903
|
if (!token) {
|
|
3715
3904
|
throw new Error("GITHUB_TOKEN is required for GitHub API research discovery.");
|
|
@@ -3770,20 +3959,20 @@ async function discoverRepos(options) {
|
|
|
3770
3959
|
}
|
|
3771
3960
|
}
|
|
3772
3961
|
const candidates = [...deduped.values()].slice(0, maxRepos);
|
|
3773
|
-
const output = options.output ??
|
|
3962
|
+
const output = options.output ?? join15(options.cwd, "research", "repo-candidates.json");
|
|
3774
3963
|
writeText(output, `${JSON.stringify(candidates, null, 2)}
|
|
3775
3964
|
`);
|
|
3776
3965
|
return candidates;
|
|
3777
3966
|
}
|
|
3778
3967
|
|
|
3779
3968
|
// src/research/scan.ts
|
|
3780
|
-
import { existsSync as existsSync16, mkdirSync as mkdirSync2, readFileSync as
|
|
3781
|
-
import { join as
|
|
3969
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync2, readFileSync as readFileSync15, rmSync } from "fs";
|
|
3970
|
+
import { join as join17 } from "path";
|
|
3782
3971
|
import { simpleGit } from "simple-git";
|
|
3783
3972
|
|
|
3784
3973
|
// src/research/analyze.ts
|
|
3785
|
-
import { existsSync as existsSync15, readFileSync as
|
|
3786
|
-
import { join as
|
|
3974
|
+
import { existsSync as existsSync15, readFileSync as readFileSync14 } from "fs";
|
|
3975
|
+
import { join as join16 } from "path";
|
|
3787
3976
|
function normalizeRelativePath(file) {
|
|
3788
3977
|
return file.replace(/\\/g, "/");
|
|
3789
3978
|
}
|
|
@@ -3791,8 +3980,8 @@ function hasFile(files, matcher) {
|
|
|
3791
3980
|
return files.some((file) => matcher.test(normalizeRelativePath(file)));
|
|
3792
3981
|
}
|
|
3793
3982
|
function fileText(root, file) {
|
|
3794
|
-
const path =
|
|
3795
|
-
return existsSync15(path) ?
|
|
3983
|
+
const path = join16(root, file);
|
|
3984
|
+
return existsSync15(path) ? readFileSync14(path, "utf8") : "";
|
|
3796
3985
|
}
|
|
3797
3986
|
function textIncludes(root, files, matcher, terms) {
|
|
3798
3987
|
const lowerTerms = terms.map((term) => term.toLowerCase());
|
|
@@ -3923,24 +4112,24 @@ ${finding.impactOnKit.map((item) => `- ${item}`).join("\n")}
|
|
|
3923
4112
|
`;
|
|
3924
4113
|
}
|
|
3925
4114
|
async function scanRepos(options) {
|
|
3926
|
-
const candidatesPath = options.candidatesPath ??
|
|
4115
|
+
const candidatesPath = options.candidatesPath ?? join17(options.cwd, "research", "repo-candidates.json");
|
|
3927
4116
|
if (!existsSync16(candidatesPath)) {
|
|
3928
4117
|
throw new Error(`Candidates file not found: ${candidatesPath}`);
|
|
3929
4118
|
}
|
|
3930
|
-
const candidates = JSON.parse(
|
|
3931
|
-
const workdir = options.workdir ??
|
|
4119
|
+
const candidates = JSON.parse(readFileSync15(candidatesPath, "utf8"));
|
|
4120
|
+
const workdir = options.workdir ?? join17(options.cwd, "research", "workdir");
|
|
3932
4121
|
mkdirSync2(workdir, { recursive: true });
|
|
3933
|
-
mkdirSync2(
|
|
4122
|
+
mkdirSync2(join17(options.cwd, "research", "findings"), { recursive: true });
|
|
3934
4123
|
const findings = [];
|
|
3935
4124
|
const git = simpleGit();
|
|
3936
4125
|
for (const candidate of candidates) {
|
|
3937
4126
|
const repoSlug = candidate.fullName.replace("/", "__");
|
|
3938
|
-
const repoPath =
|
|
4127
|
+
const repoPath = join17(workdir, repoSlug);
|
|
3939
4128
|
if (existsSync16(repoPath)) rmSync(repoPath, { recursive: true, force: true });
|
|
3940
4129
|
await git.raw(["clone", "--depth", "1", candidate.htmlUrl, repoPath]);
|
|
3941
4130
|
const finding = analyzeRepository(candidate, repoPath);
|
|
3942
4131
|
findings.push(finding);
|
|
3943
|
-
writeText(
|
|
4132
|
+
writeText(join17(options.cwd, "research", "findings", `${repoSlug}.md`), findingToMarkdown(finding));
|
|
3944
4133
|
if (!options.keepClones) {
|
|
3945
4134
|
rmSync(repoPath, { recursive: true, force: true });
|
|
3946
4135
|
}
|
|
@@ -3949,8 +4138,8 @@ async function scanRepos(options) {
|
|
|
3949
4138
|
}
|
|
3950
4139
|
|
|
3951
4140
|
// src/research/summarize.ts
|
|
3952
|
-
import { existsSync as existsSync17, readFileSync as
|
|
3953
|
-
import { join as
|
|
4141
|
+
import { existsSync as existsSync17, readFileSync as readFileSync16, readdirSync as readdirSync3 } from "fs";
|
|
4142
|
+
import { join as join18 } from "path";
|
|
3954
4143
|
var SUMMARY_TARGETS = {
|
|
3955
4144
|
"nextjs-patterns": {
|
|
3956
4145
|
title: "Next.js Patterns",
|
|
@@ -4012,7 +4201,7 @@ function sectionBullets(text, start, end) {
|
|
|
4012
4201
|
const afterStart = text.slice(startIndex + start.length);
|
|
4013
4202
|
const endIndex = afterStart.indexOf(end);
|
|
4014
4203
|
const section = endIndex === -1 ? afterStart : afterStart.slice(0, endIndex);
|
|
4015
|
-
return section.split("\n").map((
|
|
4204
|
+
return section.split("\n").map((line2) => line2.trim()).filter((line2) => line2.startsWith("- ") && !line2.includes("None detected")).map((line2) => line2.slice(2));
|
|
4016
4205
|
}
|
|
4017
4206
|
function parseFinding(file, text) {
|
|
4018
4207
|
const fullName = text.match(/^# Repo Finding: (.+)$/m)?.[1];
|
|
@@ -4053,12 +4242,12 @@ function renderRepoList(findings, scoreKeys) {
|
|
|
4053
4242
|
return findings.slice().sort((a, b) => scoreFor(b, scoreKeys) - scoreFor(a, scoreKeys) || b.totalScore - a.totalScore || b.stars - a.stars).slice(0, 12).map((finding) => `- ${finding.fullName} (${finding.category}) - focus score ${scoreFor(finding, scoreKeys)}, total ${finding.totalScore}/${maxTotalScore}`).join("\n");
|
|
4054
4243
|
}
|
|
4055
4244
|
function summarizeFindings(cwd) {
|
|
4056
|
-
const findingsDir =
|
|
4245
|
+
const findingsDir = join18(cwd, "research", "findings");
|
|
4057
4246
|
if (!existsSync17(findingsDir)) {
|
|
4058
4247
|
throw new Error("No research/findings directory exists. Run agent-kit research scan first.");
|
|
4059
4248
|
}
|
|
4060
4249
|
const findingFiles = readdirSync3(findingsDir).filter((file) => file.endsWith(".md"));
|
|
4061
|
-
const findings = findingFiles.map((file) => parseFinding(file,
|
|
4250
|
+
const findings = findingFiles.map((file) => parseFinding(file, readFileSync16(join18(findingsDir, file), "utf8"))).filter((finding) => finding !== null);
|
|
4062
4251
|
const categoryCounts = countBy(findings.map((finding) => finding.category));
|
|
4063
4252
|
const outputs = [];
|
|
4064
4253
|
const overview = `# Research Scan Overview
|
|
@@ -4077,13 +4266,13 @@ ${countBy(findings.flatMap((finding) => finding.strongPractices)).slice(0, 12).m
|
|
|
4077
4266
|
## Most Repeated Gaps
|
|
4078
4267
|
${countBy(findings.flatMap((finding) => finding.weakPractices)).slice(0, 12).map(([practice, count]) => `- ${practice} (${count})`).join("\n")}
|
|
4079
4268
|
`;
|
|
4080
|
-
const overviewPath =
|
|
4269
|
+
const overviewPath = join18(cwd, "research", "summaries", "scan-overview.md");
|
|
4081
4270
|
writeText(overviewPath, overview);
|
|
4082
4271
|
outputs.push(overviewPath);
|
|
4083
4272
|
for (const [target, config] of Object.entries(SUMMARY_TARGETS)) {
|
|
4084
4273
|
const categories = config.categories;
|
|
4085
4274
|
const scopedFindings = findings.filter((finding) => categories.includes(finding.category));
|
|
4086
|
-
const path =
|
|
4275
|
+
const path = join18(cwd, "research", "summaries", `${target}.md`);
|
|
4087
4276
|
const summary2 = `# ${config.title}
|
|
4088
4277
|
|
|
4089
4278
|
Generated from ${scopedFindings.length} relevant repository findings.
|
|
@@ -4124,12 +4313,19 @@ Review the generated research summaries, then convert repeated best practices in
|
|
|
4124
4313
|
|
|
4125
4314
|
Do not copy source code from scanned repositories. Adopt only generalized practices with clear rationale.
|
|
4126
4315
|
`;
|
|
4127
|
-
const path =
|
|
4316
|
+
const path = join18(cwd, "research", "proposed-updates.md");
|
|
4128
4317
|
writeText(path, output);
|
|
4129
4318
|
return path;
|
|
4130
4319
|
}
|
|
4131
4320
|
|
|
4132
4321
|
// src/studio/corrections.ts
|
|
4322
|
+
var VALID_CORRECTION_SCOPES = ["session", "project", "agent", "upstream-proposal"];
|
|
4323
|
+
function parseCorrectionScope(scope) {
|
|
4324
|
+
if (typeof scope === "string" && VALID_CORRECTION_SCOPES.includes(scope)) {
|
|
4325
|
+
return scope;
|
|
4326
|
+
}
|
|
4327
|
+
throw new Error(`Invalid correction scope: expected one of ${VALID_CORRECTION_SCOPES.join(", ")}`);
|
|
4328
|
+
}
|
|
4133
4329
|
function fileForScope(scope) {
|
|
4134
4330
|
if (scope === "agent") return AGENT_RULES_JSON;
|
|
4135
4331
|
if (scope === "upstream-proposal") return UPSTREAM_PROPOSALS_JSON;
|
|
@@ -4153,14 +4349,15 @@ function ensureCorrectionFiles(cwd) {
|
|
|
4153
4349
|
}
|
|
4154
4350
|
}
|
|
4155
4351
|
function addCorrection(cwd, options) {
|
|
4352
|
+
const scope = parseCorrectionScope(options.scope);
|
|
4156
4353
|
ensureCorrectionFiles(cwd);
|
|
4157
|
-
const targetPath = fileForScope(
|
|
4354
|
+
const targetPath = fileForScope(scope);
|
|
4158
4355
|
const rules = readCorrectionRules(cwd, targetPath);
|
|
4159
4356
|
const id = options.id ?? safeSlug(options.text).slice(0, 48);
|
|
4160
4357
|
const rule = {
|
|
4161
4358
|
id,
|
|
4162
|
-
scope
|
|
4163
|
-
status:
|
|
4359
|
+
scope,
|
|
4360
|
+
status: scope === "upstream-proposal" ? "proposed" : "active",
|
|
4164
4361
|
text: redactSensitive(options.text),
|
|
4165
4362
|
...options.agentId ? { agentId: options.agentId, appliesToAgents: [options.agentId] } : {},
|
|
4166
4363
|
...options.sourceSessionId ? { sourceSessionId: options.sourceSessionId } : {},
|
|
@@ -4233,8 +4430,8 @@ function proposeCorrectionUpstream(cwd, id) {
|
|
|
4233
4430
|
}
|
|
4234
4431
|
|
|
4235
4432
|
// src/studio/session.ts
|
|
4236
|
-
import { existsSync as existsSync18, readFileSync as
|
|
4237
|
-
import { join as
|
|
4433
|
+
import { existsSync as existsSync18, readFileSync as readFileSync17, readdirSync as readdirSync4, statSync as statSync2 } from "fs";
|
|
4434
|
+
import { join as join19 } from "path";
|
|
4238
4435
|
function sessionDir(sessionId) {
|
|
4239
4436
|
return `${COUNCIL_SESSIONS_DIR}/${safeSlug(sessionId)}`;
|
|
4240
4437
|
}
|
|
@@ -4291,9 +4488,9 @@ function startSession(cwd, options) {
|
|
|
4291
4488
|
return { sessionId, sessionPath: sessionDir(sessionId) };
|
|
4292
4489
|
}
|
|
4293
4490
|
function listSessions(cwd) {
|
|
4294
|
-
const root =
|
|
4491
|
+
const root = join19(cwd, COUNCIL_SESSIONS_DIR);
|
|
4295
4492
|
if (!existsSync18(root)) return [];
|
|
4296
|
-
return readdirSync4(root).filter((entry) => entry !== "active").map((entry) =>
|
|
4493
|
+
return readdirSync4(root).filter((entry) => entry !== "active").map((entry) => join19(root, entry, "session.json")).filter((path) => existsSync18(path) && statSync2(path).isFile()).map((path) => StudioSessionContract.parse(JSON.parse(readFileSync17(path, "utf8")))).sort((a, b) => a.createdAt.localeCompare(b.createdAt));
|
|
4297
4494
|
}
|
|
4298
4495
|
function getActiveSessionId(cwd) {
|
|
4299
4496
|
const active = readTextFile(cwd, ACTIVE_SESSION_FILE)?.trim();
|
|
@@ -4550,8 +4747,8 @@ function renderSessionTranscript(session2, events) {
|
|
|
4550
4747
|
}
|
|
4551
4748
|
const sections = [...byAgent.entries()].map(([agentId, agentEvents]) => {
|
|
4552
4749
|
const rows = agentEvents.map((event) => {
|
|
4553
|
-
const
|
|
4554
|
-
return `- ${event.createdAt} \`${event.type}\`: ${escapeMarkdownText(
|
|
4750
|
+
const detail2 = event.text ?? event.decision ?? event.command ?? event.artifactPath ?? (event.outputName ? `${event.outputName}: ${event.outputStatus ?? ""}` : void 0) ?? event.status ?? "";
|
|
4751
|
+
return `- ${event.createdAt} \`${event.type}\`: ${escapeMarkdownText(detail2)}`;
|
|
4555
4752
|
});
|
|
4556
4753
|
return `## ${escapeMarkdownText(agentId)}
|
|
4557
4754
|
|
|
@@ -4714,7 +4911,9 @@ function renderCorrections(data) {
|
|
|
4714
4911
|
return `<table>
|
|
4715
4912
|
<thead><tr><th>Scope</th><th>Agent</th><th>Correction</th></tr></thead>
|
|
4716
4913
|
<tbody>
|
|
4717
|
-
${rules.map(
|
|
4914
|
+
${rules.map(
|
|
4915
|
+
(rule) => `<tr><td>${escapeHtml(rule.scope)}</td><td>${escapeHtml(rule.agentId ?? rule.appliesToAgents?.join(", ") ?? "all")}</td><td>${escapeHtml(rule.text)}</td></tr>`
|
|
4916
|
+
).join("\n")}
|
|
4718
4917
|
</tbody>
|
|
4719
4918
|
</table>`;
|
|
4720
4919
|
}
|
|
@@ -4763,13 +4962,16 @@ function renderAgentStreams(item) {
|
|
|
4763
4962
|
const agent = event.agentId ?? event.fromAgentId ?? "session";
|
|
4764
4963
|
byAgent.set(agent, [...byAgent.get(agent) ?? [], event]);
|
|
4765
4964
|
}
|
|
4766
|
-
return [...byAgent.entries()].map(
|
|
4965
|
+
return [...byAgent.entries()].map(
|
|
4966
|
+
([agent, events]) => `<details class="agent-stream"><summary>${escapeHtml(agent)} (${events.length})</summary><div class="stream-body">${renderEventList(events)}</div></details>`
|
|
4967
|
+
).join("\n");
|
|
4767
4968
|
}
|
|
4768
4969
|
function renderEventList(events) {
|
|
4769
4970
|
return `<ol class="event-list">${events.map((event) => `<li><time>${escapeHtml(event.createdAt)}</time> <code>${escapeHtml(event.type)}</code>: ${escapeHtml(eventDetail(event))}</li>`).join("\n")}</ol>`;
|
|
4770
4971
|
}
|
|
4771
4972
|
function eventDetail(event) {
|
|
4772
|
-
if (event.type === "handoff")
|
|
4973
|
+
if (event.type === "handoff")
|
|
4974
|
+
return `${event.fromAgentId ?? "unknown"} -> ${event.toAgentId ?? "unknown"}: ${event.decision ?? ""} Risk: ${event.risk ?? ""}`;
|
|
4773
4975
|
if (event.type === "required_output_updated") return `${event.outputName ?? "output"}: ${event.outputStatus ?? "unknown"}`;
|
|
4774
4976
|
return event.text ?? event.decision ?? event.command ?? event.artifactPath ?? event.status ?? "";
|
|
4775
4977
|
}
|
|
@@ -4840,28 +5042,6 @@ function openBrowser(url) {
|
|
|
4840
5042
|
|
|
4841
5043
|
// src/studio/setup-init.ts
|
|
4842
5044
|
import { createInterface } from "readline";
|
|
4843
|
-
function formatInitSummary(result) {
|
|
4844
|
-
const lines = [
|
|
4845
|
-
`${PACKAGE_NAME} v${PACKAGE_VERSION} installed.`,
|
|
4846
|
-
"",
|
|
4847
|
-
`Created/updated: ${result.copied.length} file(s)`,
|
|
4848
|
-
`Unchanged: ${result.unchanged.length} file(s)`
|
|
4849
|
-
];
|
|
4850
|
-
if (result.conflicts.length > 0) {
|
|
4851
|
-
lines.push(`Conflicts to review: ${result.conflicts.length} \u2192 see .agent-kit/conflicts/`);
|
|
4852
|
-
}
|
|
4853
|
-
if (result.contextPath) {
|
|
4854
|
-
lines.push(`Project context: ${result.contextPath}`);
|
|
4855
|
-
}
|
|
4856
|
-
if (result.activation?.activated.length) {
|
|
4857
|
-
lines.push(`IDE activation: ${result.activation.activated.join(", ")}`);
|
|
4858
|
-
}
|
|
4859
|
-
if ([...result.copied, ...result.unchanged].some((path) => path.includes("agent-kit-audit.yml"))) {
|
|
4860
|
-
lines.push("CI template: .github/workflows/agent-kit-audit.yml");
|
|
4861
|
-
}
|
|
4862
|
-
lines.push("", "Next: teach agents about your project with the setup wizard (~5 min).", " agent-kit setup --open");
|
|
4863
|
-
return lines.join("\n");
|
|
4864
|
-
}
|
|
4865
5045
|
async function promptStartSetup(defaultYes = true) {
|
|
4866
5046
|
if (!process.stdin.isTTY || !process.stdout.isTTY) return false;
|
|
4867
5047
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
@@ -4883,7 +5063,7 @@ import { createServer } from "http";
|
|
|
4883
5063
|
// src/studio/setup-form.ts
|
|
4884
5064
|
var RECOMMENDED_SUPABASE_AUTH = "Supabase Auth with server-set session cookies via @supabase/ssr. Authorization is enforced in Postgres RLS for private tables, not only in UI code. Service-role keys stay server-only. Document how privileged admin or operator roles are granted and verified before changing auth boundaries.";
|
|
4885
5065
|
function splitLines(value) {
|
|
4886
|
-
return value.split(/\r?\n/).map((
|
|
5066
|
+
return value.split(/\r?\n/).map((line2) => line2.trim()).filter(Boolean);
|
|
4887
5067
|
}
|
|
4888
5068
|
function uniqueStrings(values) {
|
|
4889
5069
|
return [...new Set(values.filter(Boolean))];
|
|
@@ -4937,10 +5117,7 @@ function applySetupFormAnswers(cwd, payload) {
|
|
|
4937
5117
|
qualityTarget: payload.qualityTarget,
|
|
4938
5118
|
owners,
|
|
4939
5119
|
lastReviewedAt: nowIso(),
|
|
4940
|
-
evidence: uniqueEvidence2([
|
|
4941
|
-
...base.evidence,
|
|
4942
|
-
{ source: "agent-kit setup wizard", note: "Project context updated through the local web setup wizard." }
|
|
4943
|
-
])
|
|
5120
|
+
evidence: uniqueEvidence2([...base.evidence, { source: "agent-kit setup wizard", note: "Project context updated through the local web setup wizard." }])
|
|
4944
5121
|
};
|
|
4945
5122
|
return writeProjectContext(cwd, updated);
|
|
4946
5123
|
}
|
|
@@ -4991,8 +5168,8 @@ function parseSetupFormPayload(raw) {
|
|
|
4991
5168
|
}
|
|
4992
5169
|
|
|
4993
5170
|
// src/studio/wizard/checklist.ts
|
|
4994
|
-
import { existsSync as existsSync19, readFileSync as
|
|
4995
|
-
import { join as
|
|
5171
|
+
import { existsSync as existsSync19, readFileSync as readFileSync18 } from "fs";
|
|
5172
|
+
import { join as join20 } from "path";
|
|
4996
5173
|
var IDE_PATHS = {
|
|
4997
5174
|
cursor: ".cursor/agents/planner.md",
|
|
4998
5175
|
copilot: ".github/copilot-instructions.md",
|
|
@@ -5013,12 +5190,12 @@ function saveIdeChecklist(cwd, ideSurface) {
|
|
|
5013
5190
|
function detectIdeRulePresent(cwd, ideSurface) {
|
|
5014
5191
|
const rel = IDE_PATHS[ideSurface];
|
|
5015
5192
|
if (ideSurface === "cursor") {
|
|
5016
|
-
return existsSync19(
|
|
5193
|
+
return existsSync19(join20(cwd, rel)) || existsSync19(join20(cwd, ".cursor/rules/cursor-agent-kit.mdc"));
|
|
5017
5194
|
}
|
|
5018
5195
|
if (rel.endsWith("/")) {
|
|
5019
|
-
return existsSync19(
|
|
5196
|
+
return existsSync19(join20(cwd, rel));
|
|
5020
5197
|
}
|
|
5021
|
-
return existsSync19(
|
|
5198
|
+
return existsSync19(join20(cwd, rel));
|
|
5022
5199
|
}
|
|
5023
5200
|
var VISUAL_QA_MARKER = "## Visual QA Tier";
|
|
5024
5201
|
var VISUAL_QA_BLOCKS = {
|
|
@@ -5046,11 +5223,11 @@ This project uses the **Mature** visual QA tier.
|
|
|
5046
5223
|
};
|
|
5047
5224
|
function writeVisualQaTier(cwd, tier) {
|
|
5048
5225
|
const path = "TESTING.md";
|
|
5049
|
-
const fullPath =
|
|
5226
|
+
const fullPath = join20(cwd, path);
|
|
5050
5227
|
if (!existsSync19(fullPath)) {
|
|
5051
5228
|
return { updated: false, path, reason: "TESTING.md not found in project root." };
|
|
5052
5229
|
}
|
|
5053
|
-
const current =
|
|
5230
|
+
const current = readFileSync18(fullPath, "utf8");
|
|
5054
5231
|
if (current.includes(VISUAL_QA_MARKER)) {
|
|
5055
5232
|
return {
|
|
5056
5233
|
updated: false,
|
|
@@ -5226,8 +5403,8 @@ function extractSetupFormFromWizardForm(form) {
|
|
|
5226
5403
|
}
|
|
5227
5404
|
|
|
5228
5405
|
// src/studio/wizard/drafts.ts
|
|
5229
|
-
import { existsSync as existsSync20, readFileSync as
|
|
5230
|
-
import { join as
|
|
5406
|
+
import { existsSync as existsSync20, readFileSync as readFileSync19 } from "fs";
|
|
5407
|
+
import { join as join21 } from "path";
|
|
5231
5408
|
var DESIGN_DRAFT_JSON = ".agent-kit/onboarding/design-draft.json";
|
|
5232
5409
|
var MESSAGING_DRAFT_JSON = ".agent-kit/onboarding/messaging-draft.json";
|
|
5233
5410
|
function loadDesignDraft(cwd) {
|
|
@@ -5272,11 +5449,11 @@ function previewMessagingMarkdown(draft) {
|
|
|
5272
5449
|
`;
|
|
5273
5450
|
}
|
|
5274
5451
|
function appendSectionToDoc(cwd, doc, sectionMarkdown) {
|
|
5275
|
-
const fullPath =
|
|
5452
|
+
const fullPath = join21(cwd, doc);
|
|
5276
5453
|
if (!existsSync20(fullPath)) {
|
|
5277
5454
|
return { target: doc, action: "missing" };
|
|
5278
5455
|
}
|
|
5279
|
-
const current =
|
|
5456
|
+
const current = readFileSync19(fullPath, "utf8");
|
|
5280
5457
|
if (current.includes("(wizard draft)")) {
|
|
5281
5458
|
return { target: doc, action: "conflict", conflictPath: `.agent-kit/conflicts/wizard-${doc}` };
|
|
5282
5459
|
}
|
|
@@ -5315,8 +5492,8 @@ function applyDrafts(cwd) {
|
|
|
5315
5492
|
}
|
|
5316
5493
|
|
|
5317
5494
|
// src/studio/office/render.ts
|
|
5318
|
-
import { readFileSync as
|
|
5319
|
-
import { join as
|
|
5495
|
+
import { readFileSync as readFileSync20 } from "fs";
|
|
5496
|
+
import { join as join22 } from "path";
|
|
5320
5497
|
|
|
5321
5498
|
// src/studio/office/map.ts
|
|
5322
5499
|
var MAP_WIDTH = 28;
|
|
@@ -5434,28 +5611,16 @@ function buildOfficeStations(agents) {
|
|
|
5434
5611
|
}
|
|
5435
5612
|
|
|
5436
5613
|
// src/studio/office/render.ts
|
|
5437
|
-
var PRODUCT_CATEGORIES = [
|
|
5438
|
-
"content-app",
|
|
5439
|
-
"saas",
|
|
5440
|
-
"admin",
|
|
5441
|
-
"marketplace",
|
|
5442
|
-
"tool",
|
|
5443
|
-
"ecommerce",
|
|
5444
|
-
"portfolio",
|
|
5445
|
-
"education",
|
|
5446
|
-
"community",
|
|
5447
|
-
"ai-workflow",
|
|
5448
|
-
"other"
|
|
5449
|
-
];
|
|
5614
|
+
var PRODUCT_CATEGORIES = ["content-app", "saas", "admin", "marketplace", "tool", "ecommerce", "portfolio", "education", "community", "ai-workflow", "other"];
|
|
5450
5615
|
var TENANT_MODELS = ["single-user", "team", "tenant", "marketplace", "admin", "public-content"];
|
|
5451
5616
|
function readOfficeAsset(name) {
|
|
5452
5617
|
const root = findPackageRoot();
|
|
5453
|
-
const distPath =
|
|
5454
|
-
const srcPath =
|
|
5618
|
+
const distPath = join22(root, "dist", "studio", "office", "assets", name);
|
|
5619
|
+
const srcPath = join22(root, "src", "studio", "office", "assets", name);
|
|
5455
5620
|
try {
|
|
5456
|
-
return
|
|
5621
|
+
return readFileSync20(distPath, "utf8");
|
|
5457
5622
|
} catch {
|
|
5458
|
-
return
|
|
5623
|
+
return readFileSync20(srcPath, "utf8");
|
|
5459
5624
|
}
|
|
5460
5625
|
}
|
|
5461
5626
|
function buildOfficeBootConfig(cwd, viewModel) {
|
|
@@ -5481,24 +5646,22 @@ function renderSetupOfficeHtml(boot) {
|
|
|
5481
5646
|
function renderOfficeHtml(boot, mode) {
|
|
5482
5647
|
const css = readOfficeAsset("office.css");
|
|
5483
5648
|
const js = readOfficeAsset("office.js");
|
|
5484
|
-
const bootJson = JSON.stringify(
|
|
5485
|
-
{
|
|
5486
|
-
|
|
5487
|
-
|
|
5488
|
-
|
|
5489
|
-
|
|
5490
|
-
|
|
5491
|
-
|
|
5492
|
-
|
|
5493
|
-
|
|
5494
|
-
|
|
5495
|
-
|
|
5496
|
-
|
|
5497
|
-
|
|
5498
|
-
|
|
5499
|
-
|
|
5500
|
-
}
|
|
5501
|
-
).replace(/</g, "\\u003c");
|
|
5649
|
+
const bootJson = JSON.stringify({
|
|
5650
|
+
...boot ?? {
|
|
5651
|
+
mapWidth: MAP_WIDTH,
|
|
5652
|
+
mapHeight: MAP_HEIGHT,
|
|
5653
|
+
tileSize: TILE_SIZE,
|
|
5654
|
+
scale: CANVAS_SCALE,
|
|
5655
|
+
stations: [],
|
|
5656
|
+
agents: [],
|
|
5657
|
+
categories: PRODUCT_CATEGORIES,
|
|
5658
|
+
tenantModels: TENANT_MODELS,
|
|
5659
|
+
ideSurfaces: [],
|
|
5660
|
+
hasSupabase: false,
|
|
5661
|
+
stackSignals: []
|
|
5662
|
+
},
|
|
5663
|
+
mode
|
|
5664
|
+
}).replace(/</g, "\\u003c");
|
|
5502
5665
|
const isStudio = mode === "studio";
|
|
5503
5666
|
const title = isStudio ? "Agent Kit \u2014 Live Studio" : "Agent Kit \u2014 Setup Office";
|
|
5504
5667
|
const dataView = isStudio ? "studio-v1" : "office-v1";
|
|
@@ -5518,14 +5681,21 @@ function renderOfficeHtml(boot, mode) {
|
|
|
5518
5681
|
</div>
|
|
5519
5682
|
<div class="header-actions">
|
|
5520
5683
|
<span class="progress-pill" id="progress-pill">${isStudio ? "Live" : "0% ready"}</span>
|
|
5684
|
+
${isStudio ? "" : '<span class="level-pill" id="level-pill" aria-live="polite">L3 \u2192 L5</span>'}
|
|
5521
5685
|
${isStudio ? '<span class="session-pill" id="session-pill">No session</span>' : '<a class="btn secondary" href="/wizard">Form view</a>'}
|
|
5522
5686
|
${isStudio ? "" : '<button type="button" class="btn primary" id="review-btn">Review & save</button>'}
|
|
5523
5687
|
</div>
|
|
5524
5688
|
</header>
|
|
5689
|
+
${isStudio ? "" : '<div class="iceberg-strip" id="iceberg-strip" aria-label="Agentic engineering levels L3 through L8"></div>'}
|
|
5525
5690
|
<main class="office-main${isStudio ? " studio-layout" : ""}">
|
|
5526
5691
|
<aside class="station-list${isStudio ? " hidden" : ""}" aria-label="Setup stations">
|
|
5527
5692
|
<h2>Stations</h2>
|
|
5528
5693
|
<p class="hint">Keyboard-friendly list \u2014 same actions as the office floor.</p>
|
|
5694
|
+
<div class="climb-panel" id="climb-panel" hidden>
|
|
5695
|
+
<h3>Climb checklist</h3>
|
|
5696
|
+
<ol id="climb-list"></ol>
|
|
5697
|
+
<button type="button" class="btn secondary climb-refresh" id="climb-refresh">Refresh level</button>
|
|
5698
|
+
</div>
|
|
5529
5699
|
<ul id="station-list"></ul>
|
|
5530
5700
|
</aside>
|
|
5531
5701
|
<div class="canvas-wrap">
|
|
@@ -5622,30 +5792,18 @@ function allAgentBriefsComplete(form, agentIds) {
|
|
|
5622
5792
|
}
|
|
5623
5793
|
|
|
5624
5794
|
// src/studio/wizard/render.ts
|
|
5625
|
-
import { readFileSync as
|
|
5626
|
-
import { join as
|
|
5627
|
-
var PRODUCT_CATEGORIES2 = [
|
|
5628
|
-
"content-app",
|
|
5629
|
-
"saas",
|
|
5630
|
-
"admin",
|
|
5631
|
-
"marketplace",
|
|
5632
|
-
"tool",
|
|
5633
|
-
"ecommerce",
|
|
5634
|
-
"portfolio",
|
|
5635
|
-
"education",
|
|
5636
|
-
"community",
|
|
5637
|
-
"ai-workflow",
|
|
5638
|
-
"other"
|
|
5639
|
-
];
|
|
5795
|
+
import { readFileSync as readFileSync21 } from "fs";
|
|
5796
|
+
import { join as join23 } from "path";
|
|
5797
|
+
var PRODUCT_CATEGORIES2 = ["content-app", "saas", "admin", "marketplace", "tool", "ecommerce", "portfolio", "education", "community", "ai-workflow", "other"];
|
|
5640
5798
|
var TENANT_MODELS2 = ["single-user", "team", "tenant", "marketplace", "admin", "public-content"];
|
|
5641
5799
|
function readWizardAsset(name) {
|
|
5642
5800
|
const root = findPackageRoot();
|
|
5643
|
-
const distPath =
|
|
5644
|
-
const srcPath =
|
|
5801
|
+
const distPath = join23(root, "dist", "studio", "wizard", "assets", name);
|
|
5802
|
+
const srcPath = join23(root, "src", "studio", "wizard", "assets", name);
|
|
5645
5803
|
try {
|
|
5646
|
-
return
|
|
5804
|
+
return readFileSync21(distPath, "utf8");
|
|
5647
5805
|
} catch {
|
|
5648
|
-
return
|
|
5806
|
+
return readFileSync21(srcPath, "utf8");
|
|
5649
5807
|
}
|
|
5650
5808
|
}
|
|
5651
5809
|
function mergeWizardSteps(cwd) {
|
|
@@ -5699,6 +5857,7 @@ function renderSetupWizardHtml(boot) {
|
|
|
5699
5857
|
<div>
|
|
5700
5858
|
<div style="font-weight:600;color:#f8fafc">Setup progress</div>
|
|
5701
5859
|
<div style="font-size:13px;color:#94a3b8">Save anytime \u2014 resume with agent-kit setup</div>
|
|
5860
|
+
<div class="wizard-level-pill" id="wizard-level-pill" hidden aria-live="polite">L3 \u2192 L5</div>
|
|
5702
5861
|
</div>
|
|
5703
5862
|
</div>
|
|
5704
5863
|
<ul class="section-nav" id="section-nav"></ul>
|
|
@@ -5733,6 +5892,272 @@ function renderSetupWizardHtmlWithContext(cwd) {
|
|
|
5733
5892
|
return renderSetupWizardHtml({ ...boot, stackSignals: [...new Set(stackSignals)] });
|
|
5734
5893
|
}
|
|
5735
5894
|
|
|
5895
|
+
// src/studio/agentic-level.ts
|
|
5896
|
+
import { existsSync as existsSync21, readFileSync as readFileSync22 } from "fs";
|
|
5897
|
+
import { join as join24 } from "path";
|
|
5898
|
+
var CACHE_TTL_MS = 3e4;
|
|
5899
|
+
var cache = /* @__PURE__ */ new Map();
|
|
5900
|
+
function isMaintainerSourceRepo(cwd) {
|
|
5901
|
+
return existsSync21(join24(cwd, "package.json")) && existsSync21(join24(cwd, "src")) && existsSync21(join24(cwd, "templates"));
|
|
5902
|
+
}
|
|
5903
|
+
function signal(id, level, label, pass, evidence, remediation) {
|
|
5904
|
+
return { id, level, label, pass, evidence, remediation };
|
|
5905
|
+
}
|
|
5906
|
+
function detectIdePresent(cwd) {
|
|
5907
|
+
const onboarding = loadOnboardingState(cwd);
|
|
5908
|
+
if (onboarding.ideSurface && detectIdeRulePresent(cwd, onboarding.ideSurface)) {
|
|
5909
|
+
return { pass: true, evidence: `${onboarding.ideSurface} adapter configured` };
|
|
5910
|
+
}
|
|
5911
|
+
const surfaces = ["cursor", "copilot", "claude", "codex"];
|
|
5912
|
+
for (const surface of surfaces) {
|
|
5913
|
+
if (detectIdeRulePresent(cwd, surface)) {
|
|
5914
|
+
return { pass: true, evidence: `${surface} adapter files detected` };
|
|
5915
|
+
}
|
|
5916
|
+
}
|
|
5917
|
+
if (existsSync21(join24(cwd, ".cursor/rules/cursor-agent-kit.mdc"))) {
|
|
5918
|
+
return { pass: true, evidence: "Cursor council rules from init" };
|
|
5919
|
+
}
|
|
5920
|
+
return { pass: false, evidence: "No IDE adapter rules or subagents detected" };
|
|
5921
|
+
}
|
|
5922
|
+
function detectTierBSubagents(cwd) {
|
|
5923
|
+
const paths = [".cursor/agents/planner.md", ".codex/agents/planner.toml", ".claude/agents/planner.md", ".github/copilot-instructions.md"];
|
|
5924
|
+
const found = paths.filter((rel) => existsSync21(join24(cwd, rel)));
|
|
5925
|
+
if (found.length > 0) {
|
|
5926
|
+
return { pass: true, evidence: `Specialist surface: ${found[0]}` };
|
|
5927
|
+
}
|
|
5928
|
+
return { pass: false, evidence: "No council subagents or Copilot instructions installed" };
|
|
5929
|
+
}
|
|
5930
|
+
function readDocSnippet(cwd, name, needles) {
|
|
5931
|
+
const path = join24(cwd, name);
|
|
5932
|
+
if (!existsSync21(path)) return false;
|
|
5933
|
+
const lower = readFileSync22(path, "utf8").toLowerCase();
|
|
5934
|
+
return needles.every((needle) => lower.includes(needle.toLowerCase()));
|
|
5935
|
+
}
|
|
5936
|
+
function adapterTargetForIde(ide) {
|
|
5937
|
+
if (ide === "cursor" || ide === "codex" || ide === "claude" || ide === "copilot") return ide;
|
|
5938
|
+
return null;
|
|
5939
|
+
}
|
|
5940
|
+
function buildSignals(cwd, maintainerProfile) {
|
|
5941
|
+
const signals = [];
|
|
5942
|
+
const ide = detectIdePresent(cwd);
|
|
5943
|
+
signals.push(
|
|
5944
|
+
signal(
|
|
5945
|
+
"l3-ide",
|
|
5946
|
+
3,
|
|
5947
|
+
"AI-native IDE or adapter rules",
|
|
5948
|
+
ide.pass,
|
|
5949
|
+
ide.evidence,
|
|
5950
|
+
"Run agent-kit init and complete the IDE station, or agent-kit init --activate cursor|codex"
|
|
5951
|
+
)
|
|
5952
|
+
);
|
|
5953
|
+
const context2 = scanProjectContext(cwd);
|
|
5954
|
+
const openQuestions = context2.openQuestions.length;
|
|
5955
|
+
const contextReady = Boolean(context2.productSummary.trim()) && Boolean(context2.primaryAudience.trim()) && Boolean(context2.authModel.trim()) && context2.primaryWorkflows.length > 0 && openQuestions === 0;
|
|
5956
|
+
signals.push(
|
|
5957
|
+
signal(
|
|
5958
|
+
"l4-agents-md",
|
|
5959
|
+
4,
|
|
5960
|
+
"Council contract (AGENTS.md)",
|
|
5961
|
+
existsSync21(join24(cwd, "AGENTS.md")),
|
|
5962
|
+
existsSync21(join24(cwd, "AGENTS.md")) ? "AGENTS.md installed" : "AGENTS.md missing",
|
|
5963
|
+
"Run agent-kit init --stack next-supabase"
|
|
5964
|
+
)
|
|
5965
|
+
);
|
|
5966
|
+
signals.push(
|
|
5967
|
+
signal(
|
|
5968
|
+
"l4-adapters-doc",
|
|
5969
|
+
4,
|
|
5970
|
+
"Assistant activation doc",
|
|
5971
|
+
existsSync21(join24(cwd, "ASSISTANT_ADAPTERS.md")),
|
|
5972
|
+
existsSync21(join24(cwd, "ASSISTANT_ADAPTERS.md")) ? "ASSISTANT_ADAPTERS.md installed" : "ASSISTANT_ADAPTERS.md missing",
|
|
5973
|
+
"Run agent-kit init or agent-kit update"
|
|
5974
|
+
)
|
|
5975
|
+
);
|
|
5976
|
+
signals.push(
|
|
5977
|
+
signal(
|
|
5978
|
+
"l4-roster",
|
|
5979
|
+
4,
|
|
5980
|
+
"Machine-readable council roster",
|
|
5981
|
+
existsSync21(join24(cwd, ".agent-kit/agent-roster.json")),
|
|
5982
|
+
existsSync21(join24(cwd, ".agent-kit/agent-roster.json")) ? ".agent-kit/agent-roster.json present" : "Roster missing",
|
|
5983
|
+
"Run agent-kit init or agent-kit update"
|
|
5984
|
+
)
|
|
5985
|
+
);
|
|
5986
|
+
signals.push(
|
|
5987
|
+
signal(
|
|
5988
|
+
"l4-project-context",
|
|
5989
|
+
4,
|
|
5990
|
+
"Project context without open questions",
|
|
5991
|
+
contextReady,
|
|
5992
|
+
contextReady ? "Core project context fields complete" : openQuestions > 0 ? `${openQuestions} open question(s) remain` : "Fill product, audience, auth, and workflows in setup",
|
|
5993
|
+
"Complete setup wizard or edit .agent-kit/project-context.json"
|
|
5994
|
+
)
|
|
5995
|
+
);
|
|
5996
|
+
const tierB = detectTierBSubagents(cwd);
|
|
5997
|
+
signals.push(
|
|
5998
|
+
signal("l5-subagents", 5, "Tier-B specialist activation", tierB.pass, tierB.evidence, "Run agent-kit init --activate cursor|codex|claude|copilot")
|
|
5999
|
+
);
|
|
6000
|
+
const loopCoding = existsSync21(join24(cwd, "LOOP_CODING.md"));
|
|
6001
|
+
signals.push(
|
|
6002
|
+
signal(
|
|
6003
|
+
"l6-loop-coding",
|
|
6004
|
+
6,
|
|
6005
|
+
"Loop coding playbook",
|
|
6006
|
+
loopCoding,
|
|
6007
|
+
loopCoding ? "LOOP_CODING.md installed" : "LOOP_CODING.md missing",
|
|
6008
|
+
"Run agent-kit update or agent-kit init on a current kit version"
|
|
6009
|
+
)
|
|
6010
|
+
);
|
|
6011
|
+
let auditPass = false;
|
|
6012
|
+
let auditEvidence = "Audit not run";
|
|
6013
|
+
try {
|
|
6014
|
+
const audit = createAuditReport(cwd);
|
|
6015
|
+
auditPass = audit.summary.fail === 0 && audit.readiness.level !== "needs-setup";
|
|
6016
|
+
auditEvidence = `${audit.summary.pass} pass / ${audit.summary.warn} warn / ${audit.summary.fail} fail \xB7 ${audit.readiness.level}`;
|
|
6017
|
+
} catch (error) {
|
|
6018
|
+
auditEvidence = error instanceof Error ? error.message : String(error);
|
|
6019
|
+
}
|
|
6020
|
+
signals.push(
|
|
6021
|
+
signal(
|
|
6022
|
+
"l6-audit-gate",
|
|
6023
|
+
6,
|
|
6024
|
+
"Audit gate at baseline-setup or better",
|
|
6025
|
+
auditPass,
|
|
6026
|
+
auditEvidence,
|
|
6027
|
+
"Run agent-kit audit --min-readiness baseline-setup and fix failures"
|
|
6028
|
+
)
|
|
6029
|
+
);
|
|
6030
|
+
if (maintainerProfile) {
|
|
6031
|
+
const pkgPath = join24(cwd, "package.json");
|
|
6032
|
+
let releaseCheck = false;
|
|
6033
|
+
if (existsSync21(pkgPath)) {
|
|
6034
|
+
try {
|
|
6035
|
+
const pkg = JSON.parse(readFileSync22(pkgPath, "utf8"));
|
|
6036
|
+
releaseCheck = Boolean(pkg.scripts?.["release:check"]) && existsSync21(join24(cwd, "scripts/release-check.mjs"));
|
|
6037
|
+
} catch {
|
|
6038
|
+
releaseCheck = false;
|
|
6039
|
+
}
|
|
6040
|
+
}
|
|
6041
|
+
signals.push(
|
|
6042
|
+
signal(
|
|
6043
|
+
"l6-maintainer-release-check",
|
|
6044
|
+
6,
|
|
6045
|
+
"Maintainer release-check gate",
|
|
6046
|
+
releaseCheck,
|
|
6047
|
+
releaseCheck ? "npm run release:check wired in package.json" : "release:check script missing",
|
|
6048
|
+
"Use npm run release:check before merge; see MAINTAINER_RELEASE.md"
|
|
6049
|
+
)
|
|
6050
|
+
);
|
|
6051
|
+
const maintainerDocs = existsSync21(join24(cwd, "MAINTAINER_RELEASE.md")) || readDocSnippet(cwd, "DOCS.md", ["maintainer dogfood", "dogfood:init"]);
|
|
6052
|
+
signals.push(
|
|
6053
|
+
signal(
|
|
6054
|
+
"l6-maintainer-docs",
|
|
6055
|
+
6,
|
|
6056
|
+
"Maintainer dogfood and release evidence docs",
|
|
6057
|
+
maintainerDocs,
|
|
6058
|
+
maintainerDocs ? "Maintainer climb docs present" : "Add MAINTAINER_RELEASE.md / DOCS maintainer section",
|
|
6059
|
+
"Read MAINTAINER_RELEASE.md and run npm run dogfood:init locally"
|
|
6060
|
+
)
|
|
6061
|
+
);
|
|
6062
|
+
} else {
|
|
6063
|
+
const onboarding = loadOnboardingState(cwd);
|
|
6064
|
+
const adapterTarget = adapterTargetForIde(onboarding.ideSurface);
|
|
6065
|
+
let adapterPass = false;
|
|
6066
|
+
let adapterEvidence = "No IDE surface selected for validation";
|
|
6067
|
+
if (adapterTarget) {
|
|
6068
|
+
const report2 = validateAdapter(cwd, adapterTarget);
|
|
6069
|
+
adapterPass = report2.summary.fail === 0;
|
|
6070
|
+
adapterEvidence = `${adapterTarget}: ${report2.summary.pass} pass / ${report2.summary.warn} warn / ${report2.summary.fail} fail`;
|
|
6071
|
+
} else if (tierB.pass) {
|
|
6072
|
+
const report2 = validateAdapter(cwd, "cursor");
|
|
6073
|
+
adapterPass = report2.summary.fail === 0;
|
|
6074
|
+
adapterEvidence = `cursor (detected): ${report2.summary.pass} pass / ${report2.summary.fail} fail`;
|
|
6075
|
+
}
|
|
6076
|
+
signals.push(
|
|
6077
|
+
signal("l6-adapter-validate", 6, "Adapter validate for active IDE", adapterPass, adapterEvidence, "Run agent-kit adapter validate cursor|codex|all")
|
|
6078
|
+
);
|
|
6079
|
+
const ciWorkflow = existsSync21(join24(cwd, ".github/workflows/agent-kit-audit.yml"));
|
|
6080
|
+
const testingEval = existsSync21(join24(cwd, "TESTING.md")) && readDocSnippet(cwd, "TESTING.md", ["agent-kit audit", "eval"]);
|
|
6081
|
+
const evalLoop = ciWorkflow || testingEval;
|
|
6082
|
+
signals.push(
|
|
6083
|
+
signal(
|
|
6084
|
+
"l6-eval-loop",
|
|
6085
|
+
6,
|
|
6086
|
+
"Eval-driven loop documented in CI or TESTING.md",
|
|
6087
|
+
evalLoop,
|
|
6088
|
+
ciWorkflow ? ".github/workflows/agent-kit-audit.yml present" : testingEval ? "TESTING.md documents eval/audit loop" : "No CI audit workflow or TESTING eval section",
|
|
6089
|
+
"Enable agent-kit-audit.yml or add eval loop section to TESTING.md (see LOOP_CODING.md)"
|
|
6090
|
+
)
|
|
6091
|
+
);
|
|
6092
|
+
}
|
|
6093
|
+
return signals;
|
|
6094
|
+
}
|
|
6095
|
+
function computeCurrentLevel(signals) {
|
|
6096
|
+
let current = 3;
|
|
6097
|
+
for (const level of [3, 4, 5, 6]) {
|
|
6098
|
+
const tier = signals.filter((item) => item.level === level);
|
|
6099
|
+
if (tier.length === 0) continue;
|
|
6100
|
+
if (tier.every((item) => item.pass)) {
|
|
6101
|
+
current = level;
|
|
6102
|
+
} else {
|
|
6103
|
+
break;
|
|
6104
|
+
}
|
|
6105
|
+
}
|
|
6106
|
+
return current;
|
|
6107
|
+
}
|
|
6108
|
+
function defaultTargetLevel(maintainerProfile) {
|
|
6109
|
+
return maintainerProfile ? 6 : 5;
|
|
6110
|
+
}
|
|
6111
|
+
function resolveTargetLevel(cwd, maintainerProfile) {
|
|
6112
|
+
const onboarding = loadOnboardingState(cwd);
|
|
6113
|
+
const raw = onboarding.targetAgenticLevel;
|
|
6114
|
+
if (raw && raw >= 3 && raw <= 8) return raw;
|
|
6115
|
+
return defaultTargetLevel(maintainerProfile);
|
|
6116
|
+
}
|
|
6117
|
+
function computeAgenticLevel(cwd, options = {}) {
|
|
6118
|
+
const cacheKey = cwd;
|
|
6119
|
+
const cached = cache.get(cacheKey);
|
|
6120
|
+
if (!options.forceRefresh && cached && Date.now() - cached.at < CACHE_TTL_MS) {
|
|
6121
|
+
return cached.report;
|
|
6122
|
+
}
|
|
6123
|
+
const maintainerProfile = isMaintainerSourceRepo(cwd);
|
|
6124
|
+
const signals = buildSignals(cwd, maintainerProfile);
|
|
6125
|
+
const currentLevel = computeCurrentLevel(signals);
|
|
6126
|
+
const targetLevel = resolveTargetLevel(cwd, maintainerProfile);
|
|
6127
|
+
const climbSteps = signals.filter((item) => !item.pass && item.level <= Math.min(targetLevel, 6)).slice(0, 5);
|
|
6128
|
+
const report2 = AgenticLevelContract.parse({
|
|
6129
|
+
currentLevel,
|
|
6130
|
+
targetLevel,
|
|
6131
|
+
maintainerProfile,
|
|
6132
|
+
computedAt: nowIso(),
|
|
6133
|
+
maintainerNote: maintainerProfile ? "Kit source repo \u2014 run npm run dogfood:init locally; overlay is gitignored." : void 0,
|
|
6134
|
+
signals,
|
|
6135
|
+
climbSteps
|
|
6136
|
+
});
|
|
6137
|
+
cache.set(cacheKey, { at: Date.now(), report: report2 });
|
|
6138
|
+
saveOnboardingState(cwd, {
|
|
6139
|
+
lastAgenticLevel: currentLevel,
|
|
6140
|
+
lastAgenticComputedAt: report2.computedAt
|
|
6141
|
+
});
|
|
6142
|
+
return report2;
|
|
6143
|
+
}
|
|
6144
|
+
function summarizeAdapterValidation(cwd, ideSurface) {
|
|
6145
|
+
const target = adapterTargetForIde(ideSurface);
|
|
6146
|
+
if (!target) {
|
|
6147
|
+
return { pass: 0, warn: 0, fail: 0, target: null };
|
|
6148
|
+
}
|
|
6149
|
+
const report2 = validateAdapter(cwd, target);
|
|
6150
|
+
return {
|
|
6151
|
+
pass: report2.summary.pass,
|
|
6152
|
+
warn: report2.summary.warn,
|
|
6153
|
+
fail: report2.summary.fail,
|
|
6154
|
+
target
|
|
6155
|
+
};
|
|
6156
|
+
}
|
|
6157
|
+
function invalidateAgenticLevelCache(cwd) {
|
|
6158
|
+
cache.delete(cwd);
|
|
6159
|
+
}
|
|
6160
|
+
|
|
5736
6161
|
// src/studio/setup-server.ts
|
|
5737
6162
|
var DEFAULT_PORT = 9321;
|
|
5738
6163
|
var DEFAULT_HOST = "127.0.0.1";
|
|
@@ -5776,7 +6201,7 @@ function sendHtml(response, html) {
|
|
|
5776
6201
|
});
|
|
5777
6202
|
response.end(html);
|
|
5778
6203
|
}
|
|
5779
|
-
function buildStatePayload(cwd) {
|
|
6204
|
+
function buildStatePayload(cwd, options = {}) {
|
|
5780
6205
|
ensureProjectContextForSetup(cwd);
|
|
5781
6206
|
const viewModel = getSetupFormViewModel(cwd);
|
|
5782
6207
|
const onboarding = loadOnboardingState(cwd);
|
|
@@ -5784,16 +6209,16 @@ function buildStatePayload(cwd) {
|
|
|
5784
6209
|
const designDraft = loadDesignDraft(cwd);
|
|
5785
6210
|
const messagingDraft = loadMessagingDraft(cwd);
|
|
5786
6211
|
const draft = loadWizardDraft(cwd);
|
|
6212
|
+
const agenticLevel = computeAgenticLevel(cwd, options.forceAgenticRefresh ? { forceRefresh: true } : {});
|
|
5787
6213
|
return {
|
|
5788
6214
|
projectName: viewModel.projectName,
|
|
5789
6215
|
form: buildWizardFormState(cwd),
|
|
5790
|
-
hasExistingContext: Boolean(
|
|
5791
|
-
viewModel.form.productSummary.trim() || viewModel.form.primaryAudience.trim() || viewModel.form.valueProposition.trim()
|
|
5792
|
-
),
|
|
6216
|
+
hasExistingContext: Boolean(viewModel.form.productSummary.trim() || viewModel.form.primaryAudience.trim() || viewModel.form.valueProposition.trim()),
|
|
5793
6217
|
openQuestions: viewModel.openQuestions,
|
|
5794
6218
|
hasSupabase: viewModel.hasSupabase,
|
|
5795
6219
|
onboarding,
|
|
5796
6220
|
progress,
|
|
6221
|
+
agenticLevel,
|
|
5797
6222
|
designDraft,
|
|
5798
6223
|
messagingDraft,
|
|
5799
6224
|
draftUpdatedAt: draft.updatedAt,
|
|
@@ -5855,8 +6280,10 @@ async function handleRequest(cwd, request, response) {
|
|
|
5855
6280
|
if (body.currentSection) patch.currentSection = String(body.currentSection);
|
|
5856
6281
|
if (typeof body.currentStep === "number") patch.currentStep = body.currentStep;
|
|
5857
6282
|
if (Array.isArray(body.completedSections)) patch.completedSections = body.completedSections;
|
|
6283
|
+
if (typeof body.targetAgenticLevel === "number") patch.targetAgenticLevel = body.targetAgenticLevel;
|
|
5858
6284
|
if (Object.keys(patch).length > 0) saveOnboardingState(cwd, patch);
|
|
5859
|
-
|
|
6285
|
+
invalidateAgenticLevelCache(cwd);
|
|
6286
|
+
sendJson(response, 200, buildStatePayload(cwd, { forceAgenticRefresh: true }));
|
|
5860
6287
|
} catch (error) {
|
|
5861
6288
|
sendJson(response, 400, { error: error instanceof Error ? error.message : String(error) });
|
|
5862
6289
|
}
|
|
@@ -5869,8 +6296,9 @@ async function handleRequest(cwd, request, response) {
|
|
|
5869
6296
|
const result = applySetupFormAnswers(cwd, payload);
|
|
5870
6297
|
saveAgentBriefs(cwd, extractAgentBriefsFromForm(raw));
|
|
5871
6298
|
markQuickPathComplete(cwd);
|
|
6299
|
+
invalidateAgenticLevelCache(cwd);
|
|
5872
6300
|
sendJson(response, 200, {
|
|
5873
|
-
...buildStatePayload(cwd),
|
|
6301
|
+
...buildStatePayload(cwd, { forceAgenticRefresh: true }),
|
|
5874
6302
|
saved: true,
|
|
5875
6303
|
contextPath: result.contextPath,
|
|
5876
6304
|
markdownPath: result.markdownPath,
|
|
@@ -5923,7 +6351,14 @@ async function handleRequest(cwd, request, response) {
|
|
|
5923
6351
|
}
|
|
5924
6352
|
const result = saveIdeChecklist(cwd, body.ideSurface);
|
|
5925
6353
|
markSectionComplete(cwd, "ide");
|
|
5926
|
-
|
|
6354
|
+
invalidateAgenticLevelCache(cwd);
|
|
6355
|
+
const adapterValidation = summarizeAdapterValidation(cwd, body.ideSurface);
|
|
6356
|
+
sendJson(response, 200, {
|
|
6357
|
+
...result,
|
|
6358
|
+
activation,
|
|
6359
|
+
adapterValidation,
|
|
6360
|
+
...buildStatePayload(cwd, { forceAgenticRefresh: true })
|
|
6361
|
+
});
|
|
5927
6362
|
} catch (error) {
|
|
5928
6363
|
sendJson(response, 400, { error: error instanceof Error ? error.message : String(error) });
|
|
5929
6364
|
}
|
|
@@ -5981,6 +6416,11 @@ async function handleRequest(cwd, request, response) {
|
|
|
5981
6416
|
}
|
|
5982
6417
|
return;
|
|
5983
6418
|
}
|
|
6419
|
+
if (request.method === "POST" && url.pathname === "/api/agentic-level/refresh") {
|
|
6420
|
+
invalidateAgenticLevelCache(cwd);
|
|
6421
|
+
sendJson(response, 200, buildStatePayload(cwd, { forceAgenticRefresh: true }));
|
|
6422
|
+
return;
|
|
6423
|
+
}
|
|
5984
6424
|
sendJson(response, 404, { error: "Not found." });
|
|
5985
6425
|
}
|
|
5986
6426
|
function listen(server, host, port) {
|
|
@@ -6036,7 +6476,7 @@ async function startSetupServer(options) {
|
|
|
6036
6476
|
// src/studio/studio-server.ts
|
|
6037
6477
|
import { watch } from "fs";
|
|
6038
6478
|
import { createServer as createServer2 } from "http";
|
|
6039
|
-
import { join as
|
|
6479
|
+
import { join as join25 } from "path";
|
|
6040
6480
|
var DEFAULT_PORT2 = 9331;
|
|
6041
6481
|
var DEFAULT_HOST2 = "127.0.0.1";
|
|
6042
6482
|
var sseClients = /* @__PURE__ */ new Set();
|
|
@@ -6078,7 +6518,7 @@ function stopWatcher() {
|
|
|
6078
6518
|
}
|
|
6079
6519
|
}
|
|
6080
6520
|
function watchSessionEvents(cwd, sessionId) {
|
|
6081
|
-
const eventsPath2 =
|
|
6521
|
+
const eventsPath2 = join25(cwd, COUNCIL_SESSIONS_DIR, sessionId, "events.jsonl");
|
|
6082
6522
|
if (watchedEventsPath === eventsPath2 && activeWatcher) return;
|
|
6083
6523
|
stopWatcher();
|
|
6084
6524
|
watchedEventsPath = eventsPath2;
|
|
@@ -6100,7 +6540,7 @@ function safeSessionId(raw) {
|
|
|
6100
6540
|
if (!/^[a-z0-9-]+$/i.test(raw)) return null;
|
|
6101
6541
|
return raw;
|
|
6102
6542
|
}
|
|
6103
|
-
|
|
6543
|
+
function handleRequest2(cwd, request, response) {
|
|
6104
6544
|
const url = new URL(request.url ?? "/", "http://127.0.0.1");
|
|
6105
6545
|
if (request.method === "GET" && (url.pathname === "/" || url.pathname === "/office")) {
|
|
6106
6546
|
sendHtml2(response, renderLiveStudioHtmlWithContext(cwd));
|
|
@@ -6195,9 +6635,11 @@ async function startStudioServer(options) {
|
|
|
6195
6635
|
const requestedPort = options.port ?? DEFAULT_PORT2;
|
|
6196
6636
|
ensureStudioDirs(options.cwd);
|
|
6197
6637
|
const server = createServer2((request, response) => {
|
|
6198
|
-
|
|
6638
|
+
try {
|
|
6639
|
+
handleRequest2(options.cwd, request, response);
|
|
6640
|
+
} catch (error) {
|
|
6199
6641
|
sendJson2(response, 500, { error: error instanceof Error ? error.message : String(error) });
|
|
6200
|
-
}
|
|
6642
|
+
}
|
|
6201
6643
|
});
|
|
6202
6644
|
let port = requestedPort;
|
|
6203
6645
|
let portFallback = false;
|
|
@@ -6234,33 +6676,33 @@ async function startStudioServer(options) {
|
|
|
6234
6676
|
}
|
|
6235
6677
|
|
|
6236
6678
|
// src/studio/session-checkpoint.ts
|
|
6237
|
-
import { existsSync as
|
|
6238
|
-
import { extname, join as
|
|
6679
|
+
import { existsSync as existsSync22, readFileSync as readFileSync23 } from "fs";
|
|
6680
|
+
import { extname, join as join26 } from "path";
|
|
6239
6681
|
function parseCheckpointMarkdown(content) {
|
|
6240
6682
|
const payload = { notes: [], decisions: [], handoffs: [], outputs: [] };
|
|
6241
6683
|
const sections = content.split(/^## /m).slice(1);
|
|
6242
6684
|
for (const section of sections) {
|
|
6243
6685
|
const [headingLine, ...bodyLines] = section.split("\n");
|
|
6244
6686
|
if (!headingLine) continue;
|
|
6245
|
-
const
|
|
6246
|
-
const lines = bodyLines.map((
|
|
6247
|
-
if (
|
|
6248
|
-
for (const
|
|
6249
|
-
const match =
|
|
6687
|
+
const heading2 = headingLine.trim().toLowerCase();
|
|
6688
|
+
const lines = bodyLines.map((line2) => line2.trim()).filter(Boolean);
|
|
6689
|
+
if (heading2 === "notes") {
|
|
6690
|
+
for (const line2 of lines) {
|
|
6691
|
+
const match = line2.match(/^-?\s*@(\S+):\s*(.+)$/);
|
|
6250
6692
|
if (match?.[1] && match[2]) payload.notes?.push({ agent: match[1], text: match[2] });
|
|
6251
6693
|
}
|
|
6252
6694
|
}
|
|
6253
|
-
if (
|
|
6254
|
-
for (const
|
|
6255
|
-
const match =
|
|
6695
|
+
if (heading2 === "decisions") {
|
|
6696
|
+
for (const line2 of lines) {
|
|
6697
|
+
const match = line2.match(/^-?\s*@(\S+):\s*(.+?)(?:\s+\(risk:\s*(.+)\))?$/i);
|
|
6256
6698
|
if (match?.[1] && match[2]) {
|
|
6257
6699
|
payload.decisions?.push({ agent: match[1], text: match[2], ...match[3] ? { risk: match[3] } : {} });
|
|
6258
6700
|
}
|
|
6259
6701
|
}
|
|
6260
6702
|
}
|
|
6261
|
-
if (
|
|
6262
|
-
for (const
|
|
6263
|
-
const match =
|
|
6703
|
+
if (heading2 === "handoffs") {
|
|
6704
|
+
for (const line2 of lines) {
|
|
6705
|
+
const match = line2.match(/^-?\s*(\S+)\s*->\s*(\S+):\s*(.+?)\s+\|\s*risk:\s*(.+)$/i);
|
|
6264
6706
|
if (match?.[1] && match?.[2] && match?.[3] && match?.[4]) {
|
|
6265
6707
|
payload.handoffs?.push({
|
|
6266
6708
|
fromAgentId: match[1],
|
|
@@ -6271,9 +6713,9 @@ function parseCheckpointMarkdown(content) {
|
|
|
6271
6713
|
}
|
|
6272
6714
|
}
|
|
6273
6715
|
}
|
|
6274
|
-
if (
|
|
6275
|
-
for (const
|
|
6276
|
-
const match =
|
|
6716
|
+
if (heading2 === "outputs") {
|
|
6717
|
+
for (const line2 of lines) {
|
|
6718
|
+
const match = line2.match(/^-?\s*(.+?):\s*(missing|partial|complete|not-applicable)(?:\s+\|\s*(.+))?$/i);
|
|
6277
6719
|
if (match?.[1] && match?.[2]) {
|
|
6278
6720
|
payload.outputs?.push({
|
|
6279
6721
|
name: match[1].trim(),
|
|
@@ -6283,15 +6725,15 @@ function parseCheckpointMarkdown(content) {
|
|
|
6283
6725
|
}
|
|
6284
6726
|
}
|
|
6285
6727
|
}
|
|
6286
|
-
if (
|
|
6287
|
-
if (lines.some((
|
|
6288
|
-
if (lines.some((
|
|
6728
|
+
if (heading2 === "options") {
|
|
6729
|
+
if (lines.some((line2) => /render:\s*true/i.test(line2))) payload.render = true;
|
|
6730
|
+
if (lines.some((line2) => /close:\s*true/i.test(line2))) payload.close = true;
|
|
6289
6731
|
}
|
|
6290
6732
|
}
|
|
6291
6733
|
return payload;
|
|
6292
6734
|
}
|
|
6293
6735
|
function parseCheckpointFile(filePath) {
|
|
6294
|
-
const content =
|
|
6736
|
+
const content = readFileSync23(filePath, "utf8");
|
|
6295
6737
|
const ext = extname(filePath).toLowerCase();
|
|
6296
6738
|
if (ext === ".json") {
|
|
6297
6739
|
const parsed = JSON.parse(content);
|
|
@@ -6367,11 +6809,55 @@ function applySessionCheckpoint(cwd, payload) {
|
|
|
6367
6809
|
};
|
|
6368
6810
|
}
|
|
6369
6811
|
function checkpointSessionFromFile(cwd, filePath) {
|
|
6370
|
-
const absolute =
|
|
6371
|
-
if (!
|
|
6812
|
+
const absolute = join26(cwd, filePath);
|
|
6813
|
+
if (!existsSync22(absolute)) throw new Error(`Checkpoint file not found: ${filePath}`);
|
|
6372
6814
|
return applySessionCheckpoint(cwd, parseCheckpointFile(absolute));
|
|
6373
6815
|
}
|
|
6374
6816
|
|
|
6817
|
+
// src/cli/output.ts
|
|
6818
|
+
import pc from "picocolors";
|
|
6819
|
+
var colorEnabled = process.env.NO_COLOR === void 0 && process.stdout.isTTY === true;
|
|
6820
|
+
function paint(painter, text) {
|
|
6821
|
+
return colorEnabled ? painter(text) : text;
|
|
6822
|
+
}
|
|
6823
|
+
var style = {
|
|
6824
|
+
heading: (text) => paint(pc.cyan, text),
|
|
6825
|
+
pass: (text) => paint(pc.green, text),
|
|
6826
|
+
warn: (text) => paint(pc.yellow, text),
|
|
6827
|
+
fail: (text) => paint(pc.red, text),
|
|
6828
|
+
dim: (text) => paint(pc.dim, text),
|
|
6829
|
+
bold: (text) => paint(pc.bold, text)
|
|
6830
|
+
};
|
|
6831
|
+
function levelLabel(level) {
|
|
6832
|
+
const label = level.toUpperCase().padEnd(4);
|
|
6833
|
+
if (level === "pass") return style.pass(label);
|
|
6834
|
+
if (level === "warn") return style.warn(label);
|
|
6835
|
+
return style.fail(label);
|
|
6836
|
+
}
|
|
6837
|
+
function printJson(value) {
|
|
6838
|
+
console.log(JSON.stringify(value, null, 2));
|
|
6839
|
+
}
|
|
6840
|
+
function heading(text) {
|
|
6841
|
+
console.log(style.heading(text));
|
|
6842
|
+
}
|
|
6843
|
+
function line(text = "") {
|
|
6844
|
+
console.log(text);
|
|
6845
|
+
}
|
|
6846
|
+
function detail(text) {
|
|
6847
|
+
console.log(style.dim(` ${text}`));
|
|
6848
|
+
}
|
|
6849
|
+
function listItem(text) {
|
|
6850
|
+
console.log(`- ${text}`);
|
|
6851
|
+
}
|
|
6852
|
+
function fileGroup(label, files) {
|
|
6853
|
+
if (files.length === 0) return;
|
|
6854
|
+
console.log(`${style.bold(label)} (${files.length})`);
|
|
6855
|
+
for (const file of files) console.log(` ${file}`);
|
|
6856
|
+
}
|
|
6857
|
+
function fail(message) {
|
|
6858
|
+
console.error(style.fail(`error: ${message}`));
|
|
6859
|
+
}
|
|
6860
|
+
|
|
6375
6861
|
// src/cli/index.ts
|
|
6376
6862
|
var program = new Command();
|
|
6377
6863
|
var requiredOutputStatuses = ["missing", "partial", "complete", "not-applicable"];
|
|
@@ -6379,6 +6865,37 @@ function isRequiredOutputStatus(value) {
|
|
|
6379
6865
|
return requiredOutputStatuses.includes(value);
|
|
6380
6866
|
}
|
|
6381
6867
|
program.name("agent-kit").description("Next.js + Supabase agent, skill, docs, design, and research kit.").version(PACKAGE_VERSION);
|
|
6868
|
+
async function runGuidedContextPrompts(cwd) {
|
|
6869
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) return;
|
|
6870
|
+
const clack = await import("@clack/prompts");
|
|
6871
|
+
clack.intro("agent-kit guided setup");
|
|
6872
|
+
const questions = [
|
|
6873
|
+
{ key: "productSummary", message: "What does this product do, in one concrete paragraph?" },
|
|
6874
|
+
{ key: "primaryAudience", message: "Who is the primary user or buyer?" },
|
|
6875
|
+
{ key: "authModel", message: "What authentication model should agents preserve?" },
|
|
6876
|
+
{ key: "tenantModel", message: "Is this single-user, team, tenant, marketplace, admin, or public content?" }
|
|
6877
|
+
];
|
|
6878
|
+
const answers = {};
|
|
6879
|
+
for (const question of questions) {
|
|
6880
|
+
const answer = await clack.text({ message: question.message, placeholder: "Leave empty to answer later" });
|
|
6881
|
+
if (clack.isCancel(answer)) {
|
|
6882
|
+
clack.cancel("Guided setup cancelled. Context files were still created; answer later with agent-kit context ask.");
|
|
6883
|
+
return;
|
|
6884
|
+
}
|
|
6885
|
+
if (typeof answer === "string" && answer.trim()) answers[question.key] = answer.trim();
|
|
6886
|
+
}
|
|
6887
|
+
if (Object.keys(answers).length > 0) {
|
|
6888
|
+
const contextPath = join27(cwd, ".agent-kit", "project-context.json");
|
|
6889
|
+
if (existsSync23(contextPath)) {
|
|
6890
|
+
const context2 = JSON.parse(readFileSync24(contextPath, "utf8"));
|
|
6891
|
+
Object.assign(context2, answers);
|
|
6892
|
+
writeFileSync2(contextPath, `${JSON.stringify(context2, null, 2)}
|
|
6893
|
+
`);
|
|
6894
|
+
renderProjectContext(cwd);
|
|
6895
|
+
}
|
|
6896
|
+
}
|
|
6897
|
+
clack.outro("Project context saved. Run agent-kit audit next.");
|
|
6898
|
+
}
|
|
6382
6899
|
async function runSetupServer(options) {
|
|
6383
6900
|
const handle = await startSetupServer({
|
|
6384
6901
|
cwd: process.cwd(),
|
|
@@ -6386,35 +6903,73 @@ async function runSetupServer(options) {
|
|
|
6386
6903
|
host: options.host
|
|
6387
6904
|
});
|
|
6388
6905
|
if (handle.portFallback) {
|
|
6389
|
-
console.warn(
|
|
6390
|
-
`Port ${handle.requestedPort} is in use \u2014 an old setup server may still be running. Kill it and restart to load the latest Agent Office.`
|
|
6391
|
-
);
|
|
6906
|
+
console.warn(`Port ${handle.requestedPort} is in use \u2014 an old setup server may still be running. Kill it and restart to load the latest Agent Office.`);
|
|
6392
6907
|
console.warn(`Using fallback port ${handle.port} instead.`);
|
|
6393
6908
|
}
|
|
6394
6909
|
console.log(`Agent Kit v${PACKAGE_VERSION} \u2014 ${handle.defaultView} view at ${handle.url}/`);
|
|
6395
6910
|
console.log(`Pixel office (default): ${handle.url}/ | Form fallback: ${handle.url}/wizard`);
|
|
6396
6911
|
console.log("Pick Quick, Standard, or Complete on first visit. Press Ctrl+C to stop.");
|
|
6397
|
-
if (options.open) openBrowser(`${handle.url}/`);
|
|
6912
|
+
if (options.open) void openBrowser(`${handle.url}/`);
|
|
6398
6913
|
await new Promise((resolve3) => {
|
|
6399
6914
|
const shutdown = () => {
|
|
6400
|
-
handle.close().finally(resolve3);
|
|
6915
|
+
void handle.close().finally(resolve3);
|
|
6401
6916
|
};
|
|
6402
6917
|
process.once("SIGINT", shutdown);
|
|
6403
6918
|
process.once("SIGTERM", shutdown);
|
|
6404
6919
|
});
|
|
6405
6920
|
}
|
|
6406
|
-
program.command("init").description("Install agent-kit docs and library files into a project.").option("--stack <stack>", "Stack profile to install.", "next-supabase").option("--force", "Overwrite existing docs instead of writing conflicts.").option("--activate <targets...>", "Promote IDE/runtime adapters: cursor, claude, codex, copilot, antigravity, or all.").option("--guided", "
|
|
6921
|
+
program.command("init").description("Install agent-kit docs and library files into a project.").option("--stack <stack>", "Stack profile to install.", "next-supabase").option("--force", "Overwrite existing docs instead of writing conflicts.").option("--activate <targets...>", "Promote IDE/runtime adapters: cursor, claude, codex, copilot, antigravity, or all.").option("--guided", "Also create local project context files (interactive on a terminal, scan-based otherwise).").option("--dry-run", "Preview what init would create or conflict on without writing files.").option("--json", "Print machine-readable JSON output.").option("--setup", "Start the setup wizard after install.").option("--no-setup", "Skip the post-install setup wizard prompt.").option("--open", "Open the setup wizard in your default browser.").action(async (options) => {
|
|
6407
6922
|
const cwd = process.cwd();
|
|
6923
|
+
if (options.dryRun) {
|
|
6924
|
+
const preview = diffProject(cwd, options.stack);
|
|
6925
|
+
if (options.json) {
|
|
6926
|
+
printJson({ dryRun: true, preview: preview.preview, missing: preview.missing, changed: preview.changed, unchanged: preview.unchanged });
|
|
6927
|
+
return;
|
|
6928
|
+
}
|
|
6929
|
+
heading("agent-kit init --dry-run");
|
|
6930
|
+
fileGroup("Would create", preview.preview.wouldCreate);
|
|
6931
|
+
fileGroup("Would write conflicts for", preview.preview.wouldWriteConflicts);
|
|
6932
|
+
fileGroup("Already up to date", preview.unchanged);
|
|
6933
|
+
line();
|
|
6934
|
+
line(`Run ${style.bold("agent-kit init")} to apply.`);
|
|
6935
|
+
return;
|
|
6936
|
+
}
|
|
6408
6937
|
const result = initProject({
|
|
6409
6938
|
cwd,
|
|
6410
6939
|
stack: options.stack,
|
|
6411
6940
|
force: Boolean(options.force),
|
|
6412
6941
|
...options.activate ? { activate: options.activate } : {}
|
|
6413
6942
|
});
|
|
6943
|
+
const context2 = options.guided ? initProjectContext(cwd) : null;
|
|
6414
6944
|
if (options.json) {
|
|
6415
|
-
|
|
6945
|
+
printJson(context2 ? { install: result, context: context2 } : result);
|
|
6416
6946
|
} else {
|
|
6417
|
-
|
|
6947
|
+
heading(`agent-kit ${PACKAGE_VERSION} installed (stack: ${options.stack})`);
|
|
6948
|
+
fileGroup("Created", result.copied);
|
|
6949
|
+
fileGroup("Unchanged", result.unchanged);
|
|
6950
|
+
fileGroup("Overwritten", result.overwritten);
|
|
6951
|
+
if (result.conflicts.length > 0) {
|
|
6952
|
+
fileGroup("Conflicts (local file kept, template saved for review)", result.conflicts);
|
|
6953
|
+
detail("Review .agent-kit/conflicts/ before adopting template changes.");
|
|
6954
|
+
}
|
|
6955
|
+
line();
|
|
6956
|
+
line(`Manifest: ${result.manifestPath}`);
|
|
6957
|
+
}
|
|
6958
|
+
if (options.guided && context2) {
|
|
6959
|
+
if (!options.json) {
|
|
6960
|
+
line();
|
|
6961
|
+
heading("Project context");
|
|
6962
|
+
line(`Context: ${context2.contextPath}`);
|
|
6963
|
+
if (context2.openQuestions.length > 0) {
|
|
6964
|
+
line("Open questions:");
|
|
6965
|
+
for (const question of context2.openQuestions) listItem(question);
|
|
6966
|
+
}
|
|
6967
|
+
}
|
|
6968
|
+
await runGuidedContextPrompts(cwd);
|
|
6969
|
+
}
|
|
6970
|
+
if (!options.json) {
|
|
6971
|
+
line();
|
|
6972
|
+
line(`Next: run ${style.bold("agent-kit audit")} to check readiness.`);
|
|
6418
6973
|
}
|
|
6419
6974
|
const shouldPrompt = !options.noSetup && !options.json;
|
|
6420
6975
|
const startWizard = Boolean(options.setup) || shouldPrompt && await promptStartSetup(true);
|
|
@@ -6427,26 +6982,26 @@ program.command("audit").description("Audit an existing project for agent-kit co
|
|
|
6427
6982
|
let minimumReadiness;
|
|
6428
6983
|
if (options.minReadiness) {
|
|
6429
6984
|
if (!isAuditReadinessLevel(options.minReadiness)) {
|
|
6430
|
-
|
|
6985
|
+
fail(`Invalid --min-readiness value "${options.minReadiness}". Expected one of: ${READINESS_ORDER.join(", ")}.`);
|
|
6431
6986
|
process.exitCode = 1;
|
|
6432
6987
|
return;
|
|
6433
6988
|
}
|
|
6434
6989
|
minimumReadiness = options.minReadiness;
|
|
6435
6990
|
}
|
|
6436
6991
|
if (options.json) {
|
|
6437
|
-
|
|
6992
|
+
printJson(report2);
|
|
6438
6993
|
} else {
|
|
6439
|
-
|
|
6440
|
-
|
|
6994
|
+
const readinessStyle = report2.summary.fail > 0 ? style.fail : report2.summary.warn > 0 ? style.warn : style.pass;
|
|
6995
|
+
line(`${style.bold("READINESS")} ${readinessStyle(report2.readiness.level)}: ${report2.readiness.summary}`);
|
|
6996
|
+
line(`${style.bold("SUMMARY")} pass=${report2.summary.pass} warn=${report2.summary.warn} fail=${report2.summary.fail}`);
|
|
6441
6997
|
if (report2.readiness.nextActions.length > 0) {
|
|
6442
|
-
|
|
6443
|
-
for (const action of report2.readiness.nextActions)
|
|
6998
|
+
line(style.bold("NEXT ACTIONS"));
|
|
6999
|
+
for (const action of report2.readiness.nextActions) listItem(action);
|
|
6444
7000
|
}
|
|
6445
|
-
|
|
7001
|
+
line();
|
|
6446
7002
|
for (const finding of report2.findings) {
|
|
6447
|
-
|
|
6448
|
-
|
|
6449
|
-
if (finding.remediation) console.log(` remediation: ${finding.remediation}`);
|
|
7003
|
+
line(`${levelLabel(finding.level)} ${finding.area}: ${finding.message}`);
|
|
7004
|
+
if (finding.remediation) detail(`remediation: ${finding.remediation}`);
|
|
6450
7005
|
}
|
|
6451
7006
|
}
|
|
6452
7007
|
if (report2.summary.fail > 0) {
|
|
@@ -6457,32 +7012,88 @@ program.command("audit").description("Audit an existing project for agent-kit co
|
|
|
6457
7012
|
process.exitCode = 1;
|
|
6458
7013
|
}
|
|
6459
7014
|
});
|
|
6460
|
-
program.command("diff").description("Compare project docs against bundled templates.").action(() => {
|
|
6461
|
-
|
|
7015
|
+
program.command("diff").description("Compare project docs against bundled templates.").option("--json", "Print machine-readable JSON output.").action((options) => {
|
|
7016
|
+
const result = diffProject(process.cwd());
|
|
7017
|
+
if (options.json) {
|
|
7018
|
+
printJson(result);
|
|
7019
|
+
return;
|
|
7020
|
+
}
|
|
7021
|
+
heading("agent-kit diff");
|
|
7022
|
+
fileGroup("Missing (update would create)", result.missing);
|
|
7023
|
+
fileGroup("Changed locally (update would write conflicts)", result.changed);
|
|
7024
|
+
fileGroup("Unchanged", result.unchanged);
|
|
7025
|
+
line();
|
|
7026
|
+
line(`Agent roster: ${result.agentRoster}`);
|
|
7027
|
+
line(`Model routing: ${result.modelRouting}`);
|
|
7028
|
+
if (result.libraryFolders.missing.length > 0) {
|
|
7029
|
+
line(`Missing library folders: ${result.libraryFolders.missing.join(", ")}`);
|
|
7030
|
+
}
|
|
7031
|
+
line();
|
|
7032
|
+
line(`Next: run ${style.bold("agent-kit update --dry-run")} to preview the exact per-file plan.`);
|
|
6462
7033
|
});
|
|
6463
|
-
program.command("update").description("Update installed templates,
|
|
6464
|
-
const result =
|
|
6465
|
-
|
|
7034
|
+
program.command("update").description("Update installed templates: pristine docs are refreshed, local edits are preserved, and template conflicts are written for review.").option("--force", "Overwrite locally customized docs with the current templates.").option("--dry-run", "Report what would change without writing any files.").option("--json", "Print machine-readable JSON output.").action((options) => {
|
|
7035
|
+
const result = updateProject({ cwd: process.cwd(), force: Boolean(options.force), dryRun: Boolean(options.dryRun) });
|
|
7036
|
+
if (options.json) {
|
|
7037
|
+
printJson(result);
|
|
7038
|
+
return;
|
|
7039
|
+
}
|
|
7040
|
+
heading(result.dryRun ? "agent-kit update --dry-run" : "agent-kit update");
|
|
7041
|
+
const byAction = (action) => result.files.filter((file) => file.action === action).map((file) => file.target);
|
|
7042
|
+
fileGroup(result.dryRun ? "Would create" : "Created", byAction("created"));
|
|
7043
|
+
fileGroup(result.dryRun ? "Would update (pristine)" : "Updated (pristine)", byAction("updated"));
|
|
7044
|
+
fileGroup("Kept local customizations", byAction("kept-local"));
|
|
7045
|
+
fileGroup(result.dryRun ? "Would overwrite" : "Overwritten", byAction("overwritten"));
|
|
7046
|
+
const conflicts = result.files.filter((file) => file.action === "conflict");
|
|
7047
|
+
if (conflicts.length > 0) {
|
|
7048
|
+
line(`${style.bold("Conflicts")} (${conflicts.length})`);
|
|
7049
|
+
for (const file of conflicts) {
|
|
7050
|
+
line(` ${file.target}${file.conflictPath ? ` -> ${file.conflictPath}` : ""}`);
|
|
7051
|
+
}
|
|
7052
|
+
detail("Local files were kept. Review the conflict copies before adopting template changes.");
|
|
7053
|
+
}
|
|
7054
|
+
detail(`unchanged: ${result.summary.unchanged} file(s) already match the current templates`);
|
|
7055
|
+
if (!result.dryRun) {
|
|
7056
|
+
line();
|
|
7057
|
+
line(`Library folders refreshed: ${result.libraryFoldersRefreshed.length}`);
|
|
7058
|
+
line(`Manifest: ${result.manifestPath}`);
|
|
7059
|
+
}
|
|
6466
7060
|
});
|
|
6467
7061
|
var addCommand = program.command("add").description("Add one agent-kit asset.");
|
|
6468
|
-
addCommand.command("skill <name>").description("Add a single skill into .agent-kit/skills.").option("--force", "Overwrite existing skill.").action((name, options) => {
|
|
6469
|
-
|
|
7062
|
+
addCommand.command("skill <name>").description("Add a single skill into .agent-kit/skills.").option("--force", "Overwrite existing skill.").option("--dry-run", "Report what would happen without writing.").option("--json", "Print machine-readable JSON output.").action((name, options) => {
|
|
7063
|
+
const result = addSkill(process.cwd(), name, { force: Boolean(options.force), dryRun: Boolean(options.dryRun) });
|
|
7064
|
+
if (options.json) {
|
|
7065
|
+
printJson(result);
|
|
7066
|
+
return;
|
|
7067
|
+
}
|
|
7068
|
+
line(`${result.action}: ${result.target}${result.conflictPath ? ` -> ${result.conflictPath}` : ""}`);
|
|
7069
|
+
if (options.dryRun) detail("dry run: no files were written");
|
|
6470
7070
|
});
|
|
6471
|
-
program.command("doctor").description("Validate local CLI runtime prerequisites.").action(() => {
|
|
7071
|
+
program.command("doctor").description("Validate local CLI runtime prerequisites.").option("--json", "Print machine-readable JSON output.").action((options) => {
|
|
6472
7072
|
const cwd = process.cwd();
|
|
6473
|
-
|
|
6474
|
-
|
|
6475
|
-
|
|
6476
|
-
|
|
6477
|
-
|
|
6478
|
-
|
|
6479
|
-
|
|
6480
|
-
|
|
7073
|
+
const report2 = {
|
|
7074
|
+
version: PACKAGE_VERSION,
|
|
7075
|
+
node: process.version,
|
|
7076
|
+
availableSkills: listSkills().length,
|
|
7077
|
+
setupProgress: onboardingStateExists(cwd) ? getSetupProgress(cwd) : null,
|
|
7078
|
+
status: "ok"
|
|
7079
|
+
};
|
|
7080
|
+
if (options.json) {
|
|
7081
|
+
printJson(report2);
|
|
7082
|
+
return;
|
|
7083
|
+
}
|
|
7084
|
+
heading("agent-kit doctor");
|
|
7085
|
+
line(`version: ${report2.version}`);
|
|
7086
|
+
line(`node: ${report2.node}`);
|
|
7087
|
+
line(`available skills: ${report2.availableSkills}`);
|
|
7088
|
+
if (report2.setupProgress) {
|
|
7089
|
+
line(`setup progress: ${report2.setupProgress.percent}% (depth: ${report2.setupProgress.depth})`);
|
|
7090
|
+
if (!report2.setupProgress.quickComplete) {
|
|
7091
|
+
detail("run agent-kit setup --open to finish project context onboarding.");
|
|
6481
7092
|
}
|
|
6482
7093
|
} else {
|
|
6483
|
-
|
|
7094
|
+
detail("run agent-kit init then agent-kit setup to onboard this project.");
|
|
6484
7095
|
}
|
|
6485
|
-
|
|
7096
|
+
line(`status: ${style.pass(report2.status)}`);
|
|
6486
7097
|
});
|
|
6487
7098
|
function printValidationReport(report2, json) {
|
|
6488
7099
|
if (json) {
|
|
@@ -6515,8 +7126,19 @@ packageCommand.command("validate").description("Validate package assets, runtime
|
|
|
6515
7126
|
printValidationReport(report2, Boolean(options.json));
|
|
6516
7127
|
if (report2.summary.fail > 0) process.exitCode = 1;
|
|
6517
7128
|
});
|
|
6518
|
-
program.command("onboard").description("Create or refresh local project context files for installed agents.").option("--refresh", "Refresh inferred context from the current project state.").action(() => {
|
|
6519
|
-
|
|
7129
|
+
program.command("onboard").description("Create or refresh local project context files for installed agents.").option("--refresh", "Refresh inferred context from the current project state.").option("--json", "Print machine-readable JSON output.").action((options) => {
|
|
7130
|
+
const result = initProjectContext(process.cwd());
|
|
7131
|
+
if (options.json) {
|
|
7132
|
+
printJson(result);
|
|
7133
|
+
return;
|
|
7134
|
+
}
|
|
7135
|
+
heading("agent-kit onboard");
|
|
7136
|
+
line(`Context: ${result.contextPath}`);
|
|
7137
|
+
line(`Markdown: ${result.markdownPath}`);
|
|
7138
|
+
if (result.openQuestions.length > 0) {
|
|
7139
|
+
line("Open questions:");
|
|
7140
|
+
for (const question of result.openQuestions) listItem(question);
|
|
7141
|
+
}
|
|
6520
7142
|
});
|
|
6521
7143
|
program.command("setup").description("Start the local Agent Office setup view for project context.").option("--port <number>", "Port to listen on.", (value) => Number.parseInt(value, 10), 9321).option("--host <host>", "Host to bind.", "127.0.0.1").option("--open", "Open the wizard in your default browser.").option("--status", "Print setup progress and exit.").action(async (options) => {
|
|
6522
7144
|
const cwd = process.cwd();
|
|
@@ -6529,140 +7151,194 @@ program.command("setup").description("Start the local Agent Office setup view fo
|
|
|
6529
7151
|
await runSetupServer({ port: options.port, host: options.host, open: Boolean(options.open) });
|
|
6530
7152
|
});
|
|
6531
7153
|
var context = program.command("context").description("Manage local project context for Agent Studio.");
|
|
6532
|
-
context.command("init").description("Create project context from a local scan.").action(() => {
|
|
6533
|
-
|
|
7154
|
+
context.command("init").description("Create project context from a local scan.").option("--json", "Print machine-readable JSON output.").action((options) => {
|
|
7155
|
+
const result = initProjectContext(process.cwd());
|
|
7156
|
+
if (options.json) {
|
|
7157
|
+
printJson(result);
|
|
7158
|
+
return;
|
|
7159
|
+
}
|
|
7160
|
+
line(`Context written: ${result.contextPath}`);
|
|
7161
|
+
if (result.openQuestions.length > 0) {
|
|
7162
|
+
line("Open questions:");
|
|
7163
|
+
for (const question of result.openQuestions) listItem(question);
|
|
7164
|
+
}
|
|
6534
7165
|
});
|
|
6535
7166
|
context.command("scan").description("Print inferred project context without writing it.").action(() => {
|
|
6536
|
-
|
|
7167
|
+
printJson(scanProjectContext(process.cwd()));
|
|
6537
7168
|
});
|
|
6538
7169
|
context.command("ask").description("Print unanswered high-value project context questions.").action(() => {
|
|
6539
7170
|
const result = initProjectContext(process.cwd());
|
|
6540
7171
|
if (result.openQuestions.length === 0) {
|
|
6541
|
-
|
|
7172
|
+
line("No open project-context questions.");
|
|
6542
7173
|
return;
|
|
6543
7174
|
}
|
|
6544
|
-
|
|
6545
|
-
|
|
6546
|
-
for (const question of result.openQuestions)
|
|
7175
|
+
line("Answer these in the web setup wizard with: agent-kit setup --open");
|
|
7176
|
+
detail("Check progress with: agent-kit setup --status");
|
|
7177
|
+
for (const question of result.openQuestions) listItem(question);
|
|
6547
7178
|
});
|
|
6548
|
-
context.command("render").description("Render .agent-kit/project-context.md from project-context.json.").action(() => {
|
|
6549
|
-
|
|
7179
|
+
context.command("render").description("Render .agent-kit/project-context.md from project-context.json.").option("--json", "Print machine-readable JSON output.").action((options) => {
|
|
7180
|
+
const result = renderProjectContext(process.cwd());
|
|
7181
|
+
if (options.json) {
|
|
7182
|
+
printJson(result);
|
|
7183
|
+
return;
|
|
7184
|
+
}
|
|
7185
|
+
line(`Rendered: ${result.markdownPath}`);
|
|
6550
7186
|
});
|
|
6551
|
-
context.command("validate").description("Validate .agent-kit/project-context.json.").action(() => {
|
|
6552
|
-
|
|
7187
|
+
context.command("validate").description("Validate .agent-kit/project-context.json.").option("--json", "Print machine-readable JSON output.").action((options) => {
|
|
7188
|
+
const result = validateProjectContext(process.cwd());
|
|
7189
|
+
if (options.json) {
|
|
7190
|
+
printJson(result);
|
|
7191
|
+
return;
|
|
7192
|
+
}
|
|
7193
|
+
line(`Valid: ${result.contextPath}`);
|
|
7194
|
+
if (result.openQuestions.length > 0) {
|
|
7195
|
+
line("Open questions:");
|
|
7196
|
+
for (const question of result.openQuestions) listItem(question);
|
|
7197
|
+
}
|
|
6553
7198
|
});
|
|
6554
7199
|
context.command("show").description("Print rendered project context markdown.").action(() => {
|
|
6555
7200
|
console.log(readTextFile(process.cwd(), ".agent-kit/project-context.md") ?? "");
|
|
6556
7201
|
});
|
|
6557
7202
|
var session = program.command("session").description("Record and render local Agent Studio council sessions.");
|
|
6558
|
-
session.command("start <title...>").description("Start a local council session.").option("--workflow <workflow>", "Workflow id.", "planning").option("--request <request>", "Original user request.").action((titleParts, options) => {
|
|
7203
|
+
session.command("start <title...>").description("Start a local council session.").option("--workflow <workflow>", "Workflow id.", "planning").option("--request <request>", "Original user request.").option("--json", "Print machine-readable JSON output.").action((titleParts, options) => {
|
|
6559
7204
|
const title = titleParts.join(" ");
|
|
6560
|
-
|
|
6561
|
-
|
|
6562
|
-
|
|
6563
|
-
|
|
6564
|
-
|
|
6565
|
-
|
|
6566
|
-
|
|
6567
|
-
|
|
6568
|
-
|
|
6569
|
-
|
|
6570
|
-
);
|
|
7205
|
+
const result = startSession(process.cwd(), {
|
|
7206
|
+
title,
|
|
7207
|
+
workflowId: options.workflow,
|
|
7208
|
+
...options.request ? { request: options.request } : {}
|
|
7209
|
+
});
|
|
7210
|
+
if (options.json) {
|
|
7211
|
+
printJson(result);
|
|
7212
|
+
return;
|
|
7213
|
+
}
|
|
7214
|
+
line(`Session started: ${result.sessionId}`);
|
|
7215
|
+
line(`Path: ${result.sessionPath}`);
|
|
6571
7216
|
});
|
|
6572
|
-
session.command("list").description("List local council sessions.").action(() => {
|
|
6573
|
-
|
|
7217
|
+
session.command("list").description("List local council sessions.").option("--json", "Print machine-readable JSON output.").action((options) => {
|
|
7218
|
+
const sessions = listSessions(process.cwd());
|
|
7219
|
+
if (options.json) {
|
|
7220
|
+
printJson(sessions);
|
|
7221
|
+
return;
|
|
7222
|
+
}
|
|
7223
|
+
if (sessions.length === 0) {
|
|
7224
|
+
line("No sessions yet. Start one with agent-kit session start <title>.");
|
|
7225
|
+
return;
|
|
7226
|
+
}
|
|
7227
|
+
for (const item of sessions) {
|
|
7228
|
+
line(`${item.sessionId} [${item.status}] ${item.title}`);
|
|
7229
|
+
}
|
|
6574
7230
|
});
|
|
6575
7231
|
session.command("active").description("Print the active council session id.").action(() => {
|
|
6576
7232
|
console.log(getActiveSessionId(process.cwd()));
|
|
6577
7233
|
});
|
|
6578
|
-
session.command("note <text...>").description("Record a visible agent message.").requiredOption("--agent <agent>", "Agent id.").action((textParts, options) => {
|
|
6579
|
-
|
|
7234
|
+
session.command("note <text...>").description("Record a visible agent message.").requiredOption("--agent <agent>", "Agent id.").option("--json", "Print machine-readable JSON output.").action((textParts, options) => {
|
|
7235
|
+
const result = recordNote(process.cwd(), options.agent, textParts.join(" "));
|
|
7236
|
+
if (options.json) printJson(result);
|
|
7237
|
+
else line(`Recorded note from ${options.agent}.`);
|
|
6580
7238
|
});
|
|
6581
|
-
session.command("decision <text...>").description("Record an agent decision.").requiredOption("--agent <agent>", "Agent id.").option("--risk <risk>", "Risk associated with the decision.").action((textParts, options) => {
|
|
6582
|
-
|
|
7239
|
+
session.command("decision <text...>").description("Record an agent decision.").requiredOption("--agent <agent>", "Agent id.").option("--risk <risk>", "Risk associated with the decision.").option("--json", "Print machine-readable JSON output.").action((textParts, options) => {
|
|
7240
|
+
const result = recordDecision(process.cwd(), options.agent, textParts.join(" "), options.risk);
|
|
7241
|
+
if (options.json) printJson(result);
|
|
7242
|
+
else line(`Recorded decision from ${options.agent}.`);
|
|
6583
7243
|
});
|
|
6584
|
-
session.command("handoff").description("Record an agent handoff.").requiredOption("--from <agent>", "Source agent id.").requiredOption("--to <agent>", "Target agent id.").requiredOption("--decision <decision>", "Decision being handed off.").requiredOption("--risk <risk>", "Risk that remains.").option("--evidence <evidence...>", "Evidence paths or notes.").action((options) => {
|
|
6585
|
-
|
|
6586
|
-
|
|
6587
|
-
|
|
6588
|
-
|
|
6589
|
-
|
|
6590
|
-
|
|
6591
|
-
|
|
6592
|
-
|
|
6593
|
-
|
|
6594
|
-
null,
|
|
6595
|
-
2
|
|
6596
|
-
)
|
|
6597
|
-
);
|
|
7244
|
+
session.command("handoff").description("Record an agent handoff.").requiredOption("--from <agent>", "Source agent id.").requiredOption("--to <agent>", "Target agent id.").requiredOption("--decision <decision>", "Decision being handed off.").requiredOption("--risk <risk>", "Risk that remains.").option("--evidence <evidence...>", "Evidence paths or notes.").option("--json", "Print machine-readable JSON output.").action((options) => {
|
|
7245
|
+
const result = recordHandoff(process.cwd(), {
|
|
7246
|
+
fromAgentId: options.from,
|
|
7247
|
+
toAgentId: options.to,
|
|
7248
|
+
decision: options.decision,
|
|
7249
|
+
risk: options.risk,
|
|
7250
|
+
...options.evidence ? { evidence: options.evidence } : {}
|
|
7251
|
+
});
|
|
7252
|
+
if (options.json) printJson(result);
|
|
7253
|
+
else line(`Recorded handoff ${options.from} -> ${options.to}.`);
|
|
6598
7254
|
});
|
|
6599
|
-
session.command("correct <text...>").description("Record a human correction and optionally promote it to durable rules.").option("--agent <agent>", "Agent id.").option("--scope <scope>", "Correction scope: session, project, agent, upstream-proposal.", "session").action((textParts, options) => {
|
|
6600
|
-
|
|
6601
|
-
|
|
6602
|
-
|
|
6603
|
-
|
|
6604
|
-
|
|
6605
|
-
|
|
6606
|
-
|
|
6607
|
-
null,
|
|
6608
|
-
2
|
|
6609
|
-
)
|
|
6610
|
-
);
|
|
7255
|
+
session.command("correct <text...>").description("Record a human correction and optionally promote it to durable rules.").option("--agent <agent>", "Agent id.").option("--scope <scope>", "Correction scope: session, project, agent, upstream-proposal.", "session").option("--json", "Print machine-readable JSON output.").action((textParts, options) => {
|
|
7256
|
+
const result = recordCorrection(process.cwd(), {
|
|
7257
|
+
...options.agent ? { agentId: options.agent } : {},
|
|
7258
|
+
scope: options.scope,
|
|
7259
|
+
text: textParts.join(" ")
|
|
7260
|
+
});
|
|
7261
|
+
if (options.json) printJson(result);
|
|
7262
|
+
else line(`Recorded ${options.scope}-scoped correction.`);
|
|
6611
7263
|
});
|
|
6612
|
-
session.command("artifact").description("Record a changed or relevant artifact path.").requiredOption("--file <file>", "Artifact file path.").option("--note <note>", "Artifact note.").action((options) => {
|
|
6613
|
-
|
|
7264
|
+
session.command("artifact").description("Record a changed or relevant artifact path.").requiredOption("--file <file>", "Artifact file path.").option("--note <note>", "Artifact note.").option("--json", "Print machine-readable JSON output.").action((options) => {
|
|
7265
|
+
const result = recordArtifact(process.cwd(), options.file, options.note);
|
|
7266
|
+
if (options.json) printJson(result);
|
|
7267
|
+
else line(`Recorded artifact ${options.file}.`);
|
|
6614
7268
|
});
|
|
6615
|
-
session.command("verify").description("Record verification evidence.").requiredOption("--command <command>", "Command or review performed.").requiredOption("--result <result>", "pass, fail, or skipped.").option("--notes <notes>", "Verification notes.").action((options) => {
|
|
6616
|
-
|
|
7269
|
+
session.command("verify").description("Record verification evidence.").requiredOption("--command <command>", "Command or review performed.").requiredOption("--result <result>", "pass, fail, or skipped.").option("--notes <notes>", "Verification notes.").option("--json", "Print machine-readable JSON output.").action((options) => {
|
|
7270
|
+
const result = recordVerification(process.cwd(), options.command, options.result, options.notes);
|
|
7271
|
+
if (options.json) printJson(result);
|
|
7272
|
+
else line(`Recorded verification (${options.result}): ${options.command}`);
|
|
6617
7273
|
});
|
|
6618
|
-
session.command("output <name...>").description("Mark a required session output status.").requiredOption("--status <status>", "missing, partial, complete, or not-applicable.").option("--evidence <evidence>", "Evidence path, command, or note.").action((nameParts, options) => {
|
|
7274
|
+
session.command("output <name...>").description("Mark a required session output status.").requiredOption("--status <status>", "missing, partial, complete, or not-applicable.").option("--evidence <evidence>", "Evidence path, command, or note.").option("--json", "Print machine-readable JSON output.").action((nameParts, options) => {
|
|
6619
7275
|
if (!isRequiredOutputStatus(options.status)) {
|
|
6620
|
-
|
|
7276
|
+
fail(`Invalid --status value "${options.status}". Expected one of: ${requiredOutputStatuses.join(", ")}.`);
|
|
6621
7277
|
process.exitCode = 1;
|
|
6622
7278
|
return;
|
|
6623
7279
|
}
|
|
6624
|
-
|
|
7280
|
+
const result = recordRequiredOutput(process.cwd(), nameParts.join(" "), options.status, options.evidence);
|
|
7281
|
+
if (options.json) printJson(result);
|
|
7282
|
+
else line(`Marked "${nameParts.join(" ")}" as ${options.status}.`);
|
|
6625
7283
|
});
|
|
6626
|
-
session.command("render").description("Render active session Markdown files.").action(() => {
|
|
6627
|
-
|
|
7284
|
+
session.command("render").description("Render active session Markdown files.").option("--json", "Print machine-readable JSON output.").action((options) => {
|
|
7285
|
+
const result = renderActiveSession(process.cwd());
|
|
7286
|
+
if (options.json) printJson(result);
|
|
7287
|
+
else line(`Rendered session ${result.sessionId} at ${result.sessionPath}.`);
|
|
6628
7288
|
});
|
|
6629
7289
|
session.command("checkpoint").description("Apply a batch of session events from a JSON or Markdown checkpoint file.").requiredOption("--file <file>", "Checkpoint file (.json or .md) relative to the project root.").action((options) => {
|
|
6630
7290
|
console.log(JSON.stringify(checkpointSessionFromFile(process.cwd(), options.file), null, 2));
|
|
6631
7291
|
});
|
|
6632
|
-
session.command("close").description("Close the active session.").option("--status <status>", "planned, in-progress, blocked, or complete.", "complete").action((options) => {
|
|
6633
|
-
|
|
7292
|
+
session.command("close").description("Close the active session.").option("--status <status>", "planned, in-progress, blocked, or complete.", "complete").option("--json", "Print machine-readable JSON output.").action((options) => {
|
|
7293
|
+
const result = closeSession(process.cwd(), options.status);
|
|
7294
|
+
if (options.json) printJson(result);
|
|
7295
|
+
else line(`Closed session ${result.sessionId} with status ${options.status}.`);
|
|
6634
7296
|
});
|
|
6635
7297
|
var correction = program.command("correction").description("Manage durable Agent Studio correction rules.");
|
|
6636
|
-
correction.command("list").description("List correction rules.").action(() => {
|
|
6637
|
-
|
|
7298
|
+
correction.command("list").description("List correction rules.").option("--json", "Print machine-readable JSON output.").action((options) => {
|
|
7299
|
+
const corrections = listCorrections(process.cwd());
|
|
7300
|
+
if (options.json) {
|
|
7301
|
+
printJson(corrections);
|
|
7302
|
+
return;
|
|
7303
|
+
}
|
|
7304
|
+
const rules = [...corrections.project, ...corrections.agent, ...corrections.upstream];
|
|
7305
|
+
if (rules.length === 0) {
|
|
7306
|
+
line("No correction rules yet. Add one with agent-kit correction add <text>.");
|
|
7307
|
+
return;
|
|
7308
|
+
}
|
|
7309
|
+
for (const rule of rules) {
|
|
7310
|
+
line(`${rule.id} [${rule.status}] (${rule.scope}) ${rule.text}`);
|
|
7311
|
+
}
|
|
6638
7312
|
});
|
|
6639
|
-
correction.command("add <text...>").description("Add a durable correction rule.").option("--scope <scope>", "Correction scope: project, agent, or upstream-proposal.", "project").option("--agent <agent>", "Agent id for agent-scoped corrections.").action((textParts, options) => {
|
|
6640
|
-
|
|
6641
|
-
|
|
6642
|
-
|
|
6643
|
-
|
|
6644
|
-
|
|
6645
|
-
|
|
6646
|
-
|
|
6647
|
-
null,
|
|
6648
|
-
2
|
|
6649
|
-
)
|
|
6650
|
-
);
|
|
7313
|
+
correction.command("add <text...>").description("Add a durable correction rule.").option("--scope <scope>", "Correction scope: project, agent, or upstream-proposal.", "project").option("--agent <agent>", "Agent id for agent-scoped corrections.").option("--json", "Print machine-readable JSON output.").action((textParts, options) => {
|
|
7314
|
+
const result = addCorrection(process.cwd(), {
|
|
7315
|
+
scope: options.scope,
|
|
7316
|
+
...options.agent ? { agentId: options.agent } : {},
|
|
7317
|
+
text: textParts.join(" ")
|
|
7318
|
+
});
|
|
7319
|
+
if (options.json) printJson(result);
|
|
7320
|
+
else line(`Added ${options.scope}-scoped correction ${result.id}.`);
|
|
6651
7321
|
});
|
|
6652
|
-
correction.command("apply [id]").description("Mark a correction rule active and reviewed.").option("--id <id>", "Correction id.").action((idArgument, options) => {
|
|
7322
|
+
correction.command("apply [id]").description("Mark a correction rule active and reviewed.").option("--id <id>", "Correction id.").option("--json", "Print machine-readable JSON output.").action((idArgument, options) => {
|
|
6653
7323
|
const id = idArgument ?? options.id;
|
|
6654
7324
|
if (!id) {
|
|
6655
|
-
|
|
7325
|
+
fail("Missing correction id. Use agent-kit correction apply <id> or --id <id>.");
|
|
6656
7326
|
process.exitCode = 1;
|
|
6657
7327
|
return;
|
|
6658
7328
|
}
|
|
6659
|
-
|
|
7329
|
+
const result = applyCorrection(process.cwd(), id);
|
|
7330
|
+
if (options.json) printJson(result);
|
|
7331
|
+
else line(`Applied correction ${id}.`);
|
|
6660
7332
|
});
|
|
6661
|
-
correction.command("retire <id>").description("Retire a correction rule.").requiredOption("--reason <reason>", "Reason for retirement.").action((id, options) => {
|
|
6662
|
-
|
|
7333
|
+
correction.command("retire <id>").description("Retire a correction rule.").requiredOption("--reason <reason>", "Reason for retirement.").option("--json", "Print machine-readable JSON output.").action((id, options) => {
|
|
7334
|
+
const result = retireCorrection(process.cwd(), id, options.reason);
|
|
7335
|
+
if (options.json) printJson(result);
|
|
7336
|
+
else line(`Retired correction ${id}: ${options.reason}`);
|
|
6663
7337
|
});
|
|
6664
|
-
correction.command("propose-upstream <id>").description("Create an upstream proposal from a project or agent correction.").action((id) => {
|
|
6665
|
-
|
|
7338
|
+
correction.command("propose-upstream <id>").description("Create an upstream proposal from a project or agent correction.").option("--json", "Print machine-readable JSON output.").action((id, options) => {
|
|
7339
|
+
const result = proposeCorrectionUpstream(process.cwd(), id);
|
|
7340
|
+
if (options.json) printJson(result);
|
|
7341
|
+
else line(`Created upstream proposal from correction ${id}.`);
|
|
6666
7342
|
});
|
|
6667
7343
|
var studio = program.command("studio").description("Export and serve local Agent Studio views.");
|
|
6668
7344
|
async function runStudioServer(options) {
|
|
@@ -6672,16 +7348,14 @@ async function runStudioServer(options) {
|
|
|
6672
7348
|
host: options.host
|
|
6673
7349
|
});
|
|
6674
7350
|
if (handle.portFallback) {
|
|
6675
|
-
console.warn(
|
|
6676
|
-
`Port ${handle.requestedPort} is in use \u2014 using fallback port ${handle.port}. Kill the old process to avoid confusion.`
|
|
6677
|
-
);
|
|
7351
|
+
console.warn(`Port ${handle.requestedPort} is in use \u2014 using fallback port ${handle.port}. Kill the old process to avoid confusion.`);
|
|
6678
7352
|
}
|
|
6679
7353
|
console.log(`Agent Kit v${PACKAGE_VERSION} \u2014 live studio at ${handle.url}/`);
|
|
6680
7354
|
console.log("SSE: GET /api/events/stream | Press Ctrl+C to stop.");
|
|
6681
|
-
if (options.open) openBrowser(`${handle.url}/`);
|
|
7355
|
+
if (options.open) void openBrowser(`${handle.url}/`);
|
|
6682
7356
|
await new Promise((resolve3) => {
|
|
6683
7357
|
const shutdown = () => {
|
|
6684
|
-
handle.close().finally(resolve3);
|
|
7358
|
+
void handle.close().finally(resolve3);
|
|
6685
7359
|
};
|
|
6686
7360
|
process.once("SIGINT", shutdown);
|
|
6687
7361
|
process.once("SIGTERM", shutdown);
|
|
@@ -6690,8 +7364,13 @@ async function runStudioServer(options) {
|
|
|
6690
7364
|
studio.command("serve").description("Start localhost live Agent Studio viewer with SSE session events.").option("--port <number>", "Port to listen on.", (value) => Number.parseInt(value, 10), 9331).option("--host <host>", "Host to bind.", "127.0.0.1").option("--open", "Open the studio in your default browser.").action(async (options) => {
|
|
6691
7365
|
await runStudioServer(options);
|
|
6692
7366
|
});
|
|
6693
|
-
studio.command("export").description("Generate a self-contained static Agent Studio HTML file.").action(() => {
|
|
6694
|
-
|
|
7367
|
+
studio.command("export").description("Generate a self-contained static Agent Studio HTML file.").option("--json", "Print machine-readable JSON output.").action((options) => {
|
|
7368
|
+
const result = exportStaticStudio(process.cwd());
|
|
7369
|
+
if (options.json) {
|
|
7370
|
+
printJson(result);
|
|
7371
|
+
return;
|
|
7372
|
+
}
|
|
7373
|
+
line(`Exported ${result.sessionCount} session(s) to ${result.studioPath}.`);
|
|
6695
7374
|
});
|
|
6696
7375
|
var research = program.command("research").description("Research high-quality open-source repositories.");
|
|
6697
7376
|
research.command("discover").description("Discover GitHub repo candidates using configured queries.").option("--limit <number>", "Maximum repositories to write.", (value) => Number.parseInt(value, 10)).action(async (options) => {
|
|
@@ -6713,7 +7392,7 @@ research.command("propose-updates").description("Create a research-to-template u
|
|
|
6713
7392
|
console.log(proposeUpdates(process.cwd()));
|
|
6714
7393
|
});
|
|
6715
7394
|
program.parseAsync(process.argv).catch((error) => {
|
|
6716
|
-
|
|
7395
|
+
fail(error instanceof Error ? error.message : String(error));
|
|
6717
7396
|
process.exitCode = 1;
|
|
6718
7397
|
});
|
|
6719
7398
|
//# sourceMappingURL=index.js.map
|