deweyou-cli 0.3.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +35 -0
- package/README.md +21 -0
- package/dist/deweyou.mjs +100 -5
- package/dist/{init-g2D-URoL.mjs → init-6406tZjR.mjs} +293 -27
- package/dist/prompts-DdaeRkBa.mjs +189 -0
- package/package.json +1 -1
- package/dist/prompts-DVRcV560.mjs +0 -100
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.5.0 - 2026-05-17
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- add deweyou-cli help and version flags
|
|
8
|
+
## 0.4.0 - 2026-05-17
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- add interactive rule install prompts
|
|
13
|
+
- wire rule installs into init
|
|
14
|
+
- add rule install adapters
|
|
15
|
+
- parse rule install init flags
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- refuse agents symlink writes
|
|
20
|
+
- harden rule install safety
|
|
21
|
+
- preserve explicit init mode
|
|
22
|
+
- preserve init flags in wizard
|
|
23
|
+
- omit claude preview without rules
|
|
24
|
+
- include agents preview for claude installs
|
|
25
|
+
- read inline project rules from cache
|
|
26
|
+
- forward init rule install flags
|
|
27
|
+
- handle Claude rule install validation
|
|
28
|
+
- preserve only AGENTS Claude symlink
|
|
29
|
+
- document rule install init flags
|
|
30
|
+
|
|
31
|
+
### Changed
|
|
32
|
+
|
|
33
|
+
- share managed markdown sections
|
|
34
|
+
|
|
35
|
+
### Documentation
|
|
36
|
+
|
|
37
|
+
- document rule install targets
|
|
3
38
|
## 0.3.1 - 2026-05-17
|
|
4
39
|
|
|
5
40
|
### Changed
|
package/README.md
CHANGED
|
@@ -37,6 +37,8 @@ cd /path/to/your/repo
|
|
|
37
37
|
deweyou-cli agent init
|
|
38
38
|
deweyou-cli agent doctor
|
|
39
39
|
deweyou-cli agent context --format markdown
|
|
40
|
+
deweyou-cli agent -h
|
|
41
|
+
deweyou-cli -v
|
|
40
42
|
```
|
|
41
43
|
|
|
42
44
|
For a non-interactive setup that selects everything:
|
|
@@ -59,6 +61,13 @@ skills and rules; a writing or design repo can select different ones.
|
|
|
59
61
|
|
|
60
62
|
## Commands
|
|
61
63
|
|
|
64
|
+
General options:
|
|
65
|
+
|
|
66
|
+
| Option | Meaning |
|
|
67
|
+
|--------|---------|
|
|
68
|
+
| `-h`, `--help` | Show help. Supports nested help such as `deweyou-cli agent -h` and `deweyou-cli agent init -h`. |
|
|
69
|
+
| `-v`, `--version` | Show the installed CLI version. |
|
|
70
|
+
|
|
62
71
|
### `deweyou-cli agent update`
|
|
63
72
|
|
|
64
73
|
Refreshes the local Dewey asset cache from the default `deweyou/agents` source
|
|
@@ -91,6 +100,12 @@ Initializes the current repository with selected skills and rules.
|
|
|
91
100
|
deweyou-cli agent init
|
|
92
101
|
```
|
|
93
102
|
|
|
103
|
+
Usage:
|
|
104
|
+
|
|
105
|
+
```text
|
|
106
|
+
deweyou-cli agent init [--all] [--skills a,b] [--rules a,b] [--mode link|copy|pointer] [--scope project|global] [--tools codex,claude|all] [--rule-wiring reference|inline] [--yes] [--dry-run] [--force]
|
|
107
|
+
```
|
|
108
|
+
|
|
94
109
|
Without selection flags, this opens an interactive setup where you choose:
|
|
95
110
|
|
|
96
111
|
- install mode
|
|
@@ -102,6 +117,8 @@ Scripted examples:
|
|
|
102
117
|
```bash
|
|
103
118
|
deweyou-cli agent init --all --mode link --yes
|
|
104
119
|
deweyou-cli agent init --skills repo-memory,spec-driven-coding,git-delivery --rules code-style
|
|
120
|
+
deweyou-cli agent init --scope project --tools codex,claude --rules code-style --mode link
|
|
121
|
+
deweyou-cli agent init --scope global --tools all --rules code-style --rule-wiring reference --yes
|
|
105
122
|
deweyou-cli agent init --dry-run
|
|
106
123
|
```
|
|
107
124
|
|
|
@@ -182,6 +199,10 @@ AGENTS.md
|
|
|
182
199
|
`AGENTS.md` receives a managed Dewey section that points agents at the selected
|
|
183
200
|
workflow context. Existing content outside that managed section is preserved.
|
|
184
201
|
|
|
202
|
+
Project installs write repository instruction files such as `AGENTS.md` and
|
|
203
|
+
`CLAUDE.md`. Global installs write user-level instruction files such as
|
|
204
|
+
`~/.codex/AGENTS.md` and `~/.claude/CLAUDE.md`.
|
|
205
|
+
|
|
185
206
|
## Safety Notes
|
|
186
207
|
|
|
187
208
|
- Run `deweyou-cli agent update` before `deweyou-cli agent init`.
|
package/dist/deweyou.mjs
CHANGED
|
@@ -11,7 +11,10 @@ const VALUE_FLAGS = new Set([
|
|
|
11
11
|
"mode",
|
|
12
12
|
"skills",
|
|
13
13
|
"rules",
|
|
14
|
-
"format"
|
|
14
|
+
"format",
|
|
15
|
+
"scope",
|
|
16
|
+
"tools",
|
|
17
|
+
"rule-wiring"
|
|
15
18
|
]);
|
|
16
19
|
const FLAGS_BY_COMMAND = {
|
|
17
20
|
init: new Set([
|
|
@@ -19,6 +22,9 @@ const FLAGS_BY_COMMAND = {
|
|
|
19
22
|
"skills",
|
|
20
23
|
"rules",
|
|
21
24
|
"mode",
|
|
25
|
+
"scope",
|
|
26
|
+
"tools",
|
|
27
|
+
"rule-wiring",
|
|
22
28
|
"yes",
|
|
23
29
|
"dry-run",
|
|
24
30
|
"force"
|
|
@@ -69,19 +75,37 @@ function isAllowedForCommand(command, name) {
|
|
|
69
75
|
return FLAGS_BY_COMMAND[command]?.has(name) ?? false;
|
|
70
76
|
}
|
|
71
77
|
function parseValue(name, value) {
|
|
72
|
-
if (name === "skills" || name === "rules") return value.split(",").map((item) => item.trim()).filter(Boolean);
|
|
78
|
+
if (name === "skills" || name === "rules" || name === "tools") return value.split(",").map((item) => item.trim()).filter(Boolean);
|
|
73
79
|
return value;
|
|
74
80
|
}
|
|
75
81
|
function toCamel(value) {
|
|
76
82
|
return value.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
77
83
|
}
|
|
78
84
|
//#endregion
|
|
85
|
+
//#region package.json
|
|
86
|
+
var version = "0.5.0";
|
|
87
|
+
//#endregion
|
|
79
88
|
//#region src/cli/main.ts
|
|
89
|
+
const COMMANDS = [
|
|
90
|
+
"init",
|
|
91
|
+
"update",
|
|
92
|
+
"context",
|
|
93
|
+
"doctor"
|
|
94
|
+
];
|
|
80
95
|
async function main(argv) {
|
|
96
|
+
const help = helpFor(argv);
|
|
97
|
+
if (help) {
|
|
98
|
+
console.log(help);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
if (isVersionRequest(argv)) {
|
|
102
|
+
console.log(version);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
81
105
|
const parsed = parseArgs(argv);
|
|
82
106
|
if (parsed.topic !== "agent") printUsageAndThrow();
|
|
83
107
|
if (parsed.command === "init") {
|
|
84
|
-
const { runInit } = await import("./init-
|
|
108
|
+
const { runInit } = await import("./init-6406tZjR.mjs");
|
|
85
109
|
await runInit(parsed.flags);
|
|
86
110
|
return;
|
|
87
111
|
}
|
|
@@ -103,16 +127,87 @@ async function main(argv) {
|
|
|
103
127
|
printUsageAndThrow();
|
|
104
128
|
}
|
|
105
129
|
function usage() {
|
|
130
|
+
return rootUsage();
|
|
131
|
+
}
|
|
132
|
+
function rootUsage() {
|
|
133
|
+
return `Usage:
|
|
134
|
+
deweyou-cli agent <command> [options]
|
|
135
|
+
|
|
136
|
+
Commands:
|
|
137
|
+
agent init Initialize the current repository with Dewey assets.
|
|
138
|
+
agent update Refresh the local Dewey asset cache.
|
|
139
|
+
agent context Print the active Dewey agent context.
|
|
140
|
+
agent doctor Check whether the repository and cache are healthy.
|
|
141
|
+
|
|
142
|
+
Options:
|
|
143
|
+
-h, --help Show help.
|
|
144
|
+
-v, --version Show the CLI version.`;
|
|
145
|
+
}
|
|
146
|
+
function agentUsage() {
|
|
106
147
|
return `Usage:
|
|
107
|
-
deweyou-cli agent init [--all] [--skills a,b] [--rules a,b] [--mode link|copy|pointer] [--yes] [--dry-run] [--force]
|
|
148
|
+
deweyou-cli agent init [--all] [--skills a,b] [--rules a,b] [--mode link|copy|pointer] [--scope project|global] [--tools codex,claude|all] [--rule-wiring reference|inline] [--yes] [--dry-run] [--force]
|
|
108
149
|
deweyou-cli agent update
|
|
109
150
|
deweyou-cli agent context [--format markdown|json]
|
|
110
|
-
deweyou-cli agent doctor
|
|
151
|
+
deweyou-cli agent doctor
|
|
152
|
+
|
|
153
|
+
Run \`deweyou-cli agent <command> -h\` for command-specific help.`;
|
|
154
|
+
}
|
|
155
|
+
function commandUsage(command) {
|
|
156
|
+
if (command === "init") return `Usage:
|
|
157
|
+
deweyou-cli agent init [--all] [--skills a,b] [--rules a,b] [--mode link|copy|pointer] [--scope project|global] [--tools codex,claude|all] [--rule-wiring reference|inline] [--yes] [--dry-run] [--force]
|
|
158
|
+
|
|
159
|
+
Options:
|
|
160
|
+
--all Select every skill and rule.
|
|
161
|
+
--skills a,b Select comma-separated skill ids.
|
|
162
|
+
--rules a,b Select comma-separated rule ids.
|
|
163
|
+
--mode link|copy|pointer Choose how assets are referenced.
|
|
164
|
+
--scope project|global Write project or user-level instructions.
|
|
165
|
+
--tools codex,claude|all Select target agent tools.
|
|
166
|
+
--rule-wiring reference|inline
|
|
167
|
+
Choose how rules are written into instructions.
|
|
168
|
+
--yes Run without prompts for scripted selections.
|
|
169
|
+
--dry-run Print the plan without writing files.
|
|
170
|
+
--force Replace existing Dewey-managed destinations.
|
|
171
|
+
-h, --help Show help.`;
|
|
172
|
+
if (command === "context") return `Usage:
|
|
173
|
+
deweyou-cli agent context [--format markdown|json]
|
|
174
|
+
|
|
175
|
+
Options:
|
|
176
|
+
--format markdown|json Choose human-readable or structured output.
|
|
177
|
+
-h, --help Show help.`;
|
|
178
|
+
if (command === "update") return `Usage:
|
|
179
|
+
deweyou-cli agent update
|
|
180
|
+
|
|
181
|
+
Options:
|
|
182
|
+
-h, --help Show help.`;
|
|
183
|
+
return `Usage:
|
|
184
|
+
deweyou-cli agent doctor
|
|
185
|
+
|
|
186
|
+
Options:
|
|
187
|
+
-h, --help Show help.`;
|
|
111
188
|
}
|
|
112
189
|
function printUsageAndThrow() {
|
|
113
190
|
console.log(usage());
|
|
114
191
|
throw usageError("", { silent: true });
|
|
115
192
|
}
|
|
193
|
+
function helpFor(argv) {
|
|
194
|
+
if (!argv.some(isHelpFlag)) return null;
|
|
195
|
+
if (isHelpFlag(argv[0])) return rootUsage();
|
|
196
|
+
if (argv[0] !== "agent") return rootUsage();
|
|
197
|
+
const command = argv[1];
|
|
198
|
+
if (!command || isHelpFlag(command)) return agentUsage();
|
|
199
|
+
if (isAgentCommand(command)) return commandUsage(command);
|
|
200
|
+
return agentUsage();
|
|
201
|
+
}
|
|
202
|
+
function isVersionRequest(argv) {
|
|
203
|
+
return argv.length === 1 && (argv[0] === "-v" || argv[0] === "--version");
|
|
204
|
+
}
|
|
205
|
+
function isHelpFlag(value) {
|
|
206
|
+
return value === "-h" || value === "--help";
|
|
207
|
+
}
|
|
208
|
+
function isAgentCommand(value) {
|
|
209
|
+
return COMMANDS.includes(value);
|
|
210
|
+
}
|
|
116
211
|
//#endregion
|
|
117
212
|
//#region src/bin/deweyou.ts
|
|
118
213
|
main(process.argv.slice(2)).catch((error) => {
|
|
@@ -1,18 +1,37 @@
|
|
|
1
1
|
import { cachePaths, n as writeJson, t as readJson } from "./cache-rbXm6Wyh.mjs";
|
|
2
|
-
import { cp, lstat, mkdir, readFile, realpath, rename, rm, symlink, writeFile } from "node:fs/promises";
|
|
2
|
+
import { cp, lstat, mkdir, readFile, readlink, realpath, rename, rm, symlink, writeFile } from "node:fs/promises";
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
|
-
import { basename, dirname, isAbsolute, join, relative } from "node:path";
|
|
4
|
+
import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
5
|
+
//#region src/cli/managed-section.ts
|
|
6
|
+
function upsertManagedSection(contents, { start, end, body }) {
|
|
7
|
+
const section = `${start}\n${body.trimEnd()}\n${end}`;
|
|
8
|
+
const markedSection = new RegExp(`${escapeRegex(start)}[\\s\\S]*?${escapeRegex(end)}`);
|
|
9
|
+
if (markedSection.test(contents)) return ensureTrailingNewline(contents.replace(markedSection, section));
|
|
10
|
+
const trimmed = contents.trimEnd();
|
|
11
|
+
if (!trimmed) return `${section}\n`;
|
|
12
|
+
return `${trimmed}\n\n${section}\n`;
|
|
13
|
+
}
|
|
14
|
+
function escapeRegex(value) {
|
|
15
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
16
|
+
}
|
|
17
|
+
function ensureTrailingNewline(value) {
|
|
18
|
+
return value.endsWith("\n") ? value : `${value}\n`;
|
|
19
|
+
}
|
|
20
|
+
//#endregion
|
|
5
21
|
//#region src/cli/agents-md.ts
|
|
6
22
|
const DEWEYOU_SECTION_START = "<!-- deweyou-agent:start -->";
|
|
7
23
|
const DEWEYOU_SECTION_END = "<!-- deweyou-agent:end -->";
|
|
8
|
-
const
|
|
9
|
-
## Dewey Workflow
|
|
24
|
+
const DEWEY_SECTION_BODY = `## Dewey Workflow
|
|
10
25
|
|
|
11
|
-
This repository uses Dewey's personal agent workflow. Inspect \`.agents/\` before making changes, then run \`deweyou-cli agent context --format markdown\` and follow the returned rules, skill index, asset paths, and runtime notices
|
|
12
|
-
${DEWEYOU_SECTION_END}`;
|
|
26
|
+
This repository uses Dewey's personal agent workflow. Inspect \`.agents/\` before making changes, then run \`deweyou-cli agent context --format markdown\` and follow the returned rules, skill index, asset paths, and runtime notices.`;
|
|
13
27
|
async function upsertAgentsSection(repoRoot) {
|
|
14
28
|
const path = join(repoRoot, "AGENTS.md");
|
|
15
|
-
|
|
29
|
+
await validateAgentsWritePath(path);
|
|
30
|
+
const next = upsertManagedSection(await readAgentsFile(path), {
|
|
31
|
+
start: DEWEYOU_SECTION_START,
|
|
32
|
+
end: DEWEYOU_SECTION_END,
|
|
33
|
+
body: DEWEY_SECTION_BODY
|
|
34
|
+
});
|
|
16
35
|
await writeFile(path, next);
|
|
17
36
|
return next;
|
|
18
37
|
}
|
|
@@ -25,18 +44,160 @@ async function readAgentsFile(path) {
|
|
|
25
44
|
throw error;
|
|
26
45
|
}
|
|
27
46
|
}
|
|
28
|
-
function
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
47
|
+
async function validateAgentsWritePath(path) {
|
|
48
|
+
try {
|
|
49
|
+
if ((await lstat(path)).isSymbolicLink()) throw new Error(`Refusing to write Dewey workflow through symlink: ${path}`);
|
|
50
|
+
} catch (error) {
|
|
51
|
+
if (!(error instanceof Error) || !("code" in error)) throw error;
|
|
52
|
+
if (error.code === "ENOENT") return;
|
|
53
|
+
throw error;
|
|
54
|
+
}
|
|
34
55
|
}
|
|
35
|
-
|
|
36
|
-
|
|
56
|
+
//#endregion
|
|
57
|
+
//#region src/cli/rule-install.ts
|
|
58
|
+
const CODEX_START = "<!-- deweyou-codex-rules:start -->";
|
|
59
|
+
const CODEX_END = "<!-- deweyou-codex-rules:end -->";
|
|
60
|
+
const CLAUDE_START = "<!-- deweyou-claude-rules:start -->";
|
|
61
|
+
const CLAUDE_END = "<!-- deweyou-claude-rules:end -->";
|
|
62
|
+
async function planRuleInstall(input) {
|
|
63
|
+
validateRuleInstallInput(input);
|
|
64
|
+
if (input.selectedRules.length === 0) return {
|
|
65
|
+
files: [],
|
|
66
|
+
operations: []
|
|
67
|
+
};
|
|
68
|
+
const operations = [];
|
|
69
|
+
if (input.tools.includes("codex")) operations.push(await codexOperation(input));
|
|
70
|
+
if (input.tools.includes("claude")) {
|
|
71
|
+
const operation = await claudeOperation(input);
|
|
72
|
+
if (operation) operations.push(operation);
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
files: operations.map((operation) => operation.path),
|
|
76
|
+
operations
|
|
77
|
+
};
|
|
37
78
|
}
|
|
38
|
-
function
|
|
39
|
-
|
|
79
|
+
async function applyRuleInstall(plan) {
|
|
80
|
+
for (const operation of plan.operations) {
|
|
81
|
+
await mkdir(dirname(operation.path), { recursive: true });
|
|
82
|
+
await validateInstructionWritePath(operation.path);
|
|
83
|
+
const next = upsertManagedSection(await readTextIfPresent(operation.path), operation);
|
|
84
|
+
await writeFile(operation.path, next);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
async function codexOperation(input) {
|
|
88
|
+
return {
|
|
89
|
+
path: input.scope === "project" ? join(input.repoRoot, "AGENTS.md") : join(input.homeDir, ".codex", "AGENTS.md"),
|
|
90
|
+
start: CODEX_START,
|
|
91
|
+
end: CODEX_END,
|
|
92
|
+
body: await renderRuleSection(input, "Codex")
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
async function claudeOperation(input) {
|
|
96
|
+
if (input.scope === "project") {
|
|
97
|
+
const claudePath = join(input.repoRoot, "CLAUDE.md");
|
|
98
|
+
if (await isSymlinkToAgentsMd(claudePath, input.repoRoot)) {
|
|
99
|
+
if (input.tools.includes("codex")) return null;
|
|
100
|
+
return {
|
|
101
|
+
path: join(input.repoRoot, "AGENTS.md"),
|
|
102
|
+
start: CLAUDE_START,
|
|
103
|
+
end: CLAUDE_END,
|
|
104
|
+
body: await renderRuleSection(input, "Claude Code")
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
if (input.tools.includes("codex") && !await exists(claudePath)) return {
|
|
108
|
+
path: claudePath,
|
|
109
|
+
start: CLAUDE_START,
|
|
110
|
+
end: CLAUDE_END,
|
|
111
|
+
body: "@AGENTS.md"
|
|
112
|
+
};
|
|
113
|
+
return {
|
|
114
|
+
path: claudePath,
|
|
115
|
+
start: CLAUDE_START,
|
|
116
|
+
end: CLAUDE_END,
|
|
117
|
+
body: await renderRuleSection(input, "Claude Code")
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
return {
|
|
121
|
+
path: join(input.homeDir, ".claude", "CLAUDE.md"),
|
|
122
|
+
start: CLAUDE_START,
|
|
123
|
+
end: CLAUDE_END,
|
|
124
|
+
body: await renderRuleSection(input, "Claude Code")
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
function validateRuleInstallInput(input) {
|
|
128
|
+
if (input.scope !== "project" && input.scope !== "global") throw new Error(`Invalid rule install scope: ${input.scope}`);
|
|
129
|
+
for (const tool of input.tools) if (tool !== "codex" && tool !== "claude") throw new Error(`Invalid rule install tool: ${tool}`);
|
|
130
|
+
if (input.ruleWiring !== "reference" && input.ruleWiring !== "inline") throw new Error(`Invalid rule wiring: ${input.ruleWiring}`);
|
|
131
|
+
if (input.scope === "global") for (const rule of input.selectedRules) {
|
|
132
|
+
const path = requireRulePath(input, rule);
|
|
133
|
+
if (!isPathInside(input.cacheRoot, path)) throw new Error(`Global Dewey rule path must be inside cacheRoot for ${rule}: ${path}`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
async function renderRuleSection(input, toolLabel) {
|
|
137
|
+
if (input.ruleWiring === "inline") return `## Dewey Rules for ${toolLabel}
|
|
138
|
+
|
|
139
|
+
Follow these selected Dewey rules:
|
|
140
|
+
|
|
141
|
+
${(await Promise.all(input.selectedRules.map(async (rule) => {
|
|
142
|
+
return `### ${rule}\n\n${await readFile(requireRulePath(input, rule), "utf8")}`;
|
|
143
|
+
}))).join("\n\n")}`;
|
|
144
|
+
return `## Dewey Rules for ${toolLabel}
|
|
145
|
+
|
|
146
|
+
Follow these selected Dewey rules. Read the referenced files before applying a rule:
|
|
147
|
+
|
|
148
|
+
${input.selectedRules.map((rule) => `- ${rule}: ${displayPath(input, requireRulePath(input, rule))}`).join("\n")}`;
|
|
149
|
+
}
|
|
150
|
+
function requireRulePath(input, rule) {
|
|
151
|
+
const path = input.rulePaths.get(rule);
|
|
152
|
+
if (!path) throw new Error(`Missing path for Dewey rule: ${rule}`);
|
|
153
|
+
return path;
|
|
154
|
+
}
|
|
155
|
+
function displayPath(input, path) {
|
|
156
|
+
if (input.scope === "project") return relative(input.repoRoot, path);
|
|
157
|
+
return path;
|
|
158
|
+
}
|
|
159
|
+
function isPathInside(root, path) {
|
|
160
|
+
const pathFromRoot = relative(resolve(root), resolve(path));
|
|
161
|
+
return pathFromRoot === "" || !pathFromRoot.startsWith("..") && !isAbsolute(pathFromRoot);
|
|
162
|
+
}
|
|
163
|
+
async function readTextIfPresent(path) {
|
|
164
|
+
try {
|
|
165
|
+
return await readFile(path, "utf8");
|
|
166
|
+
} catch (error) {
|
|
167
|
+
if (!(error instanceof Error) || !("code" in error)) throw error;
|
|
168
|
+
if (error.code === "ENOENT") return "";
|
|
169
|
+
throw error;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
async function validateInstructionWritePath(path) {
|
|
173
|
+
try {
|
|
174
|
+
if ((await lstat(path)).isSymbolicLink()) throw new Error(`Refusing to write Dewey rules through symlink: ${path}`);
|
|
175
|
+
} catch (error) {
|
|
176
|
+
if (!(error instanceof Error) || !("code" in error)) throw error;
|
|
177
|
+
if (error.code === "ENOENT") return;
|
|
178
|
+
throw error;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
async function exists(path) {
|
|
182
|
+
try {
|
|
183
|
+
await lstat(path);
|
|
184
|
+
return true;
|
|
185
|
+
} catch (error) {
|
|
186
|
+
if (!(error instanceof Error) || !("code" in error)) throw error;
|
|
187
|
+
if (error.code === "ENOENT") return false;
|
|
188
|
+
throw error;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
async function isSymlinkToAgentsMd(path, repoRoot) {
|
|
192
|
+
try {
|
|
193
|
+
if (!(await lstat(path)).isSymbolicLink()) return false;
|
|
194
|
+
const target = await readlink(path);
|
|
195
|
+
return target === "AGENTS.md" || resolve(dirname(path), target) === resolve(repoRoot, "AGENTS.md");
|
|
196
|
+
} catch (error) {
|
|
197
|
+
if (!(error instanceof Error) || !("code" in error)) throw error;
|
|
198
|
+
if (error.code === "ENOENT") return false;
|
|
199
|
+
throw error;
|
|
200
|
+
}
|
|
40
201
|
}
|
|
41
202
|
//#endregion
|
|
42
203
|
//#region src/cli/init.ts
|
|
@@ -45,9 +206,23 @@ const VALID_MODES = new Set([
|
|
|
45
206
|
"copy",
|
|
46
207
|
"pointer"
|
|
47
208
|
]);
|
|
209
|
+
const VALID_SCOPES = new Set(["project", "global"]);
|
|
210
|
+
const VALID_TOOLS = new Set(["codex", "claude"]);
|
|
211
|
+
const VALID_TOOL_SELECTIONS = new Set([
|
|
212
|
+
"all",
|
|
213
|
+
"codex",
|
|
214
|
+
"claude"
|
|
215
|
+
]);
|
|
216
|
+
const VALID_RULE_WIRING = new Set(["reference", "inline"]);
|
|
48
217
|
const SAFE_ID = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
49
|
-
async function initRepo(
|
|
218
|
+
async function initRepo(options = {}) {
|
|
219
|
+
const { repoRoot = process.cwd(), homeDir = homedir(), mode = "link", selected, force = false, dryRun = false } = options;
|
|
50
220
|
if (!selected) throw new Error("selected assets are required");
|
|
221
|
+
const scope = options.scope ?? "project";
|
|
222
|
+
const ruleWiring = options.ruleWiring ?? "reference";
|
|
223
|
+
validateScope(scope);
|
|
224
|
+
validateRuleWiring(ruleWiring);
|
|
225
|
+
const tools = normalizeTools(options.tools);
|
|
51
226
|
validateMode(mode);
|
|
52
227
|
const paths = cachePaths({ homeDir });
|
|
53
228
|
const registry = await readCachedRegistry(paths.assetsRoot);
|
|
@@ -55,6 +230,17 @@ async function initRepo({ repoRoot = process.cwd(), homeDir = homedir(), mode =
|
|
|
55
230
|
const assets = normalizeSelected(selected);
|
|
56
231
|
const agentsRoot = join(repoRoot, ".agents");
|
|
57
232
|
validateSelectedAssets(registry, assets);
|
|
233
|
+
if (scope === "global") return await initGlobal({
|
|
234
|
+
homeDir,
|
|
235
|
+
repoRoot,
|
|
236
|
+
paths,
|
|
237
|
+
registry,
|
|
238
|
+
cacheManifest,
|
|
239
|
+
assets,
|
|
240
|
+
tools,
|
|
241
|
+
ruleWiring,
|
|
242
|
+
dryRun
|
|
243
|
+
});
|
|
58
244
|
const plan = await buildInitPlan({
|
|
59
245
|
repoRoot,
|
|
60
246
|
agentsRoot,
|
|
@@ -75,21 +261,62 @@ async function initRepo({ repoRoot = process.cwd(), homeDir = homedir(), mode =
|
|
|
75
261
|
cacheRoot: paths.assetsRoot,
|
|
76
262
|
assets,
|
|
77
263
|
assetSnapshot: snapshotSelectedAssetMetadata(registry, assets),
|
|
264
|
+
scope,
|
|
265
|
+
tools,
|
|
266
|
+
ruleWiring,
|
|
78
267
|
initializedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
79
268
|
};
|
|
269
|
+
const rulePlan = await planRuleInstall({
|
|
270
|
+
repoRoot,
|
|
271
|
+
homeDir,
|
|
272
|
+
cacheRoot: paths.assetsRoot,
|
|
273
|
+
scope: "project",
|
|
274
|
+
tools,
|
|
275
|
+
ruleWiring,
|
|
276
|
+
selectedRules: assets.rules,
|
|
277
|
+
rulePaths: projectRulePathMap(repoRoot, paths.assetsRoot, registry, assets, mode, ruleWiring)
|
|
278
|
+
});
|
|
80
279
|
if (dryRun) return {
|
|
280
|
+
...manifest,
|
|
81
281
|
dryRun: true,
|
|
82
|
-
|
|
83
|
-
source: cacheManifest.source,
|
|
84
|
-
cacheRoot: paths.assetsRoot,
|
|
85
|
-
assets,
|
|
86
|
-
assetSnapshot: snapshotSelectedAssetMetadata(registry, assets),
|
|
87
|
-
files: plan.files
|
|
282
|
+
files: uniqueFiles([...plan.files, ...rulePlan.files])
|
|
88
283
|
};
|
|
89
284
|
await mkdir(agentsRoot, { recursive: true });
|
|
90
285
|
if (mode !== "pointer") await installAssets(plan.assets);
|
|
91
286
|
await writeJson(join(agentsRoot, "manifest.json"), manifest);
|
|
92
287
|
await upsertAgentsSection(repoRoot);
|
|
288
|
+
await applyRuleInstall(rulePlan);
|
|
289
|
+
return manifest;
|
|
290
|
+
}
|
|
291
|
+
async function initGlobal({ homeDir, repoRoot, paths, registry, cacheManifest, assets, tools, ruleWiring, dryRun }) {
|
|
292
|
+
if (assets.skills.length > 0) throw new Error("Global installs currently support rules only");
|
|
293
|
+
const rulePlan = await planRuleInstall({
|
|
294
|
+
repoRoot,
|
|
295
|
+
homeDir,
|
|
296
|
+
cacheRoot: paths.assetsRoot,
|
|
297
|
+
scope: "global",
|
|
298
|
+
tools,
|
|
299
|
+
ruleWiring,
|
|
300
|
+
selectedRules: assets.rules,
|
|
301
|
+
rulePaths: rulePathMap(paths.assetsRoot, registry, assets.rules)
|
|
302
|
+
});
|
|
303
|
+
const manifest = {
|
|
304
|
+
scope: "global",
|
|
305
|
+
source: cacheManifest.source,
|
|
306
|
+
cacheRoot: paths.assetsRoot,
|
|
307
|
+
assets,
|
|
308
|
+
assetSnapshot: snapshotSelectedAssetMetadata(registry, assets),
|
|
309
|
+
tools,
|
|
310
|
+
ruleWiring,
|
|
311
|
+
initializedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
312
|
+
};
|
|
313
|
+
if (dryRun) return {
|
|
314
|
+
...manifest,
|
|
315
|
+
dryRun: true,
|
|
316
|
+
files: uniqueFiles([...rulePlan.files, join(homeDir, ".deweyou/agents/global-manifest.json")])
|
|
317
|
+
};
|
|
318
|
+
await applyRuleInstall(rulePlan);
|
|
319
|
+
await writeJson(join(homeDir, ".deweyou/agents/global-manifest.json"), manifest);
|
|
93
320
|
return manifest;
|
|
94
321
|
}
|
|
95
322
|
async function runInit(flags = {}, { promptForInit } = {}) {
|
|
@@ -98,6 +325,9 @@ async function runInit(flags = {}, { promptForInit } = {}) {
|
|
|
98
325
|
const registry = await readCachedRegistry(cachePaths({ homeDir }).assetsRoot);
|
|
99
326
|
const scripted = hasScriptedSelectionFlags(flags);
|
|
100
327
|
let mode = flags.mode ?? "link";
|
|
328
|
+
let scope = flags.scope;
|
|
329
|
+
let tools = flags.tools;
|
|
330
|
+
let ruleWiring = flags.ruleWiring;
|
|
101
331
|
let selected;
|
|
102
332
|
validateMode(mode);
|
|
103
333
|
if (flags.yes && !scripted) throw new Error("--yes requires --all, --skills, or --rules");
|
|
@@ -109,15 +339,25 @@ async function runInit(flags = {}, { promptForInit } = {}) {
|
|
|
109
339
|
const prompted = await (promptForInit ?? await loadPromptForInit())({
|
|
110
340
|
registry,
|
|
111
341
|
repoRoot,
|
|
112
|
-
mode: flags.mode
|
|
342
|
+
mode: flags.mode,
|
|
343
|
+
scope: flags.scope,
|
|
344
|
+
tools: flags.tools,
|
|
345
|
+
ruleWiring: flags.ruleWiring
|
|
113
346
|
});
|
|
114
|
-
mode = prompted.mode;
|
|
347
|
+
mode = flags.mode ?? prompted.mode;
|
|
348
|
+
scope = flags.scope ?? prompted.scope;
|
|
349
|
+
tools = flags.tools ?? prompted.tools;
|
|
350
|
+
ruleWiring = flags.ruleWiring ?? prompted.ruleWiring;
|
|
115
351
|
selected = prompted.selected;
|
|
116
352
|
}
|
|
117
353
|
if (!hasSelectedAssets(selected)) throw new Error("No assets selected. Pass --all, --skills, or --rules, or run interactive setup.");
|
|
354
|
+
if (scripted && scope === "global" && !flags.yes && !flags.dryRun) throw new Error("--scope global with scripted selections requires --yes or --dry-run");
|
|
118
355
|
const manifest = await initRepo({
|
|
119
356
|
repoRoot,
|
|
120
357
|
mode,
|
|
358
|
+
scope,
|
|
359
|
+
tools,
|
|
360
|
+
ruleWiring,
|
|
121
361
|
selected,
|
|
122
362
|
force: flags.force ?? false,
|
|
123
363
|
dryRun: flags.dryRun ?? false,
|
|
@@ -130,7 +370,7 @@ async function runInit(flags = {}, { promptForInit } = {}) {
|
|
|
130
370
|
return manifest;
|
|
131
371
|
}
|
|
132
372
|
async function loadPromptForInit() {
|
|
133
|
-
const { promptForInit } = await import("./prompts-
|
|
373
|
+
const { promptForInit } = await import("./prompts-DdaeRkBa.mjs");
|
|
134
374
|
return promptForInit;
|
|
135
375
|
}
|
|
136
376
|
async function readCachedRegistry(assetsRoot) {
|
|
@@ -175,6 +415,22 @@ function validateMode(mode) {
|
|
|
175
415
|
if (typeof mode !== "string") throw new Error("mode must be one of link, copy, or pointer");
|
|
176
416
|
if (!VALID_MODES.has(mode)) throw new Error("mode must be one of link, copy, or pointer");
|
|
177
417
|
}
|
|
418
|
+
function validateScope(scope) {
|
|
419
|
+
if (typeof scope !== "string") throw new Error("scope must be one of project or global");
|
|
420
|
+
if (!VALID_SCOPES.has(scope)) throw new Error("scope must be one of project or global");
|
|
421
|
+
}
|
|
422
|
+
function normalizeTools(tools) {
|
|
423
|
+
if (tools) {
|
|
424
|
+
for (const tool of tools) if (typeof tool !== "string" || !VALID_TOOL_SELECTIONS.has(tool)) throw new Error(`tool must be one of codex or claude: ${tool}`);
|
|
425
|
+
}
|
|
426
|
+
const selected = !tools || tools.includes("all") ? ["codex", "claude"] : [...tools];
|
|
427
|
+
for (const tool of selected) if (typeof tool !== "string" || !VALID_TOOLS.has(tool)) throw new Error(`tool must be one of codex or claude: ${tool}`);
|
|
428
|
+
return [...new Set(selected)];
|
|
429
|
+
}
|
|
430
|
+
function validateRuleWiring(ruleWiring) {
|
|
431
|
+
if (typeof ruleWiring !== "string") throw new Error("ruleWiring must be one of reference or inline");
|
|
432
|
+
if (!VALID_RULE_WIRING.has(ruleWiring)) throw new Error("ruleWiring must be one of reference or inline");
|
|
433
|
+
}
|
|
178
434
|
function validateSelectedAssets(registry, selected) {
|
|
179
435
|
for (const skill of selected.skills) {
|
|
180
436
|
if (!registry.assets.skills[skill]) throw new Error(`Unknown Dewey skill: ${skill}`);
|
|
@@ -206,6 +462,16 @@ function pickAssetMetadata(asset) {
|
|
|
206
462
|
hash: asset.hash
|
|
207
463
|
};
|
|
208
464
|
}
|
|
465
|
+
function uniqueFiles(files) {
|
|
466
|
+
return [...new Set(files)];
|
|
467
|
+
}
|
|
468
|
+
function rulePathMap(assetsRoot, registry, rules) {
|
|
469
|
+
return new Map(rules.map((rule) => [rule, join(assetsRoot, registry.assets.rules[rule].path)]));
|
|
470
|
+
}
|
|
471
|
+
function projectRulePathMap(repoRoot, assetsRoot, registry, assets, mode, ruleWiring) {
|
|
472
|
+
if (mode === "pointer" || ruleWiring === "inline") return rulePathMap(assetsRoot, registry, assets.rules);
|
|
473
|
+
return new Map(assets.rules.map((rule) => [rule, join(repoRoot, ".agents", "rules", `${rule}.md`)]));
|
|
474
|
+
}
|
|
209
475
|
async function buildInitPlan({ repoRoot, agentsRoot, assetsRoot, registry, assets, mode }) {
|
|
210
476
|
const assetPlans = mode === "pointer" ? [] : await Promise.all([...assets.skills.map((id) => buildAssetPlan({
|
|
211
477
|
kind: "skill",
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { cancel, confirm, intro, isCancel, multiselect, note, select } from "@clack/prompts";
|
|
2
|
+
//#region src/cli/prompts.ts
|
|
3
|
+
const SETUP_SCOPES = [{
|
|
4
|
+
value: "project",
|
|
5
|
+
label: "project",
|
|
6
|
+
hint: "Install into this repository."
|
|
7
|
+
}, {
|
|
8
|
+
value: "global",
|
|
9
|
+
label: "global",
|
|
10
|
+
hint: "Install into Codex and Claude user homes."
|
|
11
|
+
}];
|
|
12
|
+
const TOOL_OPTIONS = [
|
|
13
|
+
{
|
|
14
|
+
value: "both",
|
|
15
|
+
label: "both",
|
|
16
|
+
hint: "Wire Codex and Claude Code."
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
value: "codex",
|
|
20
|
+
label: "codex",
|
|
21
|
+
hint: "Wire AGENTS.md only."
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
value: "claude",
|
|
25
|
+
label: "claude",
|
|
26
|
+
hint: "Wire CLAUDE.md only."
|
|
27
|
+
}
|
|
28
|
+
];
|
|
29
|
+
const SETUP_MODES = [
|
|
30
|
+
{
|
|
31
|
+
value: "link",
|
|
32
|
+
label: "link",
|
|
33
|
+
hint: "Symlink assets from the Dewey cache."
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
value: "copy",
|
|
37
|
+
label: "copy",
|
|
38
|
+
hint: "Copy asset files into this repository."
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
value: "pointer",
|
|
42
|
+
label: "pointer",
|
|
43
|
+
hint: "Write only the manifest and AGENTS.md pointers."
|
|
44
|
+
}
|
|
45
|
+
];
|
|
46
|
+
const RULE_WIRING_OPTIONS = [{
|
|
47
|
+
value: "reference",
|
|
48
|
+
label: "reference",
|
|
49
|
+
hint: "Reference selected rule files."
|
|
50
|
+
}, {
|
|
51
|
+
value: "inline",
|
|
52
|
+
label: "inline",
|
|
53
|
+
hint: "Inline selected rule bodies."
|
|
54
|
+
}];
|
|
55
|
+
const ASSET_SCOPES = [
|
|
56
|
+
{
|
|
57
|
+
value: "all",
|
|
58
|
+
label: "all",
|
|
59
|
+
hint: "Enable every cached skill and rule."
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
value: "custom",
|
|
63
|
+
label: "custom",
|
|
64
|
+
hint: "Choose skills and rules individually."
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
value: "skills",
|
|
68
|
+
label: "skills only",
|
|
69
|
+
hint: "Choose skills without installing rules."
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
value: "rules",
|
|
73
|
+
label: "rules only",
|
|
74
|
+
hint: "Choose rules without installing skills."
|
|
75
|
+
}
|
|
76
|
+
];
|
|
77
|
+
const GLOBAL_ASSET_SCOPES = [{
|
|
78
|
+
value: "all",
|
|
79
|
+
label: "all rules",
|
|
80
|
+
hint: "Enable every cached rule."
|
|
81
|
+
}, {
|
|
82
|
+
value: "rules",
|
|
83
|
+
label: "choose rules",
|
|
84
|
+
hint: "Choose rules individually."
|
|
85
|
+
}];
|
|
86
|
+
async function promptForInit({ registry, repoRoot, mode, scope, tools, ruleWiring }) {
|
|
87
|
+
intro("Dewey Agent Setup");
|
|
88
|
+
note(repoRoot, "Repository");
|
|
89
|
+
const selectedScope = scope ?? await promptOrExit(select({
|
|
90
|
+
message: "Select install scope",
|
|
91
|
+
options: SETUP_SCOPES
|
|
92
|
+
}));
|
|
93
|
+
const selectedTools = tools === void 0 ? normalizePromptTools(await promptOrExit(select({
|
|
94
|
+
message: "Select tools",
|
|
95
|
+
options: TOOL_OPTIONS
|
|
96
|
+
}))) : normalizeToolSelection(tools);
|
|
97
|
+
const selectedMode = selectedScope === "global" ? "pointer" : mode ?? await promptOrExit(select({
|
|
98
|
+
message: "Select setup mode",
|
|
99
|
+
options: SETUP_MODES
|
|
100
|
+
}));
|
|
101
|
+
const selected = await selectAssets({
|
|
102
|
+
registry,
|
|
103
|
+
scope: await promptOrExit(select({
|
|
104
|
+
message: "Select asset scope",
|
|
105
|
+
options: selectedScope === "global" ? GLOBAL_ASSET_SCOPES : ASSET_SCOPES
|
|
106
|
+
})),
|
|
107
|
+
installScope: selectedScope
|
|
108
|
+
});
|
|
109
|
+
const selectedRuleWiring = ruleWiring ?? (selected.rules.length > 0 ? await promptOrExit(select({
|
|
110
|
+
message: "Select rule wiring",
|
|
111
|
+
options: RULE_WIRING_OPTIONS
|
|
112
|
+
})) : "reference");
|
|
113
|
+
note(plannedFiles({
|
|
114
|
+
repoRoot,
|
|
115
|
+
scope: selectedScope,
|
|
116
|
+
tools: selectedTools,
|
|
117
|
+
selected
|
|
118
|
+
}), "Dewey will update");
|
|
119
|
+
if (!await promptOrExit(confirm({ message: `Enable ${selected.skills.length} skill(s) and ${selected.rules.length} rule(s) using ${selectedMode} mode?` }))) exitCancelled();
|
|
120
|
+
return {
|
|
121
|
+
mode: selectedMode,
|
|
122
|
+
scope: selectedScope,
|
|
123
|
+
tools: selectedTools,
|
|
124
|
+
ruleWiring: selectedRuleWiring,
|
|
125
|
+
selected
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
async function selectAssets({ registry, scope, installScope }) {
|
|
129
|
+
if (scope === "all") return {
|
|
130
|
+
skills: installScope === "global" ? [] : Object.keys(registry.assets.skills),
|
|
131
|
+
rules: Object.keys(registry.assets.rules)
|
|
132
|
+
};
|
|
133
|
+
const selected = {
|
|
134
|
+
skills: [],
|
|
135
|
+
rules: []
|
|
136
|
+
};
|
|
137
|
+
if (installScope === "project" && (scope === "custom" || scope === "skills")) selected.skills = await promptOrExit(multiselect({
|
|
138
|
+
message: "Select skills",
|
|
139
|
+
options: assetOptions(registry.assets.skills),
|
|
140
|
+
required: false
|
|
141
|
+
}));
|
|
142
|
+
if (scope === "custom" || scope === "rules") selected.rules = await promptOrExit(multiselect({
|
|
143
|
+
message: "Select rules",
|
|
144
|
+
options: assetOptions(registry.assets.rules),
|
|
145
|
+
required: false
|
|
146
|
+
}));
|
|
147
|
+
return selected;
|
|
148
|
+
}
|
|
149
|
+
function assetOptions(assets) {
|
|
150
|
+
return Object.entries(assets).map(([name, asset]) => ({
|
|
151
|
+
value: name,
|
|
152
|
+
label: name,
|
|
153
|
+
hint: asset.description
|
|
154
|
+
}));
|
|
155
|
+
}
|
|
156
|
+
function normalizePromptTools(selectedTools) {
|
|
157
|
+
if (selectedTools === "both") return ["codex", "claude"];
|
|
158
|
+
return [selectedTools];
|
|
159
|
+
}
|
|
160
|
+
function normalizeToolSelection(tools) {
|
|
161
|
+
if (tools.includes("all")) return ["codex", "claude"];
|
|
162
|
+
return [...new Set(tools)];
|
|
163
|
+
}
|
|
164
|
+
function plannedFiles({ repoRoot, scope, tools, selected }) {
|
|
165
|
+
const files = [];
|
|
166
|
+
if (scope === "global") {
|
|
167
|
+
if (tools.includes("codex")) files.push("~/.codex/AGENTS.md");
|
|
168
|
+
if (tools.includes("claude")) files.push("~/.claude/CLAUDE.md");
|
|
169
|
+
files.push("~/.deweyou/agents/global-manifest.json");
|
|
170
|
+
return files.join("\n");
|
|
171
|
+
}
|
|
172
|
+
files.push("AGENTS.md");
|
|
173
|
+
if (tools.includes("claude") && selected.rules.length > 0) files.push("CLAUDE.md");
|
|
174
|
+
files.push(".agents/manifest.json");
|
|
175
|
+
if (selected.skills.length > 0) files.push(".agents/skills/<skill>/SKILL.md");
|
|
176
|
+
if (selected.rules.length > 0) files.push(".agents/rules/<rule>.md");
|
|
177
|
+
return `${repoRoot}\n\n${files.join("\n")}`;
|
|
178
|
+
}
|
|
179
|
+
async function promptOrExit(prompt) {
|
|
180
|
+
const value = await prompt;
|
|
181
|
+
if (isCancel(value)) exitCancelled();
|
|
182
|
+
return value;
|
|
183
|
+
}
|
|
184
|
+
function exitCancelled() {
|
|
185
|
+
cancel("Dewey agent setup cancelled.");
|
|
186
|
+
process.exit(0);
|
|
187
|
+
}
|
|
188
|
+
//#endregion
|
|
189
|
+
export { promptForInit };
|
package/package.json
CHANGED
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
import { cancel, confirm, intro, isCancel, multiselect, note, select } from "@clack/prompts";
|
|
2
|
-
//#region src/cli/prompts.ts
|
|
3
|
-
const SETUP_MODES = [
|
|
4
|
-
{
|
|
5
|
-
value: "link",
|
|
6
|
-
label: "link",
|
|
7
|
-
hint: "Symlink assets from the Dewey cache."
|
|
8
|
-
},
|
|
9
|
-
{
|
|
10
|
-
value: "copy",
|
|
11
|
-
label: "copy",
|
|
12
|
-
hint: "Copy asset files into this repository."
|
|
13
|
-
},
|
|
14
|
-
{
|
|
15
|
-
value: "pointer",
|
|
16
|
-
label: "pointer",
|
|
17
|
-
hint: "Write only the manifest and AGENTS.md pointers."
|
|
18
|
-
}
|
|
19
|
-
];
|
|
20
|
-
const ASSET_SCOPES = [
|
|
21
|
-
{
|
|
22
|
-
value: "all",
|
|
23
|
-
label: "all",
|
|
24
|
-
hint: "Enable every cached skill and rule."
|
|
25
|
-
},
|
|
26
|
-
{
|
|
27
|
-
value: "custom",
|
|
28
|
-
label: "custom",
|
|
29
|
-
hint: "Choose skills and rules individually."
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
value: "skills",
|
|
33
|
-
label: "skills only",
|
|
34
|
-
hint: "Choose skills without installing rules."
|
|
35
|
-
},
|
|
36
|
-
{
|
|
37
|
-
value: "rules",
|
|
38
|
-
label: "rules only",
|
|
39
|
-
hint: "Choose rules without installing skills."
|
|
40
|
-
}
|
|
41
|
-
];
|
|
42
|
-
async function promptForInit({ registry, repoRoot, mode }) {
|
|
43
|
-
intro("Dewey Agent Setup");
|
|
44
|
-
note(repoRoot, "Repository");
|
|
45
|
-
const selectedMode = mode ?? await promptOrExit(select({
|
|
46
|
-
message: "Select setup mode",
|
|
47
|
-
options: SETUP_MODES
|
|
48
|
-
}));
|
|
49
|
-
const selected = await selectAssets({
|
|
50
|
-
registry,
|
|
51
|
-
scope: await promptOrExit(select({
|
|
52
|
-
message: "Select asset scope",
|
|
53
|
-
options: ASSET_SCOPES
|
|
54
|
-
}))
|
|
55
|
-
});
|
|
56
|
-
if (!await promptOrExit(confirm({ message: `Enable ${selected.skills.length} skill(s) and ${selected.rules.length} rule(s) using ${selectedMode} mode?` }))) exitCancelled();
|
|
57
|
-
return {
|
|
58
|
-
mode: selectedMode,
|
|
59
|
-
selected
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
async function selectAssets({ registry, scope }) {
|
|
63
|
-
if (scope === "all") return {
|
|
64
|
-
skills: Object.keys(registry.assets.skills),
|
|
65
|
-
rules: Object.keys(registry.assets.rules)
|
|
66
|
-
};
|
|
67
|
-
const selected = {
|
|
68
|
-
skills: [],
|
|
69
|
-
rules: []
|
|
70
|
-
};
|
|
71
|
-
if (scope === "custom" || scope === "skills") selected.skills = await promptOrExit(multiselect({
|
|
72
|
-
message: "Select skills",
|
|
73
|
-
options: assetOptions(registry.assets.skills),
|
|
74
|
-
required: false
|
|
75
|
-
}));
|
|
76
|
-
if (scope === "custom" || scope === "rules") selected.rules = await promptOrExit(multiselect({
|
|
77
|
-
message: "Select rules",
|
|
78
|
-
options: assetOptions(registry.assets.rules),
|
|
79
|
-
required: false
|
|
80
|
-
}));
|
|
81
|
-
return selected;
|
|
82
|
-
}
|
|
83
|
-
function assetOptions(assets) {
|
|
84
|
-
return Object.entries(assets).map(([name, asset]) => ({
|
|
85
|
-
value: name,
|
|
86
|
-
label: name,
|
|
87
|
-
hint: asset.description
|
|
88
|
-
}));
|
|
89
|
-
}
|
|
90
|
-
async function promptOrExit(prompt) {
|
|
91
|
-
const value = await prompt;
|
|
92
|
-
if (isCancel(value)) exitCancelled();
|
|
93
|
-
return value;
|
|
94
|
-
}
|
|
95
|
-
function exitCancelled() {
|
|
96
|
-
cancel("Dewey agent setup cancelled.");
|
|
97
|
-
process.exit(0);
|
|
98
|
-
}
|
|
99
|
-
//#endregion
|
|
100
|
-
export { promptForInit };
|