@moskala/oneagent-core 0.4.0 → 0.4.2

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.
@@ -0,0 +1,5 @@
1
+ import type { RuleFile } from "./types.ts";
2
+ export declare function readOpencode(root: string): Promise<Record<string, unknown> | null>;
3
+ export declare function buildOpencodeConfig(existing: Record<string, unknown> | null): object;
4
+ export declare function addOpenCodePlugin(root: string, id: string): Promise<void>;
5
+ export declare function writeOpencode(root: string, _rules: RuleFile[]): Promise<void>;
@@ -0,0 +1,2 @@
1
+ import type { RuleFile } from "./types.ts";
2
+ export declare function readRules(root: string): Promise<RuleFile[]>;
@@ -0,0 +1,11 @@
1
+ import type { SkillFile } from "./types.ts";
2
+ declare const VALID_MODES: readonly ["ask", "edit", "agent"];
3
+ type SkillMode = (typeof VALID_MODES)[number];
4
+ export declare function parseSkillFrontmatter(raw: string): {
5
+ description: string;
6
+ mode: SkillMode;
7
+ content: string;
8
+ };
9
+ export declare function readSkillFile(filePath: string): Promise<SkillFile>;
10
+ export declare function readSkills(root: string): Promise<SkillFile[]>;
11
+ export {};
@@ -0,0 +1,5 @@
1
+ import type { Config, GeneratedFileCheck, OpenCodeCheck, RuleFile, StatusResult } from "./types.ts";
2
+ export declare function checkGeneratedFile(root: string, rule: RuleFile): Promise<GeneratedFileCheck>;
3
+ export declare function checkOpencodeStatus(root: string, _rules: RuleFile[]): Promise<OpenCodeCheck>;
4
+ export declare function checkCopilotPrompt(root: string, skill: import("./types.ts").SkillFile): Promise<GeneratedFileCheck>;
5
+ export declare function checkStatus(root: string, config: Config): Promise<StatusResult>;
@@ -0,0 +1,12 @@
1
+ import type { AgentTarget, SymlinkCheck, SymlinkEntry } from "./types.ts";
2
+ export declare function ensureDir(dirPath: string): Promise<void>;
3
+ export declare function createSymlink(symlinkPath: string, target: string): Promise<void>;
4
+ export declare function buildMainSymlinks(root: string, targets: AgentTarget[]): SymlinkEntry[];
5
+ export declare function buildRulesSymlinks(root: string, targets: AgentTarget[]): SymlinkEntry[];
6
+ export declare function buildSkillSymlinks(root: string, targets: AgentTarget[]): SymlinkEntry[];
7
+ export declare function buildCommandSymlinks(root: string, targets: AgentTarget[]): SymlinkEntry[];
8
+ export declare function buildAgentsDirSymlinks(root: string): SymlinkEntry[];
9
+ export declare function migrateRuleAndSkillFiles(root: string): Promise<void>;
10
+ export declare function cleanupAgentDir(root: string, target: import("./types.ts").AgentTarget): Promise<void>;
11
+ export declare function createAllSymlinks(entries: SymlinkEntry[]): Promise<void>;
12
+ export declare function checkSymlink(entry: SymlinkEntry): Promise<SymlinkCheck>;
@@ -0,0 +1,50 @@
1
+ export type AgentTarget = "claude" | "cursor" | "windsurf" | "opencode" | "copilot";
2
+ export interface Config {
3
+ version: 1;
4
+ targets: Record<AgentTarget, boolean>;
5
+ }
6
+ export interface DetectedFile {
7
+ relativePath: string;
8
+ absolutePath: string;
9
+ sizeBytes: number;
10
+ modifiedAt: Date;
11
+ content: string;
12
+ }
13
+ export interface RuleFile {
14
+ name: string;
15
+ path: string;
16
+ }
17
+ export interface CommandFile {
18
+ name: string;
19
+ path: string;
20
+ }
21
+ export interface SkillFile {
22
+ name: string;
23
+ path: string;
24
+ description: string;
25
+ mode: "ask" | "edit" | "agent";
26
+ content: string;
27
+ }
28
+ export interface SymlinkEntry {
29
+ symlinkPath: string;
30
+ target: string;
31
+ label: string;
32
+ }
33
+ export interface SymlinkCheck extends SymlinkEntry {
34
+ exists: boolean;
35
+ valid: boolean;
36
+ }
37
+ export interface StatusResult {
38
+ symlinks: SymlinkCheck[];
39
+ generatedFiles: GeneratedFileCheck[];
40
+ opencode: OpenCodeCheck;
41
+ }
42
+ export interface GeneratedFileCheck {
43
+ path: string;
44
+ exists: boolean;
45
+ upToDate: boolean;
46
+ }
47
+ export interface OpenCodeCheck {
48
+ exists: boolean;
49
+ valid: boolean;
50
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moskala/oneagent-core",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
4
4
  "type": "module",
5
5
  "description": "Core library for oneagent — one source of truth for AI agent rules",
6
6
  "license": "MIT",
@@ -8,16 +8,20 @@
8
8
  "type": "git",
9
9
  "url": "https://github.com/moskalakamil/oneagent"
10
10
  },
