cortex-agents 1.1.0 → 2.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/.opencode/agents/build.md +97 -11
- package/.opencode/agents/debug.md +24 -2
- package/.opencode/agents/devops.md +1 -2
- package/.opencode/agents/fullstack.md +1 -2
- package/.opencode/agents/plan.md +16 -7
- package/.opencode/agents/security.md +1 -2
- package/.opencode/agents/testing.md +1 -2
- package/.opencode/skills/api-design/SKILL.md +348 -0
- package/.opencode/skills/architecture-patterns/SKILL.md +323 -0
- package/.opencode/skills/backend-development/SKILL.md +329 -0
- package/.opencode/skills/code-quality/SKILL.md +12 -0
- package/.opencode/skills/database-design/SKILL.md +347 -0
- package/.opencode/skills/deployment-automation/SKILL.md +7 -0
- package/.opencode/skills/design-patterns/SKILL.md +295 -0
- package/.opencode/skills/desktop-development/SKILL.md +295 -0
- package/.opencode/skills/frontend-development/SKILL.md +210 -0
- package/.opencode/skills/mobile-development/SKILL.md +407 -0
- package/.opencode/skills/performance-optimization/SKILL.md +330 -0
- package/.opencode/skills/testing-strategies/SKILL.md +33 -0
- package/README.md +309 -111
- package/dist/cli.js +264 -36
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +43 -0
- package/dist/plugin.js +3 -2
- package/dist/registry.d.ts +45 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +140 -0
- package/dist/tools/cortex.d.ts.map +1 -1
- package/dist/tools/cortex.js +3 -4
- package/dist/tools/docs.d.ts +52 -0
- package/dist/tools/docs.d.ts.map +1 -0
- package/dist/tools/docs.js +328 -0
- package/dist/tools/task.d.ts +20 -0
- package/dist/tools/task.d.ts.map +1 -0
- package/dist/tools/task.js +302 -0
- package/dist/tools/worktree.d.ts +32 -0
- package/dist/tools/worktree.d.ts.map +1 -1
- package/dist/tools/worktree.js +403 -2
- package/dist/utils/plan-extract.d.ts +37 -0
- package/dist/utils/plan-extract.d.ts.map +1 -0
- package/dist/utils/plan-extract.js +137 -0
- package/dist/utils/propagate.d.ts +22 -0
- package/dist/utils/propagate.d.ts.map +1 -0
- package/dist/utils/propagate.js +64 -0
- package/dist/utils/worktree-detect.d.ts +20 -0
- package/dist/utils/worktree-detect.d.ts.map +1 -0
- package/dist/utils/worktree-detect.js +42 -0
- package/package.json +17 -7
- package/.opencode/skills/web-development/SKILL.md +0 -122
package/dist/tools/cortex.js
CHANGED
|
@@ -3,10 +3,9 @@ import * as fs from "fs";
|
|
|
3
3
|
import * as path from "path";
|
|
4
4
|
const CORTEX_DIR = ".cortex";
|
|
5
5
|
const DEFAULT_CONFIG = {
|
|
6
|
-
$schema: "https://k2p5.dev/cortex-config.json",
|
|
7
6
|
version: "1.0.0",
|
|
8
7
|
worktree: {
|
|
9
|
-
root: "
|
|
8
|
+
root: ".worktrees",
|
|
10
9
|
autoCleanup: false,
|
|
11
10
|
},
|
|
12
11
|
branches: {
|
|
@@ -33,7 +32,7 @@ config.local.json
|
|
|
33
32
|
`;
|
|
34
33
|
const README_CONTENT = `# .cortex
|
|
35
34
|
|
|
36
|
-
This directory contains project context for the
|
|
35
|
+
This directory contains project context for the Cortex development agents.
|
|
37
36
|
|
|
38
37
|
## Structure
|
|
39
38
|
|
|
@@ -56,7 +55,7 @@ They are gitignored by default but can be kept if needed.
|
|
|
56
55
|
|
|
57
56
|
## Usage
|
|
58
57
|
|
|
59
|
-
The
|
|
58
|
+
The Cortex agents will automatically use this directory for:
|
|
60
59
|
- Saving implementation plans before coding
|
|
61
60
|
- Recording session summaries with key decisions
|
|
62
61
|
- Managing worktree and branch workflows
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export declare const init: {
|
|
2
|
+
description: string;
|
|
3
|
+
args: {
|
|
4
|
+
path: import("zod").ZodOptional<import("zod").ZodString>;
|
|
5
|
+
confirm: import("zod").ZodOptional<import("zod").ZodBoolean>;
|
|
6
|
+
};
|
|
7
|
+
execute(args: {
|
|
8
|
+
path?: string | undefined;
|
|
9
|
+
confirm?: boolean | undefined;
|
|
10
|
+
}, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
|
|
11
|
+
};
|
|
12
|
+
export declare const save: {
|
|
13
|
+
description: string;
|
|
14
|
+
args: {
|
|
15
|
+
title: import("zod").ZodString;
|
|
16
|
+
type: import("zod").ZodEnum<{
|
|
17
|
+
feature: "feature";
|
|
18
|
+
decision: "decision";
|
|
19
|
+
flow: "flow";
|
|
20
|
+
}>;
|
|
21
|
+
content: import("zod").ZodString;
|
|
22
|
+
tags: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString>>;
|
|
23
|
+
relatedFiles: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString>>;
|
|
24
|
+
};
|
|
25
|
+
execute(args: {
|
|
26
|
+
title: string;
|
|
27
|
+
type: "feature" | "decision" | "flow";
|
|
28
|
+
content: string;
|
|
29
|
+
tags?: string[] | undefined;
|
|
30
|
+
relatedFiles?: string[] | undefined;
|
|
31
|
+
}, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
|
|
32
|
+
};
|
|
33
|
+
export declare const list: {
|
|
34
|
+
description: string;
|
|
35
|
+
args: {
|
|
36
|
+
type: import("zod").ZodOptional<import("zod").ZodEnum<{
|
|
37
|
+
feature: "feature";
|
|
38
|
+
all: "all";
|
|
39
|
+
decision: "decision";
|
|
40
|
+
flow: "flow";
|
|
41
|
+
}>>;
|
|
42
|
+
};
|
|
43
|
+
execute(args: {
|
|
44
|
+
type?: "feature" | "all" | "decision" | "flow" | undefined;
|
|
45
|
+
}, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
|
|
46
|
+
};
|
|
47
|
+
export declare const index: {
|
|
48
|
+
description: string;
|
|
49
|
+
args: {};
|
|
50
|
+
execute(args: Record<string, never>, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
|
|
51
|
+
};
|
|
52
|
+
//# sourceMappingURL=docs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docs.d.ts","sourceRoot":"","sources":["../../src/tools/docs.ts"],"names":[],"mappings":"AAoNA,eAAO,MAAM,IAAI;;;;;;;;;;CA4Df,CAAC;AAEH,eAAO,MAAM,IAAI;;;;;;;;;;;;;;;;;;;;CAiEf,CAAC;AAEH,eAAO,MAAM,IAAI;;;;;;;;;;;;;CAmEf,CAAC;AAEH,eAAO,MAAM,KAAK;;;;CAahB,CAAC"}
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
import { tool } from "@opencode-ai/plugin";
|
|
2
|
+
import * as fs from "fs";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
const DOCS_DIR = "docs";
|
|
5
|
+
const DOC_TYPES = ["decisions", "features", "flows"];
|
|
6
|
+
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
7
|
+
function slugify(text) {
|
|
8
|
+
return text
|
|
9
|
+
.toLowerCase()
|
|
10
|
+
.replace(/[^\w\s-]/g, "")
|
|
11
|
+
.replace(/\s+/g, "-")
|
|
12
|
+
.replace(/-+/g, "-")
|
|
13
|
+
.substring(0, 60);
|
|
14
|
+
}
|
|
15
|
+
function getDatePrefix() {
|
|
16
|
+
return new Date().toISOString().split("T")[0]; // YYYY-MM-DD
|
|
17
|
+
}
|
|
18
|
+
/** Map singular type to plural folder name */
|
|
19
|
+
function typeToFolder(type) {
|
|
20
|
+
const map = {
|
|
21
|
+
decision: "decisions",
|
|
22
|
+
feature: "features",
|
|
23
|
+
flow: "flows",
|
|
24
|
+
};
|
|
25
|
+
return map[type] || type;
|
|
26
|
+
}
|
|
27
|
+
function ensureDocsDir(worktree, docsPath) {
|
|
28
|
+
const resolved = path.join(worktree, docsPath || DOCS_DIR);
|
|
29
|
+
for (const sub of DOC_TYPES) {
|
|
30
|
+
fs.mkdirSync(path.join(resolved, sub), { recursive: true });
|
|
31
|
+
}
|
|
32
|
+
return resolved;
|
|
33
|
+
}
|
|
34
|
+
function parseFrontmatter(content) {
|
|
35
|
+
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
36
|
+
if (!match)
|
|
37
|
+
return null;
|
|
38
|
+
const fm = match[1];
|
|
39
|
+
const get = (key) => {
|
|
40
|
+
const m = fm.match(new RegExp(`${key}:\\s*"?([^"\\n]+)"?`));
|
|
41
|
+
return m ? m[1].trim() : undefined;
|
|
42
|
+
};
|
|
43
|
+
const getArray = (key) => {
|
|
44
|
+
const m = fm.match(new RegExp(`${key}:\\s*\\[([^\\]]*)]`));
|
|
45
|
+
if (!m)
|
|
46
|
+
return [];
|
|
47
|
+
return m[1]
|
|
48
|
+
.split(",")
|
|
49
|
+
.map((s) => s.trim().replace(/^"|"$/g, ""))
|
|
50
|
+
.filter(Boolean);
|
|
51
|
+
};
|
|
52
|
+
return {
|
|
53
|
+
title: get("title") || "Untitled",
|
|
54
|
+
type: get("type") || "unknown",
|
|
55
|
+
date: get("date") || "",
|
|
56
|
+
status: get("status"),
|
|
57
|
+
tags: getArray("tags"),
|
|
58
|
+
related_files: getArray("related_files"),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
// ─── Templates ───────────────────────────────────────────────────────────────
|
|
62
|
+
function buildFrontmatter(args) {
|
|
63
|
+
const date = new Date().toISOString();
|
|
64
|
+
const tagsStr = args.tags && args.tags.length > 0
|
|
65
|
+
? `[${args.tags.map((t) => `"${t}"`).join(", ")}]`
|
|
66
|
+
: "[]";
|
|
67
|
+
const filesStr = args.relatedFiles && args.relatedFiles.length > 0
|
|
68
|
+
? `[${args.relatedFiles.map((f) => `"${f}"`).join(", ")}]`
|
|
69
|
+
: "[]";
|
|
70
|
+
return `---
|
|
71
|
+
title: "${args.title}"
|
|
72
|
+
type: ${args.type}
|
|
73
|
+
date: ${date}
|
|
74
|
+
${args.status ? `status: ${args.status}` : ""}
|
|
75
|
+
tags: ${tagsStr}
|
|
76
|
+
related_files: ${filesStr}
|
|
77
|
+
---`.replace(/\n{2,}/g, "\n");
|
|
78
|
+
}
|
|
79
|
+
function buildDocument(args) {
|
|
80
|
+
const statusMap = {
|
|
81
|
+
decision: "accepted",
|
|
82
|
+
feature: "implemented",
|
|
83
|
+
flow: "",
|
|
84
|
+
};
|
|
85
|
+
const frontmatter = buildFrontmatter({
|
|
86
|
+
title: args.title,
|
|
87
|
+
type: args.type,
|
|
88
|
+
status: statusMap[args.type] || undefined,
|
|
89
|
+
tags: args.tags,
|
|
90
|
+
relatedFiles: args.relatedFiles,
|
|
91
|
+
});
|
|
92
|
+
const relatedSection = args.relatedFiles && args.relatedFiles.length > 0
|
|
93
|
+
? `\n\n## Related Files\n\n${args.relatedFiles.map((f) => `- \`${f}\``).join("\n")}`
|
|
94
|
+
: "";
|
|
95
|
+
return `${frontmatter}\n\n${args.content}${relatedSection}\n`;
|
|
96
|
+
}
|
|
97
|
+
function rebuildIndex(docsRoot) {
|
|
98
|
+
const sections = [
|
|
99
|
+
{ type: "decisions", label: "Decisions", icon: "📋", entries: [] },
|
|
100
|
+
{ type: "features", label: "Features", icon: "🚀", entries: [] },
|
|
101
|
+
{ type: "flows", label: "Flows", icon: "🔄", entries: [] },
|
|
102
|
+
];
|
|
103
|
+
for (const section of sections) {
|
|
104
|
+
const folderPath = path.join(docsRoot, section.type);
|
|
105
|
+
if (!fs.existsSync(folderPath))
|
|
106
|
+
continue;
|
|
107
|
+
const files = fs
|
|
108
|
+
.readdirSync(folderPath)
|
|
109
|
+
.filter((f) => f.endsWith(".md") && f !== ".gitkeep")
|
|
110
|
+
.sort()
|
|
111
|
+
.reverse();
|
|
112
|
+
for (const file of files) {
|
|
113
|
+
const content = fs.readFileSync(path.join(folderPath, file), "utf-8");
|
|
114
|
+
const fm = parseFrontmatter(content);
|
|
115
|
+
if (fm) {
|
|
116
|
+
section.entries.push({ ...fm, filename: file, folder: section.type });
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
const now = new Date().toISOString().split("T")[0];
|
|
121
|
+
let index = `# Project Documentation\n\n> Auto-generated by cortex-agents. Last updated: ${now}\n`;
|
|
122
|
+
for (const section of sections) {
|
|
123
|
+
index += `\n## ${section.icon} ${section.label} (${section.entries.length})\n\n`;
|
|
124
|
+
if (section.entries.length === 0) {
|
|
125
|
+
index += `_No ${section.label.toLowerCase()} documented yet._\n`;
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
if (section.type === "flows") {
|
|
129
|
+
index += `| Date | Title | Tags |\n|------|-------|------|\n`;
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
index += `| Date | Title | Status | Tags |\n|------|-------|--------|------|\n`;
|
|
133
|
+
}
|
|
134
|
+
for (const entry of section.entries) {
|
|
135
|
+
const date = entry.date ? entry.date.split("T")[0] : "—";
|
|
136
|
+
const link = `[${entry.title}](${entry.folder}/${entry.filename})`;
|
|
137
|
+
const tags = entry.tags && entry.tags.length > 0 ? entry.tags.join(", ") : "—";
|
|
138
|
+
if (section.type === "flows") {
|
|
139
|
+
index += `| ${date} | ${link} | ${tags} |\n`;
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
const status = entry.status || "—";
|
|
143
|
+
index += `| ${date} | ${link} | ${status} | ${tags} |\n`;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
const indexPath = path.join(docsRoot, "INDEX.md");
|
|
148
|
+
fs.writeFileSync(indexPath, index);
|
|
149
|
+
const totalDocs = sections.reduce((sum, s) => sum + s.entries.length, 0);
|
|
150
|
+
return `✓ Index rebuilt: ${totalDocs} documents indexed in docs/INDEX.md`;
|
|
151
|
+
}
|
|
152
|
+
// ─── Tools ───────────────────────────────────────────────────────────────────
|
|
153
|
+
export const init = tool({
|
|
154
|
+
description: "Initialize docs/ directory with folders for decisions, features, and flows documentation",
|
|
155
|
+
args: {
|
|
156
|
+
path: tool.schema
|
|
157
|
+
.string()
|
|
158
|
+
.optional()
|
|
159
|
+
.describe("Custom docs directory path relative to project root (default: 'docs')"),
|
|
160
|
+
confirm: tool.schema
|
|
161
|
+
.boolean()
|
|
162
|
+
.optional()
|
|
163
|
+
.describe("If docs/ already exists, set to true to confirm using the existing folder"),
|
|
164
|
+
},
|
|
165
|
+
async execute(args, context) {
|
|
166
|
+
const docsPath = args.path || DOCS_DIR;
|
|
167
|
+
const docsRoot = path.join(context.worktree, docsPath);
|
|
168
|
+
// Check if docs/ already exists
|
|
169
|
+
if (fs.existsSync(docsRoot)) {
|
|
170
|
+
if (!args.confirm) {
|
|
171
|
+
// Check what's already there
|
|
172
|
+
const existing = fs.readdirSync(docsRoot);
|
|
173
|
+
return `⚠ Directory '${docsPath}/' already exists with ${existing.length} entries: ${existing.join(", ")}
|
|
174
|
+
|
|
175
|
+
To use this existing folder, call docs_init again with confirm: true.
|
|
176
|
+
This will add the decisions/, features/, and flows/ subfolders without overwriting existing files.`;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
// Create folder structure
|
|
180
|
+
for (const sub of DOC_TYPES) {
|
|
181
|
+
const subPath = path.join(docsRoot, sub);
|
|
182
|
+
fs.mkdirSync(subPath, { recursive: true });
|
|
183
|
+
const gitkeep = path.join(subPath, ".gitkeep");
|
|
184
|
+
if (!fs.existsSync(gitkeep)) {
|
|
185
|
+
fs.writeFileSync(gitkeep, "");
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
// Create initial INDEX.md
|
|
189
|
+
const indexPath = path.join(docsRoot, "INDEX.md");
|
|
190
|
+
if (!fs.existsSync(indexPath)) {
|
|
191
|
+
rebuildIndex(docsRoot);
|
|
192
|
+
}
|
|
193
|
+
return `✓ Documentation directory initialized at ${docsPath}/
|
|
194
|
+
|
|
195
|
+
Structure:
|
|
196
|
+
${docsPath}/
|
|
197
|
+
├── INDEX.md Auto-generated index of all docs
|
|
198
|
+
├── decisions/ Architecture & technology decisions (ADRs)
|
|
199
|
+
├── features/ Feature documentation with diagrams
|
|
200
|
+
└── flows/ Process & data flow documentation
|
|
201
|
+
|
|
202
|
+
Use docs_save to create documentation files.
|
|
203
|
+
Use docs_list to browse existing docs.
|
|
204
|
+
The INDEX.md is automatically rebuilt whenever you save a new document.`;
|
|
205
|
+
},
|
|
206
|
+
});
|
|
207
|
+
export const save = tool({
|
|
208
|
+
description: "Save a documentation file with mermaid diagrams to docs/. Auto-rebuilds the index.",
|
|
209
|
+
args: {
|
|
210
|
+
title: tool.schema
|
|
211
|
+
.string()
|
|
212
|
+
.describe("Document title (e.g., 'User Authentication System')"),
|
|
213
|
+
type: tool.schema
|
|
214
|
+
.enum(["decision", "feature", "flow"])
|
|
215
|
+
.describe("Document type: decision (ADR), feature (component docs), or flow (sequence/process)"),
|
|
216
|
+
content: tool.schema
|
|
217
|
+
.string()
|
|
218
|
+
.describe("Full markdown content including mermaid diagram blocks. Must follow the template structure for the chosen type."),
|
|
219
|
+
tags: tool.schema
|
|
220
|
+
.array(tool.schema.string())
|
|
221
|
+
.optional()
|
|
222
|
+
.describe("Tags for categorization (e.g., ['auth', 'security'])"),
|
|
223
|
+
relatedFiles: tool.schema
|
|
224
|
+
.array(tool.schema.string())
|
|
225
|
+
.optional()
|
|
226
|
+
.describe("Source files related to this document (e.g., ['src/auth.ts'])"),
|
|
227
|
+
},
|
|
228
|
+
async execute(args, context) {
|
|
229
|
+
const { title, type, content, tags, relatedFiles } = args;
|
|
230
|
+
const docsRoot = path.join(context.worktree, DOCS_DIR);
|
|
231
|
+
const folder = typeToFolder(type);
|
|
232
|
+
const folderPath = path.join(docsRoot, folder);
|
|
233
|
+
// Auto-init if docs/ doesn't exist
|
|
234
|
+
if (!fs.existsSync(folderPath)) {
|
|
235
|
+
ensureDocsDir(context.worktree);
|
|
236
|
+
}
|
|
237
|
+
const datePrefix = getDatePrefix();
|
|
238
|
+
const slug = slugify(title);
|
|
239
|
+
const filename = `${datePrefix}-${slug}.md`;
|
|
240
|
+
const filepath = path.join(folderPath, filename);
|
|
241
|
+
// Build the full document
|
|
242
|
+
const fullContent = buildDocument({
|
|
243
|
+
title,
|
|
244
|
+
type,
|
|
245
|
+
content,
|
|
246
|
+
tags,
|
|
247
|
+
relatedFiles,
|
|
248
|
+
});
|
|
249
|
+
fs.writeFileSync(filepath, fullContent);
|
|
250
|
+
// Auto-rebuild index
|
|
251
|
+
const indexResult = rebuildIndex(docsRoot);
|
|
252
|
+
return `✓ Documentation saved
|
|
253
|
+
|
|
254
|
+
File: ${folder}/${filename}
|
|
255
|
+
Path: ${filepath}
|
|
256
|
+
Type: ${type}
|
|
257
|
+
Tags: ${tags?.join(", ") || "none"}
|
|
258
|
+
Related files: ${relatedFiles?.length || 0}
|
|
259
|
+
|
|
260
|
+
${indexResult}`;
|
|
261
|
+
},
|
|
262
|
+
});
|
|
263
|
+
export const list = tool({
|
|
264
|
+
description: "List all documentation files in docs/",
|
|
265
|
+
args: {
|
|
266
|
+
type: tool.schema
|
|
267
|
+
.enum(["decision", "feature", "flow", "all"])
|
|
268
|
+
.optional()
|
|
269
|
+
.describe("Filter by document type (default: all)"),
|
|
270
|
+
},
|
|
271
|
+
async execute(args, context) {
|
|
272
|
+
const { type = "all" } = args;
|
|
273
|
+
const docsRoot = path.join(context.worktree, DOCS_DIR);
|
|
274
|
+
if (!fs.existsSync(docsRoot)) {
|
|
275
|
+
return `No docs/ directory found.
|
|
276
|
+
|
|
277
|
+
Run docs_init to set up the documentation folder structure.`;
|
|
278
|
+
}
|
|
279
|
+
const foldersToScan = type === "all" ? [...DOC_TYPES] : [typeToFolder(type)];
|
|
280
|
+
let output = "📚 Project Documentation:\n";
|
|
281
|
+
let totalCount = 0;
|
|
282
|
+
for (const folder of foldersToScan) {
|
|
283
|
+
const folderPath = path.join(docsRoot, folder);
|
|
284
|
+
if (!fs.existsSync(folderPath))
|
|
285
|
+
continue;
|
|
286
|
+
const files = fs
|
|
287
|
+
.readdirSync(folderPath)
|
|
288
|
+
.filter((f) => f.endsWith(".md") && f !== ".gitkeep")
|
|
289
|
+
.sort()
|
|
290
|
+
.reverse();
|
|
291
|
+
if (files.length === 0)
|
|
292
|
+
continue;
|
|
293
|
+
const icon = folder === "decisions" ? "📋" : folder === "features" ? "🚀" : "🔄";
|
|
294
|
+
output += `\n${icon} ${folder.charAt(0).toUpperCase() + folder.slice(1)} (${files.length}):\n\n`;
|
|
295
|
+
for (const file of files) {
|
|
296
|
+
const content = fs.readFileSync(path.join(folderPath, file), "utf-8");
|
|
297
|
+
const fm = parseFrontmatter(content);
|
|
298
|
+
const title = fm?.title || file;
|
|
299
|
+
const date = fm?.date ? fm.date.split("T")[0] : file.substring(0, 10);
|
|
300
|
+
const tags = fm?.tags && fm.tags.length > 0
|
|
301
|
+
? ` [${fm.tags.join(", ")}]`
|
|
302
|
+
: "";
|
|
303
|
+
const status = fm?.status ? ` (${fm.status})` : "";
|
|
304
|
+
output += ` • ${title}${status}${tags}\n`;
|
|
305
|
+
output += ` File: ${folder}/${file} | Date: ${date}\n\n`;
|
|
306
|
+
totalCount++;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
if (totalCount === 0) {
|
|
310
|
+
return `No documentation files found in docs/.
|
|
311
|
+
|
|
312
|
+
Use docs_save to create your first document, or docs_init to set up the folder structure.`;
|
|
313
|
+
}
|
|
314
|
+
output += `\nTotal: ${totalCount} documents. See docs/INDEX.md for the full index.`;
|
|
315
|
+
return output;
|
|
316
|
+
},
|
|
317
|
+
});
|
|
318
|
+
export const index = tool({
|
|
319
|
+
description: "Rebuild docs/INDEX.md with links to all documentation files. Called automatically by docs_save.",
|
|
320
|
+
args: {},
|
|
321
|
+
async execute(_args, context) {
|
|
322
|
+
const docsRoot = path.join(context.worktree, DOCS_DIR);
|
|
323
|
+
if (!fs.existsSync(docsRoot)) {
|
|
324
|
+
return `No docs/ directory found. Run docs_init first.`;
|
|
325
|
+
}
|
|
326
|
+
return rebuildIndex(docsRoot);
|
|
327
|
+
},
|
|
328
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export declare const finalize: {
|
|
2
|
+
description: string;
|
|
3
|
+
args: {
|
|
4
|
+
commitMessage: import("zod").ZodString;
|
|
5
|
+
prTitle: import("zod").ZodOptional<import("zod").ZodString>;
|
|
6
|
+
prBody: import("zod").ZodOptional<import("zod").ZodString>;
|
|
7
|
+
baseBranch: import("zod").ZodOptional<import("zod").ZodString>;
|
|
8
|
+
planFilename: import("zod").ZodOptional<import("zod").ZodString>;
|
|
9
|
+
draft: import("zod").ZodOptional<import("zod").ZodBoolean>;
|
|
10
|
+
};
|
|
11
|
+
execute(args: {
|
|
12
|
+
commitMessage: string;
|
|
13
|
+
prTitle?: string | undefined;
|
|
14
|
+
prBody?: string | undefined;
|
|
15
|
+
baseBranch?: string | undefined;
|
|
16
|
+
planFilename?: string | undefined;
|
|
17
|
+
draft?: boolean | undefined;
|
|
18
|
+
}, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=task.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task.d.ts","sourceRoot":"","sources":["../../src/tools/task.ts"],"names":[],"mappings":"AAyGA,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;CA0OnB,CAAC"}
|