@ludecker/aaac 1.1.1 → 1.1.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.
- package/package.json +1 -1
- package/src/generators/generate-commands.mjs +17 -9
- package/src/run-engine/advance-phase.mjs +2 -2
- package/src/run-engine/gate-write.mjs +14 -2
- package/src/run-engine/init-run.mjs +41 -0
- package/src/run-engine/lib.mjs +33 -0
- package/src/run-engine/record-task.mjs +7 -1
- package/src/run-engine/stop-check.mjs +7 -1
- package/src/run-engine/verify-website-build.mjs +67 -30
- package/templates/cursor/aaac/capabilities/registry.json +14 -16
- package/templates/cursor/aaac/graph.project.yaml +4 -204
- package/templates/cursor/aaac/ontology.md +17 -32
- package/templates/cursor/aaac/project.config.json +4 -1
- package/templates/cursor/aaac/run/schema.json +3 -1
- package/templates/cursor/aaac/scripts/run-engine/advance-phase.mjs +2 -2
- package/templates/cursor/aaac/scripts/run-engine/gate-write.mjs +14 -2
- package/templates/cursor/aaac/scripts/run-engine/init-run.mjs +41 -0
- package/templates/cursor/aaac/scripts/run-engine/lib.mjs +33 -0
- package/templates/cursor/aaac/scripts/run-engine/record-task.mjs +7 -1
- package/templates/cursor/aaac/scripts/run-engine/stop-check.mjs +7 -1
- package/templates/cursor/aaac/scripts/run-engine/verify-website-build.mjs +67 -30
- package/templates/cursor/agents/playwright-check-run.md +8 -26
- package/templates/cursor/agents/release-git.md +2 -2
- package/templates/cursor/agents/unit-test-run.md +3 -7
- package/templates/cursor/skills/shared/governance/implementation/SKILL.md +25 -396
- package/templates/cursor/skills/shared/testing/SKILL.md +2 -2
- package/templates/cursor/skills/shared/verbs/check/orchestrator/SKILL.md +1 -1
- package/templates/cursor/skills/shared/verification/SKILL.md +2 -2
- package/templates/docs/agentic_architecture.md +86 -166
package/package.json
CHANGED
|
@@ -50,10 +50,13 @@ function isFixCommand(cmd, entry) {
|
|
|
50
50
|
function writeFixCmd(cmd, entry = null) {
|
|
51
51
|
const canonical = entry?.alias ?? cmd;
|
|
52
52
|
const isBug = canonical === "fix-bug" || cmd === "bug-fix";
|
|
53
|
-
const
|
|
54
|
-
const
|
|
55
|
-
? "Domain slug **recommended**
|
|
56
|
-
: "
|
|
53
|
+
const hasResolver = Boolean(entry?.resolver);
|
|
54
|
+
const domainLine = hasResolver
|
|
55
|
+
? "Domain slug **recommended** when your project overlay defines domain resolvers (see `graph.project.yaml`)."
|
|
56
|
+
: "Domain slug optional.";
|
|
57
|
+
const dispatchLine = hasResolver
|
|
58
|
+
? `3. resolver **\`${entry.resolver}\`** (project overlay in \`graph.project.yaml\`)`
|
|
59
|
+
: `3. [verb-fix orchestrator](../skills/shared/verbs/fix/orchestrator/SKILL.md) — object \`${isBug ? "feature" : "module"}\``;
|
|
57
60
|
const aliasLine =
|
|
58
61
|
cmd !== canonical
|
|
59
62
|
? `\n\n> Alias → \`/${canonical}\`. See [${canonical}.md](${canonical}.md).\n`
|
|
@@ -71,10 +74,10 @@ AAAC: \`/${cmd} <domain> "<intent>"\`
|
|
|
71
74
|
|
|
72
75
|
1. [.cursor/aaac/dispatch.md](../aaac/dispatch.md)
|
|
73
76
|
2. [.cursor/aaac/graph.yaml](../aaac/graph.yaml) — **\`${canonical}\`**
|
|
74
|
-
|
|
75
|
-
4. [investigation/SKILL.md](../skills/shared/investigation/SKILL.md) Mode A + domain
|
|
77
|
+
${dispatchLine}
|
|
78
|
+
4. [investigation/SKILL.md](../skills/shared/investigation/SKILL.md) Mode A${hasResolver ? " + domain `fix_mode` when resolver routes to a domain orchestrator" : ""}
|
|
76
79
|
|
|
77
|
-
${
|
|
80
|
+
${domainLine}
|
|
78
81
|
|
|
79
82
|
## Swarm (mandatory)
|
|
80
83
|
|
|
@@ -90,8 +93,8 @@ Contract: [${canonical}.yaml](../aaac/contracts/commands/${canonical}.yaml)
|
|
|
90
93
|
## Example
|
|
91
94
|
|
|
92
95
|
\`\`\`text
|
|
93
|
-
/${cmd}
|
|
94
|
-
/${cmd}
|
|
96
|
+
/${cmd} payments "Webhook handler drops events on retry"
|
|
97
|
+
/${cmd} api "Auth middleware returns 500 on expired token"
|
|
95
98
|
\`\`\`
|
|
96
99
|
`;
|
|
97
100
|
fs.writeFileSync(path.join(commandsDir, `${cmd}.md`), body);
|
|
@@ -247,6 +250,11 @@ const written = new Set();
|
|
|
247
250
|
|
|
248
251
|
for (const [cmd, entry] of Object.entries(command_overrides)) {
|
|
249
252
|
if (KEEP_EXTRA.has(`${cmd}.md`)) continue;
|
|
253
|
+
if (isFixCommand(cmd, entry)) {
|
|
254
|
+
writeFixCmd(cmd, entry);
|
|
255
|
+
written.add(cmd);
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
250
258
|
writeCmd(cmd, entry);
|
|
251
259
|
written.add(cmd);
|
|
252
260
|
}
|
|
@@ -102,7 +102,7 @@ if (
|
|
|
102
102
|
manifest.updated_at = isoNow();
|
|
103
103
|
writeJson(manifestPath, manifest);
|
|
104
104
|
console.error(
|
|
105
|
-
"
|
|
105
|
+
"App verify failed (see project.config.json verify). Fix errors, then re-run:\n" +
|
|
106
106
|
` node .cursor/aaac/scripts/run-engine/verify-website-build.mjs --run-id ${runId}\n` +
|
|
107
107
|
detail,
|
|
108
108
|
);
|
|
@@ -112,7 +112,7 @@ if (
|
|
|
112
112
|
event: "verify_website_pass",
|
|
113
113
|
phase: completedPhase,
|
|
114
114
|
phase_kind: manifest.phase_kind,
|
|
115
|
-
detail: "
|
|
115
|
+
detail: "app verify gate",
|
|
116
116
|
level: "info",
|
|
117
117
|
});
|
|
118
118
|
}
|
|
@@ -53,10 +53,22 @@ process.stdin.on("end", () => {
|
|
|
53
53
|
if (!conversationId) allow();
|
|
54
54
|
|
|
55
55
|
const active = loadActiveRun(conversationId);
|
|
56
|
-
if (
|
|
56
|
+
if (
|
|
57
|
+
!active?.run_id ||
|
|
58
|
+
active.status === "completed" ||
|
|
59
|
+
active.status === "cancelled"
|
|
60
|
+
) {
|
|
61
|
+
allow();
|
|
62
|
+
}
|
|
57
63
|
|
|
58
64
|
const manifest = loadRunManifest(active.run_id);
|
|
59
|
-
if (
|
|
65
|
+
if (
|
|
66
|
+
!manifest ||
|
|
67
|
+
manifest.status === "completed" ||
|
|
68
|
+
manifest.status === "cancelled"
|
|
69
|
+
) {
|
|
70
|
+
allow();
|
|
71
|
+
}
|
|
60
72
|
if (manifest.conversation_id && manifest.conversation_id !== conversationId) allow();
|
|
61
73
|
|
|
62
74
|
const enforcement = loadEnforcement();
|
|
@@ -11,6 +11,11 @@ import {
|
|
|
11
11
|
phaseKind,
|
|
12
12
|
writeJson,
|
|
13
13
|
saveActiveRun,
|
|
14
|
+
loadActiveRun,
|
|
15
|
+
loadRunManifest,
|
|
16
|
+
clearActiveRun,
|
|
17
|
+
cancelRunManifest,
|
|
18
|
+
isUserStopIntent,
|
|
14
19
|
conversationIdFromHook,
|
|
15
20
|
promptFromHook,
|
|
16
21
|
} from "./lib.mjs";
|
|
@@ -41,6 +46,42 @@ try {
|
|
|
41
46
|
|
|
42
47
|
const prompt = process.argv[2] ?? promptFromHook(hook);
|
|
43
48
|
const conversationId = conversationIdFromHook(hook);
|
|
49
|
+
|
|
50
|
+
if (isUserStopIntent(prompt) && conversationId) {
|
|
51
|
+
const active = loadActiveRun(conversationId);
|
|
52
|
+
let cancelledRunId = null;
|
|
53
|
+
if (active?.run_id) {
|
|
54
|
+
const existing = loadRunManifest(active.run_id);
|
|
55
|
+
if (
|
|
56
|
+
existing &&
|
|
57
|
+
existing.status !== "completed" &&
|
|
58
|
+
existing.status !== "cancelled"
|
|
59
|
+
) {
|
|
60
|
+
cancelRunManifest(existing, prompt.trim());
|
|
61
|
+
recordLog(existing, {
|
|
62
|
+
event: "run_cancelled",
|
|
63
|
+
phase: existing.phase,
|
|
64
|
+
phase_kind: existing.phase_kind,
|
|
65
|
+
detail: `user stop: ${prompt.trim()}`,
|
|
66
|
+
level: "info",
|
|
67
|
+
});
|
|
68
|
+
recordDecision(existing, {
|
|
69
|
+
phase: existing.phase ?? "dispatch",
|
|
70
|
+
decision: "user_stop",
|
|
71
|
+
reason: "User requested stop",
|
|
72
|
+
evidence: prompt.trim(),
|
|
73
|
+
});
|
|
74
|
+
writeJson(`${runDir(active.run_id)}/run.json`, existing);
|
|
75
|
+
cancelledRunId = active.run_id;
|
|
76
|
+
}
|
|
77
|
+
clearActiveRun(conversationId);
|
|
78
|
+
}
|
|
79
|
+
console.log(
|
|
80
|
+
JSON.stringify({ ok: true, aaac: false, cancelled: cancelledRunId }),
|
|
81
|
+
);
|
|
82
|
+
process.exit(0);
|
|
83
|
+
}
|
|
84
|
+
|
|
44
85
|
const parsed = parseAaacPrompt(prompt);
|
|
45
86
|
|
|
46
87
|
if (!parsed) {
|
package/src/run-engine/lib.mjs
CHANGED
|
@@ -139,3 +139,36 @@ export function phaseKind(phase, registry) {
|
|
|
139
139
|
export function promptFromHook(hook) {
|
|
140
140
|
return hook?.prompt ?? hook?.text ?? hook?.content ?? "";
|
|
141
141
|
}
|
|
142
|
+
|
|
143
|
+
/** User explicitly asked to halt the current Run (short prompts only). */
|
|
144
|
+
export function isUserStopIntent(text) {
|
|
145
|
+
if (!text || typeof text !== "string") return false;
|
|
146
|
+
const trimmed = text.trim();
|
|
147
|
+
if (trimmed.length > 60) return false;
|
|
148
|
+
return (
|
|
149
|
+
/^(stop|cancel|abort)([.!?]*)$/i.test(trimmed) ||
|
|
150
|
+
/^(please\s+)?(stop|cancel|abort)([.!?]*)$/i.test(trimmed) ||
|
|
151
|
+
/^(stop|cancel|abort)\s+(the\s+)?run([.!?]*)$/i.test(trimmed)
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export function cancelRunManifest(manifest, evidence = "user_stop") {
|
|
156
|
+
manifest.status = "cancelled";
|
|
157
|
+
manifest.awaiting_approval = false;
|
|
158
|
+
manifest.blocked_reason = null;
|
|
159
|
+
manifest.updated_at = isoNow();
|
|
160
|
+
if (manifest.enforcement) {
|
|
161
|
+
manifest.enforcement.edit_allowed = true;
|
|
162
|
+
}
|
|
163
|
+
return manifest;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export function clearActiveRun(conversationId) {
|
|
167
|
+
if (!conversationId) return;
|
|
168
|
+
const filePath = activeRunPath(conversationId);
|
|
169
|
+
try {
|
|
170
|
+
fs.unlinkSync(filePath);
|
|
171
|
+
} catch {
|
|
172
|
+
// already cleared
|
|
173
|
+
}
|
|
174
|
+
}
|
|
@@ -34,7 +34,13 @@ process.stdin.on("end", () => {
|
|
|
34
34
|
if (!active?.run_id) allow();
|
|
35
35
|
|
|
36
36
|
const manifest = loadRunManifest(active.run_id);
|
|
37
|
-
if (
|
|
37
|
+
if (
|
|
38
|
+
!manifest ||
|
|
39
|
+
manifest.status === "completed" ||
|
|
40
|
+
manifest.status === "cancelled"
|
|
41
|
+
) {
|
|
42
|
+
allow();
|
|
43
|
+
}
|
|
38
44
|
if (manifest.conversation_id && manifest.conversation_id !== conversationId) allow();
|
|
39
45
|
|
|
40
46
|
manifest.swarm = manifest.swarm ?? {};
|
|
@@ -28,7 +28,13 @@ process.stdin.on("end", () => {
|
|
|
28
28
|
if (!active?.run_id) process.exit(0);
|
|
29
29
|
|
|
30
30
|
const manifest = loadRunManifest(active.run_id);
|
|
31
|
-
if (
|
|
31
|
+
if (
|
|
32
|
+
!manifest ||
|
|
33
|
+
manifest.status === "completed" ||
|
|
34
|
+
manifest.status === "cancelled"
|
|
35
|
+
) {
|
|
36
|
+
process.exit(0);
|
|
37
|
+
}
|
|
32
38
|
|
|
33
39
|
const remaining = [manifest.phase, ...(manifest.pending ?? [])].filter(Boolean);
|
|
34
40
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* Verify
|
|
4
|
-
*
|
|
3
|
+
* Verify app static assets + production build (project overlay).
|
|
4
|
+
* Skips when `.cursor/aaac/project.config.json` has `verify.enabled: false`.
|
|
5
5
|
*
|
|
6
6
|
* Usage:
|
|
7
7
|
* node verify-website-build.mjs [--run-id <run_id>] [--skip-build]
|
|
@@ -9,23 +9,42 @@
|
|
|
9
9
|
import fs from "fs";
|
|
10
10
|
import path from "path";
|
|
11
11
|
import { spawnSync } from "child_process";
|
|
12
|
-
import {
|
|
13
|
-
import { REPO_ROOT, runDir, isoNow, writeJson } from "./lib.mjs";
|
|
12
|
+
import { runDir, isoNow, writeJson, readJson } from "./lib.mjs";
|
|
14
13
|
|
|
15
|
-
const
|
|
16
|
-
const WEBSITE_ROOT = path.join(REPO_ROOT, "apps/website");
|
|
17
|
-
const INDEX_HTML = path.join(WEBSITE_ROOT, "index.html");
|
|
14
|
+
const PROJECT_ROOT = process.cwd();
|
|
18
15
|
|
|
19
16
|
const args = process.argv.slice(2);
|
|
20
17
|
const runIdIdx = args.indexOf("--run-id");
|
|
21
18
|
const runId = runIdIdx >= 0 ? args[runIdIdx + 1] : null;
|
|
22
19
|
const skipBuild = args.includes("--skip-build");
|
|
23
20
|
|
|
21
|
+
function loadVerifyConfig() {
|
|
22
|
+
const configPath = path.join(PROJECT_ROOT, ".cursor/aaac/project.config.json");
|
|
23
|
+
const config = readJson(configPath, { verify: { enabled: false } });
|
|
24
|
+
const verify = config.verify ?? { enabled: false };
|
|
25
|
+
if (!verify.enabled) {
|
|
26
|
+
return { enabled: false };
|
|
27
|
+
}
|
|
28
|
+
const appRootRel = verify.app_root ?? "apps/website";
|
|
29
|
+
const indexRel =
|
|
30
|
+
verify.index_html ?? path.join(appRootRel, "index.html").replace(/\\/g, "/");
|
|
31
|
+
const appRoot = path.join(PROJECT_ROOT, appRootRel);
|
|
32
|
+
const indexHtml = path.join(PROJECT_ROOT, indexRel);
|
|
33
|
+
const build = verify.build ?? { command: "pnpm", args: ["run", "build"] };
|
|
34
|
+
return { enabled: true, appRoot, indexHtml, build, appRootRel };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const verifyConfig = loadVerifyConfig();
|
|
38
|
+
|
|
24
39
|
const results = {
|
|
25
40
|
status: "pass",
|
|
26
41
|
checked_at: isoNow(),
|
|
27
42
|
static_assets: { status: "pass", missing: [] },
|
|
28
|
-
build: {
|
|
43
|
+
build: {
|
|
44
|
+
status: skipBuild ? "skipped" : "pending",
|
|
45
|
+
command: null,
|
|
46
|
+
},
|
|
47
|
+
verify_config: verifyConfig.enabled ? "enabled" : "disabled",
|
|
29
48
|
};
|
|
30
49
|
|
|
31
50
|
function fail(section, detail) {
|
|
@@ -40,11 +59,11 @@ function fail(section, detail) {
|
|
|
40
59
|
console.error(`[verify-website-build] FAIL ${section}: ${detail}`);
|
|
41
60
|
}
|
|
42
61
|
|
|
43
|
-
function resolveRootAsset(assetPath) {
|
|
62
|
+
function resolveRootAsset(assetPath, websiteRoot, appRootRel) {
|
|
44
63
|
const rel = assetPath.replace(/^\//, "");
|
|
45
64
|
const candidates = [
|
|
46
|
-
path.join(
|
|
47
|
-
path.join(
|
|
65
|
+
path.join(websiteRoot, "public", rel),
|
|
66
|
+
path.join(websiteRoot, rel),
|
|
48
67
|
];
|
|
49
68
|
for (const candidate of candidates) {
|
|
50
69
|
if (fs.existsSync(candidate)) {
|
|
@@ -54,13 +73,13 @@ function resolveRootAsset(assetPath) {
|
|
|
54
73
|
return null;
|
|
55
74
|
}
|
|
56
75
|
|
|
57
|
-
function checkStaticAssets() {
|
|
58
|
-
if (!fs.existsSync(
|
|
59
|
-
fail("static_assets", `missing index.html at ${
|
|
76
|
+
function checkStaticAssets(indexHtml, websiteRoot, appRootRel) {
|
|
77
|
+
if (!fs.existsSync(indexHtml)) {
|
|
78
|
+
fail("static_assets", `missing index.html at ${indexHtml}`);
|
|
60
79
|
return;
|
|
61
80
|
}
|
|
62
81
|
|
|
63
|
-
const html = fs.readFileSync(
|
|
82
|
+
const html = fs.readFileSync(indexHtml, "utf8");
|
|
64
83
|
const rootRefs = [
|
|
65
84
|
...html.matchAll(/\b(?:href|src)="(\/[^"#?]+)"/g),
|
|
66
85
|
].map((match) => match[1]);
|
|
@@ -70,28 +89,28 @@ function checkStaticAssets() {
|
|
|
70
89
|
if (seen.has(ref) || ref.startsWith("//")) continue;
|
|
71
90
|
seen.add(ref);
|
|
72
91
|
|
|
73
|
-
const resolved = resolveRootAsset(ref);
|
|
92
|
+
const resolved = resolveRootAsset(ref, websiteRoot, appRootRel);
|
|
74
93
|
if (!resolved) {
|
|
75
94
|
fail(
|
|
76
95
|
"static_assets",
|
|
77
|
-
`${ref} not found under
|
|
96
|
+
`${ref} not found under ${appRootRel}/public/ or ${appRootRel}/`,
|
|
78
97
|
);
|
|
79
98
|
}
|
|
80
99
|
}
|
|
81
100
|
}
|
|
82
101
|
|
|
83
|
-
function runBuild() {
|
|
102
|
+
function runBuild(build) {
|
|
84
103
|
if (skipBuild) return;
|
|
85
104
|
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
},
|
|
94
|
-
);
|
|
105
|
+
const command = build.command ?? "pnpm";
|
|
106
|
+
const buildArgs = build.args ?? ["run", "build"];
|
|
107
|
+
results.build.command = [command, ...buildArgs].join(" ");
|
|
108
|
+
|
|
109
|
+
const proc = spawnSync(command, buildArgs, {
|
|
110
|
+
cwd: build.cwd ? path.join(PROJECT_ROOT, build.cwd) : PROJECT_ROOT,
|
|
111
|
+
encoding: "utf8",
|
|
112
|
+
env: { ...process.env, CI: "1" },
|
|
113
|
+
});
|
|
95
114
|
|
|
96
115
|
if (proc.status !== 0) {
|
|
97
116
|
const detail = [proc.stderr, proc.stdout].filter(Boolean).join("\n").trim();
|
|
@@ -114,12 +133,13 @@ function writeArtifact() {
|
|
|
114
133
|
const yaml = [
|
|
115
134
|
`status: ${results.status}`,
|
|
116
135
|
`checked_at: ${results.checked_at}`,
|
|
136
|
+
`verify_config: ${results.verify_config}`,
|
|
117
137
|
"static_assets:",
|
|
118
138
|
` status: ${results.static_assets.status}`,
|
|
119
139
|
` missing: ${JSON.stringify(results.static_assets.missing)}`,
|
|
120
140
|
"build:",
|
|
121
141
|
` status: ${results.build.status}`,
|
|
122
|
-
` command: ${JSON.stringify(results.build.command)}
|
|
142
|
+
results.build.command ? ` command: ${JSON.stringify(results.build.command)}` : null,
|
|
123
143
|
results.build.exit_code != null ? ` exit_code: ${results.build.exit_code}` : null,
|
|
124
144
|
results.build.detail ? ` detail: ${JSON.stringify(results.build.detail)}` : null,
|
|
125
145
|
]
|
|
@@ -140,8 +160,25 @@ function writeArtifact() {
|
|
|
140
160
|
}
|
|
141
161
|
}
|
|
142
162
|
|
|
143
|
-
|
|
144
|
-
|
|
163
|
+
if (!verifyConfig.enabled) {
|
|
164
|
+
results.static_assets.status = "skipped";
|
|
165
|
+
results.build.status = "skipped";
|
|
166
|
+
results.build.command = null;
|
|
167
|
+
writeArtifact();
|
|
168
|
+
console.log(JSON.stringify({ ok: true, skipped: true, reason: "verify.disabled", ...results }));
|
|
169
|
+
process.exit(0);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
results.build.command = skipBuild
|
|
173
|
+
? null
|
|
174
|
+
: [verifyConfig.build.command, ...(verifyConfig.build.args ?? [])].join(" ");
|
|
175
|
+
|
|
176
|
+
checkStaticAssets(
|
|
177
|
+
verifyConfig.indexHtml,
|
|
178
|
+
verifyConfig.appRoot,
|
|
179
|
+
verifyConfig.appRootRel,
|
|
180
|
+
);
|
|
181
|
+
runBuild(verifyConfig.build);
|
|
145
182
|
writeArtifact();
|
|
146
183
|
|
|
147
184
|
console.log(JSON.stringify({ ok: results.status === "pass", ...results }));
|
|
@@ -2,44 +2,43 @@
|
|
|
2
2
|
"version": 2,
|
|
3
3
|
"capabilities": {
|
|
4
4
|
"ui-design": {
|
|
5
|
-
"description": "
|
|
5
|
+
"description": "Presentational components, token-based styling",
|
|
6
6
|
"providers": [
|
|
7
|
-
{ "id": "
|
|
7
|
+
{ "id": "component", "type": "skill", "path": "skills/shared/component" }
|
|
8
8
|
]
|
|
9
9
|
},
|
|
10
10
|
"ux-design": {
|
|
11
|
-
"description": "Editorial readability,
|
|
11
|
+
"description": "Editorial readability, navigation clarity",
|
|
12
12
|
"providers": [
|
|
13
|
-
{ "id": "
|
|
13
|
+
{ "id": "documentation", "type": "skill", "path": "skills/shared/documentation" }
|
|
14
14
|
]
|
|
15
15
|
},
|
|
16
16
|
"api-design": {
|
|
17
17
|
"description": "Contracts and validation at boundaries",
|
|
18
18
|
"providers": [
|
|
19
|
-
{ "id": "
|
|
19
|
+
{ "id": "integration", "type": "skill", "path": "skills/shared/integration" }
|
|
20
20
|
]
|
|
21
21
|
},
|
|
22
22
|
"database-design": {
|
|
23
|
-
"description": "Schema, migrations,
|
|
23
|
+
"description": "Schema, migrations, persistence boundaries",
|
|
24
24
|
"providers": [
|
|
25
|
-
{ "id": "
|
|
26
|
-
{ "id": "supabase-mcp", "type": "mcp", "optional": true, "note": "Apply migrations and RLS via Supabase MCP" }
|
|
25
|
+
{ "id": "schema", "type": "skill", "path": "skills/shared/schema" }
|
|
27
26
|
]
|
|
28
27
|
},
|
|
29
28
|
"security": {
|
|
30
|
-
"description": "Auth,
|
|
29
|
+
"description": "Auth, secrets, access control at boundaries",
|
|
31
30
|
"providers": [
|
|
32
|
-
{ "id": "
|
|
31
|
+
{ "id": "architecture", "type": "skill", "path": "skills/shared/architecture" }
|
|
33
32
|
]
|
|
34
33
|
},
|
|
35
34
|
"infrastructure": {
|
|
36
|
-
"description": "Deploy,
|
|
35
|
+
"description": "Deploy, hosting, environment configuration",
|
|
37
36
|
"providers": [
|
|
38
|
-
{ "id": "
|
|
37
|
+
{ "id": "integration", "type": "skill", "path": "skills/shared/integration" }
|
|
39
38
|
]
|
|
40
39
|
},
|
|
41
40
|
"layer-boundaries": {
|
|
42
|
-
"description": "SSOT, import direction,
|
|
41
|
+
"description": "SSOT, import direction, module layers",
|
|
43
42
|
"providers": [
|
|
44
43
|
{ "id": "architecture", "type": "skill", "path": "skills/shared/architecture" }
|
|
45
44
|
]
|
|
@@ -65,8 +64,7 @@
|
|
|
65
64
|
"migration-model": {
|
|
66
65
|
"description": "Migration scripts and apply procedure",
|
|
67
66
|
"providers": [
|
|
68
|
-
{ "id": "migration", "type": "skill", "path": "skills/shared/migration" }
|
|
69
|
-
{ "id": "supabase-mcp", "type": "mcp", "optional": true }
|
|
67
|
+
{ "id": "migration", "type": "skill", "path": "skills/shared/migration" }
|
|
70
68
|
]
|
|
71
69
|
},
|
|
72
70
|
"workflow-model": {
|
|
@@ -76,7 +74,7 @@
|
|
|
76
74
|
]
|
|
77
75
|
},
|
|
78
76
|
"integration-model": {
|
|
79
|
-
"description": "API routes, webhooks,
|
|
77
|
+
"description": "API routes, webhooks, external adapters",
|
|
80
78
|
"providers": [
|
|
81
79
|
{ "id": "integration", "type": "skill", "path": "skills/shared/integration" }
|
|
82
80
|
]
|