squads-cli 0.2.0 → 0.2.2
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/README.md +521 -288
- package/dist/auth-YW3UPFSB.js +23 -0
- package/dist/auth-YW3UPFSB.js.map +1 -0
- package/dist/autonomy-GARI6J2J.js +105 -0
- package/dist/autonomy-GARI6J2J.js.map +1 -0
- package/dist/chunk-67RO2HKR.js +174 -0
- package/dist/chunk-67RO2HKR.js.map +1 -0
- package/dist/chunk-7OCVIDC7.js +12 -0
- package/dist/chunk-7OCVIDC7.js.map +1 -0
- package/dist/chunk-BODLDQY7.js +452 -0
- package/dist/chunk-BODLDQY7.js.map +1 -0
- package/dist/chunk-EHQJHRIW.js +103 -0
- package/dist/chunk-EHQJHRIW.js.map +1 -0
- package/dist/chunk-FFFCFZ6A.js +121 -0
- package/dist/chunk-FFFCFZ6A.js.map +1 -0
- package/dist/chunk-FIWT2NMM.js +165 -0
- package/dist/chunk-FIWT2NMM.js.map +1 -0
- package/dist/chunk-HF4WR7RA.js +154 -0
- package/dist/chunk-HF4WR7RA.js.map +1 -0
- package/dist/chunk-J6QF4ZQX.js +230 -0
- package/dist/chunk-J6QF4ZQX.js.map +1 -0
- package/dist/chunk-LOA3KWYJ.js +294 -0
- package/dist/chunk-LOA3KWYJ.js.map +1 -0
- package/dist/chunk-M5FXNY6Y.js +384 -0
- package/dist/chunk-M5FXNY6Y.js.map +1 -0
- package/dist/chunk-NP5BDPE6.js +240 -0
- package/dist/chunk-NP5BDPE6.js.map +1 -0
- package/dist/chunk-O632SBON.js +62 -0
- package/dist/chunk-O632SBON.js.map +1 -0
- package/dist/chunk-QJ7C7CMB.js +223 -0
- package/dist/chunk-QJ7C7CMB.js.map +1 -0
- package/dist/chunk-QRNR4GIT.js +88 -0
- package/dist/chunk-QRNR4GIT.js.map +1 -0
- package/dist/chunk-RM6BWILN.js +74 -0
- package/dist/chunk-RM6BWILN.js.map +1 -0
- package/dist/chunk-TYFTF53O.js +613 -0
- package/dist/chunk-TYFTF53O.js.map +1 -0
- package/dist/chunk-TZXD6WFN.js +420 -0
- package/dist/chunk-TZXD6WFN.js.map +1 -0
- package/dist/chunk-WVOIY5GW.js +621 -0
- package/dist/chunk-WVOIY5GW.js.map +1 -0
- package/dist/chunk-XTHZT53Y.js +364 -0
- package/dist/chunk-XTHZT53Y.js.map +1 -0
- package/dist/chunk-Z2UKDBNL.js +162 -0
- package/dist/chunk-Z2UKDBNL.js.map +1 -0
- package/dist/chunk-ZTQ7ISUR.js +338 -0
- package/dist/chunk-ZTQ7ISUR.js.map +1 -0
- package/dist/cli.js +3371 -5852
- package/dist/cli.js.map +1 -1
- package/dist/context-PYTO2UQG.js +291 -0
- package/dist/context-PYTO2UQG.js.map +1 -0
- package/dist/context-feed-TLVZZ24S.js +394 -0
- package/dist/context-feed-TLVZZ24S.js.map +1 -0
- package/dist/cost-OALPURUQ.js +275 -0
- package/dist/cost-OALPURUQ.js.map +1 -0
- package/dist/create-BLFGG6PF.js +286 -0
- package/dist/create-BLFGG6PF.js.map +1 -0
- package/dist/dashboard-HQIEHTZC.js +951 -0
- package/dist/dashboard-HQIEHTZC.js.map +1 -0
- package/dist/dashboard-RMK2BOD2.js +794 -0
- package/dist/dashboard-RMK2BOD2.js.map +1 -0
- package/dist/doctor-TWHMR23W.js +374 -0
- package/dist/doctor-TWHMR23W.js.map +1 -0
- package/dist/env-config-SQEI3Y7Y.js +21 -0
- package/dist/env-config-SQEI3Y7Y.js.map +1 -0
- package/dist/exec-DYLI4TXY.js +223 -0
- package/dist/exec-DYLI4TXY.js.map +1 -0
- package/dist/feedback-5AEACUX6.js +229 -0
- package/dist/feedback-5AEACUX6.js.map +1 -0
- package/dist/github-UQTM5KMS.js +23 -0
- package/dist/github-UQTM5KMS.js.map +1 -0
- package/dist/goal-XUNV3CKV.js +168 -0
- package/dist/goal-XUNV3CKV.js.map +1 -0
- package/dist/health-ZF3HSA4W.js +218 -0
- package/dist/health-ZF3HSA4W.js.map +1 -0
- package/dist/history-WP6R5BNG.js +232 -0
- package/dist/history-WP6R5BNG.js.map +1 -0
- package/dist/index.d.ts +736 -8
- package/dist/index.js +1312 -6
- package/dist/index.js.map +1 -1
- package/dist/init-BQSCG57S.js +921 -0
- package/dist/init-BQSCG57S.js.map +1 -0
- package/dist/kpi-VBGDO4GI.js +413 -0
- package/dist/kpi-VBGDO4GI.js.map +1 -0
- package/dist/learn-C4B2PQ5J.js +269 -0
- package/dist/learn-C4B2PQ5J.js.map +1 -0
- package/dist/login-F6ITE7PR.js +155 -0
- package/dist/login-F6ITE7PR.js.map +1 -0
- package/dist/memory-33HYD6AN.js +560 -0
- package/dist/memory-33HYD6AN.js.map +1 -0
- package/dist/memory-VNF2VFRB.js +23 -0
- package/dist/memory-VNF2VFRB.js.map +1 -0
- package/dist/observability-CL23L7LD.js +20 -0
- package/dist/observability-CL23L7LD.js.map +1 -0
- package/dist/org-cycle-Q74OT4I4.js +130 -0
- package/dist/org-cycle-Q74OT4I4.js.map +1 -0
- package/dist/progress-P2EIZBKP.js +202 -0
- package/dist/progress-P2EIZBKP.js.map +1 -0
- package/dist/providers-LE744DM6.js +65 -0
- package/dist/providers-LE744DM6.js.map +1 -0
- package/dist/repo-enforcement-JJQMKDAU.js +75 -0
- package/dist/repo-enforcement-JJQMKDAU.js.map +1 -0
- package/dist/results-6TH33HPN.js +224 -0
- package/dist/results-6TH33HPN.js.map +1 -0
- package/dist/run-DOY5SGF3.js +4074 -0
- package/dist/run-DOY5SGF3.js.map +1 -0
- package/dist/run-context-GB6GUCKZ.js +26 -0
- package/dist/run-context-GB6GUCKZ.js.map +1 -0
- package/dist/session-HBU6KZOD.js +64 -0
- package/dist/session-HBU6KZOD.js.map +1 -0
- package/dist/sessions-CK25VGPL.js +333 -0
- package/dist/sessions-CK25VGPL.js.map +1 -0
- package/dist/squad-parser-DCG65BJS.js +35 -0
- package/dist/squad-parser-DCG65BJS.js.map +1 -0
- package/dist/stats-G6NAU5BD.js +334 -0
- package/dist/stats-G6NAU5BD.js.map +1 -0
- package/dist/status-PFFB2NV6.js +352 -0
- package/dist/status-PFFB2NV6.js.map +1 -0
- package/dist/sync-FR6LQJ4C.js +836 -0
- package/dist/sync-FR6LQJ4C.js.map +1 -0
- package/dist/templates/core/AGENTS.md.template +51 -0
- package/dist/templates/core/BUSINESS_BRIEF.md.template +29 -0
- package/dist/templates/core/CLAUDE.md.template +48 -0
- package/dist/templates/core/provider.yaml.template +5 -0
- package/dist/templates/first-squad/SQUAD.md.template +23 -0
- package/dist/templates/first-squad/lead.md.template +44 -0
- package/dist/templates/memory/getting-started/state.md.template +19 -0
- package/dist/templates/seed/BUSINESS_BRIEF.md.template +27 -0
- package/dist/templates/seed/CLAUDE.md.template +119 -0
- package/dist/templates/seed/README.md.template +42 -0
- package/dist/templates/seed/config/SYSTEM.md +58 -0
- package/dist/templates/seed/config/provider.yaml +4 -0
- package/dist/templates/seed/hooks/settings.json.template +31 -0
- package/dist/templates/seed/idp/catalog/service.yaml.template +25 -0
- package/dist/templates/seed/memory/_squad/goals.md +23 -0
- package/dist/templates/seed/memory/_squad/priorities.md +25 -0
- package/dist/templates/seed/memory/company/company.md +31 -0
- package/dist/templates/seed/memory/company/directives.md +37 -0
- package/dist/templates/seed/memory/company/manager/state.md +16 -0
- package/dist/templates/seed/memory/engineering/issue-solver/state.md +12 -0
- package/dist/templates/seed/memory/intelligence/intel-lead/state.md +9 -0
- package/dist/templates/seed/memory/marketing/content-drafter/state.md +12 -0
- package/dist/templates/seed/memory/operations/ops-lead/state.md +12 -0
- package/dist/templates/seed/memory/product/lead/state.md +14 -0
- package/dist/templates/seed/memory/research/lead/state.md +14 -0
- package/dist/templates/seed/skills/gh/SKILL.md +57 -0
- package/dist/templates/seed/skills/squads-cli/SKILL.md +329 -0
- package/dist/templates/seed/skills/squads-cli/references/commands.md +181 -0
- package/dist/templates/seed/squads/company/SQUAD.md +51 -0
- package/dist/templates/seed/squads/company/company-critic.md +57 -0
- package/dist/templates/seed/squads/company/company-eval.md +57 -0
- package/dist/templates/seed/squads/company/event-dispatcher.md +53 -0
- package/dist/templates/seed/squads/company/goal-tracker.md +51 -0
- package/dist/templates/seed/squads/company/manager.md +60 -0
- package/dist/templates/seed/squads/engineering/SQUAD.md +48 -0
- package/dist/templates/seed/squads/engineering/code-reviewer.md +69 -0
- package/dist/templates/seed/squads/engineering/issue-solver.md +66 -0
- package/dist/templates/seed/squads/engineering/test-writer.md +60 -0
- package/dist/templates/seed/squads/intelligence/SQUAD.md +38 -0
- package/dist/templates/seed/squads/intelligence/intel-critic.md +53 -0
- package/dist/templates/seed/squads/intelligence/intel-eval.md +48 -0
- package/dist/templates/seed/squads/intelligence/intel-lead.md +79 -0
- package/dist/templates/seed/squads/marketing/SQUAD.md +47 -0
- package/dist/templates/seed/squads/marketing/content-drafter.md +81 -0
- package/dist/templates/seed/squads/marketing/growth-analyst.md +61 -0
- package/dist/templates/seed/squads/marketing/social-poster.md +56 -0
- package/dist/templates/seed/squads/operations/SQUAD.md +45 -0
- package/dist/templates/seed/squads/operations/finance-tracker.md +55 -0
- package/dist/templates/seed/squads/operations/goal-tracker.md +60 -0
- package/dist/templates/seed/squads/operations/ops-lead.md +68 -0
- package/dist/templates/seed/squads/product/SQUAD.md +41 -0
- package/dist/templates/seed/squads/product/lead.md +64 -0
- package/dist/templates/seed/squads/product/scanner.md +58 -0
- package/dist/templates/seed/squads/product/worker.md +63 -0
- package/dist/templates/seed/squads/research/SQUAD.md +38 -0
- package/dist/templates/seed/squads/research/analyst.md +58 -0
- package/dist/templates/seed/squads/research/lead.md +58 -0
- package/dist/templates/seed/squads/research/synthesizer.md +67 -0
- package/dist/templates/skills/squads-learn/SKILL.md +86 -0
- package/dist/templates/skills/squads-workflow/instruction.md +70 -0
- package/dist/terminal-FBQFQTKZ.js +55 -0
- package/dist/terminal-FBQFQTKZ.js.map +1 -0
- package/dist/tier-detect-YX2HPNNR.js +15 -0
- package/dist/tier-detect-YX2HPNNR.js.map +1 -0
- package/dist/update-D7CGIZ3M.js +18 -0
- package/dist/update-D7CGIZ3M.js.map +1 -0
- package/dist/update-STU276HR.js +83 -0
- package/dist/update-STU276HR.js.map +1 -0
- package/package.json +31 -13
- package/templates/core/AGENTS.md.template +51 -0
- package/templates/core/BUSINESS_BRIEF.md.template +29 -0
- package/templates/core/CLAUDE.md.template +48 -0
- package/templates/core/provider.yaml.template +5 -0
- package/templates/first-squad/SQUAD.md.template +23 -0
- package/templates/first-squad/lead.md.template +44 -0
- package/templates/memory/getting-started/state.md.template +19 -0
- package/templates/seed/BUSINESS_BRIEF.md.template +27 -0
- package/templates/seed/CLAUDE.md.template +119 -0
- package/templates/seed/README.md.template +42 -0
- package/templates/seed/config/SYSTEM.md +58 -0
- package/templates/seed/config/provider.yaml +4 -0
- package/templates/seed/hooks/settings.json.template +31 -0
- package/templates/seed/idp/catalog/service.yaml.template +25 -0
- package/templates/seed/memory/_squad/goals.md +23 -0
- package/templates/seed/memory/_squad/priorities.md +25 -0
- package/templates/seed/memory/company/company.md +31 -0
- package/templates/seed/memory/company/directives.md +37 -0
- package/templates/seed/memory/company/manager/state.md +16 -0
- package/templates/seed/memory/engineering/issue-solver/state.md +12 -0
- package/templates/seed/memory/intelligence/intel-lead/state.md +9 -0
- package/templates/seed/memory/marketing/content-drafter/state.md +12 -0
- package/templates/seed/memory/operations/ops-lead/state.md +12 -0
- package/templates/seed/memory/product/lead/state.md +14 -0
- package/templates/seed/memory/research/lead/state.md +14 -0
- package/templates/seed/skills/gh/SKILL.md +57 -0
- package/templates/seed/skills/squads-cli/SKILL.md +329 -0
- package/templates/seed/skills/squads-cli/references/commands.md +181 -0
- package/templates/seed/squads/company/SQUAD.md +51 -0
- package/templates/seed/squads/company/company-critic.md +57 -0
- package/templates/seed/squads/company/company-eval.md +57 -0
- package/templates/seed/squads/company/event-dispatcher.md +53 -0
- package/templates/seed/squads/company/goal-tracker.md +51 -0
- package/templates/seed/squads/company/manager.md +60 -0
- package/templates/seed/squads/engineering/SQUAD.md +48 -0
- package/templates/seed/squads/engineering/code-reviewer.md +69 -0
- package/templates/seed/squads/engineering/issue-solver.md +66 -0
- package/templates/seed/squads/engineering/test-writer.md +60 -0
- package/templates/seed/squads/intelligence/SQUAD.md +38 -0
- package/templates/seed/squads/intelligence/intel-critic.md +53 -0
- package/templates/seed/squads/intelligence/intel-eval.md +48 -0
- package/templates/seed/squads/intelligence/intel-lead.md +79 -0
- package/templates/seed/squads/marketing/SQUAD.md +47 -0
- package/templates/seed/squads/marketing/content-drafter.md +81 -0
- package/templates/seed/squads/marketing/growth-analyst.md +61 -0
- package/templates/seed/squads/marketing/social-poster.md +56 -0
- package/templates/seed/squads/operations/SQUAD.md +45 -0
- package/templates/seed/squads/operations/finance-tracker.md +55 -0
- package/templates/seed/squads/operations/goal-tracker.md +60 -0
- package/templates/seed/squads/operations/ops-lead.md +68 -0
- package/templates/seed/squads/product/SQUAD.md +41 -0
- package/templates/seed/squads/product/lead.md +64 -0
- package/templates/seed/squads/product/scanner.md +58 -0
- package/templates/seed/squads/product/worker.md +63 -0
- package/templates/seed/squads/research/SQUAD.md +38 -0
- package/templates/seed/squads/research/analyst.md +58 -0
- package/templates/seed/squads/research/lead.md +58 -0
- package/templates/seed/squads/research/synthesizer.md +67 -0
- package/templates/skills/squads-learn/SKILL.md +86 -0
- package/templates/skills/squads-workflow/instruction.md +70 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
appendToMemory,
|
|
4
|
+
appendToMemorySync,
|
|
5
|
+
findMemoryDir,
|
|
6
|
+
getSquadState,
|
|
7
|
+
listMemoryEntries,
|
|
8
|
+
searchMemory,
|
|
9
|
+
updateMemory,
|
|
10
|
+
updateMemorySync
|
|
11
|
+
} from "./chunk-ZTQ7ISUR.js";
|
|
12
|
+
import "./chunk-7OCVIDC7.js";
|
|
13
|
+
export {
|
|
14
|
+
appendToMemory,
|
|
15
|
+
appendToMemorySync,
|
|
16
|
+
findMemoryDir,
|
|
17
|
+
getSquadState,
|
|
18
|
+
listMemoryEntries,
|
|
19
|
+
searchMemory,
|
|
20
|
+
updateMemory,
|
|
21
|
+
updateMemorySync
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=memory-VNF2VFRB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
calculateCostSummary,
|
|
4
|
+
captureSessionUsage,
|
|
5
|
+
diffGoals,
|
|
6
|
+
logObservability,
|
|
7
|
+
queryExecutions,
|
|
8
|
+
snapshotGoals
|
|
9
|
+
} from "./chunk-NP5BDPE6.js";
|
|
10
|
+
import "./chunk-TYFTF53O.js";
|
|
11
|
+
import "./chunk-7OCVIDC7.js";
|
|
12
|
+
export {
|
|
13
|
+
calculateCostSummary,
|
|
14
|
+
captureSessionUsage,
|
|
15
|
+
diffGoals,
|
|
16
|
+
logObservability,
|
|
17
|
+
queryExecutions,
|
|
18
|
+
snapshotGoals
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=observability-CL23L7LD.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
RESET,
|
|
4
|
+
bold,
|
|
5
|
+
colors,
|
|
6
|
+
writeLine
|
|
7
|
+
} from "./chunk-M5FXNY6Y.js";
|
|
8
|
+
import {
|
|
9
|
+
findMemoryDir
|
|
10
|
+
} from "./chunk-ZTQ7ISUR.js";
|
|
11
|
+
import {
|
|
12
|
+
findSquadsDir,
|
|
13
|
+
loadSquad
|
|
14
|
+
} from "./chunk-TYFTF53O.js";
|
|
15
|
+
import "./chunk-7OCVIDC7.js";
|
|
16
|
+
|
|
17
|
+
// src/lib/org-cycle.ts
|
|
18
|
+
import { existsSync, readFileSync, readdirSync, statSync } from "fs";
|
|
19
|
+
import { join } from "path";
|
|
20
|
+
function scanOrg() {
|
|
21
|
+
const squadsDir = findSquadsDir();
|
|
22
|
+
const memoryDir = findMemoryDir();
|
|
23
|
+
if (!squadsDir || !memoryDir) return [];
|
|
24
|
+
const results = [];
|
|
25
|
+
const now = Date.now();
|
|
26
|
+
for (const squadName of readdirSync(squadsDir).sort()) {
|
|
27
|
+
const squadPath = join(squadsDir, squadName);
|
|
28
|
+
if (!statSync(squadPath).isDirectory()) continue;
|
|
29
|
+
if (!existsSync(join(squadPath, "SQUAD.md"))) continue;
|
|
30
|
+
const squad = loadSquad(squadName);
|
|
31
|
+
const result = {
|
|
32
|
+
squad: squadName,
|
|
33
|
+
status: "healthy",
|
|
34
|
+
prioritiesAge: 999,
|
|
35
|
+
goalsActive: 0,
|
|
36
|
+
lastExecution: null,
|
|
37
|
+
lead: null,
|
|
38
|
+
repo: squad?.repo || null,
|
|
39
|
+
reason: ""
|
|
40
|
+
};
|
|
41
|
+
for (const file of readdirSync(squadPath)) {
|
|
42
|
+
if (file.endsWith("-lead.md") || file === "coo.md" || file.startsWith("web-lead") || file.startsWith("intel-lead") || file.startsWith("eng-lead")) {
|
|
43
|
+
result.lead = file.replace(".md", "");
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const prioritiesPath = join(memoryDir, squadName, "priorities.md");
|
|
48
|
+
if (existsSync(prioritiesPath)) {
|
|
49
|
+
const content = readFileSync(prioritiesPath, "utf-8");
|
|
50
|
+
if (content.includes("frozen")) {
|
|
51
|
+
result.status = "frozen";
|
|
52
|
+
result.reason = "Squad frozen \u2014 no work until trigger";
|
|
53
|
+
results.push(result);
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
const updatedMatch = content.match(/updated:\s*"?(\d{4}-\d{2}-\d{2})"?/);
|
|
57
|
+
if (updatedMatch) {
|
|
58
|
+
const updated = new Date(updatedMatch[1]).getTime();
|
|
59
|
+
result.prioritiesAge = Math.round((now - updated) / (24 * 60 * 60 * 1e3));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const goalsPath = join(memoryDir, squadName, "goals.md");
|
|
63
|
+
if (existsSync(goalsPath)) {
|
|
64
|
+
const content = readFileSync(goalsPath, "utf-8");
|
|
65
|
+
const activeMatches = content.match(/status: (in-progress|not-started)/g);
|
|
66
|
+
result.goalsActive = activeMatches?.length || 0;
|
|
67
|
+
}
|
|
68
|
+
if (result.prioritiesAge > 14) {
|
|
69
|
+
result.status = "stale";
|
|
70
|
+
result.reason = `Priorities ${result.prioritiesAge}d old`;
|
|
71
|
+
} else if (result.goalsActive === 0) {
|
|
72
|
+
result.status = "stale";
|
|
73
|
+
result.reason = "No active goals";
|
|
74
|
+
} else {
|
|
75
|
+
result.reason = `${result.goalsActive} active goals, priorities ${result.prioritiesAge}d old`;
|
|
76
|
+
}
|
|
77
|
+
results.push(result);
|
|
78
|
+
}
|
|
79
|
+
return results;
|
|
80
|
+
}
|
|
81
|
+
function planOrgCycle(scan) {
|
|
82
|
+
return scan.filter((s) => s.status !== "frozen").filter((s) => s.lead !== null).sort((a, b) => {
|
|
83
|
+
if (a.status === "stale" && b.status !== "stale") return -1;
|
|
84
|
+
if (b.status === "stale" && a.status !== "stale") return 1;
|
|
85
|
+
return b.goalsActive - a.goalsActive;
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
function displayOrgScan(scan) {
|
|
89
|
+
writeLine();
|
|
90
|
+
writeLine(` ${bold}Org Scan${RESET} (${scan.length} squads)
|
|
91
|
+
`);
|
|
92
|
+
const frozen = scan.filter((s) => s.status === "frozen");
|
|
93
|
+
const stale = scan.filter((s) => s.status === "stale");
|
|
94
|
+
const healthy = scan.filter((s) => s.status === "healthy");
|
|
95
|
+
if (healthy.length > 0) {
|
|
96
|
+
writeLine(` ${colors.green}Healthy (${healthy.length})${RESET}`);
|
|
97
|
+
for (const s of healthy) {
|
|
98
|
+
writeLine(` ${s.squad.padEnd(22)} ${colors.dim}${s.reason}${RESET}`);
|
|
99
|
+
}
|
|
100
|
+
writeLine();
|
|
101
|
+
}
|
|
102
|
+
if (stale.length > 0) {
|
|
103
|
+
writeLine(` ${colors.yellow}Stale (${stale.length})${RESET}`);
|
|
104
|
+
for (const s of stale) {
|
|
105
|
+
writeLine(` ${s.squad.padEnd(22)} ${colors.yellow}${s.reason}${RESET}`);
|
|
106
|
+
}
|
|
107
|
+
writeLine();
|
|
108
|
+
}
|
|
109
|
+
if (frozen.length > 0) {
|
|
110
|
+
writeLine(` ${colors.dim}Frozen (${frozen.length}): ${frozen.map((s) => s.squad).join(", ")}${RESET}`);
|
|
111
|
+
writeLine();
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
function displayPlan(plan) {
|
|
115
|
+
writeLine(` ${bold}Execution Plan${RESET} (${plan.length} squads)
|
|
116
|
+
`);
|
|
117
|
+
for (let i = 0; i < plan.length; i++) {
|
|
118
|
+
const s = plan[i];
|
|
119
|
+
const statusIcon = s.status === "stale" ? `${colors.yellow}stale${RESET}` : `${colors.green}ready${RESET}`;
|
|
120
|
+
writeLine(` ${i + 1}. ${bold}${s.squad}${RESET} \u2192 ${s.lead} ${colors.dim}(${statusIcon}, ${s.goalsActive} goals)${RESET}`);
|
|
121
|
+
}
|
|
122
|
+
writeLine();
|
|
123
|
+
}
|
|
124
|
+
export {
|
|
125
|
+
displayOrgScan,
|
|
126
|
+
displayPlan,
|
|
127
|
+
planOrgCycle,
|
|
128
|
+
scanOrg
|
|
129
|
+
};
|
|
130
|
+
//# sourceMappingURL=org-cycle-Q74OT4I4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/org-cycle.ts"],"sourcesContent":["/**\n * Org cycle — run the whole organization as a coordinated system.\n *\n * squads run --org [--dry-run]\n *\n * Steps:\n * 1. SCAN: Check all squads — priorities freshness, goal progress, scorecard grades\n * 2. PLAN: Decide what to run — skip frozen, prioritize by staleness + score\n * 3. EXECUTE: Run leads in dependency order (phased)\n * 4. EVALUATE: COO reviews all outputs\n * 5. REPORT: Org-level summary to observability\n */\n\nimport { existsSync, readFileSync, readdirSync, statSync } from 'fs';\nimport { join } from 'path';\nimport { findSquadsDir, loadSquad } from './squad-parser.js';\nimport { findMemoryDir } from './memory.js';\nimport { colors, bold, RESET, writeLine } from './terminal.js';\nimport { logObservability, type ObservabilityRecord } from './observability.js';\n\nexport interface OrgScanResult {\n squad: string;\n status: 'active' | 'frozen' | 'stale' | 'healthy';\n prioritiesAge: number; // days since last update\n goalsActive: number;\n lastExecution: string | null;\n lead: string | null;\n repo: string | null;\n reason: string;\n}\n\n/**\n * Scan all squads and return their health status.\n */\nexport function scanOrg(): OrgScanResult[] {\n const squadsDir = findSquadsDir();\n const memoryDir = findMemoryDir();\n if (!squadsDir || !memoryDir) return [];\n\n const results: OrgScanResult[] = [];\n const now = Date.now();\n\n for (const squadName of readdirSync(squadsDir).sort()) {\n const squadPath = join(squadsDir, squadName);\n if (!statSync(squadPath).isDirectory()) continue;\n if (!existsSync(join(squadPath, 'SQUAD.md'))) continue;\n\n const squad = loadSquad(squadName);\n const result: OrgScanResult = {\n squad: squadName,\n status: 'healthy',\n prioritiesAge: 999,\n goalsActive: 0,\n lastExecution: null,\n lead: null,\n repo: squad?.repo || null,\n reason: '',\n };\n\n // Find lead agent\n for (const file of readdirSync(squadPath)) {\n if (file.endsWith('-lead.md') || file === 'coo.md' || file.startsWith('web-lead') || file.startsWith('intel-lead') || file.startsWith('eng-lead')) {\n result.lead = file.replace('.md', '');\n break;\n }\n }\n\n // Check if frozen\n const prioritiesPath = join(memoryDir, squadName, 'priorities.md');\n if (existsSync(prioritiesPath)) {\n const content = readFileSync(prioritiesPath, 'utf-8');\n if (content.includes('frozen')) {\n result.status = 'frozen';\n result.reason = 'Squad frozen — no work until trigger';\n results.push(result);\n continue;\n }\n\n // Check freshness from frontmatter\n const updatedMatch = content.match(/updated:\\s*\"?(\\d{4}-\\d{2}-\\d{2})\"?/);\n if (updatedMatch) {\n const updated = new Date(updatedMatch[1]).getTime();\n result.prioritiesAge = Math.round((now - updated) / (24 * 60 * 60 * 1000));\n }\n }\n\n // Check goals\n const goalsPath = join(memoryDir, squadName, 'goals.md');\n if (existsSync(goalsPath)) {\n const content = readFileSync(goalsPath, 'utf-8');\n const activeMatches = content.match(/status: (in-progress|not-started)/g);\n result.goalsActive = activeMatches?.length || 0;\n }\n\n // Determine status\n if (result.prioritiesAge > 14) {\n result.status = 'stale';\n result.reason = `Priorities ${result.prioritiesAge}d old`;\n } else if (result.goalsActive === 0) {\n result.status = 'stale';\n result.reason = 'No active goals';\n } else {\n result.reason = `${result.goalsActive} active goals, priorities ${result.prioritiesAge}d old`;\n }\n\n results.push(result);\n }\n\n return results;\n}\n\n/**\n * Plan which squads to run based on scan results.\n * Returns squads ordered by priority (most needy first).\n */\nexport function planOrgCycle(scan: OrgScanResult[]): OrgScanResult[] {\n return scan\n .filter(s => s.status !== 'frozen') // Skip frozen\n .filter(s => s.lead !== null) // Must have a lead\n .sort((a, b) => {\n // Stale squads first\n if (a.status === 'stale' && b.status !== 'stale') return -1;\n if (b.status === 'stale' && a.status !== 'stale') return 1;\n // Then by goals count (more goals = more work to do)\n return b.goalsActive - a.goalsActive;\n });\n}\n\n/**\n * Display org scan results.\n */\nexport function displayOrgScan(scan: OrgScanResult[]): void {\n writeLine();\n writeLine(` ${bold}Org Scan${RESET} (${scan.length} squads)\\n`);\n\n const frozen = scan.filter(s => s.status === 'frozen');\n const stale = scan.filter(s => s.status === 'stale');\n const healthy = scan.filter(s => s.status === 'healthy');\n\n if (healthy.length > 0) {\n writeLine(` ${colors.green}Healthy (${healthy.length})${RESET}`);\n for (const s of healthy) {\n writeLine(` ${s.squad.padEnd(22)} ${colors.dim}${s.reason}${RESET}`);\n }\n writeLine();\n }\n\n if (stale.length > 0) {\n writeLine(` ${colors.yellow}Stale (${stale.length})${RESET}`);\n for (const s of stale) {\n writeLine(` ${s.squad.padEnd(22)} ${colors.yellow}${s.reason}${RESET}`);\n }\n writeLine();\n }\n\n if (frozen.length > 0) {\n writeLine(` ${colors.dim}Frozen (${frozen.length}): ${frozen.map(s => s.squad).join(', ')}${RESET}`);\n writeLine();\n }\n}\n\n/**\n * Display execution plan.\n */\nexport function displayPlan(plan: OrgScanResult[]): void {\n writeLine(` ${bold}Execution Plan${RESET} (${plan.length} squads)\\n`);\n for (let i = 0; i < plan.length; i++) {\n const s = plan[i];\n const statusIcon = s.status === 'stale' ? `${colors.yellow}stale${RESET}` : `${colors.green}ready${RESET}`;\n writeLine(` ${i + 1}. ${bold}${s.squad}${RESET} → ${s.lead} ${colors.dim}(${statusIcon}, ${s.goalsActive} goals)${RESET}`);\n }\n writeLine();\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
RESET,
|
|
4
|
+
bold,
|
|
5
|
+
box,
|
|
6
|
+
colors,
|
|
7
|
+
gradient,
|
|
8
|
+
icons,
|
|
9
|
+
padEnd,
|
|
10
|
+
truncate,
|
|
11
|
+
writeLine
|
|
12
|
+
} from "./chunk-M5FXNY6Y.js";
|
|
13
|
+
import {
|
|
14
|
+
findMemoryDir
|
|
15
|
+
} from "./chunk-ZTQ7ISUR.js";
|
|
16
|
+
import "./chunk-TYFTF53O.js";
|
|
17
|
+
import "./chunk-7OCVIDC7.js";
|
|
18
|
+
|
|
19
|
+
// src/commands/progress.ts
|
|
20
|
+
import { execSync } from "child_process";
|
|
21
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
|
|
22
|
+
import { join } from "path";
|
|
23
|
+
function getTasksFilePath() {
|
|
24
|
+
const memoryDir = findMemoryDir();
|
|
25
|
+
if (!memoryDir) {
|
|
26
|
+
const cwd = process.cwd();
|
|
27
|
+
const agentsDir = join(cwd, ".agents");
|
|
28
|
+
if (!existsSync(agentsDir)) {
|
|
29
|
+
mkdirSync(agentsDir, { recursive: true });
|
|
30
|
+
}
|
|
31
|
+
return join(agentsDir, "tasks.json");
|
|
32
|
+
}
|
|
33
|
+
return join(memoryDir, "..", "tasks.json");
|
|
34
|
+
}
|
|
35
|
+
function loadTasks() {
|
|
36
|
+
const tasksPath = getTasksFilePath();
|
|
37
|
+
if (existsSync(tasksPath)) {
|
|
38
|
+
try {
|
|
39
|
+
return JSON.parse(readFileSync(tasksPath, "utf-8"));
|
|
40
|
+
} catch {
|
|
41
|
+
return { tasks: [], lastUpdated: (/* @__PURE__ */ new Date()).toISOString() };
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return { tasks: [], lastUpdated: (/* @__PURE__ */ new Date()).toISOString() };
|
|
45
|
+
}
|
|
46
|
+
function saveTasks(data) {
|
|
47
|
+
const tasksPath = getTasksFilePath();
|
|
48
|
+
data.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
|
|
49
|
+
writeFileSync(tasksPath, JSON.stringify(data, null, 2));
|
|
50
|
+
}
|
|
51
|
+
function getRecentActivity() {
|
|
52
|
+
const activity = [];
|
|
53
|
+
const squadKeywords = {
|
|
54
|
+
website: ["website", "web", "homepage", "astro", "page"],
|
|
55
|
+
product: ["cli", "squads-cli", "command"],
|
|
56
|
+
research: ["research", "report", "analysis"],
|
|
57
|
+
engineering: ["infra", "engineering", "build"],
|
|
58
|
+
intelligence: ["intel", "monitor", "competitor"],
|
|
59
|
+
customer: ["lead", "customer", "outreach"],
|
|
60
|
+
finance: ["cost", "finance", "budget"],
|
|
61
|
+
company: ["company", "strategy", "mission"],
|
|
62
|
+
marketing: ["marketing", "content", "social"]
|
|
63
|
+
};
|
|
64
|
+
try {
|
|
65
|
+
const logOutput = execSync(
|
|
66
|
+
'git log --since="24 hours ago" --format="%h|%aI|%s" 2>/dev/null',
|
|
67
|
+
{ encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
68
|
+
).trim();
|
|
69
|
+
if (!logOutput) return activity;
|
|
70
|
+
for (const line of logOutput.split("\n")) {
|
|
71
|
+
const [hash, date, ...msgParts] = line.split("|");
|
|
72
|
+
const message = msgParts.join("|");
|
|
73
|
+
if (!hash || !message) continue;
|
|
74
|
+
const msgLower = message.toLowerCase();
|
|
75
|
+
let detectedSquad = "unknown";
|
|
76
|
+
for (const [squad, keywords] of Object.entries(squadKeywords)) {
|
|
77
|
+
if (keywords.some((k) => msgLower.includes(k))) {
|
|
78
|
+
detectedSquad = squad;
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
activity.push({
|
|
83
|
+
squad: detectedSquad,
|
|
84
|
+
message,
|
|
85
|
+
hash,
|
|
86
|
+
date: date.split("T")[0]
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
} catch {
|
|
90
|
+
}
|
|
91
|
+
return activity;
|
|
92
|
+
}
|
|
93
|
+
async function progressCommand(options = {}) {
|
|
94
|
+
writeLine();
|
|
95
|
+
writeLine(` ${gradient("squads")} ${colors.dim}progress${RESET}`);
|
|
96
|
+
writeLine();
|
|
97
|
+
const tasksData = loadTasks();
|
|
98
|
+
const recentActivity = getRecentActivity();
|
|
99
|
+
const activeTasks = tasksData.tasks.filter((t) => t.status === "active");
|
|
100
|
+
const completedToday = tasksData.tasks.filter(
|
|
101
|
+
(t) => t.status === "completed" && t.completedAt?.startsWith((/* @__PURE__ */ new Date()).toISOString().split("T")[0])
|
|
102
|
+
);
|
|
103
|
+
const stats = [
|
|
104
|
+
`${colors.cyan}${activeTasks.length}${RESET} active`,
|
|
105
|
+
`${colors.green}${completedToday.length}${RESET} done today`,
|
|
106
|
+
`${colors.purple}${recentActivity.length}${RESET} commits (24h)`
|
|
107
|
+
].join(` ${colors.dim}\u2502${RESET} `);
|
|
108
|
+
writeLine(` ${stats}`);
|
|
109
|
+
writeLine();
|
|
110
|
+
if (activeTasks.length > 0) {
|
|
111
|
+
writeLine(` ${bold}Active Tasks${RESET}`);
|
|
112
|
+
writeLine();
|
|
113
|
+
for (const task of activeTasks) {
|
|
114
|
+
const elapsed = getElapsedTime(task.startedAt);
|
|
115
|
+
writeLine(` ${icons.progress} ${colors.cyan}${task.squad}${RESET} ${truncate(task.description, 45)}`);
|
|
116
|
+
writeLine(` ${colors.dim}started ${elapsed} ago${RESET}`);
|
|
117
|
+
}
|
|
118
|
+
writeLine();
|
|
119
|
+
} else {
|
|
120
|
+
writeLine(` ${colors.dim}No active tasks${RESET}`);
|
|
121
|
+
writeLine();
|
|
122
|
+
}
|
|
123
|
+
if (recentActivity.length > 0) {
|
|
124
|
+
writeLine(` ${bold}Recent Activity${RESET} ${colors.dim}(last 24h)${RESET}`);
|
|
125
|
+
writeLine();
|
|
126
|
+
const w = { squad: 12, message: 50 };
|
|
127
|
+
const tableWidth = w.squad + w.message + 4;
|
|
128
|
+
writeLine(` ${colors.purple}${box.topLeft}${colors.dim}${box.horizontal.repeat(tableWidth)}${colors.purple}${box.topRight}${RESET}`);
|
|
129
|
+
writeLine(` ${colors.purple}${box.vertical}${RESET} ${bold}${padEnd("SQUAD", w.squad)}${RESET}${bold}COMMIT${RESET}${" ".repeat(w.message - 6)} ${colors.purple}${box.vertical}${RESET}`);
|
|
130
|
+
writeLine(` ${colors.purple}${box.teeRight}${colors.dim}${box.horizontal.repeat(tableWidth)}${colors.purple}${box.teeLeft}${RESET}`);
|
|
131
|
+
const maxRows = options.verbose ? 15 : 8;
|
|
132
|
+
for (const act of recentActivity.slice(0, maxRows)) {
|
|
133
|
+
const squadColor = act.squad === "unknown" ? colors.dim : colors.cyan;
|
|
134
|
+
const row = ` ${colors.purple}${box.vertical}${RESET} ${squadColor}${padEnd(act.squad, w.squad)}${RESET}${truncate(act.message, w.message - 2)} ${colors.purple}${box.vertical}${RESET}`;
|
|
135
|
+
writeLine(row);
|
|
136
|
+
}
|
|
137
|
+
writeLine(` ${colors.purple}${box.bottomLeft}${colors.dim}${box.horizontal.repeat(tableWidth)}${colors.purple}${box.bottomRight}${RESET}`);
|
|
138
|
+
if (recentActivity.length > maxRows) {
|
|
139
|
+
writeLine(` ${colors.dim}+${recentActivity.length - maxRows} more commits${RESET}`);
|
|
140
|
+
}
|
|
141
|
+
writeLine();
|
|
142
|
+
}
|
|
143
|
+
if (completedToday.length > 0) {
|
|
144
|
+
writeLine(` ${bold}Completed Today${RESET}`);
|
|
145
|
+
writeLine();
|
|
146
|
+
for (const task of completedToday.slice(0, 5)) {
|
|
147
|
+
writeLine(` ${icons.success} ${colors.cyan}${task.squad}${RESET} ${truncate(task.description, 50)}`);
|
|
148
|
+
}
|
|
149
|
+
if (completedToday.length > 5) {
|
|
150
|
+
writeLine(` ${colors.dim}+${completedToday.length - 5} more${RESET}`);
|
|
151
|
+
}
|
|
152
|
+
writeLine();
|
|
153
|
+
}
|
|
154
|
+
writeLine(` ${colors.dim}$${RESET} squads results ${colors.dim}KPI goals vs actuals${RESET}`);
|
|
155
|
+
writeLine(` ${colors.dim}$${RESET} squads dash ${colors.dim}Full dashboard${RESET}`);
|
|
156
|
+
writeLine();
|
|
157
|
+
}
|
|
158
|
+
async function progressStartCommand(squad, description) {
|
|
159
|
+
const tasksData = loadTasks();
|
|
160
|
+
const id = Math.random().toString(36).substring(2, 9);
|
|
161
|
+
tasksData.tasks.push({
|
|
162
|
+
id,
|
|
163
|
+
squad,
|
|
164
|
+
description,
|
|
165
|
+
status: "active",
|
|
166
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
167
|
+
});
|
|
168
|
+
saveTasks(tasksData);
|
|
169
|
+
writeLine(` ${icons.active} Task ${colors.cyan}${id}${RESET} started for ${colors.purple}${squad}${RESET}`);
|
|
170
|
+
}
|
|
171
|
+
async function progressCompleteCommand(taskId, options = {}) {
|
|
172
|
+
const tasksData = loadTasks();
|
|
173
|
+
const task = tasksData.tasks.find((t) => t.id === taskId);
|
|
174
|
+
if (!task) {
|
|
175
|
+
writeLine(` ${icons.error} Task ${colors.red}${taskId}${RESET} not found`);
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
task.status = options.failed ? "failed" : "completed";
|
|
179
|
+
task.completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
180
|
+
saveTasks(tasksData);
|
|
181
|
+
const icon = options.failed ? icons.error : icons.success;
|
|
182
|
+
const status = options.failed ? "failed" : "completed";
|
|
183
|
+
writeLine(` ${icon} Task ${colors.cyan}${taskId}${RESET} ${status}`);
|
|
184
|
+
}
|
|
185
|
+
function getElapsedTime(startTime) {
|
|
186
|
+
const start = new Date(startTime).getTime();
|
|
187
|
+
const now = Date.now();
|
|
188
|
+
const diffMs = now - start;
|
|
189
|
+
const minutes = Math.floor(diffMs / 6e4);
|
|
190
|
+
const hours = Math.floor(minutes / 60);
|
|
191
|
+
const days = Math.floor(hours / 24);
|
|
192
|
+
if (days > 0) return `${days}d`;
|
|
193
|
+
if (hours > 0) return `${hours}h`;
|
|
194
|
+
if (minutes > 0) return `${minutes}m`;
|
|
195
|
+
return "<1m";
|
|
196
|
+
}
|
|
197
|
+
export {
|
|
198
|
+
progressCommand,
|
|
199
|
+
progressCompleteCommand,
|
|
200
|
+
progressStartCommand
|
|
201
|
+
};
|
|
202
|
+
//# sourceMappingURL=progress-P2EIZBKP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/progress.ts"],"sourcesContent":["import { execSync } from 'child_process';\nimport { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';\nimport { join } from 'path';\nimport '../lib/squad-parser.js';\nimport { findMemoryDir } from '../lib/memory.js';\nimport {\n colors,\n bold,\n RESET,\n gradient,\n box,\n padEnd,\n truncate,\n icons,\n writeLine,\n} from '../lib/terminal.js';\n\ninterface TaskEntry {\n id: string;\n squad: string;\n description: string;\n status: 'active' | 'completed' | 'failed';\n startedAt: string;\n completedAt?: string;\n commits?: string[];\n}\n\ninterface TasksFile {\n tasks: TaskEntry[];\n lastUpdated: string;\n}\n\nfunction getTasksFilePath(): string {\n const memoryDir = findMemoryDir();\n if (!memoryDir) {\n const cwd = process.cwd();\n const agentsDir = join(cwd, '.agents');\n if (!existsSync(agentsDir)) {\n mkdirSync(agentsDir, { recursive: true });\n }\n return join(agentsDir, 'tasks.json');\n }\n return join(memoryDir, '..', 'tasks.json');\n}\n\nfunction loadTasks(): TasksFile {\n const tasksPath = getTasksFilePath();\n if (existsSync(tasksPath)) {\n try {\n return JSON.parse(readFileSync(tasksPath, 'utf-8'));\n } catch {\n return { tasks: [], lastUpdated: new Date().toISOString() };\n }\n }\n return { tasks: [], lastUpdated: new Date().toISOString() };\n}\n\nfunction saveTasks(data: TasksFile): void {\n const tasksPath = getTasksFilePath();\n data.lastUpdated = new Date().toISOString();\n writeFileSync(tasksPath, JSON.stringify(data, null, 2));\n}\n\n// Get recent commits to infer activity\nfunction getRecentActivity(): { squad: string; message: string; hash: string; date: string }[] {\n const activity: { squad: string; message: string; hash: string; date: string }[] = [];\n\n const squadKeywords: Record<string, string[]> = {\n website: ['website', 'web', 'homepage', 'astro', 'page'],\n product: ['cli', 'squads-cli', 'command'],\n research: ['research', 'report', 'analysis'],\n engineering: ['infra', 'engineering', 'build'],\n intelligence: ['intel', 'monitor', 'competitor'],\n customer: ['lead', 'customer', 'outreach'],\n finance: ['cost', 'finance', 'budget'],\n company: ['company', 'strategy', 'mission'],\n marketing: ['marketing', 'content', 'social'],\n };\n\n try {\n const logOutput = execSync(\n 'git log --since=\"24 hours ago\" --format=\"%h|%aI|%s\" 2>/dev/null',\n { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] }\n ).trim();\n\n if (!logOutput) return activity;\n\n for (const line of logOutput.split('\\n')) {\n const [hash, date, ...msgParts] = line.split('|');\n const message = msgParts.join('|');\n if (!hash || !message) continue;\n\n // Detect squad from commit message\n const msgLower = message.toLowerCase();\n let detectedSquad = 'unknown';\n\n for (const [squad, keywords] of Object.entries(squadKeywords)) {\n if (keywords.some(k => msgLower.includes(k))) {\n detectedSquad = squad;\n break;\n }\n }\n\n activity.push({\n squad: detectedSquad,\n message,\n hash,\n date: date.split('T')[0],\n });\n }\n } catch {\n // Not in git repo\n }\n\n return activity;\n}\n\nexport async function progressCommand(options: { verbose?: boolean } = {}): Promise<void> {\n writeLine();\n writeLine(` ${gradient('squads')} ${colors.dim}progress${RESET}`);\n writeLine();\n\n const tasksData = loadTasks();\n const recentActivity = getRecentActivity();\n\n // Active tasks\n const activeTasks = tasksData.tasks.filter(t => t.status === 'active');\n const completedToday = tasksData.tasks.filter(t =>\n t.status === 'completed' &&\n t.completedAt?.startsWith(new Date().toISOString().split('T')[0])\n );\n\n // Stats row\n const stats = [\n `${colors.cyan}${activeTasks.length}${RESET} active`,\n `${colors.green}${completedToday.length}${RESET} done today`,\n `${colors.purple}${recentActivity.length}${RESET} commits (24h)`,\n ].join(` ${colors.dim}│${RESET} `);\n writeLine(` ${stats}`);\n writeLine();\n\n // Active tasks section\n if (activeTasks.length > 0) {\n writeLine(` ${bold}Active Tasks${RESET}`);\n writeLine();\n\n for (const task of activeTasks) {\n const elapsed = getElapsedTime(task.startedAt);\n writeLine(` ${icons.progress} ${colors.cyan}${task.squad}${RESET} ${truncate(task.description, 45)}`);\n writeLine(` ${colors.dim}started ${elapsed} ago${RESET}`);\n }\n writeLine();\n } else {\n writeLine(` ${colors.dim}No active tasks${RESET}`);\n writeLine();\n }\n\n // Recent activity from git\n if (recentActivity.length > 0) {\n writeLine(` ${bold}Recent Activity${RESET} ${colors.dim}(last 24h)${RESET}`);\n writeLine();\n\n const w = { squad: 12, message: 50 };\n const tableWidth = w.squad + w.message + 4;\n\n writeLine(` ${colors.purple}${box.topLeft}${colors.dim}${box.horizontal.repeat(tableWidth)}${colors.purple}${box.topRight}${RESET}`);\n writeLine(` ${colors.purple}${box.vertical}${RESET} ${bold}${padEnd('SQUAD', w.squad)}${RESET}${bold}COMMIT${RESET}${' '.repeat(w.message - 6)} ${colors.purple}${box.vertical}${RESET}`);\n writeLine(` ${colors.purple}${box.teeRight}${colors.dim}${box.horizontal.repeat(tableWidth)}${colors.purple}${box.teeLeft}${RESET}`);\n\n const maxRows = options.verbose ? 15 : 8;\n for (const act of recentActivity.slice(0, maxRows)) {\n const squadColor = act.squad === 'unknown' ? colors.dim : colors.cyan;\n const row = ` ${colors.purple}${box.vertical}${RESET} ` +\n `${squadColor}${padEnd(act.squad, w.squad)}${RESET}` +\n `${truncate(act.message, w.message - 2)}` +\n ` ${colors.purple}${box.vertical}${RESET}`;\n writeLine(row);\n }\n\n writeLine(` ${colors.purple}${box.bottomLeft}${colors.dim}${box.horizontal.repeat(tableWidth)}${colors.purple}${box.bottomRight}${RESET}`);\n\n if (recentActivity.length > maxRows) {\n writeLine(` ${colors.dim}+${recentActivity.length - maxRows} more commits${RESET}`);\n }\n writeLine();\n }\n\n // Completed today\n if (completedToday.length > 0) {\n writeLine(` ${bold}Completed Today${RESET}`);\n writeLine();\n for (const task of completedToday.slice(0, 5)) {\n writeLine(` ${icons.success} ${colors.cyan}${task.squad}${RESET} ${truncate(task.description, 50)}`);\n }\n if (completedToday.length > 5) {\n writeLine(` ${colors.dim}+${completedToday.length - 5} more${RESET}`);\n }\n writeLine();\n }\n\n // Commands\n writeLine(` ${colors.dim}$${RESET} squads results ${colors.dim}KPI goals vs actuals${RESET}`);\n writeLine(` ${colors.dim}$${RESET} squads dash ${colors.dim}Full dashboard${RESET}`);\n writeLine();\n}\n\n// Register a new task (called by agents)\nexport async function progressStartCommand(\n squad: string,\n description: string\n): Promise<void> {\n const tasksData = loadTasks();\n const id = Math.random().toString(36).substring(2, 9);\n\n tasksData.tasks.push({\n id,\n squad,\n description,\n status: 'active',\n startedAt: new Date().toISOString(),\n });\n\n saveTasks(tasksData);\n writeLine(` ${icons.active} Task ${colors.cyan}${id}${RESET} started for ${colors.purple}${squad}${RESET}`);\n}\n\n// Complete a task\nexport async function progressCompleteCommand(\n taskId: string,\n options: { failed?: boolean } = {}\n): Promise<void> {\n const tasksData = loadTasks();\n const task = tasksData.tasks.find(t => t.id === taskId);\n\n if (!task) {\n writeLine(` ${icons.error} Task ${colors.red}${taskId}${RESET} not found`);\n return;\n }\n\n task.status = options.failed ? 'failed' : 'completed';\n task.completedAt = new Date().toISOString();\n\n saveTasks(tasksData);\n\n const icon = options.failed ? icons.error : icons.success;\n const status = options.failed ? 'failed' : 'completed';\n writeLine(` ${icon} Task ${colors.cyan}${taskId}${RESET} ${status}`);\n}\n\nfunction getElapsedTime(startTime: string): string {\n const start = new Date(startTime).getTime();\n const now = Date.now();\n const diffMs = now - start;\n\n const minutes = Math.floor(diffMs / 60000);\n const hours = Math.floor(minutes / 60);\n const days = Math.floor(hours / 24);\n\n if (days > 0) return `${days}d`;\n if (hours > 0) return `${hours}h`;\n if (minutes > 0) return `${minutes}m`;\n return '<1m';\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
getAllCLIStatus
|
|
4
|
+
} from "./chunk-QRNR4GIT.js";
|
|
5
|
+
import {
|
|
6
|
+
Events,
|
|
7
|
+
track
|
|
8
|
+
} from "./chunk-QJ7C7CMB.js";
|
|
9
|
+
import {
|
|
10
|
+
RESET,
|
|
11
|
+
colors,
|
|
12
|
+
gradient,
|
|
13
|
+
icons,
|
|
14
|
+
writeLine
|
|
15
|
+
} from "./chunk-M5FXNY6Y.js";
|
|
16
|
+
import "./chunk-7OCVIDC7.js";
|
|
17
|
+
|
|
18
|
+
// src/commands/providers.ts
|
|
19
|
+
async function providersCommand(options = {}) {
|
|
20
|
+
const statuses = getAllCLIStatus();
|
|
21
|
+
await track(Events.CLI_PROVIDERS, {
|
|
22
|
+
available: statuses.filter((s) => s.available).length,
|
|
23
|
+
total: statuses.length
|
|
24
|
+
});
|
|
25
|
+
if (options.json) {
|
|
26
|
+
console.log(JSON.stringify(statuses, null, 2));
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
writeLine();
|
|
30
|
+
writeLine(` ${gradient("squads")} ${colors.dim}providers${RESET}`);
|
|
31
|
+
writeLine();
|
|
32
|
+
writeLine(` ${colors.dim}Provider CLI Status${RESET}`);
|
|
33
|
+
writeLine(` ${colors.dim}${"\u2500".repeat(40)}${RESET}`);
|
|
34
|
+
const ready = [];
|
|
35
|
+
const missing = [];
|
|
36
|
+
for (const status of statuses) {
|
|
37
|
+
const statusText = status.available ? `${colors.green}${icons.success} ready${RESET}` : `${colors.red}${icons.error} not installed${RESET}`;
|
|
38
|
+
const providerCol = status.displayName.padEnd(12);
|
|
39
|
+
const commandCol = status.command.padEnd(9);
|
|
40
|
+
writeLine(` ${colors.cyan}${providerCol}${RESET} ${commandCol} ${statusText}`);
|
|
41
|
+
if (status.available) {
|
|
42
|
+
ready.push(status);
|
|
43
|
+
} else {
|
|
44
|
+
missing.push(status);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
writeLine();
|
|
48
|
+
if (ready.length === statuses.length) {
|
|
49
|
+
writeLine(` ${colors.green}${icons.success}${RESET} All providers ready`);
|
|
50
|
+
} else {
|
|
51
|
+
writeLine(` ${colors.dim}${ready.length}/${statuses.length} providers available${RESET}`);
|
|
52
|
+
}
|
|
53
|
+
if (missing.length > 0) {
|
|
54
|
+
writeLine();
|
|
55
|
+
writeLine(` ${colors.dim}Install missing:${RESET}`);
|
|
56
|
+
for (const status of missing) {
|
|
57
|
+
writeLine(` ${colors.dim}$${RESET} ${status.install}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
writeLine();
|
|
61
|
+
}
|
|
62
|
+
export {
|
|
63
|
+
providersCommand
|
|
64
|
+
};
|
|
65
|
+
//# sourceMappingURL=providers-LE744DM6.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/providers.ts"],"sourcesContent":["/**\n * squads providers - Show available LLM CLI providers\n *\n * Lists all supported LLM CLIs and their availability status.\n * Provides install instructions for missing CLIs.\n *\n * @see specs/multi-llm.md\n */\n\nimport {\n colors,\n RESET,\n gradient,\n icons,\n writeLine,\n} from '../lib/terminal.js';\nimport { getAllCLIStatus, CLIStatus } from '../lib/llm-clis.js';\nimport { track, Events } from '../lib/telemetry.js';\n\nexport interface ProvidersOptions {\n json?: boolean;\n}\n\n/**\n * Show status of all LLM CLI providers\n */\nexport async function providersCommand(options: ProvidersOptions = {}): Promise<void> {\n const statuses = getAllCLIStatus();\n\n // Track telemetry\n await track(Events.CLI_PROVIDERS, {\n available: statuses.filter((s) => s.available).length,\n total: statuses.length,\n });\n\n // JSON output for programmatic use\n if (options.json) {\n console.log(JSON.stringify(statuses, null, 2));\n return;\n }\n\n // Pretty output\n writeLine();\n writeLine(` ${gradient('squads')} ${colors.dim}providers${RESET}`);\n writeLine();\n\n // Header\n writeLine(` ${colors.dim}Provider CLI Status${RESET}`);\n writeLine(` ${colors.dim}${'─'.repeat(40)}${RESET}`);\n\n // Provider rows\n const ready: CLIStatus[] = [];\n const missing: CLIStatus[] = [];\n\n for (const status of statuses) {\n const statusText = status.available\n ? `${colors.green}${icons.success} ready${RESET}`\n : `${colors.red}${icons.error} not installed${RESET}`;\n\n // Pad columns for alignment\n const providerCol = status.displayName.padEnd(12);\n const commandCol = status.command.padEnd(9);\n\n writeLine(` ${colors.cyan}${providerCol}${RESET} ${commandCol} ${statusText}`);\n\n if (status.available) {\n ready.push(status);\n } else {\n missing.push(status);\n }\n }\n\n writeLine();\n\n // Summary\n if (ready.length === statuses.length) {\n writeLine(` ${colors.green}${icons.success}${RESET} All providers ready`);\n } else {\n writeLine(` ${colors.dim}${ready.length}/${statuses.length} providers available${RESET}`);\n }\n\n // Install instructions for missing\n if (missing.length > 0) {\n writeLine();\n writeLine(` ${colors.dim}Install missing:${RESET}`);\n\n for (const status of missing) {\n writeLine(` ${colors.dim}$${RESET} ${status.install}`);\n }\n }\n\n writeLine();\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AA0BA,eAAsB,iBAAiB,UAA4B,CAAC,GAAkB;AACpF,QAAM,WAAW,gBAAgB;AAGjC,QAAM,MAAM,OAAO,eAAe;AAAA,IAChC,WAAW,SAAS,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE;AAAA,IAC/C,OAAO,SAAS;AAAA,EAClB,CAAC;AAGD,MAAI,QAAQ,MAAM;AAChB,YAAQ,IAAI,KAAK,UAAU,UAAU,MAAM,CAAC,CAAC;AAC7C;AAAA,EACF;AAGA,YAAU;AACV,YAAU,KAAK,SAAS,QAAQ,CAAC,IAAI,OAAO,GAAG,YAAY,KAAK,EAAE;AAClE,YAAU;AAGV,YAAU,KAAK,OAAO,GAAG,gCAAgC,KAAK,EAAE;AAChE,YAAU,KAAK,OAAO,GAAG,GAAG,SAAI,OAAO,EAAE,CAAC,GAAG,KAAK,EAAE;AAGpD,QAAM,QAAqB,CAAC;AAC5B,QAAM,UAAuB,CAAC;AAE9B,aAAW,UAAU,UAAU;AAC7B,UAAM,aAAa,OAAO,YACtB,GAAG,OAAO,KAAK,GAAG,MAAM,OAAO,SAAS,KAAK,KAC7C,GAAG,OAAO,GAAG,GAAG,MAAM,KAAK,iBAAiB,KAAK;AAGrD,UAAM,cAAc,OAAO,YAAY,OAAO,EAAE;AAChD,UAAM,aAAa,OAAO,QAAQ,OAAO,CAAC;AAE1C,cAAU,KAAK,OAAO,IAAI,GAAG,WAAW,GAAG,KAAK,IAAI,UAAU,IAAI,UAAU,EAAE;AAE9E,QAAI,OAAO,WAAW;AACpB,YAAM,KAAK,MAAM;AAAA,IACnB,OAAO;AACL,cAAQ,KAAK,MAAM;AAAA,IACrB;AAAA,EACF;AAEA,YAAU;AAGV,MAAI,MAAM,WAAW,SAAS,QAAQ;AACpC,cAAU,KAAK,OAAO,KAAK,GAAG,MAAM,OAAO,GAAG,KAAK,sBAAsB;AAAA,EAC3E,OAAO;AACL,cAAU,KAAK,OAAO,GAAG,GAAG,MAAM,MAAM,IAAI,SAAS,MAAM,uBAAuB,KAAK,EAAE;AAAA,EAC3F;AAGA,MAAI,QAAQ,SAAS,GAAG;AACtB,cAAU;AACV,cAAU,KAAK,OAAO,GAAG,mBAAmB,KAAK,EAAE;AAEnD,eAAW,UAAU,SAAS;AAC5B,gBAAU,OAAO,OAAO,GAAG,IAAI,KAAK,IAAI,OAAO,OAAO,EAAE;AAAA,IAC1D;AAAA,EACF;AAEA,YAAU;AACZ;","names":[]}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
RESET,
|
|
4
|
+
colors,
|
|
5
|
+
writeLine
|
|
6
|
+
} from "./chunk-M5FXNY6Y.js";
|
|
7
|
+
import {
|
|
8
|
+
findProjectRoot,
|
|
9
|
+
loadSquad
|
|
10
|
+
} from "./chunk-TYFTF53O.js";
|
|
11
|
+
import "./chunk-7OCVIDC7.js";
|
|
12
|
+
|
|
13
|
+
// src/lib/repo-enforcement.ts
|
|
14
|
+
import { existsSync, readdirSync, statSync } from "fs";
|
|
15
|
+
import { join, dirname } from "path";
|
|
16
|
+
function enforceRepoLayout(squadName, options) {
|
|
17
|
+
const result = { ok: true, warnings: [], errors: [] };
|
|
18
|
+
const projectRoot = findProjectRoot();
|
|
19
|
+
if (!projectRoot) return result;
|
|
20
|
+
const parentDir = dirname(projectRoot);
|
|
21
|
+
try {
|
|
22
|
+
const squad = loadSquad(squadName);
|
|
23
|
+
if (squad?.repo) {
|
|
24
|
+
const repoName = squad.repo.split("/").pop();
|
|
25
|
+
if (repoName) {
|
|
26
|
+
const siblingPath = join(parentDir, repoName);
|
|
27
|
+
if (!existsSync(siblingPath)) {
|
|
28
|
+
result.warnings.push(`Target repo '${squad.repo}' not found locally at ${siblingPath}`);
|
|
29
|
+
} else if (options?.verbose) {
|
|
30
|
+
writeLine(` ${colors.dim}Target repo: ${siblingPath}${RESET}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
} catch {
|
|
35
|
+
}
|
|
36
|
+
try {
|
|
37
|
+
const topLevelDirs = readdirSync(projectRoot).filter((f) => {
|
|
38
|
+
if (f.startsWith(".")) return false;
|
|
39
|
+
try {
|
|
40
|
+
return statSync(join(projectRoot, f)).isDirectory();
|
|
41
|
+
} catch {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
for (const dir of topLevelDirs) {
|
|
46
|
+
const nestedGit = join(projectRoot, dir, ".git");
|
|
47
|
+
if (existsSync(nestedGit)) {
|
|
48
|
+
result.errors.push(`Nested git repo found at ${dir}/ \u2014 this breaks 'git add'. Remove it or move to a sibling directory.`);
|
|
49
|
+
result.ok = false;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
} catch {
|
|
53
|
+
}
|
|
54
|
+
const idpGit = join(projectRoot, ".agents", "idp", ".git");
|
|
55
|
+
if (existsSync(idpGit)) {
|
|
56
|
+
result.errors.push(`Nested git repo in .agents/idp/ \u2014 remove it. IDP instance data should be part of hq, not a separate clone.`);
|
|
57
|
+
result.ok = false;
|
|
58
|
+
}
|
|
59
|
+
return result;
|
|
60
|
+
}
|
|
61
|
+
function checkAndReport(squadName, options) {
|
|
62
|
+
const result = enforceRepoLayout(squadName, options);
|
|
63
|
+
for (const warning of result.warnings) {
|
|
64
|
+
writeLine(` ${colors.yellow}warn${RESET}: ${warning}`);
|
|
65
|
+
}
|
|
66
|
+
for (const error of result.errors) {
|
|
67
|
+
writeLine(` ${colors.red}error${RESET}: ${error}`);
|
|
68
|
+
}
|
|
69
|
+
return result.ok;
|
|
70
|
+
}
|
|
71
|
+
export {
|
|
72
|
+
checkAndReport,
|
|
73
|
+
enforceRepoLayout
|
|
74
|
+
};
|
|
75
|
+
//# sourceMappingURL=repo-enforcement-JJQMKDAU.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/repo-enforcement.ts"],"sourcesContent":["/**\n * Repo enforcement — validates workspace layout before agent execution.\n *\n * Checks:\n * 1. SQUAD.md repo: field points to an existing sibling repo\n * 2. No nested .git directories inside hq (prevents clone-inside-hq)\n * 3. Agent definitions exist in hq only (not in domain repos)\n *\n * Called by agent-runner before spawning Claude Code.\n * Warns on mismatches, blocks on critical (nested .git).\n */\n\nimport { existsSync, readdirSync, statSync } from 'fs';\nimport { join, dirname, resolve } from 'path';\nimport { findProjectRoot, loadSquad } from './squad-parser.js';\nimport { colors, RESET, writeLine } from './terminal.js';\n\nexport interface EnforcementResult {\n ok: boolean;\n warnings: string[];\n errors: string[];\n}\n\n/**\n * Validate workspace layout for a squad before execution.\n */\nexport function enforceRepoLayout(squadName: string, options?: { verbose?: boolean }): EnforcementResult {\n const result: EnforcementResult = { ok: true, warnings: [], errors: [] };\n const projectRoot = findProjectRoot();\n if (!projectRoot) return result; // Can't validate without project root\n\n const parentDir = dirname(projectRoot);\n\n // 1. Check SQUAD.md repo: field points to existing sibling\n try {\n const squad = loadSquad(squadName);\n if (squad?.repo) {\n const repoName = squad.repo.split('/').pop();\n if (repoName) {\n const siblingPath = join(parentDir, repoName);\n if (!existsSync(siblingPath)) {\n result.warnings.push(`Target repo '${squad.repo}' not found locally at ${siblingPath}`);\n } else if (options?.verbose) {\n writeLine(` ${colors.dim}Target repo: ${siblingPath}${RESET}`);\n }\n }\n }\n } catch {\n // Squad not found — not our problem here\n }\n\n // 2. Check for nested .git directories inside project root\n // Only check top-level dirs (not .agents/memory/* which are fine)\n try {\n const topLevelDirs = readdirSync(projectRoot).filter(f => {\n if (f.startsWith('.')) return false; // Skip hidden dirs\n try { return statSync(join(projectRoot, f)).isDirectory(); } catch { return false; }\n });\n\n for (const dir of topLevelDirs) {\n const nestedGit = join(projectRoot, dir, '.git');\n if (existsSync(nestedGit)) {\n result.errors.push(`Nested git repo found at ${dir}/ — this breaks 'git add'. Remove it or move to a sibling directory.`);\n result.ok = false;\n }\n }\n } catch {\n // Can't read directory — skip\n }\n\n // 3. Check .agents/idp/ doesn't have a .git (the bug we hit)\n const idpGit = join(projectRoot, '.agents', 'idp', '.git');\n if (existsSync(idpGit)) {\n result.errors.push(`Nested git repo in .agents/idp/ — remove it. IDP instance data should be part of hq, not a separate clone.`);\n result.ok = false;\n }\n\n return result;\n}\n\n/**\n * Run enforcement and display results. Returns false if blocked.\n */\nexport function checkAndReport(squadName: string, options?: { verbose?: boolean }): boolean {\n const result = enforceRepoLayout(squadName, options);\n\n for (const warning of result.warnings) {\n writeLine(` ${colors.yellow}warn${RESET}: ${warning}`);\n }\n\n for (const error of result.errors) {\n writeLine(` ${colors.red}error${RESET}: ${error}`);\n }\n\n return result.ok;\n}\n"],"mappings":";;;;;;;;;;;;;AAYA,SAAS,YAAY,aAAa,gBAAgB;AAClD,SAAS,MAAM,eAAwB;AAahC,SAAS,kBAAkB,WAAmB,SAAoD;AACvG,QAAM,SAA4B,EAAE,IAAI,MAAM,UAAU,CAAC,GAAG,QAAQ,CAAC,EAAE;AACvE,QAAM,cAAc,gBAAgB;AACpC,MAAI,CAAC,YAAa,QAAO;AAEzB,QAAM,YAAY,QAAQ,WAAW;AAGrC,MAAI;AACF,UAAM,QAAQ,UAAU,SAAS;AACjC,QAAI,OAAO,MAAM;AACf,YAAM,WAAW,MAAM,KAAK,MAAM,GAAG,EAAE,IAAI;AAC3C,UAAI,UAAU;AACZ,cAAM,cAAc,KAAK,WAAW,QAAQ;AAC5C,YAAI,CAAC,WAAW,WAAW,GAAG;AAC5B,iBAAO,SAAS,KAAK,gBAAgB,MAAM,IAAI,0BAA0B,WAAW,EAAE;AAAA,QACxF,WAAW,SAAS,SAAS;AAC3B,oBAAU,KAAK,OAAO,GAAG,gBAAgB,WAAW,GAAG,KAAK,EAAE;AAAA,QAChE;AAAA,MACF;AAAA,IACF;AAAA,EACF,QAAQ;AAAA,EAER;AAIA,MAAI;AACF,UAAM,eAAe,YAAY,WAAW,EAAE,OAAO,OAAK;AACxD,UAAI,EAAE,WAAW,GAAG,EAAG,QAAO;AAC9B,UAAI;AAAE,eAAO,SAAS,KAAK,aAAa,CAAC,CAAC,EAAE,YAAY;AAAA,MAAG,QAAQ;AAAE,eAAO;AAAA,MAAO;AAAA,IACrF,CAAC;AAED,eAAW,OAAO,cAAc;AAC9B,YAAM,YAAY,KAAK,aAAa,KAAK,MAAM;AAC/C,UAAI,WAAW,SAAS,GAAG;AACzB,eAAO,OAAO,KAAK,4BAA4B,GAAG,2EAAsE;AACxH,eAAO,KAAK;AAAA,MACd;AAAA,IACF;AAAA,EACF,QAAQ;AAAA,EAER;AAGA,QAAM,SAAS,KAAK,aAAa,WAAW,OAAO,MAAM;AACzD,MAAI,WAAW,MAAM,GAAG;AACtB,WAAO,OAAO,KAAK,iHAA4G;AAC/H,WAAO,KAAK;AAAA,EACd;AAEA,SAAO;AACT;AAKO,SAAS,eAAe,WAAmB,SAA0C;AAC1F,QAAM,SAAS,kBAAkB,WAAW,OAAO;AAEnD,aAAW,WAAW,OAAO,UAAU;AACrC,cAAU,KAAK,OAAO,MAAM,OAAO,KAAK,KAAK,OAAO,EAAE;AAAA,EACxD;AAEA,aAAW,SAAS,OAAO,QAAQ;AACjC,cAAU,KAAK,OAAO,GAAG,QAAQ,KAAK,KAAK,KAAK,EAAE;AAAA,EACpD;AAEA,SAAO,OAAO;AAChB;","names":[]}
|