11
- "module": "./src/index.ts",
12
- "main": "./src/index.ts",
11
+ "module": "./dist/index.js",
12
+ "main": "./dist/index.js",
13
13
  "exports": {
14
- ".": "./src/index.ts"
14
+ ".": {
15
+ "bun": "./src/index.ts",
16
+ "types": "./dist/index.d.ts",
17
+ "default": "./dist/index.js"
18
+ }
15
19
  },
16
20
  "files": [
17
- "src",
18
- "!src/__tests__"
21
+ "dist"
19
22
  ],
20
23
  "scripts": {
24
+ "build": "bun ./scripts/build.ts",
21
25
  "typecheck": "tsc --noEmit",
22
26
  "test": "bun test"
23
27
  },
package/src/agents.ts DELETED
@@ -1,76 +0,0 @@
1
- import type { AgentTarget } from "./types.ts";
2
-
3
- export interface AgentDefinition {
4
- target: AgentTarget;
5
- displayName: string;
6
- hint: string;
7
- /** Paths (relative to root) checked to detect agent presence. Any match = present. */
8
- detectIndicators: string[];
9
- /** Symlink path for main instructions file (relative to root). */
10
- mainFile: string;
11
- /** Whole-dir symlink for rules (relative to root). Omit if not applicable. */
12
- rulesDir?: string;
13
- /** Whole-dir symlink for skills (relative to root). Omit if not applicable. */
14
- skillsDir?: string;
15
- /** Whole-dir symlink for commands (relative to root). Omit if agent does not support custom commands. */
16
- commandsDir?: string;
17
- /** Legacy files to remove during init (superseded by current format). */
18
- deprecatedFiles?: string[];
19
- }
20
-
21
- export const AGENT_DEFINITIONS: AgentDefinition[] = [
22
- {
23
- target: "claude",
24
- displayName: "Claude Code",
25
- hint: "CLAUDE.md + .claude/rules/",
26
- detectIndicators: ["CLAUDE.md", ".claude"],
27
- mainFile: "CLAUDE.md",
28
- rulesDir: ".claude/rules",
29
- skillsDir: ".claude/skills",
30
- commandsDir: ".claude/commands",
31
- },
32
- {
33
- target: "cursor",
34
- displayName: "Cursor",
35
- hint: "AGENTS.md + .cursor/rules/",
36
- detectIndicators: [".cursor", ".cursorrules"],
37
- mainFile: "AGENTS.md",
38
- rulesDir: ".cursor/rules",
39
- skillsDir: ".cursor/skills",
40
- deprecatedFiles: [".cursorrules"],
41
- commandsDir: ".cursor/commands",
42
- },
43
- {
44
- target: "windsurf",
45
- displayName: "Windsurf",
46
- hint: "AGENTS.md + .windsurf/rules/",
47
- detectIndicators: [".windsurf", ".windsurfrules"],
48
- mainFile: "AGENTS.md",
49
- rulesDir: ".windsurf/rules",
50
- skillsDir: ".windsurf/skills",
51
- deprecatedFiles: [".windsurfrules"],
52
- },
53
- {
54
- target: "opencode",
55
- displayName: "OpenCode",
56
- hint: "AGENTS.md + .opencode/",
57
- detectIndicators: ["opencode.json", ".opencode"],
58
- mainFile: "AGENTS.md",
59
- rulesDir: ".opencode/rules",
60
- skillsDir: ".opencode/skills",
61
- commandsDir: ".opencode/commands",
62
- },
63
- {
64
- target: "copilot",
65
- displayName: "GitHub Copilot",
66
- hint: ".github/instructions/*.instructions.md",
67
- detectIndicators: [".github/copilot-instructions.md", ".github/instructions"],
68
- mainFile: ".github/copilot-instructions.md",
69
- skillsDir: ".github/skills",
70
- // rules: generated as <name>.instructions.md files, not symlinks
71
- },
72
- ];
73
-
74
- export function getAgentDef(target: AgentTarget): AgentDefinition {
75
- return AGENT_DEFINITIONS.find((d) => d.target === target)!;
76
- }
@@ -1,335 +0,0 @@
1
- import path from "path";
2
- import fs from "fs/promises";
3
- import { execFile } from "child_process";
4
- import { promisify } from "util";
5
- import type { AgentTarget } from "./types.ts";
6
- import { addOpenCodePlugin } from "./opencode.ts";
7
- import { ONEAGENT_DIR } from "./constants.ts";
8
-
9
- const execFileAsync = promisify(execFile);
10
-
11
- export interface TemplatePlugin {
12
- target: AgentTarget;
13
- id: string;
14
- }
15
-
16
- export interface SkillEntry {
17
- repo: string;
18
- skill: string;
19
- }
20
-
21
- export interface TemplateDefinition {
22
- name: string;
23
- description: string;
24
- skills: SkillEntry[];
25
- plugins: TemplatePlugin[];
26
- instructions: string;
27
- rules: Array<{ name: string; content: string }>;
28
- }
29
-
30
- // Parses name, description, skills and plugins from a template.yml string.
31
- // This is the single source of truth for the template.yml format — used by
32
- // both builtin template loading and GitHub URL template fetching.
33
- export function parseTemplateYaml(yamlText: string, fallbackName = "custom"): Pick<TemplateDefinition, "name" | "description" | "skills" | "plugins"> & { extends?: string } {
34
- const nameMatch = yamlText.match(/^name:\s*(.+)$/m);
35
- const name = nameMatch?.[1]?.trim() ?? fallbackName;
36
-
37
- const descMatch = yamlText.match(/^description:\s*(.+)$/m);
38
- const description = descMatch?.[1]?.trim() ?? "";
39
-
40
- const extendsMatch = yamlText.match(/^extends:\s*(.+)$/m);
41
- const extendsValue = extendsMatch?.[1]?.trim();
42
-
43
- const skills = parseSkillsFromYaml(yamlText);
44
- const plugins = parsePluginsFromYaml(yamlText);
45
- return { name, description, skills, plugins, ...(extendsValue ? { extends: extendsValue } : {}) };
46
- }
47
-
48
- // Parses the `skills:` block from a template.yml string.
49
- // Expects entries in the format:
50
- // skills:
51
- // - repo: https://github.com/owner/skills
52
- // skill: skill-name
53
- export function parseSkillsFromYaml(yamlText: string): SkillEntry[] {
54
- const skills: SkillEntry[] = [];
55
- const section = yamlText.match(/^skills:\s*\n((?:(?: -.+|\s{4}.+)\n?)*)/m);
56
- if (!section) return skills;
57
- const block = section[1]!;
58
- const entries = block.split(/\n(?= -)/);
59
- for (const entry of entries) {
60
- const repoMatch = entry.match(/repo:\s*(\S+)/);
61
- const skillMatch = entry.match(/skill:\s*(\S+)/);
62
- if (repoMatch && skillMatch) {
63
- skills.push({ repo: repoMatch[1]!.trim(), skill: skillMatch[1]!.trim() });
64
- }
65
- }
66
- return skills;
67
- }
68
-
69
- // Parses the `plugins:` block from a template.yml string.
70
- // Expects entries in the format:
71
- // plugins:
72
- // - target: claude
73
- // id: typescript-lsp@claude-plugins-official
74
- export function parsePluginsFromYaml(yamlText: string): TemplatePlugin[] {
75
- const plugins: TemplatePlugin[] = [];
76
- const section = yamlText.match(/^plugins:\s*\n((?:(?: -.+|\s{4}.+)\n?)*)/m);
77
- if (!section) return plugins;
78
- const block = section[1]!;
79
- const entries = block.split(/\n(?= -)/);
80
- for (const entry of entries) {
81
- const targetMatch = entry.match(/target:\s*(\S+)/);
82
- const idMatch = entry.match(/id:\s*(.+)/);
83
- if (targetMatch && idMatch) {
84
- plugins.push({
85
- target: targetMatch[1]!.trim() as AgentTarget,
86
- id: idMatch[1]!.trim(),
87
- });
88
- }
89
- }
90
- return plugins;
91
- }
92
-
93
- // Resolves the `extends` field — loads parent template from builtin name or GitHub URL.
94
- // Merges skills, plugins, rules (parent first, then child).
95
- // Instructions are NOT inherited — each template has its own.
96
- export async function resolveExtends(
97
- child: TemplateDefinition & { extends?: string },
98
- resolveBuiltin?: (name: string) => Promise<TemplateDefinition | null>,
99
- ): Promise<TemplateDefinition> {
100
- if (!child.extends) return child;
101
-
102
- let parent: TemplateDefinition;
103
- if (child.extends.startsWith("https://")) {
104
- parent = await fetchTemplateFromGitHub(child.extends);
105
- } else if (resolveBuiltin) {
106
- const resolved = await resolveBuiltin(child.extends);
107
- if (!resolved) throw new Error(`Unknown builtin template: "${child.extends}"`);
108
- parent = resolved;
109
- } else {
110
- throw new Error(`Cannot resolve extends: "${child.extends}"`);
111
- }
112
-
113
- return {
114
- name: child.name,
115
- description: child.description,
116
- instructions: child.instructions,
117
- skills: [...parent.skills, ...child.skills],
118
- plugins: [...parent.plugins, ...child.plugins],
119
- rules: [...parent.rules, ...child.rules],
120
- };
121
- }
122
-
123
- // Phase 1: writes instructions.md and rules/*.md.
124
- // Call this BEFORE generate() so symlinks to rules are created.
125
- export async function applyTemplateFiles(root: string, template: TemplateDefinition): Promise<void> {
126
- const oneagentDir = path.join(root, ONEAGENT_DIR);
127
-
128
- await fs.mkdir(path.join(oneagentDir, "rules"), { recursive: true });
129
- await fs.mkdir(path.join(oneagentDir, "skills"), { recursive: true });
130
-
131
- await fs.writeFile(path.join(oneagentDir, "instructions.md"), template.instructions);
132
-
133
- for (const rule of template.rules) {
134
- await fs.writeFile(path.join(oneagentDir, "rules", `${rule.name}.md`), rule.content);
135
- }
136
- }
137
-
138
- export interface SkillInstallResult {
139
- installed: SkillEntry[];
140
- failed: Array<{ entry: SkillEntry; reason: string }>;
141
- }
142
-
143
- // Phase 2: installs skills via `npx skills add <repo> --skill <name>`.
144
- // Skills are installed sequentially to avoid race conditions — each `npx skills add` call
145
- // sets up agent directories and running them in parallel causes "skills 2" naming conflicts.
146
- // Call this AFTER generate() so agent directories exist.
147
- // Never throws — failed skills are collected and returned in the result.
148
- export async function installTemplateSkills(
149
- root: string,
150
- template: TemplateDefinition,
151
- ): Promise<SkillInstallResult> {
152
- const installed: SkillEntry[] = [];
153
- const failed: Array<{ entry: SkillEntry; reason: string }> = [];
154
-
155
- for (const entry of template.skills) {
156
- try {
157
- await execFileAsync("npx", ["skills", "add", entry.repo, "--skill", entry.skill, "--agent", "universal", "--yes"], { cwd: root });
158
- installed.push(entry);
159
- } catch (err) {
160
- const reason = err instanceof Error ? err.message : String(err);
161
- failed.push({ entry, reason });
162
- }
163
- }
164
-
165
- return { installed, failed };
166
- }
167
-
168
- const BUILTIN_SKILL_REPO = "https://github.com/moskalakamil/oneagent";
169
- const BUILTIN_SKILL_NAME = "oneagent";
170
-
171
- // Installs the built-in oneagent skill that teaches agents how to work with the .oneagent/ directory.
172
- // Never throws — returns true if installed, false if failed.
173
- export async function installBuiltinSkill(root: string): Promise<boolean> {
174
- try {
175
- await execFileAsync("npx", ["skills", "add", BUILTIN_SKILL_REPO, "--skill", BUILTIN_SKILL_NAME, "--agent", "universal", "--yes"], { cwd: root });
176
- return true;
177
- } catch {
178
- return false;
179
- }
180
- }
181
-
182
- export interface PluginInstallResult {
183
- installed: TemplatePlugin[];
184
- manual: TemplatePlugin[];
185
- failed: Array<{ plugin: TemplatePlugin; reason: string }>;
186
- }
187
-
188
- // Phase 3: installs plugins for active targets. Call AFTER generate().
189
- // - claude → `claude plugin install <id>`
190
- // - copilot → `copilot plugin install <id>`
191
- // - opencode → adds id to plugin[] in opencode.json
192
- // - cursor → added to manual list (no CLI yet — user runs /add-plugin in chat)
193
- // - windsurf → skipped (no marketplace)
194
- // Never throws — failed plugins are collected and returned in the result.
195
- export async function installTemplatePlugins(
196
- root: string,
197
- template: TemplateDefinition,
198
- activeTargets: AgentTarget[],
199
- ): Promise<PluginInstallResult> {
200
- const installed: TemplatePlugin[] = [];
201
- const manual: TemplatePlugin[] = [];
202
- const failed: Array<{ plugin: TemplatePlugin; reason: string }> = [];
203
-
204
- for (const plugin of template.plugins) {
205
- if (!activeTargets.includes(plugin.target)) continue;
206
-
207
- try {
208
- switch (plugin.target) {
209
- case "claude":
210
- await execFileAsync("claude", ["plugin", "install", plugin.id], { cwd: root });
211
- installed.push(plugin);
212
- break;
213
-
214
- case "copilot":
215
- await execFileAsync("copilot", ["plugin", "install", plugin.id], { cwd: root });
216
- installed.push(plugin);
217
- break;
218
-
219
- case "opencode":
220
- await addOpenCodePlugin(root, plugin.id);
221
- installed.push(plugin);
222
- break;
223
-
224
- case "cursor":
225
- manual.push(plugin);
226
- break;
227
-
228
- case "windsurf":
229
- // No marketplace yet — skip silently
230
- break;
231
- }
232
- } catch (err) {
233
- const reason = err instanceof Error ? err.message : String(err);
234
- failed.push({ plugin, reason });
235
- }
236
- }
237
-
238
- return { installed, manual, failed };
239
- }
240
-
241
- // Fetches a template from a GitHub URL.
242
- // Expects the repository to contain: template.yml, instructions.md, and optionally rules/*.md
243
- // When no branch is specified in the URL, queries the GitHub API for the default branch.
244
- export async function fetchTemplateFromGitHub(url: string): Promise<TemplateDefinition> {
245
- const { owner, repo, branch, subdir } = parseGitHubUrl(url);
246
- const branchExplicit = url.includes("/tree/");
247
-
248
- const resolvedBranch = branchExplicit ? branch : await fetchDefaultBranch(owner, repo);
249
- const rawBase = `https://raw.githubusercontent.com/${owner}/${repo}/${resolvedBranch}${subdir ? `/${subdir}` : ""}`;
250
-
251
- const [yamlText, instructions] = await Promise.all([
252
- fetchText(`${rawBase}/template.yml`),
253
- fetchText(`${rawBase}/instructions.md`),
254
- ]);
255
-
256
- const parsed = parseTemplateYaml(yamlText);
257
-
258
- // Try to list rules via GitHub API
259
- const rules = await fetchGitHubRules(url);
260
-
261
- const base = { ...parsed, instructions, rules };
262
- return resolveExtends(base);
263
- }
264
-
265
- async function fetchDefaultBranch(owner: string, repo: string): Promise<string> {
266
- try {
267
- const response = await fetch(`https://api.github.com/repos/${owner}/${repo}`, {
268
- headers: { Accept: "application/vnd.github.v3+json" },
269
- });
270
- if (!response.ok) return "main";
271
- const data = (await response.json()) as { default_branch?: string };
272
- return data.default_branch ?? "main";
273
- } catch {
274
- return "main";
275
- }
276
- }
277
-
278
- async function fetchText(url: string): Promise<string> {
279
- const response = await fetch(url);
280
- if (!response.ok) {
281
- throw new Error(`Failed to fetch ${url}: ${response.status} ${response.statusText}`);
282
- }
283
- return response.text();
284
- }
285
-
286
- interface GitHubUrlParts {
287
- owner: string;
288
- repo: string;
289
- branch: string;
290
- subdir: string; // "" for root, "path/to/dir" for subdirectories
291
- }
292
-
293
- function parseGitHubUrl(url: string): GitHubUrlParts {
294
- // Supports:
295
- // https://github.com/owner/repo
296
- // https://github.com/owner/repo/tree/branch
297
- // https://github.com/owner/repo/tree/branch/path/to/subdir
298
- const match = url.match(/^https:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\/tree\/([^/]+?)(?:\/(.+))?)?(?:\/)?$/);
299
- if (!match) {
300
- throw new Error(`Invalid GitHub URL: "${url}". Expected format: https://github.com/owner/repo`);
301
- }
302
- const [, owner, repo, branch = "main", subdir = ""] = match;
303
- return { owner: owner!, repo: repo!, branch, subdir };
304
- }
305
-
306
- function githubUrlToRawBase(url: string): string {
307
- const { owner, repo, branch, subdir } = parseGitHubUrl(url);
308
- const base = `https://raw.githubusercontent.com/${owner}/${repo}/${branch}`;
309
- return subdir ? `${base}/${subdir}` : base;
310
- }
311
-
312
- async function fetchGitHubRules(repoUrl: string): Promise<Array<{ name: string; content: string }>> {
313
- const { owner, repo, branch, subdir } = parseGitHubUrl(repoUrl);
314
- const rulesPath = subdir ? `${subdir}/rules` : "rules";
315
- const apiUrl = `https://api.github.com/repos/${owner}/${repo}/contents/${rulesPath}?ref=${branch}`;
316
- try {
317
- const response = await fetch(apiUrl, {
318
- headers: { Accept: "application/vnd.github.v3+json" },
319
- });
320
- if (!response.ok) return [];
321
-
322
- const files = (await response.json()) as Array<{ name: string; download_url: string | null }>;
323
- const mdFiles = files.filter((f) => f.name.endsWith(".md") && f.download_url);
324
-
325
- const rules = await Promise.all(
326
- mdFiles.map(async (f) => {
327
- const content = await fetchText(f.download_url!);
328
- return { name: path.basename(f.name, ".md"), content };
329
- }),
330
- );
331
- return rules;
332
- } catch {
333
- return [];
334
- }
335
- }
package/src/commands.ts DELETED
@@ -1,17 +0,0 @@
1
- import path from "path";
2
- import fs from "fs/promises";
3
- import type { CommandFile } from "./types.ts";
4
- import { ONEAGENT_DIR } from "./constants.ts";
5
-
6
- export async function readCommands(root: string): Promise<CommandFile[]> {
7
- const commandsDir = path.join(root, ONEAGENT_DIR, "commands");
8
- try {
9
- const files = await fs.readdir(commandsDir);
10
- return files
11
- .filter((f) => f.endsWith(".md"))
12
- .map((f) => ({ name: path.basename(f, ".md"), path: path.join(commandsDir, f) }))
13
- .sort((a, b) => a.name.localeCompare(b.name));
14
- } catch {
15
- return [];
16
- }
17
- }
package/src/config.ts DELETED
@@ -1,32 +0,0 @@
1
- import { parse, stringify } from "yaml";
2
- import path from "path";
3
- import fs from "fs/promises";
4
- import type { AgentTarget, Config } from "./types.ts";
5
- import { ONEAGENT_DIR } from "./constants.ts";
6
-
7
- const CONFIG_REL = `${ONEAGENT_DIR}/config.yml`;
8
-
9
- export const ALL_AGENT_TARGETS: AgentTarget[] = ["claude", "cursor", "windsurf", "opencode", "copilot"];
10
-
11
- export function activeTargets(config: Config): AgentTarget[] {
12
- return ALL_AGENT_TARGETS.filter((t) => config.targets[t]);
13
- }
14
-
15
- export function makeTargets(...enabled: AgentTarget[]): Record<AgentTarget, boolean> {
16
- return Object.fromEntries(ALL_AGENT_TARGETS.map((t) => [t, enabled.includes(t)])) as Record<AgentTarget, boolean>;
17
- }
18
-
19
- export async function configExists(root: string): Promise<boolean> {
20
- return fs.access(path.join(root, CONFIG_REL)).then(() => true, () => false);
21
- }
22
-
23
- export async function readConfig(root: string): Promise<Config> {
24
- const content = await fs.readFile(path.join(root, CONFIG_REL), "utf-8");
25
- return parse(content) as Config;
26
- }
27
-
28
- export async function writeConfig(root: string, config: Config): Promise<void> {
29
- const filePath = path.join(root, CONFIG_REL);
30
- await fs.mkdir(path.dirname(filePath), { recursive: true });
31
- await fs.writeFile(filePath, stringify(config));
32
- }
package/src/constants.ts DELETED
@@ -1 +0,0 @@
1
- export const ONEAGENT_DIR = ".oneagent";
package/src/copilot.ts DELETED
@@ -1,38 +0,0 @@
1
- import path from "path";
2
- import fs from "fs/promises";
3
- import type { RuleFile, SkillFile } from "./types.ts";
4
-
5
- export function copilotFilePath(root: string, ruleName: string): string {
6
- return path.join(root, ".github/instructions", `${ruleName}.instructions.md`);
7
- }
8
-
9
- export async function generateCopilotRule(root: string, rule: RuleFile): Promise<void> {
10
- const destPath = copilotFilePath(root, rule.name);
11
- await fs.mkdir(path.dirname(destPath), { recursive: true });
12
- await fs.copyFile(rule.path, destPath);
13
- }
14
-
15
- export async function generateCopilotRules(root: string, rules: RuleFile[]): Promise<void> {
16
- await Promise.all(rules.map((rule) => generateCopilotRule(root, rule)));
17
- }
18
-
19
- export function buildCopilotPromptContent(skill: SkillFile): string {
20
- const lines = ["---", `mode: "${skill.mode}"`];
21
- if (skill.description) lines.push(`description: "${skill.description}"`);
22
- lines.push("---", skill.content);
23
- return lines.join("\n");
24
- }
25
-
26
- export function copilotPromptFilePath(root: string, skillName: string): string {
27
- return path.join(root, ".github/prompts", `${skillName}.prompt.md`);
28
- }
29
-
30
- export async function generateCopilotSkill(root: string, skill: SkillFile): Promise<void> {
31
- const filePath = copilotPromptFilePath(root, skill.name);
32
- await fs.mkdir(path.dirname(filePath), { recursive: true });
33
- await fs.writeFile(filePath, buildCopilotPromptContent(skill));
34
- }
35
-
36
- export async function generateCopilotSkills(root: string, skills: SkillFile[]): Promise<void> {
37
- await Promise.all(skills.map((skill) => generateCopilotSkill(root, skill)));
38
- }