special-agents 0.3.5 → 0.3.6
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/content/defaults.yaml +1 -1
- package/content/preamble.md +1 -0
- package/dist/compile.d.ts +18 -0
- package/dist/compile.js +78 -7
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/node_modules/rafi-spec/dist/schemas.d.ts +61 -1
- package/node_modules/rafi-spec/dist/schemas.js +27 -1
- package/node_modules/rafi-spec/dist/types.d.ts +19 -1
- package/node_modules/rafi-spec/src/schemas.ts +29 -1
- package/node_modules/rafi-spec/src/types.ts +23 -1
- package/package.json +1 -1
package/content/defaults.yaml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Default stack values + flags. These reproduce the original hardcoded rules.md
|
|
2
2
|
# guidance: rendering the templated packs with these defaults equals the source.
|
|
3
|
-
# `rafi create` writes a
|
|
3
|
+
# `rafi create` writes a rafi-config.yaml that overrides these per project.
|
|
4
4
|
stack:
|
|
5
5
|
frontend: "React with TypeScript"
|
|
6
6
|
backend: "Python and Node.js"
|
package/content/preamble.md
CHANGED
|
@@ -11,3 +11,4 @@ For Claude Code, create a repository-root `CLAUDE.md` that imports the same rule
|
|
|
11
11
|
|
|
12
12
|
Keep durable process rules in this file. Put detailed project facts in the project documents named below, not in the agent rules.
|
|
13
13
|
|
|
14
|
+
Custom Rafi skills or agents can replace the defaults by setting `artifact_source: existing` and editing their paths in `rafi-config.yaml`.
|
package/dist/compile.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type Defaults, type LoadedPack } from "./content.js";
|
|
2
2
|
import { type ConditionFlags, type ResolvableManifest } from "./resolve.js";
|
|
3
3
|
import type { AgentManifest, AgentRole, EffortLevel } from "rafi-spec";
|
|
4
|
+
export declare const CUSTOM_ARTIFACTS_NOTE = "Custom Rafi skills or agents can replace the defaults by setting `artifact_source: existing` and editing their paths in `rafi-config.yaml`.\n";
|
|
4
5
|
export interface CompileOptions {
|
|
5
6
|
/** Stack/flags to render with. Defaults to the bundled `defaults.yaml`. */
|
|
6
7
|
defaults?: Defaults;
|
|
@@ -62,9 +63,13 @@ export declare function emitAgentsMd(targetDir: string, opts?: CompileOptions):
|
|
|
62
63
|
* Write `<targetDir>/CLAUDE.md` — the lean Claude entrypoint that imports `AGENTS.md`.
|
|
63
64
|
*/
|
|
64
65
|
export declare function emitClaudeMd(targetDir: string, opts?: CompileOptions): void;
|
|
66
|
+
export declare function renderAgentsMd(opts?: CompileOptions): string;
|
|
67
|
+
export declare function renderClaudeMd(opts?: CompileOptions): string;
|
|
65
68
|
export interface EmitOptions extends AgentComposeOptions {
|
|
66
69
|
/** Roles to emit. Defaults to all four. */
|
|
67
70
|
roles?: AgentRole[];
|
|
71
|
+
/** Map generic skill names in role manifests to the installed runtime skill names. */
|
|
72
|
+
skillNames?: Record<string, string>;
|
|
68
73
|
}
|
|
69
74
|
/**
|
|
70
75
|
* Write `.rafi/compiled/<role>/system.md` + `meta.json` for each role.
|
|
@@ -77,3 +82,16 @@ export declare function emitCompiledBundles(targetDir: string, opts?: EmitOption
|
|
|
77
82
|
* composed system text.
|
|
78
83
|
*/
|
|
79
84
|
export declare function emitClaudeAgents(targetDir: string, opts?: EmitOptions): void;
|
|
85
|
+
export interface EmitMappedOptions extends EmitOptions {
|
|
86
|
+
paths?: Record<string, string>;
|
|
87
|
+
force?: boolean;
|
|
88
|
+
}
|
|
89
|
+
export declare function emitMappedClaudeAgents(targetDir: string, opts?: EmitMappedOptions): void;
|
|
90
|
+
export declare function emitCodexAgents(targetDir: string, opts?: EmitMappedOptions): void;
|
|
91
|
+
export interface EmitSkillsOptions {
|
|
92
|
+
/** Generic skill name -> runtime-specific path. */
|
|
93
|
+
paths?: Record<string, string>;
|
|
94
|
+
names?: string[];
|
|
95
|
+
force?: boolean;
|
|
96
|
+
}
|
|
97
|
+
export declare function emitSkills(targetDir: string, opts?: EmitSkillsOptions): void;
|
package/dist/compile.js
CHANGED
|
@@ -9,12 +9,14 @@
|
|
|
9
9
|
*
|
|
10
10
|
* Per-role and lean-Claude emission build on this and the resolver (see resolve.ts).
|
|
11
11
|
*/
|
|
12
|
-
import { mkdirSync, writeFileSync } from "node:fs";
|
|
13
|
-
import { join } from "node:path";
|
|
12
|
+
import { cpSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
13
|
+
import { dirname, join } from "node:path";
|
|
14
14
|
import { render } from "./template.js";
|
|
15
15
|
import { loadAllPacks, loadDefaults, loadPack, loadPacksIndex, loadPreamble, } from "./content.js";
|
|
16
16
|
import { resolveAgentPacks } from "./resolve.js";
|
|
17
17
|
import { loadAgent, AGENT_ROLES } from "./agents.js";
|
|
18
|
+
import { loadAllSkills, SKILLS_DIR } from "./skills.js";
|
|
19
|
+
export const CUSTOM_ARTIFACTS_NOTE = "Custom Rafi skills or agents can replace the defaults by setting `artifact_source: existing` and editing their paths in `rafi-config.yaml`.\n";
|
|
18
20
|
/** Render one pack body, substituting `{{vars}}` and resolving `{{#if flag}}` blocks. */
|
|
19
21
|
export function renderPackBody(pack, defaults) {
|
|
20
22
|
return render(pack.body, { vars: defaults.stack, flags: defaults.flags });
|
|
@@ -69,17 +71,23 @@ export function buildConditionsHeader(flags) {
|
|
|
69
71
|
* Format: one-line conditions header + preamble + all packs rendered with defaults.
|
|
70
72
|
*/
|
|
71
73
|
export function emitAgentsMd(targetDir, opts = {}) {
|
|
72
|
-
|
|
73
|
-
const header = buildConditionsHeader(defaults.flags);
|
|
74
|
-
writeFileSync(join(targetDir, "AGENTS.md"), header + composeRulesMarkdown({ defaults }), "utf8");
|
|
74
|
+
writeFileSync(join(targetDir, "AGENTS.md"), renderAgentsMd(opts), "utf8");
|
|
75
75
|
}
|
|
76
76
|
/**
|
|
77
77
|
* Write `<targetDir>/CLAUDE.md` — the lean Claude entrypoint that imports `AGENTS.md`.
|
|
78
78
|
*/
|
|
79
79
|
export function emitClaudeMd(targetDir, opts = {}) {
|
|
80
|
+
writeFileSync(join(targetDir, "CLAUDE.md"), renderClaudeMd(opts), "utf8");
|
|
81
|
+
}
|
|
82
|
+
export function renderAgentsMd(opts = {}) {
|
|
83
|
+
const defaults = opts.defaults ?? loadDefaults();
|
|
84
|
+
const header = buildConditionsHeader(defaults.flags);
|
|
85
|
+
return header + composeRulesMarkdown({ defaults });
|
|
86
|
+
}
|
|
87
|
+
export function renderClaudeMd(opts = {}) {
|
|
80
88
|
const defaults = opts.defaults ?? loadDefaults();
|
|
81
89
|
const header = buildConditionsHeader(defaults.flags);
|
|
82
|
-
|
|
90
|
+
return header + "@AGENTS.md\n\n" + CUSTOM_ARTIFACTS_NOTE;
|
|
83
91
|
}
|
|
84
92
|
/**
|
|
85
93
|
* Write `.rafi/compiled/<role>/system.md` + `meta.json` for each role.
|
|
@@ -92,7 +100,8 @@ export function emitCompiledBundles(targetDir, opts = {}) {
|
|
|
92
100
|
const dir = join(targetDir, ".rafi", "compiled", role);
|
|
93
101
|
mkdirSync(dir, { recursive: true });
|
|
94
102
|
writeFileSync(join(dir, "system.md"), bundle.system, "utf8");
|
|
95
|
-
const
|
|
103
|
+
const skills = bundle.skills.map((skill) => opts.skillNames?.[skill] ?? skill);
|
|
104
|
+
const meta = { skills, model: bundle.model, effort: bundle.effort };
|
|
96
105
|
writeFileSync(join(dir, "meta.json"), JSON.stringify(meta, null, 2) + "\n", "utf8");
|
|
97
106
|
}
|
|
98
107
|
}
|
|
@@ -111,3 +120,65 @@ export function emitClaudeAgents(targetDir, opts = {}) {
|
|
|
111
120
|
writeFileSync(join(agentsDir, `${role}.md`), frontMatter + bundle.system, "utf8");
|
|
112
121
|
}
|
|
113
122
|
}
|
|
123
|
+
export function emitMappedClaudeAgents(targetDir, opts = {}) {
|
|
124
|
+
const roles = opts.roles ?? AGENT_ROLES;
|
|
125
|
+
for (const role of roles) {
|
|
126
|
+
const bundle = getAgent(role, opts);
|
|
127
|
+
const path = join(targetDir, opts.paths?.[role] ?? `./.claude/agents/${role}.md`);
|
|
128
|
+
if (!opts.force && fileExists(path))
|
|
129
|
+
continue;
|
|
130
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
131
|
+
const name = artifactNameFromPath(path, role);
|
|
132
|
+
const frontMatter = `---\nname: ${name}\ndescription: ${bundle.manifest.description}\n---\n\n`;
|
|
133
|
+
writeFileSync(path, frontMatter + bundle.system, "utf8");
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
export function emitCodexAgents(targetDir, opts = {}) {
|
|
137
|
+
const roles = opts.roles ?? AGENT_ROLES;
|
|
138
|
+
for (const role of roles) {
|
|
139
|
+
const bundle = getAgent(role, opts);
|
|
140
|
+
const path = join(targetDir, opts.paths?.[role] ?? `./.codex/agents/${role}.toml`);
|
|
141
|
+
if (!opts.force && fileExists(path))
|
|
142
|
+
continue;
|
|
143
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
144
|
+
const name = artifactNameFromPath(path, role);
|
|
145
|
+
const toml = `name = ${JSON.stringify(name)}\n` +
|
|
146
|
+
`description = ${JSON.stringify(bundle.manifest.description)}\n` +
|
|
147
|
+
`developer_instructions = ${JSON.stringify(bundle.system)}\n`;
|
|
148
|
+
writeFileSync(path, toml, "utf8");
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
export function emitSkills(targetDir, opts = {}) {
|
|
152
|
+
for (const skill of loadAllSkills()) {
|
|
153
|
+
if (opts.names && !opts.names.includes(skill.name))
|
|
154
|
+
continue;
|
|
155
|
+
const path = join(targetDir, opts.paths?.[skill.name] ?? `./.agents/skills/${skill.name}/SKILL.md`);
|
|
156
|
+
if (!opts.force && fileExists(path))
|
|
157
|
+
continue;
|
|
158
|
+
const dir = dirname(path);
|
|
159
|
+
mkdirSync(dirname(dir), { recursive: true });
|
|
160
|
+
cpSync(join(SKILLS_DIR, skill.name), dir, { recursive: true });
|
|
161
|
+
const installedName = artifactNameFromPath(path, skill.name);
|
|
162
|
+
if (installedName !== skill.name) {
|
|
163
|
+
const raw = readFileSync(join(SKILLS_DIR, skill.name, "SKILL.md"), "utf8");
|
|
164
|
+
writeFileSync(path, raw.replace(/^name:\s*.+$/m, `name: ${installedName}`), "utf8");
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
function artifactNameFromPath(path, fallback) {
|
|
169
|
+
const file = path.split(/[\\/]/).pop() ?? fallback;
|
|
170
|
+
if (file === "SKILL.md") {
|
|
171
|
+
const parent = path.split(/[\\/]/).at(-2);
|
|
172
|
+
return parent && parent.length > 0 ? parent : fallback;
|
|
173
|
+
}
|
|
174
|
+
return file.replace(/\.(md|toml)$/i, "") || fallback;
|
|
175
|
+
}
|
|
176
|
+
function fileExists(path) {
|
|
177
|
+
try {
|
|
178
|
+
readFileSync(path);
|
|
179
|
+
return true;
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
export * from "rafi-spec";
|
|
7
7
|
export { render, type TemplateContext } from "./template.js";
|
|
8
8
|
export { CONTENT_DIR, DOCS_DIR, parseRulePack, loadDefaults, loadDocsIndex, loadPreamble, loadPacksIndex, loadPack, loadAllPacks, packFilesOnDisk, type Defaults, type PackIndexEntry, type LoadedPack, type DocIndexEntry, } from "./content.js";
|
|
9
|
-
export { composeRulesMarkdown, composeAgentSystem, getAgent, buildConditionsHeader, emitAgentsMd, emitClaudeMd, emitCompiledBundles, emitClaudeAgents, renderPackBody, type CompileOptions, type AgentComposeOptions, type ComposedAgent, type EmitOptions, } from "./compile.js";
|
|
9
|
+
export { composeRulesMarkdown, composeAgentSystem, getAgent, buildConditionsHeader, CUSTOM_ARTIFACTS_NOTE, renderAgentsMd, renderClaudeMd, emitAgentsMd, emitClaudeMd, emitCompiledBundles, emitClaudeAgents, emitMappedClaudeAgents, emitCodexAgents, emitSkills, renderPackBody, type CompileOptions, type AgentComposeOptions, type ComposedAgent, type EmitOptions, type EmitMappedOptions, type EmitSkillsOptions, } from "./compile.js";
|
|
10
10
|
export { resolvePackRefs, resolveAgentPacks, type ConditionFlags, type ResolveContext, type ResolvableManifest, } from "./resolve.js";
|
|
11
11
|
export { SKILLS_DIR, parseSkillManifest, loadSkill, loadAllSkills, skillNames, } from "./skills.js";
|
|
12
12
|
export { AGENTS_DIR, AGENT_ROLES, parseAgentManifest, loadAgent, loadAllAgents, } from "./agents.js";
|
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
export * from "rafi-spec";
|
|
7
7
|
export { render } from "./template.js";
|
|
8
8
|
export { CONTENT_DIR, DOCS_DIR, parseRulePack, loadDefaults, loadDocsIndex, loadPreamble, loadPacksIndex, loadPack, loadAllPacks, packFilesOnDisk, } from "./content.js";
|
|
9
|
-
export { composeRulesMarkdown, composeAgentSystem, getAgent, buildConditionsHeader, emitAgentsMd, emitClaudeMd, emitCompiledBundles, emitClaudeAgents, renderPackBody, } from "./compile.js";
|
|
9
|
+
export { composeRulesMarkdown, composeAgentSystem, getAgent, buildConditionsHeader, CUSTOM_ARTIFACTS_NOTE, renderAgentsMd, renderClaudeMd, emitAgentsMd, emitClaudeMd, emitCompiledBundles, emitClaudeAgents, emitMappedClaudeAgents, emitCodexAgents, emitSkills, renderPackBody, } from "./compile.js";
|
|
10
10
|
export { resolvePackRefs, resolveAgentPacks, } from "./resolve.js";
|
|
11
11
|
export { SKILLS_DIR, parseSkillManifest, loadSkill, loadAllSkills, skillNames, } from "./skills.js";
|
|
12
12
|
export { AGENTS_DIR, AGENT_ROLES, parseAgentManifest, loadAgent, loadAllAgents, } from "./agents.js";
|
|
@@ -133,7 +133,7 @@ export declare const projectConfigSchema: {
|
|
|
133
133
|
readonly $id: "rafi/projectConfig";
|
|
134
134
|
readonly type: "object";
|
|
135
135
|
readonly additionalProperties: false;
|
|
136
|
-
readonly required: readonly ["appName", "timezone", "stack", "flags", "harness"];
|
|
136
|
+
readonly required: readonly ["appName", "timezone", "stack", "flags", "harness", "agent_files", "agents", "skills"];
|
|
137
137
|
readonly properties: {
|
|
138
138
|
readonly appName: {
|
|
139
139
|
readonly type: "string";
|
|
@@ -181,5 +181,65 @@ export declare const projectConfigSchema: {
|
|
|
181
181
|
};
|
|
182
182
|
};
|
|
183
183
|
};
|
|
184
|
+
readonly agent_files: {
|
|
185
|
+
readonly type: "object";
|
|
186
|
+
readonly additionalProperties: false;
|
|
187
|
+
readonly required: readonly ["mode", "codex", "claude"];
|
|
188
|
+
readonly properties: {
|
|
189
|
+
readonly mode: {
|
|
190
|
+
readonly enum: readonly ["append", "update", "overwrite"];
|
|
191
|
+
};
|
|
192
|
+
readonly codex: {
|
|
193
|
+
readonly type: "string";
|
|
194
|
+
readonly minLength: 1;
|
|
195
|
+
};
|
|
196
|
+
readonly claude: {
|
|
197
|
+
readonly type: "string";
|
|
198
|
+
readonly minLength: 1;
|
|
199
|
+
};
|
|
200
|
+
};
|
|
201
|
+
};
|
|
202
|
+
readonly agents: {
|
|
203
|
+
readonly type: "object";
|
|
204
|
+
readonly additionalProperties: {
|
|
205
|
+
readonly type: "object";
|
|
206
|
+
readonly additionalProperties: false;
|
|
207
|
+
readonly required: readonly ["artifact_source", "claude", "codex"];
|
|
208
|
+
readonly properties: {
|
|
209
|
+
readonly artifact_source: {
|
|
210
|
+
readonly enum: readonly ["rafi", "existing"];
|
|
211
|
+
};
|
|
212
|
+
readonly claude: {
|
|
213
|
+
readonly type: "string";
|
|
214
|
+
readonly minLength: 1;
|
|
215
|
+
};
|
|
216
|
+
readonly codex: {
|
|
217
|
+
readonly type: "string";
|
|
218
|
+
readonly minLength: 1;
|
|
219
|
+
};
|
|
220
|
+
};
|
|
221
|
+
};
|
|
222
|
+
};
|
|
223
|
+
readonly skills: {
|
|
224
|
+
readonly type: "object";
|
|
225
|
+
readonly additionalProperties: {
|
|
226
|
+
readonly type: "object";
|
|
227
|
+
readonly additionalProperties: false;
|
|
228
|
+
readonly required: readonly ["artifact_source", "claude", "codex"];
|
|
229
|
+
readonly properties: {
|
|
230
|
+
readonly artifact_source: {
|
|
231
|
+
readonly enum: readonly ["rafi", "existing"];
|
|
232
|
+
};
|
|
233
|
+
readonly claude: {
|
|
234
|
+
readonly type: "string";
|
|
235
|
+
readonly minLength: 1;
|
|
236
|
+
};
|
|
237
|
+
readonly codex: {
|
|
238
|
+
readonly type: "string";
|
|
239
|
+
readonly minLength: 1;
|
|
240
|
+
};
|
|
241
|
+
};
|
|
242
|
+
};
|
|
243
|
+
};
|
|
184
244
|
};
|
|
185
245
|
};
|
|
@@ -68,11 +68,25 @@ const boolRecord = (keys) => ({
|
|
|
68
68
|
required: keys,
|
|
69
69
|
properties: Object.fromEntries(keys.map((k) => [k, { type: "boolean" }])),
|
|
70
70
|
});
|
|
71
|
+
const runtimeArtifactPaths = {
|
|
72
|
+
type: "object",
|
|
73
|
+
additionalProperties: false,
|
|
74
|
+
required: ["artifact_source", "claude", "codex"],
|
|
75
|
+
properties: {
|
|
76
|
+
artifact_source: { enum: ["rafi", "existing"] },
|
|
77
|
+
claude: { type: "string", minLength: 1 },
|
|
78
|
+
codex: { type: "string", minLength: 1 },
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
const artifactPathMap = {
|
|
82
|
+
type: "object",
|
|
83
|
+
additionalProperties: runtimeArtifactPaths,
|
|
84
|
+
};
|
|
71
85
|
export const projectConfigSchema = {
|
|
72
86
|
$id: "rafi/projectConfig",
|
|
73
87
|
type: "object",
|
|
74
88
|
additionalProperties: false,
|
|
75
|
-
required: ["appName", "timezone", "stack", "flags", "harness"],
|
|
89
|
+
required: ["appName", "timezone", "stack", "flags", "harness", "agent_files", "agents", "skills"],
|
|
76
90
|
properties: {
|
|
77
91
|
appName: { type: "string", minLength: 1 },
|
|
78
92
|
timezone: { type: "string", minLength: 1 },
|
|
@@ -91,5 +105,17 @@ export const projectConfigSchema = {
|
|
|
91
105
|
qa: { type: "boolean" },
|
|
92
106
|
},
|
|
93
107
|
},
|
|
108
|
+
agent_files: {
|
|
109
|
+
type: "object",
|
|
110
|
+
additionalProperties: false,
|
|
111
|
+
required: ["mode", "codex", "claude"],
|
|
112
|
+
properties: {
|
|
113
|
+
mode: { enum: ["append", "update", "overwrite"] },
|
|
114
|
+
codex: { type: "string", minLength: 1 },
|
|
115
|
+
claude: { type: "string", minLength: 1 },
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
agents: artifactPathMap,
|
|
119
|
+
skills: artifactPathMap,
|
|
94
120
|
},
|
|
95
121
|
};
|
|
@@ -98,8 +98,23 @@ export interface HarnessConfig {
|
|
|
98
98
|
targets: HarnessTarget[];
|
|
99
99
|
qa: boolean;
|
|
100
100
|
}
|
|
101
|
+
/** How Rafi should handle existing root instruction files. */
|
|
102
|
+
export type AgentFileMode = "append" | "update" | "overwrite";
|
|
103
|
+
/** Root instruction files used by Codex and Claude. */
|
|
104
|
+
export interface AgentFilesConfig {
|
|
105
|
+
mode: AgentFileMode;
|
|
106
|
+
codex: string;
|
|
107
|
+
claude: string;
|
|
108
|
+
}
|
|
109
|
+
/** Per-runtime paths for a skill or agent artifact. */
|
|
110
|
+
export type ArtifactSource = "rafi" | "existing";
|
|
111
|
+
export interface RuntimeArtifactConfig {
|
|
112
|
+
artifact_source: ArtifactSource;
|
|
113
|
+
claude: string;
|
|
114
|
+
codex: string;
|
|
115
|
+
}
|
|
101
116
|
/**
|
|
102
|
-
* The committed `
|
|
117
|
+
* The committed `rafi-config.yaml` in a target repo. Skipping the walkthrough uses
|
|
103
118
|
* the library defaults, which reproduce today's hardcoded guidance.
|
|
104
119
|
*/
|
|
105
120
|
export interface ProjectConfig {
|
|
@@ -108,4 +123,7 @@ export interface ProjectConfig {
|
|
|
108
123
|
stack: ProjectStack;
|
|
109
124
|
flags: ProjectFlags;
|
|
110
125
|
harness: HarnessConfig;
|
|
126
|
+
agent_files: AgentFilesConfig;
|
|
127
|
+
agents: Record<string, RuntimeArtifactConfig>;
|
|
128
|
+
skills: Record<string, RuntimeArtifactConfig>;
|
|
111
129
|
}
|
|
@@ -75,11 +75,27 @@ const boolRecord = (keys: string[]) => ({
|
|
|
75
75
|
properties: Object.fromEntries(keys.map((k) => [k, { type: "boolean" }])),
|
|
76
76
|
});
|
|
77
77
|
|
|
78
|
+
const runtimeArtifactPaths = {
|
|
79
|
+
type: "object",
|
|
80
|
+
additionalProperties: false,
|
|
81
|
+
required: ["artifact_source", "claude", "codex"],
|
|
82
|
+
properties: {
|
|
83
|
+
artifact_source: { enum: ["rafi", "existing"] },
|
|
84
|
+
claude: { type: "string", minLength: 1 },
|
|
85
|
+
codex: { type: "string", minLength: 1 },
|
|
86
|
+
},
|
|
87
|
+
} as const;
|
|
88
|
+
|
|
89
|
+
const artifactPathMap = {
|
|
90
|
+
type: "object",
|
|
91
|
+
additionalProperties: runtimeArtifactPaths,
|
|
92
|
+
} as const;
|
|
93
|
+
|
|
78
94
|
export const projectConfigSchema = {
|
|
79
95
|
$id: "rafi/projectConfig",
|
|
80
96
|
type: "object",
|
|
81
97
|
additionalProperties: false,
|
|
82
|
-
required: ["appName", "timezone", "stack", "flags", "harness"],
|
|
98
|
+
required: ["appName", "timezone", "stack", "flags", "harness", "agent_files", "agents", "skills"],
|
|
83
99
|
properties: {
|
|
84
100
|
appName: { type: "string", minLength: 1 },
|
|
85
101
|
timezone: { type: "string", minLength: 1 },
|
|
@@ -98,5 +114,17 @@ export const projectConfigSchema = {
|
|
|
98
114
|
qa: { type: "boolean" },
|
|
99
115
|
},
|
|
100
116
|
},
|
|
117
|
+
agent_files: {
|
|
118
|
+
type: "object",
|
|
119
|
+
additionalProperties: false,
|
|
120
|
+
required: ["mode", "codex", "claude"],
|
|
121
|
+
properties: {
|
|
122
|
+
mode: { enum: ["append", "update", "overwrite"] },
|
|
123
|
+
codex: { type: "string", minLength: 1 },
|
|
124
|
+
claude: { type: "string", minLength: 1 },
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
agents: artifactPathMap,
|
|
128
|
+
skills: artifactPathMap,
|
|
101
129
|
},
|
|
102
130
|
} as const;
|
|
@@ -121,8 +121,27 @@ export interface HarnessConfig {
|
|
|
121
121
|
qa: boolean;
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
+
/** How Rafi should handle existing root instruction files. */
|
|
125
|
+
export type AgentFileMode = "append" | "update" | "overwrite";
|
|
126
|
+
|
|
127
|
+
/** Root instruction files used by Codex and Claude. */
|
|
128
|
+
export interface AgentFilesConfig {
|
|
129
|
+
mode: AgentFileMode;
|
|
130
|
+
codex: string;
|
|
131
|
+
claude: string;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** Per-runtime paths for a skill or agent artifact. */
|
|
135
|
+
export type ArtifactSource = "rafi" | "existing";
|
|
136
|
+
|
|
137
|
+
export interface RuntimeArtifactConfig {
|
|
138
|
+
artifact_source: ArtifactSource;
|
|
139
|
+
claude: string;
|
|
140
|
+
codex: string;
|
|
141
|
+
}
|
|
142
|
+
|
|
124
143
|
/**
|
|
125
|
-
* The committed `
|
|
144
|
+
* The committed `rafi-config.yaml` in a target repo. Skipping the walkthrough uses
|
|
126
145
|
* the library defaults, which reproduce today's hardcoded guidance.
|
|
127
146
|
*/
|
|
128
147
|
export interface ProjectConfig {
|
|
@@ -131,4 +150,7 @@ export interface ProjectConfig {
|
|
|
131
150
|
stack: ProjectStack;
|
|
132
151
|
flags: ProjectFlags;
|
|
133
152
|
harness: HarnessConfig;
|
|
153
|
+
agent_files: AgentFilesConfig;
|
|
154
|
+
agents: Record<string, RuntimeArtifactConfig>;
|
|
155
|
+
skills: Record<string, RuntimeArtifactConfig>;
|
|
134
156
|
}
|