overarch-darwin-arm64 0.8.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/LICENSE +21 -0
- package/README.md +214 -0
- package/dist/bin/overarch.d.ts +2 -0
- package/dist/bin/overarch.js +178 -0
- package/dist/src/agent/context.d.ts +14 -0
- package/dist/src/agent/context.js +200 -0
- package/dist/src/agent/context_compressor.d.ts +21 -0
- package/dist/src/agent/context_compressor.js +90 -0
- package/dist/src/agent/manifest.d.ts +22 -0
- package/dist/src/agent/manifest.js +131 -0
- package/dist/src/agent/planner.d.ts +38 -0
- package/dist/src/agent/planner.js +118 -0
- package/dist/src/agent/runtime.d.ts +59 -0
- package/dist/src/agent/runtime.js +400 -0
- package/dist/src/cli/approval.d.ts +13 -0
- package/dist/src/cli/approval.js +71 -0
- package/dist/src/cli/args.d.ts +15 -0
- package/dist/src/cli/args.js +47 -0
- package/dist/src/cli/commands/audit.d.ts +10 -0
- package/dist/src/cli/commands/audit.js +79 -0
- package/dist/src/cli/commands/companion.d.ts +1 -0
- package/dist/src/cli/commands/companion.js +143 -0
- package/dist/src/cli/commands/config.d.ts +1 -0
- package/dist/src/cli/commands/config.js +135 -0
- package/dist/src/cli/commands/doctor.d.ts +1 -0
- package/dist/src/cli/commands/doctor.js +217 -0
- package/dist/src/cli/commands/init.d.ts +1 -0
- package/dist/src/cli/commands/init.js +134 -0
- package/dist/src/cli/commands/memory.d.ts +2 -0
- package/dist/src/cli/commands/memory.js +98 -0
- package/dist/src/cli/commands/onboarding.d.ts +3 -0
- package/dist/src/cli/commands/onboarding.js +223 -0
- package/dist/src/cli/commands/sessions.d.ts +1 -0
- package/dist/src/cli/commands/sessions.js +22 -0
- package/dist/src/cli/commands/status.d.ts +1 -0
- package/dist/src/cli/commands/status.js +37 -0
- package/dist/src/cli/commands/update.d.ts +9 -0
- package/dist/src/cli/commands/update.js +105 -0
- package/dist/src/cli/repl.d.ts +3 -0
- package/dist/src/cli/repl.js +821 -0
- package/dist/src/cli/ui.d.ts +53 -0
- package/dist/src/cli/ui.js +215 -0
- package/dist/src/companion/petdex_adapter.d.ts +31 -0
- package/dist/src/companion/petdex_adapter.js +171 -0
- package/dist/src/companion/petdex_bridge.d.ts +65 -0
- package/dist/src/companion/petdex_bridge.js +356 -0
- package/dist/src/companion/types.d.ts +57 -0
- package/dist/src/companion/types.js +11 -0
- package/dist/src/config/index.d.ts +24 -0
- package/dist/src/config/index.js +237 -0
- package/dist/src/config/types.d.ts +58 -0
- package/dist/src/config/types.js +7 -0
- package/dist/src/core/diagnostics.d.ts +48 -0
- package/dist/src/core/diagnostics.js +115 -0
- package/dist/src/core/index.d.ts +23 -0
- package/dist/src/core/index.js +23 -0
- package/dist/src/core/mission.d.ts +55 -0
- package/dist/src/core/mission.js +173 -0
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.js +1 -0
- package/dist/src/learning/memory_manager.d.ts +26 -0
- package/dist/src/learning/memory_manager.js +211 -0
- package/dist/src/learning/types.d.ts +54 -0
- package/dist/src/learning/types.js +1 -0
- package/dist/src/mcp/registry.d.ts +17 -0
- package/dist/src/mcp/registry.js +97 -0
- package/dist/src/mcp/types.d.ts +13 -0
- package/dist/src/mcp/types.js +1 -0
- package/dist/src/providers/anthropic.d.ts +10 -0
- package/dist/src/providers/anthropic.js +95 -0
- package/dist/src/providers/base.d.ts +15 -0
- package/dist/src/providers/base.js +108 -0
- package/dist/src/providers/factory.d.ts +28 -0
- package/dist/src/providers/factory.js +142 -0
- package/dist/src/providers/gemini.d.ts +10 -0
- package/dist/src/providers/gemini.js +97 -0
- package/dist/src/providers/openai.d.ts +9 -0
- package/dist/src/providers/openai.js +85 -0
- package/dist/src/providers/openrouter.d.ts +5 -0
- package/dist/src/providers/openrouter.js +14 -0
- package/dist/src/providers/registry.d.ts +19 -0
- package/dist/src/providers/registry.js +209 -0
- package/dist/src/providers/types.d.ts +59 -0
- package/dist/src/providers/types.js +1 -0
- package/dist/src/providers/validator.d.ts +24 -0
- package/dist/src/providers/validator.js +161 -0
- package/dist/src/security/audit.d.ts +56 -0
- package/dist/src/security/audit.js +154 -0
- package/dist/src/security/guardrails.d.ts +9 -0
- package/dist/src/security/guardrails.js +32 -0
- package/dist/src/security/permissions.d.ts +12 -0
- package/dist/src/security/permissions.js +68 -0
- package/dist/src/security/policy.d.ts +220 -0
- package/dist/src/security/policy.js +720 -0
- package/dist/src/session/manager.d.ts +22 -0
- package/dist/src/session/manager.js +172 -0
- package/dist/src/session/types.d.ts +36 -0
- package/dist/src/session/types.js +1 -0
- package/dist/src/tools/checkpoint.d.ts +26 -0
- package/dist/src/tools/checkpoint.js +160 -0
- package/dist/src/tools/diagnostics.d.ts +2 -0
- package/dist/src/tools/diagnostics.js +125 -0
- package/dist/src/tools/diff.d.ts +14 -0
- package/dist/src/tools/diff.js +124 -0
- package/dist/src/tools/filesystem.d.ts +2 -0
- package/dist/src/tools/filesystem.js +224 -0
- package/dist/src/tools/git.d.ts +2 -0
- package/dist/src/tools/git.js +138 -0
- package/dist/src/tools/markdown.d.ts +33 -0
- package/dist/src/tools/markdown.js +190 -0
- package/dist/src/tools/project.d.ts +2 -0
- package/dist/src/tools/project.js +63 -0
- package/dist/src/tools/registry.d.ts +14 -0
- package/dist/src/tools/registry.js +230 -0
- package/dist/src/tools/search.d.ts +2 -0
- package/dist/src/tools/search.js +136 -0
- package/dist/src/tools/shell.d.ts +2 -0
- package/dist/src/tools/shell.js +74 -0
- package/dist/src/tools/symbols.d.ts +30 -0
- package/dist/src/tools/symbols.js +155 -0
- package/dist/src/tools/types.d.ts +28 -0
- package/dist/src/tools/types.js +1 -0
- package/dist/src/tools/web_search.d.ts +14 -0
- package/dist/src/tools/web_search.js +154 -0
- package/install.sh +29 -0
- package/overarch +15 -0
- package/package.json +28 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { exec } from 'node:child_process';
|
|
2
|
+
import { promisify } from 'node:util';
|
|
3
|
+
import * as ui from '../ui.js';
|
|
4
|
+
import { petdexAdapter } from '../../companion/petdex_adapter.js';
|
|
5
|
+
import { petdexBridge } from '../../companion/petdex_bridge.js';
|
|
6
|
+
const execAsync = promisify(exec);
|
|
7
|
+
export async function handleCompanionCommand(subcommand, arg1, _arg2) {
|
|
8
|
+
const sub = (subcommand || 'status').toLowerCase();
|
|
9
|
+
switch (sub) {
|
|
10
|
+
case 'start':
|
|
11
|
+
case 'launch': {
|
|
12
|
+
ui.info('Launching Overarch Desktop Companion...');
|
|
13
|
+
const res = await petdexBridge.launchCompanion(process.cwd());
|
|
14
|
+
if (res.success) {
|
|
15
|
+
ui.success(res.message);
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
ui.warn(res.message);
|
|
19
|
+
console.log(ui.dim('Ensure dist-desktop/OverarchCompanion.exe is built: npm run build:desktop'));
|
|
20
|
+
}
|
|
21
|
+
break;
|
|
22
|
+
}
|
|
23
|
+
case 'stop':
|
|
24
|
+
case 'kill': {
|
|
25
|
+
try {
|
|
26
|
+
await execAsync('powershell -Command "Stop-Process -Name \'OverarchCompanion\' -Force -ErrorAction SilentlyContinue"');
|
|
27
|
+
ui.success('Stopped Overarch Desktop Companion.');
|
|
28
|
+
}
|
|
29
|
+
catch (err) {
|
|
30
|
+
ui.info('No active companion process detected.');
|
|
31
|
+
}
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
case 'status': {
|
|
35
|
+
let isProcRunning = false;
|
|
36
|
+
try {
|
|
37
|
+
const { stdout } = await execAsync('powershell -Command "Get-Process -Name \'OverarchCompanion\' -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Id"');
|
|
38
|
+
isProcRunning = Boolean(stdout && stdout.trim());
|
|
39
|
+
}
|
|
40
|
+
catch { }
|
|
41
|
+
const bridgeStatus = petdexBridge.getStatus();
|
|
42
|
+
const activePet = petdexBridge.getActivePet();
|
|
43
|
+
const petInfo = await petdexAdapter.getPet(activePet);
|
|
44
|
+
ui.statusCard('Overarch Desktop Companion Status', {
|
|
45
|
+
'Desktop Window': isProcRunning ? ui.green('Running (Floating Overlay)') : ui.dim('Not running (start with `overarch companion start`)'),
|
|
46
|
+
'Active Pet': petInfo ? `${petInfo.displayName} (${petInfo.id})` : activePet,
|
|
47
|
+
'Format / Version': petInfo ? `${petInfo.spritesheetFormat.toUpperCase()} (v${petInfo.spriteVersionNumber}, ${petInfo.columns}x${petInfo.rows} grid)` : 'Default',
|
|
48
|
+
'Agent State': bridgeStatus.state.toUpperCase(),
|
|
49
|
+
'Bridge Event Port': bridgeStatus.port,
|
|
50
|
+
'Connected Clients': bridgeStatus.connectedClients,
|
|
51
|
+
'Controls': 'Right-click pet for menu, left-click drag to reposition'
|
|
52
|
+
});
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
case 'pets':
|
|
56
|
+
case 'list': {
|
|
57
|
+
ui.info('Scanning Petdex library...');
|
|
58
|
+
const pets = await petdexAdapter.listPets();
|
|
59
|
+
const activePet = petdexBridge.getActivePet();
|
|
60
|
+
ui.heading(`Available Petdex Pets (${pets.length})`);
|
|
61
|
+
console.log();
|
|
62
|
+
if (pets.length === 0) {
|
|
63
|
+
console.log(ui.dim(' No installed Petdex pets found in ~/.petdex/pets/ or ~/.codex/pets/'));
|
|
64
|
+
console.log(` ${ui.dim('Install one with:')} ${ui.accent('overarch companion install <slug>')}`);
|
|
65
|
+
console.log(` ${ui.dim('Example:')} ${ui.accent('overarch companion install savage-codex-hacker')}`);
|
|
66
|
+
console.log(` ${ui.dim('Gallery:')} https://petdex.dev`);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
pets.forEach((p, idx) => {
|
|
70
|
+
const isAct = p.id === activePet ? ui.accent(' (active)') : '';
|
|
71
|
+
console.log(` ${idx + 1}. ${ui.bold(p.displayName)} ${ui.dim(`[${p.id}]`)}${isAct}`);
|
|
72
|
+
if (p.description) {
|
|
73
|
+
console.log(` ${ui.dim(p.description)}`);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
console.log(`\n${ui.dim('Switch active pet:')} ${ui.accent('overarch companion select <slug>')}`);
|
|
77
|
+
console.log(`${ui.dim('Install more pets:')} ${ui.accent('overarch companion install <slug>')}`);
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
case 'select':
|
|
81
|
+
case 'set': {
|
|
82
|
+
if (!arg1) {
|
|
83
|
+
ui.warn('Usage: overarch companion select <slug>');
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
const targetSlug = arg1.trim();
|
|
87
|
+
const pet = await petdexAdapter.getPet(targetSlug);
|
|
88
|
+
if (!pet) {
|
|
89
|
+
ui.warn(`Pet '${targetSlug}' is not installed locally.`);
|
|
90
|
+
console.log(ui.dim(`Run \`overarch companion install ${targetSlug}\` to install it from Petdex.`));
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
petdexBridge.setActivePet(pet.id);
|
|
94
|
+
ui.success(`Selected Petdex companion: ${ui.bold(pet.displayName)} (${pet.id})`);
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
case 'install':
|
|
98
|
+
case 'add': {
|
|
99
|
+
if (!arg1) {
|
|
100
|
+
ui.warn('Usage: overarch companion install <slug>');
|
|
101
|
+
console.log(ui.dim('Example: overarch companion install savage-codex-hacker'));
|
|
102
|
+
console.log(ui.dim('Browse 200+ pets at: https://petdex.dev'));
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
const slug = arg1.trim();
|
|
106
|
+
ui.info(`Installing '${slug}' from Petdex library...`);
|
|
107
|
+
const spin = ui.spinner(`Fetching ${slug} from Petdex...`);
|
|
108
|
+
const result = await petdexAdapter.installPet(slug);
|
|
109
|
+
spin.stop();
|
|
110
|
+
if (result.success) {
|
|
111
|
+
ui.success(result.message);
|
|
112
|
+
if (result.pet) {
|
|
113
|
+
petdexBridge.setActivePet(result.pet.id);
|
|
114
|
+
console.log(ui.dim(`Automatically set ${result.pet.displayName} as active companion.`));
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
ui.fail(result.message);
|
|
119
|
+
}
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
case 'help':
|
|
123
|
+
default: {
|
|
124
|
+
ui.heading('Overarch Floating Desktop Companion');
|
|
125
|
+
console.log(`
|
|
126
|
+
${ui.bold('Commands')}
|
|
127
|
+
overarch companion start Launch floating desktop companion
|
|
128
|
+
overarch companion stop Close companion window
|
|
129
|
+
overarch companion status Display companion connection & active pet
|
|
130
|
+
overarch companion pets List all installed Petdex companions
|
|
131
|
+
overarch companion select <slug> Switch active desktop companion
|
|
132
|
+
overarch companion install <slug> Install any pet from https://petdex.dev
|
|
133
|
+
|
|
134
|
+
${ui.bold('Desktop Interaction')}
|
|
135
|
+
• Left-click & drag: Move pet anywhere on desktop (position is saved)
|
|
136
|
+
• Double-click: Wave / greeting reaction
|
|
137
|
+
• Right-click: Context menu (change pet, terminal, status, reset)
|
|
138
|
+
• Non-activating: Never steals keyboard focus from editor or terminal
|
|
139
|
+
`);
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function handleConfigCommand(subcommand?: string, key?: string, value?: string): Promise<void>;
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import * as ui from '../ui.js';
|
|
2
|
+
import { loadConfig, saveGlobalConfig } from '../../config/index.js';
|
|
3
|
+
import { resolveModel } from '../../providers/factory.js';
|
|
4
|
+
export async function handleConfigCommand(subcommand, key, value) {
|
|
5
|
+
const config = await loadConfig();
|
|
6
|
+
// 1. Direct Target Shortcuts
|
|
7
|
+
if (subcommand === 'provider') {
|
|
8
|
+
if (!key) {
|
|
9
|
+
console.log(`\nActive Provider: ${ui.bold(config.activeProvider || 'anthropic')}`);
|
|
10
|
+
console.log(`Provider Mode: ${config.mode === 'offline' ? ui.yellow('Offline') : ui.green('Online')}`);
|
|
11
|
+
console.log(ui.dim('To change provider: overarch config set provider <anthropic|openai|gemini|openrouter>'));
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
await saveGlobalConfig({ activeProvider: key.toLowerCase() });
|
|
15
|
+
ui.success(`Active provider set to: ${key.toLowerCase()}`);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
if (subcommand === 'model') {
|
|
19
|
+
if (!key) {
|
|
20
|
+
const resolved = resolveModel(config.defaultModel);
|
|
21
|
+
console.log(`\nActive Model: ${ui.bold(config.defaultModel)}`);
|
|
22
|
+
if (resolved) {
|
|
23
|
+
console.log(`Display Name: ${resolved.displayName} (${resolved.provider})`);
|
|
24
|
+
}
|
|
25
|
+
console.log(ui.dim('To change model: overarch config set model <id>'));
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const resolved = resolveModel(key);
|
|
29
|
+
if (!resolved) {
|
|
30
|
+
ui.warn(`Model '${key}' will be treated as custom '${key}'`);
|
|
31
|
+
}
|
|
32
|
+
await saveGlobalConfig({ defaultModel: key });
|
|
33
|
+
ui.success(`Default model set to: ${key}`);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
if (subcommand === 'accent') {
|
|
37
|
+
if (!key) {
|
|
38
|
+
console.log(`\nCurrent Accent: ${ui.accent(config.ui?.accentColor || 'cyan')}`);
|
|
39
|
+
console.log(ui.dim('Available: cyan, magenta, blue, green, yellow'));
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
await saveGlobalConfig({ ui: { ...config.ui, accentColor: key } });
|
|
43
|
+
ui.setAccent(key);
|
|
44
|
+
ui.success(`Accent color updated to: ${ui.accent(key)}`);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (subcommand === 'avatar') {
|
|
48
|
+
if (!key) {
|
|
49
|
+
console.log(`\nCurrent Avatar: ${ui.accent(config.ui?.avatar || '◆')}`);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
await saveGlobalConfig({ ui: { ...config.ui, avatar: key } });
|
|
53
|
+
ui.setAvatar(key);
|
|
54
|
+
ui.success(`Avatar token updated to: ${ui.accent(key)}`);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (subcommand === 'permissions') {
|
|
58
|
+
console.log(`\nAuto-Approve Tiers: ${config.permissions?.autoApprove?.join(', ') || 'none'}`);
|
|
59
|
+
console.log(`Require-Approval: ${config.permissions?.requireApproval?.join(', ') || 'none'}`);
|
|
60
|
+
console.log(`Denied Tools: ${config.permissions?.deny?.join(', ') || 'none'}`);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
// 2. Default List / Status View
|
|
64
|
+
if (!subcommand || subcommand === 'show' || subcommand === 'list') {
|
|
65
|
+
ui.statusCard('Overarch Configuration', {
|
|
66
|
+
'Config File': config.configPath || 'Defaults',
|
|
67
|
+
'Scope': config.isProjectConfig ? 'Project (.overarch/config.json)' : 'Global (~/.overarch/config.json)',
|
|
68
|
+
'Provider': config.activeProvider || 'anthropic',
|
|
69
|
+
'Model': config.defaultModel,
|
|
70
|
+
'Mode': config.mode === 'offline' ? ui.yellow('Offline') : 'Online',
|
|
71
|
+
'Accent Color': ui.accent(config.ui?.accentColor || 'cyan'),
|
|
72
|
+
'Avatar': ui.accent(config.ui?.avatar || '◆'),
|
|
73
|
+
'Ponytail Mode': config.ponytail || 'full',
|
|
74
|
+
'CCSS Mode': config.ccss || 'auto',
|
|
75
|
+
'Agent Mode': config.agentMode || 'approval',
|
|
76
|
+
'Auto-Approve Tiers': config.permissions?.autoApprove?.join(', ') || 'none'
|
|
77
|
+
});
|
|
78
|
+
console.log(ui.dim('\nTargets: provider, model, accent, avatar, permissions'));
|
|
79
|
+
console.log(ui.dim('Usage: overarch config <target> [value] | overarch config get <key> | overarch config set <key> <val>'));
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
// 3. Get Key
|
|
83
|
+
if (subcommand === 'get') {
|
|
84
|
+
if (!key) {
|
|
85
|
+
ui.error('Key name required. Example: overarch config get defaultModel');
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const val = config[key] ?? config.ui?.[key];
|
|
89
|
+
if (val !== undefined) {
|
|
90
|
+
console.log(typeof val === 'object' ? JSON.stringify(val, null, 2) : String(val));
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
ui.warn(`Key '${key}' not found in configuration.`);
|
|
94
|
+
}
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
// 4. Set Key
|
|
98
|
+
if (subcommand === 'set') {
|
|
99
|
+
if (!key || value === undefined) {
|
|
100
|
+
ui.error('Key and value required. Example: overarch config set model gpt-4o');
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const updates = {};
|
|
104
|
+
if (key === 'model' || key === 'defaultModel') {
|
|
105
|
+
updates.defaultModel = value;
|
|
106
|
+
}
|
|
107
|
+
else if (key === 'provider' || key === 'activeProvider') {
|
|
108
|
+
updates.activeProvider = value.toLowerCase();
|
|
109
|
+
}
|
|
110
|
+
else if (key === 'accent' || key === 'accentColor') {
|
|
111
|
+
updates.ui = { ...config.ui, accentColor: value };
|
|
112
|
+
ui.setAccent(value);
|
|
113
|
+
}
|
|
114
|
+
else if (key === 'avatar') {
|
|
115
|
+
updates.ui = { ...config.ui, avatar: value };
|
|
116
|
+
ui.setAvatar(value);
|
|
117
|
+
}
|
|
118
|
+
else if (key === 'ponytail') {
|
|
119
|
+
updates.ponytail = value.toLowerCase();
|
|
120
|
+
}
|
|
121
|
+
else if (key === 'ccss') {
|
|
122
|
+
updates.ccss = value.toLowerCase();
|
|
123
|
+
}
|
|
124
|
+
else if (key === 'mode') {
|
|
125
|
+
updates.mode = value.toLowerCase() === 'offline' ? 'offline' : 'online';
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
updates[key] = value;
|
|
129
|
+
}
|
|
130
|
+
await saveGlobalConfig(updates);
|
|
131
|
+
ui.success(`Updated ${key} = ${value}`);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
ui.error(`Unknown config action: ${subcommand}.`);
|
|
135
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function doctor(): Promise<void>;
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import { execSync } from 'node:child_process';
|
|
2
|
+
import * as ui from '../ui.js';
|
|
3
|
+
import { loadConfig, getApiKey } from '../../config/index.js';
|
|
4
|
+
import { resolveModel } from '../../providers/factory.js';
|
|
5
|
+
import { ToolRegistry } from '../../tools/registry.js';
|
|
6
|
+
import { petdexBridge } from '../../companion/petdex_bridge.js';
|
|
7
|
+
import { policyEngine } from '../../security/policy.js';
|
|
8
|
+
import fs from 'node:fs/promises';
|
|
9
|
+
import * as syncFs from 'node:fs';
|
|
10
|
+
import path from 'node:path';
|
|
11
|
+
import os from 'node:os';
|
|
12
|
+
export async function doctor() {
|
|
13
|
+
ui.heading('Overarch Doctor Diagnostics');
|
|
14
|
+
console.log(ui.dim('Inspecting runtime, security policies, tool integrity, project context, and subsystems...\n'));
|
|
15
|
+
const issues = [];
|
|
16
|
+
// 1. Runtime & Environment (Node.js >= 20.0.0)
|
|
17
|
+
const nodeVersion = process.version;
|
|
18
|
+
const majorVersion = parseInt(nodeVersion.slice(1).split('.')[0], 10);
|
|
19
|
+
if (majorVersion >= 20) {
|
|
20
|
+
ui.done(`Runtime: Node.js ${nodeVersion} (${process.platform} ${process.arch}, ESM & native APIs active)`);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
ui.fail(`Runtime: Node.js ${nodeVersion} (>= 20 required)`);
|
|
24
|
+
issues.push('Upgrade Node.js to v20 or higher.');
|
|
25
|
+
}
|
|
26
|
+
// 2. PATH Resolution & Global Command Integrity
|
|
27
|
+
try {
|
|
28
|
+
let resolvedCommand = '';
|
|
29
|
+
if (process.platform === 'win32') {
|
|
30
|
+
try {
|
|
31
|
+
const whereOutput = execSync('where.exe overarch 2>nul', { encoding: 'utf8' }).trim();
|
|
32
|
+
const lines = whereOutput.split('\r\n').map(l => l.trim()).filter(Boolean);
|
|
33
|
+
resolvedCommand = lines[0] || '';
|
|
34
|
+
if (lines.length > 1) {
|
|
35
|
+
ui.done(`PATH: 'overarch' found in ${lines.length} locations (Primary: ${resolvedCommand})`);
|
|
36
|
+
}
|
|
37
|
+
else if (resolvedCommand) {
|
|
38
|
+
ui.done(`PATH: 'overarch' command resolved cleanly at: ${resolvedCommand}`);
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
ui.warn(`PATH: 'overarch' not found via 'where.exe'`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
ui.done(`PATH: Standard environment active`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
const whichOutput = execSync('which overarch 2>/dev/null', { encoding: 'utf8' }).trim();
|
|
50
|
+
ui.done(`PATH: 'overarch' resolved at: ${whichOutput}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
ui.warn('PATH: Could not query active binary resolution');
|
|
55
|
+
}
|
|
56
|
+
// 3. Wrapper Script UTF-8 BOM Verification (preventing '@echo' syntax error in cmd.exe)
|
|
57
|
+
if (process.platform === 'win32') {
|
|
58
|
+
const candidateWrappers = [
|
|
59
|
+
path.join(os.homedir(), 'AppData', 'Local', 'Programs', 'Overarch', 'overarch.cmd'),
|
|
60
|
+
path.join(os.homedir(), 'AppData', 'Local', 'Microsoft', 'WindowsApps', 'overarch.cmd'),
|
|
61
|
+
path.join(os.homedir(), 'AppData', 'Roaming', 'npm', 'overarch.cmd'),
|
|
62
|
+
];
|
|
63
|
+
let checkedWrappers = 0;
|
|
64
|
+
let hasBom = false;
|
|
65
|
+
for (const wrapper of candidateWrappers) {
|
|
66
|
+
if (syncFs.existsSync(wrapper)) {
|
|
67
|
+
checkedWrappers++;
|
|
68
|
+
try {
|
|
69
|
+
const fd = syncFs.openSync(wrapper, 'r');
|
|
70
|
+
const buffer = Buffer.alloc(3);
|
|
71
|
+
syncFs.readSync(fd, buffer, 0, 3, 0);
|
|
72
|
+
syncFs.closeSync(fd);
|
|
73
|
+
if (buffer[0] === 0xef && buffer[1] === 0xbb && buffer[2] === 0xbf) {
|
|
74
|
+
hasBom = true;
|
|
75
|
+
ui.fail(`Wrapper Scripts: UTF-8 BOM detected in ${wrapper} (causes '@echo' command error)`);
|
|
76
|
+
issues.push(`Re-save '${wrapper}' without BOM or re-run Overarch installer.`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
catch { }
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (!hasBom && checkedWrappers > 0) {
|
|
83
|
+
ui.done(`Wrapper Scripts: Verified BOM-free across ${checkedWrappers} candidate shims (compatible with cmd.exe & PowerShell)`);
|
|
84
|
+
}
|
|
85
|
+
else if (checkedWrappers === 0) {
|
|
86
|
+
ui.done(`Wrapper Scripts: No external Windows shims to check (running locally)`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// 4. Git Version Control
|
|
90
|
+
try {
|
|
91
|
+
const gitVersion = execSync('git --version', { encoding: 'utf8' }).trim();
|
|
92
|
+
ui.done(`Git: ${gitVersion}`);
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
ui.fail('Git: Not found in system PATH');
|
|
96
|
+
issues.push('Install Git or add it to your system PATH to enable version control and rollback features.');
|
|
97
|
+
}
|
|
98
|
+
// 5. Native Windows Desktop Compiler (if on Windows)
|
|
99
|
+
if (process.platform === 'win32') {
|
|
100
|
+
const cscCandidates = [
|
|
101
|
+
'C:\\Windows\\Microsoft.NET\\Framework64\\v4.0.30319\\csc.exe',
|
|
102
|
+
'C:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\csc.exe',
|
|
103
|
+
];
|
|
104
|
+
const foundCsc = cscCandidates.find((p) => {
|
|
105
|
+
try {
|
|
106
|
+
return execSync(`where csc.exe 2>nul || (dir "${p}" 2>nul)`).length > 0;
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
if (foundCsc) {
|
|
113
|
+
ui.done(`Windows Compiler: Native .NET C# compiler (csc.exe) detected`);
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
ui.done(`Windows Compiler: Standard Windows system environment active`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// 6. CCHCFAI Security & Policy Engine
|
|
120
|
+
const safeOnly = policyEngine.isSafeOnly();
|
|
121
|
+
if (safeOnly) {
|
|
122
|
+
ui.done(`CCHCFAI Policy: Active in SAFE-ONLY mode (all destructive shell & mutations blocked)`);
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
ui.done(`CCHCFAI Policy: Active (Tier 0-3 tiered authority with human control gates)`);
|
|
126
|
+
}
|
|
127
|
+
// 7. File System Read / Write Permissions (Workspace & .overarch)
|
|
128
|
+
const cwd = process.cwd();
|
|
129
|
+
try {
|
|
130
|
+
const testFile = path.join(cwd, `.overarch_rw_test_${Date.now()}.tmp`);
|
|
131
|
+
await fs.writeFile(testFile, 'test', 'utf8');
|
|
132
|
+
await fs.unlink(testFile);
|
|
133
|
+
const overarchGlobal = path.join(os.homedir(), '.overarch');
|
|
134
|
+
if (!syncFs.existsSync(overarchGlobal)) {
|
|
135
|
+
await fs.mkdir(overarchGlobal, { recursive: true });
|
|
136
|
+
}
|
|
137
|
+
const testGlobal = path.join(overarchGlobal, `.rw_test_${Date.now()}.tmp`);
|
|
138
|
+
await fs.writeFile(testGlobal, 'test', 'utf8');
|
|
139
|
+
await fs.unlink(testGlobal);
|
|
140
|
+
ui.done(`Filesystem: Read & Write verified in workspace (${cwd}) and global (~/.overarch)`);
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
ui.fail(`Filesystem: Write permission check failed: ${err.message}`);
|
|
144
|
+
issues.push(`Ensure directory permissions allow reading and writing.`);
|
|
145
|
+
}
|
|
146
|
+
// 8. Configuration & Auth
|
|
147
|
+
const config = await loadConfig();
|
|
148
|
+
ui.done(`Configuration: ${config.isProjectConfig ? 'Project (.overarch/config.json)' : 'Global (~/.overarch/config.json)'}`);
|
|
149
|
+
const activeModel = config.defaultModel;
|
|
150
|
+
const resolved = resolveModel(activeModel);
|
|
151
|
+
if (config.mode === 'offline' || resolved?.provider === 'none') {
|
|
152
|
+
ui.done(`Provider: Offline mode active (AI calls disabled)`);
|
|
153
|
+
}
|
|
154
|
+
else if (resolved) {
|
|
155
|
+
const key = getApiKey(resolved.provider);
|
|
156
|
+
if (key) {
|
|
157
|
+
ui.done(`Authentication: ${resolved.provider.toUpperCase()} API key detected`);
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
ui.fail(`Authentication: Missing API key for provider '${resolved.provider}'`);
|
|
161
|
+
issues.push(`Set ${resolved.provider.toUpperCase()}_API_KEY in your environment or add to .env via \`/setup\`.`);
|
|
162
|
+
}
|
|
163
|
+
ui.done(`Model: ${resolved.displayName} (${resolved.provider}/${resolved.model})`);
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
ui.fail(`Model: Unknown model '${activeModel}'`);
|
|
167
|
+
issues.push('Run `/setup` or `/config model <name>` to select a valid model.');
|
|
168
|
+
}
|
|
169
|
+
// 9. .overarch Project Subsystem & Audit Log
|
|
170
|
+
const overarchDir = path.join(cwd, '.overarch');
|
|
171
|
+
try {
|
|
172
|
+
await fs.access(overarchDir);
|
|
173
|
+
const subFiles = await fs.readdir(overarchDir);
|
|
174
|
+
ui.done(`.overarch Subsystem: Initialized (${subFiles.length} items: ${subFiles.join(', ')})`);
|
|
175
|
+
}
|
|
176
|
+
catch {
|
|
177
|
+
ui.warn(`.overarch Subsystem: Not initialized in current directory`);
|
|
178
|
+
issues.push('Run `overarch init` or `/init` in the REPL to initialize project context.');
|
|
179
|
+
}
|
|
180
|
+
// 10. Tool Registry (including web_search)
|
|
181
|
+
const registry = ToolRegistry.createDefault();
|
|
182
|
+
const tools = registry.list();
|
|
183
|
+
const hasWebSearch = tools.some((t) => t.name === 'web_search');
|
|
184
|
+
if (hasWebSearch) {
|
|
185
|
+
ui.done(`Tools: ${tools.length} registered (including native web_search & precision file patchers)`);
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
ui.warn(`Tools: ${tools.length} registered`);
|
|
189
|
+
}
|
|
190
|
+
// 11. Companion Health & Petdex Bridge
|
|
191
|
+
const bridgeStatus = petdexBridge.getStatus();
|
|
192
|
+
let companionExeFound = false;
|
|
193
|
+
if (process.platform === 'win32') {
|
|
194
|
+
const compCandidates = [
|
|
195
|
+
path.join(cwd, 'dist-desktop', 'OverarchCompanion.exe'),
|
|
196
|
+
path.join(os.homedir(), 'AppData', 'Local', 'Programs', 'Overarch', 'OverarchCompanion.exe'),
|
|
197
|
+
];
|
|
198
|
+
companionExeFound = compCandidates.some(c => syncFs.existsSync(c));
|
|
199
|
+
}
|
|
200
|
+
if (bridgeStatus.running) {
|
|
201
|
+
ui.done(`Companion Health: Active and listening on port ${bridgeStatus.port} (Companion binary: ${companionExeFound ? 'Available' : 'Standby'})`);
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
ui.done(`Companion Health: Standby (Bridge ready, companion executable: ${companionExeFound ? 'Available' : 'Ready'})`);
|
|
205
|
+
}
|
|
206
|
+
console.log();
|
|
207
|
+
if (issues.length === 0) {
|
|
208
|
+
ui.success('All systems healthy. Overarch CLI is ready for autonomous software engineering.');
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
ui.warn(`Identified ${issues.length} item(s) requiring attention:`);
|
|
212
|
+
issues.forEach((iss, idx) => {
|
|
213
|
+
console.log(` ${idx + 1}. ${iss}`);
|
|
214
|
+
});
|
|
215
|
+
console.log(`\n${ui.dim('Run /setup to re-run the configuration wizard.')}`);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function init(): Promise<void>;
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import * as ui from '../ui.js';
|
|
4
|
+
import { DEFAULT_CONFIG } from '../../config/index.js';
|
|
5
|
+
export async function init() {
|
|
6
|
+
ui.heading('Initialize Overarch Project Context');
|
|
7
|
+
const cwd = process.cwd();
|
|
8
|
+
const projectConfigDir = path.join(cwd, '.overarch');
|
|
9
|
+
// 1. Detect project characteristics
|
|
10
|
+
const detectedStacks = [];
|
|
11
|
+
let testCommand = '';
|
|
12
|
+
let buildCommand = '';
|
|
13
|
+
try {
|
|
14
|
+
const pkg = JSON.parse(await fs.readFile(path.join(cwd, 'package.json'), 'utf8'));
|
|
15
|
+
detectedStacks.push(`Node.js (${pkg.name || 'unnamed'})`);
|
|
16
|
+
if (pkg.scripts?.test)
|
|
17
|
+
testCommand = 'npm test';
|
|
18
|
+
if (pkg.scripts?.build)
|
|
19
|
+
buildCommand = 'npm run build';
|
|
20
|
+
if (pkg.dependencies?.typescript || pkg.devDependencies?.typescript) {
|
|
21
|
+
detectedStacks.push('TypeScript');
|
|
22
|
+
}
|
|
23
|
+
if (pkg.dependencies?.react || pkg.devDependencies?.react) {
|
|
24
|
+
detectedStacks.push('React');
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
catch { }
|
|
28
|
+
try {
|
|
29
|
+
await fs.readFile(path.join(cwd, 'Cargo.toml'), 'utf8');
|
|
30
|
+
detectedStacks.push('Rust');
|
|
31
|
+
if (!testCommand)
|
|
32
|
+
testCommand = 'cargo test';
|
|
33
|
+
if (!buildCommand)
|
|
34
|
+
buildCommand = 'cargo build';
|
|
35
|
+
}
|
|
36
|
+
catch { }
|
|
37
|
+
try {
|
|
38
|
+
await fs.readFile(path.join(cwd, 'pyproject.toml'), 'utf8');
|
|
39
|
+
detectedStacks.push('Python');
|
|
40
|
+
if (!testCommand)
|
|
41
|
+
testCommand = 'pytest';
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
try {
|
|
45
|
+
await fs.readFile(path.join(cwd, 'requirements.txt'), 'utf8');
|
|
46
|
+
detectedStacks.push('Python');
|
|
47
|
+
}
|
|
48
|
+
catch { }
|
|
49
|
+
}
|
|
50
|
+
try {
|
|
51
|
+
await fs.readFile(path.join(cwd, 'go.mod'), 'utf8');
|
|
52
|
+
detectedStacks.push('Go');
|
|
53
|
+
if (!testCommand)
|
|
54
|
+
testCommand = 'go test ./...';
|
|
55
|
+
if (!buildCommand)
|
|
56
|
+
buildCommand = 'go build ./...';
|
|
57
|
+
}
|
|
58
|
+
catch { }
|
|
59
|
+
// 2. Discover root files & directories
|
|
60
|
+
const ignoreList = new Set(['node_modules', '.git', 'dist', 'build', '.next', '.turbo', '.cache']);
|
|
61
|
+
const files = await fs.readdir(cwd, { withFileTypes: true });
|
|
62
|
+
const keyDirs = [];
|
|
63
|
+
for (const f of files) {
|
|
64
|
+
if (ignoreList.has(f.name))
|
|
65
|
+
continue;
|
|
66
|
+
if (f.isDirectory())
|
|
67
|
+
keyDirs.push(f.name);
|
|
68
|
+
}
|
|
69
|
+
// 3. Create .overarch structure
|
|
70
|
+
await fs.mkdir(projectConfigDir, { recursive: true });
|
|
71
|
+
await fs.mkdir(path.join(projectConfigDir, 'sessions'), { recursive: true });
|
|
72
|
+
await fs.mkdir(path.join(projectConfigDir, 'cache'), { recursive: true });
|
|
73
|
+
// config.json
|
|
74
|
+
const configPath = path.join(projectConfigDir, 'config.json');
|
|
75
|
+
try {
|
|
76
|
+
await fs.access(configPath);
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
const projectConfig = {
|
|
80
|
+
project: {
|
|
81
|
+
...DEFAULT_CONFIG.project,
|
|
82
|
+
include: keyDirs,
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
await fs.writeFile(configPath, JSON.stringify(projectConfig, null, 2), 'utf8');
|
|
86
|
+
}
|
|
87
|
+
// instructions.md
|
|
88
|
+
const instructionsPath = path.join(projectConfigDir, 'instructions.md');
|
|
89
|
+
try {
|
|
90
|
+
await fs.access(instructionsPath);
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
let template = `# ${path.basename(cwd)} — Architecture Guidelines\n\n`;
|
|
94
|
+
template += `## Tech Stack\n${detectedStacks.length > 0 ? detectedStacks.map(s => `- ${s}`).join('\n') : '- General'}\n\n`;
|
|
95
|
+
if (buildCommand)
|
|
96
|
+
template += `## Build Command\n\`${buildCommand}\`\n\n`;
|
|
97
|
+
if (testCommand)
|
|
98
|
+
template += `## Test Command\n\`${testCommand}\`\n\n`;
|
|
99
|
+
template += `## Development Principles\n`;
|
|
100
|
+
template += `- Prefer small, verifiable changes\n`;
|
|
101
|
+
template += `- Always run tests before declaring tasks complete\n`;
|
|
102
|
+
template += `- Follow existing styling and patterns\n`;
|
|
103
|
+
await fs.writeFile(instructionsPath, template, 'utf8');
|
|
104
|
+
}
|
|
105
|
+
// memory.md
|
|
106
|
+
const memoryPath = path.join(projectConfigDir, 'memory.md');
|
|
107
|
+
try {
|
|
108
|
+
await fs.access(memoryPath);
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
const memTemplate = `# Project Memory\n\n- [${new Date().toISOString().slice(0, 10)}] Initialized Overarch project context\n`;
|
|
112
|
+
await fs.writeFile(memoryPath, memTemplate, 'utf8');
|
|
113
|
+
}
|
|
114
|
+
// .gitignore
|
|
115
|
+
const gitignorePath = path.join(projectConfigDir, '.gitignore');
|
|
116
|
+
await fs.writeFile(gitignorePath, 'sessions/\ncache/\n*.log\n*.env\nstate.json\n', 'utf8');
|
|
117
|
+
// context.json
|
|
118
|
+
const contextPath = path.join(projectConfigDir, 'context.json');
|
|
119
|
+
const contextIndex = {
|
|
120
|
+
initializedAt: new Date().toISOString(),
|
|
121
|
+
stacks: detectedStacks,
|
|
122
|
+
keyDirectories: keyDirs,
|
|
123
|
+
buildCommand,
|
|
124
|
+
testCommand
|
|
125
|
+
};
|
|
126
|
+
await fs.writeFile(contextPath, JSON.stringify(contextIndex, null, 2), 'utf8');
|
|
127
|
+
console.log();
|
|
128
|
+
ui.done(`Detected Stack: ${detectedStacks.length > 0 ? detectedStacks.join(', ') : 'Generic'}`);
|
|
129
|
+
ui.done(`Discovered Directories: ${keyDirs.join(', ') || 'root'}`);
|
|
130
|
+
ui.done(`Initialized .overarch subsystem in ${projectConfigDir}`);
|
|
131
|
+
ui.done(`Created project instructions template at .overarch/instructions.md`);
|
|
132
|
+
ui.done(`Created project memory ledger at .overarch/memory.md`);
|
|
133
|
+
console.log(`\n${ui.accent(ui.getAvatar())} Project context established. Overarch is now tailored to this repository.`);
|
|
134
|
+
}
|