destinotes-skills 0.2.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/LICENSE +21 -0
- package/README.md +63 -0
- package/bin/install.mjs +228 -0
- package/bin/lib/config.mjs +70 -0
- package/bin/lib/git.mjs +66 -0
- package/bin/lib/prompt.mjs +42 -0
- package/bin/setup.mjs +149 -0
- package/package.json +30 -0
- package/skills/destinotes-cost-analysis/SKILL.md +79 -0
- package/skills/destinotes-document/SKILL.md +64 -0
- package/skills/destinotes-feature/SKILL.md +59 -0
- package/skills/destinotes-general/SKILL.md +66 -0
- package/skills/destinotes-prompt/SKILL.md +124 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Destinotes contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# destinotes-skills
|
|
2
|
+
|
|
3
|
+
Agent skills that generate repository documentation under `./destinotes/`. Works with **Cursor** and **Claude Code**.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
From any project directory:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npx destinotes-skills
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
This runs an **interactive setup** that walks you through:
|
|
14
|
+
|
|
15
|
+
- Project name (auto-detected from `package.json` or folder name)
|
|
16
|
+
- Repository URL (auto-detected from `git remote origin` when possible)
|
|
17
|
+
- Default branch
|
|
18
|
+
- Docs output folder (default: `./destinotes/`)
|
|
19
|
+
- Which agents to install to (Cursor, Claude Code)
|
|
20
|
+
- Project-level vs global skill install
|
|
21
|
+
|
|
22
|
+
Settings are saved to `./destinotes/destinotes.config.json`. Skills are copied into `.cursor/skills/` and/or `.claude/skills/`.
|
|
23
|
+
|
|
24
|
+
### Non-interactive / CI
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npx destinotes-skills install -y # skip prompts, use detected defaults
|
|
28
|
+
npx destinotes-skills -g -y # global install, no prompts
|
|
29
|
+
npx destinotes-skills -a cursor -y # Cursor only
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Commands
|
|
33
|
+
|
|
34
|
+
| Command | Description |
|
|
35
|
+
|---------|-------------|
|
|
36
|
+
| `setup` | Interactive setup + install (default) |
|
|
37
|
+
| `install` | Install skills only, skip project prompts (use with `-y`) |
|
|
38
|
+
|
|
39
|
+
## Skills
|
|
40
|
+
|
|
41
|
+
| Skill | Invocation | Output |
|
|
42
|
+
|-------|------------|--------|
|
|
43
|
+
| `destinotes-prompt` | (parent contract; always active) | — |
|
|
44
|
+
| `destinotes-general` | `/destinotes-general` | `./destinotes/<category>/*.md` |
|
|
45
|
+
| `destinotes-feature` | `/destinotes-feature <slug> <context>` | `./destinotes/features/<slug>.md` |
|
|
46
|
+
| `destinotes-document` | `/destinotes-document <folder>:<file> <context>` | `./destinotes/<folder>/<file>.md` |
|
|
47
|
+
| `destinotes-cost-analysis` | `/destinotes-cost-analysis <slug> <context>` | `./destinotes/cost-analysis/<slug>.md` |
|
|
48
|
+
|
|
49
|
+
## Publish
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
cd packages/skills
|
|
53
|
+
npm login
|
|
54
|
+
npm publish --access public
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Development
|
|
58
|
+
|
|
59
|
+
Skill source of truth lives in `packages/skills/skills/`. To sync into this app's Claude skills for local dev:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
node packages/skills/scripts/sync-to-claude.mjs
|
|
63
|
+
```
|
package/bin/install.mjs
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { cpSync, existsSync, mkdirSync, readdirSync } from "node:fs";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
import { dirname, join } from "node:path";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
import { readConfig } from "./lib/config.mjs";
|
|
8
|
+
import { finalizeProjectFiles, runSetup } from "./setup.mjs";
|
|
9
|
+
|
|
10
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
const PACKAGE_ROOT = join(__dirname, "..");
|
|
12
|
+
const SKILLS_SOURCE = join(PACKAGE_ROOT, "skills");
|
|
13
|
+
|
|
14
|
+
const AGENTS = {
|
|
15
|
+
cursor: {
|
|
16
|
+
label: "Cursor",
|
|
17
|
+
projectDir: ".cursor/skills",
|
|
18
|
+
globalDir: join(homedir(), ".cursor", "skills"),
|
|
19
|
+
},
|
|
20
|
+
claude: {
|
|
21
|
+
label: "Claude Code",
|
|
22
|
+
projectDir: ".claude/skills",
|
|
23
|
+
globalDir: join(homedir(), ".claude", "skills"),
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const AGENT_LABELS = Object.fromEntries(
|
|
28
|
+
Object.entries(AGENTS).map(([id, agent]) => [id, agent.label]),
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
function parseArgs(argv) {
|
|
32
|
+
const options = {
|
|
33
|
+
command: "setup",
|
|
34
|
+
global: false,
|
|
35
|
+
yes: false,
|
|
36
|
+
agents: null,
|
|
37
|
+
help: false,
|
|
38
|
+
cwd: process.cwd(),
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const args = [...argv];
|
|
42
|
+
|
|
43
|
+
if (args[0] && !args[0].startsWith("-")) {
|
|
44
|
+
options.command = args.shift();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
48
|
+
const arg = args[i];
|
|
49
|
+
if (arg === "-h" || arg === "--help") {
|
|
50
|
+
options.help = true;
|
|
51
|
+
} else if (arg === "-g" || arg === "--global") {
|
|
52
|
+
options.global = true;
|
|
53
|
+
} else if (arg === "-y" || arg === "--yes") {
|
|
54
|
+
options.yes = true;
|
|
55
|
+
} else if (arg === "--cwd") {
|
|
56
|
+
options.cwd = args[i + 1];
|
|
57
|
+
i += 1;
|
|
58
|
+
} else if (arg === "-a" || arg === "--agents") {
|
|
59
|
+
options.agents = (args[i + 1] ?? "")
|
|
60
|
+
.split(",")
|
|
61
|
+
.map((name) => name.trim())
|
|
62
|
+
.filter(Boolean);
|
|
63
|
+
i += 1;
|
|
64
|
+
} else if (arg.startsWith("-")) {
|
|
65
|
+
throw new Error(`Unknown option: ${arg}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return options;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function printHelp() {
|
|
73
|
+
console.log(`destinotes-skills — install Destinotes agent skills
|
|
74
|
+
|
|
75
|
+
Usage:
|
|
76
|
+
npx destinotes-skills [command] [options]
|
|
77
|
+
|
|
78
|
+
Commands:
|
|
79
|
+
setup Interactive setup + install (default)
|
|
80
|
+
install Install skills only, skip project prompts (-y)
|
|
81
|
+
|
|
82
|
+
Options:
|
|
83
|
+
-g, --global Install to user-level skill dirs
|
|
84
|
+
-a, --agents <list> Comma-separated agents: cursor, claude
|
|
85
|
+
--cwd <path> Project directory (default: cwd)
|
|
86
|
+
-y, --yes Skip interactive prompts
|
|
87
|
+
-h, --help Show this help
|
|
88
|
+
|
|
89
|
+
Interactive setup configures:
|
|
90
|
+
- Project name
|
|
91
|
+
- Repository URL (auto-detected from git remote when possible)
|
|
92
|
+
- Default branch
|
|
93
|
+
- Docs output folder (default: ./destinotes/)
|
|
94
|
+
- Agent targets (Cursor, Claude Code)
|
|
95
|
+
- Project vs global skill install
|
|
96
|
+
|
|
97
|
+
Config is saved to ./destinotes/destinotes.config.json (or your chosen docs folder).
|
|
98
|
+
|
|
99
|
+
Skills installed:
|
|
100
|
+
destinotes-prompt, destinotes-general, destinotes-feature,
|
|
101
|
+
destinotes-document, destinotes-cost-analysis
|
|
102
|
+
`);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function listSkillNames() {
|
|
106
|
+
return readdirSync(SKILLS_SOURCE, { withFileTypes: true })
|
|
107
|
+
.filter((entry) => entry.isDirectory())
|
|
108
|
+
.map((entry) => entry.name)
|
|
109
|
+
.sort();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function detectAgents(cwd, global) {
|
|
113
|
+
const detected = [];
|
|
114
|
+
|
|
115
|
+
for (const [id, agent] of Object.entries(AGENTS)) {
|
|
116
|
+
if (global) {
|
|
117
|
+
const parent = dirname(agent.globalDir);
|
|
118
|
+
if (existsSync(parent) || existsSync(agent.globalDir)) {
|
|
119
|
+
detected.push(id);
|
|
120
|
+
}
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const projectMarker = join(cwd, agent.projectDir.split("/")[0]);
|
|
125
|
+
if (existsSync(projectMarker)) {
|
|
126
|
+
detected.push(id);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return detected.length > 0 ? detected : ["cursor", "claude"];
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function resolveTargetDirs(agentId, cwd, global) {
|
|
134
|
+
const agent = AGENTS[agentId];
|
|
135
|
+
if (!agent) {
|
|
136
|
+
throw new Error(`Unknown agent: ${agentId}. Use cursor or claude.`);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const base = global ? agent.globalDir : join(cwd, agent.projectDir);
|
|
140
|
+
return { agent, base };
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function installSkills(targetBase, skillNames) {
|
|
144
|
+
mkdirSync(targetBase, { recursive: true });
|
|
145
|
+
|
|
146
|
+
for (const skillName of skillNames) {
|
|
147
|
+
const source = join(SKILLS_SOURCE, skillName);
|
|
148
|
+
const destination = join(targetBase, skillName);
|
|
149
|
+
cpSync(source, destination, { recursive: true, force: true });
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
async function main() {
|
|
154
|
+
let options;
|
|
155
|
+
try {
|
|
156
|
+
options = parseArgs(process.argv.slice(2));
|
|
157
|
+
} catch (error) {
|
|
158
|
+
console.error(error.message);
|
|
159
|
+
process.exit(1);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (options.help) {
|
|
163
|
+
printHelp();
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (options.command !== "setup" && options.command !== "install") {
|
|
168
|
+
console.error(`Unknown command: ${options.command}`);
|
|
169
|
+
printHelp();
|
|
170
|
+
process.exit(1);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const skillNames = listSkillNames();
|
|
174
|
+
if (skillNames.length === 0) {
|
|
175
|
+
console.error("No skills found in package. Is the install corrupted?");
|
|
176
|
+
process.exit(1);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const detectedAgents = detectAgents(options.cwd, options.global);
|
|
180
|
+
const skipSetup = options.command === "install" || options.yes;
|
|
181
|
+
|
|
182
|
+
const existingConfig = readConfig(options.cwd);
|
|
183
|
+
const config = await runSetup({
|
|
184
|
+
cwd: options.cwd,
|
|
185
|
+
global: options.global,
|
|
186
|
+
yes: skipSetup,
|
|
187
|
+
agents: options.agents,
|
|
188
|
+
detectedAgents,
|
|
189
|
+
agentLabels: AGENT_LABELS,
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
const agentIds = config.agents ?? options.agents ?? detectedAgents;
|
|
193
|
+
const installGlobal = config.global ?? options.global;
|
|
194
|
+
const invalidAgents = agentIds.filter((id) => !AGENTS[id]);
|
|
195
|
+
|
|
196
|
+
if (invalidAgents.length > 0) {
|
|
197
|
+
console.error(`Unknown agent(s): ${invalidAgents.join(", ")}`);
|
|
198
|
+
process.exit(1);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
for (const agentId of agentIds) {
|
|
202
|
+
const { agent, base } = resolveTargetDirs(agentId, options.cwd, installGlobal);
|
|
203
|
+
installSkills(base, skillNames);
|
|
204
|
+
console.log(`✓ ${agent.label}: ${base}`);
|
|
205
|
+
for (const skillName of skillNames) {
|
|
206
|
+
console.log(` · ${skillName}`);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (!installGlobal) {
|
|
211
|
+
const docs = finalizeProjectFiles(options.cwd, config, existingConfig);
|
|
212
|
+
if (docs) {
|
|
213
|
+
console.log(`✓ Config: ${docs.configPath}`);
|
|
214
|
+
if (docs.readmeCreated) {
|
|
215
|
+
console.log(`✓ Created ${docs.readmePath}`);
|
|
216
|
+
} else {
|
|
217
|
+
console.log(`✓ Docs folder: ${docs.readmePath.replace(/README\.md$/, "")}`);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
console.log("\nDone. Try /destinotes-general in your agent.");
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
main().catch((error) => {
|
|
226
|
+
console.error(error);
|
|
227
|
+
process.exit(1);
|
|
228
|
+
});
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
4
|
+
export const CONFIG_VERSION = 1;
|
|
5
|
+
export const CONFIG_FILENAME = "destinotes.config.json";
|
|
6
|
+
|
|
7
|
+
export function getConfigPath(cwd, docsDir) {
|
|
8
|
+
return join(cwd, docsDir, CONFIG_FILENAME);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function readConfig(cwd, docsDir = "destinotes") {
|
|
12
|
+
const configPath = getConfigPath(cwd, docsDir);
|
|
13
|
+
if (!existsSync(configPath)) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
try {
|
|
18
|
+
return JSON.parse(readFileSync(configPath, "utf8"));
|
|
19
|
+
} catch {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function writeConfig(cwd, config) {
|
|
25
|
+
const docsDir = config.docsDir ?? "destinotes";
|
|
26
|
+
const destinotesDir = join(cwd, docsDir);
|
|
27
|
+
mkdirSync(destinotesDir, { recursive: true });
|
|
28
|
+
|
|
29
|
+
const configPath = getConfigPath(cwd, docsDir);
|
|
30
|
+
writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`, "utf8");
|
|
31
|
+
return configPath;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function buildReadme(config) {
|
|
35
|
+
const repoLine = config.repositoryUrl
|
|
36
|
+
? `Repository: ${config.repositoryUrl}`
|
|
37
|
+
: "Repository: (not set — run `npx destinotes-skills` to configure)";
|
|
38
|
+
|
|
39
|
+
return `# ${config.projectName}
|
|
40
|
+
|
|
41
|
+
${config.description ? `${config.description}\n\n` : ""}Generated technical documentation for this project. Agent skills write markdown files in \`./${config.docsDir}/\`.
|
|
42
|
+
|
|
43
|
+
${repoLine}
|
|
44
|
+
|
|
45
|
+
## Regenerate
|
|
46
|
+
|
|
47
|
+
- Whole-repo wiki: \`/destinotes-general\`
|
|
48
|
+
- Single feature: \`/destinotes-feature <slug> <context>\`
|
|
49
|
+
- Custom doc: \`/destinotes-document <folder>:<file> <context>\`
|
|
50
|
+
- Cost analysis: \`/destinotes-cost-analysis <slug> <context>\`
|
|
51
|
+
|
|
52
|
+
Reconfigure: \`npx destinotes-skills\`
|
|
53
|
+
`;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function scaffoldDocs(cwd, config, { overwriteReadme = false } = {}) {
|
|
57
|
+
const docsDir = join(cwd, config.docsDir);
|
|
58
|
+
const readmePath = join(docsDir, "README.md");
|
|
59
|
+
mkdirSync(docsDir, { recursive: true });
|
|
60
|
+
|
|
61
|
+
const configPath = writeConfig(cwd, config);
|
|
62
|
+
|
|
63
|
+
let readmeCreated = false;
|
|
64
|
+
if (overwriteReadme || !existsSync(readmePath)) {
|
|
65
|
+
writeFileSync(readmePath, buildReadme(config), "utf8");
|
|
66
|
+
readmeCreated = true;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return { configPath, readmePath, readmeCreated };
|
|
70
|
+
}
|
package/bin/lib/git.mjs
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { execSync } from "node:child_process";
|
|
2
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
3
|
+
import { basename, join } from "node:path";
|
|
4
|
+
|
|
5
|
+
function runGit(cwd, args) {
|
|
6
|
+
try {
|
|
7
|
+
return execSync(`git ${args.join(" ")}`, {
|
|
8
|
+
cwd,
|
|
9
|
+
encoding: "utf8",
|
|
10
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
11
|
+
}).trim();
|
|
12
|
+
} catch {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function normalizeRemoteUrl(url) {
|
|
18
|
+
if (!url) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (url.startsWith("git@")) {
|
|
23
|
+
const match = url.match(/^git@([^:]+):(.+?)(?:\.git)?$/);
|
|
24
|
+
if (match) {
|
|
25
|
+
return `https://${match[1]}/${match[2]}`;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return url.replace(/\.git$/, "");
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function detectGitContext(cwd) {
|
|
33
|
+
const isRepo = existsSync(join(cwd, ".git"));
|
|
34
|
+
if (!isRepo) {
|
|
35
|
+
return {
|
|
36
|
+
isRepo: false,
|
|
37
|
+
repositoryUrl: null,
|
|
38
|
+
defaultBranch: "main",
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const remote = runGit(cwd, ["remote", "get-url", "origin"]);
|
|
43
|
+
const branch = runGit(cwd, ["rev-parse", "--abbrev-ref", "HEAD"]) ?? "main";
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
isRepo: true,
|
|
47
|
+
repositoryUrl: normalizeRemoteUrl(remote),
|
|
48
|
+
defaultBranch: branch,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function detectProjectName(cwd) {
|
|
53
|
+
const packageJsonPath = join(cwd, "package.json");
|
|
54
|
+
if (existsSync(packageJsonPath)) {
|
|
55
|
+
try {
|
|
56
|
+
const pkg = JSON.parse(readFileSync(packageJsonPath, "utf8"));
|
|
57
|
+
if (pkg.name) {
|
|
58
|
+
return pkg.name.replace(/^@[^/]+\//, "");
|
|
59
|
+
}
|
|
60
|
+
} catch {
|
|
61
|
+
// ignore invalid package.json
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return basename(cwd);
|
|
66
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { createInterface } from "node:readline/promises";
|
|
2
|
+
import { stdin as input, stdout as output } from "node:process";
|
|
3
|
+
|
|
4
|
+
export async function createPrompter() {
|
|
5
|
+
return createInterface({ input, output });
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export async function ask(rl, question, defaultValue = "") {
|
|
9
|
+
const suffix = defaultValue ? ` (${defaultValue})` : "";
|
|
10
|
+
const answer = (await rl.question(`${question}${suffix}: `)).trim();
|
|
11
|
+
return answer || defaultValue;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export async function confirm(rl, question, defaultYes = true) {
|
|
15
|
+
const hint = defaultYes ? "Y/n" : "y/N";
|
|
16
|
+
const answer = (await rl.question(`${question} [${hint}]: `)).trim().toLowerCase();
|
|
17
|
+
|
|
18
|
+
if (!answer) {
|
|
19
|
+
return defaultYes;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return answer === "y" || answer === "yes";
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export async function chooseAgents(rl, detected, labels) {
|
|
26
|
+
const selected = [];
|
|
27
|
+
|
|
28
|
+
console.log("\nWhich coding agents should receive the skills?");
|
|
29
|
+
for (const id of detected) {
|
|
30
|
+
const yes = await confirm(rl, ` Install for ${labels[id]}?`, true);
|
|
31
|
+
if (yes) {
|
|
32
|
+
selected.push(id);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (selected.length === 0) {
|
|
37
|
+
console.log(" No agents selected — defaulting to all detected agents.");
|
|
38
|
+
return detected;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return selected;
|
|
42
|
+
}
|
package/bin/setup.mjs
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { detectGitContext, detectProjectName } from "./lib/git.mjs";
|
|
2
|
+
import {
|
|
3
|
+
CONFIG_VERSION,
|
|
4
|
+
readConfig,
|
|
5
|
+
scaffoldDocs,
|
|
6
|
+
} from "./lib/config.mjs";
|
|
7
|
+
import {
|
|
8
|
+
ask,
|
|
9
|
+
chooseAgents,
|
|
10
|
+
confirm,
|
|
11
|
+
createPrompter,
|
|
12
|
+
} from "./lib/prompt.mjs";
|
|
13
|
+
|
|
14
|
+
export async function runSetup({
|
|
15
|
+
cwd,
|
|
16
|
+
global = false,
|
|
17
|
+
yes = false,
|
|
18
|
+
agents = null,
|
|
19
|
+
detectedAgents,
|
|
20
|
+
agentLabels,
|
|
21
|
+
}) {
|
|
22
|
+
const git = detectGitContext(cwd);
|
|
23
|
+
const existing = readConfig(cwd);
|
|
24
|
+
|
|
25
|
+
if (yes) {
|
|
26
|
+
return {
|
|
27
|
+
version: CONFIG_VERSION,
|
|
28
|
+
projectName: existing?.projectName ?? detectProjectName(cwd),
|
|
29
|
+
description: existing?.description ?? "",
|
|
30
|
+
repositoryUrl: existing?.repositoryUrl ?? git.repositoryUrl ?? "",
|
|
31
|
+
defaultBranch: existing?.defaultBranch ?? git.defaultBranch,
|
|
32
|
+
docsDir: existing?.docsDir ?? "destinotes",
|
|
33
|
+
installedAt: new Date().toISOString(),
|
|
34
|
+
global,
|
|
35
|
+
agents: agents ?? existing?.agents ?? detectedAgents,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const rl = await createPrompter();
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
console.log("\nDestinotes setup\n");
|
|
43
|
+
|
|
44
|
+
if (existing) {
|
|
45
|
+
const reconfigure = await confirm(
|
|
46
|
+
rl,
|
|
47
|
+
"Existing destinotes.config.json found. Reconfigure project settings?",
|
|
48
|
+
false,
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
if (!reconfigure) {
|
|
52
|
+
console.log("Keeping existing project settings.");
|
|
53
|
+
const selectedAgents =
|
|
54
|
+
agents ??
|
|
55
|
+
existing.agents ??
|
|
56
|
+
(await chooseAgents(rl, detectedAgents, agentLabels));
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
...existing,
|
|
60
|
+
global: existing.global ?? global,
|
|
61
|
+
agents: selectedAgents,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const projectName = await ask(
|
|
67
|
+
rl,
|
|
68
|
+
"Project name",
|
|
69
|
+
existing?.projectName ?? detectProjectName(cwd),
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
const repositoryUrl = await ask(
|
|
73
|
+
rl,
|
|
74
|
+
"Repository URL",
|
|
75
|
+
existing?.repositoryUrl ?? git.repositoryUrl ?? "",
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
const defaultBranch = await ask(
|
|
79
|
+
rl,
|
|
80
|
+
"Default branch",
|
|
81
|
+
existing?.defaultBranch ?? git.defaultBranch,
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
const docsDir = await ask(
|
|
85
|
+
rl,
|
|
86
|
+
"Docs output folder (relative to project root)",
|
|
87
|
+
existing?.docsDir ?? "destinotes",
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
const description = await ask(
|
|
91
|
+
rl,
|
|
92
|
+
"Short project description (optional)",
|
|
93
|
+
existing?.description ?? "",
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
if (!global) {
|
|
97
|
+
global = await confirm(
|
|
98
|
+
rl,
|
|
99
|
+
"Install skills globally (all projects) instead of this project only?",
|
|
100
|
+
false,
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const selectedAgents =
|
|
105
|
+
agents ?? (await chooseAgents(rl, detectedAgents, agentLabels));
|
|
106
|
+
|
|
107
|
+
const config = {
|
|
108
|
+
version: CONFIG_VERSION,
|
|
109
|
+
projectName,
|
|
110
|
+
description,
|
|
111
|
+
repositoryUrl,
|
|
112
|
+
defaultBranch,
|
|
113
|
+
docsDir,
|
|
114
|
+
installedAt: new Date().toISOString(),
|
|
115
|
+
global,
|
|
116
|
+
agents: selectedAgents,
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
console.log("\nSetup summary:");
|
|
120
|
+
console.log(` Project: ${config.projectName}`);
|
|
121
|
+
console.log(` Repository: ${config.repositoryUrl || "(none)"}`);
|
|
122
|
+
console.log(` Branch: ${config.defaultBranch}`);
|
|
123
|
+
console.log(` Docs folder: ./${config.docsDir}/`);
|
|
124
|
+
console.log(
|
|
125
|
+
` Agents: ${selectedAgents.map((id) => agentLabels[id]).join(", ")}`,
|
|
126
|
+
);
|
|
127
|
+
console.log(` Scope: ${global ? "global" : "this project"}`);
|
|
128
|
+
|
|
129
|
+
const proceed = await confirm(rl, "\nProceed with install?", true);
|
|
130
|
+
if (!proceed) {
|
|
131
|
+
console.log("Setup cancelled.");
|
|
132
|
+
process.exit(0);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return config;
|
|
136
|
+
} finally {
|
|
137
|
+
rl.close();
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export function finalizeProjectFiles(cwd, config, existingConfig) {
|
|
142
|
+
if (config.global) {
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return scaffoldDocs(cwd, config, {
|
|
147
|
+
overwriteReadme: Boolean(existingConfig),
|
|
148
|
+
});
|
|
149
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "destinotes-skills",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Agent skills that generate repository documentation under ./destinotes/",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": ">=18"
|
|
9
|
+
},
|
|
10
|
+
"bin": {
|
|
11
|
+
"destinotes-skills": "./bin/install.mjs"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"bin",
|
|
15
|
+
"skills"
|
|
16
|
+
],
|
|
17
|
+
"keywords": [
|
|
18
|
+
"agent-skill",
|
|
19
|
+
"cursor",
|
|
20
|
+
"claude-code",
|
|
21
|
+
"documentation",
|
|
22
|
+
"destinotes",
|
|
23
|
+
"wiki"
|
|
24
|
+
],
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "git+https://github.com/destinotes/destinotes.git",
|
|
28
|
+
"directory": "packages/skills"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: destinotes-cost-analysis
|
|
3
|
+
description: >-
|
|
4
|
+
Produces cost-analysis documentation for one feature or system slice by
|
|
5
|
+
combining repository evidence with live vendor pricing docs. Invoke with
|
|
6
|
+
/destinotes-cost-analysis [analysis-slug] [context]. Maps billable units
|
|
7
|
+
(tokens, requests, GB, minutes, seats), applies pricing sources, and writes
|
|
8
|
+
a pricing report under ./destinotes/cost-analysis/<slug>.md.
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Destinotes Cost Analysis — Money-focused technical doc
|
|
12
|
+
|
|
13
|
+
**Inherits all rules from `destinotes-prompt`** (output location, folder discovery, document skeleton — *Contents / Tags / Develop the issue* — tone, code citation, freshness footer). Read that skill first; this file only adds cost-scope rules.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Invocation (context required)
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
/destinotes-cost-analysis [analysis-slug] [context]
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
| Param | Required | Meaning |
|
|
24
|
+
|---|---|---|
|
|
25
|
+
| `context` | **Yes** | Target capability/workload and what to include (token spend, storage, egress, queue ops, monthly scenarios). |
|
|
26
|
+
| `analysis-slug` | No* | `kebab-case` stem. If omitted, derive from context and echo it under *Contents*. |
|
|
27
|
+
|
|
28
|
+
## Output path
|
|
29
|
+
|
|
30
|
+
`./destinotes/cost-analysis/<analysis-slug>.md` — fixed. One primary file per invocation. On update, preserve `<!-- human:begin --> ... <!-- human:end -->` blocks.
|
|
31
|
+
|
|
32
|
+
## Data collection workflow
|
|
33
|
+
|
|
34
|
+
1. Parse `context` → scope + workloads + required outputs.
|
|
35
|
+
2. Scan repo for cost drivers: routes, workers, model calls, DB R/W, storage, egress, cron/queues, third-party SDKs, plan limits.
|
|
36
|
+
3. Identify billable units per driver (input/output tokens, requests, GB-month, GB egress, compute minutes, seats/month).
|
|
37
|
+
4. Web-research **official** vendor pricing pages (calculators, quotas, free tier, region notes); record source URL + retrieval date.
|
|
38
|
+
5. Build formulas and run **Low / Base / High** scenarios.
|
|
39
|
+
6. Mark unverifiable prices as `Unknown` and route to *Gaps & follow-ups*.
|
|
40
|
+
|
|
41
|
+
## Extra required sections (per analysis)
|
|
42
|
+
|
|
43
|
+
Append these **after** the parent skeleton’s `Develop the issue`:
|
|
44
|
+
|
|
45
|
+
1. **Scope** — In scope / Out of scope.
|
|
46
|
+
2. **Cost drivers** — Table: `driver | component/file | billable unit | why it costs money`.
|
|
47
|
+
3. **Pricing sources** — Table: `provider | plan/tier | unit price | source URL | retrieved date`.
|
|
48
|
+
4. **Assumptions & formulas** — Explicit assumptions and exact math (e.g. `monthly_cost = requests × price_per_request`).
|
|
49
|
+
5. **Scenario estimates** — At least 3 scenarios (Low / Base / High) with monthly totals and per-unit breakdown.
|
|
50
|
+
6. **Architecture-to-cost diagram** — Mermaid `flowchart LR` showing request path and where each billable event occurs.
|
|
51
|
+
7. **Sensitivity analysis** — Variables that move cost most (token length, cache hit rate, retention, egress).
|
|
52
|
+
8. **Optimization opportunities** — Concrete actions with expected impact and tradeoffs.
|
|
53
|
+
9. **Risks & unknowns** — Missing prices, ambiguous units, rate-limit / plan-change risk.
|
|
54
|
+
10. **Gaps & follow-ups** — What to instrument, contracts to review, dashboards to add.
|
|
55
|
+
|
|
56
|
+
Add when relevant: **Unit economics** (cost per request/user/document), **Break-even points**, **Regional / currency notes**, **Validation plan** (estimates vs real invoices).
|
|
57
|
+
|
|
58
|
+
## Baseline table templates
|
|
59
|
+
|
|
60
|
+
```markdown
|
|
61
|
+
### Cost driver inventory
|
|
62
|
+
| Driver | Source location | Unit | Baseline usage | Notes |
|
|
63
|
+
|
|
64
|
+
### Scenario estimates
|
|
65
|
+
| Scenario | Requests/mo | Tokens in/out or ops | Storage / Egress | Estimated monthly cost |
|
|
66
|
+
|
|
67
|
+
### Optimization backlog
|
|
68
|
+
| Opportunity | Estimated savings | Effort | Risk | Owner |
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Quality rules
|
|
72
|
+
|
|
73
|
+
- Architecture/workload claims cite repo paths and symbols (per `destinotes-prompt`).
|
|
74
|
+
- Pricing claims cite **official** vendor pages; avoid secondary blogs unless no official source exists.
|
|
75
|
+
- Never present uncertain values as fact—mark `Assumption` or `Unknown`.
|
|
76
|
+
|
|
77
|
+
## Triggers
|
|
78
|
+
|
|
79
|
+
`/destinotes-cost-analysis`, requests for cost estimate, pricing analysis, unit economics, token spend / LLM cost modeling, infra cost breakdown per request/user/month, or provider pricing comparison grounded in repo workload.
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: destinotes-document
|
|
3
|
+
description: >-
|
|
4
|
+
Generates one custom markdown document at an arbitrary path under
|
|
5
|
+
./destinotes/, chosen by the caller (folder + file). Invoke with
|
|
6
|
+
/destinotes-document [folderName]:[fileName] [context] for narrative or
|
|
7
|
+
scoped docs that do not fit destinotes-general (whole-repo) or
|
|
8
|
+
destinotes-feature (single feature) or destinotes-cost-analysis (pricing).
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Destinotes Document — Custom-path technical note
|
|
12
|
+
|
|
13
|
+
**Inherits all rules from `destinotes-prompt`** (output location, folder discovery, document skeleton — *Contents / Tags / Develop the issue* — tone, code citation, freshness footer). Read that skill first; this file only adds custom-path rules.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Invocation
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
/destinotes-document [folderName]:[fileName] [context]
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
| Param | Required | Meaning |
|
|
24
|
+
|---|---|---|
|
|
25
|
+
| `folderName` | Yes | Subfolder under `./destinotes/` (e.g. `api`, `modules/auth`, `patterns`). Must already exist or be approved by the user (see folder discovery in `destinotes-prompt`). |
|
|
26
|
+
| `fileName` | Yes | Markdown stem without `.md` (kebab-case, e.g. `oauth-flow`). |
|
|
27
|
+
| `context` | Yes | Plain-language description of what to document, scope, and audience. |
|
|
28
|
+
|
|
29
|
+
If `folderName` does not exist, ask the user before creating it.
|
|
30
|
+
|
|
31
|
+
## Output path
|
|
32
|
+
|
|
33
|
+
`./destinotes/<folderName>/<fileName>.md`. Overwrite if the file exists; preserve `<!-- human:begin --> ... <!-- human:end -->` blocks.
|
|
34
|
+
|
|
35
|
+
## Workflow
|
|
36
|
+
|
|
37
|
+
1. Parse `context` into subject, scope, audience, exclusions.
|
|
38
|
+
2. List `./destinotes/` to confirm the target folder fits the subject; otherwise ask.
|
|
39
|
+
3. Search the repo for the materials referenced in `context` (modules, routes, schemas, jobs, configs, tests).
|
|
40
|
+
4. Write the doc using the parent skeleton, then add the extra sections below as relevant.
|
|
41
|
+
|
|
42
|
+
## Extra recommended sections
|
|
43
|
+
|
|
44
|
+
Pick what fits the subject; omit empty ones. All go after `Develop the issue`.
|
|
45
|
+
|
|
46
|
+
- **Scope** — In scope / Out of scope.
|
|
47
|
+
- **Architecture** — Components, dependencies, data flow (mermaid when helpful).
|
|
48
|
+
- **Public surface** — Functions/classes/endpoints/events with signatures.
|
|
49
|
+
- **Data & types** — Schemas, DB tables, TS/Zod types.
|
|
50
|
+
- **Configuration** — Env vars, feature flags, config files (names only).
|
|
51
|
+
- **Errors & edge cases** — What can fail and how.
|
|
52
|
+
- **Examples** — Short, real excerpts from the repo (with paths) or minimal usage snippets.
|
|
53
|
+
- **Related docs** — Links to other `./destinotes/...` files.
|
|
54
|
+
- **Gaps & follow-ups** — Open questions, missing coverage.
|
|
55
|
+
|
|
56
|
+
## Optional metadata flags
|
|
57
|
+
|
|
58
|
+
The caller may append flags; render them inside `## 2. Tags` or as a small metadata line under the title:
|
|
59
|
+
|
|
60
|
+
- `--version=X.Y` · `--status=draft|review|published` · `--audience=backend,frontend,devops` · `--tags=tag1,tag2`
|
|
61
|
+
|
|
62
|
+
## Triggers
|
|
63
|
+
|
|
64
|
+
`/destinotes-document`, requests for a narrative or scoped doc at an arbitrary `./destinotes/<folder>/<file>.md` path that is **not** a whole-repo wiki, a single feature dive, or a pricing report.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: destinotes-feature
|
|
3
|
+
description: >-
|
|
4
|
+
Documents a single app feature from required natural-language context:
|
|
5
|
+
locates relevant routes, handlers, jobs, and data paths in the repo and
|
|
6
|
+
writes one markdown doc under ./destinotes/features/<slug>.md. Use for
|
|
7
|
+
feature deep dives (JWT creation, OAuth callback, billing webhook)—not
|
|
8
|
+
whole-repo wikis or arbitrary destinotes paths.
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Destinotes Feature — Single-feature technical note
|
|
12
|
+
|
|
13
|
+
**Inherits all rules from `destinotes-prompt`** (output location, folder discovery, document skeleton — *Contents / Tags / Develop the issue* — tone, code citation, freshness footer). Read that skill first; this file only adds feature-scope rules.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Invocation (context required)
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
/destinotes-feature [feature-slug] [context]
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
| Param | Required | Meaning |
|
|
24
|
+
|---|---|---|
|
|
25
|
+
| `context` | **Yes** | What the feature is, what to include, audience, boundaries. If only one block of text is given, treat it as `context` and derive `feature-slug`. |
|
|
26
|
+
| `feature-slug` | No* | `kebab-case` stem. If omitted, derive from the first explicit feature name in `context` (e.g. “JWT access token creation” → `jwt-access-token-creation`) and echo the chosen slug under *Contents*. |
|
|
27
|
+
|
|
28
|
+
## Output path
|
|
29
|
+
|
|
30
|
+
`./destinotes/features/<feature-slug>.md` — fixed. Use only `a-z`, `0-9`, hyphens. If the feature splits (server + client), keep one file with subsections; only add `…-<facet>.md` when the user asks.
|
|
31
|
+
|
|
32
|
+
## Discovery workflow
|
|
33
|
+
|
|
34
|
+
1. Parse `context` for scope, inclusions, exclusions, sensitivity.
|
|
35
|
+
2. Search the repo: routes, API handlers, server actions, middleware, `lib/`, workers, config, types, Supabase/migrations, related tests.
|
|
36
|
+
3. Build an **implementation map** (path → role); trim to files that materially participate.
|
|
37
|
+
4. Trace one **primary success path** and note **failure** branches from entry (HTTP/UI/event) to persistence/external IO.
|
|
38
|
+
5. If `./destinotes/features/<feature-slug>.md` exists, update it.
|
|
39
|
+
|
|
40
|
+
## Extra required sections (per feature doc)
|
|
41
|
+
|
|
42
|
+
Append these **after** the parent skeleton’s `Develop the issue`:
|
|
43
|
+
|
|
44
|
+
1. **Scope** — In scope / Out of scope (2–5 bullets each).
|
|
45
|
+
2. **Surface area** — Routes (method + path), UI entry, CLI, queue topic. Table preferred.
|
|
46
|
+
3. **Implementation map** — Table: `path | responsibility | key symbols`.
|
|
47
|
+
4. **Control flow** — Mermaid `sequenceDiagram` or `flowchart LR` for the main path (≤ ~15 nodes).
|
|
48
|
+
5. **Data & types** — Payloads, DB tables/columns touched, TS types or Zod schemas.
|
|
49
|
+
6. **Security & trust** — Authn/z, secrets (names only), CSRF/cookies, validation, multi-tenant boundaries. `N/A` line if irrelevant.
|
|
50
|
+
7. **Errors & edge cases** — Status codes, retries, idempotency, race conditions evidenced in code.
|
|
51
|
+
8. **Configuration** — Env vars and config files by name; default vs production differences if visible.
|
|
52
|
+
9. **Verification** — Manual test steps or test files/commands (`npm run test …`, file:line pointers).
|
|
53
|
+
10. **Gaps & follow-ups** — Unknowns, suspected dead code, missing tests. Do not invent answers.
|
|
54
|
+
|
|
55
|
+
Add when useful: **Dependencies** (internal modules; link to `../libraries/inventory.md`), **Performance** (only if evidenced), **Related docs**.
|
|
56
|
+
|
|
57
|
+
## Triggers
|
|
58
|
+
|
|
59
|
+
`/destinotes-feature`, “document this feature” targeting `features/`, or a request for a route-level explanation of one capability (JWT, OAuth, webhooks, billing, etc.) as a single Destinotes file.
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: destinotes-general
|
|
3
|
+
description: >-
|
|
4
|
+
Bootstraps or refreshes a full-repository technical wiki under ./destinotes/
|
|
5
|
+
by scanning the codebase and writing one seed article per fixed category
|
|
6
|
+
(architecture, libraries, security, deployment, data, configuration,
|
|
7
|
+
integrations, testing, development, observability). Use for whole-repo docs
|
|
8
|
+
baselines and onboarding packs—not for single-feature docs.
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Destinotes General — Repository wiki bootstrap
|
|
12
|
+
|
|
13
|
+
**Inherits all rules from `destinotes-prompt`** (output location, folder discovery, document skeleton — *Contents / Tags / Develop the issue* — tone, code citation, freshness footer). Read that skill first; this file only adds whole-repo scope.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Invocation
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
/destinotes-general [optional context]
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Optional context: target audience (new hire, security review), emphasis (“focus on auth”), or partial refresh (“refresh only libraries + deployment”).
|
|
24
|
+
|
|
25
|
+
## Output
|
|
26
|
+
|
|
27
|
+
One seed article per category under `./destinotes/`. Create folders if missing; update files in place if present.
|
|
28
|
+
|
|
29
|
+
| Folder | Seed file | Purpose |
|
|
30
|
+
|---|---|---|
|
|
31
|
+
| `architecture/` | `overview.md` | System shape, components, data/control flow, boundaries |
|
|
32
|
+
| `libraries/` | `inventory.md` | Deps + devDeps with **resolved versions** (lockfile preferred; otherwise quote `package.json` ranges and flag) |
|
|
33
|
+
| `security/` | `posture.md` | Authn/z, secrets, headers, supply chain, hardening |
|
|
34
|
+
| `deployment/` | `pipeline-and-hosting.md` | Build, hosting, env vars, migrations, rollback |
|
|
35
|
+
| `data-and-storage/` | `overview.md` | DB, R2/KV/D1, Supabase schema, retention |
|
|
36
|
+
| `configuration/` | `environment.md` | Env files, `wrangler.toml`, flags, per-env deltas |
|
|
37
|
+
| `integrations/` | `external-services.md` | OAuth, email, analytics, webhooks, rate limits |
|
|
38
|
+
| `testing-and-quality/` | `gates.md` | Test runners, coverage, lint/typecheck gates |
|
|
39
|
+
| `development/` | `local-setup.md` | Setup, scripts, conventions, troubleshooting |
|
|
40
|
+
| `observability/` | `overview.md` | Logging, metrics, tracing, error reporting |
|
|
41
|
+
|
|
42
|
+
Add `compliance-and-privacy/`, `performance/`, or `user-guide/` only when the repo has meaningful content for them. Also create `./destinotes/README.md` (one paragraph: layout + how to regenerate).
|
|
43
|
+
|
|
44
|
+
## Extra required sections (per article)
|
|
45
|
+
|
|
46
|
+
Append these **after** the parent skeleton’s `Develop the issue`:
|
|
47
|
+
|
|
48
|
+
1. **Facts from the repository** — Tables of paths, versions, bindings. No speculation.
|
|
49
|
+
2. **Diagrams** — Mermaid (flowchart/LR for pipelines, sequenceDiagram for auth/email). Keep small.
|
|
50
|
+
3. **Key files & entry points** — Bulleted repo-relative paths.
|
|
51
|
+
4. **Gaps & follow-ups** — Unknowns, TODOs, files not yet read.
|
|
52
|
+
|
|
53
|
+
Add when relevant: **Scope & out of scope**, **Decisions & constraints** (ADR-style one-liners inferred from config/code), **Operational notes**, **References**.
|
|
54
|
+
|
|
55
|
+
## Execution checklist
|
|
56
|
+
|
|
57
|
+
1. Map repo: package manager, framework, infra files (`wrangler.toml`, Docker, `.github/workflows`).
|
|
58
|
+
2. Read lockfile + `package.json` → `libraries/inventory.md`.
|
|
59
|
+
3. Read deployment + README/scripts → `deployment/` + `configuration/`.
|
|
60
|
+
4. Skim auth, middleware, routes, server actions → `security/` + `architecture/`.
|
|
61
|
+
5. Skim Supabase/migrations/ORM → `data-and-storage/`.
|
|
62
|
+
6. Write/update all seed articles in one pass; keep cross-links consistent.
|
|
63
|
+
|
|
64
|
+
## Triggers
|
|
65
|
+
|
|
66
|
+
`/destinotes-general`, “whole repo overview”, “wiki bootstrap”, “onboarding docs pack”, “refresh destinotes tree”, or any request for a project-wide architecture + libraries + security snapshot.
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: destinotes-prompt
|
|
3
|
+
description: >-
|
|
4
|
+
Parent skill and shared contract for every destinotes-* skill. Defines the
|
|
5
|
+
output location, folder/subject conventions, document skeleton (Contents,
|
|
6
|
+
Tags, Develop the issue), code-citation rules, and tone. All other
|
|
7
|
+
destinotes-* skills MUST read this file first and inherit its rules; they
|
|
8
|
+
only add their own scope and skill-specific sections on top.
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Destinotes Prompt — Shared contract for all destinotes-* skills
|
|
12
|
+
|
|
13
|
+
This is the **parent** skill. Every other `destinotes-*` skill (`destinotes-general`, `destinotes-feature`, `destinotes-document`, `destinotes-cost-analysis`, …) **must read this file first** and obey the rules below. Child skills only add **scope, invocation, and extra sections**—they do not override these defaults.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## 1. Output is always markdown under `./destinotes/`
|
|
18
|
+
|
|
19
|
+
- Every artifact is a single `.md` file.
|
|
20
|
+
- Root for all docs: `./destinotes/` (repo-relative), unless `destinotes/destinotes.config.json` sets a different `docsDir` — then use `./<docsDir>/` instead.
|
|
21
|
+
- Each **subfolder = one subject** (e.g. `architecture/`, `security/`, `features/`, `cost-analysis/`).
|
|
22
|
+
- **Never** write outside the configured docs root and never create binaries.
|
|
23
|
+
|
|
24
|
+
### Project config (read first)
|
|
25
|
+
|
|
26
|
+
If `destinotes/destinotes.config.json` exists (or `<docsDir>/destinotes.config.json`), read it before writing docs. Use:
|
|
27
|
+
|
|
28
|
+
- `projectName` — human title in generated READMEs and doc intros when relevant
|
|
29
|
+
- `repositoryUrl` — link back to the canonical repo in cross-references
|
|
30
|
+
- `defaultBranch` — when citing branches or comparing to main
|
|
31
|
+
- `description` — one-line project context where helpful
|
|
32
|
+
- `docsDir` — output root (default `destinotes`)
|
|
33
|
+
|
|
34
|
+
Do not invent values missing from config; omit or mark as unknown.
|
|
35
|
+
|
|
36
|
+
## 2. Folder discovery before writing
|
|
37
|
+
|
|
38
|
+
Before creating any file:
|
|
39
|
+
|
|
40
|
+
1. List `./destinotes/` and inspect existing subfolders.
|
|
41
|
+
2. Pick the folder whose **subject** best fits the new doc.
|
|
42
|
+
3. If no folder fits, **ask the user** whether to create a new folder (propose a kebab-case name); do not invent folders silently.
|
|
43
|
+
4. Child skills with a fixed output path (e.g. `features/`, `cost-analysis/`) keep that path; only ambiguous docs trigger the question.
|
|
44
|
+
|
|
45
|
+
## 3. Required document skeleton
|
|
46
|
+
|
|
47
|
+
Every generated doc starts with these three sections in this order:
|
|
48
|
+
|
|
49
|
+
```markdown
|
|
50
|
+
# <Human Title>
|
|
51
|
+
|
|
52
|
+
## 1. Contents
|
|
53
|
+
|
|
54
|
+
- One short bullet per section in this doc, describing what it covers.
|
|
55
|
+
|
|
56
|
+
## 2. Tags
|
|
57
|
+
|
|
58
|
+
`tag-one` `tag-two` `tag-three`
|
|
59
|
+
|
|
60
|
+
## 3. Develop the issue
|
|
61
|
+
|
|
62
|
+
<Main body. Expand the subject as broadly as possible while staying concise.
|
|
63
|
+
Cover what it is, how it works in this repo, key flows, edge cases, and
|
|
64
|
+
boundaries. Use tables and mermaid diagrams over prose when they compress
|
|
65
|
+
information.>
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
- **Contents** = a description of what the document contains (not a clickable TOC).
|
|
69
|
+
- **Tags** = 3–8 short kebab-case tags that aid search/grouping in Destinotes.
|
|
70
|
+
- **Develop the issue** = the substantive body. Child skills add their own subsections here (and may add sibling top-level sections after it).
|
|
71
|
+
- Child skills append their **extra required sections** after `Develop the issue` (e.g. *Cost drivers*, *Implementation map*, *Pricing sources*).
|
|
72
|
+
|
|
73
|
+
## 4. Tone & coverage
|
|
74
|
+
|
|
75
|
+
- **Concise, direct, complete.** No filler, no marketing language, no restating the question.
|
|
76
|
+
- **Broad but tight**: cover the whole subject; cut anything not load-bearing.
|
|
77
|
+
- Prefer **tables**, **bulleted lists**, and **mermaid** over long paragraphs.
|
|
78
|
+
- Never invent behavior, versions, or APIs not evidenced in the repo or in cited sources.
|
|
79
|
+
- If unknown, list it under a final **Gaps & follow-ups** bullet—do not guess.
|
|
80
|
+
|
|
81
|
+
## 5. Grounding in the actual codebase
|
|
82
|
+
|
|
83
|
+
- Use **real code from this repository** as evidence.
|
|
84
|
+
- Every code excerpt must include the **repo-relative path** and ideally the line range and symbol name.
|
|
85
|
+
- Use this exact citation format for existing code:
|
|
86
|
+
|
|
87
|
+
```startLine:endLine:repo/relative/path
|
|
88
|
+
// short, faithful excerpt
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
- Prefer short excerpts (≤ ~15 lines). For longer logic, cite path + symbol and summarize.
|
|
92
|
+
- **Never** paste secret values; reference variable names only and point to `.env.example`, `wrangler secret put`, etc.
|
|
93
|
+
|
|
94
|
+
## 6. Cross-linking & freshness
|
|
95
|
+
|
|
96
|
+
- Link related Destinotes docs with relative paths (e.g. `../architecture/overview.md`).
|
|
97
|
+
- End every doc with a one-line footer: `Last updated: YYYY-MM-DD` (use today’s date if available in session).
|
|
98
|
+
- When updating an existing file, preserve any block wrapped in `<!-- human:begin --> ... <!-- human:end -->` exactly.
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## How child skills extend this
|
|
103
|
+
|
|
104
|
+
A child skill’s `SKILL.md` should:
|
|
105
|
+
|
|
106
|
+
1. Reference this file in its preamble (“inherits rules from `destinotes-prompt`”).
|
|
107
|
+
2. Define its **invocation**, **fixed output path** (or rule for choosing one), and **scope**.
|
|
108
|
+
3. List the **extra required sections** to append after `Develop the issue`.
|
|
109
|
+
4. Avoid re-stating tone, length, citation, or folder rules—they live here.
|
|
110
|
+
|
|
111
|
+
Children currently bound to this contract:
|
|
112
|
+
|
|
113
|
+
| Skill | Scope | Output path |
|
|
114
|
+
|-------|-------|-------------|
|
|
115
|
+
| `destinotes-general` | Whole-repo wiki bootstrap | `./destinotes/<category>/*.md` |
|
|
116
|
+
| `destinotes-feature` | Single feature deep dive | `./destinotes/features/<slug>.md` |
|
|
117
|
+
| `destinotes-document` | Custom `folder:file` doc | `./destinotes/<folder>/<file>.md` |
|
|
118
|
+
| `destinotes-cost-analysis` | Pricing/cost report | `./destinotes/cost-analysis/<slug>.md` |
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Triggers
|
|
123
|
+
|
|
124
|
+
This skill is **always implicitly active** whenever a `destinotes-*` skill runs. Read it before producing any Destinotes file.
|