@shahmarasy/prodo 0.1.4 → 0.1.5
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 +201 -97
- package/bin/prodo.cjs +6 -6
- package/dist/agents/agent-registry.d.ts +13 -0
- package/dist/agents/agent-registry.js +79 -0
- package/dist/agents/anthropic/index.d.ts +9 -0
- package/dist/agents/anthropic/index.js +55 -0
- package/dist/agents/base.d.ts +25 -0
- package/dist/agents/base.js +71 -0
- package/dist/agents/google/index.d.ts +9 -0
- package/dist/agents/google/index.js +53 -0
- package/dist/agents/mock/index.d.ts +11 -0
- package/dist/agents/mock/index.js +26 -0
- package/dist/agents/openai/index.d.ts +9 -0
- package/dist/agents/openai/index.js +57 -0
- package/dist/agents/system-prompts.d.ts +3 -0
- package/dist/agents/system-prompts.js +32 -0
- package/dist/cli/agent-command-installer.d.ts +4 -0
- package/dist/cli/agent-command-installer.js +148 -0
- package/dist/cli/agent-ids.d.ts +15 -0
- package/dist/cli/agent-ids.js +49 -0
- package/dist/cli/doctor.d.ts +1 -0
- package/dist/cli/doctor.js +144 -0
- package/dist/cli/fix-tui.d.ts +4 -0
- package/dist/cli/fix-tui.js +79 -0
- package/dist/cli/index.d.ts +9 -0
- package/dist/cli/index.js +465 -0
- package/dist/cli/init-tui.d.ts +23 -0
- package/dist/cli/init-tui.js +176 -0
- package/dist/cli/init.d.ts +11 -0
- package/dist/cli/init.js +334 -0
- package/dist/cli/normalize-interactive.d.ts +8 -0
- package/dist/cli/normalize-interactive.js +167 -0
- package/dist/cli/preset-loader.d.ts +4 -0
- package/dist/cli/preset-loader.js +210 -0
- package/dist/core/artifact-registry.d.ts +11 -0
- package/dist/core/artifact-registry.js +49 -0
- package/dist/core/artifacts.d.ts +10 -0
- package/dist/core/artifacts.js +892 -0
- package/dist/core/clean.d.ts +10 -0
- package/dist/core/clean.js +74 -0
- package/dist/core/consistency.d.ts +8 -0
- package/dist/core/consistency.js +328 -0
- package/dist/core/constants.d.ts +7 -0
- package/dist/core/constants.js +64 -0
- package/dist/core/errors.d.ts +3 -0
- package/dist/core/errors.js +10 -0
- package/dist/core/fix.d.ts +31 -0
- package/dist/core/fix.js +188 -0
- package/dist/core/hook-executor.d.ts +1 -0
- package/dist/core/hook-executor.js +175 -0
- package/dist/core/markdown.d.ts +16 -0
- package/dist/core/markdown.js +81 -0
- package/dist/core/normalize.d.ts +8 -0
- package/dist/core/normalize.js +125 -0
- package/dist/core/normalized-brief.d.ts +48 -0
- package/dist/core/normalized-brief.js +182 -0
- package/dist/core/output-index.d.ts +13 -0
- package/dist/core/output-index.js +55 -0
- package/dist/core/paths.d.ts +17 -0
- package/dist/core/paths.js +80 -0
- package/dist/core/project-config.d.ts +14 -0
- package/dist/core/project-config.js +69 -0
- package/dist/core/registry.d.ts +13 -0
- package/dist/core/registry.js +115 -0
- package/dist/core/settings.d.ts +7 -0
- package/dist/core/settings.js +35 -0
- package/dist/core/template-engine.d.ts +3 -0
- package/dist/core/template-engine.js +43 -0
- package/dist/core/template-resolver.d.ts +15 -0
- package/dist/core/template-resolver.js +46 -0
- package/dist/core/templates.d.ts +33 -0
- package/dist/core/templates.js +440 -0
- package/dist/core/terminology.d.ts +21 -0
- package/dist/core/terminology.js +143 -0
- package/dist/core/tracing.d.ts +21 -0
- package/dist/core/tracing.js +74 -0
- package/dist/core/types.d.ts +35 -0
- package/dist/core/types.js +5 -0
- package/dist/core/utils.d.ts +7 -0
- package/dist/core/utils.js +66 -0
- package/dist/core/validate.d.ts +10 -0
- package/dist/core/validate.js +226 -0
- package/dist/core/validator.d.ts +5 -0
- package/dist/core/validator.js +76 -0
- package/dist/core/version.d.ts +1 -0
- package/dist/core/version.js +30 -0
- package/dist/core/workflow-commands.d.ts +7 -0
- package/dist/core/workflow-commands.js +29 -0
- package/dist/i18n/en.json +45 -0
- package/dist/i18n/index.d.ts +5 -0
- package/dist/i18n/index.js +63 -0
- package/dist/i18n/tr.json +45 -0
- package/dist/providers/index.d.ts +2 -1
- package/dist/providers/index.js +20 -6
- package/dist/providers/mock-provider.d.ts +1 -1
- package/dist/providers/mock-provider.js +7 -6
- package/dist/providers/openai-provider.d.ts +1 -1
- package/dist/providers/openai-provider.js +1 -1
- package/dist/skills/engine.d.ts +10 -0
- package/dist/skills/engine.js +75 -0
- package/dist/skills/fix-skill.d.ts +2 -0
- package/dist/skills/fix-skill.js +38 -0
- package/dist/skills/generate-artifact-skill.d.ts +2 -0
- package/dist/skills/generate-artifact-skill.js +32 -0
- package/dist/skills/generate-pipeline-skill.d.ts +2 -0
- package/dist/skills/generate-pipeline-skill.js +45 -0
- package/dist/skills/normalize-skill.d.ts +2 -0
- package/dist/skills/normalize-skill.js +29 -0
- package/dist/skills/types.d.ts +28 -0
- package/dist/skills/types.js +2 -0
- package/dist/skills/validate-skill.d.ts +2 -0
- package/dist/skills/validate-skill.js +29 -0
- package/package.json +74 -45
- package/src/agents/agent-registry.ts +93 -0
- package/src/agents/anthropic/index.ts +86 -0
- package/src/agents/anthropic/manifest.json +7 -0
- package/src/agents/base.ts +77 -0
- package/src/agents/google/index.ts +79 -0
- package/src/agents/google/manifest.json +7 -0
- package/src/agents/mock/index.ts +32 -0
- package/src/agents/mock/manifest.json +7 -0
- package/src/agents/openai/index.ts +83 -0
- package/src/agents/openai/manifest.json +7 -0
- package/src/agents/system-prompts.ts +35 -0
- package/src/{agent-command-installer.ts → cli/agent-command-installer.ts} +164 -164
- package/src/{agents.ts → cli/agent-ids.ts} +58 -58
- package/src/{doctor.ts → cli/doctor.ts} +157 -137
- package/src/cli/fix-tui.ts +111 -0
- package/src/{cli.ts → cli/index.ts} +459 -410
- package/src/{init-tui.ts → cli/init-tui.ts} +208 -208
- package/src/{init.ts → cli/init.ts} +398 -398
- package/src/cli/normalize-interactive.ts +241 -0
- package/src/{preset-loader.ts → cli/preset-loader.ts} +237 -237
- package/src/{artifact-registry.ts → core/artifact-registry.ts} +69 -69
- package/src/{artifacts.ts → core/artifacts.ts} +1081 -1072
- package/src/core/clean.ts +88 -0
- package/src/{consistency.ts → core/consistency.ts} +374 -303
- package/src/{constants.ts → core/constants.ts} +72 -72
- package/src/{errors.ts → core/errors.ts} +7 -7
- package/src/core/fix.ts +253 -0
- package/src/{hook-executor.ts → core/hook-executor.ts} +196 -196
- package/src/{markdown.ts → core/markdown.ts} +93 -73
- package/src/{normalize.ts → core/normalize.ts} +145 -137
- package/src/{normalized-brief.ts → core/normalized-brief.ts} +227 -206
- package/src/{output-index.ts → core/output-index.ts} +59 -59
- package/src/{paths.ts → core/paths.ts} +75 -71
- package/src/{project-config.ts → core/project-config.ts} +78 -78
- package/src/{registry.ts → core/registry.ts} +119 -119
- package/src/{settings.ts → core/settings.ts} +35 -35
- package/src/core/template-engine.ts +45 -0
- package/src/{template-resolver.ts → core/template-resolver.ts} +54 -54
- package/src/{templates.ts → core/templates.ts} +452 -452
- package/src/core/terminology.ts +177 -0
- package/src/core/tracing.ts +110 -0
- package/src/{types.ts → core/types.ts} +46 -46
- package/src/{utils.ts → core/utils.ts} +64 -64
- package/src/{validate.ts → core/validate.ts} +252 -246
- package/src/{validator.ts → core/validator.ts} +92 -92
- package/src/{version.ts → core/version.ts} +24 -24
- package/src/{workflow-commands.ts → core/workflow-commands.ts} +32 -32
- package/src/i18n/en.json +45 -0
- package/src/i18n/index.ts +58 -0
- package/src/i18n/tr.json +45 -0
- package/src/providers/index.ts +29 -12
- package/src/providers/mock-provider.ts +200 -199
- package/src/providers/openai-provider.ts +88 -88
- package/src/skills/engine.ts +94 -0
- package/src/skills/fix-skill.ts +38 -0
- package/src/skills/generate-artifact-skill.ts +32 -0
- package/src/skills/generate-pipeline-skill.ts +49 -0
- package/src/skills/normalize-skill.ts +29 -0
- package/src/skills/types.ts +36 -0
- package/src/skills/validate-skill.ts +29 -0
|
@@ -0,0 +1,465 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.runCli = runCli;
|
|
40
|
+
const commander_1 = require("commander");
|
|
41
|
+
const node_crypto_1 = require("node:crypto");
|
|
42
|
+
const promises_1 = __importDefault(require("node:fs/promises"));
|
|
43
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
44
|
+
const agent_ids_1 = require("./agent-ids");
|
|
45
|
+
const artifact_registry_1 = require("../core/artifact-registry");
|
|
46
|
+
const artifacts_1 = require("../core/artifacts");
|
|
47
|
+
const doctor_1 = require("./doctor");
|
|
48
|
+
const errors_1 = require("../core/errors");
|
|
49
|
+
const hook_executor_1 = require("../core/hook-executor");
|
|
50
|
+
const init_1 = require("./init");
|
|
51
|
+
const init_tui_1 = require("./init-tui");
|
|
52
|
+
const clean_1 = require("../core/clean");
|
|
53
|
+
const fix_1 = require("../core/fix");
|
|
54
|
+
const normalize_1 = require("../core/normalize");
|
|
55
|
+
const normalize_interactive_1 = require("./normalize-interactive");
|
|
56
|
+
const fix_tui_1 = require("./fix-tui");
|
|
57
|
+
const paths_1 = require("../core/paths");
|
|
58
|
+
const utils_1 = require("../core/utils");
|
|
59
|
+
const validate_1 = require("../core/validate");
|
|
60
|
+
const version_1 = require("../core/version");
|
|
61
|
+
const dynamicImport = new Function("specifier", "return import(specifier)");
|
|
62
|
+
function mapForcedCommand(forcedCommand) {
|
|
63
|
+
if (forcedCommand === "prodo-init")
|
|
64
|
+
return "init";
|
|
65
|
+
if (forcedCommand === "prodo-validate")
|
|
66
|
+
return "validate";
|
|
67
|
+
if (forcedCommand === "prodo-normalize")
|
|
68
|
+
return "normalize";
|
|
69
|
+
if (forcedCommand === "prodo-fix")
|
|
70
|
+
return "fix";
|
|
71
|
+
if (forcedCommand === "prodo-prd")
|
|
72
|
+
return "prd";
|
|
73
|
+
if (forcedCommand === "prodo-workflow")
|
|
74
|
+
return "workflow";
|
|
75
|
+
if (forcedCommand === "prodo-wireframe")
|
|
76
|
+
return "wireframe";
|
|
77
|
+
if (forcedCommand === "prodo-stories")
|
|
78
|
+
return "stories";
|
|
79
|
+
if (forcedCommand === "prodo-techspec")
|
|
80
|
+
return "techspec";
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
async function runArtifactCommand(type, opts, cwd, log, options) {
|
|
84
|
+
await (0, hook_executor_1.runHookPhase)(cwd, `before_${type}`, log);
|
|
85
|
+
const agent = (0, agent_ids_1.resolveAgent)(opts.agent);
|
|
86
|
+
const file = await (0, artifacts_1.generateArtifact)({
|
|
87
|
+
artifactType: type,
|
|
88
|
+
cwd,
|
|
89
|
+
normalizedBriefOverride: opts.from,
|
|
90
|
+
outPath: opts.out,
|
|
91
|
+
agent,
|
|
92
|
+
revisionType: opts.revisionType
|
|
93
|
+
});
|
|
94
|
+
const agentMsg = agent ? ` [agent=${agent}]` : "";
|
|
95
|
+
log(`${type.toUpperCase()} generated${agentMsg}: ${file}`);
|
|
96
|
+
if (options?.suggestValidate !== false) {
|
|
97
|
+
log("Tip: run `prodo validate` to check cross-artifact consistency.");
|
|
98
|
+
}
|
|
99
|
+
await (0, hook_executor_1.runHookPhase)(cwd, `after_${type}`, log);
|
|
100
|
+
}
|
|
101
|
+
async function snapshotBrief(cwd) {
|
|
102
|
+
const file = (0, paths_1.briefPath)(cwd);
|
|
103
|
+
if (!(await (0, utils_1.fileExists)(file)))
|
|
104
|
+
return null;
|
|
105
|
+
const [raw, stat] = await Promise.all([promises_1.default.readFile(file), promises_1.default.stat(file)]);
|
|
106
|
+
return {
|
|
107
|
+
hash: (0, node_crypto_1.createHash)("sha256").update(raw).digest("hex"),
|
|
108
|
+
mtimeMs: stat.mtimeMs,
|
|
109
|
+
size: stat.size
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
async function withBriefReadOnlyGuard(cwd, task) {
|
|
113
|
+
const before = await snapshotBrief(cwd);
|
|
114
|
+
await task();
|
|
115
|
+
const after = await snapshotBrief(cwd);
|
|
116
|
+
if (!before)
|
|
117
|
+
return;
|
|
118
|
+
if (!after) {
|
|
119
|
+
throw new errors_1.UserError("Input file `brief.md` was removed during execution. Input files are read-only.");
|
|
120
|
+
}
|
|
121
|
+
if (before.hash !== after.hash || before.size !== after.size || before.mtimeMs !== after.mtimeMs) {
|
|
122
|
+
throw new errors_1.UserError("Input file `brief.md` was modified during execution. Input files are read-only.");
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
async function runCli(options = {}) {
|
|
126
|
+
const cwd = options.cwd ?? process.cwd();
|
|
127
|
+
const argv = options.argv ?? process.argv;
|
|
128
|
+
const out = options.log ?? console.log;
|
|
129
|
+
const err = options.error ?? console.error;
|
|
130
|
+
const forced = options.forcedCommand ? mapForcedCommand(options.forcedCommand) : undefined;
|
|
131
|
+
const program = new commander_1.Command();
|
|
132
|
+
const version = await (0, version_1.readCliVersion)(cwd);
|
|
133
|
+
program
|
|
134
|
+
.name("prodo")
|
|
135
|
+
.description("CLI-first, prompt-powered product artifact kit")
|
|
136
|
+
.version(`prodo ${version}`, "-v, --version", "Show Prodo version")
|
|
137
|
+
.showHelpAfterError();
|
|
138
|
+
const artifactTypes = await (0, artifact_registry_1.listArtifactTypes)(cwd);
|
|
139
|
+
program
|
|
140
|
+
.command("init [target]")
|
|
141
|
+
.option("--ai <name>", "agent integration: codex | gemini-cli | claude-cli")
|
|
142
|
+
.option("--lang <code>", "document language (e.g. en, tr)")
|
|
143
|
+
.option("--author <name>", "document author name")
|
|
144
|
+
.option("--preset <name>", "preset to install during initialization")
|
|
145
|
+
.action(async (target, opts) => {
|
|
146
|
+
const projectRoot = node_path_1.default.resolve(cwd, target ?? ".");
|
|
147
|
+
const selected = await (0, init_tui_1.gatherInitSelections)({
|
|
148
|
+
projectRoot,
|
|
149
|
+
aiInput: opts.ai,
|
|
150
|
+
langInput: opts.lang,
|
|
151
|
+
authorInput: opts.author
|
|
152
|
+
});
|
|
153
|
+
const selectedAi = selected.ai;
|
|
154
|
+
if (selected.interactive) {
|
|
155
|
+
const clack = (await dynamicImport("@clack/prompts"));
|
|
156
|
+
const s = clack.spinner();
|
|
157
|
+
s.start("Scaffolding Prodo workspace...");
|
|
158
|
+
const result = await (0, init_1.runInit)(projectRoot, {
|
|
159
|
+
ai: selectedAi,
|
|
160
|
+
lang: selected.lang,
|
|
161
|
+
author: selected.author,
|
|
162
|
+
preset: opts.preset,
|
|
163
|
+
script: selected.script
|
|
164
|
+
});
|
|
165
|
+
s.stop("Scaffold complete.");
|
|
166
|
+
await (0, init_tui_1.finishInitInteractive)({
|
|
167
|
+
projectRoot,
|
|
168
|
+
settingsPath: result.settingsPath,
|
|
169
|
+
ai: selectedAi,
|
|
170
|
+
lang: selected.lang,
|
|
171
|
+
author: selected.author
|
|
172
|
+
});
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
const result = await (0, init_1.runInit)(projectRoot, {
|
|
176
|
+
ai: selectedAi,
|
|
177
|
+
lang: selected.lang,
|
|
178
|
+
author: selected.author,
|
|
179
|
+
preset: opts.preset,
|
|
180
|
+
script: selected.script
|
|
181
|
+
});
|
|
182
|
+
out(`Initialized Prodo scaffold at ${node_path_1.default.join(projectRoot, ".prodo")}`);
|
|
183
|
+
if (selectedAi) {
|
|
184
|
+
out(`Agent command set installed for ${selectedAi}.`);
|
|
185
|
+
out(`Installed ${result.installedAgentFiles.length} command files.`);
|
|
186
|
+
out("Agent workflow: edit brief.md, then run slash commands in your agent.");
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
out("No agent selected. Use `prodo generate` for end-to-end generation.");
|
|
190
|
+
}
|
|
191
|
+
out(`Settings file: ${result.settingsPath}`);
|
|
192
|
+
out(`Author: ${selected.author}`);
|
|
193
|
+
out("Next: edit brief.md.");
|
|
194
|
+
});
|
|
195
|
+
program
|
|
196
|
+
.command("generate")
|
|
197
|
+
.description("Run end-to-end pipeline: normalize -> generate artifacts -> validate")
|
|
198
|
+
.option("--agent <name>", "agent profile: codex | gemini-cli | claude-cli")
|
|
199
|
+
.option("--strict", "treat validation warnings as errors")
|
|
200
|
+
.option("--report <path>", "validation report output path")
|
|
201
|
+
.option("--dry-run", "show what would be generated without writing files")
|
|
202
|
+
.action(async (opts) => {
|
|
203
|
+
if (opts.agent)
|
|
204
|
+
(0, agent_ids_1.resolveAgent)(opts.agent);
|
|
205
|
+
if (opts.dryRun) {
|
|
206
|
+
out("[Dry Run] Pipeline would execute:");
|
|
207
|
+
out(` 1. Normalize brief.md`);
|
|
208
|
+
for (const type of artifactTypes) {
|
|
209
|
+
out(` 2. Generate ${type}`);
|
|
210
|
+
}
|
|
211
|
+
out(` 3. Validate all artifacts`);
|
|
212
|
+
out(`\nArtifact types: ${artifactTypes.join(", ")}`);
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
await withBriefReadOnlyGuard(cwd, async () => {
|
|
216
|
+
await (0, hook_executor_1.runHookPhase)(cwd, "before_normalize", out);
|
|
217
|
+
const normalizedPath = await (0, normalize_1.runNormalize)({ cwd });
|
|
218
|
+
out(`Normalized brief written to: ${normalizedPath}`);
|
|
219
|
+
await (0, hook_executor_1.runHookPhase)(cwd, "after_normalize", out);
|
|
220
|
+
for (const type of artifactTypes) {
|
|
221
|
+
await runArtifactCommand(type, { from: normalizedPath, agent: opts.agent }, cwd, out, {
|
|
222
|
+
suggestValidate: false
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
await (0, hook_executor_1.runHookPhase)(cwd, "before_validate", out);
|
|
226
|
+
const result = await (0, validate_1.runValidate)(cwd, {
|
|
227
|
+
strict: Boolean(opts.strict),
|
|
228
|
+
report: opts.report
|
|
229
|
+
});
|
|
230
|
+
out(`Validation report written to: ${result.reportPath}`);
|
|
231
|
+
if (!result.pass) {
|
|
232
|
+
throw new errors_1.UserError("Validation failed. Review report and fix issues.");
|
|
233
|
+
}
|
|
234
|
+
out("Generation pipeline completed. Validation passed.");
|
|
235
|
+
await (0, hook_executor_1.runHookPhase)(cwd, "after_validate", out);
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
program
|
|
239
|
+
.command("fix", { hidden: true })
|
|
240
|
+
.description("Advanced: auto-regenerate affected artifacts from validation findings")
|
|
241
|
+
.option("--agent <name>", "agent profile: codex | gemini-cli | claude-cli")
|
|
242
|
+
.option("--strict", "treat validation warnings as errors")
|
|
243
|
+
.option("--report <path>", "validation report output path")
|
|
244
|
+
.option("--dry-run", "show fix proposal without applying changes")
|
|
245
|
+
.action(async (opts) => {
|
|
246
|
+
if (opts.agent)
|
|
247
|
+
(0, agent_ids_1.resolveAgent)(opts.agent);
|
|
248
|
+
await withBriefReadOnlyGuard(cwd, async () => {
|
|
249
|
+
const fixOpts = {
|
|
250
|
+
cwd,
|
|
251
|
+
agent: opts.agent,
|
|
252
|
+
strict: Boolean(opts.strict),
|
|
253
|
+
report: opts.report,
|
|
254
|
+
dryRun: Boolean(opts.dryRun),
|
|
255
|
+
log: out
|
|
256
|
+
};
|
|
257
|
+
if (opts.dryRun) {
|
|
258
|
+
const result = await (0, fix_1.runFix)(fixOpts);
|
|
259
|
+
out(`Validation report: ${result.reportPath}`);
|
|
260
|
+
if (result.proposal.targets.length > 0) {
|
|
261
|
+
await (0, fix_tui_1.displayFixProposal)(result.proposal, out);
|
|
262
|
+
}
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
const proposal = await (0, fix_1.buildFixProposal)(fixOpts);
|
|
266
|
+
out(`Validation report: ${proposal.initialReport.reportPath}`);
|
|
267
|
+
if (proposal.targets.length === 0) {
|
|
268
|
+
out("No blocking issues found. Nothing to fix.");
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
await (0, fix_tui_1.displayFixProposal)(proposal, out);
|
|
272
|
+
const confirmed = await (0, fix_tui_1.confirmFixExecution)(proposal);
|
|
273
|
+
if (!confirmed) {
|
|
274
|
+
out("Fix cancelled by user.");
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
out(`Regenerating impacted artifacts: ${proposal.targets.join(", ")}`);
|
|
278
|
+
const result = await (0, fix_1.applyFix)(cwd, proposal, fixOpts);
|
|
279
|
+
await (0, fix_tui_1.displayFixResult)(result, out);
|
|
280
|
+
if (!result.finalPass) {
|
|
281
|
+
throw new errors_1.UserError("Fix completed but validation is still failing. Review report and retry.");
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
});
|
|
285
|
+
program
|
|
286
|
+
.command("normalize", { hidden: true })
|
|
287
|
+
.description("Advanced: normalize brief without full pipeline")
|
|
288
|
+
.option("--brief <path>", "path to start brief markdown")
|
|
289
|
+
.option("--out <path>", "output normalized brief json path")
|
|
290
|
+
.option("--agent <name>", "agent profile: codex | gemini-cli | claude-cli")
|
|
291
|
+
.option("-i, --interactive", "interactively clarify low-confidence fields")
|
|
292
|
+
.option("--dry-run", "show what would be normalized without writing")
|
|
293
|
+
.action(async (opts) => {
|
|
294
|
+
if (opts.agent)
|
|
295
|
+
(0, agent_ids_1.resolveAgent)(opts.agent);
|
|
296
|
+
if (opts.dryRun) {
|
|
297
|
+
const briefFile = opts.brief ?? "brief.md";
|
|
298
|
+
out(`[Dry Run] Would normalize: ${briefFile}`);
|
|
299
|
+
out(`[Dry Run] Output would be written to: .prodo/briefs/normalized-brief.json`);
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
await withBriefReadOnlyGuard(cwd, async () => {
|
|
303
|
+
await (0, hook_executor_1.runHookPhase)(cwd, "before_normalize", out);
|
|
304
|
+
const outPath = opts.interactive
|
|
305
|
+
? await (0, normalize_interactive_1.runInteractiveNormalize)({ cwd, brief: opts.brief, out: opts.out, log: out })
|
|
306
|
+
: await (0, normalize_1.runNormalize)({ cwd, brief: opts.brief, out: opts.out });
|
|
307
|
+
out(`Normalized brief written to: ${outPath}`);
|
|
308
|
+
await (0, hook_executor_1.runHookPhase)(cwd, "after_normalize", out);
|
|
309
|
+
});
|
|
310
|
+
});
|
|
311
|
+
program
|
|
312
|
+
.command("doctor")
|
|
313
|
+
.alias("check")
|
|
314
|
+
.description("Check local environment and toolchain readiness")
|
|
315
|
+
.action(async () => {
|
|
316
|
+
await (0, doctor_1.runDoctor)(cwd, out);
|
|
317
|
+
});
|
|
318
|
+
program
|
|
319
|
+
.command("clean")
|
|
320
|
+
.description("Remove all generated artifacts, keep brief.md and config")
|
|
321
|
+
.option("--dry-run", "show what would be removed without deleting")
|
|
322
|
+
.action(async (opts) => {
|
|
323
|
+
const result = await (0, clean_1.runClean)({
|
|
324
|
+
cwd,
|
|
325
|
+
dryRun: Boolean(opts.dryRun),
|
|
326
|
+
log: out
|
|
327
|
+
});
|
|
328
|
+
if (result.removedPaths.length === 0) {
|
|
329
|
+
out("Nothing to clean.");
|
|
330
|
+
}
|
|
331
|
+
else if (!opts.dryRun) {
|
|
332
|
+
out(`Cleaned ${result.removedPaths.length} path(s). Project is ready for a fresh run.`);
|
|
333
|
+
}
|
|
334
|
+
});
|
|
335
|
+
for (const type of artifactTypes) {
|
|
336
|
+
program
|
|
337
|
+
.command(type, { hidden: true })
|
|
338
|
+
.description(`Advanced: generate only ${type} artifact`)
|
|
339
|
+
.option("--from <path>", "path to normalized-brief.json")
|
|
340
|
+
.option("--out <path>", "output file path")
|
|
341
|
+
.option("--agent <name>", "agent profile: codex | gemini-cli | claude-cli")
|
|
342
|
+
.action(async (opts) => {
|
|
343
|
+
await withBriefReadOnlyGuard(cwd, async () => {
|
|
344
|
+
await runArtifactCommand(type, opts, cwd, out);
|
|
345
|
+
});
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
program
|
|
349
|
+
.command("agent-commands", { hidden: true })
|
|
350
|
+
.requiredOption("--agent <name>", "agent profile: codex | gemini-cli | claude-cli")
|
|
351
|
+
.action(async (opts) => {
|
|
352
|
+
const agent = (0, agent_ids_1.resolveAgent)(opts.agent);
|
|
353
|
+
if (!agent)
|
|
354
|
+
throw new errors_1.UserError("Agent is required.");
|
|
355
|
+
const set = await (0, agent_ids_1.loadAgentCommandSet)(cwd, agent);
|
|
356
|
+
out(`Agent: ${set.agent}`);
|
|
357
|
+
if (set.description)
|
|
358
|
+
out(`Description: ${set.description}`);
|
|
359
|
+
out("");
|
|
360
|
+
out("Recommended sequence:");
|
|
361
|
+
for (const item of set.recommended_sequence ?? []) {
|
|
362
|
+
out(`- ${item.command}: ${item.purpose}`);
|
|
363
|
+
}
|
|
364
|
+
if (set.artifact_shortcuts) {
|
|
365
|
+
out("");
|
|
366
|
+
out("Artifact shortcuts:");
|
|
367
|
+
for (const [key, command] of Object.entries(set.artifact_shortcuts)) {
|
|
368
|
+
out(`- ${key}: ${command}`);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
});
|
|
372
|
+
program
|
|
373
|
+
.command("validate", { hidden: true })
|
|
374
|
+
.description("Advanced: run validation only")
|
|
375
|
+
.option("--strict", "treat warnings as errors")
|
|
376
|
+
.option("--report <path>", "report output path")
|
|
377
|
+
.option("--agent <name>", "agent profile: codex | gemini-cli | claude-cli")
|
|
378
|
+
.action(async (opts) => {
|
|
379
|
+
if (opts.agent)
|
|
380
|
+
(0, agent_ids_1.resolveAgent)(opts.agent);
|
|
381
|
+
await withBriefReadOnlyGuard(cwd, async () => {
|
|
382
|
+
await (0, hook_executor_1.runHookPhase)(cwd, "before_validate", out);
|
|
383
|
+
const result = await (0, validate_1.runValidate)(cwd, {
|
|
384
|
+
strict: Boolean(opts.strict),
|
|
385
|
+
report: opts.report
|
|
386
|
+
});
|
|
387
|
+
out(`Validation report written to: ${result.reportPath}`);
|
|
388
|
+
if (!result.pass) {
|
|
389
|
+
throw new errors_1.UserError("Validation failed. Review report and fix issues.");
|
|
390
|
+
}
|
|
391
|
+
out("Validation passed.");
|
|
392
|
+
await (0, hook_executor_1.runHookPhase)(cwd, "after_validate", out);
|
|
393
|
+
});
|
|
394
|
+
});
|
|
395
|
+
program
|
|
396
|
+
.command("skills", { hidden: true })
|
|
397
|
+
.description("Advanced: manage and run skills")
|
|
398
|
+
.argument("[action]", "list or run", "list")
|
|
399
|
+
.argument("[name]", "skill name (for run)")
|
|
400
|
+
.option("--input <json>", "JSON input for skill execution")
|
|
401
|
+
.action(async (action, name, opts) => {
|
|
402
|
+
const { getGlobalSkillEngine } = await Promise.resolve().then(() => __importStar(require("../skills/engine")));
|
|
403
|
+
const engine = getGlobalSkillEngine();
|
|
404
|
+
if (action === "list") {
|
|
405
|
+
const manifests = engine.listSkills();
|
|
406
|
+
if (manifests.length === 0) {
|
|
407
|
+
out("No skills registered.");
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
out("Available skills:\n");
|
|
411
|
+
for (const m of manifests) {
|
|
412
|
+
out(` ${m.name.padEnd(25)} [${m.category}] ${m.description}`);
|
|
413
|
+
}
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
if (action === "run") {
|
|
417
|
+
if (!name)
|
|
418
|
+
throw new errors_1.UserError("Skill name is required. Usage: prodo skills run <name>");
|
|
419
|
+
const inputs = opts.input ? JSON.parse(opts.input) : {};
|
|
420
|
+
inputs.cwd = inputs.cwd ?? cwd;
|
|
421
|
+
const result = await engine.execute(name, { cwd, log: out }, inputs);
|
|
422
|
+
out(`\nSkill "${name}" completed.`);
|
|
423
|
+
out(JSON.stringify(result, null, 2));
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
throw new errors_1.UserError(`Unknown skills action: "${action}". Use: list or run`);
|
|
427
|
+
});
|
|
428
|
+
try {
|
|
429
|
+
if (forced) {
|
|
430
|
+
if (forced === "init") {
|
|
431
|
+
await program.parseAsync(["node", "prodo", "init", ...argv.slice(2)]);
|
|
432
|
+
}
|
|
433
|
+
else if (forced === "normalize") {
|
|
434
|
+
await program.parseAsync(["node", "prodo", "normalize", ...argv.slice(2)]);
|
|
435
|
+
}
|
|
436
|
+
else if (forced === "validate") {
|
|
437
|
+
await program.parseAsync(["node", "prodo", "validate", ...argv.slice(2)]);
|
|
438
|
+
}
|
|
439
|
+
else if (forced === "fix") {
|
|
440
|
+
await program.parseAsync(["node", "prodo", "fix", ...argv.slice(2)]);
|
|
441
|
+
}
|
|
442
|
+
else {
|
|
443
|
+
await program.parseAsync(["node", "prodo", forced, ...argv.slice(2)]);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
else {
|
|
447
|
+
await program.parseAsync(argv);
|
|
448
|
+
}
|
|
449
|
+
return 0;
|
|
450
|
+
}
|
|
451
|
+
catch (error) {
|
|
452
|
+
if (error instanceof errors_1.UserError) {
|
|
453
|
+
err(error.message);
|
|
454
|
+
return 1;
|
|
455
|
+
}
|
|
456
|
+
const unknown = error;
|
|
457
|
+
err(unknown.message);
|
|
458
|
+
return 1;
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
if (require.main === module) {
|
|
462
|
+
runCli().then((code) => {
|
|
463
|
+
process.exitCode = code;
|
|
464
|
+
});
|
|
465
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type SupportedAi } from "./agent-command-installer";
|
|
2
|
+
export type InitSelections = {
|
|
3
|
+
ai?: SupportedAi;
|
|
4
|
+
script: "sh" | "ps";
|
|
5
|
+
lang: "tr" | "en";
|
|
6
|
+
author: string;
|
|
7
|
+
interactive: boolean;
|
|
8
|
+
};
|
|
9
|
+
type GatherInitUiOptions = {
|
|
10
|
+
projectRoot: string;
|
|
11
|
+
aiInput?: string;
|
|
12
|
+
langInput?: string;
|
|
13
|
+
authorInput?: string;
|
|
14
|
+
};
|
|
15
|
+
export declare function gatherInitSelections(options: GatherInitUiOptions): Promise<InitSelections>;
|
|
16
|
+
export declare function finishInitInteractive(summary: {
|
|
17
|
+
projectRoot: string;
|
|
18
|
+
settingsPath: string;
|
|
19
|
+
ai?: SupportedAi;
|
|
20
|
+
lang: "tr" | "en";
|
|
21
|
+
author: string;
|
|
22
|
+
}): Promise<void>;
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.gatherInitSelections = gatherInitSelections;
|
|
7
|
+
exports.finishInitInteractive = finishInitInteractive;
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const node_os_1 = __importDefault(require("node:os"));
|
|
10
|
+
const agent_command_installer_1 = require("./agent-command-installer");
|
|
11
|
+
const errors_1 = require("../core/errors");
|
|
12
|
+
const utils_1 = require("../core/utils");
|
|
13
|
+
const dynamicImport = new Function("specifier", "return import(specifier)");
|
|
14
|
+
async function loadClack() {
|
|
15
|
+
return (await dynamicImport("@clack/prompts"));
|
|
16
|
+
}
|
|
17
|
+
function isInteractiveTerminal() {
|
|
18
|
+
return Boolean(process.stdin.isTTY && process.stdout.isTTY && !process.env.CI);
|
|
19
|
+
}
|
|
20
|
+
function color(text, code) {
|
|
21
|
+
return `${code}${text}\u001B[0m`;
|
|
22
|
+
}
|
|
23
|
+
function stripAnsi(input) {
|
|
24
|
+
return input.replace(/\u001B\[[0-9;]*m/g, "");
|
|
25
|
+
}
|
|
26
|
+
function centerLine(line, width) {
|
|
27
|
+
const visible = stripAnsi(line).length;
|
|
28
|
+
const left = Math.max(0, Math.floor((width - visible) / 2));
|
|
29
|
+
return `${" ".repeat(left)}${line}`;
|
|
30
|
+
}
|
|
31
|
+
function centerBlock(lines, width) {
|
|
32
|
+
return lines.map((line) => centerLine(line, width)).join("\n");
|
|
33
|
+
}
|
|
34
|
+
function terminalWidth() {
|
|
35
|
+
const columns = process.stdout.columns ?? 100;
|
|
36
|
+
return Math.max(80, columns);
|
|
37
|
+
}
|
|
38
|
+
function renderLogo() {
|
|
39
|
+
const cyan = "\u001B[38;5;45m";
|
|
40
|
+
const blue = "\u001B[38;5;39m";
|
|
41
|
+
const lines = [
|
|
42
|
+
"██████╗ ██████╗ ██████╗ ██████╗ ██████╗ ",
|
|
43
|
+
"██╔══██╗██╔══██╗██╔═══██╗██╔══██╗██╔═══██╗",
|
|
44
|
+
"██████╔╝██████╔╝██║ ██║██║ ██║██║ ██║",
|
|
45
|
+
"██╔═══╝ ██╔══██╗██║ ██║██║ ██║██║ ██║",
|
|
46
|
+
"██║ ██║ ██║╚██████╔╝██████╔╝╚██████╔╝"
|
|
47
|
+
];
|
|
48
|
+
return lines.map((line, idx) => color(line, idx % 2 === 0 ? cyan : blue)).join("\n");
|
|
49
|
+
}
|
|
50
|
+
function renderProjectBox(projectName, projectRoot) {
|
|
51
|
+
const content = [`Project ${projectName}`, `Directory ${projectRoot}`];
|
|
52
|
+
const innerWidth = Math.max(...content.map((line) => line.length)) + 2;
|
|
53
|
+
const top = `┌${"─".repeat(innerWidth)}┐`;
|
|
54
|
+
const rows = content.map((line) => `│ ${line.padEnd(innerWidth - 1)}│`);
|
|
55
|
+
const bottom = `└${"─".repeat(innerWidth)}┘`;
|
|
56
|
+
return [top, ...rows, bottom].join("\n");
|
|
57
|
+
}
|
|
58
|
+
async function detectAi(projectRoot) {
|
|
59
|
+
if (await (0, utils_1.fileExists)(node_path_1.default.join(projectRoot, ".agents")))
|
|
60
|
+
return "codex";
|
|
61
|
+
if (await (0, utils_1.fileExists)(node_path_1.default.join(projectRoot, ".gemini")))
|
|
62
|
+
return "gemini-cli";
|
|
63
|
+
if (await (0, utils_1.fileExists)(node_path_1.default.join(projectRoot, ".claude")))
|
|
64
|
+
return "claude-cli";
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
function normalizeLang(lang) {
|
|
68
|
+
if ((lang ?? "").trim().toLowerCase().startsWith("tr"))
|
|
69
|
+
return "tr";
|
|
70
|
+
return "en";
|
|
71
|
+
}
|
|
72
|
+
function modelChoiceFromAi(ai) {
|
|
73
|
+
if (ai === "codex")
|
|
74
|
+
return "codex";
|
|
75
|
+
if (ai === "gemini-cli")
|
|
76
|
+
return "gemini";
|
|
77
|
+
return "auto-detect";
|
|
78
|
+
}
|
|
79
|
+
function defaultAuthorName(authorInput) {
|
|
80
|
+
const explicit = (authorInput ?? "").trim();
|
|
81
|
+
if (explicit.length > 0)
|
|
82
|
+
return explicit;
|
|
83
|
+
try {
|
|
84
|
+
const username = node_os_1.default.userInfo().username.trim();
|
|
85
|
+
if (username.length > 0)
|
|
86
|
+
return username;
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
// ignore lookup errors and continue with fallback
|
|
90
|
+
}
|
|
91
|
+
return "Product Author";
|
|
92
|
+
}
|
|
93
|
+
async function gatherInitSelections(options) {
|
|
94
|
+
const clack = await loadClack();
|
|
95
|
+
const defaultLang = normalizeLang(options.langInput);
|
|
96
|
+
const fallbackScript = process.platform === "win32" ? "ps" : "sh";
|
|
97
|
+
const parsedAi = (0, agent_command_installer_1.resolveAi)(options.aiInput);
|
|
98
|
+
const defaultAuthor = defaultAuthorName(options.authorInput);
|
|
99
|
+
if (!isInteractiveTerminal()) {
|
|
100
|
+
return {
|
|
101
|
+
ai: parsedAi,
|
|
102
|
+
script: fallbackScript,
|
|
103
|
+
lang: defaultLang,
|
|
104
|
+
author: defaultAuthor,
|
|
105
|
+
interactive: false
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
const detectedAi = await detectAi(options.projectRoot);
|
|
109
|
+
const initialModel = modelChoiceFromAi(parsedAi ?? detectedAi);
|
|
110
|
+
const projectName = node_path_1.default.basename(options.projectRoot) || ".";
|
|
111
|
+
const width = terminalWidth();
|
|
112
|
+
const subtitle = color("Prodo — Product Artifact Toolkit", "\u001B[1;37m");
|
|
113
|
+
const signature = color("Crafted by Codex, guided by Shahmarasy intelligence", "\u001B[38;5;244m");
|
|
114
|
+
const hero = [
|
|
115
|
+
"",
|
|
116
|
+
centerBlock(renderLogo().split("\n"), width),
|
|
117
|
+
"",
|
|
118
|
+
centerLine(subtitle, width),
|
|
119
|
+
centerLine(signature, width),
|
|
120
|
+
""
|
|
121
|
+
].join("\n");
|
|
122
|
+
clack.intro(hero);
|
|
123
|
+
clack.note(renderProjectBox(projectName, options.projectRoot), "Project Setup");
|
|
124
|
+
const model = await clack.select({
|
|
125
|
+
message: "Select model",
|
|
126
|
+
initialValue: initialModel,
|
|
127
|
+
options: [
|
|
128
|
+
{ value: "codex", label: "codex", hint: "Native Codex flow" },
|
|
129
|
+
{ value: "gemini", label: "gemini", hint: "Gemini CLI command set" },
|
|
130
|
+
{ value: "auto-detect", label: "auto-detect", hint: "Detect from local agent directories" }
|
|
131
|
+
]
|
|
132
|
+
});
|
|
133
|
+
if (clack.isCancel(model)) {
|
|
134
|
+
clack.cancel("Initialization cancelled.");
|
|
135
|
+
throw new errors_1.UserError("Initialization cancelled.");
|
|
136
|
+
}
|
|
137
|
+
const lang = await clack.select({
|
|
138
|
+
message: "Select language",
|
|
139
|
+
initialValue: defaultLang,
|
|
140
|
+
options: [
|
|
141
|
+
{ value: "tr", label: "tr", hint: "Turkish" },
|
|
142
|
+
{ value: "en", label: "en", hint: "English" }
|
|
143
|
+
]
|
|
144
|
+
});
|
|
145
|
+
if (clack.isCancel(lang)) {
|
|
146
|
+
clack.cancel("Initialization cancelled.");
|
|
147
|
+
throw new errors_1.UserError("Initialization cancelled.");
|
|
148
|
+
}
|
|
149
|
+
const author = await clack.text({
|
|
150
|
+
message: "Author name",
|
|
151
|
+
placeholder: "Shahmarasy",
|
|
152
|
+
defaultValue: defaultAuthor
|
|
153
|
+
});
|
|
154
|
+
if (clack.isCancel(author)) {
|
|
155
|
+
clack.cancel("Initialization cancelled.");
|
|
156
|
+
throw new errors_1.UserError("Initialization cancelled.");
|
|
157
|
+
}
|
|
158
|
+
let selectedAi;
|
|
159
|
+
if (model === "codex")
|
|
160
|
+
selectedAi = "codex";
|
|
161
|
+
else if (model === "gemini")
|
|
162
|
+
selectedAi = "gemini-cli";
|
|
163
|
+
else
|
|
164
|
+
selectedAi = detectedAi;
|
|
165
|
+
return {
|
|
166
|
+
ai: selectedAi,
|
|
167
|
+
script: fallbackScript,
|
|
168
|
+
lang,
|
|
169
|
+
author: String(author).trim() || defaultAuthor,
|
|
170
|
+
interactive: true
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
function finishInitInteractive(summary) {
|
|
174
|
+
const aiText = summary.ai ?? "none";
|
|
175
|
+
return loadClack().then((clack) => clack.outro(`Scaffold complete.\nAI: ${aiText}\nLanguage: ${summary.lang}\nAuthor: ${summary.author}\nSettings: ${summary.settingsPath}\nNext: edit brief.md`));
|
|
176
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type SupportedAi } from "./agent-command-installer";
|
|
2
|
+
export declare function runInit(cwd: string, options?: {
|
|
3
|
+
ai?: SupportedAi;
|
|
4
|
+
lang?: string;
|
|
5
|
+
author?: string;
|
|
6
|
+
preset?: string;
|
|
7
|
+
script?: "sh" | "ps";
|
|
8
|
+
}): Promise<{
|
|
9
|
+
installedAgentFiles: string[];
|
|
10
|
+
settingsPath: string;
|
|
11
|
+
}>;
|