@veewo/claw-core 0.1.59 → 0.1.61
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/README.md +16 -16
- package/dist/src/context.js +0 -1
- package/dist/src/context.js.map +1 -1
- package/dist/src/embedding-config.d.ts +9 -0
- package/dist/src/embedding-config.js +21 -0
- package/dist/src/embedding-config.js.map +1 -0
- package/dist/src/errors.d.ts +1 -1
- package/dist/src/errors.js.map +1 -1
- package/dist/src/index.d.ts +0 -1
- package/dist/src/index.js +0 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/init.js +0 -1
- package/dist/src/init.js.map +1 -1
- package/dist/src/io.d.ts +0 -4
- package/dist/src/io.js +0 -55
- package/dist/src/io.js.map +1 -1
- package/dist/src/paths.d.ts +0 -1
- package/dist/src/paths.js +1 -25
- package/dist/src/paths.js.map +1 -1
- package/dist/src/plan-templates.d.ts +2 -25
- package/dist/src/plan-templates.js +28 -582
- package/dist/src/plan-templates.js.map +1 -1
- package/dist/src/plan.js +213 -301
- package/dist/src/plan.js.map +1 -1
- package/dist/src/project-check.js +0 -10
- package/dist/src/project-check.js.map +1 -1
- package/dist/src/project-config-defaults.d.ts +6 -0
- package/dist/src/project-config-defaults.js +5 -0
- package/dist/src/project-config-defaults.js.map +1 -0
- package/dist/src/templates/plans/default.d.ts +14 -44
- package/dist/src/templates/plans/default.js +10 -44
- package/dist/src/templates/plans/default.js.map +1 -1
- package/dist/src/types.d.ts +1 -15
- package/dist/src/workflow-guidance.config.json +366 -367
- package/dist/src/workflow-guidance.d.ts +1 -2
- package/dist/src/workflow-guidance.js +21 -166
- package/dist/src/workflow-guidance.js.map +1 -1
- package/package.json +44 -44
- package/dist/src/effective-config.d.ts +0 -2
- package/dist/src/effective-config.js +0 -10
- package/dist/src/effective-config.js.map +0 -1
|
@@ -1,81 +1,26 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
|
-
import os from "node:os";
|
|
3
2
|
import path from "node:path";
|
|
4
3
|
import { pathToFileURL } from "node:url";
|
|
5
4
|
import { ClawError } from "./errors.js";
|
|
6
|
-
import { defaultPlanTemplate
|
|
7
|
-
const PLAN_TEMPLATES = [
|
|
5
|
+
import { defaultPlanTemplate } from "./templates/plans/default.js";
|
|
6
|
+
const PLAN_TEMPLATES = [defaultPlanTemplate];
|
|
8
7
|
export async function resolveSeedPlanTemplate(params) {
|
|
9
8
|
const normalized = params.templateName?.trim().toLowerCase() || defaultPlanTemplate.id;
|
|
10
|
-
const projectTemplate = params.projectRoot ? await
|
|
9
|
+
const projectTemplate = params.projectRoot ? await loadProjectSeedTemplate(params.projectRoot, normalized) : null;
|
|
11
10
|
if (projectTemplate) {
|
|
12
11
|
return projectTemplate;
|
|
13
12
|
}
|
|
14
|
-
const
|
|
15
|
-
if (projectSkillTemplate) {
|
|
16
|
-
return projectSkillTemplate;
|
|
17
|
-
}
|
|
18
|
-
const projectPackageTemplate = params.projectRoot ? await loadProjectPackagePlanTemplate(params.projectRoot, normalized) : null;
|
|
19
|
-
if (projectPackageTemplate) {
|
|
20
|
-
return projectPackageTemplate;
|
|
21
|
-
}
|
|
22
|
-
const globalTemplate = await loadGlobalPlanTemplate(normalized);
|
|
23
|
-
if (globalTemplate) {
|
|
24
|
-
return globalTemplate;
|
|
25
|
-
}
|
|
26
|
-
const globalSkillTemplate = await loadGlobalSkillPlanTemplate(normalized);
|
|
27
|
-
if (globalSkillTemplate) {
|
|
28
|
-
return globalSkillTemplate;
|
|
29
|
-
}
|
|
30
|
-
const globalPackageTemplate = await loadGlobalPackagePlanTemplate(normalized);
|
|
31
|
-
if (globalPackageTemplate) {
|
|
32
|
-
return globalPackageTemplate;
|
|
33
|
-
}
|
|
34
|
-
const match = PLAN_TEMPLATES.find((template) => template.id.toLowerCase() === normalized);
|
|
13
|
+
const match = PLAN_TEMPLATES.find((template) => template.id.toLowerCase() === normalized || template.aliases.some((alias) => alias.toLowerCase() === normalized));
|
|
35
14
|
if (!match) {
|
|
36
15
|
throw new ClawError("PROJECT_CONFIG_INVALID", `Unknown plan template "${params.templateName ?? normalized}".`, {
|
|
37
16
|
templateName: params.templateName ?? normalized,
|
|
38
|
-
availableTemplates: PLAN_TEMPLATES.
|
|
17
|
+
availableTemplates: PLAN_TEMPLATES.flatMap((template) => [template.id, ...template.aliases]),
|
|
39
18
|
});
|
|
40
19
|
}
|
|
41
20
|
return match;
|
|
42
21
|
}
|
|
43
|
-
|
|
44
|
-
const
|
|
45
|
-
? JSON.parse(fs.readFileSync(templatePath, "utf-8"))
|
|
46
|
-
: await import(pathToFileURL(templatePath).href).then((module) => module.default ?? module);
|
|
47
|
-
return validatePlanTemplateSource(raw, templatePath, "project");
|
|
48
|
-
}
|
|
49
|
-
export function validatePlanTemplateSource(raw, templatePath, source = "project") {
|
|
50
|
-
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
51
|
-
throw new ClawError("PROJECT_CONFIG_INVALID", `Invalid plan template at ${templatePath}.`, {
|
|
52
|
-
templatePath,
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
return normalizePlanLikeTemplate(validatePlanLikeTemplate(raw, templatePath), {
|
|
56
|
-
source,
|
|
57
|
-
templatePath: source === "project" ? templatePath : undefined,
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
async function loadProjectPlanTemplate(projectRoot, normalizedTemplateName) {
|
|
61
|
-
return loadPlanTemplateFromDirectory(path.join(projectRoot, ".claw", "templates"), normalizedTemplateName);
|
|
62
|
-
}
|
|
63
|
-
async function loadProjectSkillPlanTemplate(projectRoot, normalizedTemplateName) {
|
|
64
|
-
return loadPlanTemplateFromSkillRoots(resolveProjectSkillRoots(projectRoot), normalizedTemplateName);
|
|
65
|
-
}
|
|
66
|
-
async function loadProjectPackagePlanTemplate(projectRoot, normalizedTemplateName) {
|
|
67
|
-
return loadPlanTemplateFromTemplateDirs(resolveProjectPackageTemplateDirs(projectRoot), normalizedTemplateName);
|
|
68
|
-
}
|
|
69
|
-
async function loadGlobalPlanTemplate(normalizedTemplateName) {
|
|
70
|
-
return loadPlanTemplateFromDirectory(path.join(os.homedir(), ".claw", "templates"), normalizedTemplateName);
|
|
71
|
-
}
|
|
72
|
-
async function loadGlobalSkillPlanTemplate(normalizedTemplateName) {
|
|
73
|
-
return loadPlanTemplateFromSkillRoots(resolveGlobalSkillRoots(), normalizedTemplateName);
|
|
74
|
-
}
|
|
75
|
-
async function loadGlobalPackagePlanTemplate(normalizedTemplateName) {
|
|
76
|
-
return loadPlanTemplateFromTemplateDirs(resolveGlobalPackageTemplateDirs(), normalizedTemplateName);
|
|
77
|
-
}
|
|
78
|
-
async function loadPlanTemplateFromDirectory(templatesDir, normalizedTemplateName) {
|
|
22
|
+
async function loadProjectSeedTemplate(projectRoot, normalizedTemplateName) {
|
|
23
|
+
const templatesDir = path.join(projectRoot, ".claw", "templates");
|
|
79
24
|
if (!fs.existsSync(templatesDir)) {
|
|
80
25
|
return null;
|
|
81
26
|
}
|
|
@@ -95,533 +40,34 @@ async function loadPlanTemplateFromDirectory(templatesDir, normalizedTemplateNam
|
|
|
95
40
|
candidatePaths: candidateEntries.map((entryName) => path.join(templatesDir, entryName)),
|
|
96
41
|
});
|
|
97
42
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
const match = await loadPlanTemplateFromDirectory(templateDir, normalizedTemplateName);
|
|
104
|
-
if (match?.templatePath) {
|
|
105
|
-
matches.push(match.templatePath);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
if (matches.length > 1) {
|
|
109
|
-
throw new ClawError("PROJECT_CONFIG_INVALID", `Multiple package plan templates matched "${normalizedTemplateName}".`, {
|
|
110
|
-
templateName: normalizedTemplateName,
|
|
111
|
-
candidatePaths: matches,
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
return matches.length === 1 ? resolvePlanTemplateFile(matches[0]) : null;
|
|
115
|
-
}
|
|
116
|
-
async function loadPlanTemplateFromSkillRoots(skillRoots, normalizedTemplateName) {
|
|
117
|
-
const matches = [];
|
|
118
|
-
for (const skillRoot of skillRoots) {
|
|
119
|
-
for (const templatePath of collectSkillTemplateFiles(skillRoot)) {
|
|
120
|
-
const template = await resolvePlanTemplateFile(templatePath);
|
|
121
|
-
if (template.id.toLowerCase() === normalizedTemplateName) {
|
|
122
|
-
matches.push({ path: templatePath, signature: signatureForTemplateConflict(template) });
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
if (matches.length > 1) {
|
|
127
|
-
const uniqueSignatures = new Set(matches.map((match) => match.signature));
|
|
128
|
-
if (uniqueSignatures.size === 1) {
|
|
129
|
-
return resolvePlanTemplateFile(matches[0].path);
|
|
130
|
-
}
|
|
131
|
-
throw new ClawError("PROJECT_CONFIG_INVALID", `Multiple skill-local plan templates matched "${normalizedTemplateName}".`, {
|
|
132
|
-
templateName: normalizedTemplateName,
|
|
133
|
-
candidatePaths: matches.map((match) => match.path),
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
return matches.length === 1 ? resolvePlanTemplateFile(matches[0].path) : null;
|
|
137
|
-
}
|
|
138
|
-
function signatureForTemplateConflict(template) {
|
|
139
|
-
const { source: _source, templatePath: _templatePath, ...portableTemplate } = template;
|
|
140
|
-
return JSON.stringify(portableTemplate);
|
|
141
|
-
}
|
|
142
|
-
function resolveProjectSkillRoots(projectRoot) {
|
|
143
|
-
const roots = [path.join(projectRoot, "skills")];
|
|
144
|
-
const packagesDir = path.join(projectRoot, "packages");
|
|
145
|
-
if (!fs.existsSync(packagesDir)) {
|
|
146
|
-
return roots;
|
|
147
|
-
}
|
|
148
|
-
for (const entry of fs.readdirSync(packagesDir, { withFileTypes: true })) {
|
|
149
|
-
if (!entry.isDirectory()) {
|
|
150
|
-
continue;
|
|
151
|
-
}
|
|
152
|
-
roots.push(path.join(packagesDir, entry.name, "skills"));
|
|
153
|
-
}
|
|
154
|
-
return roots;
|
|
155
|
-
}
|
|
156
|
-
function resolveProjectPackageTemplateDirs(projectRoot) {
|
|
157
|
-
const templateDirs = [];
|
|
158
|
-
const packagesDir = path.join(projectRoot, "packages");
|
|
159
|
-
if (!fs.existsSync(packagesDir)) {
|
|
160
|
-
return templateDirs;
|
|
161
|
-
}
|
|
162
|
-
for (const entry of fs.readdirSync(packagesDir, { withFileTypes: true })) {
|
|
163
|
-
if (!entry.isDirectory()) {
|
|
164
|
-
continue;
|
|
165
|
-
}
|
|
166
|
-
templateDirs.push(path.join(packagesDir, entry.name, "templates"));
|
|
167
|
-
}
|
|
168
|
-
return templateDirs;
|
|
169
|
-
}
|
|
170
|
-
function resolveGlobalSkillRoots() {
|
|
171
|
-
const homeDir = os.homedir();
|
|
172
|
-
const roots = [
|
|
173
|
-
path.join(homeDir, ".agents", "skills"),
|
|
174
|
-
path.join(homeDir, ".codex", "skills"),
|
|
175
|
-
];
|
|
176
|
-
const cacheRoot = path.join(homeDir, ".codex", "plugins", "cache");
|
|
177
|
-
if (fs.existsSync(cacheRoot)) {
|
|
178
|
-
for (const vendor of fs.readdirSync(cacheRoot, { withFileTypes: true })) {
|
|
179
|
-
if (!vendor.isDirectory()) {
|
|
180
|
-
continue;
|
|
181
|
-
}
|
|
182
|
-
const vendorDir = path.join(cacheRoot, vendor.name);
|
|
183
|
-
for (const plugin of fs.readdirSync(vendorDir, { withFileTypes: true })) {
|
|
184
|
-
if (!plugin.isDirectory()) {
|
|
185
|
-
continue;
|
|
186
|
-
}
|
|
187
|
-
const pluginDir = path.join(vendorDir, plugin.name);
|
|
188
|
-
roots.push(path.join(pluginDir, "skills"));
|
|
189
|
-
for (const version of fs.readdirSync(pluginDir, { withFileTypes: true })) {
|
|
190
|
-
if (!version.isDirectory()) {
|
|
191
|
-
continue;
|
|
192
|
-
}
|
|
193
|
-
roots.push(path.join(pluginDir, version.name, "skills"));
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
return roots;
|
|
199
|
-
}
|
|
200
|
-
function resolveGlobalPackageTemplateDirs() {
|
|
201
|
-
const homeDir = os.homedir();
|
|
202
|
-
const templateDirs = [];
|
|
203
|
-
const cacheRoot = path.join(homeDir, ".codex", "plugins", "cache");
|
|
204
|
-
if (!fs.existsSync(cacheRoot)) {
|
|
205
|
-
return templateDirs;
|
|
206
|
-
}
|
|
207
|
-
for (const vendor of fs.readdirSync(cacheRoot, { withFileTypes: true })) {
|
|
208
|
-
if (!vendor.isDirectory()) {
|
|
209
|
-
continue;
|
|
210
|
-
}
|
|
211
|
-
const vendorDir = path.join(cacheRoot, vendor.name);
|
|
212
|
-
for (const plugin of fs.readdirSync(vendorDir, { withFileTypes: true })) {
|
|
213
|
-
if (!plugin.isDirectory()) {
|
|
214
|
-
continue;
|
|
215
|
-
}
|
|
216
|
-
const pluginDir = path.join(vendorDir, plugin.name);
|
|
217
|
-
templateDirs.push(path.join(pluginDir, "templates"));
|
|
218
|
-
for (const version of fs.readdirSync(pluginDir, { withFileTypes: true })) {
|
|
219
|
-
if (!version.isDirectory()) {
|
|
220
|
-
continue;
|
|
221
|
-
}
|
|
222
|
-
templateDirs.push(path.join(pluginDir, version.name, "templates"));
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
return templateDirs;
|
|
227
|
-
}
|
|
228
|
-
function collectSkillTemplateFiles(skillRoot) {
|
|
229
|
-
if (!fs.existsSync(skillRoot)) {
|
|
230
|
-
return [];
|
|
231
|
-
}
|
|
232
|
-
const templateFiles = [];
|
|
233
|
-
for (const entry of fs.readdirSync(skillRoot, { withFileTypes: true })) {
|
|
234
|
-
if (!entry.isDirectory()) {
|
|
235
|
-
continue;
|
|
236
|
-
}
|
|
237
|
-
const skillDir = path.join(skillRoot, entry.name);
|
|
238
|
-
for (const candidateName of [
|
|
239
|
-
"TEMPLATE.json",
|
|
240
|
-
"TEMPLATE.js",
|
|
241
|
-
"TEMPLATE.mjs",
|
|
242
|
-
"TEMPLATE.cjs",
|
|
243
|
-
"CLAW-TEMPLATE.json",
|
|
244
|
-
"CLAW-TEMPLATE.js",
|
|
245
|
-
"CLAW-TEMPLATE.mjs",
|
|
246
|
-
"CLAW-TEMPLATE.cjs",
|
|
247
|
-
]) {
|
|
248
|
-
const candidatePath = path.join(skillDir, candidateName);
|
|
249
|
-
if (fs.existsSync(candidatePath)) {
|
|
250
|
-
templateFiles.push(candidatePath);
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
return templateFiles;
|
|
43
|
+
const templatePath = path.join(templatesDir, candidateEntries[0]);
|
|
44
|
+
const raw = templatePath.endsWith(".json")
|
|
45
|
+
? JSON.parse(fs.readFileSync(templatePath, "utf-8"))
|
|
46
|
+
: await import(pathToFileURL(templatePath).href).then((module) => module.default ?? module);
|
|
47
|
+
return validateSeedPlanTemplate(raw, templatePath);
|
|
255
48
|
}
|
|
256
|
-
function
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
"id",
|
|
260
|
-
"configOverride",
|
|
261
|
-
"title",
|
|
262
|
-
"status",
|
|
263
|
-
"goal",
|
|
264
|
-
"requirements",
|
|
265
|
-
"tasks",
|
|
266
|
-
"references",
|
|
267
|
-
"rules",
|
|
268
|
-
"keyDecisions",
|
|
269
|
-
"retrospective",
|
|
270
|
-
]);
|
|
271
|
-
for (const key of Object.keys(candidate)) {
|
|
272
|
-
if (!allowedKeys.has(key)) {
|
|
273
|
-
throw new ClawError("PROJECT_CONFIG_INVALID", `Invalid plan-like template field "${key}" at ${templatePath}.`, {
|
|
274
|
-
templatePath,
|
|
275
|
-
field: key,
|
|
276
|
-
});
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
if (!isTemplateConfigOverride(candidate.configOverride)) {
|
|
280
|
-
throw new ClawError("PROJECT_CONFIG_INVALID", `Invalid template configOverride at ${templatePath}.`, {
|
|
281
|
-
templatePath,
|
|
282
|
-
});
|
|
283
|
-
}
|
|
284
|
-
if (typeof candidate.id !== "string" || typeof candidate.status !== "string") {
|
|
285
|
-
throw new ClawError("PROJECT_CONFIG_INVALID", `Invalid plan-like template header at ${templatePath}.`, {
|
|
286
|
-
templatePath,
|
|
287
|
-
});
|
|
288
|
-
}
|
|
289
|
-
if (candidate.title !== undefined && typeof candidate.title !== "string") {
|
|
290
|
-
throw new ClawError("PROJECT_CONFIG_INVALID", `Invalid template title at ${templatePath}.`, {
|
|
291
|
-
templatePath,
|
|
292
|
-
});
|
|
293
|
-
}
|
|
294
|
-
if (candidate.goal !== undefined) {
|
|
295
|
-
if (!candidate.goal || typeof candidate.goal !== "object" || Array.isArray(candidate.goal)) {
|
|
296
|
-
throw new ClawError("PROJECT_CONFIG_INVALID", `Invalid template goal at ${templatePath}.`, {
|
|
297
|
-
templatePath,
|
|
298
|
-
});
|
|
299
|
-
}
|
|
300
|
-
const goal = candidate.goal;
|
|
301
|
-
if (goal.text !== undefined && typeof goal.text !== "string") {
|
|
302
|
-
throw new ClawError("PROJECT_CONFIG_INVALID", `Invalid template goal.text at ${templatePath}.`, {
|
|
303
|
-
templatePath,
|
|
304
|
-
});
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
if (candidate.requirements !== undefined && !isPlanRequirements(candidate.requirements)) {
|
|
308
|
-
throw new ClawError("PROJECT_CONFIG_INVALID", `Invalid template requirements at ${templatePath}.`, {
|
|
309
|
-
templatePath,
|
|
310
|
-
});
|
|
311
|
-
}
|
|
312
|
-
if (!Array.isArray(candidate.tasks)) {
|
|
313
|
-
throw new ClawError("PROJECT_CONFIG_INVALID", `Template tasks must be an array at ${templatePath}.`, {
|
|
314
|
-
templatePath,
|
|
315
|
-
});
|
|
316
|
-
}
|
|
317
|
-
for (const task of candidate.tasks) {
|
|
318
|
-
if (!isPlanTemplateTask(task)) {
|
|
319
|
-
throw new ClawError("PROJECT_CONFIG_INVALID", `Invalid template task at ${templatePath}.`, {
|
|
320
|
-
templatePath,
|
|
321
|
-
});
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
if (candidate.references !== undefined && !isPlanReferences(candidate.references)) {
|
|
325
|
-
throw new ClawError("PROJECT_CONFIG_INVALID", `Invalid template references at ${templatePath}.`, {
|
|
326
|
-
templatePath,
|
|
327
|
-
});
|
|
328
|
-
}
|
|
329
|
-
if (candidate.rules !== undefined && (!Array.isArray(candidate.rules) || candidate.rules.some((item) => typeof item !== "string"))) {
|
|
330
|
-
throw new ClawError("PROJECT_CONFIG_INVALID", `Invalid template rules at ${templatePath}.`, {
|
|
331
|
-
templatePath,
|
|
332
|
-
});
|
|
333
|
-
}
|
|
334
|
-
if (candidate.keyDecisions !== undefined
|
|
335
|
-
&& (!Array.isArray(candidate.keyDecisions) || candidate.keyDecisions.some((item) => typeof item !== "string"))) {
|
|
336
|
-
throw new ClawError("PROJECT_CONFIG_INVALID", `Invalid template keyDecisions at ${templatePath}.`, {
|
|
49
|
+
function validateSeedPlanTemplate(raw, templatePath) {
|
|
50
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
51
|
+
throw new ClawError("PROJECT_CONFIG_INVALID", `Invalid plan template at ${templatePath}.`, {
|
|
337
52
|
templatePath,
|
|
338
53
|
});
|
|
339
54
|
}
|
|
340
|
-
|
|
341
|
-
|
|
55
|
+
const candidate = raw;
|
|
56
|
+
const aliasesValid = Array.isArray(candidate.aliases) && candidate.aliases.every((alias) => typeof alias === "string");
|
|
57
|
+
if (typeof candidate.id !== "string" ||
|
|
58
|
+
!aliasesValid ||
|
|
59
|
+
typeof candidate.planningEnabledStatus !== "string" ||
|
|
60
|
+
typeof candidate.planningDisabledStatus !== "string" ||
|
|
61
|
+
typeof candidate.planningTask?.title !== "string" ||
|
|
62
|
+
typeof candidate.planningTask?.detail !== "string" ||
|
|
63
|
+
typeof candidate.activationTask?.title !== "string" ||
|
|
64
|
+
typeof candidate.activationTask?.detail !== "string" ||
|
|
65
|
+
typeof candidate.activationTask?.goalModeDetail !== "string") {
|
|
66
|
+
throw new ClawError("PROJECT_CONFIG_INVALID", `Invalid plan template at ${templatePath}.`, {
|
|
342
67
|
templatePath,
|
|
343
68
|
});
|
|
344
69
|
}
|
|
345
|
-
return
|
|
346
|
-
}
|
|
347
|
-
function normalizePlanLikeTemplate(template, meta) {
|
|
348
|
-
return {
|
|
349
|
-
id: template.id,
|
|
350
|
-
configOverride: template.configOverride,
|
|
351
|
-
title: template.title,
|
|
352
|
-
status: template.status,
|
|
353
|
-
goal: template.goal,
|
|
354
|
-
requirements: template.requirements,
|
|
355
|
-
tasks: template.tasks,
|
|
356
|
-
references: template.references,
|
|
357
|
-
rules: template.rules,
|
|
358
|
-
keyDecisions: template.keyDecisions,
|
|
359
|
-
retrospective: template.retrospective,
|
|
360
|
-
source: meta.source,
|
|
361
|
-
templatePath: meta.templatePath,
|
|
362
|
-
};
|
|
363
|
-
}
|
|
364
|
-
export function getTemplateTaskDoneChoices(template, taskId) {
|
|
365
|
-
return getTemplateTaskGuidance(template, taskId)?.onDone?.choices;
|
|
366
|
-
}
|
|
367
|
-
export function getTemplateTaskDoneGuidanceRoute(template, taskId, choiceId) {
|
|
368
|
-
const onDone = getTemplateTaskGuidance(template, taskId)?.onDone;
|
|
369
|
-
if (!onDone) {
|
|
370
|
-
return undefined;
|
|
371
|
-
}
|
|
372
|
-
if (choiceId && onDone.choices && Object.prototype.hasOwnProperty.call(onDone.choices, choiceId)) {
|
|
373
|
-
return onDone.choices[choiceId];
|
|
374
|
-
}
|
|
375
|
-
return onDone.default;
|
|
376
|
-
}
|
|
377
|
-
export function getTemplateTaskGuidance(template, taskId) {
|
|
378
|
-
return template.tasks.find((task) => task.id === taskId)?.guidance;
|
|
379
|
-
}
|
|
380
|
-
function isPlanRequirements(value) {
|
|
381
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
382
|
-
return false;
|
|
383
|
-
}
|
|
384
|
-
const candidate = value;
|
|
385
|
-
return typeof candidate.summary === "string"
|
|
386
|
-
&& Array.isArray(candidate.openQuestions)
|
|
387
|
-
&& candidate.openQuestions.every((item) => typeof item === "string")
|
|
388
|
-
&& Array.isArray(candidate.acceptanceCriteria)
|
|
389
|
-
&& candidate.acceptanceCriteria.every((item) => typeof item === "string");
|
|
390
|
-
}
|
|
391
|
-
function isPlanReferences(value) {
|
|
392
|
-
if (!Array.isArray(value)) {
|
|
393
|
-
return false;
|
|
394
|
-
}
|
|
395
|
-
return value.every((reference) => reference
|
|
396
|
-
&& typeof reference === "object"
|
|
397
|
-
&& !Array.isArray(reference)
|
|
398
|
-
&& typeof reference.path === "string"
|
|
399
|
-
&& typeof reference.why === "string");
|
|
400
|
-
}
|
|
401
|
-
function isPlanRetrospective(value) {
|
|
402
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
403
|
-
return false;
|
|
404
|
-
}
|
|
405
|
-
const candidate = value;
|
|
406
|
-
if (typeof candidate.summary !== "string") {
|
|
407
|
-
return false;
|
|
408
|
-
}
|
|
409
|
-
for (const key of ["whatWorked", "issues", "followUps", "knowledgeCandidates"]) {
|
|
410
|
-
const field = candidate[key];
|
|
411
|
-
if (field !== undefined && (!Array.isArray(field) || field.some((item) => typeof item !== "string"))) {
|
|
412
|
-
return false;
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
return true;
|
|
416
|
-
}
|
|
417
|
-
function isPlanTemplateTask(value) {
|
|
418
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
419
|
-
return false;
|
|
420
|
-
}
|
|
421
|
-
const candidate = value;
|
|
422
|
-
const allowedKeys = new Set([
|
|
423
|
-
"id",
|
|
424
|
-
"title",
|
|
425
|
-
"detail",
|
|
426
|
-
"status",
|
|
427
|
-
"guidance",
|
|
428
|
-
"goalModeDetail",
|
|
429
|
-
"execution",
|
|
430
|
-
"sessionKey",
|
|
431
|
-
]);
|
|
432
|
-
for (const key of Object.keys(candidate)) {
|
|
433
|
-
if (!allowedKeys.has(key)) {
|
|
434
|
-
return false;
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
if (!Number.isInteger(candidate.id)) {
|
|
438
|
-
return false;
|
|
439
|
-
}
|
|
440
|
-
if (typeof candidate.title !== "string") {
|
|
441
|
-
return false;
|
|
442
|
-
}
|
|
443
|
-
if (candidate.detail !== undefined && typeof candidate.detail !== "string") {
|
|
444
|
-
return false;
|
|
445
|
-
}
|
|
446
|
-
if (candidate.status !== "pending"
|
|
447
|
-
&& candidate.status !== "in_progress"
|
|
448
|
-
&& candidate.status !== "subagent_running"
|
|
449
|
-
&& candidate.status !== "done"
|
|
450
|
-
&& candidate.status !== "blocked") {
|
|
451
|
-
return false;
|
|
452
|
-
}
|
|
453
|
-
if (!isTemplateTaskGuidance(candidate.guidance)) {
|
|
454
|
-
return false;
|
|
455
|
-
}
|
|
456
|
-
if (candidate.goalModeDetail !== undefined && typeof candidate.goalModeDetail !== "string") {
|
|
457
|
-
return false;
|
|
458
|
-
}
|
|
459
|
-
if (candidate.execution !== undefined) {
|
|
460
|
-
if (!candidate.execution || typeof candidate.execution !== "object" || Array.isArray(candidate.execution)) {
|
|
461
|
-
return false;
|
|
462
|
-
}
|
|
463
|
-
const execution = candidate.execution;
|
|
464
|
-
if (execution.type !== undefined
|
|
465
|
-
&& execution.type !== "default"
|
|
466
|
-
&& execution.type !== "subagent"
|
|
467
|
-
&& execution.type !== "subplan") {
|
|
468
|
-
return false;
|
|
469
|
-
}
|
|
470
|
-
if (execution.subplan !== undefined && typeof execution.subplan !== "string") {
|
|
471
|
-
return false;
|
|
472
|
-
}
|
|
473
|
-
if (execution.planPath !== undefined && typeof execution.planPath !== "string") {
|
|
474
|
-
return false;
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
if (candidate.sessionKey !== undefined && typeof candidate.sessionKey !== "string") {
|
|
478
|
-
return false;
|
|
479
|
-
}
|
|
480
|
-
return true;
|
|
481
|
-
}
|
|
482
|
-
function isTemplateConfigOverride(value) {
|
|
483
|
-
if (value === undefined) {
|
|
484
|
-
return true;
|
|
485
|
-
}
|
|
486
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
487
|
-
return false;
|
|
488
|
-
}
|
|
489
|
-
const allowedKeys = new Set([
|
|
490
|
-
"goalMode",
|
|
491
|
-
"truthDispatch",
|
|
492
|
-
"externalPlanningSkill",
|
|
493
|
-
"externalTruthSkill",
|
|
494
|
-
"externalAdrSkill",
|
|
495
|
-
]);
|
|
496
|
-
const candidate = value;
|
|
497
|
-
for (const key of Object.keys(candidate)) {
|
|
498
|
-
if (!allowedKeys.has(key)) {
|
|
499
|
-
return false;
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
|
-
if (candidate.goalMode !== undefined && typeof candidate.goalMode !== "boolean") {
|
|
503
|
-
return false;
|
|
504
|
-
}
|
|
505
|
-
if (candidate.truthDispatch !== undefined && candidate.truthDispatch !== "per_task" && candidate.truthDispatch !== "final_only") {
|
|
506
|
-
return false;
|
|
507
|
-
}
|
|
508
|
-
if (candidate.externalPlanningSkill !== undefined && candidate.externalPlanningSkill !== null && typeof candidate.externalPlanningSkill !== "string") {
|
|
509
|
-
return false;
|
|
510
|
-
}
|
|
511
|
-
if (candidate.externalTruthSkill !== undefined && candidate.externalTruthSkill !== null && typeof candidate.externalTruthSkill !== "string") {
|
|
512
|
-
return false;
|
|
513
|
-
}
|
|
514
|
-
if (candidate.externalAdrSkill !== undefined && candidate.externalAdrSkill !== null && typeof candidate.externalAdrSkill !== "string") {
|
|
515
|
-
return false;
|
|
516
|
-
}
|
|
517
|
-
return true;
|
|
518
|
-
}
|
|
519
|
-
function isTemplateTaskGuidance(value) {
|
|
520
|
-
if (value === undefined) {
|
|
521
|
-
return true;
|
|
522
|
-
}
|
|
523
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
524
|
-
return false;
|
|
525
|
-
}
|
|
526
|
-
const candidate = value;
|
|
527
|
-
const allowedKeys = new Set(["onDone"]);
|
|
528
|
-
for (const key of Object.keys(candidate)) {
|
|
529
|
-
if (!allowedKeys.has(key)) {
|
|
530
|
-
return false;
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
if (candidate.onDone === undefined) {
|
|
534
|
-
return true;
|
|
535
|
-
}
|
|
536
|
-
if (!candidate.onDone || typeof candidate.onDone !== "object" || Array.isArray(candidate.onDone)) {
|
|
537
|
-
return false;
|
|
538
|
-
}
|
|
539
|
-
const onDone = candidate.onDone;
|
|
540
|
-
const allowedOnDoneKeys = new Set(["default", "choices"]);
|
|
541
|
-
for (const key of Object.keys(onDone)) {
|
|
542
|
-
if (!allowedOnDoneKeys.has(key)) {
|
|
543
|
-
return false;
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
if (onDone.default !== undefined && !isTemplateGuidanceRoute(onDone.default)) {
|
|
547
|
-
return false;
|
|
548
|
-
}
|
|
549
|
-
if (onDone.choices !== undefined) {
|
|
550
|
-
if (!onDone.choices || typeof onDone.choices !== "object" || Array.isArray(onDone.choices)) {
|
|
551
|
-
return false;
|
|
552
|
-
}
|
|
553
|
-
for (const [choiceId, route] of Object.entries(onDone.choices)) {
|
|
554
|
-
if (!choiceId.trim() || !isTemplateGuidanceRoute(route)) {
|
|
555
|
-
return false;
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
return true;
|
|
560
|
-
}
|
|
561
|
-
function isTemplateGuidanceRoute(value) {
|
|
562
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
563
|
-
return false;
|
|
564
|
-
}
|
|
565
|
-
const candidate = value;
|
|
566
|
-
const allowedKeys = new Set([
|
|
567
|
-
"mergeMode",
|
|
568
|
-
"summary",
|
|
569
|
-
"nextsteps",
|
|
570
|
-
"notes",
|
|
571
|
-
"recommendedCommands",
|
|
572
|
-
"nextTaskId",
|
|
573
|
-
"label",
|
|
574
|
-
"delegateTruth",
|
|
575
|
-
]);
|
|
576
|
-
for (const key of Object.keys(candidate)) {
|
|
577
|
-
if (!allowedKeys.has(key)) {
|
|
578
|
-
return false;
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
if (candidate.mergeMode !== undefined && candidate.mergeMode !== "override" && candidate.mergeMode !== "replace") {
|
|
582
|
-
return false;
|
|
583
|
-
}
|
|
584
|
-
if (candidate.summary !== undefined && typeof candidate.summary !== "string") {
|
|
585
|
-
return false;
|
|
586
|
-
}
|
|
587
|
-
if (candidate.nextsteps !== undefined && (!Array.isArray(candidate.nextsteps) || candidate.nextsteps.some((step) => typeof step !== "string"))) {
|
|
588
|
-
return false;
|
|
589
|
-
}
|
|
590
|
-
if (candidate.notes !== undefined && typeof candidate.notes !== "string") {
|
|
591
|
-
return false;
|
|
592
|
-
}
|
|
593
|
-
if (candidate.recommendedCommands !== undefined &&
|
|
594
|
-
(!Array.isArray(candidate.recommendedCommands) || candidate.recommendedCommands.some((command) => typeof command !== "string"))) {
|
|
595
|
-
return false;
|
|
596
|
-
}
|
|
597
|
-
if (candidate.nextTaskId !== undefined && !Number.isInteger(candidate.nextTaskId)) {
|
|
598
|
-
return false;
|
|
599
|
-
}
|
|
600
|
-
if (candidate.label !== undefined && typeof candidate.label !== "string") {
|
|
601
|
-
return false;
|
|
602
|
-
}
|
|
603
|
-
if (candidate.delegateTruth !== undefined && typeof candidate.delegateTruth !== "boolean") {
|
|
604
|
-
return false;
|
|
605
|
-
}
|
|
606
|
-
if (candidate.mergeMode === "replace") {
|
|
607
|
-
if (typeof candidate.summary !== "string") {
|
|
608
|
-
return false;
|
|
609
|
-
}
|
|
610
|
-
if (!Array.isArray(candidate.nextsteps) || candidate.nextsteps.some((step) => typeof step !== "string")) {
|
|
611
|
-
return false;
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
if (candidate.mergeMode !== "replace"
|
|
615
|
-
&& candidate.summary === undefined
|
|
616
|
-
&& candidate.nextsteps === undefined
|
|
617
|
-
&& candidate.notes === undefined
|
|
618
|
-
&& candidate.recommendedCommands === undefined
|
|
619
|
-
&& candidate.nextTaskId === undefined
|
|
620
|
-
&& candidate.label === undefined
|
|
621
|
-
&& candidate.delegateTruth === undefined) {
|
|
622
|
-
return false;
|
|
623
|
-
}
|
|
624
|
-
return true;
|
|
70
|
+
return candidate;
|
|
625
71
|
}
|
|
626
72
|
export function renderSeedTemplateText(template, vars) {
|
|
627
73
|
return template.replace(/{{\s*planningSkill\s*}}/g, vars.planningSkill);
|