@interf/compiler 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +183 -0
- package/README.md +1008 -0
- package/TRADEMARKS.md +19 -0
- package/dist/bin.d.ts +3 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +30 -0
- package/dist/bin.js.map +1 -0
- package/dist/commands/benchmark.d.ts +3 -0
- package/dist/commands/benchmark.d.ts.map +1 -0
- package/dist/commands/benchmark.js +400 -0
- package/dist/commands/benchmark.js.map +1 -0
- package/dist/commands/compile.d.ts +3 -0
- package/dist/commands/compile.d.ts.map +1 -0
- package/dist/commands/compile.js +139 -0
- package/dist/commands/compile.js.map +1 -0
- package/dist/commands/create.d.ts +49 -0
- package/dist/commands/create.d.ts.map +1 -0
- package/dist/commands/create.js +813 -0
- package/dist/commands/create.js.map +1 -0
- package/dist/commands/default.d.ts +3 -0
- package/dist/commands/default.d.ts.map +1 -0
- package/dist/commands/default.js +52 -0
- package/dist/commands/default.js.map +1 -0
- package/dist/commands/doctor.d.ts +3 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +146 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/init.d.ts +3 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +235 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/list.d.ts +3 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +32 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/reset.d.ts +3 -0
- package/dist/commands/reset.d.ts.map +1 -0
- package/dist/commands/reset.js +136 -0
- package/dist/commands/reset.js.map +1 -0
- package/dist/commands/status.d.ts +3 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +67 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/verify.d.ts +3 -0
- package/dist/commands/verify.d.ts.map +1 -0
- package/dist/commands/verify.js +112 -0
- package/dist/commands/verify.js.map +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/agents.d.ts +59 -0
- package/dist/lib/agents.d.ts.map +1 -0
- package/dist/lib/agents.js +760 -0
- package/dist/lib/agents.js.map +1 -0
- package/dist/lib/benchmark.d.ts +30 -0
- package/dist/lib/benchmark.d.ts.map +1 -0
- package/dist/lib/benchmark.js +325 -0
- package/dist/lib/benchmark.js.map +1 -0
- package/dist/lib/config.d.ts +6 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +15 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/discovery.d.ts +8 -0
- package/dist/lib/discovery.d.ts.map +1 -0
- package/dist/lib/discovery.js +80 -0
- package/dist/lib/discovery.js.map +1 -0
- package/dist/lib/executors.d.ts +33 -0
- package/dist/lib/executors.d.ts.map +1 -0
- package/dist/lib/executors.js +44 -0
- package/dist/lib/executors.js.map +1 -0
- package/dist/lib/filesystem.d.ts +4 -0
- package/dist/lib/filesystem.d.ts.map +1 -0
- package/dist/lib/filesystem.js +61 -0
- package/dist/lib/filesystem.js.map +1 -0
- package/dist/lib/interf.d.ts +37 -0
- package/dist/lib/interf.d.ts.map +1 -0
- package/dist/lib/interf.js +1104 -0
- package/dist/lib/interf.js.map +1 -0
- package/dist/lib/local-workflows.d.ts +35 -0
- package/dist/lib/local-workflows.d.ts.map +1 -0
- package/dist/lib/local-workflows.js +149 -0
- package/dist/lib/local-workflows.js.map +1 -0
- package/dist/lib/parse.d.ts +9 -0
- package/dist/lib/parse.d.ts.map +1 -0
- package/dist/lib/parse.js +51 -0
- package/dist/lib/parse.js.map +1 -0
- package/dist/lib/registry.d.ts +28 -0
- package/dist/lib/registry.d.ts.map +1 -0
- package/dist/lib/registry.js +80 -0
- package/dist/lib/registry.js.map +1 -0
- package/dist/lib/runtime.d.ts +59 -0
- package/dist/lib/runtime.d.ts.map +1 -0
- package/dist/lib/runtime.js +615 -0
- package/dist/lib/runtime.js.map +1 -0
- package/dist/lib/schema.d.ts +705 -0
- package/dist/lib/schema.d.ts.map +1 -0
- package/dist/lib/schema.js +443 -0
- package/dist/lib/schema.js.map +1 -0
- package/dist/lib/state.d.ts +49 -0
- package/dist/lib/state.d.ts.map +1 -0
- package/dist/lib/state.js +633 -0
- package/dist/lib/state.js.map +1 -0
- package/dist/lib/summarize-plan.d.ts +16 -0
- package/dist/lib/summarize-plan.d.ts.map +1 -0
- package/dist/lib/summarize-plan.js +112 -0
- package/dist/lib/summarize-plan.js.map +1 -0
- package/dist/lib/user-config.d.ts +6 -0
- package/dist/lib/user-config.d.ts.map +1 -0
- package/dist/lib/user-config.js +16 -0
- package/dist/lib/user-config.js.map +1 -0
- package/dist/lib/validate.d.ts +149 -0
- package/dist/lib/validate.d.ts.map +1 -0
- package/dist/lib/validate.js +838 -0
- package/dist/lib/validate.js.map +1 -0
- package/dist/lib/workflow-definitions.d.ts +79 -0
- package/dist/lib/workflow-definitions.d.ts.map +1 -0
- package/dist/lib/workflow-definitions.js +565 -0
- package/dist/lib/workflow-definitions.js.map +1 -0
- package/dist/lib/workflows.d.ts +125 -0
- package/dist/lib/workflows.d.ts.map +1 -0
- package/dist/lib/workflows.js +1107 -0
- package/dist/lib/workflows.js.map +1 -0
- package/package.json +73 -0
- package/skills/benchmark/SKILL.md +129 -0
- package/skills/interface/analyze/SKILL.md +140 -0
- package/skills/interface/compile/SKILL.md +153 -0
- package/skills/interface/compile/references/output-format.md +48 -0
- package/skills/interface/create/SKILL.md +264 -0
- package/skills/interface/create/references/compile-plan-format.md +109 -0
- package/skills/interface/create/references/workflows.md +50 -0
- package/skills/interface/query/SKILL.md +34 -0
- package/skills/interface/retrieve/SKILL.md +166 -0
- package/skills/knowledge-base/compile/SKILL.md +220 -0
- package/skills/knowledge-base/compile/references/output-format.md +48 -0
- package/skills/knowledge-base/compile/references/stage-claims.md +60 -0
- package/skills/knowledge-base/compile/references/stage-entities.md +46 -0
- package/skills/knowledge-base/query/SKILL.md +33 -0
- package/skills/knowledge-base/summarize/SKILL.md +122 -0
- package/skills/workflow/create/SKILL.md +126 -0
- package/templates/interface/README.md +158 -0
- package/templates/interface/interfaces.md +99 -0
- package/templates/knowledge-base/README.md +138 -0
- package/templates/knowledge-base/interfignore +19 -0
- package/templates/knowledge-base/registry.md +118 -0
|
@@ -0,0 +1,813 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { basename } from "node:path";
|
|
3
|
+
import * as p from "@clack/prompts";
|
|
4
|
+
import { detectInterf, listKnowledgeBasesForSourceFolder, readInterfConfig, resolveInterfaceKnowledgeBasePath, resolveKnowledgeBaseSourcePath, writeInterfaceCompilePlanTemplate, } from "../lib/interf.js";
|
|
5
|
+
import { discoverSourceFiles } from "../lib/discovery.js";
|
|
6
|
+
import { addKnowledgeBaseWithWorkflow, addInterface } from "../lib/registry.js";
|
|
7
|
+
import { resolveLocalExecutor } from "../lib/executors.js";
|
|
8
|
+
import { loadRegistry } from "../lib/registry.js";
|
|
9
|
+
import { loadUserConfig } from "../lib/user-config.js";
|
|
10
|
+
import { formatInterfaceWorkflowStageStep, formatKnowledgeBaseWorkflowStageStep, listInterfaceWorkflowChoices, listKnowledgeBaseInterfaceWorkflowChoices, listKnowledgeBaseWorkflowChoices, resolveInterfaceWorkflowFromConfig, resolveKnowledgeBaseWorkflowFromConfig, } from "../lib/workflow-definitions.js";
|
|
11
|
+
import { createKnowledgeBase, createInterface, planInterface, compileKnowledgeBase as compileKnowledgeBaseWorkflow, compileInterface as compileInterfaceWorkflow, } from "../lib/workflows.js";
|
|
12
|
+
import { isWorkflowId, writeLocalWorkflowDefinition, } from "../lib/local-workflows.js";
|
|
13
|
+
import { renderJsonFrontmatter } from "../lib/parse.js";
|
|
14
|
+
const clackWorkflowPrompts = {
|
|
15
|
+
intro: p.intro,
|
|
16
|
+
select: (options) => p.select(options),
|
|
17
|
+
text: (options) => p.text(options),
|
|
18
|
+
isCancel: p.isCancel,
|
|
19
|
+
log: {
|
|
20
|
+
info: p.log.info,
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
function slugify(input) {
|
|
24
|
+
return input
|
|
25
|
+
.toLowerCase()
|
|
26
|
+
.trim()
|
|
27
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
28
|
+
.replace(/^-+|-+$/g, "")
|
|
29
|
+
.slice(0, 80);
|
|
30
|
+
}
|
|
31
|
+
function normalizeCreateTarget(value) {
|
|
32
|
+
if (!value)
|
|
33
|
+
return null;
|
|
34
|
+
switch (value) {
|
|
35
|
+
case "knowledge-base":
|
|
36
|
+
case "knowledgebase":
|
|
37
|
+
case "base":
|
|
38
|
+
case "kb":
|
|
39
|
+
return "knowledge-base";
|
|
40
|
+
case "interface":
|
|
41
|
+
return "interface";
|
|
42
|
+
case "workflow":
|
|
43
|
+
case "wf":
|
|
44
|
+
return "workflow";
|
|
45
|
+
default:
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
async function selectCreateTarget() {
|
|
50
|
+
const detected = detectInterf(process.cwd());
|
|
51
|
+
const registry = loadRegistry();
|
|
52
|
+
if (!detected && registry.knowledgeBases.length === 0) {
|
|
53
|
+
return "knowledge-base";
|
|
54
|
+
}
|
|
55
|
+
const recommendInterface = Boolean(detected);
|
|
56
|
+
return p.select({
|
|
57
|
+
message: "Create what?",
|
|
58
|
+
options: recommendInterface
|
|
59
|
+
? [
|
|
60
|
+
{
|
|
61
|
+
value: "interface",
|
|
62
|
+
label: "Interface (Recommended)",
|
|
63
|
+
hint: "Create a focused workspace on top of an existing knowledge base",
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
value: "knowledge-base",
|
|
67
|
+
label: "Knowledge Base",
|
|
68
|
+
hint: "Attach the current folder as a new local knowledge base",
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
value: "workflow",
|
|
72
|
+
label: "Workflow",
|
|
73
|
+
hint: "Create a reusable workflow package for knowledge bases or interfaces",
|
|
74
|
+
},
|
|
75
|
+
]
|
|
76
|
+
: [
|
|
77
|
+
{
|
|
78
|
+
value: "knowledge-base",
|
|
79
|
+
label: "Knowledge Base (Recommended)",
|
|
80
|
+
hint: "Attach the current folder as a new local knowledge base",
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
value: "interface",
|
|
84
|
+
label: "Interface",
|
|
85
|
+
hint: "Create an interface from a knowledge base already in your registry",
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
value: "workflow",
|
|
89
|
+
label: "Workflow",
|
|
90
|
+
hint: "Create a reusable workflow package for knowledge bases or interfaces",
|
|
91
|
+
},
|
|
92
|
+
],
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
async function selectWorkflowTargetType(prompts = clackWorkflowPrompts) {
|
|
96
|
+
return prompts.select({
|
|
97
|
+
message: "Workflow type?",
|
|
98
|
+
options: [
|
|
99
|
+
{
|
|
100
|
+
value: "knowledge-base",
|
|
101
|
+
label: "Knowledge Base Workflow (Recommended)",
|
|
102
|
+
hint: "Create a reusable compile method for attached folders",
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
value: "interface",
|
|
106
|
+
label: "Interface Workflow",
|
|
107
|
+
hint: "Create a reusable task-specific method on top of a knowledge base",
|
|
108
|
+
},
|
|
109
|
+
],
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
function formatWorkflowLabel(workflow) {
|
|
113
|
+
return {
|
|
114
|
+
value: workflow.id,
|
|
115
|
+
label: workflow.scope === "local" ? `${workflow.label} (Local)` : workflow.label,
|
|
116
|
+
hint: workflow.hint,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
const CREATE_NEW_WORKFLOW_VALUE = "__create_new_workflow__";
|
|
120
|
+
export function buildKnowledgeBaseWorkflowOptions(sourcePath) {
|
|
121
|
+
return [
|
|
122
|
+
...listKnowledgeBaseWorkflowChoices(sourcePath).map(formatWorkflowLabel),
|
|
123
|
+
{
|
|
124
|
+
value: CREATE_NEW_WORKFLOW_VALUE,
|
|
125
|
+
label: "Create new workflow...",
|
|
126
|
+
hint: "Answer a few questions and save a reusable local workflow under interf/workflows/",
|
|
127
|
+
},
|
|
128
|
+
];
|
|
129
|
+
}
|
|
130
|
+
export function buildInterfaceWorkflowOptions(knowledgeBasePath) {
|
|
131
|
+
const sourcePath = resolveKnowledgeBaseSourcePath(knowledgeBasePath);
|
|
132
|
+
const workflowMap = new Map();
|
|
133
|
+
for (const workflow of listKnowledgeBaseInterfaceWorkflowChoices(knowledgeBasePath)) {
|
|
134
|
+
workflowMap.set(workflow.id, workflow);
|
|
135
|
+
}
|
|
136
|
+
for (const workflow of listInterfaceWorkflowChoices(sourcePath)) {
|
|
137
|
+
if (!workflowMap.has(workflow.id))
|
|
138
|
+
workflowMap.set(workflow.id, workflow);
|
|
139
|
+
}
|
|
140
|
+
return [
|
|
141
|
+
...Array.from(workflowMap.values()).map(formatWorkflowLabel),
|
|
142
|
+
{
|
|
143
|
+
value: CREATE_NEW_WORKFLOW_VALUE,
|
|
144
|
+
label: "Create new interface workflow...",
|
|
145
|
+
hint: "Answer a few questions and save a reusable interface workflow template",
|
|
146
|
+
},
|
|
147
|
+
];
|
|
148
|
+
}
|
|
149
|
+
function buildStandaloneInterfaceWorkflowOptions(sourcePath) {
|
|
150
|
+
return [
|
|
151
|
+
...listInterfaceWorkflowChoices(sourcePath).map(formatWorkflowLabel),
|
|
152
|
+
{
|
|
153
|
+
value: CREATE_NEW_WORKFLOW_VALUE,
|
|
154
|
+
label: "Create new interface workflow...",
|
|
155
|
+
hint: "Answer a few questions and save a reusable interface workflow template",
|
|
156
|
+
},
|
|
157
|
+
];
|
|
158
|
+
}
|
|
159
|
+
async function chooseKnowledgeBaseWorkflow(sourcePath) {
|
|
160
|
+
const workflowChoice = await p.select({
|
|
161
|
+
message: "Knowledge-base workflow?",
|
|
162
|
+
options: buildKnowledgeBaseWorkflowOptions(sourcePath),
|
|
163
|
+
});
|
|
164
|
+
if (p.isCancel(workflowChoice))
|
|
165
|
+
return workflowChoice;
|
|
166
|
+
if (workflowChoice === CREATE_NEW_WORKFLOW_VALUE) {
|
|
167
|
+
return createKnowledgeBaseWorkflowWizard(sourcePath);
|
|
168
|
+
}
|
|
169
|
+
return workflowChoice;
|
|
170
|
+
}
|
|
171
|
+
async function chooseInterfaceWorkflow(knowledgeBasePath) {
|
|
172
|
+
const workflowChoice = await p.select({
|
|
173
|
+
message: "Interface workflow?",
|
|
174
|
+
options: buildInterfaceWorkflowOptions(knowledgeBasePath),
|
|
175
|
+
});
|
|
176
|
+
if (p.isCancel(workflowChoice))
|
|
177
|
+
return workflowChoice;
|
|
178
|
+
if (workflowChoice === CREATE_NEW_WORKFLOW_VALUE) {
|
|
179
|
+
return createInterfaceWorkflowWizard({
|
|
180
|
+
sourcePath: resolveKnowledgeBaseSourcePath(knowledgeBasePath),
|
|
181
|
+
knowledgeBasePath,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
return workflowChoice;
|
|
185
|
+
}
|
|
186
|
+
async function createWorkflowWizard(options = {}, prompts = clackWorkflowPrompts) {
|
|
187
|
+
if (options.intro !== false) {
|
|
188
|
+
prompts.intro(chalk.bold("Create a workflow"));
|
|
189
|
+
}
|
|
190
|
+
const workflowType = options.type ?? await selectWorkflowTargetType(prompts);
|
|
191
|
+
if (prompts.isCancel(workflowType))
|
|
192
|
+
return workflowType;
|
|
193
|
+
const sourcePath = options.sourcePath ?? process.cwd();
|
|
194
|
+
if (workflowType === "knowledge-base") {
|
|
195
|
+
return createKnowledgeBaseWorkflowWizard(sourcePath, prompts);
|
|
196
|
+
}
|
|
197
|
+
return createInterfaceWorkflowWizard({
|
|
198
|
+
sourcePath,
|
|
199
|
+
knowledgeBasePath: options.knowledgeBasePath,
|
|
200
|
+
}, prompts);
|
|
201
|
+
}
|
|
202
|
+
export async function createKnowledgeBaseWorkflowWizard(sourcePath, prompts = clackWorkflowPrompts) {
|
|
203
|
+
const baseWorkflow = await prompts.select({
|
|
204
|
+
message: "Start from which existing knowledge-base workflow?",
|
|
205
|
+
options: listKnowledgeBaseWorkflowChoices(sourcePath).map(formatWorkflowLabel),
|
|
206
|
+
});
|
|
207
|
+
if (prompts.isCancel(baseWorkflow))
|
|
208
|
+
return baseWorkflow;
|
|
209
|
+
const rawName = await prompts.text({
|
|
210
|
+
message: "New workflow name?",
|
|
211
|
+
placeholder: "founder-research",
|
|
212
|
+
validate: (value) => {
|
|
213
|
+
if (value.trim().length === 0)
|
|
214
|
+
return "Name is required";
|
|
215
|
+
const workflowId = slugify(value);
|
|
216
|
+
if (!isWorkflowId(workflowId))
|
|
217
|
+
return "Use letters, numbers, and dashes only";
|
|
218
|
+
if (listKnowledgeBaseWorkflowChoices(sourcePath).some((workflow) => workflow.id === workflowId)) {
|
|
219
|
+
return "That workflow name already exists";
|
|
220
|
+
}
|
|
221
|
+
return undefined;
|
|
222
|
+
},
|
|
223
|
+
});
|
|
224
|
+
if (prompts.isCancel(rawName))
|
|
225
|
+
return rawName;
|
|
226
|
+
const workflowId = slugify(rawName);
|
|
227
|
+
const label = rawName.trim();
|
|
228
|
+
const hint = await prompts.text({
|
|
229
|
+
message: "One-line workflow description?",
|
|
230
|
+
placeholder: "Bias toward investor-grade research and strong evidence tracking",
|
|
231
|
+
validate: (value) => (value.trim().length === 0 ? "Description is required" : undefined),
|
|
232
|
+
});
|
|
233
|
+
if (prompts.isCancel(hint))
|
|
234
|
+
return hint;
|
|
235
|
+
const summarizeBias = await prompts.text({
|
|
236
|
+
message: "What should summarize emphasize?",
|
|
237
|
+
placeholder: "Preserve evidence tiers, decision context, and source metadata",
|
|
238
|
+
validate: (value) => (value.trim().length === 0 ? "Summarize guidance is required" : undefined),
|
|
239
|
+
});
|
|
240
|
+
if (prompts.isCancel(summarizeBias))
|
|
241
|
+
return summarizeBias;
|
|
242
|
+
const compileBias = await prompts.text({
|
|
243
|
+
message: "What should compile emphasize?",
|
|
244
|
+
placeholder: "Build retrieval-ready concepts, timelines, and decision indexes",
|
|
245
|
+
validate: (value) => (value.trim().length === 0 ? "Compile guidance is required" : undefined),
|
|
246
|
+
});
|
|
247
|
+
if (prompts.isCancel(compileBias))
|
|
248
|
+
return compileBias;
|
|
249
|
+
const workflowPath = writeLocalWorkflowDefinition(sourcePath, {
|
|
250
|
+
id: workflowId,
|
|
251
|
+
type: "knowledge-base",
|
|
252
|
+
label,
|
|
253
|
+
hint: hint.trim(),
|
|
254
|
+
extends: baseWorkflow,
|
|
255
|
+
stage_policy_notes: {
|
|
256
|
+
summarize: [summarizeBias.trim()],
|
|
257
|
+
compile: [compileBias.trim()],
|
|
258
|
+
},
|
|
259
|
+
starter_docs: [
|
|
260
|
+
{
|
|
261
|
+
relativePath: "README.md",
|
|
262
|
+
content: [
|
|
263
|
+
renderJsonFrontmatter({ mode: "extend" }),
|
|
264
|
+
`# ${label}`,
|
|
265
|
+
"",
|
|
266
|
+
`This local knowledge-base workflow extends \`${baseWorkflow}\`.`,
|
|
267
|
+
"",
|
|
268
|
+
`- summarize bias: ${summarizeBias.trim()}`,
|
|
269
|
+
`- compile bias: ${compileBias.trim()}`,
|
|
270
|
+
"",
|
|
271
|
+
].join("\n"),
|
|
272
|
+
},
|
|
273
|
+
],
|
|
274
|
+
});
|
|
275
|
+
prompts.log.info(`Saved local workflow: ${workflowPath}`);
|
|
276
|
+
return workflowId;
|
|
277
|
+
}
|
|
278
|
+
export async function createInterfaceWorkflowWizard(options, prompts = clackWorkflowPrompts) {
|
|
279
|
+
const sourcePath = options.sourcePath;
|
|
280
|
+
const knowledgeBasePath = options.knowledgeBasePath;
|
|
281
|
+
const workflowOptions = knowledgeBasePath
|
|
282
|
+
? buildInterfaceWorkflowOptions(knowledgeBasePath)
|
|
283
|
+
: buildStandaloneInterfaceWorkflowOptions(sourcePath);
|
|
284
|
+
const baseWorkflow = await prompts.select({
|
|
285
|
+
message: "Start from which existing interface workflow?",
|
|
286
|
+
options: workflowOptions
|
|
287
|
+
.filter((option) => option.value !== CREATE_NEW_WORKFLOW_VALUE),
|
|
288
|
+
});
|
|
289
|
+
if (prompts.isCancel(baseWorkflow))
|
|
290
|
+
return baseWorkflow;
|
|
291
|
+
const rawName = await prompts.text({
|
|
292
|
+
message: "New workflow name?",
|
|
293
|
+
placeholder: "diligence-memo",
|
|
294
|
+
validate: (value) => {
|
|
295
|
+
if (value.trim().length === 0)
|
|
296
|
+
return "Name is required";
|
|
297
|
+
const workflowId = slugify(value);
|
|
298
|
+
if (!isWorkflowId(workflowId))
|
|
299
|
+
return "Use letters, numbers, and dashes only";
|
|
300
|
+
if (workflowOptions.some((workflow) => workflow.value === workflowId)) {
|
|
301
|
+
return "That workflow name already exists";
|
|
302
|
+
}
|
|
303
|
+
return undefined;
|
|
304
|
+
},
|
|
305
|
+
});
|
|
306
|
+
if (prompts.isCancel(rawName))
|
|
307
|
+
return rawName;
|
|
308
|
+
const workflowId = slugify(rawName);
|
|
309
|
+
const label = rawName.trim();
|
|
310
|
+
const hint = await prompts.text({
|
|
311
|
+
message: "One-line workflow description?",
|
|
312
|
+
placeholder: "Bias toward evidence-backed diligence notes and decision-ready outputs",
|
|
313
|
+
validate: (value) => (value.trim().length === 0 ? "Description is required" : undefined),
|
|
314
|
+
});
|
|
315
|
+
if (prompts.isCancel(hint))
|
|
316
|
+
return hint;
|
|
317
|
+
const placeholder = await prompts.text({
|
|
318
|
+
message: "Prompt placeholder for this interface workflow?",
|
|
319
|
+
placeholder: "What should this interface focus on for this knowledge base?",
|
|
320
|
+
validate: (value) => (value.trim().length === 0 ? "Placeholder is required" : undefined),
|
|
321
|
+
});
|
|
322
|
+
if (prompts.isCancel(placeholder))
|
|
323
|
+
return placeholder;
|
|
324
|
+
const retrieveBias = await prompts.text({
|
|
325
|
+
message: "What should retrieve emphasize?",
|
|
326
|
+
placeholder: "Current decisions, canonical docs, and materials with strong signal",
|
|
327
|
+
validate: (value) => (value.trim().length === 0 ? "Retrieve guidance is required" : undefined),
|
|
328
|
+
});
|
|
329
|
+
if (prompts.isCancel(retrieveBias))
|
|
330
|
+
return retrieveBias;
|
|
331
|
+
const analyzeBias = await prompts.text({
|
|
332
|
+
message: "What should analyze emphasize?",
|
|
333
|
+
placeholder: "Risks, contradictions, and evidence-weighted findings",
|
|
334
|
+
validate: (value) => (value.trim().length === 0 ? "Analyze guidance is required" : undefined),
|
|
335
|
+
});
|
|
336
|
+
if (prompts.isCancel(analyzeBias))
|
|
337
|
+
return analyzeBias;
|
|
338
|
+
const compileBias = await prompts.text({
|
|
339
|
+
message: "What should compile emphasize?",
|
|
340
|
+
placeholder: "Decision-ready notes, concise briefs, and linked evidence",
|
|
341
|
+
validate: (value) => (value.trim().length === 0 ? "Compile guidance is required" : undefined),
|
|
342
|
+
});
|
|
343
|
+
if (prompts.isCancel(compileBias))
|
|
344
|
+
return compileBias;
|
|
345
|
+
const workflowPath = writeLocalWorkflowDefinition(sourcePath, {
|
|
346
|
+
id: workflowId,
|
|
347
|
+
type: "interface",
|
|
348
|
+
label,
|
|
349
|
+
hint: hint.trim(),
|
|
350
|
+
extends: baseWorkflow,
|
|
351
|
+
placeholder: placeholder.trim(),
|
|
352
|
+
stage_policy_notes: {
|
|
353
|
+
retrieve: [retrieveBias.trim()],
|
|
354
|
+
analyze: [analyzeBias.trim()],
|
|
355
|
+
compile: [compileBias.trim()],
|
|
356
|
+
},
|
|
357
|
+
starter_docs: [
|
|
358
|
+
{
|
|
359
|
+
relativePath: "README.md",
|
|
360
|
+
content: [
|
|
361
|
+
renderJsonFrontmatter({ mode: "extend" }),
|
|
362
|
+
`# ${label}`,
|
|
363
|
+
"",
|
|
364
|
+
`This local interface workflow extends \`${baseWorkflow}\`.`,
|
|
365
|
+
"",
|
|
366
|
+
`- retrieve bias: ${retrieveBias.trim()}`,
|
|
367
|
+
`- analyze bias: ${analyzeBias.trim()}`,
|
|
368
|
+
`- compile bias: ${compileBias.trim()}`,
|
|
369
|
+
"",
|
|
370
|
+
].join("\n"),
|
|
371
|
+
},
|
|
372
|
+
],
|
|
373
|
+
});
|
|
374
|
+
prompts.log.info(`Saved local workflow: ${workflowPath}`);
|
|
375
|
+
return workflowId;
|
|
376
|
+
}
|
|
377
|
+
export const createCommand = {
|
|
378
|
+
command: "create [type]",
|
|
379
|
+
describe: "Create a knowledge base, interface, or reusable workflow, or choose when omitted",
|
|
380
|
+
builder: (yargs) => yargs.positional("type", {
|
|
381
|
+
type: "string",
|
|
382
|
+
describe: "Type to create (`knowledge-base`, `interface`, or `workflow`)",
|
|
383
|
+
default: undefined,
|
|
384
|
+
}),
|
|
385
|
+
handler: async (argv) => {
|
|
386
|
+
const rawType = argv.type;
|
|
387
|
+
let type = normalizeCreateTarget(rawType);
|
|
388
|
+
if (rawType && !type) {
|
|
389
|
+
p.log.error(`Unknown create target: ${rawType}`);
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
if (!type) {
|
|
393
|
+
const selected = await selectCreateTarget();
|
|
394
|
+
if (p.isCancel(selected))
|
|
395
|
+
return;
|
|
396
|
+
type = selected;
|
|
397
|
+
}
|
|
398
|
+
if (type === "knowledge-base") {
|
|
399
|
+
await createKnowledgeBaseWizard();
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
if (type === "workflow") {
|
|
403
|
+
const cwd = process.cwd();
|
|
404
|
+
const detected = detectInterf(cwd);
|
|
405
|
+
let sourcePath = cwd;
|
|
406
|
+
let knowledgeBasePath;
|
|
407
|
+
if (detected?.config.type === "knowledge-base") {
|
|
408
|
+
knowledgeBasePath = detected.path;
|
|
409
|
+
sourcePath = resolveKnowledgeBaseSourcePath(detected.path);
|
|
410
|
+
}
|
|
411
|
+
else if (detected?.config.type === "interface") {
|
|
412
|
+
const parentKnowledgeBasePath = resolveInterfaceKnowledgeBasePath(detected.path);
|
|
413
|
+
if (parentKnowledgeBasePath) {
|
|
414
|
+
knowledgeBasePath = parentKnowledgeBasePath;
|
|
415
|
+
sourcePath = resolveKnowledgeBaseSourcePath(parentKnowledgeBasePath);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
else {
|
|
419
|
+
const localKnowledgeBases = listKnowledgeBasesForSourceFolder(cwd);
|
|
420
|
+
if (localKnowledgeBases.length === 1) {
|
|
421
|
+
knowledgeBasePath = localKnowledgeBases[0].path;
|
|
422
|
+
sourcePath = resolveKnowledgeBaseSourcePath(localKnowledgeBases[0].path);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
await createWorkflowWizard({ sourcePath, knowledgeBasePath });
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
await createInterfaceWizard();
|
|
429
|
+
},
|
|
430
|
+
};
|
|
431
|
+
export async function createKnowledgeBaseWizard(options = {}) {
|
|
432
|
+
if (options.intro !== false) {
|
|
433
|
+
p.intro(chalk.bold("Create a knowledge base"));
|
|
434
|
+
}
|
|
435
|
+
p.log.info("Interf compiles this folder into an LLM knowledge base for agents.");
|
|
436
|
+
p.log.info("Your files stay on disk. Interf stores the compiled knowledge base under `./interf/<name>/` together with summaries, knowledge, agent instructions, and a local workflow package.");
|
|
437
|
+
const cwd = process.cwd();
|
|
438
|
+
const currentConfig = readInterfConfig(cwd);
|
|
439
|
+
if (currentConfig) {
|
|
440
|
+
p.log.error("You are already inside an Interf knowledge base or interface.");
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
const existingKnowledgeBases = listKnowledgeBasesForSourceFolder(cwd);
|
|
444
|
+
if (existingKnowledgeBases.length > 0) {
|
|
445
|
+
p.log.info(`This source folder already has ${existingKnowledgeBases.length} knowledge base${existingKnowledgeBases.length === 1 ? "" : "s"}. Creating another is fine when you want to compare workflows on the same data.`);
|
|
446
|
+
}
|
|
447
|
+
const defaultName = slugify(basename(cwd));
|
|
448
|
+
const rawName = await p.text({
|
|
449
|
+
message: "Knowledge base name?",
|
|
450
|
+
placeholder: defaultName || "my-knowledge-base",
|
|
451
|
+
initialValue: defaultName,
|
|
452
|
+
validate: (v) => (v.length === 0 ? "Name is required" : undefined),
|
|
453
|
+
});
|
|
454
|
+
if (p.isCancel(rawName))
|
|
455
|
+
return;
|
|
456
|
+
const name = slugify(rawName);
|
|
457
|
+
if (name !== rawName) {
|
|
458
|
+
p.log.info(`Knowledge base name: ${name}`);
|
|
459
|
+
}
|
|
460
|
+
const workflowChoice = await chooseKnowledgeBaseWorkflow(cwd);
|
|
461
|
+
if (p.isCancel(workflowChoice))
|
|
462
|
+
return;
|
|
463
|
+
const selectedWorkflow = workflowChoice;
|
|
464
|
+
const s = p.spinner();
|
|
465
|
+
if (!options.skipSkillInstall) {
|
|
466
|
+
p.log.info("Interf uses bundled stage instructions and local workflow docs by default. Run `interf init` when you want to choose an executor or install optional global helper skills.");
|
|
467
|
+
}
|
|
468
|
+
// Create
|
|
469
|
+
s.start("Creating knowledge base...");
|
|
470
|
+
let knowledgeBasePath;
|
|
471
|
+
try {
|
|
472
|
+
knowledgeBasePath = createKnowledgeBase(name, cwd, selectedWorkflow);
|
|
473
|
+
}
|
|
474
|
+
catch (error) {
|
|
475
|
+
s.stop("Create failed");
|
|
476
|
+
p.log.error(error instanceof Error ? error.message : "Failed to create knowledge base.");
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
addKnowledgeBaseWithWorkflow(name, knowledgeBasePath, selectedWorkflow);
|
|
480
|
+
s.stop(`Knowledge base "${name}" created`);
|
|
481
|
+
const createdKnowledgeBaseConfig = readInterfConfig(knowledgeBasePath);
|
|
482
|
+
if (createdKnowledgeBaseConfig?.workflow) {
|
|
483
|
+
p.log.info(`Workflow: ${createdKnowledgeBaseConfig.workflow}`);
|
|
484
|
+
}
|
|
485
|
+
// Discovery preflight
|
|
486
|
+
const discovery = discoverSourceFiles(cwd, knowledgeBasePath);
|
|
487
|
+
p.log.info(`Found ${discovery.totalCount} source files ready to summarize and compile.`);
|
|
488
|
+
if (discovery.ignoredCount > 0) {
|
|
489
|
+
p.log.info("This count already excludes Interf files, hidden folders, and anything matched by `.interfignore`.");
|
|
490
|
+
}
|
|
491
|
+
if (loadUserConfig()?.viewer === "obsidian") {
|
|
492
|
+
p.log.info(`Obsidian defaults applied; knowledge base registered with Obsidian when available as "${name}".`);
|
|
493
|
+
}
|
|
494
|
+
const buildNow = await p.confirm({
|
|
495
|
+
message: "Compile this knowledge base now?",
|
|
496
|
+
initialValue: true,
|
|
497
|
+
});
|
|
498
|
+
if (p.isCancel(buildNow))
|
|
499
|
+
return;
|
|
500
|
+
if (buildNow) {
|
|
501
|
+
const { executor, error } = resolveLocalExecutor();
|
|
502
|
+
if (!executor) {
|
|
503
|
+
p.log.warn(error ?? "No local executor detected.");
|
|
504
|
+
p.outro([
|
|
505
|
+
`Knowledge base: ${knowledgeBasePath}`,
|
|
506
|
+
`Next: run \`interf compile\` from ${cwd} once an executor is configured.`,
|
|
507
|
+
].join("\n"));
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
510
|
+
const compiled = await runKnowledgeBaseCompile(executor, knowledgeBasePath);
|
|
511
|
+
if (compiled) {
|
|
512
|
+
const createFirstInterface = await p.confirm({
|
|
513
|
+
message: "Create a first interface now?",
|
|
514
|
+
initialValue: false,
|
|
515
|
+
});
|
|
516
|
+
if (p.isCancel(createFirstInterface))
|
|
517
|
+
return;
|
|
518
|
+
if (createFirstInterface) {
|
|
519
|
+
await createInterfaceWizard({
|
|
520
|
+
intro: false,
|
|
521
|
+
knowledgeBasePathOverride: knowledgeBasePath,
|
|
522
|
+
knowledgeBaseNameOverride: name,
|
|
523
|
+
});
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
526
|
+
p.outro([
|
|
527
|
+
`Knowledge base ready: ${knowledgeBasePath}`,
|
|
528
|
+
`CLI control plane: ${cwd}`,
|
|
529
|
+
`Workspace entrypoint: ${knowledgeBasePath}`,
|
|
530
|
+
`Browse in Obsidian or markdown from: ${knowledgeBasePath}`,
|
|
531
|
+
`Next: \`interf create interface\` from ${cwd} when you want a focused interface for a specific job.`,
|
|
532
|
+
].join("\n"));
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
535
|
+
p.outro([
|
|
536
|
+
`Knowledge base created: ${knowledgeBasePath}`,
|
|
537
|
+
`The compile did not complete cleanly.`,
|
|
538
|
+
`Next: rerun \`cd ${knowledgeBasePath} && interf compile\` after fixing the reported issue, or run \`interf compile\` from ${cwd}.`,
|
|
539
|
+
].join("\n"));
|
|
540
|
+
return;
|
|
541
|
+
}
|
|
542
|
+
p.outro([
|
|
543
|
+
`Knowledge base created: ${knowledgeBasePath}`,
|
|
544
|
+
`CLI control plane: ${cwd}`,
|
|
545
|
+
`Workspace entrypoint: ${knowledgeBasePath}`,
|
|
546
|
+
`Next: run \`cd ${knowledgeBasePath} && interf compile\`, or run \`interf compile\` from ${cwd}.`,
|
|
547
|
+
].join("\n"));
|
|
548
|
+
}
|
|
549
|
+
export async function createInterfaceWizard(options = {}) {
|
|
550
|
+
if (options.intro !== false) {
|
|
551
|
+
p.intro(chalk.bold("Create an interface"));
|
|
552
|
+
}
|
|
553
|
+
p.log.info("An interface is a focused layer on top of a knowledge base.");
|
|
554
|
+
p.log.info("Use it for one job, perspective, or workflow. It keeps local outputs, a local workflow package, and its own agent instructions while reusing knowledge-base evidence.");
|
|
555
|
+
// Find the knowledge-base — either cwd has interf/ or we look up registry
|
|
556
|
+
const cwd = process.cwd();
|
|
557
|
+
const detected = detectInterf(cwd);
|
|
558
|
+
const localKnowledgeBases = listKnowledgeBasesForSourceFolder(cwd);
|
|
559
|
+
let knowledgeBasePath;
|
|
560
|
+
let connectedKnowledgeBaseName;
|
|
561
|
+
if (options.knowledgeBasePathOverride && options.knowledgeBaseNameOverride) {
|
|
562
|
+
knowledgeBasePath = options.knowledgeBasePathOverride;
|
|
563
|
+
connectedKnowledgeBaseName = options.knowledgeBaseNameOverride;
|
|
564
|
+
}
|
|
565
|
+
else if (detected && detected.config.type === "knowledge-base") {
|
|
566
|
+
const useCurrentKnowledgeBase = await p.confirm({
|
|
567
|
+
message: `Use the current knowledge base "${detected.config.name}"?`,
|
|
568
|
+
initialValue: true,
|
|
569
|
+
});
|
|
570
|
+
if (p.isCancel(useCurrentKnowledgeBase))
|
|
571
|
+
return;
|
|
572
|
+
if (useCurrentKnowledgeBase) {
|
|
573
|
+
knowledgeBasePath = detected.path;
|
|
574
|
+
connectedKnowledgeBaseName = detected.config.name;
|
|
575
|
+
}
|
|
576
|
+
else {
|
|
577
|
+
const availableKnowledgeBases = [
|
|
578
|
+
...localKnowledgeBases
|
|
579
|
+
.filter((knowledgeBase) => knowledgeBase.path !== detected.path)
|
|
580
|
+
.map((knowledgeBase) => ({
|
|
581
|
+
path: knowledgeBase.path,
|
|
582
|
+
name: knowledgeBase.config.name,
|
|
583
|
+
label: `${knowledgeBase.config.name} (${knowledgeBase.path})`,
|
|
584
|
+
})),
|
|
585
|
+
...loadRegistry().knowledgeBases
|
|
586
|
+
.filter((knowledgeBase) => knowledgeBase.path !== detected.path)
|
|
587
|
+
.map((knowledgeBase) => ({
|
|
588
|
+
path: knowledgeBase.path,
|
|
589
|
+
name: knowledgeBase.name,
|
|
590
|
+
label: `${knowledgeBase.name} (${knowledgeBase.path})`,
|
|
591
|
+
})),
|
|
592
|
+
];
|
|
593
|
+
const uniqueKnowledgeBases = Array.from(new Map(availableKnowledgeBases.map((knowledgeBase) => [knowledgeBase.path, knowledgeBase])).values());
|
|
594
|
+
if (uniqueKnowledgeBases.length === 0) {
|
|
595
|
+
p.log.error("No other knowledge bases found. Use the current one or create another knowledge base first.");
|
|
596
|
+
return;
|
|
597
|
+
}
|
|
598
|
+
const choice = await p.select({
|
|
599
|
+
message: "Which knowledge base?",
|
|
600
|
+
options: uniqueKnowledgeBases.map((knowledgeBase) => ({
|
|
601
|
+
value: knowledgeBase.path,
|
|
602
|
+
label: knowledgeBase.label,
|
|
603
|
+
})),
|
|
604
|
+
});
|
|
605
|
+
if (p.isCancel(choice))
|
|
606
|
+
return;
|
|
607
|
+
const knowledgeBase = uniqueKnowledgeBases.find((entry) => entry.path === choice);
|
|
608
|
+
knowledgeBasePath = knowledgeBase.path;
|
|
609
|
+
connectedKnowledgeBaseName = knowledgeBase.name;
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
else if (localKnowledgeBases.length > 0) {
|
|
613
|
+
const choice = await p.select({
|
|
614
|
+
message: "Which local knowledge base?",
|
|
615
|
+
options: localKnowledgeBases.map((knowledgeBase) => ({
|
|
616
|
+
value: knowledgeBase.path,
|
|
617
|
+
label: `${knowledgeBase.config.name} (${knowledgeBase.path})`,
|
|
618
|
+
})),
|
|
619
|
+
});
|
|
620
|
+
if (p.isCancel(choice))
|
|
621
|
+
return;
|
|
622
|
+
const knowledgeBase = localKnowledgeBases.find((entry) => entry.path === choice);
|
|
623
|
+
knowledgeBasePath = knowledgeBase.path;
|
|
624
|
+
connectedKnowledgeBaseName = knowledgeBase.config.name;
|
|
625
|
+
}
|
|
626
|
+
else {
|
|
627
|
+
const reg = loadRegistry();
|
|
628
|
+
if (reg.knowledgeBases.length === 0) {
|
|
629
|
+
p.log.error("No knowledge bases found. Create one first: interf create knowledge-base");
|
|
630
|
+
return;
|
|
631
|
+
}
|
|
632
|
+
const choice = await p.select({
|
|
633
|
+
message: "Which knowledge base?",
|
|
634
|
+
options: reg.knowledgeBases.map((knowledgeBase) => ({
|
|
635
|
+
value: knowledgeBase.path,
|
|
636
|
+
label: `${knowledgeBase.name} (${knowledgeBase.path})`,
|
|
637
|
+
})),
|
|
638
|
+
});
|
|
639
|
+
if (p.isCancel(choice))
|
|
640
|
+
return;
|
|
641
|
+
const knowledgeBase = reg.knowledgeBases.find((entry) => entry.path === choice);
|
|
642
|
+
knowledgeBasePath = knowledgeBase.path;
|
|
643
|
+
connectedKnowledgeBaseName = knowledgeBase.name;
|
|
644
|
+
}
|
|
645
|
+
const rawName = await p.text({
|
|
646
|
+
message: "Interface name?",
|
|
647
|
+
placeholder: "weekly-briefing",
|
|
648
|
+
validate: (v) => (v.length === 0 ? "Name is required" : undefined),
|
|
649
|
+
});
|
|
650
|
+
if (p.isCancel(rawName))
|
|
651
|
+
return;
|
|
652
|
+
const name = slugify(rawName);
|
|
653
|
+
if (name !== rawName) {
|
|
654
|
+
p.log.info(`Directory name: ${name}`);
|
|
655
|
+
}
|
|
656
|
+
const workflow = await chooseInterfaceWorkflow(knowledgeBasePath);
|
|
657
|
+
if (p.isCancel(workflow))
|
|
658
|
+
return;
|
|
659
|
+
const selectedWorkflow = workflow;
|
|
660
|
+
const workflowInfo = [
|
|
661
|
+
...listKnowledgeBaseInterfaceWorkflowChoices(knowledgeBasePath),
|
|
662
|
+
...listInterfaceWorkflowChoices(resolveKnowledgeBaseSourcePath(knowledgeBasePath)),
|
|
663
|
+
].find((option) => option.id === selectedWorkflow);
|
|
664
|
+
const interfaceStageSequence = workflowInfo.stages.map((stage) => stage.label).join(" -> ");
|
|
665
|
+
p.log.info(`Interface workflow = the default ${interfaceStageSequence} method for this interface. You can edit it later in \`workflow/\` or create your own saved workflow.`);
|
|
666
|
+
p.log.info(`${workflowInfo.label}: ${workflowInfo.hint}`);
|
|
667
|
+
const useCase = await p.text({
|
|
668
|
+
message: "Primary question or job for this interface?",
|
|
669
|
+
placeholder: workflowInfo.placeholder,
|
|
670
|
+
validate: (v) => (v.trim().length === 0 ? "Describe the main job for this interface" : undefined),
|
|
671
|
+
});
|
|
672
|
+
if (p.isCancel(useCase))
|
|
673
|
+
return;
|
|
674
|
+
const { executor, error } = resolveLocalExecutor();
|
|
675
|
+
if (!executor) {
|
|
676
|
+
p.log.error(error ?? "No coding agent detected. Install Claude Code or Codex to create interfaces.");
|
|
677
|
+
return;
|
|
678
|
+
}
|
|
679
|
+
let dirPath;
|
|
680
|
+
try {
|
|
681
|
+
dirPath = createInterface(name, knowledgeBasePath, connectedKnowledgeBaseName, selectedWorkflow);
|
|
682
|
+
}
|
|
683
|
+
catch (error) {
|
|
684
|
+
p.log.error(error instanceof Error ? error.message : "Failed to create interface scaffold.");
|
|
685
|
+
return;
|
|
686
|
+
}
|
|
687
|
+
if (loadUserConfig()?.viewer === "obsidian") {
|
|
688
|
+
p.log.info("Obsidian defaults applied. Interfaces stay inside the parent knowledge-base vault by default so knowledge-base summaries and source links remain navigable.");
|
|
689
|
+
}
|
|
690
|
+
p.log.info(`Created interface scaffold at ${dirPath}`);
|
|
691
|
+
const createdInterfaceConfig = readInterfConfig(dirPath);
|
|
692
|
+
if (createdInterfaceConfig?.workflow) {
|
|
693
|
+
p.log.info(`Workflow: ${createdInterfaceConfig.workflow}`);
|
|
694
|
+
}
|
|
695
|
+
writeInterfaceCompilePlanTemplate(dirPath, {
|
|
696
|
+
workflowId: selectedWorkflow,
|
|
697
|
+
sourcePath: resolveKnowledgeBaseSourcePath(knowledgeBasePath),
|
|
698
|
+
interfaceName: name,
|
|
699
|
+
useCase: useCase.trim(),
|
|
700
|
+
});
|
|
701
|
+
p.log.info("Spawning agent to analyze the knowledge base and refine the interface plan.");
|
|
702
|
+
const result = await planInterface({
|
|
703
|
+
executor,
|
|
704
|
+
knowledgeBasePath: dirPath,
|
|
705
|
+
name,
|
|
706
|
+
workflow: selectedWorkflow,
|
|
707
|
+
useCase: useCase,
|
|
708
|
+
knowledgeBaseName: connectedKnowledgeBaseName,
|
|
709
|
+
});
|
|
710
|
+
if (result.ok) {
|
|
711
|
+
addInterface(name, dirPath, connectedKnowledgeBaseName, knowledgeBasePath, selectedWorkflow);
|
|
712
|
+
const buildNow = await p.confirm({
|
|
713
|
+
message: "Compile this interface now?",
|
|
714
|
+
initialValue: true,
|
|
715
|
+
});
|
|
716
|
+
if (p.isCancel(buildNow))
|
|
717
|
+
return;
|
|
718
|
+
if (buildNow) {
|
|
719
|
+
const built = await runInterfaceCompile(executor, dirPath);
|
|
720
|
+
if (built) {
|
|
721
|
+
p.outro([
|
|
722
|
+
`Interface ready: ${dirPath}`,
|
|
723
|
+
`CLI control plane: ${resolveSourceManagementRoot(knowledgeBasePath)}`,
|
|
724
|
+
`Workspace entrypoint: ${dirPath}`,
|
|
725
|
+
`Browse it from the knowledge base at: ${knowledgeBasePath}`,
|
|
726
|
+
].join("\n"));
|
|
727
|
+
return;
|
|
728
|
+
}
|
|
729
|
+
p.outro([
|
|
730
|
+
`Interface created: ${dirPath}`,
|
|
731
|
+
`The compile did not complete cleanly.`,
|
|
732
|
+
`Next: rerun \`cd ${dirPath} && interf compile\` after fixing the reported issue, or run \`interf compile\` from the source folder.`,
|
|
733
|
+
].join("\n"));
|
|
734
|
+
return;
|
|
735
|
+
}
|
|
736
|
+
p.outro([
|
|
737
|
+
`Interface created: ${dirPath}`,
|
|
738
|
+
`CLI control plane: ${resolveSourceManagementRoot(knowledgeBasePath)}`,
|
|
739
|
+
`Workspace entrypoint: ${dirPath}`,
|
|
740
|
+
`Next: run \`cd ${dirPath} && interf compile\`, or run \`interf compile\` from ${resolveSourceManagementRoot(knowledgeBasePath)}.`,
|
|
741
|
+
].join("\n"));
|
|
742
|
+
}
|
|
743
|
+
else {
|
|
744
|
+
const failureSummary = result.summary?.trim();
|
|
745
|
+
writeInterfaceCompilePlanTemplate(dirPath, {
|
|
746
|
+
workflowId: selectedWorkflow,
|
|
747
|
+
sourcePath: resolveKnowledgeBaseSourcePath(knowledgeBasePath),
|
|
748
|
+
interfaceName: name,
|
|
749
|
+
useCase: useCase.trim(),
|
|
750
|
+
});
|
|
751
|
+
addInterface(name, dirPath, connectedKnowledgeBaseName, knowledgeBasePath, selectedWorkflow);
|
|
752
|
+
p.log.warn(failureSummary
|
|
753
|
+
? `${failureSummary} Restored the starter interface plan from the selected workflow.`
|
|
754
|
+
: `Agent exited with code ${result.code}. Restored the starter interface plan from the selected workflow.`);
|
|
755
|
+
p.outro([
|
|
756
|
+
`Interface created: ${dirPath}`,
|
|
757
|
+
failureSummary
|
|
758
|
+
? `The refined interface scaffold did not pass validation: ${failureSummary}`
|
|
759
|
+
: "The agent could not finish refining the plan, but the starter compile plan is valid and editable.",
|
|
760
|
+
`CLI control plane: ${resolveSourceManagementRoot(knowledgeBasePath)}`,
|
|
761
|
+
`Workspace entrypoint: ${dirPath}`,
|
|
762
|
+
`Next: review \`compile-plan.md\`, then run \`cd ${dirPath} && interf compile\`, or run \`interf compile\` from ${resolveSourceManagementRoot(knowledgeBasePath)}.`,
|
|
763
|
+
].join("\n"));
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
function createWizardReporter() {
|
|
767
|
+
return {
|
|
768
|
+
line: (message) => console.log(chalk.dim(` ${message}`)),
|
|
769
|
+
blankLine: () => console.log(),
|
|
770
|
+
};
|
|
771
|
+
}
|
|
772
|
+
async function runKnowledgeBaseCompile(executor, knowledgeBasePath) {
|
|
773
|
+
console.log();
|
|
774
|
+
console.log(chalk.bold(" Compiling knowledge base..."));
|
|
775
|
+
console.log();
|
|
776
|
+
const result = await compileKnowledgeBaseWorkflow({
|
|
777
|
+
executor,
|
|
778
|
+
knowledgeBasePath,
|
|
779
|
+
reporter: createWizardReporter(),
|
|
780
|
+
});
|
|
781
|
+
if (!result.ok) {
|
|
782
|
+
const workflowId = resolveKnowledgeBaseWorkflowFromConfig(readInterfConfig(knowledgeBasePath));
|
|
783
|
+
const failedStage = formatKnowledgeBaseWorkflowStageStep(workflowId, result.failedStage ?? "compile", { workspacePath: knowledgeBasePath });
|
|
784
|
+
console.log(chalk.red(` ${failedStage} failed.`));
|
|
785
|
+
return false;
|
|
786
|
+
}
|
|
787
|
+
console.log();
|
|
788
|
+
console.log(chalk.green(" ✓ Knowledge base ready."));
|
|
789
|
+
return true;
|
|
790
|
+
}
|
|
791
|
+
async function runInterfaceCompile(executor, interfacePath) {
|
|
792
|
+
console.log();
|
|
793
|
+
console.log(chalk.bold(" Compiling interface..."));
|
|
794
|
+
console.log();
|
|
795
|
+
const result = await compileInterfaceWorkflow({
|
|
796
|
+
executor,
|
|
797
|
+
knowledgeBasePath: interfacePath,
|
|
798
|
+
reporter: createWizardReporter(),
|
|
799
|
+
});
|
|
800
|
+
if (!result.ok) {
|
|
801
|
+
const workflowId = resolveInterfaceWorkflowFromConfig(readInterfConfig(interfacePath));
|
|
802
|
+
const failedStage = formatInterfaceWorkflowStageStep(workflowId, result.failedStage ?? "compile", { workspacePath: interfacePath });
|
|
803
|
+
console.log(chalk.red(` ${failedStage} failed.`));
|
|
804
|
+
return false;
|
|
805
|
+
}
|
|
806
|
+
console.log();
|
|
807
|
+
console.log(chalk.green(" ✓ Interface ready."));
|
|
808
|
+
return true;
|
|
809
|
+
}
|
|
810
|
+
function resolveSourceManagementRoot(knowledgeBasePath) {
|
|
811
|
+
return resolveKnowledgeBaseSourcePath(knowledgeBasePath);
|
|
812
|
+
}
|
|
813
|
+
//# sourceMappingURL=create.js.map
|