@soleri/cli 1.8.0 → 1.9.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/code-reviewer/.claude/hookify.focus-ring-required.local.md +21 -0
- package/code-reviewer/.claude/hookify.no-ai-attribution.local.md +18 -0
- package/code-reviewer/.claude/hookify.no-any-types.local.md +18 -0
- package/code-reviewer/.claude/hookify.no-console-log.local.md +21 -0
- package/code-reviewer/.claude/hookify.no-important.local.md +18 -0
- package/code-reviewer/.claude/hookify.no-inline-styles.local.md +21 -0
- package/code-reviewer/.claude/hookify.semantic-html.local.md +18 -0
- package/code-reviewer/.claude/hookify.ux-touch-targets.local.md +18 -0
- package/code-reviewer/.mcp.json +11 -0
- package/code-reviewer/README.md +346 -0
- package/code-reviewer/package-lock.json +4484 -0
- package/code-reviewer/package.json +45 -0
- package/code-reviewer/scripts/copy-assets.js +15 -0
- package/code-reviewer/scripts/setup.sh +130 -0
- package/code-reviewer/skills/brainstorming/SKILL.md +170 -0
- package/code-reviewer/skills/code-patrol/SKILL.md +176 -0
- package/code-reviewer/skills/context-resume/SKILL.md +143 -0
- package/code-reviewer/skills/executing-plans/SKILL.md +201 -0
- package/code-reviewer/skills/fix-and-learn/SKILL.md +164 -0
- package/code-reviewer/skills/health-check/SKILL.md +225 -0
- package/code-reviewer/skills/second-opinion/SKILL.md +142 -0
- package/code-reviewer/skills/systematic-debugging/SKILL.md +230 -0
- package/code-reviewer/skills/verification-before-completion/SKILL.md +170 -0
- package/code-reviewer/skills/writing-plans/SKILL.md +207 -0
- package/code-reviewer/src/__tests__/facades.test.ts +598 -0
- package/code-reviewer/src/activation/activate.ts +125 -0
- package/code-reviewer/src/activation/claude-md-content.ts +217 -0
- package/code-reviewer/src/activation/inject-claude-md.ts +113 -0
- package/code-reviewer/src/extensions/index.ts +47 -0
- package/code-reviewer/src/extensions/ops/example.ts +28 -0
- package/code-reviewer/src/identity/persona.ts +62 -0
- package/code-reviewer/src/index.ts +278 -0
- package/code-reviewer/src/intelligence/data/architecture.json +5 -0
- package/code-reviewer/src/intelligence/data/code-review.json +5 -0
- package/code-reviewer/tsconfig.json +30 -0
- package/code-reviewer/vitest.config.ts +23 -0
- package/dist/prompts/archetypes.js +35 -5
- package/dist/prompts/archetypes.js.map +1 -1
- package/dist/prompts/create-wizard.js +7 -11
- package/dist/prompts/create-wizard.js.map +1 -1
- package/dist/prompts/playbook.js +121 -25
- package/dist/prompts/playbook.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { PERSONA } from '../identity/persona.js';
|
|
4
|
+
import { hasAgentMarker, removeClaudeMdGlobal } from './inject-claude-md.js';
|
|
5
|
+
import type { Vault, Planner, Plan } from '@soleri/core';
|
|
6
|
+
|
|
7
|
+
export interface ActivationResult {
|
|
8
|
+
activated: boolean;
|
|
9
|
+
persona: {
|
|
10
|
+
name: string;
|
|
11
|
+
role: string;
|
|
12
|
+
description: string;
|
|
13
|
+
greeting: string;
|
|
14
|
+
};
|
|
15
|
+
guidelines: string[];
|
|
16
|
+
tool_recommendations: Array<{ intent: string; facade: string; op: string }>;
|
|
17
|
+
session_instruction: string;
|
|
18
|
+
setup_status: {
|
|
19
|
+
claude_md_injected: boolean;
|
|
20
|
+
global_claude_md_injected: boolean;
|
|
21
|
+
vault_has_entries: boolean;
|
|
22
|
+
vault_entry_count: number;
|
|
23
|
+
};
|
|
24
|
+
executing_plans: Array<{ id: string; objective: string; tasks: number; completed: number }>;
|
|
25
|
+
next_steps: string[];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface DeactivationResult {
|
|
29
|
+
deactivated: boolean;
|
|
30
|
+
message: string;
|
|
31
|
+
cleanup?: {
|
|
32
|
+
globalClaudeMd: boolean;
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Activate Code Reviewer — returns full context for Claude to adopt the persona.
|
|
38
|
+
*/
|
|
39
|
+
export function activateAgent(vault: Vault, projectPath: string, planner?: Planner): ActivationResult {
|
|
40
|
+
// Check CLAUDE.md injection status (project-level and global)
|
|
41
|
+
const projectClaudeMd = join(projectPath, 'CLAUDE.md');
|
|
42
|
+
const globalClaudeMd = join(homedir(), '.claude', 'CLAUDE.md');
|
|
43
|
+
const claudeMdInjected = hasAgentMarker(projectClaudeMd);
|
|
44
|
+
const globalClaudeMdInjected = hasAgentMarker(globalClaudeMd);
|
|
45
|
+
|
|
46
|
+
// Check vault status
|
|
47
|
+
const stats = vault.stats();
|
|
48
|
+
const vaultHasEntries = stats.totalEntries > 0;
|
|
49
|
+
|
|
50
|
+
// Build next steps based on what's missing
|
|
51
|
+
const nextSteps: string[] = [];
|
|
52
|
+
if (!globalClaudeMdInjected && !claudeMdInjected) {
|
|
53
|
+
nextSteps.push('No CLAUDE.md configured — run inject_claude_md with global: true for all projects, or without for this project only');
|
|
54
|
+
} else if (!globalClaudeMdInjected) {
|
|
55
|
+
nextSteps.push('Global CLAUDE.md not configured — run inject_claude_md with global: true to enable activation in all projects');
|
|
56
|
+
}
|
|
57
|
+
if (!vaultHasEntries) {
|
|
58
|
+
nextSteps.push('Vault is empty — start capturing knowledge with the domain capture ops');
|
|
59
|
+
}
|
|
60
|
+
if (nextSteps.length === 0) {
|
|
61
|
+
nextSteps.push('All set! Code Reviewer is fully integrated.');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Check for executing plans
|
|
65
|
+
const executingPlans = planner ? planner.getExecuting().map((p) => ({
|
|
66
|
+
id: p.id,
|
|
67
|
+
objective: p.objective,
|
|
68
|
+
tasks: p.tasks.length,
|
|
69
|
+
completed: p.tasks.filter((t) => t.status === 'completed').length,
|
|
70
|
+
})) : [];
|
|
71
|
+
if (executingPlans.length > 0) {
|
|
72
|
+
nextSteps.unshift(`${executingPlans.length} plan(s) in progress — use get_plan to review`);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
activated: true,
|
|
77
|
+
persona: {
|
|
78
|
+
name: PERSONA.name,
|
|
79
|
+
role: PERSONA.role,
|
|
80
|
+
description: PERSONA.description,
|
|
81
|
+
greeting: PERSONA.greeting,
|
|
82
|
+
},
|
|
83
|
+
guidelines: [
|
|
84
|
+
'Actionable feedback only',
|
|
85
|
+
'Respect existing patterns',
|
|
86
|
+
'Simplicity over cleverness',
|
|
87
|
+
],
|
|
88
|
+
tool_recommendations: [
|
|
89
|
+
{ intent: 'health check', facade: 'code-reviewer_core', op: 'health' },
|
|
90
|
+
{ intent: 'search all', facade: 'code-reviewer_core', op: 'search' },
|
|
91
|
+
{ intent: 'vault stats', facade: 'code-reviewer_core', op: 'vault_stats' },
|
|
92
|
+
{ intent: 'search code-review', facade: 'code-reviewer_code_review', op: 'search' },
|
|
93
|
+
{ intent: 'code-review patterns', facade: 'code-reviewer_code_review', op: 'get_patterns' },
|
|
94
|
+
{ intent: 'capture code-review', facade: 'code-reviewer_code_review', op: 'capture' },
|
|
95
|
+
{ intent: 'search architecture', facade: 'code-reviewer_architecture', op: 'search' },
|
|
96
|
+
{ intent: 'architecture patterns', facade: 'code-reviewer_architecture', op: 'get_patterns' },
|
|
97
|
+
{ intent: 'capture architecture', facade: 'code-reviewer_architecture', op: 'capture' },
|
|
98
|
+
],
|
|
99
|
+
session_instruction: 'You are now ' + PERSONA.name + ', a ' + PERSONA.role + '. Stay in character for the ENTIRE session. ' +
|
|
100
|
+
'Reference patterns from the knowledge vault. Provide concrete examples. Flag anti-patterns with severity.',
|
|
101
|
+
setup_status: {
|
|
102
|
+
claude_md_injected: claudeMdInjected,
|
|
103
|
+
global_claude_md_injected: globalClaudeMdInjected,
|
|
104
|
+
vault_has_entries: vaultHasEntries,
|
|
105
|
+
vault_entry_count: stats.totalEntries,
|
|
106
|
+
},
|
|
107
|
+
executing_plans: executingPlans,
|
|
108
|
+
next_steps: nextSteps,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Deactivate Code Reviewer — drops persona and cleans up CLAUDE.md sections.
|
|
114
|
+
*/
|
|
115
|
+
export function deactivateAgent(): DeactivationResult {
|
|
116
|
+
// Remove agent sections from global CLAUDE.md on deactivation
|
|
117
|
+
const globalResult = removeClaudeMdGlobal();
|
|
118
|
+
return {
|
|
119
|
+
deactivated: true,
|
|
120
|
+
message: 'Goodbye! ' + PERSONA.name + ' persona deactivated. Reverting to default behavior.',
|
|
121
|
+
cleanup: {
|
|
122
|
+
globalClaudeMd: globalResult.removed,
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLAUDE.md content for Code Reviewer.
|
|
3
|
+
* Generated by Soleri — do not edit manually.
|
|
4
|
+
*/
|
|
5
|
+
export function getClaudeMdContent(): string {
|
|
6
|
+
return [
|
|
7
|
+
'<!-- code-reviewer:mode -->',
|
|
8
|
+
'',
|
|
9
|
+
'# Code Reviewer Mode',
|
|
10
|
+
'',
|
|
11
|
+
'## Code Reviewer Integration',
|
|
12
|
+
'',
|
|
13
|
+
'**Activate:** "Hello, Code Reviewer!" → `code-reviewer_core op:activate params:{ projectPath: "." }`',
|
|
14
|
+
'**Deactivate:** "Goodbye, Code Reviewer!" → `code-reviewer_core op:activate params:{ deactivate: true }`',
|
|
15
|
+
'',
|
|
16
|
+
'On activation, adopt the returned persona. Stay in character until deactivated.',
|
|
17
|
+
'',
|
|
18
|
+
'## Session Start',
|
|
19
|
+
'',
|
|
20
|
+
'On every new session: `code-reviewer_core op:register params:{ projectPath: "." }`',
|
|
21
|
+
'',
|
|
22
|
+
'## Facades',
|
|
23
|
+
'',
|
|
24
|
+
'| Need | Facade | Op |',
|
|
25
|
+
'|------|--------|----|',
|
|
26
|
+
'| Health check | `code-reviewer_core` | `health` |',
|
|
27
|
+
'| Search all | `code-reviewer_core` | `search` |',
|
|
28
|
+
'| Vault stats | `code-reviewer_core` | `vault_stats` |',
|
|
29
|
+
'| Identity | `code-reviewer_core` | `identity` |',
|
|
30
|
+
'| code-review patterns | `code-reviewer_code_review` | `get_patterns` |',
|
|
31
|
+
'| Search code-review | `code-reviewer_code_review` | `search` |',
|
|
32
|
+
'| Capture code-review | `code-reviewer_code_review` | `capture` |',
|
|
33
|
+
'| architecture patterns | `code-reviewer_architecture` | `get_patterns` |',
|
|
34
|
+
'| Search architecture | `code-reviewer_architecture` | `search` |',
|
|
35
|
+
'| Capture architecture | `code-reviewer_architecture` | `capture` |',
|
|
36
|
+
'| Memory search | `code-reviewer_core` | `memory_search` |',
|
|
37
|
+
'| Memory capture | `code-reviewer_core` | `memory_capture` |',
|
|
38
|
+
'| Memory list | `code-reviewer_core` | `memory_list` |',
|
|
39
|
+
'| Session capture | `code-reviewer_core` | `session_capture` |',
|
|
40
|
+
'| Export knowledge | `code-reviewer_core` | `export` |',
|
|
41
|
+
'| Record feedback | `code-reviewer_core` | `record_feedback` |',
|
|
42
|
+
'| Enhanced feedback | `code-reviewer_core` | `brain_feedback` |',
|
|
43
|
+
'| Feedback stats | `code-reviewer_core` | `brain_feedback_stats` |',
|
|
44
|
+
'| Reset extracted | `code-reviewer_core` | `brain_reset_extracted` |',
|
|
45
|
+
'| Rebuild vocabulary | `code-reviewer_core` | `rebuild_vocabulary` |',
|
|
46
|
+
'| Brain stats | `code-reviewer_core` | `brain_stats` |',
|
|
47
|
+
'| LLM status | `code-reviewer_core` | `llm_status` |',
|
|
48
|
+
'| Create plan | `code-reviewer_core` | `create_plan` |',
|
|
49
|
+
'| Get plan | `code-reviewer_core` | `get_plan` |',
|
|
50
|
+
'| Approve plan | `code-reviewer_core` | `approve_plan` |',
|
|
51
|
+
'| Update task | `code-reviewer_core` | `update_task` |',
|
|
52
|
+
'| Complete plan | `code-reviewer_core` | `complete_plan` |',
|
|
53
|
+
'| Route intent | `code-reviewer_core` | `route_intent` |',
|
|
54
|
+
'| Morph mode | `code-reviewer_core` | `morph` |',
|
|
55
|
+
'| Get behavior rules | `code-reviewer_core` | `get_behavior_rules` |',
|
|
56
|
+
'| Get identity | `code-reviewer_core` | `get_identity` |',
|
|
57
|
+
'| Update identity | `code-reviewer_core` | `update_identity` |',
|
|
58
|
+
'| Add guideline | `code-reviewer_core` | `add_guideline` |',
|
|
59
|
+
'| Remove guideline | `code-reviewer_core` | `remove_guideline` |',
|
|
60
|
+
'| Rollback identity | `code-reviewer_core` | `rollback_identity` |',
|
|
61
|
+
'| Cognee status | `code-reviewer_core` | `cognee_status` |',
|
|
62
|
+
'| Cognee search | `code-reviewer_core` | `cognee_search` |',
|
|
63
|
+
'| Cognee add | `code-reviewer_core` | `cognee_add` |',
|
|
64
|
+
'| Cognee cognify | `code-reviewer_core` | `cognee_cognify` |',
|
|
65
|
+
'| Cognee config | `code-reviewer_core` | `cognee_config` |',
|
|
66
|
+
'| LLM rotate key | `code-reviewer_core` | `llm_rotate` |',
|
|
67
|
+
'| LLM call | `code-reviewer_core` | `llm_call` |',
|
|
68
|
+
'| Governance policy | `code-reviewer_core` | `governance_policy` |',
|
|
69
|
+
'| Governance proposals | `code-reviewer_core` | `governance_proposals` |',
|
|
70
|
+
'| Governance stats | `code-reviewer_core` | `governance_stats` |',
|
|
71
|
+
'| Expire proposals | `code-reviewer_core` | `governance_expire` |',
|
|
72
|
+
'| Governance dashboard | `code-reviewer_core` | `governance_dashboard` |',
|
|
73
|
+
'| Iterate plan | `code-reviewer_core` | `plan_iterate` |',
|
|
74
|
+
'| Split plan tasks | `code-reviewer_core` | `plan_split` |',
|
|
75
|
+
'| Reconcile plan | `code-reviewer_core` | `plan_reconcile` |',
|
|
76
|
+
'| Complete lifecycle | `code-reviewer_core` | `plan_complete_lifecycle` |',
|
|
77
|
+
'| Dispatch tasks | `code-reviewer_core` | `plan_dispatch` |',
|
|
78
|
+
'| Review plan | `code-reviewer_core` | `plan_review` |',
|
|
79
|
+
'| Archive plan | `code-reviewer_core` | `plan_archive` |',
|
|
80
|
+
'| List plan tasks | `code-reviewer_core` | `plan_list_tasks` |',
|
|
81
|
+
'| Plan stats | `code-reviewer_core` | `plan_stats` |',
|
|
82
|
+
'| Delete memory | `code-reviewer_core` | `memory_delete` |',
|
|
83
|
+
'| Memory stats | `code-reviewer_core` | `memory_stats` |',
|
|
84
|
+
'| Export memories | `code-reviewer_core` | `memory_export` |',
|
|
85
|
+
'| Import memories | `code-reviewer_core` | `memory_import` |',
|
|
86
|
+
'| Prune memories | `code-reviewer_core` | `memory_prune` |',
|
|
87
|
+
'| Deduplicate memories | `code-reviewer_core` | `memory_deduplicate` |',
|
|
88
|
+
'| Memory topics | `code-reviewer_core` | `memory_topics` |',
|
|
89
|
+
'| Memories by project | `code-reviewer_core` | `memory_by_project` |',
|
|
90
|
+
'| Get vault entry | `code-reviewer_core` | `vault_get` |',
|
|
91
|
+
'| Update entry | `code-reviewer_core` | `vault_update` |',
|
|
92
|
+
'| Remove entry | `code-reviewer_core` | `vault_remove` |',
|
|
93
|
+
'| Bulk add | `code-reviewer_core` | `vault_bulk_add` |',
|
|
94
|
+
'| Bulk remove | `code-reviewer_core` | `vault_bulk_remove` |',
|
|
95
|
+
'| Vault tags | `code-reviewer_core` | `vault_tags` |',
|
|
96
|
+
'| Vault domains | `code-reviewer_core` | `vault_domains` |',
|
|
97
|
+
'| Recent entries | `code-reviewer_core` | `vault_recent` |',
|
|
98
|
+
'| Import entries | `code-reviewer_core` | `vault_import` |',
|
|
99
|
+
'| Seed entries | `code-reviewer_core` | `vault_seed` |',
|
|
100
|
+
'| Backup vault | `code-reviewer_core` | `vault_backup` |',
|
|
101
|
+
'| Vault age report | `code-reviewer_core` | `vault_age_report` |',
|
|
102
|
+
'| Admin health | `code-reviewer_core` | `admin_health` |',
|
|
103
|
+
'| Tool list | `code-reviewer_core` | `admin_tool_list` |',
|
|
104
|
+
'| Config | `code-reviewer_core` | `admin_config` |',
|
|
105
|
+
'| Vault size | `code-reviewer_core` | `admin_vault_size` |',
|
|
106
|
+
'| Uptime | `code-reviewer_core` | `admin_uptime` |',
|
|
107
|
+
'| Version | `code-reviewer_core` | `admin_version` |',
|
|
108
|
+
'| Reset cache | `code-reviewer_core` | `admin_reset_cache` |',
|
|
109
|
+
'| Diagnostic | `code-reviewer_core` | `admin_diagnostic` |',
|
|
110
|
+
'| Start loop | `code-reviewer_core` | `loop_start` |',
|
|
111
|
+
'| Loop iterate | `code-reviewer_core` | `loop_iterate` |',
|
|
112
|
+
'| Loop status | `code-reviewer_core` | `loop_status` |',
|
|
113
|
+
'| Cancel loop | `code-reviewer_core` | `loop_cancel` |',
|
|
114
|
+
'| Loop history | `code-reviewer_core` | `loop_history` |',
|
|
115
|
+
'| Loop active | `code-reviewer_core` | `loop_is_active` |',
|
|
116
|
+
'| Complete loop | `code-reviewer_core` | `loop_complete` |',
|
|
117
|
+
'| Orchestrate plan | `code-reviewer_core` | `orchestrate_plan` |',
|
|
118
|
+
'| Orchestrate execute | `code-reviewer_core` | `orchestrate_execute` |',
|
|
119
|
+
'| Orchestrate complete | `code-reviewer_core` | `orchestrate_complete` |',
|
|
120
|
+
'| Orchestrate status | `code-reviewer_core` | `orchestrate_status` |',
|
|
121
|
+
'| Quick capture | `code-reviewer_core` | `orchestrate_quick_capture` |',
|
|
122
|
+
'| Capture knowledge | `code-reviewer_core` | `capture_knowledge` |',
|
|
123
|
+
'| Quick capture entry | `code-reviewer_core` | `capture_quick` |',
|
|
124
|
+
'| Intelligent search | `code-reviewer_core` | `search_intelligent` |',
|
|
125
|
+
'| Search feedback | `code-reviewer_core` | `search_feedback` |',
|
|
126
|
+
'| Grade plan | `code-reviewer_core` | `plan_grade` |',
|
|
127
|
+
'| Check history | `code-reviewer_core` | `plan_check_history` |',
|
|
128
|
+
'| Latest check | `code-reviewer_core` | `plan_latest_check` |',
|
|
129
|
+
'| Meets grade | `code-reviewer_core` | `plan_meets_grade` |',
|
|
130
|
+
'| Auto improve plan | `code-reviewer_core` | `plan_auto_improve` |',
|
|
131
|
+
'| Telemetry stats | `code-reviewer_core` | `admin_telemetry` |',
|
|
132
|
+
'| Recent calls | `code-reviewer_core` | `admin_telemetry_recent` |',
|
|
133
|
+
'| Reset telemetry | `code-reviewer_core` | `admin_telemetry_reset` |',
|
|
134
|
+
'| Permissions | `code-reviewer_core` | `admin_permissions` |',
|
|
135
|
+
'| Vault analytics | `code-reviewer_core` | `admin_vault_analytics` |',
|
|
136
|
+
'| Search insights | `code-reviewer_core` | `admin_search_insights` |',
|
|
137
|
+
'| Module status | `code-reviewer_core` | `admin_module_status` |',
|
|
138
|
+
'| Environment | `code-reviewer_core` | `admin_env` |',
|
|
139
|
+
'| Garbage collect | `code-reviewer_core` | `admin_gc` |',
|
|
140
|
+
'| Export config | `code-reviewer_core` | `admin_export_config` |',
|
|
141
|
+
'| Entry history | `code-reviewer_core` | `curator_entry_history` |',
|
|
142
|
+
'| Record snapshot | `code-reviewer_core` | `curator_record_snapshot` |',
|
|
143
|
+
'| Queue stats | `code-reviewer_core` | `curator_queue_stats` |',
|
|
144
|
+
'| Enrich metadata | `code-reviewer_core` | `curator_enrich` |',
|
|
145
|
+
'| Get project | `code-reviewer_core` | `project_get` |',
|
|
146
|
+
'| List projects | `code-reviewer_core` | `project_list` |',
|
|
147
|
+
'| Unregister project | `code-reviewer_core` | `project_unregister` |',
|
|
148
|
+
'| Project rules | `code-reviewer_core` | `project_get_rules` |',
|
|
149
|
+
'| All project rules | `code-reviewer_core` | `project_list_rules` |',
|
|
150
|
+
'| Add rule | `code-reviewer_core` | `project_add_rule` |',
|
|
151
|
+
'| Remove rule | `code-reviewer_core` | `project_remove_rule` |',
|
|
152
|
+
'| Link projects | `code-reviewer_core` | `project_link` |',
|
|
153
|
+
'| Unlink projects | `code-reviewer_core` | `project_unlink` |',
|
|
154
|
+
'| Project links | `code-reviewer_core` | `project_get_links` |',
|
|
155
|
+
'| Linked projects | `code-reviewer_core` | `project_linked_projects` |',
|
|
156
|
+
'| Touch project | `code-reviewer_core` | `project_touch` |',
|
|
157
|
+
'| Promote to global | `code-reviewer_core` | `memory_promote_to_global` |',
|
|
158
|
+
'| Configure memory | `code-reviewer_core` | `memory_configure` |',
|
|
159
|
+
'| Cross-project search | `code-reviewer_core` | `memory_cross_project_search` |',
|
|
160
|
+
'',
|
|
161
|
+
'## Auto-Routing',
|
|
162
|
+
'',
|
|
163
|
+
'A UserPromptSubmit hook auto-classifies every prompt via keyword matching.',
|
|
164
|
+
'When you see a `[MODE-NAME]` indicator in the system context:',
|
|
165
|
+
'',
|
|
166
|
+
'1. Call `code-reviewer_core op:route_intent params:{ prompt: "<user message>" }` to get full behavior rules',
|
|
167
|
+
'2. Follow the returned behavior rules for the detected mode',
|
|
168
|
+
'3. Briefly acknowledge mode changes in your response (e.g., "Switching to FIX-MODE")',
|
|
169
|
+
'',
|
|
170
|
+
'Available modes: FIX-MODE, BUILD-MODE, IMPROVE-MODE, DELIVER-MODE, REVIEW-MODE, PLAN-MODE, DESIGN-MODE, VALIDATE-MODE, EXPLORE-MODE, GENERAL-MODE.',
|
|
171
|
+
'GENERAL-MODE means the hook detected a work task but could not classify a specific mode — route_intent will refine it.',
|
|
172
|
+
'',
|
|
173
|
+
'## Intent Detection',
|
|
174
|
+
'',
|
|
175
|
+
'| Signal | Intent |',
|
|
176
|
+
'|--------|--------|',
|
|
177
|
+
'| Problem described ("broken", "janky", "weird") | FIX |',
|
|
178
|
+
'| Need expressed ("I need", "we should have") | BUILD |',
|
|
179
|
+
'| Quality questioned ("is this right?") | REVIEW |',
|
|
180
|
+
'| Advice sought ("how should I", "best way") | PLAN |',
|
|
181
|
+
'| Improvement requested ("make it faster") | IMPROVE |',
|
|
182
|
+
'',
|
|
183
|
+
'## Knowledge Protocol',
|
|
184
|
+
'',
|
|
185
|
+
'When seeking guidance: vault before codebase before web.',
|
|
186
|
+
'',
|
|
187
|
+
'1. Search vault — `code-reviewer_core op:search`',
|
|
188
|
+
'2. Codebase — only if vault has nothing',
|
|
189
|
+
'3. Web — last resort',
|
|
190
|
+
'',
|
|
191
|
+
'## Knowledge Capture',
|
|
192
|
+
'',
|
|
193
|
+
'When learning something that should persist, use the domain capture ops.',
|
|
194
|
+
'',
|
|
195
|
+
'## Session Capture',
|
|
196
|
+
'',
|
|
197
|
+
'A PreCompact hook is configured to call `session_capture` before context compaction.',
|
|
198
|
+
'This automatically preserves session summaries as memories for future sessions.',
|
|
199
|
+
'To manually capture: `code-reviewer_core op:session_capture params:{ summary: "..." }`',
|
|
200
|
+
'',
|
|
201
|
+
'## Planning',
|
|
202
|
+
'',
|
|
203
|
+
'For multi-step tasks, use the planning system:',
|
|
204
|
+
'1. Create: `code-reviewer_core op:create_plan params:{ objective: "...", scope: "...", tasks: [...] }`',
|
|
205
|
+
'2. Approve: `code-reviewer_core op:approve_plan params:{ planId: "...", startExecution: true }`',
|
|
206
|
+
'3. Track: `code-reviewer_core op:update_task params:{ planId: "...", taskId: "...", status: "completed" }`',
|
|
207
|
+
'4. Complete: `code-reviewer_core op:complete_plan params:{ planId: "..." }`',
|
|
208
|
+
'',
|
|
209
|
+
'Check activation response for recovered plans in `executing` state — remind the user.',
|
|
210
|
+
'',
|
|
211
|
+
'<!-- /code-reviewer:mode -->',
|
|
212
|
+
].join('\n');
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
export function getClaudeMdMarker(): string {
|
|
216
|
+
return 'code-reviewer:mode';
|
|
217
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { getClaudeMdContent, getClaudeMdMarker } from './claude-md-content.js';
|
|
5
|
+
|
|
6
|
+
export interface InjectResult {
|
|
7
|
+
injected: boolean;
|
|
8
|
+
path: string;
|
|
9
|
+
action: 'created' | 'updated' | 'appended';
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Inject into a specific CLAUDE.md file path.
|
|
14
|
+
* Shared logic for both project-level and global injection.
|
|
15
|
+
*/
|
|
16
|
+
function injectIntoFile(filePath: string): InjectResult {
|
|
17
|
+
const content = getClaudeMdContent();
|
|
18
|
+
const marker = getClaudeMdMarker();
|
|
19
|
+
const startMarker = '<!-- ' + marker + ' -->';
|
|
20
|
+
const endMarker = '<!-- /' + marker + ' -->';
|
|
21
|
+
|
|
22
|
+
if (!existsSync(filePath)) {
|
|
23
|
+
writeFileSync(filePath, content + '\n', 'utf-8');
|
|
24
|
+
return { injected: true, path: filePath, action: 'created' };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const existing = readFileSync(filePath, 'utf-8');
|
|
28
|
+
|
|
29
|
+
if (existing.includes(startMarker)) {
|
|
30
|
+
const startIdx = existing.indexOf(startMarker);
|
|
31
|
+
const endIdx = existing.indexOf(endMarker);
|
|
32
|
+
if (endIdx === -1) {
|
|
33
|
+
const updated = existing.slice(0, startIdx) + content + '\n' + existing.slice(startIdx + startMarker.length);
|
|
34
|
+
writeFileSync(filePath, updated, 'utf-8');
|
|
35
|
+
return { injected: true, path: filePath, action: 'updated' };
|
|
36
|
+
}
|
|
37
|
+
const updated = existing.slice(0, startIdx) + content + existing.slice(endIdx + endMarker.length);
|
|
38
|
+
writeFileSync(filePath, updated, 'utf-8');
|
|
39
|
+
return { injected: true, path: filePath, action: 'updated' };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const separator = existing.endsWith('\n') ? '\n' : '\n\n';
|
|
43
|
+
writeFileSync(filePath, existing + separator + content + '\n', 'utf-8');
|
|
44
|
+
return { injected: true, path: filePath, action: 'appended' };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Inject agent CLAUDE.md section into a project.
|
|
49
|
+
* - If no CLAUDE.md exists: creates one
|
|
50
|
+
* - If markers found: replaces content between them (update)
|
|
51
|
+
* - If no markers: appends section to end
|
|
52
|
+
*/
|
|
53
|
+
export function injectClaudeMd(projectPath: string): InjectResult {
|
|
54
|
+
return injectIntoFile(join(projectPath, 'CLAUDE.md'));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Inject agent CLAUDE.md section into the global ~/.claude/CLAUDE.md.
|
|
59
|
+
* Creates ~/.claude/ directory if it doesn't exist.
|
|
60
|
+
* This makes the activation phrase work in any project.
|
|
61
|
+
*/
|
|
62
|
+
export function injectClaudeMdGlobal(): InjectResult {
|
|
63
|
+
const claudeDir = join(homedir(), '.claude');
|
|
64
|
+
if (!existsSync(claudeDir)) {
|
|
65
|
+
mkdirSync(claudeDir, { recursive: true });
|
|
66
|
+
}
|
|
67
|
+
return injectIntoFile(join(claudeDir, 'CLAUDE.md'));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Remove agent section from a specific CLAUDE.md file.
|
|
72
|
+
* Returns true if the section was found and removed.
|
|
73
|
+
*/
|
|
74
|
+
function removeFromFile(filePath: string): { removed: boolean; path: string } {
|
|
75
|
+
if (!existsSync(filePath)) return { removed: false, path: filePath };
|
|
76
|
+
const existing = readFileSync(filePath, 'utf-8');
|
|
77
|
+
const marker = getClaudeMdMarker();
|
|
78
|
+
const startMarker = '<!-- ' + marker + ' -->';
|
|
79
|
+
const endMarker = '<!-- /' + marker + ' -->';
|
|
80
|
+
const startIdx = existing.indexOf(startMarker);
|
|
81
|
+
if (startIdx === -1) return { removed: false, path: filePath };
|
|
82
|
+
const endIdx = existing.indexOf(endMarker);
|
|
83
|
+
if (endIdx === -1) return { removed: false, path: filePath };
|
|
84
|
+
const before = existing.slice(0, startIdx).replace(/\n+$/, '');
|
|
85
|
+
const after = existing.slice(endIdx + endMarker.length).replace(/^\n+/, '');
|
|
86
|
+
const cleaned = before + (before && after ? '\n\n' : '') + after;
|
|
87
|
+
writeFileSync(filePath, cleaned || '', 'utf-8');
|
|
88
|
+
return { removed: true, path: filePath };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Remove agent section from the global ~/.claude/CLAUDE.md.
|
|
93
|
+
* Called on deactivation to clean up after test agents.
|
|
94
|
+
*/
|
|
95
|
+
export function removeClaudeMdGlobal(): { removed: boolean; path: string } {
|
|
96
|
+
return removeFromFile(join(homedir(), '.claude', 'CLAUDE.md'));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Remove agent section from a project CLAUDE.md.
|
|
101
|
+
*/
|
|
102
|
+
export function removeClaudeMd(projectPath: string): { removed: boolean; path: string } {
|
|
103
|
+
return removeFromFile(join(projectPath, 'CLAUDE.md'));
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Check if the agent marker exists in a CLAUDE.md file.
|
|
108
|
+
*/
|
|
109
|
+
export function hasAgentMarker(filePath: string): boolean {
|
|
110
|
+
if (!existsSync(filePath)) return false;
|
|
111
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
112
|
+
return content.includes('<!-- code-reviewer:mode -->');
|
|
113
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Code Reviewer — Custom Extensions
|
|
3
|
+
*
|
|
4
|
+
* Add your custom ops, facades, middleware, and lifecycle hooks here.
|
|
5
|
+
* This file is auto-discovered by the agent entry point at startup.
|
|
6
|
+
*
|
|
7
|
+
* Core ops from @soleri/core are never modified — your extensions are
|
|
8
|
+
* additive (new ops, new facades) or decorative (middleware).
|
|
9
|
+
*
|
|
10
|
+
* See: https://soleri.dev/docs/extending
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import type { AgentExtensions, AgentRuntime } from '@soleri/core';
|
|
14
|
+
|
|
15
|
+
// Import your custom ops, facades, and middleware here:
|
|
16
|
+
// import { myCustomOp } from './ops/my-custom-op.js';
|
|
17
|
+
// import { myFacade } from './facades/my-facade.js';
|
|
18
|
+
// import { auditLogger } from './middleware/audit-logger.js';
|
|
19
|
+
|
|
20
|
+
export default function loadExtensions(runtime: AgentRuntime): AgentExtensions {
|
|
21
|
+
return {
|
|
22
|
+
// ── Custom ops (merged into code-reviewer_core facade) ──────────
|
|
23
|
+
// ops: [
|
|
24
|
+
// myCustomOp(runtime),
|
|
25
|
+
// ],
|
|
26
|
+
|
|
27
|
+
// ── Custom facades (registered as separate MCP tools) ──────────
|
|
28
|
+
// facades: [
|
|
29
|
+
// myFacade(runtime),
|
|
30
|
+
// ],
|
|
31
|
+
|
|
32
|
+
// ── Middleware (wraps ALL ops across ALL facades) ───────────────
|
|
33
|
+
// middleware: [
|
|
34
|
+
// auditLogger,
|
|
35
|
+
// ],
|
|
36
|
+
|
|
37
|
+
// ── Lifecycle hooks ────────────────────────────────────────────
|
|
38
|
+
// hooks: {
|
|
39
|
+
// onStartup: async (rt) => {
|
|
40
|
+
// console.error('[code-reviewer] Custom startup logic');
|
|
41
|
+
// },
|
|
42
|
+
// onShutdown: async (rt) => {
|
|
43
|
+
// console.error('[code-reviewer] Custom shutdown logic');
|
|
44
|
+
// },
|
|
45
|
+
// },
|
|
46
|
+
};
|
|
47
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Example custom op — add your own logic here.
|
|
3
|
+
*
|
|
4
|
+
* Custom ops are merged into the code-reviewer_core facade alongside
|
|
5
|
+
* the built-in ops from @soleri/core. They have full access
|
|
6
|
+
* to the agent runtime (vault, brain, planner, etc.).
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { z } from 'zod';
|
|
10
|
+
import type { OpDefinition, AgentRuntime } from '@soleri/core';
|
|
11
|
+
|
|
12
|
+
export function createExampleOp(runtime: AgentRuntime): OpDefinition {
|
|
13
|
+
return {
|
|
14
|
+
name: 'example',
|
|
15
|
+
description: 'Example custom op — replace with your own logic.',
|
|
16
|
+
auth: 'read',
|
|
17
|
+
schema: z.object({
|
|
18
|
+
message: z.string().optional().describe('Optional message'),
|
|
19
|
+
}),
|
|
20
|
+
handler: async (params) => {
|
|
21
|
+
const stats = runtime.vault.stats();
|
|
22
|
+
return {
|
|
23
|
+
message: params.message ?? 'Hello from custom extension!',
|
|
24
|
+
vaultEntries: stats.totalEntries,
|
|
25
|
+
};
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
export interface AgentPersona {
|
|
2
|
+
name: string;
|
|
3
|
+
role: string;
|
|
4
|
+
description: string;
|
|
5
|
+
principles: string[];
|
|
6
|
+
tone: 'precise' | 'mentor' | 'pragmatic';
|
|
7
|
+
greeting: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const PERSONA: AgentPersona = {
|
|
11
|
+
name: 'Code Reviewer',
|
|
12
|
+
role: 'Catches bugs, enforces code patterns, and reviews pull requests before merge',
|
|
13
|
+
description: 'This agent reviews code for quality issues, anti-patterns, naming conventions, test coverage gaps, and architectural violations. It provides actionable feedback with concrete fix suggestions.',
|
|
14
|
+
principles: [
|
|
15
|
+
'Actionable feedback only',
|
|
16
|
+
'Respect existing patterns',
|
|
17
|
+
'Simplicity over cleverness',
|
|
18
|
+
],
|
|
19
|
+
tone: 'pragmatic',
|
|
20
|
+
greeting: 'Hello! I\'m Code Reviewer. Drop a PR link or paste code — I\'ll review it for bugs, patterns, and quality.',
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const TONE_INSTRUCTIONS: Record<string, string[]> = {
|
|
24
|
+
precise: [
|
|
25
|
+
'Communication style: precise',
|
|
26
|
+
'- Be direct and factual with minimal commentary',
|
|
27
|
+
'- Lead with the conclusion, then support it',
|
|
28
|
+
'- Omit caveats unless they change the recommendation',
|
|
29
|
+
],
|
|
30
|
+
mentor: [
|
|
31
|
+
'Communication style: mentor',
|
|
32
|
+
'- Explain the "why" behind every suggestion',
|
|
33
|
+
'- Use examples to illustrate concepts',
|
|
34
|
+
'- Guide the user to understand, not just follow instructions',
|
|
35
|
+
],
|
|
36
|
+
pragmatic: [
|
|
37
|
+
'Communication style: pragmatic',
|
|
38
|
+
'- Focus on actionable outcomes',
|
|
39
|
+
'- Balance thoroughness with brevity',
|
|
40
|
+
'- Prioritize what matters most for the current context',
|
|
41
|
+
],
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export function getPersonaPrompt(): string {
|
|
45
|
+
const toneLines = TONE_INSTRUCTIONS[PERSONA.tone] ?? TONE_INSTRUCTIONS.pragmatic;
|
|
46
|
+
return [
|
|
47
|
+
`You are ${PERSONA.name}, a ${PERSONA.role}.`,
|
|
48
|
+
'',
|
|
49
|
+
PERSONA.description,
|
|
50
|
+
'',
|
|
51
|
+
'Core principles:',
|
|
52
|
+
...PERSONA.principles.map((p) => `- ${p}`),
|
|
53
|
+
'',
|
|
54
|
+
...toneLines,
|
|
55
|
+
'',
|
|
56
|
+
'When advising:',
|
|
57
|
+
'- Reference specific patterns from the knowledge vault',
|
|
58
|
+
'- Provide concrete examples, not just theory',
|
|
59
|
+
'- Flag anti-patterns with severity level',
|
|
60
|
+
'- Suggest the simplest approach that solves the problem',
|
|
61
|
+
].join('\n');
|
|
62
|
+
}
|