@jaimevalasek/aioson 1.4.0 → 1.5.1
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/CHANGELOG.md +31 -1
- package/LICENSE +661 -21
- package/README.md +3 -1
- package/docs/en/squad-dashboard.md +372 -0
- package/docs/openclaw-bridge.md +308 -0
- package/docs/pt/agentes.md +124 -10
- package/docs/pt/cenarios.md +46 -2
- package/docs/pt/comandos-cli.md +60 -1
- package/docs/pt/inicio-rapido.md +18 -2
- package/docs/pt/squad-dashboard.md +373 -0
- package/docs/testing/genome-2.0-matrix.md +5 -5
- package/docs/testing/genome-2.0-rollout.md +9 -9
- package/package.json +2 -2
- package/src/backup-local.js +74 -0
- package/src/cli.js +98 -0
- package/src/commands/backup-local-cmd.js +25 -0
- package/src/commands/runtime.js +242 -0
- package/src/commands/setup-context.js +7 -2
- package/src/commands/squad-daemon.js +209 -0
- package/src/commands/squad-dashboard.js +39 -0
- package/src/commands/squad-deploy.js +64 -0
- package/src/commands/squad-doctor.js +52 -0
- package/src/commands/squad-mcp.js +270 -0
- package/src/commands/squad-processes.js +56 -0
- package/src/commands/squad-recovery.js +42 -0
- package/src/commands/squad-roi.js +291 -0
- package/src/commands/squad-score.js +250 -0
- package/src/commands/squad-status.js +37 -1
- package/src/commands/squad-validate.js +62 -1
- package/src/commands/squad-webhook.js +160 -0
- package/src/commands/squad-worker.js +191 -0
- package/src/commands/squad-worktrees.js +75 -0
- package/src/commands/web-map.js +70 -0
- package/src/commands/web-scrape.js +71 -0
- package/src/constants.js +8 -0
- package/src/context-writer.js +45 -1
- package/src/i18n/messages/en.js +127 -1
- package/src/i18n/messages/es.js +117 -0
- package/src/i18n/messages/fr.js +117 -0
- package/src/i18n/messages/pt-BR.js +126 -1
- package/src/lib/webhook-server.js +328 -0
- package/src/mcp-connectors/registry.js +602 -0
- package/src/runtime-store.js +259 -2
- package/src/squad/external-session.js +180 -0
- package/src/squad/inter-squad.js +74 -0
- package/src/squad/recovery-context.js +201 -0
- package/src/squad/worktree-manager.js +114 -0
- package/src/squad-daemon.js +490 -0
- package/src/squad-dashboard/api.js +223 -0
- package/src/squad-dashboard/attachment-handler.js +93 -0
- package/src/squad-dashboard/context-monitor.js +157 -0
- package/src/squad-dashboard/execution-logs.js +115 -0
- package/src/squad-dashboard/hunk-review.js +209 -0
- package/src/squad-dashboard/metrics.js +133 -0
- package/src/squad-dashboard/process-monitor.js +125 -0
- package/src/squad-dashboard/renderer.js +858 -0
- package/src/squad-dashboard/server.js +232 -0
- package/src/squad-dashboard/styles.js +525 -0
- package/src/squad-dashboard/token-tracker.js +99 -0
- package/src/web.js +284 -0
- package/src/worker-runner.js +339 -0
- package/template/.aioson/agents/analyst.md +4 -0
- package/template/.aioson/agents/architect.md +4 -0
- package/template/.aioson/agents/dev.md +120 -11
- package/template/.aioson/agents/deyvin.md +8 -0
- package/template/.aioson/agents/neo.md +152 -0
- package/template/.aioson/agents/orache.md +17 -0
- package/template/.aioson/agents/orchestrator.md +26 -0
- package/template/.aioson/agents/product.md +60 -12
- package/template/.aioson/agents/qa.md +1 -0
- package/template/.aioson/agents/setup.md +63 -19
- package/template/.aioson/agents/sheldon.md +603 -0
- package/template/.aioson/agents/squad.md +191 -0
- package/template/.aioson/agents/tester.md +254 -0
- package/template/.aioson/agents/ux-ui.md +12 -0
- package/template/.aioson/config.md +6 -0
- package/template/.aioson/locales/en/agents/analyst.md +8 -0
- package/template/.aioson/locales/en/agents/architect.md +8 -0
- package/template/.aioson/locales/en/agents/dev.md +66 -7
- package/template/.aioson/locales/en/agents/deyvin.md +8 -0
- package/template/.aioson/locales/en/agents/neo.md +8 -0
- package/template/.aioson/locales/en/agents/orchestrator.md +26 -0
- package/template/.aioson/locales/en/agents/qa.md +49 -0
- package/template/.aioson/locales/en/agents/setup.md +2 -1
- package/template/.aioson/locales/en/agents/sheldon.md +340 -0
- package/template/.aioson/locales/en/agents/ux-ui.md +8 -0
- package/template/.aioson/locales/es/agents/analyst.md +8 -0
- package/template/.aioson/locales/es/agents/architect.md +8 -0
- package/template/.aioson/locales/es/agents/dev.md +66 -7
- package/template/.aioson/locales/es/agents/deyvin.md +8 -0
- package/template/.aioson/locales/es/agents/neo.md +48 -0
- package/template/.aioson/locales/es/agents/orchestrator.md +26 -0
- package/template/.aioson/locales/es/agents/qa.md +26 -0
- package/template/.aioson/locales/es/agents/setup.md +2 -1
- package/template/.aioson/locales/es/agents/sheldon.md +192 -0
- package/template/.aioson/locales/es/agents/squad.md +63 -0
- package/template/.aioson/locales/es/agents/ux-ui.md +8 -0
- package/template/.aioson/locales/fr/agents/analyst.md +8 -0
- package/template/.aioson/locales/fr/agents/architect.md +8 -0
- package/template/.aioson/locales/fr/agents/dev.md +66 -7
- package/template/.aioson/locales/fr/agents/deyvin.md +8 -0
- package/template/.aioson/locales/fr/agents/neo.md +48 -0
- package/template/.aioson/locales/fr/agents/orchestrator.md +26 -0
- package/template/.aioson/locales/fr/agents/qa.md +26 -0
- package/template/.aioson/locales/fr/agents/setup.md +2 -1
- package/template/.aioson/locales/fr/agents/sheldon.md +192 -0
- package/template/.aioson/locales/fr/agents/squad.md +63 -0
- package/template/.aioson/locales/fr/agents/ux-ui.md +8 -0
- package/template/.aioson/locales/pt-BR/agents/analyst.md +19 -0
- package/template/.aioson/locales/pt-BR/agents/architect.md +19 -0
- package/template/.aioson/locales/pt-BR/agents/dev.md +75 -12
- package/template/.aioson/locales/pt-BR/agents/deyvin.md +8 -0
- package/template/.aioson/locales/pt-BR/agents/neo.md +147 -0
- package/template/.aioson/locales/pt-BR/agents/orchestrator.md +26 -0
- package/template/.aioson/locales/pt-BR/agents/product.md +8 -3
- package/template/.aioson/locales/pt-BR/agents/qa.md +60 -0
- package/template/.aioson/locales/pt-BR/agents/setup.md +2 -1
- package/template/.aioson/locales/pt-BR/agents/sheldon.md +192 -0
- package/template/.aioson/locales/pt-BR/agents/squad.md +105 -0
- package/template/.aioson/locales/pt-BR/agents/ux-ui.md +8 -0
- package/template/.aioson/schemas/squad-blueprint.schema.json +21 -0
- package/template/.aioson/schemas/squad-manifest.schema.json +178 -1
- package/template/.aioson/skills/design/bold-editorial-ui/SKILL.md +205 -0
- package/template/.aioson/skills/design/bold-editorial-ui/references/art-direction.md +338 -0
- package/template/.aioson/skills/design/bold-editorial-ui/references/components.md +977 -0
- package/template/.aioson/skills/design/bold-editorial-ui/references/dashboards.md +218 -0
- package/template/.aioson/skills/design/bold-editorial-ui/references/design-tokens.md +326 -0
- package/template/.aioson/skills/design/bold-editorial-ui/references/motion.md +461 -0
- package/template/.aioson/skills/design/bold-editorial-ui/references/patterns.md +293 -0
- package/template/.aioson/skills/design/bold-editorial-ui/references/websites.md +352 -0
- package/template/.aioson/skills/design/clean-saas-ui/SKILL.md +210 -0
- package/template/.aioson/skills/design/clean-saas-ui/references/art-direction.md +319 -0
- package/template/.aioson/skills/design/clean-saas-ui/references/components.md +365 -0
- package/template/.aioson/skills/design/clean-saas-ui/references/dashboards.md +196 -0
- package/template/.aioson/skills/design/clean-saas-ui/references/design-tokens.md +244 -0
- package/template/.aioson/skills/design/clean-saas-ui/references/motion.md +235 -0
- package/template/.aioson/skills/design/clean-saas-ui/references/patterns.md +215 -0
- package/template/.aioson/skills/design/clean-saas-ui/references/websites.md +295 -0
- package/template/.aioson/skills/design/cognitive-core-ui/SKILL.md +55 -9
- package/template/.aioson/skills/design/cognitive-core-ui/references/art-direction.md +339 -0
- package/template/.aioson/skills/design/cognitive-core-ui/references/components.md +1 -1
- package/template/.aioson/skills/design/cognitive-core-ui/references/dashboards.md +100 -0
- package/template/.aioson/skills/design/cognitive-core-ui/references/design-tokens.md +43 -9
- package/template/.aioson/skills/design/cognitive-core-ui/references/motion.md +40 -0
- package/template/.aioson/skills/design/cognitive-core-ui/references/patterns.md +1 -1
- package/template/.aioson/skills/design/cognitive-core-ui/references/websites.md +99 -12
- package/template/.aioson/skills/design/warm-craft-ui/SKILL.md +209 -0
- package/template/.aioson/skills/design/warm-craft-ui/references/art-direction.md +324 -0
- package/template/.aioson/skills/design/warm-craft-ui/references/components.md +508 -0
- package/template/.aioson/skills/design/warm-craft-ui/references/dashboards.md +223 -0
- package/template/.aioson/skills/design/warm-craft-ui/references/design-tokens.md +374 -0
- package/template/.aioson/skills/design/warm-craft-ui/references/motion.md +356 -0
- package/template/.aioson/skills/design/warm-craft-ui/references/patterns.md +288 -0
- package/template/.aioson/skills/design/warm-craft-ui/references/websites.md +289 -0
- package/template/.aioson/skills/premium-visual-design/SKILL.md +83 -0
- package/template/.aioson/skills/premium-visual-design/components/agent-badge.md +92 -0
- package/template/.aioson/skills/premium-visual-design/components/dependency-node.md +102 -0
- package/template/.aioson/skills/premium-visual-design/components/mention-autocomplete.md +136 -0
- package/template/.aioson/skills/premium-visual-design/components/notification-center.md +136 -0
- package/template/.aioson/skills/premium-visual-design/components/review-action-bar.md +188 -0
- package/template/.aioson/skills/premium-visual-design/components/team-switcher.md +131 -0
- package/template/.aioson/skills/premium-visual-design/patterns/agent-message-thread.md +198 -0
- package/template/.aioson/skills/premium-visual-design/patterns/notification-panel.md +275 -0
- package/template/.aioson/skills/premium-visual-design/patterns/review-workflow-ui.md +234 -0
- package/template/.aioson/skills/premium-visual-design/patterns/task-dependency-graph.md +147 -0
- package/template/.aioson/skills/premium-visual-design/tokens/status-extended.md +142 -0
- package/template/.aioson/skills/squad/formats/catalog.json +15 -0
- package/template/.aioson/skills/squad/formats/content/blog-post.md +47 -0
- package/template/.aioson/skills/squad/formats/content/newsletter.md +47 -0
- package/template/.aioson/skills/squad/formats/creative/podcast-script.md +43 -0
- package/template/.aioson/skills/squad/formats/creative/video-script.md +41 -0
- package/template/.aioson/skills/squad/formats/social/instagram-feed.md +42 -0
- package/template/.aioson/skills/squad/formats/social/linkedin-post.md +42 -0
- package/template/.aioson/skills/squad/formats/social/tiktok.md +39 -0
- package/template/.aioson/skills/squad/formats/social/twitter-thread.md +39 -0
- package/template/.aioson/skills/squad/formats/social/youtube-long.md +47 -0
- package/template/.aioson/skills/squad/formats/social/youtube-shorts.md +39 -0
- package/template/.aioson/skills/squad/patterns/multi-platform-pattern.md +108 -0
- package/template/.aioson/skills/squad/patterns/persona-based-pattern.md +98 -0
- package/template/.aioson/skills/squad/patterns/pipeline-pattern.md +106 -0
- package/template/.aioson/skills/squad/patterns/review-loop-pattern.md +81 -0
- package/template/.aioson/skills/squad/references/checklist-templates.md +122 -0
- package/template/.aioson/skills/squad/references/executor-archetypes.md +123 -0
- package/template/.aioson/skills/squad/references/workflow-templates.md +169 -0
- package/template/.aioson/skills/static/debugging-protocol.md +42 -0
- package/template/.aioson/skills/static/git-worktrees.md +36 -0
- package/template/.aioson/tasks/implementation-plan.md +19 -0
- package/template/.aioson/tasks/squad-design.md +28 -0
- package/template/.aioson/tasks/squad-profile.md +48 -0
- package/template/.aioson/tasks/squad-review.md +61 -0
- package/template/.aioson/tasks/squad-task-decompose.md +66 -0
- package/template/.claude/commands/aioson/agent/neo.md +5 -0
- package/template/.claude/commands/aioson/agent/tester.md +5 -0
- package/template/.gemini/GEMINI.md +1 -0
- package/template/.gemini/commands/aios-neo.toml +4 -0
- package/template/.gemini/commands/aios-tester.toml +6 -0
- package/template/AGENTS.md +3 -0
- package/template/CLAUDE.md +5 -2
- package/template/OPENCODE.md +2 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('node:fs/promises');
|
|
4
|
+
const path = require('node:path');
|
|
5
|
+
|
|
6
|
+
const SQUADS_DIR = path.join('.aioson', 'squads');
|
|
7
|
+
|
|
8
|
+
// Events that trigger an automatic refresh of the recovery context
|
|
9
|
+
const REFRESH_EVENTS = new Set(['task_completed', 'decision_made', 'handoff']);
|
|
10
|
+
|
|
11
|
+
// Approximate token count (chars / 4)
|
|
12
|
+
function estimateTokens(str) {
|
|
13
|
+
return Math.ceil(str.length / 4);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Read squad manifest (best-effort, returns {} on failure).
|
|
18
|
+
*/
|
|
19
|
+
async function readManifest(projectDir, squadSlug) {
|
|
20
|
+
const p = path.join(projectDir, SQUADS_DIR, squadSlug, 'squad.manifest.json');
|
|
21
|
+
try {
|
|
22
|
+
return JSON.parse(await fs.readFile(p, 'utf8'));
|
|
23
|
+
} catch {
|
|
24
|
+
return {};
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Read recent events from session-log.json (last N entries).
|
|
30
|
+
*/
|
|
31
|
+
async function readRecentEvents(projectDir, squadSlug, limit = 10) {
|
|
32
|
+
const p = path.join(projectDir, SQUADS_DIR, squadSlug, 'session-log.json');
|
|
33
|
+
try {
|
|
34
|
+
const raw = JSON.parse(await fs.readFile(p, 'utf8'));
|
|
35
|
+
const entries = Array.isArray(raw) ? raw : (raw.entries || []);
|
|
36
|
+
return entries.slice(-limit);
|
|
37
|
+
} catch {
|
|
38
|
+
return [];
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Read recent tasks from tasks.json (last 5, enriched).
|
|
44
|
+
*/
|
|
45
|
+
async function readRecentTasks(projectDir, squadSlug, limit = 5) {
|
|
46
|
+
const p = path.join(projectDir, SQUADS_DIR, squadSlug, 'tasks.json');
|
|
47
|
+
try {
|
|
48
|
+
const raw = JSON.parse(await fs.readFile(p, 'utf8'));
|
|
49
|
+
const tasks = Array.isArray(raw) ? raw : (raw.tasks || []);
|
|
50
|
+
return tasks.slice(-limit);
|
|
51
|
+
} catch {
|
|
52
|
+
return [];
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Read context-monitor.json snapshot for an agent.
|
|
58
|
+
*/
|
|
59
|
+
async function readContextSnapshot(projectDir, squadSlug, agentSlug) {
|
|
60
|
+
const p = path.join(projectDir, SQUADS_DIR, squadSlug, 'context-monitor.json');
|
|
61
|
+
try {
|
|
62
|
+
const data = JSON.parse(await fs.readFile(p, 'utf8'));
|
|
63
|
+
if (agentSlug && data.agents && data.agents[agentSlug]) {
|
|
64
|
+
return data.agents[agentSlug];
|
|
65
|
+
}
|
|
66
|
+
return data;
|
|
67
|
+
} catch {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Build the markdown content for recovery-context.md.
|
|
74
|
+
* Target < 2000 tokens.
|
|
75
|
+
*/
|
|
76
|
+
function buildRecoveryMarkdown(squadSlug, agentSlug, manifest, tasks, events, ctxSnapshot) {
|
|
77
|
+
const lines = [];
|
|
78
|
+
|
|
79
|
+
lines.push(`# Recovery Context — ${squadSlug} / ${agentSlug}`);
|
|
80
|
+
lines.push(`> Generated: ${new Date().toISOString()}`);
|
|
81
|
+
lines.push('');
|
|
82
|
+
|
|
83
|
+
// Squad goal
|
|
84
|
+
if (manifest.goal) {
|
|
85
|
+
lines.push('## Squad Goal');
|
|
86
|
+
lines.push(manifest.goal);
|
|
87
|
+
lines.push('');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Agent role (from executors array)
|
|
91
|
+
const executor = (manifest.executors || []).find(e => e.slug === agentSlug);
|
|
92
|
+
if (executor) {
|
|
93
|
+
lines.push('## Your Role');
|
|
94
|
+
lines.push(`**${executor.title || agentSlug}**: ${executor.role || ''}`);
|
|
95
|
+
lines.push('');
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Recent tasks
|
|
99
|
+
if (tasks.length > 0) {
|
|
100
|
+
lines.push('## Recent Tasks');
|
|
101
|
+
for (const t of tasks) {
|
|
102
|
+
const status = t.status || 'unknown';
|
|
103
|
+
const title = t.title || t.slug || t.id || '(untitled)';
|
|
104
|
+
lines.push(`- [${status}] ${title}`);
|
|
105
|
+
if (t.output && typeof t.output === 'string') {
|
|
106
|
+
// Truncate long outputs
|
|
107
|
+
const out = t.output.length > 200 ? t.output.slice(0, 200) + '…' : t.output;
|
|
108
|
+
lines.push(` Output: ${out}`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
lines.push('');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Recent events
|
|
115
|
+
if (events.length > 0) {
|
|
116
|
+
lines.push('## Recent Events');
|
|
117
|
+
for (const ev of events) {
|
|
118
|
+
const ts = ev.created_at || ev.timestamp || '';
|
|
119
|
+
const type = ev.event_type || ev.type || 'event';
|
|
120
|
+
const msg = ev.message || ev.summary || '';
|
|
121
|
+
lines.push(`- [${ts}] ${type}: ${msg}`);
|
|
122
|
+
}
|
|
123
|
+
lines.push('');
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Context snapshot
|
|
127
|
+
if (ctxSnapshot) {
|
|
128
|
+
lines.push('## Context Window at Last Compact');
|
|
129
|
+
const used = ctxSnapshot.totalUsed || 0;
|
|
130
|
+
const win = ctxSnapshot.windowSize || 0;
|
|
131
|
+
const pct = win > 0 ? Math.round((used / win) * 100) : 0;
|
|
132
|
+
lines.push(`Used: ${used.toLocaleString()} / ${win.toLocaleString()} tokens (${pct}%)`);
|
|
133
|
+
lines.push('');
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
lines.push('---');
|
|
137
|
+
lines.push('*Inject this file at the top of your next session to restore context after a compact.*');
|
|
138
|
+
|
|
139
|
+
const content = lines.join('\n');
|
|
140
|
+
|
|
141
|
+
// Enforce token limit: if over budget, trim events section
|
|
142
|
+
if (estimateTokens(content) > 2000) {
|
|
143
|
+
// Rebuild with fewer events
|
|
144
|
+
return buildRecoveryMarkdown(squadSlug, agentSlug, manifest, tasks, events.slice(-3), ctxSnapshot);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return content;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Generate and write recovery-context.md for an agent.
|
|
152
|
+
* @param {string} projectDir
|
|
153
|
+
* @param {string} squadSlug
|
|
154
|
+
* @param {string} agentSlug
|
|
155
|
+
* @returns {{ ok: boolean, path: string, tokens: number }}
|
|
156
|
+
*/
|
|
157
|
+
async function generateRecovery(projectDir, squadSlug, agentSlug) {
|
|
158
|
+
const [manifest, tasks, events, ctxSnapshot] = await Promise.all([
|
|
159
|
+
readManifest(projectDir, squadSlug),
|
|
160
|
+
readRecentTasks(projectDir, squadSlug),
|
|
161
|
+
readRecentEvents(projectDir, squadSlug),
|
|
162
|
+
readContextSnapshot(projectDir, squadSlug, agentSlug)
|
|
163
|
+
]);
|
|
164
|
+
|
|
165
|
+
const content = buildRecoveryMarkdown(squadSlug, agentSlug, manifest, tasks, events, ctxSnapshot);
|
|
166
|
+
const tokens = estimateTokens(content);
|
|
167
|
+
|
|
168
|
+
const outDir = path.join(projectDir, SQUADS_DIR, squadSlug);
|
|
169
|
+
const outPath = path.join(outDir, `recovery-context.md`);
|
|
170
|
+
|
|
171
|
+
try {
|
|
172
|
+
await fs.mkdir(outDir, { recursive: true });
|
|
173
|
+
await fs.writeFile(outPath, content, 'utf8');
|
|
174
|
+
} catch (err) {
|
|
175
|
+
return { ok: false, error: err.message, path: outPath, tokens };
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return { ok: true, path: outPath, tokens, squadSlug, agentSlug };
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Read the current recovery-context.md for an agent (returns null if missing).
|
|
183
|
+
*/
|
|
184
|
+
async function readRecovery(projectDir, squadSlug) {
|
|
185
|
+
const p = path.join(projectDir, SQUADS_DIR, squadSlug, 'recovery-context.md');
|
|
186
|
+
try {
|
|
187
|
+
return await fs.readFile(p, 'utf8');
|
|
188
|
+
} catch {
|
|
189
|
+
return null;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Check if a runtime event should trigger a recovery refresh.
|
|
195
|
+
* @param {string} eventType
|
|
196
|
+
*/
|
|
197
|
+
function shouldRefreshOnEvent(eventType) {
|
|
198
|
+
return REFRESH_EVENTS.has(eventType);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
module.exports = { generateRecovery, readRecovery, shouldRefreshOnEvent, REFRESH_EVENTS };
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { spawnSync } = require('node:child_process');
|
|
4
|
+
const path = require('node:path');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Create a git worktree for a squad agent.
|
|
8
|
+
* Branch: aioson/{squadSlug}/{agentSlug}
|
|
9
|
+
* Path: .aioson/squads/{squadSlug}/worktrees/{agentSlug}
|
|
10
|
+
*/
|
|
11
|
+
function createWorktree(projectDir, squadSlug, agentSlug) {
|
|
12
|
+
const branchName = `aioson/${squadSlug}/${agentSlug}`;
|
|
13
|
+
const worktreePath = path.join(projectDir, '.aioson', 'squads', squadSlug, 'worktrees', agentSlug);
|
|
14
|
+
|
|
15
|
+
// Try with new branch first
|
|
16
|
+
let result = spawnSync('git', ['worktree', 'add', '-b', branchName, worktreePath], {
|
|
17
|
+
cwd: projectDir,
|
|
18
|
+
encoding: 'utf8'
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
if (result.status !== 0) {
|
|
22
|
+
// Branch may already exist — try without -b
|
|
23
|
+
result = spawnSync('git', ['worktree', 'add', worktreePath, branchName], {
|
|
24
|
+
cwd: projectDir,
|
|
25
|
+
encoding: 'utf8'
|
|
26
|
+
});
|
|
27
|
+
if (result.status !== 0) {
|
|
28
|
+
throw new Error(result.stderr || 'Failed to create worktree');
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return { ok: true, branchName, worktreePath };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Merge worktree branch back to the current branch.
|
|
37
|
+
* autoMerge=true → attempt fast-forward. false → report without merging.
|
|
38
|
+
*/
|
|
39
|
+
function mergeWorktree(projectDir, squadSlug, agentSlug, autoMerge = false) {
|
|
40
|
+
const branchName = `aioson/${squadSlug}/${agentSlug}`;
|
|
41
|
+
|
|
42
|
+
if (!autoMerge) {
|
|
43
|
+
return { ok: false, reason: 'auto_merge_disabled', branch: branchName };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const result = spawnSync('git', ['merge', '--ff-only', branchName], {
|
|
47
|
+
cwd: projectDir,
|
|
48
|
+
encoding: 'utf8'
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
if (result.status === 0) {
|
|
52
|
+
return { ok: true, branch: branchName, merged: true };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
ok: false,
|
|
57
|
+
reason: 'merge_conflict',
|
|
58
|
+
branch: branchName,
|
|
59
|
+
detail: (result.stderr || result.stdout || '').trim()
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Remove a worktree (and optionally delete its branch).
|
|
65
|
+
*/
|
|
66
|
+
function cleanupWorktree(projectDir, squadSlug, agentSlug, deleteBranch = false) {
|
|
67
|
+
const worktreePath = path.join(projectDir, '.aioson', 'squads', squadSlug, 'worktrees', agentSlug);
|
|
68
|
+
const branchName = `aioson/${squadSlug}/${agentSlug}`;
|
|
69
|
+
|
|
70
|
+
const result = spawnSync('git', ['worktree', 'remove', '--force', worktreePath], {
|
|
71
|
+
cwd: projectDir,
|
|
72
|
+
encoding: 'utf8'
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
const removed = result.status === 0;
|
|
76
|
+
|
|
77
|
+
if (deleteBranch) {
|
|
78
|
+
spawnSync('git', ['branch', '-D', branchName], { cwd: projectDir, encoding: 'utf8' });
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return { ok: removed, worktreePath, branchName };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* List all squad worktrees (filters by aioson/{squadSlug}/ branch prefix).
|
|
86
|
+
*/
|
|
87
|
+
function listWorktrees(projectDir, squadSlug) {
|
|
88
|
+
const result = spawnSync('git', ['worktree', 'list', '--porcelain'], {
|
|
89
|
+
cwd: projectDir,
|
|
90
|
+
encoding: 'utf8'
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
if (result.status !== 0) return [];
|
|
94
|
+
|
|
95
|
+
const entries = [];
|
|
96
|
+
const blocks = result.stdout.trim().split('\n\n');
|
|
97
|
+
for (const block of blocks) {
|
|
98
|
+
if (!block.trim()) continue;
|
|
99
|
+
const entry = {};
|
|
100
|
+
for (const line of block.split('\n')) {
|
|
101
|
+
if (line.startsWith('worktree ')) entry.path = line.slice(9);
|
|
102
|
+
else if (line.startsWith('branch ')) entry.branch = line.slice(7).replace('refs/heads/', '');
|
|
103
|
+
else if (line.startsWith('HEAD ')) entry.head = line.slice(5);
|
|
104
|
+
}
|
|
105
|
+
if (entry.branch && entry.branch.startsWith(`aioson/${squadSlug}/`)) {
|
|
106
|
+
entry.agentSlug = entry.branch.split('/').pop();
|
|
107
|
+
entries.push(entry);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return entries;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
module.exports = { createWorktree, mergeWorktree, cleanupWorktree, listWorktrees };
|