@orderful/droid 0.48.0 → 0.51.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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +2 -1
- package/CHANGELOG.md +34 -0
- package/bun.lock +137 -3
- package/dist/bin/droid.js +355 -90
- package/dist/commands/pack.d.ts +5 -0
- package/dist/commands/pack.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/lib/pack.d.ts +31 -0
- package/dist/lib/pack.d.ts.map +1 -0
- package/dist/lib/types.d.ts +17 -0
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/tools/brain/.claude-plugin/plugin.json +1 -1
- package/dist/tools/brain/TOOL.yaml +3 -1
- package/dist/tools/brain/skills/brain/SKILL.md +4 -0
- package/dist/tools/brain/skills/brain/references/workflows.md +21 -7
- package/dist/tools/coach/TOOL.yaml +4 -0
- package/dist/tools/code-review/.claude-plugin/plugin.json +3 -2
- package/dist/tools/code-review/TOOL.yaml +4 -1
- package/dist/tools/code-review/agents/codex-context-researcher.md +99 -0
- package/dist/tools/code-review/skills/code-review/SKILL.md +20 -1
- package/dist/tools/codex/.claude-plugin/plugin.json +1 -1
- package/dist/tools/codex/TOOL.yaml +3 -1
- package/dist/tools/codex/skills/codex/SKILL.md +5 -1
- package/dist/tools/codex/skills/codex/scripts/normalize-frontmatter.d.ts +61 -0
- package/dist/tools/codex/skills/codex/scripts/normalize-frontmatter.d.ts.map +1 -0
- package/dist/tools/codex/skills/codex/scripts/normalize-frontmatter.ts +402 -0
- package/dist/tools/comments/TOOL.yaml +2 -0
- package/dist/tools/droid/.claude-plugin/plugin.json +1 -1
- package/dist/tools/droid/TOOL.yaml +3 -1
- package/dist/tools/droid/skills/droid/SKILL.md +48 -2
- package/dist/tools/droid/skills/droid/references/new-tool-workflow.md +234 -0
- package/dist/tools/edi-schema/TOOL.yaml +2 -0
- package/dist/tools/excalidraw/TOOL.yaml +2 -0
- package/dist/tools/meeting/TOOL.yaml +2 -0
- package/dist/tools/pii/TOOL.yaml +2 -0
- package/dist/tools/plan/.claude-plugin/plugin.json +1 -1
- package/dist/tools/plan/TOOL.yaml +5 -1
- package/dist/tools/plan/commands/plan.md +3 -2
- package/dist/tools/plan/skills/plan/SKILL.md +31 -10
- package/dist/tools/plan/skills/plan/references/workflows.md +44 -14
- package/dist/tools/project/.claude-plugin/plugin.json +1 -1
- package/dist/tools/project/TOOL.yaml +7 -1
- package/dist/tools/project/skills/project/SKILL.md +32 -1
- package/dist/tools/project/skills/project/references/loading.md +1 -0
- package/dist/tools/project/skills/project/references/pulling.md +57 -0
- package/dist/tools/project/skills/project/references/pushing.md +79 -0
- package/dist/tools/release/TOOL.yaml +2 -0
- package/dist/tools/share/TOOL.yaml +2 -0
- package/dist/tools/status-update/TOOL.yaml +4 -0
- package/dist/tools/tech-design/TOOL.yaml +2 -0
- package/dist/tools/wrapup/TOOL.yaml +2 -0
- package/package.json +3 -1
- package/scripts/build.ts +3 -2
- package/src/bin/droid.ts +9 -0
- package/src/commands/pack.ts +77 -0
- package/src/lib/pack.test.ts +85 -0
- package/src/lib/pack.ts +293 -0
- package/src/lib/types.ts +19 -0
- package/src/tools/brain/.claude-plugin/plugin.json +1 -1
- package/src/tools/brain/TOOL.yaml +3 -1
- package/src/tools/brain/skills/brain/SKILL.md +4 -0
- package/src/tools/brain/skills/brain/references/workflows.md +21 -7
- package/src/tools/coach/TOOL.yaml +4 -0
- package/src/tools/code-review/.claude-plugin/plugin.json +3 -2
- package/src/tools/code-review/TOOL.yaml +4 -1
- package/src/tools/code-review/agents/codex-context-researcher.md +99 -0
- package/src/tools/code-review/skills/code-review/SKILL.md +20 -1
- package/src/tools/codex/.claude-plugin/plugin.json +1 -1
- package/src/tools/codex/TOOL.yaml +3 -1
- package/src/tools/codex/skills/codex/SKILL.md +5 -1
- package/src/tools/codex/skills/codex/scripts/normalize-frontmatter.test.ts +331 -0
- package/src/tools/codex/skills/codex/scripts/normalize-frontmatter.ts +402 -0
- package/src/tools/comments/TOOL.yaml +2 -0
- package/src/tools/droid/.claude-plugin/plugin.json +1 -1
- package/src/tools/droid/TOOL.yaml +3 -1
- package/src/tools/droid/skills/droid/SKILL.md +48 -2
- package/src/tools/droid/skills/droid/references/new-tool-workflow.md +234 -0
- package/src/tools/edi-schema/TOOL.yaml +2 -0
- package/src/tools/excalidraw/TOOL.yaml +2 -0
- package/src/tools/meeting/TOOL.yaml +2 -0
- package/src/tools/pii/TOOL.yaml +2 -0
- package/src/tools/plan/.claude-plugin/plugin.json +1 -1
- package/src/tools/plan/TOOL.yaml +5 -1
- package/src/tools/plan/commands/plan.md +3 -2
- package/src/tools/plan/skills/plan/SKILL.md +31 -10
- package/src/tools/plan/skills/plan/references/workflows.md +44 -14
- package/src/tools/project/.claude-plugin/plugin.json +1 -1
- package/src/tools/project/TOOL.yaml +7 -1
- package/src/tools/project/skills/project/SKILL.md +32 -1
- package/src/tools/project/skills/project/references/loading.md +1 -0
- package/src/tools/project/skills/project/references/pulling.md +57 -0
- package/src/tools/project/skills/project/references/pushing.md +79 -0
- package/src/tools/release/TOOL.yaml +2 -0
- package/src/tools/share/TOOL.yaml +2 -0
- package/src/tools/status-update/TOOL.yaml +4 -0
- package/src/tools/tech-design/TOOL.yaml +2 -0
- package/src/tools/wrapup/TOOL.yaml +2 -0
- package/dist/tools/codex/skills/codex/scripts/git-scripts.test.ts +0 -364
- package/dist/tools/pii/skills/pii/scripts/presidio.test.ts +0 -444
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* codex normalize-frontmatter
|
|
4
|
+
*
|
|
5
|
+
* Normalizes YAML frontmatter format in codex markdown files to prevent
|
|
6
|
+
* unnecessary diffs from yaml.safe_dump() in the codex repo's fix-frontmatter
|
|
7
|
+
* workflow.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* droid config --get tools.codex | droid exec codex normalize-frontmatter --config -
|
|
11
|
+
*
|
|
12
|
+
* Options:
|
|
13
|
+
* --config <json> Config with codex_repo path (required)
|
|
14
|
+
* --all Process all .md files, not just uncommitted ones
|
|
15
|
+
*
|
|
16
|
+
* What it normalizes:
|
|
17
|
+
* - Flatten multiline scalars (>, |, >-, |-) into single-line quoted strings
|
|
18
|
+
* - Quote string values containing special characters (em dashes, colons, accents, @, arrows)
|
|
19
|
+
* - Consistent list indentation (- item, not - item under a key)
|
|
20
|
+
* - Unquote dates that are YYYY-MM-DD
|
|
21
|
+
*
|
|
22
|
+
* What it does NOT do:
|
|
23
|
+
* - Add missing required fields
|
|
24
|
+
* - Validate field values or enums
|
|
25
|
+
* - Reorder fields
|
|
26
|
+
*
|
|
27
|
+
* Output (JSON):
|
|
28
|
+
* { "success": true, "files_normalized": ["path/to/file.md"], "issues": [] }
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
import { execSync } from 'child_process';
|
|
32
|
+
import { readFileSync, writeFileSync, existsSync } from 'fs';
|
|
33
|
+
|
|
34
|
+
interface Config {
|
|
35
|
+
codex_repo: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
interface Result {
|
|
39
|
+
success: boolean;
|
|
40
|
+
files_normalized: string[];
|
|
41
|
+
issues: string[];
|
|
42
|
+
error?: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function parseArgs(args: string[]): { config: Config | null; all: boolean } {
|
|
46
|
+
let config: Config | null = null;
|
|
47
|
+
let all = false;
|
|
48
|
+
|
|
49
|
+
for (let i = 0; i < args.length; i++) {
|
|
50
|
+
const arg = args[i];
|
|
51
|
+
if (arg === '--config' && args[i + 1]) {
|
|
52
|
+
const configArg = args[++i];
|
|
53
|
+
if (configArg === '-') {
|
|
54
|
+
const stdin = readFileSync(0, 'utf-8').trim();
|
|
55
|
+
config = JSON.parse(stdin) as Config;
|
|
56
|
+
} else {
|
|
57
|
+
config = JSON.parse(configArg) as Config;
|
|
58
|
+
}
|
|
59
|
+
} else if (arg === '--all') {
|
|
60
|
+
all = true;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return { config, all };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function expandPath(p: string): string {
|
|
68
|
+
if (p.startsWith('~/')) {
|
|
69
|
+
return p.replace('~', process.env.HOME || '');
|
|
70
|
+
}
|
|
71
|
+
return p;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Characters that require quoting in YAML values.
|
|
76
|
+
* Matches: em dash, en dash, accented chars, @, arrows, leading/trailing spaces,
|
|
77
|
+
* colons followed by space, # preceded by space.
|
|
78
|
+
*/
|
|
79
|
+
const NEEDS_QUOTING = /[\u2013\u2014\u2018\u2019\u201c\u201d\u00e0-\u00ff\u0100-\u017f@\u2190-\u21ff\u2260]|:\s|^\s|\s$|\s#|^[{[]|[{}[\]],?$/;
|
|
80
|
+
|
|
81
|
+
/** Date pattern: YYYY-MM-DD */
|
|
82
|
+
const DATE_PATTERN = /^\d{4}-\d{2}-\d{2}$/;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Extract frontmatter block from markdown content.
|
|
86
|
+
* Returns the frontmatter lines (without delimiters) and the rest of the content.
|
|
87
|
+
*/
|
|
88
|
+
export function extractFrontmatter(content: string): {
|
|
89
|
+
frontmatter: string[] | null;
|
|
90
|
+
body: string;
|
|
91
|
+
} {
|
|
92
|
+
const lines = content.split('\n');
|
|
93
|
+
|
|
94
|
+
if (lines[0] !== '---') {
|
|
95
|
+
return { frontmatter: null, body: content };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
let endIndex = -1;
|
|
99
|
+
for (let i = 1; i < lines.length; i++) {
|
|
100
|
+
if (lines[i] === '---') {
|
|
101
|
+
endIndex = i;
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (endIndex === -1) {
|
|
107
|
+
return { frontmatter: null, body: content };
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return {
|
|
111
|
+
frontmatter: lines.slice(1, endIndex),
|
|
112
|
+
// Preserve everything after closing --- including the newline separator
|
|
113
|
+
body: '\n' + lines.slice(endIndex + 1).join('\n'),
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Check if a string value needs quoting for YAML safety.
|
|
119
|
+
*/
|
|
120
|
+
export function needsQuoting(value: string): boolean {
|
|
121
|
+
if (value === '' || value === 'true' || value === 'false' || value === 'null') return false;
|
|
122
|
+
if (DATE_PATTERN.test(value)) return false;
|
|
123
|
+
if (NEEDS_QUOTING.test(value)) return true;
|
|
124
|
+
// Values starting with special YAML chars
|
|
125
|
+
if (/^[*&!%>|'"]/.test(value)) return true;
|
|
126
|
+
// Values that look like numbers but shouldn't be
|
|
127
|
+
if (/^0\d/.test(value) && !/^0x/i.test(value)) return true;
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Quote a YAML string value using double quotes, escaping internal quotes.
|
|
133
|
+
*/
|
|
134
|
+
export function quoteValue(value: string): string {
|
|
135
|
+
// Already properly quoted
|
|
136
|
+
if ((value.startsWith('"') && value.endsWith('"')) ||
|
|
137
|
+
(value.startsWith("'") && value.endsWith("'"))) {
|
|
138
|
+
return value;
|
|
139
|
+
}
|
|
140
|
+
const escaped = value.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
141
|
+
return `"${escaped}"`;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Unquote a date value if it's YYYY-MM-DD wrapped in quotes.
|
|
146
|
+
*/
|
|
147
|
+
export function unquoteDate(value: string): string {
|
|
148
|
+
const inner = value.replace(/^["'](.*)["']$/, '$1');
|
|
149
|
+
if (DATE_PATTERN.test(inner)) {
|
|
150
|
+
return inner;
|
|
151
|
+
}
|
|
152
|
+
return value;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Normalize frontmatter lines using a line-by-line state machine.
|
|
157
|
+
* No YAML library used — that's the whole point.
|
|
158
|
+
*/
|
|
159
|
+
export function normalizeFrontmatter(lines: string[]): string[] {
|
|
160
|
+
const result: string[] = [];
|
|
161
|
+
let i = 0;
|
|
162
|
+
|
|
163
|
+
while (i < lines.length) {
|
|
164
|
+
const line = lines[i];
|
|
165
|
+
|
|
166
|
+
// Blank line — preserve
|
|
167
|
+
if (line.trim() === '') {
|
|
168
|
+
result.push(line);
|
|
169
|
+
i++;
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Comment line — preserve
|
|
174
|
+
if (line.trimStart().startsWith('#')) {
|
|
175
|
+
result.push(line);
|
|
176
|
+
i++;
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Key-value line: detect "key: value" or "key:" (for multiline/list)
|
|
181
|
+
const kvMatch = line.match(/^(\s*)([\w][\w.-]*)\s*:\s*(.*)$/);
|
|
182
|
+
if (!kvMatch) {
|
|
183
|
+
// List item at root or continuation — normalize indentation
|
|
184
|
+
const listMatch = line.match(/^(\s*)- (.*)$/);
|
|
185
|
+
if (listMatch) {
|
|
186
|
+
result.push(`${listMatch[1]}- ${normalizeScalarValue(listMatch[2])}`);
|
|
187
|
+
} else {
|
|
188
|
+
result.push(line);
|
|
189
|
+
}
|
|
190
|
+
i++;
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const [, indent, key, rawValue] = kvMatch;
|
|
195
|
+
|
|
196
|
+
// Case 1: Multiline scalar indicator (>, |, >-, |-)
|
|
197
|
+
if (/^[>|][-+]?\s*$/.test(rawValue)) {
|
|
198
|
+
// Collect continuation lines
|
|
199
|
+
const continuationLines: string[] = [];
|
|
200
|
+
const baseIndentLen = indent.length + 2; // standard YAML continuation indent
|
|
201
|
+
i++;
|
|
202
|
+
|
|
203
|
+
while (i < lines.length) {
|
|
204
|
+
const nextLine = lines[i];
|
|
205
|
+
// Empty line within multiline block
|
|
206
|
+
if (nextLine.trim() === '') {
|
|
207
|
+
continuationLines.push('');
|
|
208
|
+
i++;
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
// Check if indented beyond the key (continuation)
|
|
212
|
+
const nextIndent = nextLine.match(/^(\s*)/)?.[1].length ?? 0;
|
|
213
|
+
if (nextIndent >= baseIndentLen) {
|
|
214
|
+
continuationLines.push(nextLine.trim());
|
|
215
|
+
i++;
|
|
216
|
+
} else {
|
|
217
|
+
break;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Flatten into single-line value
|
|
222
|
+
const folded = rawValue.startsWith('|')
|
|
223
|
+
? continuationLines.join(' ') // literal: join with space for single-line
|
|
224
|
+
: continuationLines.filter(l => l !== '').join(' ');
|
|
225
|
+
|
|
226
|
+
const trimmed = folded.trim();
|
|
227
|
+
if (needsQuoting(trimmed)) {
|
|
228
|
+
result.push(`${indent}${key}: ${quoteValue(trimmed)}`);
|
|
229
|
+
} else {
|
|
230
|
+
result.push(`${indent}${key}: ${trimmed}`);
|
|
231
|
+
}
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Case 2: Key with no value — next lines are a list or nested map
|
|
236
|
+
if (rawValue === '') {
|
|
237
|
+
result.push(`${indent}${key}:`);
|
|
238
|
+
i++;
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Case 3: Regular key: value
|
|
243
|
+
let value = rawValue.trim();
|
|
244
|
+
|
|
245
|
+
// Unquote dates
|
|
246
|
+
value = unquoteDate(value);
|
|
247
|
+
|
|
248
|
+
// Quote values that need it (but aren't already quoted)
|
|
249
|
+
if (needsQuoting(value) && !((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'")))) {
|
|
250
|
+
value = quoteValue(value);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
result.push(`${indent}${key}: ${value}`);
|
|
254
|
+
i++;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return result;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Normalize a scalar value that appears in a list item or elsewhere.
|
|
262
|
+
*/
|
|
263
|
+
function normalizeScalarValue(value: string): string {
|
|
264
|
+
let v = unquoteDate(value.trim());
|
|
265
|
+
if (needsQuoting(v) && !((v.startsWith('"') && v.endsWith('"')) || (v.startsWith("'") && v.endsWith("'")))) {
|
|
266
|
+
v = quoteValue(v);
|
|
267
|
+
}
|
|
268
|
+
return v;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Normalize the frontmatter in a markdown file.
|
|
273
|
+
* Returns the normalized content, or null if no changes needed.
|
|
274
|
+
*/
|
|
275
|
+
export function normalizeFile(content: string): string | null {
|
|
276
|
+
const { frontmatter, body } = extractFrontmatter(content);
|
|
277
|
+
|
|
278
|
+
if (!frontmatter) {
|
|
279
|
+
return null; // No frontmatter to normalize
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
const normalized = normalizeFrontmatter(frontmatter);
|
|
283
|
+
|
|
284
|
+
// Check if anything changed
|
|
285
|
+
const originalBlock = frontmatter.join('\n');
|
|
286
|
+
const normalizedBlock = normalized.join('\n');
|
|
287
|
+
|
|
288
|
+
if (originalBlock === normalizedBlock) {
|
|
289
|
+
return null; // No changes needed
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
return `---\n${normalizedBlock}\n---${body}`;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Get list of markdown files with uncommitted changes.
|
|
297
|
+
*/
|
|
298
|
+
function getChangedFiles(cwd: string): string[] {
|
|
299
|
+
try {
|
|
300
|
+
// Both staged and unstaged changes, plus untracked files
|
|
301
|
+
const output = execSync(
|
|
302
|
+
'git diff --name-only HEAD 2>/dev/null; git diff --name-only --cached 2>/dev/null; git ls-files --others --exclude-standard 2>/dev/null',
|
|
303
|
+
{ cwd, encoding: 'utf-8' }
|
|
304
|
+
);
|
|
305
|
+
|
|
306
|
+
const files = output
|
|
307
|
+
.split('\n')
|
|
308
|
+
.map(f => f.trim())
|
|
309
|
+
.filter(f => f.endsWith('.md'))
|
|
310
|
+
.filter(f => f !== '')
|
|
311
|
+
// Deduplicate
|
|
312
|
+
.filter((f, i, arr) => arr.indexOf(f) === i);
|
|
313
|
+
|
|
314
|
+
return files;
|
|
315
|
+
} catch {
|
|
316
|
+
return [];
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Get all markdown files in the repo.
|
|
322
|
+
*/
|
|
323
|
+
function getAllMarkdownFiles(cwd: string): string[] {
|
|
324
|
+
try {
|
|
325
|
+
const output = execSync(
|
|
326
|
+
'git ls-files "*.md" 2>/dev/null',
|
|
327
|
+
{ cwd, encoding: 'utf-8' }
|
|
328
|
+
);
|
|
329
|
+
return output.split('\n').map(f => f.trim()).filter(f => f !== '');
|
|
330
|
+
} catch {
|
|
331
|
+
return [];
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// Main — only run when executed directly (not imported by tests)
|
|
336
|
+
export function main(): void {
|
|
337
|
+
const args = process.argv.slice(2);
|
|
338
|
+
const { config, all } = parseArgs(args);
|
|
339
|
+
|
|
340
|
+
if (!config) {
|
|
341
|
+
console.log(JSON.stringify({
|
|
342
|
+
success: false,
|
|
343
|
+
files_normalized: [],
|
|
344
|
+
issues: [],
|
|
345
|
+
error: 'Missing --config. Usage: droid config --get tools.codex | droid exec codex normalize-frontmatter --config -',
|
|
346
|
+
}));
|
|
347
|
+
process.exit(1);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
if (!config.codex_repo) {
|
|
351
|
+
console.log(JSON.stringify({
|
|
352
|
+
success: false,
|
|
353
|
+
files_normalized: [],
|
|
354
|
+
issues: [],
|
|
355
|
+
error: 'Missing codex_repo in config',
|
|
356
|
+
}));
|
|
357
|
+
process.exit(1);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
const cwd = expandPath(config.codex_repo);
|
|
361
|
+
|
|
362
|
+
if (!existsSync(cwd)) {
|
|
363
|
+
console.log(JSON.stringify({
|
|
364
|
+
success: false,
|
|
365
|
+
files_normalized: [],
|
|
366
|
+
issues: [],
|
|
367
|
+
error: `Codex repo not found at ${cwd}`,
|
|
368
|
+
}));
|
|
369
|
+
process.exit(1);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
const files = all ? getAllMarkdownFiles(cwd) : getChangedFiles(cwd);
|
|
373
|
+
const result: Result = {
|
|
374
|
+
success: true,
|
|
375
|
+
files_normalized: [],
|
|
376
|
+
issues: [],
|
|
377
|
+
};
|
|
378
|
+
|
|
379
|
+
for (const file of files) {
|
|
380
|
+
const fullPath = `${cwd}/${file}`;
|
|
381
|
+
try {
|
|
382
|
+
if (!existsSync(fullPath)) continue;
|
|
383
|
+
|
|
384
|
+
const content = readFileSync(fullPath, 'utf-8');
|
|
385
|
+
const normalized = normalizeFile(content);
|
|
386
|
+
|
|
387
|
+
if (normalized !== null) {
|
|
388
|
+
writeFileSync(fullPath, normalized, 'utf-8');
|
|
389
|
+
result.files_normalized.push(file);
|
|
390
|
+
}
|
|
391
|
+
} catch (err: unknown) {
|
|
392
|
+
const error = err as { message?: string };
|
|
393
|
+
result.issues.push(`${file}: ${error.message || 'Unknown error'}`);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
console.log(JSON.stringify(result, null, 2));
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
if (import.meta.main) {
|
|
401
|
+
main();
|
|
402
|
+
}
|
|
@@ -2,6 +2,8 @@ name: comments
|
|
|
2
2
|
description: "Enable inline conversations using @droid/@user markers. Tag @droid to ask the AI, AI responds with @{your-name}. Use /comments check to address markers, /comments cleanup to remove resolved threads. Ideal for code review notes and async collaboration."
|
|
3
3
|
version: 0.3.7
|
|
4
4
|
status: beta
|
|
5
|
+
audience:
|
|
6
|
+
- all
|
|
5
7
|
|
|
6
8
|
includes:
|
|
7
9
|
skills:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "droid",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.2",
|
|
4
4
|
"description": "Core droid meta-skill for update awareness, tool discovery, and usage help. Checks for updates, helps users find tools, and answers 'how do I...' questions about droid workflows.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Orderful",
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
name: droid
|
|
2
2
|
description: "Core droid meta-skill for update awareness, tool discovery, and usage help. Checks for updates, helps users find tools, and answers 'how do I...' questions about droid workflows."
|
|
3
|
-
version: 0.7.
|
|
3
|
+
version: 0.7.2
|
|
4
4
|
status: beta
|
|
5
|
+
audience:
|
|
6
|
+
- engineering
|
|
5
7
|
|
|
6
8
|
# System tool - always stays current regardless of auto-update settings
|
|
7
9
|
system: true
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: droid
|
|
3
|
-
description: "Core droid meta-skill for updates, tool discovery, usage help, and skill
|
|
3
|
+
description: "Core droid meta-skill for updates, tool discovery, usage help, skill overrides, and skill review. Use when checking for droid updates, discovering available tools, answering 'how do I...' questions about droid workflows, customizing skill behaviour, or reviewing a contributed skill. User prompts like 'any droid updates?', 'what tools do I have?', 'what tools do you have?', 'remind me what tools you have', 'hey droid what can you do', 'how do I add context?', 'remind me how to use codex', 'what's the best way to start a session?', 'customize brain search', 'create an override for brain', 'review this skill', 'droid review ./my-skill'."
|
|
4
4
|
alwaysApply: true
|
|
5
|
-
allowed-tools: [Bash, Read, Write]
|
|
5
|
+
allowed-tools: [Bash, Read, Write, Glob, Grep]
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Droid
|
|
@@ -69,6 +69,7 @@ cat ~/.droid/config.yaml
|
|
|
69
69
|
| Review code | `/code-review` |
|
|
70
70
|
| Capture a decision | `/codex decision {summary}` |
|
|
71
71
|
| Update project context | `/project update` |
|
|
72
|
+
| Create a new droid tool | `/droid new {name}` or `/droid new {name} --from {path}` |
|
|
72
73
|
|
|
73
74
|
## Response Guidelines
|
|
74
75
|
|
|
@@ -89,6 +90,51 @@ When answering "how do I..." questions:
|
|
|
89
90
|
2. `/codex search {topic}` - Find relevant org knowledge (if needed)
|
|
90
91
|
3. Then start working with full context
|
|
91
92
|
|
|
93
|
+
## New Tool
|
|
94
|
+
|
|
95
|
+
Create a new droid tool, optionally starting from an existing skill/agent file. The droid skill for contributing to droid.
|
|
96
|
+
|
|
97
|
+
**When:** User says `/droid new {tool-name}` or `/droid new {tool-name} --from {path}`
|
|
98
|
+
|
|
99
|
+
**Usage:**
|
|
100
|
+
```
|
|
101
|
+
/droid new {tool-name} # scaffold from scratch
|
|
102
|
+
/droid new {tool-name} --from path/to/file # import with explicit path
|
|
103
|
+
/droid new {tool-name} path/to/file # same — path detected as import source
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Accepts `.skill`, `.zip`, `.md` files, or directories. Users can also just drop a file into the chat after running `/droid new {tool-name}` and it will be picked up as the import source.
|
|
107
|
+
|
|
108
|
+
**Flow:**
|
|
109
|
+
|
|
110
|
+
1. **Import** (if `--from` provided) — Determine input type:
|
|
111
|
+
- `.skill` or `.zip` → extract to temp directory, locate SKILL.md or agent .md inside
|
|
112
|
+
- Directory → use directly
|
|
113
|
+
- Single `.md` file → determine if it's a skill (has frontmatter with `name`/`description`) or an agent
|
|
114
|
+
- No `--from` → scaffold blank SKILL.md from template
|
|
115
|
+
2. **Transform** — Massage imported content to droid standards:
|
|
116
|
+
- Multiline YAML descriptions (`>`, `>-`, `|`) → rewrite as single-line quoted string
|
|
117
|
+
- Missing `allowed-tools` → analyse content for tool usage, add appropriate list
|
|
118
|
+
- Description missing "Use when" / "User prompts like" pattern → rewrite to match
|
|
119
|
+
- `name` not kebab-case → fix it
|
|
120
|
+
- Add missing frontmatter fields (`globs: []`, `alwaysApply: false`)
|
|
121
|
+
3. **Security scan** — Flag issues. High-severity (prompt injection patterns, encoded content) blocks. Medium-severity (Bash without justification, external URLs) requires acknowledgement.
|
|
122
|
+
4. **Collect metadata** — Always ask for `audience`. Confirm tool name and description.
|
|
123
|
+
5. **Scaffold tool** — Create the full tool structure in `src/tools/{tool-name}/`:
|
|
124
|
+
- `TOOL.yaml` with name, description, version `0.1.0`, status `beta`, audience
|
|
125
|
+
- `skills/{skill-name}/SKILL.md` (+ `references/` if present)
|
|
126
|
+
- `agents/{agent-name}.md` if importing an agent
|
|
127
|
+
- Add changeset: `.changeset/{tool-name}-initial.md`
|
|
128
|
+
6. **Open PR** — Create branch `contrib/{tool-name}`, commit, push, open PR.
|
|
129
|
+
|
|
130
|
+
Present a summary with droid eyes `[● ●]` showing what was imported/transformed and what needs input. See `references/new-tool-workflow.md` for detailed validation rules, security patterns, and PR template.
|
|
131
|
+
|
|
132
|
+
**Key rules:**
|
|
133
|
+
- Fix what can be fixed automatically (formatting, frontmatter, descriptions)
|
|
134
|
+
- Only block on things that need human judgement (security, audience)
|
|
135
|
+
- New tools start at version `0.1.0` with status `beta`
|
|
136
|
+
- Always create a changeset with package name `"@orderful/droid"`
|
|
137
|
+
|
|
92
138
|
## Skill Overrides
|
|
93
139
|
|
|
94
140
|
Users can customize skill behaviour by creating override files in `~/.droid/skill_overrides/`.
|