overarch-linux-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,53 @@
|
|
|
1
|
+
import { styleText } from 'node:util';
|
|
2
|
+
type Color = Parameters<typeof styleText>[0];
|
|
3
|
+
export declare function setAccent(color: Color): void;
|
|
4
|
+
export declare function getAccent(): Color;
|
|
5
|
+
export declare function setAvatar(avatar: string): void;
|
|
6
|
+
export declare function getAvatar(): string;
|
|
7
|
+
export declare function accent(msg: string): string;
|
|
8
|
+
export declare function green(msg: string): string;
|
|
9
|
+
export declare function red(msg: string): string;
|
|
10
|
+
export declare function yellow(msg: string): string;
|
|
11
|
+
export declare function cyan(msg: string): string;
|
|
12
|
+
export declare function dim(msg: string): string;
|
|
13
|
+
export declare function bold(msg: string): string;
|
|
14
|
+
export declare function banner(): void;
|
|
15
|
+
export declare const CLAUDE_THINKING_ADJECTIVES: string[];
|
|
16
|
+
export declare function thinking(action?: string): void;
|
|
17
|
+
export declare function thinkingSpinner(initialAction?: string): {
|
|
18
|
+
setAction: (action: string) => void;
|
|
19
|
+
stop: (finalMsg?: string) => void;
|
|
20
|
+
};
|
|
21
|
+
export declare function info(msg: string): void;
|
|
22
|
+
export declare function warn(msg: string): void;
|
|
23
|
+
export declare function error(msg: string): void;
|
|
24
|
+
export declare function success(msg: string): void;
|
|
25
|
+
export declare function step(msg: string): void;
|
|
26
|
+
export declare function done(msg: string): void;
|
|
27
|
+
export declare function fail(msg: string): void;
|
|
28
|
+
export declare function heading(msg: string): void;
|
|
29
|
+
export declare function divider(): void;
|
|
30
|
+
export declare function separator(): void;
|
|
31
|
+
export declare function spinner(msg: string): {
|
|
32
|
+
stop: (finalMsg?: string) => void;
|
|
33
|
+
};
|
|
34
|
+
export declare function welcome(project: string, model: string): void;
|
|
35
|
+
export declare function prompt(): string;
|
|
36
|
+
export declare function userMessage(msg: string): void;
|
|
37
|
+
export declare function aiMessage(msg: string): void;
|
|
38
|
+
export declare function toolStart(name: string, summary: string): void;
|
|
39
|
+
export declare function toolEnd(name: string, isSuccess: boolean, duration?: number): void;
|
|
40
|
+
export declare function diff(filename: string, additions: number, deletions: number): void;
|
|
41
|
+
/**
|
|
42
|
+
* Format a unified diff with terminal colors (green additions, red deletions, cyan headers)
|
|
43
|
+
*/
|
|
44
|
+
export declare function formatDiff(diffText: string): string;
|
|
45
|
+
export declare function planStep(index: number, description: string, status: 'pending' | 'in-progress' | 'done' | 'failed'): void;
|
|
46
|
+
export declare function sessionInfo(id: string, model: string, cwd: string): void;
|
|
47
|
+
export declare function progress(current: number, total: number, label: string): void;
|
|
48
|
+
export declare function compact(msg: string): void;
|
|
49
|
+
/**
|
|
50
|
+
* Displays a structured status card with aligned labels and values
|
|
51
|
+
*/
|
|
52
|
+
export declare function statusCard(title: string, entries: Record<string, string | number | boolean | undefined>): void;
|
|
53
|
+
export {};
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { styleText } from 'node:util';
|
|
2
|
+
let currentAccent = 'cyan';
|
|
3
|
+
let currentAvatar = '◆';
|
|
4
|
+
export function setAccent(color) {
|
|
5
|
+
currentAccent = color;
|
|
6
|
+
}
|
|
7
|
+
export function getAccent() {
|
|
8
|
+
return currentAccent;
|
|
9
|
+
}
|
|
10
|
+
export function setAvatar(avatar) {
|
|
11
|
+
currentAvatar = avatar;
|
|
12
|
+
}
|
|
13
|
+
export function getAvatar() {
|
|
14
|
+
return currentAvatar;
|
|
15
|
+
}
|
|
16
|
+
export function accent(msg) {
|
|
17
|
+
return styleText(currentAccent, msg);
|
|
18
|
+
}
|
|
19
|
+
export function green(msg) {
|
|
20
|
+
return styleText('green', msg);
|
|
21
|
+
}
|
|
22
|
+
export function red(msg) {
|
|
23
|
+
return styleText('red', msg);
|
|
24
|
+
}
|
|
25
|
+
export function yellow(msg) {
|
|
26
|
+
return styleText('yellow', msg);
|
|
27
|
+
}
|
|
28
|
+
export function cyan(msg) {
|
|
29
|
+
return styleText('cyan', msg);
|
|
30
|
+
}
|
|
31
|
+
export function dim(msg) {
|
|
32
|
+
return styleText('dim', msg);
|
|
33
|
+
}
|
|
34
|
+
export function bold(msg) {
|
|
35
|
+
return styleText('bold', msg);
|
|
36
|
+
}
|
|
37
|
+
export function banner() {
|
|
38
|
+
console.log(`Overarch ${styleText('dim', 'v0.8.0')}`);
|
|
39
|
+
}
|
|
40
|
+
export const CLAUDE_THINKING_ADJECTIVES = [
|
|
41
|
+
'Analyzing repository architecture',
|
|
42
|
+
'Synthesizing change impact',
|
|
43
|
+
'Investigating code paths',
|
|
44
|
+
'Deliberating implementation plan',
|
|
45
|
+
'Evaluating symbol dependencies',
|
|
46
|
+
'Formulating surgical changes',
|
|
47
|
+
'Inspecting project context',
|
|
48
|
+
'Verifying regression safety',
|
|
49
|
+
'Distilling project memory',
|
|
50
|
+
'Validating epistemic boundaries',
|
|
51
|
+
'Diagnosing error patterns',
|
|
52
|
+
'Deconstructing multi-file dependencies'
|
|
53
|
+
];
|
|
54
|
+
export function thinking(action) {
|
|
55
|
+
const chosen = action || CLAUDE_THINKING_ADJECTIVES[Math.floor(Math.random() * CLAUDE_THINKING_ADJECTIVES.length)];
|
|
56
|
+
console.log(`${styleText('dim', '⟳')} ${styleText(['dim', 'italic'], chosen + '...')}`);
|
|
57
|
+
}
|
|
58
|
+
export function thinkingSpinner(initialAction) {
|
|
59
|
+
const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
60
|
+
let i = 0;
|
|
61
|
+
let ticks = 0;
|
|
62
|
+
let adjIdx = 0;
|
|
63
|
+
let currentAction = initialAction || CLAUDE_THINKING_ADJECTIVES[0];
|
|
64
|
+
const timer = setInterval(() => {
|
|
65
|
+
ticks++;
|
|
66
|
+
if (!initialAction && ticks % 28 === 0) {
|
|
67
|
+
adjIdx = (adjIdx + 1) % CLAUDE_THINKING_ADJECTIVES.length;
|
|
68
|
+
currentAction = CLAUDE_THINKING_ADJECTIVES[adjIdx];
|
|
69
|
+
}
|
|
70
|
+
process.stderr.write(`\r${accent(frames[i])} ${styleText('dim', currentAction + '...')}`);
|
|
71
|
+
i = (i + 1) % frames.length;
|
|
72
|
+
}, 80);
|
|
73
|
+
return {
|
|
74
|
+
setAction: (action) => {
|
|
75
|
+
currentAction = action;
|
|
76
|
+
},
|
|
77
|
+
stop: (finalMsg) => {
|
|
78
|
+
clearInterval(timer);
|
|
79
|
+
process.stderr.write('\r\x1b[K');
|
|
80
|
+
if (finalMsg) {
|
|
81
|
+
process.stderr.write(`${finalMsg}\n`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
export function info(msg) {
|
|
87
|
+
console.log(`${styleText('blue', 'i')} ${msg}`);
|
|
88
|
+
}
|
|
89
|
+
export function warn(msg) {
|
|
90
|
+
console.log(`${styleText('yellow', '!')} ${msg}`);
|
|
91
|
+
}
|
|
92
|
+
export function error(msg) {
|
|
93
|
+
console.error(`${styleText('red', '✗')} ${msg}`);
|
|
94
|
+
}
|
|
95
|
+
export function success(msg) {
|
|
96
|
+
console.log(`${styleText('green', '✓')} ${msg}`);
|
|
97
|
+
}
|
|
98
|
+
export function step(msg) {
|
|
99
|
+
console.log(`${accent('●')} ${msg}`);
|
|
100
|
+
}
|
|
101
|
+
export function done(msg) {
|
|
102
|
+
console.log(`${styleText('green', '✓')} ${msg}`);
|
|
103
|
+
}
|
|
104
|
+
export function fail(msg) {
|
|
105
|
+
console.error(`${styleText('red', '✗')} ${msg}`);
|
|
106
|
+
}
|
|
107
|
+
export function heading(msg) {
|
|
108
|
+
console.log(styleText(['bold', 'underline'], msg));
|
|
109
|
+
}
|
|
110
|
+
export function divider() {
|
|
111
|
+
console.log(styleText('dim', '────────────────────────────────────────'));
|
|
112
|
+
}
|
|
113
|
+
export function separator() {
|
|
114
|
+
console.log(styleText('dim', '·'.repeat(40)));
|
|
115
|
+
}
|
|
116
|
+
export function spinner(msg) {
|
|
117
|
+
const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
118
|
+
let i = 0;
|
|
119
|
+
const timer = setInterval(() => {
|
|
120
|
+
process.stderr.write(`\r${accent(frames[i])} ${msg}`);
|
|
121
|
+
i = (i + 1) % frames.length;
|
|
122
|
+
}, 80);
|
|
123
|
+
return {
|
|
124
|
+
stop: (finalMsg) => {
|
|
125
|
+
clearInterval(timer);
|
|
126
|
+
process.stderr.write('\r\x1b[K');
|
|
127
|
+
if (finalMsg) {
|
|
128
|
+
process.stderr.write(`${finalMsg}\n`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
export function welcome(project, model) {
|
|
134
|
+
console.log(`${styleText('dim', '◇')} Session started in ${accent(project)}`);
|
|
135
|
+
console.log(`${styleText('dim', '◇')} Model: ${model}`);
|
|
136
|
+
separator();
|
|
137
|
+
}
|
|
138
|
+
export function prompt() {
|
|
139
|
+
return `${accent(currentAvatar)} > `;
|
|
140
|
+
}
|
|
141
|
+
export function userMessage(msg) {
|
|
142
|
+
console.log(`› ${msg}`);
|
|
143
|
+
}
|
|
144
|
+
export function aiMessage(msg) {
|
|
145
|
+
console.log(`${accent(currentAvatar)} ${msg}`);
|
|
146
|
+
}
|
|
147
|
+
export function toolStart(name, summary) {
|
|
148
|
+
console.log(`${accent('▸')} ${name} ${styleText('dim', summary)}`);
|
|
149
|
+
}
|
|
150
|
+
export function toolEnd(name, isSuccess, duration) {
|
|
151
|
+
const status = isSuccess ? styleText('green', '✓') : styleText('red', '✗');
|
|
152
|
+
const timing = duration !== undefined ? styleText('dim', ` (${duration}ms)`) : '';
|
|
153
|
+
console.log(` ${status} ${name}${timing}`);
|
|
154
|
+
}
|
|
155
|
+
export function diff(filename, additions, deletions) {
|
|
156
|
+
const addStr = styleText('green', `+${additions}`);
|
|
157
|
+
const delStr = styleText('red', `-${deletions}`);
|
|
158
|
+
console.log(`${styleText('dim', '◇')} ${filename} ${addStr} ${delStr}`);
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Format a unified diff with terminal colors (green additions, red deletions, cyan headers)
|
|
162
|
+
*/
|
|
163
|
+
export function formatDiff(diffText) {
|
|
164
|
+
if (!diffText)
|
|
165
|
+
return '';
|
|
166
|
+
return diffText
|
|
167
|
+
.split('\n')
|
|
168
|
+
.map(line => {
|
|
169
|
+
if (line.startsWith('+'))
|
|
170
|
+
return styleText('green', line);
|
|
171
|
+
if (line.startsWith('-'))
|
|
172
|
+
return styleText('red', line);
|
|
173
|
+
if (line.startsWith('@'))
|
|
174
|
+
return styleText('cyan', line);
|
|
175
|
+
return styleText('dim', line);
|
|
176
|
+
})
|
|
177
|
+
.join('\n');
|
|
178
|
+
}
|
|
179
|
+
export function planStep(index, description, status) {
|
|
180
|
+
let icon = ' ';
|
|
181
|
+
if (status === 'done')
|
|
182
|
+
icon = styleText('green', '✓');
|
|
183
|
+
else if (status === 'failed')
|
|
184
|
+
icon = styleText('red', '✗');
|
|
185
|
+
else if (status === 'in-progress')
|
|
186
|
+
icon = accent('⟳');
|
|
187
|
+
else
|
|
188
|
+
icon = styleText('dim', '○');
|
|
189
|
+
console.log(`${icon} ${index}. ${description}`);
|
|
190
|
+
}
|
|
191
|
+
export function sessionInfo(id, model, cwd) {
|
|
192
|
+
console.log(`${styleText('dim', '◇')} ID: ${id} | Model: ${model} | CWD: ${cwd}`);
|
|
193
|
+
}
|
|
194
|
+
export function progress(current, total, label) {
|
|
195
|
+
const percent = total > 0 ? Math.round((current / total) * 100) : 0;
|
|
196
|
+
console.log(`${accent('⟳')} [${current}/${total}] ${percent}% - ${label}`);
|
|
197
|
+
}
|
|
198
|
+
export function compact(msg) {
|
|
199
|
+
console.log(`${styleText('dim', '◇')} ${msg}`);
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Displays a structured status card with aligned labels and values
|
|
203
|
+
*/
|
|
204
|
+
export function statusCard(title, entries) {
|
|
205
|
+
console.log(`\n${accent(currentAvatar)} ${bold(title)}`);
|
|
206
|
+
console.log(styleText('dim', '─'.repeat(45)));
|
|
207
|
+
const maxKeyLen = Math.max(...Object.keys(entries).map(k => k.length), 0);
|
|
208
|
+
for (const [key, value] of Object.entries(entries)) {
|
|
209
|
+
if (value === undefined)
|
|
210
|
+
continue;
|
|
211
|
+
const paddedKey = key.padEnd(maxKeyLen + 2, ' ');
|
|
212
|
+
console.log(` ${styleText('dim', paddedKey)}${value}`);
|
|
213
|
+
}
|
|
214
|
+
console.log(styleText('dim', '─'.repeat(45)));
|
|
215
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { AgentState, CompanionPetInfo, PetProvider } from './types.js';
|
|
2
|
+
export declare class PetdexAdapter implements PetProvider {
|
|
3
|
+
readonly id = "petdex";
|
|
4
|
+
readonly name = "Petdex Library";
|
|
5
|
+
private customSearchDirs;
|
|
6
|
+
constructor(additionalDirs?: string[]);
|
|
7
|
+
getSearchDirectories(): string[];
|
|
8
|
+
/**
|
|
9
|
+
* Scans local Petdex pet directories and returns structured metadata
|
|
10
|
+
*/
|
|
11
|
+
listPets(): Promise<CompanionPetInfo[]>;
|
|
12
|
+
getPet(petId: string): Promise<CompanionPetInfo | null>;
|
|
13
|
+
private inspectPetDirectory;
|
|
14
|
+
/**
|
|
15
|
+
* Installs a pet from the Petdex gallery using the official `petdex` CLI
|
|
16
|
+
*/
|
|
17
|
+
installPet(slug: string): Promise<{
|
|
18
|
+
success: boolean;
|
|
19
|
+
message: string;
|
|
20
|
+
pet?: CompanionPetInfo;
|
|
21
|
+
}>;
|
|
22
|
+
/**
|
|
23
|
+
* Maps an Overarch AgentState to the corresponding Petdex spritesheet row index
|
|
24
|
+
*/
|
|
25
|
+
mapStateToAnimationRow(state: AgentState): {
|
|
26
|
+
row: number;
|
|
27
|
+
label: string;
|
|
28
|
+
};
|
|
29
|
+
private slugToTitle;
|
|
30
|
+
}
|
|
31
|
+
export declare const petdexAdapter: PetdexAdapter;
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import * as fs from 'node:fs/promises';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
import * as os from 'node:os';
|
|
4
|
+
import { exec } from 'node:child_process';
|
|
5
|
+
import { promisify } from 'node:util';
|
|
6
|
+
import { PETDEX_DEFAULT_ROW_MAPPING } from './types.js';
|
|
7
|
+
const execAsync = promisify(exec);
|
|
8
|
+
export class PetdexAdapter {
|
|
9
|
+
id = 'petdex';
|
|
10
|
+
name = 'Petdex Library';
|
|
11
|
+
customSearchDirs = [];
|
|
12
|
+
constructor(additionalDirs = []) {
|
|
13
|
+
this.customSearchDirs = additionalDirs;
|
|
14
|
+
}
|
|
15
|
+
getSearchDirectories() {
|
|
16
|
+
const home = os.homedir();
|
|
17
|
+
const dirs = [
|
|
18
|
+
path.join(home, '.petdex', 'pets'),
|
|
19
|
+
path.join(home, '.codex', 'pets'),
|
|
20
|
+
...this.customSearchDirs,
|
|
21
|
+
];
|
|
22
|
+
return dirs;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Scans local Petdex pet directories and returns structured metadata
|
|
26
|
+
*/
|
|
27
|
+
async listPets() {
|
|
28
|
+
const dirs = this.getSearchDirectories();
|
|
29
|
+
const petsMap = new Map();
|
|
30
|
+
for (const baseDir of dirs) {
|
|
31
|
+
try {
|
|
32
|
+
const entries = await fs.readdir(baseDir, { withFileTypes: true });
|
|
33
|
+
for (const entry of entries) {
|
|
34
|
+
if (entry.isDirectory()) {
|
|
35
|
+
const petDir = path.join(baseDir, entry.name);
|
|
36
|
+
const petInfo = await this.inspectPetDirectory(entry.name, petDir);
|
|
37
|
+
if (petInfo && !petsMap.has(petInfo.id)) {
|
|
38
|
+
petsMap.set(petInfo.id, petInfo);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// Directory doesn't exist or is inaccessible
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return Array.from(petsMap.values());
|
|
48
|
+
}
|
|
49
|
+
async getPet(petId) {
|
|
50
|
+
const all = await this.listPets();
|
|
51
|
+
return all.find(p => p.id === petId || p.id.toLowerCase() === petId.toLowerCase()) || null;
|
|
52
|
+
}
|
|
53
|
+
async inspectPetDirectory(slug, dirPath) {
|
|
54
|
+
const petJsonPath = path.join(dirPath, 'pet.json');
|
|
55
|
+
let manifest = {};
|
|
56
|
+
try {
|
|
57
|
+
const raw = await fs.readFile(petJsonPath, 'utf8');
|
|
58
|
+
manifest = JSON.parse(raw);
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
// Manifest not found or malformed; default to slug
|
|
62
|
+
}
|
|
63
|
+
// Determine spritesheet file (.webp or .png)
|
|
64
|
+
let spritesheetPath;
|
|
65
|
+
let spritesheetFormat = 'webp';
|
|
66
|
+
const webpPath = path.join(dirPath, manifest.spritesheetPath || 'spritesheet.webp');
|
|
67
|
+
const pngPath = path.join(dirPath, manifest.spritesheetPath || 'spritesheet.png');
|
|
68
|
+
try {
|
|
69
|
+
await fs.access(webpPath);
|
|
70
|
+
spritesheetPath = webpPath;
|
|
71
|
+
spritesheetFormat = 'webp';
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
try {
|
|
75
|
+
await fs.access(pngPath);
|
|
76
|
+
spritesheetPath = pngPath;
|
|
77
|
+
spritesheetFormat = 'png';
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
// No spritesheet found
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (!spritesheetPath) {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
const spriteVersionNumber = manifest.spriteVersionNumber === 2 ? 2 : 1;
|
|
87
|
+
const columns = 8;
|
|
88
|
+
const rows = spriteVersionNumber === 2 ? 11 : 9;
|
|
89
|
+
return {
|
|
90
|
+
id: manifest.id || slug,
|
|
91
|
+
displayName: manifest.displayName || this.slugToTitle(slug),
|
|
92
|
+
description: manifest.description || 'Petdex digital companion',
|
|
93
|
+
source: 'petdex-installed',
|
|
94
|
+
spritesheetPath,
|
|
95
|
+
spritesheetFormat,
|
|
96
|
+
spriteVersionNumber,
|
|
97
|
+
columns,
|
|
98
|
+
rows,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Installs a pet from the Petdex gallery using the official `petdex` CLI
|
|
103
|
+
*/
|
|
104
|
+
async installPet(slug) {
|
|
105
|
+
const cleanSlug = slug.trim().toLowerCase();
|
|
106
|
+
if (!cleanSlug) {
|
|
107
|
+
return { success: false, message: 'Invalid or empty pet slug' };
|
|
108
|
+
}
|
|
109
|
+
try {
|
|
110
|
+
// Run npx petdex install <slug>
|
|
111
|
+
const { stdout, stderr } = await execAsync(`npx -y petdex@latest install ${cleanSlug}`, {
|
|
112
|
+
timeout: 45000,
|
|
113
|
+
env: { ...process.env, CI: 'true' },
|
|
114
|
+
});
|
|
115
|
+
const pet = await this.getPet(cleanSlug);
|
|
116
|
+
if (pet) {
|
|
117
|
+
return {
|
|
118
|
+
success: true,
|
|
119
|
+
message: `Successfully installed ${pet.displayName} from Petdex library.`,
|
|
120
|
+
pet,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
return {
|
|
124
|
+
success: true,
|
|
125
|
+
message: stdout || stderr || `Installed ${cleanSlug} into ~/.petdex/pets/`,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
catch (err) {
|
|
129
|
+
return {
|
|
130
|
+
success: false,
|
|
131
|
+
message: `Failed to install Petdex pet '${cleanSlug}': ${err.message}`,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Maps an Overarch AgentState to the corresponding Petdex spritesheet row index
|
|
137
|
+
*/
|
|
138
|
+
mapStateToAnimationRow(state) {
|
|
139
|
+
switch (state) {
|
|
140
|
+
case 'idle':
|
|
141
|
+
return { row: PETDEX_DEFAULT_ROW_MAPPING.idle, label: 'idle' };
|
|
142
|
+
case 'thinking':
|
|
143
|
+
case 'searching':
|
|
144
|
+
case 'reading':
|
|
145
|
+
return { row: PETDEX_DEFAULT_ROW_MAPPING.review, label: 'review' };
|
|
146
|
+
case 'editing':
|
|
147
|
+
case 'executing':
|
|
148
|
+
return { row: PETDEX_DEFAULT_ROW_MAPPING.running, label: 'running' };
|
|
149
|
+
case 'waiting':
|
|
150
|
+
case 'awaiting_approval':
|
|
151
|
+
return { row: PETDEX_DEFAULT_ROW_MAPPING.waiting, label: 'waiting' };
|
|
152
|
+
case 'success':
|
|
153
|
+
return { row: PETDEX_DEFAULT_ROW_MAPPING.jumping, label: 'jumping' };
|
|
154
|
+
case 'warning':
|
|
155
|
+
case 'error':
|
|
156
|
+
return { row: PETDEX_DEFAULT_ROW_MAPPING.failed, label: 'failed' };
|
|
157
|
+
case 'stopped':
|
|
158
|
+
case 'paused':
|
|
159
|
+
case 'offline':
|
|
160
|
+
default:
|
|
161
|
+
return { row: PETDEX_DEFAULT_ROW_MAPPING.waiting, label: 'waiting' };
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
slugToTitle(slug) {
|
|
165
|
+
return slug
|
|
166
|
+
.split(/[-_]/)
|
|
167
|
+
.map(w => w.charAt(0).toUpperCase() + w.slice(1))
|
|
168
|
+
.join(' ');
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
export const petdexAdapter = new PetdexAdapter();
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { AgentState, CompanionPetInfo } from './types.js';
|
|
2
|
+
export interface PetdexEvent {
|
|
3
|
+
event: 'state_change' | 'action' | 'pet_selected' | 'ping';
|
|
4
|
+
data: {
|
|
5
|
+
state: AgentState;
|
|
6
|
+
petdexTrigger: string;
|
|
7
|
+
animationRow?: number;
|
|
8
|
+
message?: string;
|
|
9
|
+
pet?: string;
|
|
10
|
+
timestamp: string;
|
|
11
|
+
metadata?: Record<string, unknown>;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export declare const STATE_TO_PETDEX_TRIGGER: Record<AgentState, string>;
|
|
15
|
+
export declare class PetdexBridge {
|
|
16
|
+
private server;
|
|
17
|
+
private sseClients;
|
|
18
|
+
private currentState;
|
|
19
|
+
private currentMessage;
|
|
20
|
+
private activePet;
|
|
21
|
+
private port;
|
|
22
|
+
private externalHookPort;
|
|
23
|
+
private isRunning;
|
|
24
|
+
private companionProcess;
|
|
25
|
+
constructor(options?: {
|
|
26
|
+
port?: number;
|
|
27
|
+
externalHookPort?: number;
|
|
28
|
+
});
|
|
29
|
+
/**
|
|
30
|
+
* Starts local SSE / HTTP bridge server (unref'd so it does not block Node process exit)
|
|
31
|
+
*/
|
|
32
|
+
start(): Promise<void>;
|
|
33
|
+
private handleRequest;
|
|
34
|
+
/**
|
|
35
|
+
* Broadcast state change to SSE subscribers and notify external hook port if present
|
|
36
|
+
*/
|
|
37
|
+
broadcastState(state: AgentState, message?: string): void;
|
|
38
|
+
private broadcast;
|
|
39
|
+
/**
|
|
40
|
+
* Non-blocking, error-tolerant notification to standard Petdex hook port 7777
|
|
41
|
+
*/
|
|
42
|
+
private notifyExternalPetdexHook;
|
|
43
|
+
/**
|
|
44
|
+
* Discovers Petdex-compatible pets
|
|
45
|
+
*/
|
|
46
|
+
discoverPets(): Promise<CompanionPetInfo[]>;
|
|
47
|
+
/**
|
|
48
|
+
* Launches native Overarch desktop companion (or external Petdex app if present)
|
|
49
|
+
*/
|
|
50
|
+
launchCompanion(cwd?: string): Promise<{
|
|
51
|
+
success: boolean;
|
|
52
|
+
message: string;
|
|
53
|
+
}>;
|
|
54
|
+
getActivePet(): string;
|
|
55
|
+
setActivePet(pet: string): void;
|
|
56
|
+
getStatus(): {
|
|
57
|
+
running: boolean;
|
|
58
|
+
port: number;
|
|
59
|
+
connectedClients: number;
|
|
60
|
+
activePet: string;
|
|
61
|
+
state: AgentState;
|
|
62
|
+
};
|
|
63
|
+
stop(): void;
|
|
64
|
+
}
|
|
65
|
+
export declare const petdexBridge: PetdexBridge;
|