daedalion 0.0.1 → 0.1.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/README.md +20 -5
- package/bin/daedalion.js +12 -5
- package/dist/commands/build.d.ts +3 -0
- package/dist/commands/build.d.ts.map +1 -0
- package/dist/commands/build.js +167 -0
- package/dist/commands/build.js.map +1 -0
- package/dist/commands/clean.d.ts +2 -0
- package/dist/commands/clean.d.ts.map +1 -0
- package/dist/commands/clean.js +106 -0
- package/dist/commands/clean.js.map +1 -0
- package/dist/commands/init.d.ts +3 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +83 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/validate.d.ts +2 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/validate.js +119 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/config.d.ts +5 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +101 -0
- package/dist/config.js.map +1 -0
- package/dist/generators/agent.d.ts +3 -0
- package/dist/generators/agent.d.ts.map +1 -0
- package/dist/generators/agent.js +105 -0
- package/dist/generators/agent.js.map +1 -0
- package/dist/generators/instructions.d.ts +3 -0
- package/dist/generators/instructions.d.ts.map +1 -0
- package/{src → dist}/generators/instructions.js +42 -52
- package/dist/generators/instructions.js.map +1 -0
- package/dist/generators/prompt.d.ts +4 -0
- package/dist/generators/prompt.d.ts.map +1 -0
- package/{src → dist}/generators/prompt.js +96 -102
- package/dist/generators/prompt.js.map +1 -0
- package/dist/generators/skill.d.ts +3 -0
- package/dist/generators/skill.d.ts.map +1 -0
- package/dist/generators/skill.js +89 -0
- package/dist/generators/skill.js.map +1 -0
- package/dist/generators/tools.d.ts +3 -0
- package/dist/generators/tools.d.ts.map +1 -0
- package/dist/generators/tools.js +192 -0
- package/dist/generators/tools.js.map +1 -0
- package/dist/generators/workflow.d.ts +3 -0
- package/dist/generators/workflow.d.ts.map +1 -0
- package/{src → dist}/generators/workflow.js +47 -53
- package/dist/generators/workflow.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/{src → dist}/index.js +1 -0
- package/dist/index.js.map +1 -0
- package/dist/parsers/proposal.d.ts +3 -0
- package/dist/parsers/proposal.d.ts.map +1 -0
- package/dist/parsers/proposal.js +45 -0
- package/dist/parsers/proposal.js.map +1 -0
- package/dist/parsers/spec.d.ts +3 -0
- package/dist/parsers/spec.d.ts.map +1 -0
- package/dist/parsers/spec.js +87 -0
- package/dist/parsers/spec.js.map +1 -0
- package/dist/parsers/tasks.d.ts +4 -0
- package/dist/parsers/tasks.d.ts.map +1 -0
- package/dist/parsers/tasks.js +39 -0
- package/dist/parsers/tasks.js.map +1 -0
- package/dist/types.d.ts +107 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +5 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +46 -0
- package/dist/utils.js.map +1 -0
- package/dist/version.d.ts +3 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +47 -0
- package/dist/version.js.map +1 -0
- package/package.json +18 -3
- package/src/commands/build.js +0 -198
- package/src/commands/clean.js +0 -85
- package/src/commands/init.js +0 -88
- package/src/commands/validate.js +0 -141
- package/src/config.js +0 -50
- package/src/generators/agent.js +0 -121
- package/src/generators/skill.js +0 -105
- package/src/generators/tools.js +0 -183
- package/src/parsers/proposal.js +0 -52
- package/src/parsers/spec.js +0 -105
- package/src/parsers/tasks.js +0 -46
- package/src/utils.js +0 -51
- package/src/version.js +0 -60
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { readFileSync, existsSync } from 'fs';
|
|
2
|
+
export function parseTasks(tasksPath, maxItems = 10) {
|
|
3
|
+
if (!existsSync(tasksPath)) {
|
|
4
|
+
return { groups: [], items: [], hasMore: false };
|
|
5
|
+
}
|
|
6
|
+
const content = readFileSync(tasksPath, 'utf-8');
|
|
7
|
+
return summarizeTasks(content, maxItems);
|
|
8
|
+
}
|
|
9
|
+
export function summarizeTasks(content, maxItems = 10) {
|
|
10
|
+
const lines = content.split('\n');
|
|
11
|
+
const groups = [];
|
|
12
|
+
const items = [];
|
|
13
|
+
let currentGroup = null;
|
|
14
|
+
let totalItems = 0;
|
|
15
|
+
for (const line of lines) {
|
|
16
|
+
const headingMatch = line.match(/^(#{1,3})\s+(.+)$/);
|
|
17
|
+
if (headingMatch) {
|
|
18
|
+
currentGroup = headingMatch[2].trim();
|
|
19
|
+
if (!groups.includes(currentGroup)) {
|
|
20
|
+
groups.push(currentGroup);
|
|
21
|
+
}
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
const taskMatch = line.match(/^-\s+(\[[ x]\])?\s*(.+)$/);
|
|
25
|
+
if (taskMatch && !line.match(/^\s{2,}-/)) {
|
|
26
|
+
totalItems++;
|
|
27
|
+
if (items.length < maxItems) {
|
|
28
|
+
const taskText = taskMatch[2].trim();
|
|
29
|
+
items.push(taskText);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
groups,
|
|
35
|
+
items,
|
|
36
|
+
hasMore: totalItems > maxItems
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=tasks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tasks.js","sourceRoot":"","sources":["../../src/parsers/tasks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAG9C,MAAM,UAAU,UAAU,CAAC,SAAiB,EAAE,WAAmB,EAAE;IACjE,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC3B,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IACnD,CAAC;IAED,MAAM,OAAO,GAAW,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IACzD,OAAO,cAAc,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,OAAe,EAAE,WAAmB,EAAE;IACnE,MAAM,KAAK,GAAa,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC5C,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,YAAY,GAAkB,IAAI,CAAC;IACvC,IAAI,UAAU,GAAW,CAAC,CAAC;IAE3B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,YAAY,GAA4B,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;QAC9E,IAAI,YAAY,EAAE,CAAC;YACjB,YAAY,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YACtC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;gBACnC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YAC5B,CAAC;YACD,SAAS;QACX,CAAC;QAED,MAAM,SAAS,GAA4B,IAAI,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;QAClF,IAAI,SAAS,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC;YACzC,UAAU,EAAE,CAAC;YACb,IAAI,KAAK,CAAC,MAAM,GAAG,QAAQ,EAAE,CAAC;gBAC5B,MAAM,QAAQ,GAAW,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;gBAC7C,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACvB,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO;QACL,MAAM;QACN,KAAK;QACL,OAAO,EAAE,UAAU,GAAG,QAAQ;KAC/B,CAAC;AACJ,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/** Result returned by every generator */
|
|
2
|
+
export interface GeneratedFile {
|
|
3
|
+
path: string;
|
|
4
|
+
content: string;
|
|
5
|
+
}
|
|
6
|
+
/** Common options passed through commands and generators */
|
|
7
|
+
export interface BuildOptions {
|
|
8
|
+
dryRun?: boolean;
|
|
9
|
+
verbose?: boolean;
|
|
10
|
+
force?: boolean;
|
|
11
|
+
withTools?: boolean;
|
|
12
|
+
}
|
|
13
|
+
/** Init command options */
|
|
14
|
+
export interface InitOptions {
|
|
15
|
+
agentTarget?: string;
|
|
16
|
+
withExample?: boolean;
|
|
17
|
+
target?: string;
|
|
18
|
+
}
|
|
19
|
+
/** Parsed spec from openspec/specs/{domain}/spec.md */
|
|
20
|
+
export interface Spec {
|
|
21
|
+
path: string;
|
|
22
|
+
domain: string;
|
|
23
|
+
title: string;
|
|
24
|
+
frontmatter: Record<string, unknown>;
|
|
25
|
+
requirements: Requirement[];
|
|
26
|
+
}
|
|
27
|
+
export interface Requirement {
|
|
28
|
+
name: string;
|
|
29
|
+
description: string;
|
|
30
|
+
scenarios: Scenario[];
|
|
31
|
+
}
|
|
32
|
+
export interface Scenario {
|
|
33
|
+
name: string;
|
|
34
|
+
steps: string[];
|
|
35
|
+
}
|
|
36
|
+
/** Parsed proposal from openspec/changes/{change}/proposal.md */
|
|
37
|
+
export interface Proposal {
|
|
38
|
+
path: string;
|
|
39
|
+
changeName: string;
|
|
40
|
+
title: string;
|
|
41
|
+
frontmatter: Record<string, unknown>;
|
|
42
|
+
why: string | null;
|
|
43
|
+
what: string | null;
|
|
44
|
+
}
|
|
45
|
+
/** Parsed task list from openspec/changes/{change}/tasks.md */
|
|
46
|
+
export interface TasksSummary {
|
|
47
|
+
groups: string[];
|
|
48
|
+
items: string[];
|
|
49
|
+
hasMore: boolean;
|
|
50
|
+
}
|
|
51
|
+
/** Tool definition from spec frontmatter */
|
|
52
|
+
export interface ToolDef {
|
|
53
|
+
name: string;
|
|
54
|
+
description?: string;
|
|
55
|
+
inputs?: ToolInput[];
|
|
56
|
+
outputs?: ToolOutput[];
|
|
57
|
+
requirements?: (string | number)[];
|
|
58
|
+
language?: string;
|
|
59
|
+
}
|
|
60
|
+
export interface ToolInput {
|
|
61
|
+
name: string;
|
|
62
|
+
type?: string;
|
|
63
|
+
description?: string;
|
|
64
|
+
}
|
|
65
|
+
export interface ToolOutput {
|
|
66
|
+
type?: string;
|
|
67
|
+
}
|
|
68
|
+
/** daedalion.yaml configuration */
|
|
69
|
+
export interface DaedalionConfig {
|
|
70
|
+
version: number;
|
|
71
|
+
target: string;
|
|
72
|
+
openspec: string;
|
|
73
|
+
output: string;
|
|
74
|
+
ci: {
|
|
75
|
+
auto_commit: boolean;
|
|
76
|
+
commit_message: string;
|
|
77
|
+
};
|
|
78
|
+
agents: {
|
|
79
|
+
target: 'ide' | 'sdk';
|
|
80
|
+
tools: string[] | null;
|
|
81
|
+
};
|
|
82
|
+
tools?: {
|
|
83
|
+
language?: string;
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
/** Manifest written by build, read by clean */
|
|
87
|
+
export interface Manifest {
|
|
88
|
+
version: number;
|
|
89
|
+
generatedAt: string;
|
|
90
|
+
files: string[];
|
|
91
|
+
}
|
|
92
|
+
/** Validation error */
|
|
93
|
+
export interface ValidationError {
|
|
94
|
+
rule: string;
|
|
95
|
+
message: string;
|
|
96
|
+
}
|
|
97
|
+
/** Change parsed from openspec/changes/{change}/ */
|
|
98
|
+
export interface ParsedChange {
|
|
99
|
+
proposal: Proposal;
|
|
100
|
+
tasks: TasksSummary;
|
|
101
|
+
}
|
|
102
|
+
/** Validate-only change reference */
|
|
103
|
+
export interface ChangeReference {
|
|
104
|
+
changeName: string;
|
|
105
|
+
path: string;
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare function ensureDir(filePath: string): void;
|
|
2
|
+
export declare function extractFirstHeading(content: string): string | null;
|
|
3
|
+
export declare function extractDescription(content: string): string | null;
|
|
4
|
+
export declare function slugify(text: string): string;
|
|
5
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAGA,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAKhD;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGlE;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA4BjE;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAK5C"}
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { mkdirSync, existsSync } from 'fs';
|
|
2
|
+
import { dirname } from 'path';
|
|
3
|
+
export function ensureDir(filePath) {
|
|
4
|
+
const dir = dirname(filePath);
|
|
5
|
+
if (!existsSync(dir)) {
|
|
6
|
+
mkdirSync(dir, { recursive: true });
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
export function extractFirstHeading(content) {
|
|
10
|
+
const match = content.match(/^#\s+(.+)$/m);
|
|
11
|
+
return match ? match[1].trim() : null;
|
|
12
|
+
}
|
|
13
|
+
export function extractDescription(content) {
|
|
14
|
+
const lines = content.split('\n');
|
|
15
|
+
let inFrontmatter = false;
|
|
16
|
+
const description = [];
|
|
17
|
+
for (const line of lines) {
|
|
18
|
+
if (line.trim() === '---') {
|
|
19
|
+
if (inFrontmatter) {
|
|
20
|
+
inFrontmatter = false;
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
inFrontmatter = true;
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
if (inFrontmatter)
|
|
27
|
+
continue;
|
|
28
|
+
if (line.startsWith('#'))
|
|
29
|
+
continue;
|
|
30
|
+
if (line.trim() && !line.startsWith('##')) {
|
|
31
|
+
description.push(line.trim());
|
|
32
|
+
if (description.length >= 2)
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
if (line.startsWith('##'))
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
return description.join(' ').slice(0, 200) || null;
|
|
39
|
+
}
|
|
40
|
+
export function slugify(text) {
|
|
41
|
+
return text
|
|
42
|
+
.toLowerCase()
|
|
43
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
44
|
+
.replace(/^-|-$/g, '');
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAE/B,MAAM,UAAU,SAAS,CAAC,QAAgB;IACxC,MAAM,GAAG,GAAW,OAAO,CAAC,QAAQ,CAAC,CAAC;IACtC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACrB,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACtC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,OAAe;IACjD,MAAM,KAAK,GAA4B,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;IACpE,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,OAAe;IAChD,MAAM,KAAK,GAAa,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC5C,IAAI,aAAa,GAAY,KAAK,CAAC;IACnC,MAAM,WAAW,GAAa,EAAE,CAAC;IAEjC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,KAAK,EAAE,CAAC;YAC1B,IAAI,aAAa,EAAE,CAAC;gBAClB,aAAa,GAAG,KAAK,CAAC;gBACtB,SAAS;YACX,CAAC;YACD,aAAa,GAAG,IAAI,CAAC;YACrB,SAAS;QACX,CAAC;QAED,IAAI,aAAa;YAAE,SAAS;QAE5B,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAS;QAEnC,IAAI,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YAC1C,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;YAC9B,IAAI,WAAW,CAAC,MAAM,IAAI,CAAC;gBAAE,MAAM;QACrC,CAAC;QAED,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,MAAM;IACnC,CAAC;IAED,OAAO,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC;AACrD,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,IAAY;IAClC,OAAO,IAAI;SACR,WAAW,EAAE;SACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;SAC3B,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;AAC3B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAUA,eAAO,MAAM,OAAO,EAAE,MAAoB,CAAC;AAE3C,wBAAgB,gBAAgB,IAAI,MAAM,CAMzC"}
|
package/dist/version.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { execSync } from 'child_process';
|
|
2
|
+
import { readFileSync } from 'fs';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
import { dirname, join } from 'path';
|
|
5
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
6
|
+
const __dirname = dirname(__filename);
|
|
7
|
+
// Read version from package.json
|
|
8
|
+
const pkg = JSON.parse(readFileSync(join(__dirname, '../package.json'), 'utf-8'));
|
|
9
|
+
export const VERSION = pkg.version;
|
|
10
|
+
export function getVersionString() {
|
|
11
|
+
const commitHash = getCommitHash();
|
|
12
|
+
if (commitHash && !isReleaseBuild()) {
|
|
13
|
+
return `${VERSION}-dev+${commitHash}`;
|
|
14
|
+
}
|
|
15
|
+
return VERSION;
|
|
16
|
+
}
|
|
17
|
+
function getCommitHash() {
|
|
18
|
+
try {
|
|
19
|
+
return execSync('git rev-parse --short HEAD', {
|
|
20
|
+
encoding: 'utf-8',
|
|
21
|
+
stdio: ['pipe', 'pipe', 'ignore'],
|
|
22
|
+
timeout: 5000,
|
|
23
|
+
windowsHide: true
|
|
24
|
+
}).trim();
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function isReleaseBuild() {
|
|
31
|
+
if (__dirname.includes('node_modules')) {
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
execSync('git describe --exact-match --tags HEAD', {
|
|
36
|
+
encoding: 'utf-8',
|
|
37
|
+
stdio: ['pipe', 'pipe', 'ignore'],
|
|
38
|
+
timeout: 5000,
|
|
39
|
+
windowsHide: true
|
|
40
|
+
});
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=version.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAErC,MAAM,UAAU,GAAW,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC1D,MAAM,SAAS,GAAW,OAAO,CAAC,UAAU,CAAC,CAAC;AAE9C,iCAAiC;AACjC,MAAM,GAAG,GAAwB,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,iBAAiB,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;AACvG,MAAM,CAAC,MAAM,OAAO,GAAW,GAAG,CAAC,OAAO,CAAC;AAE3C,MAAM,UAAU,gBAAgB;IAC9B,MAAM,UAAU,GAAkB,aAAa,EAAE,CAAC;IAClD,IAAI,UAAU,IAAI,CAAC,cAAc,EAAE,EAAE,CAAC;QACpC,OAAO,GAAG,OAAO,QAAQ,UAAU,EAAE,CAAC;IACxC,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,aAAa;IACpB,IAAI,CAAC;QACH,OAAO,QAAQ,CAAC,4BAA4B,EAAE;YAC5C,QAAQ,EAAE,OAAO;YACjB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC;YACjC,OAAO,EAAE,IAAI;YACb,WAAW,EAAE,IAAI;SAClB,CAAC,CAAC,IAAI,EAAE,CAAC;IACZ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,cAAc;IACrB,IAAI,SAAS,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;QACvC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC;QACH,QAAQ,CAAC,wCAAwC,EAAE;YACjD,QAAQ,EAAE,OAAO;YACjB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC;YACjC,OAAO,EAAE,IAAI;YACb,WAAW,EAAE,IAAI;SAClB,CAAC,CAAC;QACH,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "daedalion",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "OpenSpec-to-Agent compiler for GitHub Copilot",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
5
13
|
"bin": {
|
|
6
14
|
"daedalion": "./bin/daedalion.js"
|
|
7
15
|
},
|
|
8
16
|
"files": [
|
|
9
17
|
"bin/",
|
|
10
|
-
"
|
|
18
|
+
"dist/",
|
|
11
19
|
"templates/"
|
|
12
20
|
],
|
|
13
21
|
"type": "module",
|
|
@@ -15,9 +23,13 @@
|
|
|
15
23
|
"node": ">=20"
|
|
16
24
|
},
|
|
17
25
|
"scripts": {
|
|
26
|
+
"build": "tsc",
|
|
27
|
+
"dev": "tsx src/index.ts",
|
|
18
28
|
"test": "vitest run",
|
|
19
29
|
"test:watch": "vitest",
|
|
20
|
-
"test:coverage": "vitest run --coverage"
|
|
30
|
+
"test:coverage": "vitest run --coverage",
|
|
31
|
+
"prepublishOnly": "npm run build && npm test",
|
|
32
|
+
"typecheck": "tsc --noEmit"
|
|
21
33
|
},
|
|
22
34
|
"keywords": [
|
|
23
35
|
"openspec",
|
|
@@ -36,6 +48,9 @@
|
|
|
36
48
|
"yaml": "^2.3.0"
|
|
37
49
|
},
|
|
38
50
|
"devDependencies": {
|
|
51
|
+
"@types/node": "^25.3.0",
|
|
52
|
+
"tsx": "^4.21.0",
|
|
53
|
+
"typescript": "^5.9.3",
|
|
39
54
|
"vitest": "^1.0.0"
|
|
40
55
|
}
|
|
41
56
|
}
|
package/src/commands/build.js
DELETED
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
import { existsSync, readdirSync, statSync, writeFileSync } from 'fs';
|
|
2
|
-
import { join, relative } from 'path';
|
|
3
|
-
import chalk from 'chalk';
|
|
4
|
-
import { VERSION } from '../version.js';
|
|
5
|
-
import { glob } from 'glob';
|
|
6
|
-
import { loadConfig, resolveOpenspecPath, resolveOutputPath } from '../config.js';
|
|
7
|
-
import { parseSpec } from '../parsers/spec.js';
|
|
8
|
-
import { parseProposal } from '../parsers/proposal.js';
|
|
9
|
-
import { parseTasks } from '../parsers/tasks.js';
|
|
10
|
-
import { generateSkill } from '../generators/skill.js';
|
|
11
|
-
import { generateAgent } from '../generators/agent.js';
|
|
12
|
-
import { generatePrompt, generateCyclePrompt } from '../generators/prompt.js';
|
|
13
|
-
import { generateWorkflow } from '../generators/workflow.js';
|
|
14
|
-
import { generateInstructions } from '../generators/instructions.js';
|
|
15
|
-
import { generateTools } from '../generators/tools.js';
|
|
16
|
-
import { ensureDir } from '../utils.js';
|
|
17
|
-
|
|
18
|
-
const MANIFEST_FILENAME = '.daedalion-manifest.json';
|
|
19
|
-
|
|
20
|
-
export async function build(cwd, options = {}) {
|
|
21
|
-
console.log();
|
|
22
|
-
console.log(chalk.bold(` Daedalion v${VERSION}`));
|
|
23
|
-
console.log();
|
|
24
|
-
|
|
25
|
-
const config = loadConfig(cwd);
|
|
26
|
-
const openspecDir = resolveOpenspecPath(cwd, config);
|
|
27
|
-
const outputDir = resolveOutputPath(cwd, config);
|
|
28
|
-
|
|
29
|
-
if (!existsSync(openspecDir)) {
|
|
30
|
-
throw new Error(`OpenSpec directory not found: ${openspecDir}\n Run 'daedalion init' first.`);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const generatedFiles = [];
|
|
34
|
-
|
|
35
|
-
// Parse specs
|
|
36
|
-
console.log(' Parsing specs...');
|
|
37
|
-
const specs = await findAndParseSpecs(openspecDir, options);
|
|
38
|
-
for (const spec of specs) {
|
|
39
|
-
console.log(chalk.gray(` ✓ ${relative(cwd, spec.path)}`));
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// Parse changes
|
|
43
|
-
console.log();
|
|
44
|
-
console.log(' Parsing changes...');
|
|
45
|
-
const changes = await findAndParseChanges(openspecDir, options);
|
|
46
|
-
for (const change of changes) {
|
|
47
|
-
console.log(chalk.gray(` ✓ ${relative(cwd, change.proposal.path)}`));
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// Aggregate tasks from all changes for skills
|
|
51
|
-
const allTasks = aggregateTasks(changes);
|
|
52
|
-
|
|
53
|
-
// Generate outputs
|
|
54
|
-
console.log();
|
|
55
|
-
console.log(' Generating...');
|
|
56
|
-
|
|
57
|
-
// Generate skills and agents from specs
|
|
58
|
-
for (const spec of specs) {
|
|
59
|
-
const tasks = allTasks[spec.domain] || null;
|
|
60
|
-
const skillResult = generateSkill(spec, tasks, outputDir, options);
|
|
61
|
-
generatedFiles.push(skillResult);
|
|
62
|
-
logGenerated(skillResult.path, cwd, options);
|
|
63
|
-
|
|
64
|
-
const agentResult = generateAgent(spec, outputDir, options, config);
|
|
65
|
-
generatedFiles.push(agentResult);
|
|
66
|
-
logGenerated(agentResult.path, cwd, options);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Generate tool stubs if --with-tools flag is set
|
|
70
|
-
if (options.withTools) {
|
|
71
|
-
console.log(chalk.gray(` (generating tool stubs)`));
|
|
72
|
-
for (const spec of specs) {
|
|
73
|
-
const toolResults = generateTools(spec, outputDir, config, options);
|
|
74
|
-
for (const toolResult of toolResults) {
|
|
75
|
-
generatedFiles.push(toolResult);
|
|
76
|
-
logGenerated(toolResult.path, cwd, options);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Generate prompts from changes
|
|
82
|
-
for (const change of changes) {
|
|
83
|
-
const domain = findDomainForChange(change, specs);
|
|
84
|
-
const promptResult = generatePrompt(change.proposal, change.tasks, domain, outputDir, options);
|
|
85
|
-
generatedFiles.push(promptResult);
|
|
86
|
-
logGenerated(promptResult.path, cwd, options);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// Generate OpenSpec cycle prompt
|
|
90
|
-
const cyclePromptResult = generateCyclePrompt(outputDir, options);
|
|
91
|
-
generatedFiles.push(cyclePromptResult);
|
|
92
|
-
logGenerated(cyclePromptResult.path, cwd, options);
|
|
93
|
-
|
|
94
|
-
// Generate workflow
|
|
95
|
-
const workflowResult = generateWorkflow(config, outputDir, options);
|
|
96
|
-
generatedFiles.push(workflowResult);
|
|
97
|
-
logGenerated(workflowResult.path, cwd, options);
|
|
98
|
-
|
|
99
|
-
// Generate copilot-instructions.md
|
|
100
|
-
const instructionsResult = generateInstructions(openspecDir, outputDir, options);
|
|
101
|
-
generatedFiles.push(instructionsResult);
|
|
102
|
-
logGenerated(instructionsResult.path, cwd, options);
|
|
103
|
-
|
|
104
|
-
// Write manifest of generated files (for clean command)
|
|
105
|
-
if (!options.dryRun) {
|
|
106
|
-
writeManifest(outputDir, generatedFiles, cwd);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
console.log();
|
|
110
|
-
if (options.dryRun) {
|
|
111
|
-
console.log(chalk.yellow(` Dry run complete. ${generatedFiles.length} files would be generated.`));
|
|
112
|
-
} else {
|
|
113
|
-
console.log(chalk.green(` Done. ${generatedFiles.length} files generated.`));
|
|
114
|
-
}
|
|
115
|
-
console.log();
|
|
116
|
-
|
|
117
|
-
return generatedFiles;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
function writeManifest(outputDir, generatedFiles, cwd) {
|
|
121
|
-
const manifestPath = join(outputDir, MANIFEST_FILENAME);
|
|
122
|
-
const manifest = {
|
|
123
|
-
version: 1,
|
|
124
|
-
generatedAt: new Date().toISOString(),
|
|
125
|
-
files: generatedFiles.map(f => relative(cwd, f.path))
|
|
126
|
-
};
|
|
127
|
-
ensureDir(manifestPath);
|
|
128
|
-
writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
async function findAndParseSpecs(openspecDir, options) {
|
|
132
|
-
const specsDir = join(openspecDir, 'specs');
|
|
133
|
-
if (!existsSync(specsDir)) {
|
|
134
|
-
return [];
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
const specFiles = await glob('*/spec.md', { cwd: specsDir });
|
|
138
|
-
return specFiles.map(file => parseSpec(join(specsDir, file)));
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
async function findAndParseChanges(openspecDir, options) {
|
|
142
|
-
const changesDir = join(openspecDir, 'changes');
|
|
143
|
-
if (!existsSync(changesDir)) {
|
|
144
|
-
return [];
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
const changes = [];
|
|
148
|
-
const changeDirs = readdirSync(changesDir).filter(name => {
|
|
149
|
-
const fullPath = join(changesDir, name);
|
|
150
|
-
return statSync(fullPath).isDirectory();
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
for (const changeDir of changeDirs) {
|
|
154
|
-
const proposalPath = join(changesDir, changeDir, 'proposal.md');
|
|
155
|
-
const tasksPath = join(changesDir, changeDir, 'tasks.md');
|
|
156
|
-
|
|
157
|
-
if (existsSync(proposalPath)) {
|
|
158
|
-
changes.push({
|
|
159
|
-
proposal: parseProposal(proposalPath),
|
|
160
|
-
tasks: parseTasks(tasksPath)
|
|
161
|
-
});
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
return changes;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
function aggregateTasks(changes) {
|
|
169
|
-
const tasksByDomain = {};
|
|
170
|
-
for (const change of changes) {
|
|
171
|
-
// For now, associate all tasks with a generic key
|
|
172
|
-
// In a real implementation, you might parse domain from proposal
|
|
173
|
-
if (!tasksByDomain['default']) {
|
|
174
|
-
tasksByDomain['default'] = { groups: [], items: [], hasMore: false };
|
|
175
|
-
}
|
|
176
|
-
tasksByDomain['default'].items.push(...change.tasks.items);
|
|
177
|
-
tasksByDomain['default'].hasMore = tasksByDomain['default'].hasMore || change.tasks.hasMore;
|
|
178
|
-
}
|
|
179
|
-
return tasksByDomain;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
function findDomainForChange(change, specs) {
|
|
183
|
-
// Try to match change to a spec domain
|
|
184
|
-
// For now, use the first spec's domain or 'default'
|
|
185
|
-
if (specs.length > 0) {
|
|
186
|
-
return specs[0].domain;
|
|
187
|
-
}
|
|
188
|
-
return 'default';
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
function logGenerated(filePath, cwd, options) {
|
|
192
|
-
const relativePath = relative(cwd, filePath);
|
|
193
|
-
if (options.dryRun) {
|
|
194
|
-
console.log(chalk.yellow(` → ${relativePath}`));
|
|
195
|
-
} else {
|
|
196
|
-
console.log(chalk.green(` ✓ ${relativePath}`));
|
|
197
|
-
}
|
|
198
|
-
}
|
package/src/commands/clean.js
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import { existsSync, rmSync, readdirSync, readFileSync } from 'fs';
|
|
2
|
-
import { join, dirname } from 'path';
|
|
3
|
-
import chalk from 'chalk';
|
|
4
|
-
import { VERSION } from '../version.js';
|
|
5
|
-
import { loadConfig, resolveOutputPath } from '../config.js';
|
|
6
|
-
|
|
7
|
-
const MANIFEST_FILENAME = '.daedalion-manifest.json';
|
|
8
|
-
|
|
9
|
-
export async function clean(cwd) {
|
|
10
|
-
console.log();
|
|
11
|
-
console.log(chalk.bold(` Daedalion v${VERSION} - Clean`));
|
|
12
|
-
console.log();
|
|
13
|
-
|
|
14
|
-
const config = loadConfig(cwd);
|
|
15
|
-
const outputDir = resolveOutputPath(cwd, config);
|
|
16
|
-
|
|
17
|
-
if (!existsSync(outputDir)) {
|
|
18
|
-
console.log(chalk.yellow(' No output directory found. Nothing to clean.'));
|
|
19
|
-
console.log();
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const manifestPath = join(outputDir, MANIFEST_FILENAME);
|
|
24
|
-
|
|
25
|
-
if (!existsSync(manifestPath)) {
|
|
26
|
-
console.log(chalk.yellow(' No manifest found. Run `daedalion build` first to generate a manifest.'));
|
|
27
|
-
console.log(chalk.gray(' (Clean requires a manifest to avoid deleting non-Daedalion files)'));
|
|
28
|
-
console.log();
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const manifest = JSON.parse(readFileSync(manifestPath, 'utf-8'));
|
|
33
|
-
const filesToRemove = manifest.files || [];
|
|
34
|
-
|
|
35
|
-
let removed = 0;
|
|
36
|
-
const cleanedDirs = new Set();
|
|
37
|
-
|
|
38
|
-
for (const relativePath of filesToRemove) {
|
|
39
|
-
const fullPath = join(cwd, relativePath);
|
|
40
|
-
|
|
41
|
-
if (existsSync(fullPath)) {
|
|
42
|
-
rmSync(fullPath, { force: true });
|
|
43
|
-
console.log(chalk.green(` ✓ Removed ${relativePath}`));
|
|
44
|
-
removed++;
|
|
45
|
-
|
|
46
|
-
// Track parent directories for cleanup
|
|
47
|
-
cleanedDirs.add(dirname(fullPath));
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// Remove the manifest itself
|
|
52
|
-
rmSync(manifestPath, { force: true });
|
|
53
|
-
console.log(chalk.green(` ✓ Removed .github/${MANIFEST_FILENAME}`));
|
|
54
|
-
|
|
55
|
-
// Clean up empty directories (skills/domain/, agents/, etc.)
|
|
56
|
-
for (const dir of cleanedDirs) {
|
|
57
|
-
cleanEmptyDirs(dir, outputDir);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
console.log();
|
|
61
|
-
if (removed > 0) {
|
|
62
|
-
console.log(chalk.green(` Done. ${removed} files removed.`));
|
|
63
|
-
} else {
|
|
64
|
-
console.log(chalk.yellow(' No generated files found to clean.'));
|
|
65
|
-
}
|
|
66
|
-
console.log();
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Recursively remove empty directories up to (but not including) the output dir
|
|
70
|
-
function cleanEmptyDirs(dir, stopAt) {
|
|
71
|
-
if (dir === stopAt || !existsSync(dir)) {
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
try {
|
|
76
|
-
const contents = readdirSync(dir);
|
|
77
|
-
if (contents.length === 0) {
|
|
78
|
-
rmSync(dir, { recursive: true, force: true });
|
|
79
|
-
// Check parent directory too
|
|
80
|
-
cleanEmptyDirs(dirname(dir), stopAt);
|
|
81
|
-
}
|
|
82
|
-
} catch {
|
|
83
|
-
// Directory might have been removed already
|
|
84
|
-
}
|
|
85
|
-
}
|