@soleri/forge 5.2.0 → 5.4.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/dist/scaffolder.js +150 -2
- package/dist/scaffolder.js.map +1 -1
- package/dist/templates/claude-md-template.js +90 -1
- package/dist/templates/claude-md-template.js.map +1 -1
- package/dist/templates/domain-facade.d.ts +4 -0
- package/dist/templates/domain-facade.js +4 -0
- package/dist/templates/domain-facade.js.map +1 -1
- package/dist/templates/entry-point.js +32 -0
- package/dist/templates/entry-point.js.map +1 -1
- package/dist/templates/setup-script.js +26 -1
- package/dist/templates/setup-script.js.map +1 -1
- package/dist/templates/test-facades.js +173 -3
- package/dist/templates/test-facades.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/scaffolder.test.ts +2 -2
- package/src/scaffolder.ts +153 -2
- package/src/templates/claude-md-template.ts +181 -0
- package/src/templates/domain-facade.ts +4 -0
- package/src/templates/entry-point.ts +32 -0
- package/src/templates/setup-script.ts +28 -1
- package/src/templates/test-facades.ts +173 -3
|
@@ -123,6 +123,29 @@ ${domainDescribes}
|
|
|
123
123
|
if (stats.totalEntries === 0) {
|
|
124
124
|
recommendations.push('Vault is empty');
|
|
125
125
|
}
|
|
126
|
+
// Check hook status
|
|
127
|
+
const { readdirSync } = await import('node:fs');
|
|
128
|
+
const agentClaudeDir = joinPath(__dirname, '..', '.claude');
|
|
129
|
+
const globalClaudeDir = joinPath(homedir(), '.claude');
|
|
130
|
+
const hookStatus = { agent: [] as string[], global: [] as string[], missing: [] as string[] };
|
|
131
|
+
if (exists(agentClaudeDir)) {
|
|
132
|
+
try {
|
|
133
|
+
const agentHooks = readdirSync(agentClaudeDir)
|
|
134
|
+
.filter((f: string) => f.startsWith('hookify.') && f.endsWith('.local.md'))
|
|
135
|
+
.map((f: string) => f.replace('hookify.', '').replace('.local.md', ''));
|
|
136
|
+
hookStatus.agent = agentHooks;
|
|
137
|
+
for (const hook of agentHooks) {
|
|
138
|
+
if (exists(joinPath(globalClaudeDir, \`hookify.\${hook}.local.md\`))) {
|
|
139
|
+
hookStatus.global.push(hook);
|
|
140
|
+
} else {
|
|
141
|
+
hookStatus.missing.push(hook);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
} catch { /* ignore */ }
|
|
145
|
+
}
|
|
146
|
+
if (hookStatus.missing.length > 0) {
|
|
147
|
+
recommendations.push(\`\${hookStatus.missing.length} hook(s) not installed globally — run scripts/setup.sh\`);
|
|
148
|
+
}
|
|
126
149
|
if (recommendations.length === 0) {
|
|
127
150
|
recommendations.push('${config.name} is fully set up and ready!');
|
|
128
151
|
}
|
|
@@ -133,6 +156,7 @@ ${domainDescribes}
|
|
|
133
156
|
global: { exists: exists(globalClaudeMd), has_agent_section: hasAgentMarker(globalClaudeMd) },
|
|
134
157
|
},
|
|
135
158
|
vault: { entries: stats.totalEntries, domains: Object.keys(stats.byDomain) },
|
|
159
|
+
hooks: hookStatus,
|
|
136
160
|
recommendations,
|
|
137
161
|
};
|
|
138
162
|
},
|
|
@@ -169,6 +193,10 @@ ${domainDescribes}
|
|
|
169
193
|
expect(opNames).toContain('brain_archive_sessions');
|
|
170
194
|
expect(opNames).toContain('brain_promote_proposals');
|
|
171
195
|
expect(opNames).toContain('brain_lifecycle');
|
|
196
|
+
// Enhanced brain ops (3)
|
|
197
|
+
expect(opNames).toContain('brain_feedback');
|
|
198
|
+
expect(opNames).toContain('brain_feedback_stats');
|
|
199
|
+
expect(opNames).toContain('brain_reset_extracted');
|
|
172
200
|
// Agent-specific ops (5)
|
|
173
201
|
expect(opNames).toContain('health');
|
|
174
202
|
expect(opNames).toContain('identity');
|
|
@@ -184,8 +212,122 @@ ${domainDescribes}
|
|
|
184
212
|
expect(opNames).toContain('route_intent');
|
|
185
213
|
expect(opNames).toContain('morph');
|
|
186
214
|
expect(opNames).toContain('get_behavior_rules');
|
|
187
|
-
//
|
|
188
|
-
expect(
|
|
215
|
+
// Cognee ops (5)
|
|
216
|
+
expect(opNames).toContain('cognee_status');
|
|
217
|
+
expect(opNames).toContain('cognee_search');
|
|
218
|
+
expect(opNames).toContain('cognee_add');
|
|
219
|
+
expect(opNames).toContain('cognee_cognify');
|
|
220
|
+
expect(opNames).toContain('cognee_config');
|
|
221
|
+
// LLM ops (2)
|
|
222
|
+
expect(opNames).toContain('llm_rotate');
|
|
223
|
+
expect(opNames).toContain('llm_call');
|
|
224
|
+
// Governance ops (5)
|
|
225
|
+
expect(opNames).toContain('governance_policy');
|
|
226
|
+
expect(opNames).toContain('governance_proposals');
|
|
227
|
+
expect(opNames).toContain('governance_stats');
|
|
228
|
+
expect(opNames).toContain('governance_expire');
|
|
229
|
+
expect(opNames).toContain('governance_dashboard');
|
|
230
|
+
// Planning Extra ops (9)
|
|
231
|
+
expect(opNames).toContain('plan_iterate');
|
|
232
|
+
expect(opNames).toContain('plan_split');
|
|
233
|
+
expect(opNames).toContain('plan_reconcile');
|
|
234
|
+
expect(opNames).toContain('plan_complete_lifecycle');
|
|
235
|
+
expect(opNames).toContain('plan_dispatch');
|
|
236
|
+
expect(opNames).toContain('plan_review');
|
|
237
|
+
expect(opNames).toContain('plan_archive');
|
|
238
|
+
expect(opNames).toContain('plan_list_tasks');
|
|
239
|
+
expect(opNames).toContain('plan_stats');
|
|
240
|
+
// Memory Extra ops (8)
|
|
241
|
+
expect(opNames).toContain('memory_delete');
|
|
242
|
+
expect(opNames).toContain('memory_stats');
|
|
243
|
+
expect(opNames).toContain('memory_export');
|
|
244
|
+
expect(opNames).toContain('memory_import');
|
|
245
|
+
expect(opNames).toContain('memory_prune');
|
|
246
|
+
expect(opNames).toContain('memory_deduplicate');
|
|
247
|
+
expect(opNames).toContain('memory_topics');
|
|
248
|
+
expect(opNames).toContain('memory_by_project');
|
|
249
|
+
// Vault Extra ops (12)
|
|
250
|
+
expect(opNames).toContain('vault_get');
|
|
251
|
+
expect(opNames).toContain('vault_update');
|
|
252
|
+
expect(opNames).toContain('vault_remove');
|
|
253
|
+
expect(opNames).toContain('vault_bulk_add');
|
|
254
|
+
expect(opNames).toContain('vault_bulk_remove');
|
|
255
|
+
expect(opNames).toContain('vault_tags');
|
|
256
|
+
expect(opNames).toContain('vault_domains');
|
|
257
|
+
expect(opNames).toContain('vault_recent');
|
|
258
|
+
expect(opNames).toContain('vault_import');
|
|
259
|
+
expect(opNames).toContain('vault_seed');
|
|
260
|
+
expect(opNames).toContain('vault_backup');
|
|
261
|
+
expect(opNames).toContain('vault_age_report');
|
|
262
|
+
// Admin ops (8)
|
|
263
|
+
expect(opNames).toContain('admin_health');
|
|
264
|
+
expect(opNames).toContain('admin_tool_list');
|
|
265
|
+
expect(opNames).toContain('admin_config');
|
|
266
|
+
expect(opNames).toContain('admin_vault_size');
|
|
267
|
+
expect(opNames).toContain('admin_uptime');
|
|
268
|
+
expect(opNames).toContain('admin_version');
|
|
269
|
+
expect(opNames).toContain('admin_reset_cache');
|
|
270
|
+
expect(opNames).toContain('admin_diagnostic');
|
|
271
|
+
// Loop ops (7)
|
|
272
|
+
expect(opNames).toContain('loop_start');
|
|
273
|
+
expect(opNames).toContain('loop_iterate');
|
|
274
|
+
expect(opNames).toContain('loop_status');
|
|
275
|
+
expect(opNames).toContain('loop_cancel');
|
|
276
|
+
expect(opNames).toContain('loop_history');
|
|
277
|
+
expect(opNames).toContain('loop_is_active');
|
|
278
|
+
expect(opNames).toContain('loop_complete');
|
|
279
|
+
// Orchestrate ops (5)
|
|
280
|
+
expect(opNames).toContain('orchestrate_plan');
|
|
281
|
+
expect(opNames).toContain('orchestrate_execute');
|
|
282
|
+
expect(opNames).toContain('orchestrate_complete');
|
|
283
|
+
expect(opNames).toContain('orchestrate_status');
|
|
284
|
+
expect(opNames).toContain('orchestrate_quick_capture');
|
|
285
|
+
// Capture ops (4)
|
|
286
|
+
expect(opNames).toContain('capture_knowledge');
|
|
287
|
+
expect(opNames).toContain('capture_quick');
|
|
288
|
+
expect(opNames).toContain('search_intelligent');
|
|
289
|
+
expect(opNames).toContain('search_feedback');
|
|
290
|
+
// Grading ops (5)
|
|
291
|
+
expect(opNames).toContain('plan_grade');
|
|
292
|
+
expect(opNames).toContain('plan_check_history');
|
|
293
|
+
expect(opNames).toContain('plan_latest_check');
|
|
294
|
+
expect(opNames).toContain('plan_meets_grade');
|
|
295
|
+
expect(opNames).toContain('plan_auto_improve');
|
|
296
|
+
// Admin Extra ops (10)
|
|
297
|
+
expect(opNames).toContain('admin_telemetry');
|
|
298
|
+
expect(opNames).toContain('admin_telemetry_recent');
|
|
299
|
+
expect(opNames).toContain('admin_telemetry_reset');
|
|
300
|
+
expect(opNames).toContain('admin_permissions');
|
|
301
|
+
expect(opNames).toContain('admin_vault_analytics');
|
|
302
|
+
expect(opNames).toContain('admin_search_insights');
|
|
303
|
+
expect(opNames).toContain('admin_module_status');
|
|
304
|
+
expect(opNames).toContain('admin_env');
|
|
305
|
+
expect(opNames).toContain('admin_gc');
|
|
306
|
+
expect(opNames).toContain('admin_export_config');
|
|
307
|
+
// Curator Extra ops (4)
|
|
308
|
+
expect(opNames).toContain('curator_entry_history');
|
|
309
|
+
expect(opNames).toContain('curator_record_snapshot');
|
|
310
|
+
expect(opNames).toContain('curator_queue_stats');
|
|
311
|
+
expect(opNames).toContain('curator_enrich');
|
|
312
|
+
// Project ops (12)
|
|
313
|
+
expect(opNames).toContain('project_get');
|
|
314
|
+
expect(opNames).toContain('project_list');
|
|
315
|
+
expect(opNames).toContain('project_unregister');
|
|
316
|
+
expect(opNames).toContain('project_get_rules');
|
|
317
|
+
expect(opNames).toContain('project_list_rules');
|
|
318
|
+
expect(opNames).toContain('project_add_rule');
|
|
319
|
+
expect(opNames).toContain('project_remove_rule');
|
|
320
|
+
expect(opNames).toContain('project_link');
|
|
321
|
+
expect(opNames).toContain('project_unlink');
|
|
322
|
+
expect(opNames).toContain('project_get_links');
|
|
323
|
+
expect(opNames).toContain('project_linked_projects');
|
|
324
|
+
expect(opNames).toContain('project_touch');
|
|
325
|
+
// Cross-project memory ops (3)
|
|
326
|
+
expect(opNames).toContain('memory_promote_to_global');
|
|
327
|
+
expect(opNames).toContain('memory_configure');
|
|
328
|
+
expect(opNames).toContain('memory_cross_project_search');
|
|
329
|
+
// Total: 152 (147 core + 5 agent-specific)
|
|
330
|
+
expect(facade.ops.length).toBe(152);
|
|
189
331
|
});
|
|
190
332
|
|
|
191
333
|
it('search should query across all domains with ranked results', async () => {
|
|
@@ -277,7 +419,9 @@ ${domainDescribes}
|
|
|
277
419
|
const setupOp = facade.ops.find((o) => o.name === 'setup')!;
|
|
278
420
|
const result = (await setupOp.handler({ projectPath: '/tmp/nonexistent-test' })) as {
|
|
279
421
|
agent: { name: string };
|
|
422
|
+
claude_md: { project: { exists: boolean; has_agent_section: boolean }; global: { exists: boolean; has_agent_section: boolean } };
|
|
280
423
|
vault: { entries: number };
|
|
424
|
+
hooks: { agent: string[]; global: string[]; missing: string[] };
|
|
281
425
|
recommendations: string[];
|
|
282
426
|
};
|
|
283
427
|
expect(result.agent.name).toBe('${escapeQuotes(config.name)}');
|
|
@@ -327,6 +471,32 @@ ${domainDescribes}
|
|
|
327
471
|
const result = (await healthOp.handler({})) as { score: number };
|
|
328
472
|
expect(result.score).toBeGreaterThan(0);
|
|
329
473
|
});
|
|
474
|
+
|
|
475
|
+
it('governance_policy get should return default policy', async () => {
|
|
476
|
+
const facade = buildCoreFacade();
|
|
477
|
+
const policyOp = facade.ops.find((o) => o.name === 'governance_policy')!;
|
|
478
|
+
const result = (await policyOp.handler({ action: 'get', projectPath: '/test' })) as {
|
|
479
|
+
projectPath: string;
|
|
480
|
+
quotas: { maxEntriesTotal: number };
|
|
481
|
+
autoCapture: { enabled: boolean };
|
|
482
|
+
};
|
|
483
|
+
expect(result.projectPath).toBe('/test');
|
|
484
|
+
expect(result.quotas.maxEntriesTotal).toBe(500);
|
|
485
|
+
expect(result.autoCapture.enabled).toBe(true);
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
it('governance_dashboard should return combined view', async () => {
|
|
489
|
+
const facade = buildCoreFacade();
|
|
490
|
+
const dashOp = facade.ops.find((o) => o.name === 'governance_dashboard')!;
|
|
491
|
+
const result = (await dashOp.handler({ projectPath: '/test' })) as {
|
|
492
|
+
vaultSize: number;
|
|
493
|
+
quotaPercent: number;
|
|
494
|
+
pendingProposals: number;
|
|
495
|
+
};
|
|
496
|
+
expect(typeof result.vaultSize).toBe('number');
|
|
497
|
+
expect(typeof result.quotaPercent).toBe('number');
|
|
498
|
+
expect(result.pendingProposals).toBe(0);
|
|
499
|
+
});
|
|
330
500
|
});
|
|
331
501
|
});
|
|
332
502
|
`;
|
|
@@ -382,7 +552,7 @@ function generateDomainDescribe(agentId, domain) {
|
|
|
382
552
|
severity: 'warning',
|
|
383
553
|
description: 'A captured pattern.',
|
|
384
554
|
tags: ['captured'],
|
|
385
|
-
})) as { captured: boolean };
|
|
555
|
+
})) as { captured: boolean; governance?: { action: string } };
|
|
386
556
|
expect(result.captured).toBe(true);
|
|
387
557
|
const entry = runtime.vault.get('${domain}-cap1');
|
|
388
558
|
expect(entry).not.toBeNull();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test-facades.js","sourceRoot":"","sources":["../../src/templates/test-facades.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAmB;IACrD,MAAM,eAAe,GAAG,MAAM,CAAC,OAAO;SACnC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,sBAAsB,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;SAChD,IAAI,CAAC,MAAM,CAAC,CAAC;IAEhB,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAmCS,MAAM,CAAC,EAAE;;;;;;;;;;;EAWzB,eAAe;;cAEH,MAAM,CAAC,EAAE
|
|
1
|
+
{"version":3,"file":"test-facades.js","sourceRoot":"","sources":["../../src/templates/test-facades.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAmB;IACrD,MAAM,eAAe,GAAG,MAAM,CAAC,OAAO;SACnC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,sBAAsB,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;SAChD,IAAI,CAAC,MAAM,CAAC,CAAC;IAEhB,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAmCS,MAAM,CAAC,EAAE;;;;;;;;;;;EAWzB,eAAe;;cAEH,MAAM,CAAC,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sCA6Fe,MAAM,CAAC,IAAI;;;;;;;;;;;;;;;;iBAgBhC,MAAM,CAAC,EAAE;;;;;;;;kCAQQ,MAAM,CAAC,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iDAoKM,MAAM,CAAC,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mCAmCvB,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC;mCACzB,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC;;;;;;;;;;;0CAWlB,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;qCA0B9B,MAAM,CAAC,EAAE;;;;;;;;;;;;;;;;wCAgBN,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2EhE,CAAC;AACF,CAAC;AAED,SAAS,sBAAsB,CAAC,OAAe,EAAE,MAAc;IAC7D,MAAM,UAAU,GAAG,GAAG,OAAO,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,CAAC;IAE7D,OAAO,eAAe,UAAU;;4CAEU,OAAO,OAAO,MAAM;;;;;kCAK9B,UAAU;;;;;;;;;iDASK,MAAM;;2BAE5B,MAAM,mBAAmB,MAAM;;;;;;kDAMR,MAAM;;;iCAGvB,MAAM;;2BAEZ,MAAM,kBAAkB,MAAM;;;;;;;wDAOD,MAAM;;;wCAGtB,MAAM;;;;eAI/B,MAAM;;;;;;;;yCAQoB,MAAM;;oCAEX,MAAM;;;;6CAIG,MAAM,mBAAmB,MAAM;;;gDAG5B,MAAM;gCACtB,MAAM;;;;6CAIO,MAAM,mBAAmB,MAAM;;;gDAG5B,MAAM;;kCAEpB,MAAM;;MAElC,CAAC;AACP,CAAC;AAED,SAAS,YAAY,CAAC,CAAS;IAC7B,OAAO,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AACvD,CAAC"}
|
package/package.json
CHANGED
|
@@ -59,9 +59,9 @@ describe('Scaffolder', () => {
|
|
|
59
59
|
expect(preview.facades).toHaveLength(4); // 3 domains + core
|
|
60
60
|
expect(preview.facades[0].name).toBe('atlas_data_pipelines');
|
|
61
61
|
|
|
62
|
-
// Core facade should list all
|
|
62
|
+
// Core facade should list all 152 ops (147 core + 5 agent-specific)
|
|
63
63
|
const coreFacade = preview.facades.find((f) => f.name === 'atlas_core')!;
|
|
64
|
-
expect(coreFacade.ops.length).toBe(
|
|
64
|
+
expect(coreFacade.ops.length).toBe(152);
|
|
65
65
|
expect(coreFacade.ops).toContain('curator_status');
|
|
66
66
|
expect(coreFacade.ops).toContain('health');
|
|
67
67
|
|
package/src/scaffolder.ts
CHANGED
|
@@ -77,6 +77,13 @@ export function previewScaffold(config: AgentConfig): ScaffoldPreview {
|
|
|
77
77
|
},
|
|
78
78
|
];
|
|
79
79
|
|
|
80
|
+
if (config.hookPacks?.length) {
|
|
81
|
+
files.push({
|
|
82
|
+
path: '.claude/',
|
|
83
|
+
description: `Hook pack files (${config.hookPacks.join(', ')})`,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
80
87
|
const facades = [
|
|
81
88
|
...config.domains.map((d) => ({
|
|
82
89
|
name: `${config.id}_${d.replace(/-/g, '_')}`,
|
|
@@ -85,7 +92,7 @@ export function previewScaffold(config: AgentConfig): ScaffoldPreview {
|
|
|
85
92
|
{
|
|
86
93
|
name: `${config.id}_core`,
|
|
87
94
|
ops: [
|
|
88
|
-
// From createCoreOps() —
|
|
95
|
+
// From createCoreOps() — 144 generic ops
|
|
89
96
|
'search',
|
|
90
97
|
'vault_stats',
|
|
91
98
|
'list_all',
|
|
@@ -101,9 +108,32 @@ export function previewScaffold(config: AgentConfig): ScaffoldPreview {
|
|
|
101
108
|
'update_task',
|
|
102
109
|
'complete_plan',
|
|
103
110
|
'record_feedback',
|
|
111
|
+
'brain_feedback',
|
|
112
|
+
'brain_feedback_stats',
|
|
104
113
|
'rebuild_vocabulary',
|
|
105
114
|
'brain_stats',
|
|
106
115
|
'llm_status',
|
|
116
|
+
'brain_session_context',
|
|
117
|
+
'brain_strengths',
|
|
118
|
+
'brain_global_patterns',
|
|
119
|
+
'brain_recommend',
|
|
120
|
+
'brain_build_intelligence',
|
|
121
|
+
'brain_export',
|
|
122
|
+
'brain_import',
|
|
123
|
+
'brain_extract_knowledge',
|
|
124
|
+
'brain_archive_sessions',
|
|
125
|
+
'brain_promote_proposals',
|
|
126
|
+
'brain_lifecycle',
|
|
127
|
+
'brain_reset_extracted',
|
|
128
|
+
// Cognee ops — 5
|
|
129
|
+
'cognee_status',
|
|
130
|
+
'cognee_search',
|
|
131
|
+
'cognee_add',
|
|
132
|
+
'cognee_cognify',
|
|
133
|
+
'cognee_config',
|
|
134
|
+
// LLM ops — 2
|
|
135
|
+
'llm_rotate',
|
|
136
|
+
'llm_call',
|
|
107
137
|
'curator_status',
|
|
108
138
|
'curator_detect_duplicates',
|
|
109
139
|
'curator_contradictions',
|
|
@@ -112,6 +142,119 @@ export function previewScaffold(config: AgentConfig): ScaffoldPreview {
|
|
|
112
142
|
'curator_groom_all',
|
|
113
143
|
'curator_consolidate',
|
|
114
144
|
'curator_health_audit',
|
|
145
|
+
'get_identity',
|
|
146
|
+
'update_identity',
|
|
147
|
+
'add_guideline',
|
|
148
|
+
'remove_guideline',
|
|
149
|
+
'rollback_identity',
|
|
150
|
+
'route_intent',
|
|
151
|
+
'morph',
|
|
152
|
+
'get_behavior_rules',
|
|
153
|
+
// Governance ops — 5
|
|
154
|
+
'governance_policy',
|
|
155
|
+
'governance_proposals',
|
|
156
|
+
'governance_stats',
|
|
157
|
+
'governance_expire',
|
|
158
|
+
'governance_dashboard',
|
|
159
|
+
// Planning Extra ops — 9
|
|
160
|
+
'plan_iterate',
|
|
161
|
+
'plan_split',
|
|
162
|
+
'plan_reconcile',
|
|
163
|
+
'plan_complete_lifecycle',
|
|
164
|
+
'plan_dispatch',
|
|
165
|
+
'plan_review',
|
|
166
|
+
'plan_archive',
|
|
167
|
+
'plan_list_tasks',
|
|
168
|
+
'plan_stats',
|
|
169
|
+
// Memory Extra ops — 8
|
|
170
|
+
'memory_delete',
|
|
171
|
+
'memory_stats',
|
|
172
|
+
'memory_export',
|
|
173
|
+
'memory_import',
|
|
174
|
+
'memory_prune',
|
|
175
|
+
'memory_deduplicate',
|
|
176
|
+
'memory_topics',
|
|
177
|
+
'memory_by_project',
|
|
178
|
+
// Vault Extra ops — 12
|
|
179
|
+
'vault_get',
|
|
180
|
+
'vault_update',
|
|
181
|
+
'vault_remove',
|
|
182
|
+
'vault_bulk_add',
|
|
183
|
+
'vault_bulk_remove',
|
|
184
|
+
'vault_tags',
|
|
185
|
+
'vault_domains',
|
|
186
|
+
'vault_recent',
|
|
187
|
+
'vault_import',
|
|
188
|
+
'vault_seed',
|
|
189
|
+
'vault_backup',
|
|
190
|
+
'vault_age_report',
|
|
191
|
+
// Admin ops — 8
|
|
192
|
+
'admin_health',
|
|
193
|
+
'admin_tool_list',
|
|
194
|
+
'admin_config',
|
|
195
|
+
'admin_vault_size',
|
|
196
|
+
'admin_uptime',
|
|
197
|
+
'admin_version',
|
|
198
|
+
'admin_reset_cache',
|
|
199
|
+
'admin_diagnostic',
|
|
200
|
+
// Loop ops — 7
|
|
201
|
+
'loop_start',
|
|
202
|
+
'loop_iterate',
|
|
203
|
+
'loop_status',
|
|
204
|
+
'loop_cancel',
|
|
205
|
+
'loop_history',
|
|
206
|
+
'loop_is_active',
|
|
207
|
+
'loop_complete',
|
|
208
|
+
// Orchestrate ops — 5
|
|
209
|
+
'orchestrate_plan',
|
|
210
|
+
'orchestrate_execute',
|
|
211
|
+
'orchestrate_complete',
|
|
212
|
+
'orchestrate_status',
|
|
213
|
+
'orchestrate_quick_capture',
|
|
214
|
+
// Grading ops — 5
|
|
215
|
+
'plan_grade',
|
|
216
|
+
'plan_check_history',
|
|
217
|
+
'plan_latest_check',
|
|
218
|
+
'plan_meets_grade',
|
|
219
|
+
'plan_auto_improve',
|
|
220
|
+
// Capture ops — 4
|
|
221
|
+
'capture_knowledge',
|
|
222
|
+
'capture_quick',
|
|
223
|
+
'search_intelligent',
|
|
224
|
+
'search_feedback',
|
|
225
|
+
// Admin Extra ops — 10
|
|
226
|
+
'admin_telemetry',
|
|
227
|
+
'admin_telemetry_recent',
|
|
228
|
+
'admin_telemetry_reset',
|
|
229
|
+
'admin_permissions',
|
|
230
|
+
'admin_vault_analytics',
|
|
231
|
+
'admin_search_insights',
|
|
232
|
+
'admin_module_status',
|
|
233
|
+
'admin_env',
|
|
234
|
+
'admin_gc',
|
|
235
|
+
'admin_export_config',
|
|
236
|
+
// Curator Extra ops — 4
|
|
237
|
+
'curator_entry_history',
|
|
238
|
+
'curator_record_snapshot',
|
|
239
|
+
'curator_queue_stats',
|
|
240
|
+
'curator_enrich',
|
|
241
|
+
// Project ops — 12
|
|
242
|
+
'project_get',
|
|
243
|
+
'project_list',
|
|
244
|
+
'project_unregister',
|
|
245
|
+
'project_get_rules',
|
|
246
|
+
'project_list_rules',
|
|
247
|
+
'project_add_rule',
|
|
248
|
+
'project_remove_rule',
|
|
249
|
+
'project_link',
|
|
250
|
+
'project_unlink',
|
|
251
|
+
'project_get_links',
|
|
252
|
+
'project_linked_projects',
|
|
253
|
+
'project_touch',
|
|
254
|
+
// Cross-project memory ops — 3
|
|
255
|
+
'memory_promote_to_global',
|
|
256
|
+
'memory_configure',
|
|
257
|
+
'memory_cross_project_search',
|
|
115
258
|
// Agent-specific ops — 5
|
|
116
259
|
'health',
|
|
117
260
|
'identity',
|
|
@@ -160,6 +303,10 @@ export function scaffold(config: AgentConfig): ScaffoldResult {
|
|
|
160
303
|
'src/__tests__',
|
|
161
304
|
];
|
|
162
305
|
|
|
306
|
+
if (config.hookPacks?.length) {
|
|
307
|
+
dirs.push('.claude');
|
|
308
|
+
}
|
|
309
|
+
|
|
163
310
|
for (const dir of dirs) {
|
|
164
311
|
mkdirSync(join(agentDir, dir), { recursive: true });
|
|
165
312
|
}
|
|
@@ -211,7 +358,7 @@ export function scaffold(config: AgentConfig): ScaffoldResult {
|
|
|
211
358
|
filesCreated.push(path);
|
|
212
359
|
}
|
|
213
360
|
|
|
214
|
-
const totalOps = config.domains.length * 5 +
|
|
361
|
+
const totalOps = config.domains.length * 5 + 61; // 5 per domain + 56 core (from createCoreOps) + 5 agent-specific
|
|
215
362
|
|
|
216
363
|
// Register the agent as an MCP server in ~/.claude.json
|
|
217
364
|
const mcpReg = registerMcpServer(config.id, agentDir);
|
|
@@ -225,6 +372,10 @@ export function scaffold(config: AgentConfig): ScaffoldResult {
|
|
|
225
372
|
`1 test suite — facades (vault, brain, planner, llm tests provided by @soleri/core)`,
|
|
226
373
|
];
|
|
227
374
|
|
|
375
|
+
if (config.hookPacks?.length) {
|
|
376
|
+
summaryLines.push(`${config.hookPacks.length} hook pack(s) bundled in .claude/`);
|
|
377
|
+
}
|
|
378
|
+
|
|
228
379
|
if (mcpReg.registered) {
|
|
229
380
|
summaryLines.push(`MCP server registered in ${mcpReg.path}`);
|
|
230
381
|
} else {
|
|
@@ -57,6 +57,9 @@ export function generateClaudeMdTemplate(config: AgentConfig): string {
|
|
|
57
57
|
`| Session capture | ${bt}${toolPrefix}_core${bt} | ${bt}session_capture${bt} |`,
|
|
58
58
|
`| Export knowledge | ${bt}${toolPrefix}_core${bt} | ${bt}export${bt} |`,
|
|
59
59
|
`| Record feedback | ${bt}${toolPrefix}_core${bt} | ${bt}record_feedback${bt} |`,
|
|
60
|
+
`| Enhanced feedback | ${bt}${toolPrefix}_core${bt} | ${bt}brain_feedback${bt} |`,
|
|
61
|
+
`| Feedback stats | ${bt}${toolPrefix}_core${bt} | ${bt}brain_feedback_stats${bt} |`,
|
|
62
|
+
`| Reset extracted | ${bt}${toolPrefix}_core${bt} | ${bt}brain_reset_extracted${bt} |`,
|
|
60
63
|
`| Rebuild vocabulary | ${bt}${toolPrefix}_core${bt} | ${bt}rebuild_vocabulary${bt} |`,
|
|
61
64
|
`| Brain stats | ${bt}${toolPrefix}_core${bt} | ${bt}brain_stats${bt} |`,
|
|
62
65
|
`| LLM status | ${bt}${toolPrefix}_core${bt} | ${bt}llm_status${bt} |`,
|
|
@@ -73,6 +76,117 @@ export function generateClaudeMdTemplate(config: AgentConfig): string {
|
|
|
73
76
|
`| Add guideline | ${bt}${toolPrefix}_core${bt} | ${bt}add_guideline${bt} |`,
|
|
74
77
|
`| Remove guideline | ${bt}${toolPrefix}_core${bt} | ${bt}remove_guideline${bt} |`,
|
|
75
78
|
`| Rollback identity | ${bt}${toolPrefix}_core${bt} | ${bt}rollback_identity${bt} |`,
|
|
79
|
+
`| Cognee status | ${bt}${toolPrefix}_core${bt} | ${bt}cognee_status${bt} |`,
|
|
80
|
+
`| Cognee search | ${bt}${toolPrefix}_core${bt} | ${bt}cognee_search${bt} |`,
|
|
81
|
+
`| Cognee add | ${bt}${toolPrefix}_core${bt} | ${bt}cognee_add${bt} |`,
|
|
82
|
+
`| Cognee cognify | ${bt}${toolPrefix}_core${bt} | ${bt}cognee_cognify${bt} |`,
|
|
83
|
+
`| Cognee config | ${bt}${toolPrefix}_core${bt} | ${bt}cognee_config${bt} |`,
|
|
84
|
+
`| LLM rotate key | ${bt}${toolPrefix}_core${bt} | ${bt}llm_rotate${bt} |`,
|
|
85
|
+
`| LLM call | ${bt}${toolPrefix}_core${bt} | ${bt}llm_call${bt} |`,
|
|
86
|
+
`| Governance policy | ${bt}${toolPrefix}_core${bt} | ${bt}governance_policy${bt} |`,
|
|
87
|
+
`| Governance proposals | ${bt}${toolPrefix}_core${bt} | ${bt}governance_proposals${bt} |`,
|
|
88
|
+
`| Governance stats | ${bt}${toolPrefix}_core${bt} | ${bt}governance_stats${bt} |`,
|
|
89
|
+
`| Expire proposals | ${bt}${toolPrefix}_core${bt} | ${bt}governance_expire${bt} |`,
|
|
90
|
+
`| Governance dashboard | ${bt}${toolPrefix}_core${bt} | ${bt}governance_dashboard${bt} |`,
|
|
91
|
+
// Planning Extra ops
|
|
92
|
+
`| Iterate plan | ${bt}${toolPrefix}_core${bt} | ${bt}plan_iterate${bt} |`,
|
|
93
|
+
`| Split plan tasks | ${bt}${toolPrefix}_core${bt} | ${bt}plan_split${bt} |`,
|
|
94
|
+
`| Reconcile plan | ${bt}${toolPrefix}_core${bt} | ${bt}plan_reconcile${bt} |`,
|
|
95
|
+
`| Complete lifecycle | ${bt}${toolPrefix}_core${bt} | ${bt}plan_complete_lifecycle${bt} |`,
|
|
96
|
+
`| Dispatch tasks | ${bt}${toolPrefix}_core${bt} | ${bt}plan_dispatch${bt} |`,
|
|
97
|
+
`| Review plan | ${bt}${toolPrefix}_core${bt} | ${bt}plan_review${bt} |`,
|
|
98
|
+
`| Archive plan | ${bt}${toolPrefix}_core${bt} | ${bt}plan_archive${bt} |`,
|
|
99
|
+
`| List plan tasks | ${bt}${toolPrefix}_core${bt} | ${bt}plan_list_tasks${bt} |`,
|
|
100
|
+
`| Plan stats | ${bt}${toolPrefix}_core${bt} | ${bt}plan_stats${bt} |`,
|
|
101
|
+
// Memory Extra ops
|
|
102
|
+
`| Delete memory | ${bt}${toolPrefix}_core${bt} | ${bt}memory_delete${bt} |`,
|
|
103
|
+
`| Memory stats | ${bt}${toolPrefix}_core${bt} | ${bt}memory_stats${bt} |`,
|
|
104
|
+
`| Export memories | ${bt}${toolPrefix}_core${bt} | ${bt}memory_export${bt} |`,
|
|
105
|
+
`| Import memories | ${bt}${toolPrefix}_core${bt} | ${bt}memory_import${bt} |`,
|
|
106
|
+
`| Prune memories | ${bt}${toolPrefix}_core${bt} | ${bt}memory_prune${bt} |`,
|
|
107
|
+
`| Deduplicate memories | ${bt}${toolPrefix}_core${bt} | ${bt}memory_deduplicate${bt} |`,
|
|
108
|
+
`| Memory topics | ${bt}${toolPrefix}_core${bt} | ${bt}memory_topics${bt} |`,
|
|
109
|
+
`| Memories by project | ${bt}${toolPrefix}_core${bt} | ${bt}memory_by_project${bt} |`,
|
|
110
|
+
// Vault Extra ops
|
|
111
|
+
`| Get vault entry | ${bt}${toolPrefix}_core${bt} | ${bt}vault_get${bt} |`,
|
|
112
|
+
`| Update entry | ${bt}${toolPrefix}_core${bt} | ${bt}vault_update${bt} |`,
|
|
113
|
+
`| Remove entry | ${bt}${toolPrefix}_core${bt} | ${bt}vault_remove${bt} |`,
|
|
114
|
+
`| Bulk add | ${bt}${toolPrefix}_core${bt} | ${bt}vault_bulk_add${bt} |`,
|
|
115
|
+
`| Bulk remove | ${bt}${toolPrefix}_core${bt} | ${bt}vault_bulk_remove${bt} |`,
|
|
116
|
+
`| Vault tags | ${bt}${toolPrefix}_core${bt} | ${bt}vault_tags${bt} |`,
|
|
117
|
+
`| Vault domains | ${bt}${toolPrefix}_core${bt} | ${bt}vault_domains${bt} |`,
|
|
118
|
+
`| Recent entries | ${bt}${toolPrefix}_core${bt} | ${bt}vault_recent${bt} |`,
|
|
119
|
+
`| Import entries | ${bt}${toolPrefix}_core${bt} | ${bt}vault_import${bt} |`,
|
|
120
|
+
`| Seed entries | ${bt}${toolPrefix}_core${bt} | ${bt}vault_seed${bt} |`,
|
|
121
|
+
`| Backup vault | ${bt}${toolPrefix}_core${bt} | ${bt}vault_backup${bt} |`,
|
|
122
|
+
`| Vault age report | ${bt}${toolPrefix}_core${bt} | ${bt}vault_age_report${bt} |`,
|
|
123
|
+
// Admin ops
|
|
124
|
+
`| Admin health | ${bt}${toolPrefix}_core${bt} | ${bt}admin_health${bt} |`,
|
|
125
|
+
`| Tool list | ${bt}${toolPrefix}_core${bt} | ${bt}admin_tool_list${bt} |`,
|
|
126
|
+
`| Config | ${bt}${toolPrefix}_core${bt} | ${bt}admin_config${bt} |`,
|
|
127
|
+
`| Vault size | ${bt}${toolPrefix}_core${bt} | ${bt}admin_vault_size${bt} |`,
|
|
128
|
+
`| Uptime | ${bt}${toolPrefix}_core${bt} | ${bt}admin_uptime${bt} |`,
|
|
129
|
+
`| Version | ${bt}${toolPrefix}_core${bt} | ${bt}admin_version${bt} |`,
|
|
130
|
+
`| Reset cache | ${bt}${toolPrefix}_core${bt} | ${bt}admin_reset_cache${bt} |`,
|
|
131
|
+
`| Diagnostic | ${bt}${toolPrefix}_core${bt} | ${bt}admin_diagnostic${bt} |`,
|
|
132
|
+
// Loop ops
|
|
133
|
+
`| Start loop | ${bt}${toolPrefix}_core${bt} | ${bt}loop_start${bt} |`,
|
|
134
|
+
`| Loop iterate | ${bt}${toolPrefix}_core${bt} | ${bt}loop_iterate${bt} |`,
|
|
135
|
+
`| Loop status | ${bt}${toolPrefix}_core${bt} | ${bt}loop_status${bt} |`,
|
|
136
|
+
`| Cancel loop | ${bt}${toolPrefix}_core${bt} | ${bt}loop_cancel${bt} |`,
|
|
137
|
+
`| Loop history | ${bt}${toolPrefix}_core${bt} | ${bt}loop_history${bt} |`,
|
|
138
|
+
`| Loop active | ${bt}${toolPrefix}_core${bt} | ${bt}loop_is_active${bt} |`,
|
|
139
|
+
`| Complete loop | ${bt}${toolPrefix}_core${bt} | ${bt}loop_complete${bt} |`,
|
|
140
|
+
// Orchestrate ops
|
|
141
|
+
`| Orchestrate plan | ${bt}${toolPrefix}_core${bt} | ${bt}orchestrate_plan${bt} |`,
|
|
142
|
+
`| Orchestrate execute | ${bt}${toolPrefix}_core${bt} | ${bt}orchestrate_execute${bt} |`,
|
|
143
|
+
`| Orchestrate complete | ${bt}${toolPrefix}_core${bt} | ${bt}orchestrate_complete${bt} |`,
|
|
144
|
+
`| Orchestrate status | ${bt}${toolPrefix}_core${bt} | ${bt}orchestrate_status${bt} |`,
|
|
145
|
+
`| Quick capture | ${bt}${toolPrefix}_core${bt} | ${bt}orchestrate_quick_capture${bt} |`,
|
|
146
|
+
// Capture ops
|
|
147
|
+
`| Capture knowledge | ${bt}${toolPrefix}_core${bt} | ${bt}capture_knowledge${bt} |`,
|
|
148
|
+
`| Quick capture entry | ${bt}${toolPrefix}_core${bt} | ${bt}capture_quick${bt} |`,
|
|
149
|
+
`| Intelligent search | ${bt}${toolPrefix}_core${bt} | ${bt}search_intelligent${bt} |`,
|
|
150
|
+
`| Search feedback | ${bt}${toolPrefix}_core${bt} | ${bt}search_feedback${bt} |`,
|
|
151
|
+
// Grading ops
|
|
152
|
+
`| Grade plan | ${bt}${toolPrefix}_core${bt} | ${bt}plan_grade${bt} |`,
|
|
153
|
+
`| Check history | ${bt}${toolPrefix}_core${bt} | ${bt}plan_check_history${bt} |`,
|
|
154
|
+
`| Latest check | ${bt}${toolPrefix}_core${bt} | ${bt}plan_latest_check${bt} |`,
|
|
155
|
+
`| Meets grade | ${bt}${toolPrefix}_core${bt} | ${bt}plan_meets_grade${bt} |`,
|
|
156
|
+
`| Auto improve plan | ${bt}${toolPrefix}_core${bt} | ${bt}plan_auto_improve${bt} |`,
|
|
157
|
+
// Admin Extra ops
|
|
158
|
+
`| Telemetry stats | ${bt}${toolPrefix}_core${bt} | ${bt}admin_telemetry${bt} |`,
|
|
159
|
+
`| Recent calls | ${bt}${toolPrefix}_core${bt} | ${bt}admin_telemetry_recent${bt} |`,
|
|
160
|
+
`| Reset telemetry | ${bt}${toolPrefix}_core${bt} | ${bt}admin_telemetry_reset${bt} |`,
|
|
161
|
+
`| Permissions | ${bt}${toolPrefix}_core${bt} | ${bt}admin_permissions${bt} |`,
|
|
162
|
+
`| Vault analytics | ${bt}${toolPrefix}_core${bt} | ${bt}admin_vault_analytics${bt} |`,
|
|
163
|
+
`| Search insights | ${bt}${toolPrefix}_core${bt} | ${bt}admin_search_insights${bt} |`,
|
|
164
|
+
`| Module status | ${bt}${toolPrefix}_core${bt} | ${bt}admin_module_status${bt} |`,
|
|
165
|
+
`| Environment | ${bt}${toolPrefix}_core${bt} | ${bt}admin_env${bt} |`,
|
|
166
|
+
`| Garbage collect | ${bt}${toolPrefix}_core${bt} | ${bt}admin_gc${bt} |`,
|
|
167
|
+
`| Export config | ${bt}${toolPrefix}_core${bt} | ${bt}admin_export_config${bt} |`,
|
|
168
|
+
// Curator Extra ops
|
|
169
|
+
`| Entry history | ${bt}${toolPrefix}_core${bt} | ${bt}curator_entry_history${bt} |`,
|
|
170
|
+
`| Record snapshot | ${bt}${toolPrefix}_core${bt} | ${bt}curator_record_snapshot${bt} |`,
|
|
171
|
+
`| Queue stats | ${bt}${toolPrefix}_core${bt} | ${bt}curator_queue_stats${bt} |`,
|
|
172
|
+
`| Enrich metadata | ${bt}${toolPrefix}_core${bt} | ${bt}curator_enrich${bt} |`,
|
|
173
|
+
// Project ops
|
|
174
|
+
`| Get project | ${bt}${toolPrefix}_core${bt} | ${bt}project_get${bt} |`,
|
|
175
|
+
`| List projects | ${bt}${toolPrefix}_core${bt} | ${bt}project_list${bt} |`,
|
|
176
|
+
`| Unregister project | ${bt}${toolPrefix}_core${bt} | ${bt}project_unregister${bt} |`,
|
|
177
|
+
`| Project rules | ${bt}${toolPrefix}_core${bt} | ${bt}project_get_rules${bt} |`,
|
|
178
|
+
`| All project rules | ${bt}${toolPrefix}_core${bt} | ${bt}project_list_rules${bt} |`,
|
|
179
|
+
`| Add rule | ${bt}${toolPrefix}_core${bt} | ${bt}project_add_rule${bt} |`,
|
|
180
|
+
`| Remove rule | ${bt}${toolPrefix}_core${bt} | ${bt}project_remove_rule${bt} |`,
|
|
181
|
+
`| Link projects | ${bt}${toolPrefix}_core${bt} | ${bt}project_link${bt} |`,
|
|
182
|
+
`| Unlink projects | ${bt}${toolPrefix}_core${bt} | ${bt}project_unlink${bt} |`,
|
|
183
|
+
`| Project links | ${bt}${toolPrefix}_core${bt} | ${bt}project_get_links${bt} |`,
|
|
184
|
+
`| Linked projects | ${bt}${toolPrefix}_core${bt} | ${bt}project_linked_projects${bt} |`,
|
|
185
|
+
`| Touch project | ${bt}${toolPrefix}_core${bt} | ${bt}project_touch${bt} |`,
|
|
186
|
+
// Cross-project memory ops
|
|
187
|
+
`| Promote to global | ${bt}${toolPrefix}_core${bt} | ${bt}memory_promote_to_global${bt} |`,
|
|
188
|
+
`| Configure memory | ${bt}${toolPrefix}_core${bt} | ${bt}memory_configure${bt} |`,
|
|
189
|
+
`| Cross-project search | ${bt}${toolPrefix}_core${bt} | ${bt}memory_cross_project_search${bt} |`,
|
|
76
190
|
);
|
|
77
191
|
|
|
78
192
|
mdLines.push(
|
|
@@ -130,6 +244,73 @@ export function generateClaudeMdTemplate(config: AgentConfig): string {
|
|
|
130
244
|
`<!-- /${marker} -->`,
|
|
131
245
|
);
|
|
132
246
|
|
|
247
|
+
// ─── Hook Packs section (when configured) ─────────────────────
|
|
248
|
+
if (config.hookPacks?.length) {
|
|
249
|
+
const PACK_INFO: Record<string, { description: string; hooks: Record<string, string> }> = {
|
|
250
|
+
'typescript-safety': {
|
|
251
|
+
description: 'Block unsafe TypeScript patterns',
|
|
252
|
+
hooks: {
|
|
253
|
+
'no-any-types': '`:any`, `as any`, `<any>`, `Record<string, any>`',
|
|
254
|
+
'no-console-log': '`console.log` in committed code',
|
|
255
|
+
},
|
|
256
|
+
},
|
|
257
|
+
a11y: {
|
|
258
|
+
description: 'Accessibility enforcement',
|
|
259
|
+
hooks: {
|
|
260
|
+
'semantic-html': 'Generic divs where semantic HTML should be used',
|
|
261
|
+
'focus-ring-required': 'Missing visible focus indicators',
|
|
262
|
+
'ux-touch-targets': 'Touch targets smaller than 44px',
|
|
263
|
+
},
|
|
264
|
+
},
|
|
265
|
+
'css-discipline': {
|
|
266
|
+
description: 'CSS best practices',
|
|
267
|
+
hooks: {
|
|
268
|
+
'no-important': '`!important` in CSS',
|
|
269
|
+
'no-inline-styles': 'Inline style attributes',
|
|
270
|
+
},
|
|
271
|
+
},
|
|
272
|
+
'clean-commits': {
|
|
273
|
+
description: 'Clean git history',
|
|
274
|
+
hooks: {
|
|
275
|
+
'no-ai-attribution': 'AI attribution in commits',
|
|
276
|
+
},
|
|
277
|
+
},
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
// Build rows — expand 'full' to constituent packs
|
|
281
|
+
const rows: Array<{ pack: string; hook: string; blocks: string }> = [];
|
|
282
|
+
for (const packName of config.hookPacks) {
|
|
283
|
+
if (packName === 'full') {
|
|
284
|
+
// Composed pack — expand all constituent packs
|
|
285
|
+
for (const [subPack, info] of Object.entries(PACK_INFO)) {
|
|
286
|
+
for (const [hook, blocks] of Object.entries(info.hooks)) {
|
|
287
|
+
rows.push({ pack: subPack, hook, blocks });
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
} else if (PACK_INFO[packName]) {
|
|
291
|
+
for (const [hook, blocks] of Object.entries(PACK_INFO[packName].hooks)) {
|
|
292
|
+
rows.push({ pack: packName, hook, blocks });
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
if (rows.length > 0) {
|
|
298
|
+
// Insert before the closing marker
|
|
299
|
+
const closingMarkerIndex = mdLines.length - 1;
|
|
300
|
+
const hookLines = [
|
|
301
|
+
'',
|
|
302
|
+
'## Hook Packs',
|
|
303
|
+
'',
|
|
304
|
+
'Quality gates installed in `.claude/`. Run `scripts/setup.sh` to install globally.',
|
|
305
|
+
'',
|
|
306
|
+
'| Pack | Hook | Blocks |',
|
|
307
|
+
'|------|------|--------|',
|
|
308
|
+
...rows.map((r) => `| ${r.pack} | ${r.hook} | ${r.blocks} |`),
|
|
309
|
+
];
|
|
310
|
+
mdLines.splice(closingMarkerIndex, 0, ...hookLines);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
133
314
|
// Escape each markdown line for use in a single-quoted TS string literal
|
|
134
315
|
const quotedLines = mdLines.map((line) => {
|
|
135
316
|
const escaped = line.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
|