squadrant 0.9.2 → 0.10.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/README.md +44 -0
- package/dist/index.js +649 -193
- package/dist/index.js.map +1 -1
- package/dist/squadrantd.js +535 -51
- package/dist/squadrantd.js.map +1 -1
- package/package.json +4 -3
- package/plugin/skills/captain-ops/SKILL.md +69 -0
package/dist/index.js
CHANGED
|
@@ -155,22 +155,22 @@ function defaultCmuxConfigPath() {
|
|
|
155
155
|
return join(homedir(), ".config", "cmux", "cmux.json");
|
|
156
156
|
}
|
|
157
157
|
function ensureSocketAutomation(opts = {}) {
|
|
158
|
-
const
|
|
159
|
-
if (!existsSync(
|
|
160
|
-
mkdirSync(dirname(
|
|
161
|
-
writeFileSync(
|
|
162
|
-
return { path:
|
|
158
|
+
const path27 = opts.path ?? defaultCmuxConfigPath();
|
|
159
|
+
if (!existsSync(path27)) {
|
|
160
|
+
mkdirSync(dirname(path27), { recursive: true });
|
|
161
|
+
writeFileSync(path27, MINIMAL_TEMPLATE);
|
|
162
|
+
return { path: path27, changed: true, alreadySet: false };
|
|
163
163
|
}
|
|
164
|
-
const text = readFileSync(
|
|
164
|
+
const text = readFileSync(path27, "utf-8");
|
|
165
165
|
const current = parse(text)?.automation?.socketControlMode;
|
|
166
166
|
if (current === AUTOMATION_MODE) {
|
|
167
|
-
return { path:
|
|
167
|
+
return { path: path27, changed: false, alreadySet: true };
|
|
168
168
|
}
|
|
169
169
|
const edits = modify(text, [...SOCKET_CONTROL_MODE_PATH], AUTOMATION_MODE, {
|
|
170
170
|
formattingOptions: { insertSpaces: true, tabSize: 2 }
|
|
171
171
|
});
|
|
172
|
-
writeFileSync(
|
|
173
|
-
return { path:
|
|
172
|
+
writeFileSync(path27, applyEdits(text, edits));
|
|
173
|
+
return { path: path27, changed: true, alreadySet: false };
|
|
174
174
|
}
|
|
175
175
|
var SOCKET_CONTROL_MODE_PATH, AUTOMATION_MODE, MINIMAL_TEMPLATE;
|
|
176
176
|
var init_cmux_config = __esm({
|
|
@@ -320,15 +320,15 @@ import { dirname as dirname2, join as join4 } from "path";
|
|
|
320
320
|
function defaultStatePath() {
|
|
321
321
|
return join4(homedir3(), ".config", "squadrant", "state", "cmux-autoconfig.json");
|
|
322
322
|
}
|
|
323
|
-
function readState(
|
|
323
|
+
function readState(path27) {
|
|
324
324
|
try {
|
|
325
|
-
return JSON.parse(readFileSync4(
|
|
325
|
+
return JSON.parse(readFileSync4(path27, "utf-8"));
|
|
326
326
|
} catch {
|
|
327
327
|
return {};
|
|
328
328
|
}
|
|
329
329
|
}
|
|
330
330
|
async function ensureCmuxAutoConfig(opts = {}) {
|
|
331
|
-
const
|
|
331
|
+
const statePath2 = opts.statePath ?? defaultStatePath();
|
|
332
332
|
const ensureConfig = opts.ensureConfig ?? ensureSocketAutomation;
|
|
333
333
|
const probe = opts.probe ?? probeCmuxDaemonDirect;
|
|
334
334
|
const cfg = ensureConfig({ path: opts.configPath });
|
|
@@ -336,15 +336,15 @@ async function ensureCmuxAutoConfig(opts = {}) {
|
|
|
336
336
|
const needsRestart = verdict === "denied";
|
|
337
337
|
let promptedThisRun = false;
|
|
338
338
|
if (needsRestart) {
|
|
339
|
-
const already = readState(
|
|
339
|
+
const already = readState(statePath2).promptedRestart === true;
|
|
340
340
|
if (!already) {
|
|
341
|
-
mkdirSync2(dirname2(
|
|
342
|
-
writeFileSync3(
|
|
341
|
+
mkdirSync2(dirname2(statePath2), { recursive: true });
|
|
342
|
+
writeFileSync3(statePath2, JSON.stringify({ promptedRestart: true }));
|
|
343
343
|
promptedThisRun = true;
|
|
344
344
|
}
|
|
345
345
|
} else if (verdict === "reachable") {
|
|
346
|
-
if (existsSync4(
|
|
347
|
-
rmSync2(
|
|
346
|
+
if (existsSync4(statePath2))
|
|
347
|
+
rmSync2(statePath2, { force: true });
|
|
348
348
|
}
|
|
349
349
|
return {
|
|
350
350
|
configPath: cfg.path,
|
|
@@ -1131,10 +1131,10 @@ function daemonEntryPath() {
|
|
|
1131
1131
|
function xmlEscape(s) {
|
|
1132
1132
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
1133
1133
|
}
|
|
1134
|
-
function sanitizePathForPlist(
|
|
1134
|
+
function sanitizePathForPlist(path27) {
|
|
1135
1135
|
const seen = /* @__PURE__ */ new Set();
|
|
1136
1136
|
const stable = [];
|
|
1137
|
-
for (const p of
|
|
1137
|
+
for (const p of path27.split(":")) {
|
|
1138
1138
|
if (!p)
|
|
1139
1139
|
continue;
|
|
1140
1140
|
if (p.includes("/.claude/plugins/"))
|
|
@@ -1571,6 +1571,199 @@ var init_crew_lifecycle = __esm({
|
|
|
1571
1571
|
}
|
|
1572
1572
|
});
|
|
1573
1573
|
|
|
1574
|
+
// packages/core/dist/telegram/auth.js
|
|
1575
|
+
var init_auth = __esm({
|
|
1576
|
+
"packages/core/dist/telegram/auth.js"() {
|
|
1577
|
+
}
|
|
1578
|
+
});
|
|
1579
|
+
|
|
1580
|
+
// packages/core/dist/telegram/commands.js
|
|
1581
|
+
var init_commands = __esm({
|
|
1582
|
+
"packages/core/dist/telegram/commands.js"() {
|
|
1583
|
+
}
|
|
1584
|
+
});
|
|
1585
|
+
|
|
1586
|
+
// packages/core/dist/telegram/ensure-captain.js
|
|
1587
|
+
var init_ensure_captain = __esm({
|
|
1588
|
+
"packages/core/dist/telegram/ensure-captain.js"() {
|
|
1589
|
+
}
|
|
1590
|
+
});
|
|
1591
|
+
|
|
1592
|
+
// packages/core/dist/telegram/format.js
|
|
1593
|
+
function topicName(project) {
|
|
1594
|
+
return project;
|
|
1595
|
+
}
|
|
1596
|
+
function maskToken(token) {
|
|
1597
|
+
if (token.length <= 4)
|
|
1598
|
+
return token;
|
|
1599
|
+
return "*".repeat(token.length - 4) + token.slice(-4);
|
|
1600
|
+
}
|
|
1601
|
+
var init_format = __esm({
|
|
1602
|
+
"packages/core/dist/telegram/format.js"() {
|
|
1603
|
+
}
|
|
1604
|
+
});
|
|
1605
|
+
|
|
1606
|
+
// packages/core/dist/telegram/state.js
|
|
1607
|
+
import fs8 from "fs";
|
|
1608
|
+
import path7 from "path";
|
|
1609
|
+
function statePath(stateRoot) {
|
|
1610
|
+
return path7.join(stateRoot, "telegram-state.json");
|
|
1611
|
+
}
|
|
1612
|
+
function topicKey(project, scope = "project") {
|
|
1613
|
+
return `${project}::${scope}`;
|
|
1614
|
+
}
|
|
1615
|
+
function loadState(stateRoot) {
|
|
1616
|
+
try {
|
|
1617
|
+
const raw = fs8.readFileSync(statePath(stateRoot), "utf-8");
|
|
1618
|
+
const data = JSON.parse(raw);
|
|
1619
|
+
return {
|
|
1620
|
+
offset: typeof data.offset === "number" ? data.offset : 0,
|
|
1621
|
+
topics: data.topics ?? {}
|
|
1622
|
+
};
|
|
1623
|
+
} catch {
|
|
1624
|
+
return { offset: 0, topics: {} };
|
|
1625
|
+
}
|
|
1626
|
+
}
|
|
1627
|
+
function saveState(stateRoot, s) {
|
|
1628
|
+
fs8.mkdirSync(stateRoot, { recursive: true });
|
|
1629
|
+
fs8.writeFileSync(statePath(stateRoot), JSON.stringify(s, null, 2) + "\n");
|
|
1630
|
+
}
|
|
1631
|
+
function setTopic(stateRoot, project, topicId, scope = "project") {
|
|
1632
|
+
const s = loadState(stateRoot);
|
|
1633
|
+
s.topics[topicKey(project, scope)] = topicId;
|
|
1634
|
+
saveState(stateRoot, s);
|
|
1635
|
+
}
|
|
1636
|
+
var init_state = __esm({
|
|
1637
|
+
"packages/core/dist/telegram/state.js"() {
|
|
1638
|
+
}
|
|
1639
|
+
});
|
|
1640
|
+
|
|
1641
|
+
// packages/core/dist/telegram/client.js
|
|
1642
|
+
function createTelegramClient(opts) {
|
|
1643
|
+
const fetchImpl = opts.fetch ?? fetch;
|
|
1644
|
+
const base = `https://api.telegram.org/bot${opts.token}`;
|
|
1645
|
+
async function call(method, body) {
|
|
1646
|
+
const res = await fetchImpl(`${base}/${method}`, {
|
|
1647
|
+
method: "POST",
|
|
1648
|
+
headers: { "content-type": "application/json" },
|
|
1649
|
+
body: JSON.stringify(body)
|
|
1650
|
+
});
|
|
1651
|
+
const json = await res.json();
|
|
1652
|
+
if (!res.ok || !json.ok) {
|
|
1653
|
+
const code = json.error_code ?? res.status;
|
|
1654
|
+
const desc = json.description ?? "unknown error";
|
|
1655
|
+
throw new Error(`telegram ${method} failed (${code}): ${desc}`);
|
|
1656
|
+
}
|
|
1657
|
+
return json.result;
|
|
1658
|
+
}
|
|
1659
|
+
return {
|
|
1660
|
+
async getMe() {
|
|
1661
|
+
const r = await call("getMe", {});
|
|
1662
|
+
return { id: r.id, username: r.username };
|
|
1663
|
+
},
|
|
1664
|
+
getUpdates(offset, timeoutSec = 50) {
|
|
1665
|
+
return call("getUpdates", { offset, timeout: timeoutSec });
|
|
1666
|
+
},
|
|
1667
|
+
async sendMessage(chatId, threadId, text) {
|
|
1668
|
+
const body = { chat_id: chatId, text };
|
|
1669
|
+
if (threadId !== void 0)
|
|
1670
|
+
body.message_thread_id = threadId;
|
|
1671
|
+
await call("sendMessage", body);
|
|
1672
|
+
},
|
|
1673
|
+
async createForumTopic(chatId, name) {
|
|
1674
|
+
const r = await call("createForumTopic", { chat_id: chatId, name });
|
|
1675
|
+
return r.message_thread_id;
|
|
1676
|
+
}
|
|
1677
|
+
};
|
|
1678
|
+
}
|
|
1679
|
+
var init_client = __esm({
|
|
1680
|
+
"packages/core/dist/telegram/client.js"() {
|
|
1681
|
+
}
|
|
1682
|
+
});
|
|
1683
|
+
|
|
1684
|
+
// packages/core/dist/telegram/bridge.js
|
|
1685
|
+
var init_bridge = __esm({
|
|
1686
|
+
"packages/core/dist/telegram/bridge.js"() {
|
|
1687
|
+
init_auth();
|
|
1688
|
+
init_commands();
|
|
1689
|
+
init_format();
|
|
1690
|
+
init_state();
|
|
1691
|
+
}
|
|
1692
|
+
});
|
|
1693
|
+
|
|
1694
|
+
// packages/core/dist/telegram/setup.js
|
|
1695
|
+
import fs9 from "fs";
|
|
1696
|
+
async function detectGroupAndUser(client, opts = {}) {
|
|
1697
|
+
const timeoutMs = opts.timeoutMs ?? 6e4;
|
|
1698
|
+
const sleep2 = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
1699
|
+
const deadline = Date.now() + timeoutMs;
|
|
1700
|
+
let offset = 0;
|
|
1701
|
+
while (Date.now() < deadline) {
|
|
1702
|
+
const updates = await client.getUpdates(offset, 10);
|
|
1703
|
+
for (const u of updates) {
|
|
1704
|
+
if (u.update_id >= offset)
|
|
1705
|
+
offset = u.update_id + 1;
|
|
1706
|
+
if (u.message?.chat?.type === "supergroup") {
|
|
1707
|
+
return { supergroupId: u.message.chat.id, userId: u.message.from?.id };
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1710
|
+
await sleep2(2e3);
|
|
1711
|
+
}
|
|
1712
|
+
throw new Error("Timed out waiting for the bot to receive a message in a supergroup");
|
|
1713
|
+
}
|
|
1714
|
+
function writeTelegramConfig(configPath, opts) {
|
|
1715
|
+
let config;
|
|
1716
|
+
let raw = null;
|
|
1717
|
+
try {
|
|
1718
|
+
raw = fs9.readFileSync(configPath, "utf-8");
|
|
1719
|
+
} catch (err) {
|
|
1720
|
+
if (err.code !== "ENOENT") {
|
|
1721
|
+
throw new Error(`refusing to overwrite unreadable config at ${configPath}: ${String(err)}`);
|
|
1722
|
+
}
|
|
1723
|
+
}
|
|
1724
|
+
if (raw !== null) {
|
|
1725
|
+
try {
|
|
1726
|
+
config = JSON.parse(raw);
|
|
1727
|
+
} catch (err) {
|
|
1728
|
+
throw new Error(`refusing to overwrite corrupt config at ${configPath}: ${String(err)}`);
|
|
1729
|
+
}
|
|
1730
|
+
} else {
|
|
1731
|
+
config = {};
|
|
1732
|
+
}
|
|
1733
|
+
const prev = config.telegram && typeof config.telegram === "object" ? config.telegram : {};
|
|
1734
|
+
const next = {
|
|
1735
|
+
botToken: opts.token,
|
|
1736
|
+
supergroupId: opts.supergroupId,
|
|
1737
|
+
chats: [opts.supergroupId]
|
|
1738
|
+
};
|
|
1739
|
+
const users = opts.users ?? prev.users;
|
|
1740
|
+
const remoteControl = opts.remoteControl ?? prev.remoteControl;
|
|
1741
|
+
if (users !== void 0)
|
|
1742
|
+
next.users = users;
|
|
1743
|
+
if (remoteControl !== void 0)
|
|
1744
|
+
next.remoteControl = remoteControl;
|
|
1745
|
+
config.telegram = next;
|
|
1746
|
+
fs9.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
1747
|
+
}
|
|
1748
|
+
var init_setup = __esm({
|
|
1749
|
+
"packages/core/dist/telegram/setup.js"() {
|
|
1750
|
+
}
|
|
1751
|
+
});
|
|
1752
|
+
|
|
1753
|
+
// packages/core/dist/telegram/index.js
|
|
1754
|
+
var init_telegram = __esm({
|
|
1755
|
+
"packages/core/dist/telegram/index.js"() {
|
|
1756
|
+
init_auth();
|
|
1757
|
+
init_commands();
|
|
1758
|
+
init_ensure_captain();
|
|
1759
|
+
init_format();
|
|
1760
|
+
init_state();
|
|
1761
|
+
init_client();
|
|
1762
|
+
init_bridge();
|
|
1763
|
+
init_setup();
|
|
1764
|
+
}
|
|
1765
|
+
});
|
|
1766
|
+
|
|
1574
1767
|
// packages/core/dist/index.js
|
|
1575
1768
|
var init_dist2 = __esm({
|
|
1576
1769
|
"packages/core/dist/index.js"() {
|
|
@@ -1596,6 +1789,7 @@ var init_dist2 = __esm({
|
|
|
1596
1789
|
init_session_freshness();
|
|
1597
1790
|
init_crew_protocol();
|
|
1598
1791
|
init_crew_lifecycle();
|
|
1792
|
+
init_telegram();
|
|
1599
1793
|
}
|
|
1600
1794
|
});
|
|
1601
1795
|
|
|
@@ -2114,13 +2308,13 @@ var init_notifiers = __esm({
|
|
|
2114
2308
|
});
|
|
2115
2309
|
|
|
2116
2310
|
// packages/workspaces/dist/workspaces/obsidian.js
|
|
2117
|
-
import
|
|
2311
|
+
import fs10 from "fs/promises";
|
|
2118
2312
|
import { existsSync as existsSync8 } from "fs";
|
|
2119
|
-
import
|
|
2313
|
+
import path8 from "path";
|
|
2120
2314
|
function resolveInRoot(root, relative) {
|
|
2121
|
-
const joined =
|
|
2122
|
-
const normalized =
|
|
2123
|
-
if (joined !==
|
|
2315
|
+
const joined = path8.resolve(root, relative);
|
|
2316
|
+
const normalized = path8.resolve(root) + path8.sep;
|
|
2317
|
+
if (joined !== path8.resolve(root) && !joined.startsWith(normalized)) {
|
|
2124
2318
|
throw new Error(`Path '${relative}' escapes workspace root`);
|
|
2125
2319
|
}
|
|
2126
2320
|
return joined;
|
|
@@ -2139,16 +2333,16 @@ function createObsidianDriver(scope) {
|
|
|
2139
2333
|
};
|
|
2140
2334
|
},
|
|
2141
2335
|
async read(rel) {
|
|
2142
|
-
return
|
|
2336
|
+
return fs10.readFile(resolveInRoot(root, rel), "utf-8");
|
|
2143
2337
|
},
|
|
2144
2338
|
async write(rel, content) {
|
|
2145
2339
|
const abs = resolveInRoot(root, rel);
|
|
2146
|
-
await
|
|
2147
|
-
await
|
|
2340
|
+
await fs10.mkdir(path8.dirname(abs), { recursive: true });
|
|
2341
|
+
await fs10.writeFile(abs, content);
|
|
2148
2342
|
},
|
|
2149
2343
|
async exists(rel) {
|
|
2150
2344
|
try {
|
|
2151
|
-
await
|
|
2345
|
+
await fs10.access(resolveInRoot(root, rel));
|
|
2152
2346
|
return true;
|
|
2153
2347
|
} catch {
|
|
2154
2348
|
return false;
|
|
@@ -2156,13 +2350,13 @@ function createObsidianDriver(scope) {
|
|
|
2156
2350
|
},
|
|
2157
2351
|
async list(rel) {
|
|
2158
2352
|
try {
|
|
2159
|
-
return await
|
|
2353
|
+
return await fs10.readdir(resolveInRoot(root, rel));
|
|
2160
2354
|
} catch {
|
|
2161
2355
|
return [];
|
|
2162
2356
|
}
|
|
2163
2357
|
},
|
|
2164
2358
|
async mkdir(rel) {
|
|
2165
|
-
await
|
|
2359
|
+
await fs10.mkdir(resolveInRoot(root, rel), { recursive: true });
|
|
2166
2360
|
}
|
|
2167
2361
|
};
|
|
2168
2362
|
}
|
|
@@ -2831,8 +3025,8 @@ var init_registry4 = __esm({
|
|
|
2831
3025
|
});
|
|
2832
3026
|
|
|
2833
3027
|
// packages/agents/dist/drivers/launch-cmd.js
|
|
2834
|
-
import
|
|
2835
|
-
import
|
|
3028
|
+
import fs11 from "fs";
|
|
3029
|
+
import path9 from "path";
|
|
2836
3030
|
function buildAgentCmd(agentName, registry, role, fresh, permissionMode, model, templatesDir) {
|
|
2837
3031
|
const driver = registry.getDriver(agentName);
|
|
2838
3032
|
if (driver.name === "claude") {
|
|
@@ -2848,27 +3042,27 @@ function buildAgentCmd(agentName, registry, role, fresh, permissionMode, model,
|
|
|
2848
3042
|
cmd += ` --model ${model}`;
|
|
2849
3043
|
}
|
|
2850
3044
|
if (templatesDir) {
|
|
2851
|
-
const roleFile2 =
|
|
2852
|
-
const legacyRoleFile =
|
|
2853
|
-
const actualRoleFile =
|
|
3045
|
+
const roleFile2 = path9.join(templatesDir, `${role}.claude.md`);
|
|
3046
|
+
const legacyRoleFile = path9.join(templatesDir, `${role}.CLAUDE.md`);
|
|
3047
|
+
const actualRoleFile = fs11.existsSync(roleFile2) ? roleFile2 : fs11.existsSync(legacyRoleFile) ? legacyRoleFile : null;
|
|
2854
3048
|
if (actualRoleFile) {
|
|
2855
3049
|
cmd += ` --append-system-prompt-file ${actualRoleFile}`;
|
|
2856
3050
|
}
|
|
2857
|
-
const pluginDir =
|
|
2858
|
-
if (
|
|
3051
|
+
const pluginDir = path9.join(templatesDir, "..", "plugin");
|
|
3052
|
+
if (fs11.existsSync(pluginDir)) {
|
|
2859
3053
|
cmd += ` --plugin-dir ${pluginDir}`;
|
|
2860
3054
|
}
|
|
2861
3055
|
}
|
|
2862
3056
|
return cmd;
|
|
2863
3057
|
}
|
|
2864
|
-
const roleFile = templatesDir ?
|
|
3058
|
+
const roleFile = templatesDir ? path9.join(templatesDir, `${role}.${driver.templateSuffix}.md`) : void 0;
|
|
2865
3059
|
return driver.buildCommand({
|
|
2866
3060
|
prompt: `You are a squadrant ${role}. Read your instructions from ${roleFile ?? role} and begin.`,
|
|
2867
3061
|
workdir: process.cwd(),
|
|
2868
3062
|
role,
|
|
2869
3063
|
model,
|
|
2870
3064
|
autoApprove: true,
|
|
2871
|
-
promptFile: roleFile &&
|
|
3065
|
+
promptFile: roleFile && fs11.existsSync(roleFile) ? roleFile : void 0
|
|
2872
3066
|
});
|
|
2873
3067
|
}
|
|
2874
3068
|
var init_launch_cmd = __esm({
|
|
@@ -2891,7 +3085,7 @@ var init_drivers = __esm({
|
|
|
2891
3085
|
|
|
2892
3086
|
// packages/agents/dist/projection/cursor.js
|
|
2893
3087
|
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
2894
|
-
import
|
|
3088
|
+
import path10 from "path";
|
|
2895
3089
|
import os2 from "os";
|
|
2896
3090
|
function renderMdc(source) {
|
|
2897
3091
|
const skillSections = source.skills.map((s) => `## Skill: ${s.name}
|
|
@@ -2940,7 +3134,7 @@ function createCursorEmitter() {
|
|
|
2940
3134
|
if (scope === "user") {
|
|
2941
3135
|
return [
|
|
2942
3136
|
{
|
|
2943
|
-
path:
|
|
3137
|
+
path: path10.join(os2.homedir(), ".cursor/rules/squadrant-global.mdc"),
|
|
2944
3138
|
shared: false,
|
|
2945
3139
|
format: "mdc"
|
|
2946
3140
|
}
|
|
@@ -2950,7 +3144,7 @@ function createCursorEmitter() {
|
|
|
2950
3144
|
return [];
|
|
2951
3145
|
return [
|
|
2952
3146
|
{
|
|
2953
|
-
path:
|
|
3147
|
+
path: path10.join(projectRoot, ".cursor/rules/squadrant.mdc"),
|
|
2954
3148
|
shared: false,
|
|
2955
3149
|
format: "mdc"
|
|
2956
3150
|
}
|
|
@@ -2967,7 +3161,7 @@ function createCursorEmitter() {
|
|
|
2967
3161
|
diff: buildDiff(existing, generated)
|
|
2968
3162
|
};
|
|
2969
3163
|
}
|
|
2970
|
-
await mkdir(
|
|
3164
|
+
await mkdir(path10.dirname(dest.path), { recursive: true });
|
|
2971
3165
|
await writeFile(dest.path, generated, "utf-8");
|
|
2972
3166
|
return {
|
|
2973
3167
|
written: true,
|
|
@@ -3018,7 +3212,7 @@ var init_marker = __esm({
|
|
|
3018
3212
|
|
|
3019
3213
|
// packages/agents/dist/projection/codex.js
|
|
3020
3214
|
import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
3021
|
-
import
|
|
3215
|
+
import path11 from "path";
|
|
3022
3216
|
import os3 from "os";
|
|
3023
3217
|
function renderMarkdown(source) {
|
|
3024
3218
|
const skillSections = source.skills.map((s) => `## Skill: ${s.name}
|
|
@@ -3043,7 +3237,7 @@ function createCodexEmitter() {
|
|
|
3043
3237
|
destinations(scope, projectRoot) {
|
|
3044
3238
|
if (scope === "user") {
|
|
3045
3239
|
return [{
|
|
3046
|
-
path:
|
|
3240
|
+
path: path11.join(os3.homedir(), ".codex/AGENTS.md"),
|
|
3047
3241
|
shared: true,
|
|
3048
3242
|
format: "markdown"
|
|
3049
3243
|
}];
|
|
@@ -3051,7 +3245,7 @@ function createCodexEmitter() {
|
|
|
3051
3245
|
if (!projectRoot)
|
|
3052
3246
|
return [];
|
|
3053
3247
|
return [{
|
|
3054
|
-
path:
|
|
3248
|
+
path: path11.join(projectRoot, "AGENTS.md"),
|
|
3055
3249
|
shared: true,
|
|
3056
3250
|
format: "markdown"
|
|
3057
3251
|
}];
|
|
@@ -3072,7 +3266,7 @@ ${existing ?? ""}
|
|
|
3072
3266
|
${generated}`
|
|
3073
3267
|
};
|
|
3074
3268
|
}
|
|
3075
|
-
await mkdir2(
|
|
3269
|
+
await mkdir2(path11.dirname(dest.path), { recursive: true });
|
|
3076
3270
|
await writeFile2(dest.path, generated, "utf-8");
|
|
3077
3271
|
return {
|
|
3078
3272
|
written: true,
|
|
@@ -3090,7 +3284,7 @@ var init_codex2 = __esm({
|
|
|
3090
3284
|
|
|
3091
3285
|
// packages/agents/dist/projection/gemini.js
|
|
3092
3286
|
import { mkdir as mkdir3, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
|
|
3093
|
-
import
|
|
3287
|
+
import path12 from "path";
|
|
3094
3288
|
import os4 from "os";
|
|
3095
3289
|
function renderMarkdown2(source) {
|
|
3096
3290
|
const skillSections = source.skills.map((s) => `## Skill: ${s.name}
|
|
@@ -3115,7 +3309,7 @@ function createGeminiEmitter() {
|
|
|
3115
3309
|
destinations(scope, projectRoot) {
|
|
3116
3310
|
if (scope === "user") {
|
|
3117
3311
|
return [{
|
|
3118
|
-
path:
|
|
3312
|
+
path: path12.join(os4.homedir(), ".gemini/GEMINI.md"),
|
|
3119
3313
|
shared: true,
|
|
3120
3314
|
format: "markdown"
|
|
3121
3315
|
}];
|
|
@@ -3123,7 +3317,7 @@ function createGeminiEmitter() {
|
|
|
3123
3317
|
if (!projectRoot)
|
|
3124
3318
|
return [];
|
|
3125
3319
|
return [{
|
|
3126
|
-
path:
|
|
3320
|
+
path: path12.join(projectRoot, "GEMINI.md"),
|
|
3127
3321
|
shared: true,
|
|
3128
3322
|
format: "markdown"
|
|
3129
3323
|
}];
|
|
@@ -3144,7 +3338,7 @@ ${existing ?? ""}
|
|
|
3144
3338
|
${generated}`
|
|
3145
3339
|
};
|
|
3146
3340
|
}
|
|
3147
|
-
await mkdir3(
|
|
3341
|
+
await mkdir3(path12.dirname(dest.path), { recursive: true });
|
|
3148
3342
|
await writeFile3(dest.path, generated, "utf-8");
|
|
3149
3343
|
return {
|
|
3150
3344
|
written: true,
|
|
@@ -3162,7 +3356,7 @@ var init_gemini2 = __esm({
|
|
|
3162
3356
|
|
|
3163
3357
|
// packages/agents/dist/projection/opencode.js
|
|
3164
3358
|
import { mkdir as mkdir4, readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
|
|
3165
|
-
import
|
|
3359
|
+
import path13 from "path";
|
|
3166
3360
|
import os5 from "os";
|
|
3167
3361
|
function renderMarkdown3(source) {
|
|
3168
3362
|
const skillSections = source.skills.map((s) => `## Skill: ${s.name}
|
|
@@ -3187,7 +3381,7 @@ function createOpencodeEmitter() {
|
|
|
3187
3381
|
destinations(scope, projectRoot) {
|
|
3188
3382
|
if (scope === "user") {
|
|
3189
3383
|
return [{
|
|
3190
|
-
path:
|
|
3384
|
+
path: path13.join(os5.homedir(), ".config", "opencode", "AGENTS.md"),
|
|
3191
3385
|
shared: true,
|
|
3192
3386
|
format: "markdown"
|
|
3193
3387
|
}];
|
|
@@ -3195,7 +3389,7 @@ function createOpencodeEmitter() {
|
|
|
3195
3389
|
if (!projectRoot)
|
|
3196
3390
|
return [];
|
|
3197
3391
|
return [{
|
|
3198
|
-
path:
|
|
3392
|
+
path: path13.join(projectRoot, "AGENTS.md"),
|
|
3199
3393
|
shared: true,
|
|
3200
3394
|
format: "markdown"
|
|
3201
3395
|
}];
|
|
@@ -3216,7 +3410,7 @@ ${existing ?? ""}
|
|
|
3216
3410
|
${generated}`
|
|
3217
3411
|
};
|
|
3218
3412
|
}
|
|
3219
|
-
await mkdir4(
|
|
3413
|
+
await mkdir4(path13.dirname(dest.path), { recursive: true });
|
|
3220
3414
|
await writeFile4(dest.path, generated, "utf-8");
|
|
3221
3415
|
return {
|
|
3222
3416
|
written: true,
|
|
@@ -4081,8 +4275,8 @@ function resolveLastAssistantText(payload) {
|
|
|
4081
4275
|
const derived = deriveTranscriptPath(p?.session_id, cwd);
|
|
4082
4276
|
if (derived)
|
|
4083
4277
|
candidates.push(derived);
|
|
4084
|
-
for (const
|
|
4085
|
-
const text = readLastAssistantText(
|
|
4278
|
+
for (const path27 of candidates) {
|
|
4279
|
+
const text = readLastAssistantText(path27);
|
|
4086
4280
|
if (text != null)
|
|
4087
4281
|
return text;
|
|
4088
4282
|
}
|
|
@@ -4481,10 +4675,10 @@ var init_dist4 = __esm({
|
|
|
4481
4675
|
// packages/cli/src/index.ts
|
|
4482
4676
|
init_dist();
|
|
4483
4677
|
init_dist2();
|
|
4484
|
-
import { Command as
|
|
4678
|
+
import { Command as Command28 } from "commander";
|
|
4485
4679
|
import { readFileSync as readFileSync11, existsSync as existsSync10, writeFileSync as writeFileSync9 } from "fs";
|
|
4486
4680
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
4487
|
-
import { dirname as
|
|
4681
|
+
import { dirname as dirname7, join as join22 } from "path";
|
|
4488
4682
|
import { homedir as homedir14 } from "os";
|
|
4489
4683
|
|
|
4490
4684
|
// packages/cli/src/commands/doctor.ts
|
|
@@ -4494,9 +4688,9 @@ init_dist();
|
|
|
4494
4688
|
init_dist3();
|
|
4495
4689
|
import { Command } from "commander";
|
|
4496
4690
|
import { execSync as execSync8 } from "child_process";
|
|
4497
|
-
import
|
|
4691
|
+
import fs12 from "fs";
|
|
4498
4692
|
import { stat } from "fs/promises";
|
|
4499
|
-
import
|
|
4693
|
+
import path14 from "path";
|
|
4500
4694
|
import chalk3 from "chalk";
|
|
4501
4695
|
|
|
4502
4696
|
// packages/cli/src/commands/health-view.ts
|
|
@@ -4598,7 +4792,7 @@ function settingsHaveAgentTeams() {
|
|
|
4598
4792
|
try {
|
|
4599
4793
|
const home = process.env.HOME || "";
|
|
4600
4794
|
const settings = JSON.parse(
|
|
4601
|
-
|
|
4795
|
+
fs12.readFileSync(`${home}/.claude/settings.json`, "utf-8")
|
|
4602
4796
|
);
|
|
4603
4797
|
return settings?.env?.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS === "1";
|
|
4604
4798
|
} catch {
|
|
@@ -4609,7 +4803,7 @@ function pluginInstalled(pluginKey) {
|
|
|
4609
4803
|
try {
|
|
4610
4804
|
const home = process.env.HOME || "";
|
|
4611
4805
|
const plugins = JSON.parse(
|
|
4612
|
-
|
|
4806
|
+
fs12.readFileSync(
|
|
4613
4807
|
`${home}/.claude/plugins/installed_plugins.json`,
|
|
4614
4808
|
"utf-8"
|
|
4615
4809
|
)
|
|
@@ -4641,7 +4835,7 @@ var doctorCommand = new Command("doctor").description("Check system health and p
|
|
|
4641
4835
|
const results = [];
|
|
4642
4836
|
results.push(check("Claude Code installed", commandExists("claude")));
|
|
4643
4837
|
results.push(check(`Claude Code version >= ${compatManifest.tools.claude.min}`, claudeVersionOk()));
|
|
4644
|
-
results.push(check("Obsidian installed", commandExists("obsidian") ||
|
|
4838
|
+
results.push(check("Obsidian installed", commandExists("obsidian") || fs12.existsSync("/Applications/Obsidian.app")));
|
|
4645
4839
|
results.push(check("Node.js >= 18", nodeVersionOk()));
|
|
4646
4840
|
results.push(
|
|
4647
4841
|
check(
|
|
@@ -4714,7 +4908,7 @@ var doctorCommand = new Command("doctor").description("Check system health and p
|
|
|
4714
4908
|
const emitter = projectionRegistry.get(name);
|
|
4715
4909
|
const [userDest] = emitter.destinations("user");
|
|
4716
4910
|
if (!userDest) continue;
|
|
4717
|
-
const dir =
|
|
4911
|
+
const dir = path14.dirname(userDest.path);
|
|
4718
4912
|
let status;
|
|
4719
4913
|
try {
|
|
4720
4914
|
await stat(dir);
|
|
@@ -4727,7 +4921,7 @@ var doctorCommand = new Command("doctor").description("Check system health and p
|
|
|
4727
4921
|
results.push(
|
|
4728
4922
|
check(
|
|
4729
4923
|
"Squadrant config exists",
|
|
4730
|
-
|
|
4924
|
+
fs12.existsSync(
|
|
4731
4925
|
process.env.SQUADRANT_CONFIG || `${process.env.HOME}/.config/squadrant/config.json`
|
|
4732
4926
|
)
|
|
4733
4927
|
)
|
|
@@ -4800,39 +4994,39 @@ init_dist();
|
|
|
4800
4994
|
init_dist3();
|
|
4801
4995
|
init_dist();
|
|
4802
4996
|
import { Command as Command2 } from "commander";
|
|
4803
|
-
import
|
|
4804
|
-
import
|
|
4997
|
+
import fs13 from "fs";
|
|
4998
|
+
import path15 from "path";
|
|
4805
4999
|
import os6 from "os";
|
|
4806
5000
|
import chalk4 from "chalk";
|
|
4807
5001
|
function findPackageRoot() {
|
|
4808
|
-
let dir =
|
|
5002
|
+
let dir = path15.dirname(new URL(import.meta.url).pathname);
|
|
4809
5003
|
while (dir !== "/") {
|
|
4810
|
-
if (
|
|
4811
|
-
dir =
|
|
5004
|
+
if (fs13.existsSync(path15.join(dir, "package.json"))) return dir;
|
|
5005
|
+
dir = path15.dirname(dir);
|
|
4812
5006
|
}
|
|
4813
5007
|
return process.cwd();
|
|
4814
5008
|
}
|
|
4815
5009
|
function copyDirRecursive(src, dest) {
|
|
4816
|
-
|
|
4817
|
-
for (const entry of
|
|
4818
|
-
const srcPath =
|
|
4819
|
-
const destPath =
|
|
5010
|
+
fs13.mkdirSync(dest, { recursive: true });
|
|
5011
|
+
for (const entry of fs13.readdirSync(src, { withFileTypes: true })) {
|
|
5012
|
+
const srcPath = path15.join(src, entry.name);
|
|
5013
|
+
const destPath = path15.join(dest, entry.name);
|
|
4820
5014
|
if (entry.isDirectory()) {
|
|
4821
5015
|
copyDirRecursive(srcPath, destPath);
|
|
4822
5016
|
} else {
|
|
4823
|
-
|
|
5017
|
+
fs13.copyFileSync(srcPath, destPath);
|
|
4824
5018
|
}
|
|
4825
5019
|
}
|
|
4826
5020
|
}
|
|
4827
5021
|
var initCommand = new Command2("init").description("First-time setup: scaffold hub vault, scripts, and config").option("--hub <path>", "Hub vault path", "~/squadrant-hub").action((opts) => {
|
|
4828
5022
|
const hubPath = resolveHome(opts.hub);
|
|
4829
5023
|
const pkgRoot = findPackageRoot();
|
|
4830
|
-
const configDir =
|
|
5024
|
+
const configDir = path15.join(os6.homedir(), ".config", "squadrant");
|
|
4831
5025
|
console.log(chalk4.bold("\nSquadrant Init\n"));
|
|
4832
5026
|
const registry = new WorkspaceRegistry({ obsidian: createObsidianDriver });
|
|
4833
5027
|
try {
|
|
4834
|
-
if (
|
|
4835
|
-
const existing = JSON.parse(
|
|
5028
|
+
if (fs13.existsSync(DEFAULT_CONFIG_PATH)) {
|
|
5029
|
+
const existing = JSON.parse(fs13.readFileSync(DEFAULT_CONFIG_PATH, "utf-8"));
|
|
4836
5030
|
const wsName = existing.workspace ?? "obsidian";
|
|
4837
5031
|
registry.get(wsName);
|
|
4838
5032
|
}
|
|
@@ -4840,7 +5034,7 @@ var initCommand = new Command2("init").description("First-time setup: scaffold h
|
|
|
4840
5034
|
console.log(chalk4.red(` \u2718 ${err.message}`));
|
|
4841
5035
|
return;
|
|
4842
5036
|
}
|
|
4843
|
-
if (
|
|
5037
|
+
if (fs13.existsSync(DEFAULT_CONFIG_PATH)) {
|
|
4844
5038
|
console.log(chalk4.yellow(" \u26A0 Config already exists, skipping creation"));
|
|
4845
5039
|
} else {
|
|
4846
5040
|
const config = getDefaultConfig();
|
|
@@ -4848,37 +5042,37 @@ var initCommand = new Command2("init").description("First-time setup: scaffold h
|
|
|
4848
5042
|
saveConfig(config);
|
|
4849
5043
|
console.log(chalk4.green(` \u2714 Config created at ${DEFAULT_CONFIG_PATH}`));
|
|
4850
5044
|
}
|
|
4851
|
-
const hubTemplate =
|
|
4852
|
-
if (
|
|
5045
|
+
const hubTemplate = path15.join(pkgRoot, "obsidian", "hub");
|
|
5046
|
+
if (fs13.existsSync(hubPath)) {
|
|
4853
5047
|
console.log(chalk4.yellow(` \u26A0 Hub vault already exists at ${hubPath}, skipping`));
|
|
4854
|
-
} else if (
|
|
5048
|
+
} else if (fs13.existsSync(hubTemplate)) {
|
|
4855
5049
|
copyDirRecursive(hubTemplate, hubPath);
|
|
4856
5050
|
console.log(chalk4.green(` \u2714 Hub vault scaffolded at ${hubPath}`));
|
|
4857
5051
|
} else {
|
|
4858
|
-
|
|
5052
|
+
fs13.mkdirSync(hubPath, { recursive: true });
|
|
4859
5053
|
console.log(chalk4.yellow(` \u26A0 Hub template not found; created empty dir at ${hubPath}`));
|
|
4860
5054
|
}
|
|
4861
|
-
const hubDashboardSrc =
|
|
4862
|
-
const hubDashboardDest =
|
|
4863
|
-
if (
|
|
4864
|
-
|
|
5055
|
+
const hubDashboardSrc = path15.join(pkgRoot, "obsidian", "hub", "dashboard.md");
|
|
5056
|
+
const hubDashboardDest = path15.join(hubPath, "dashboard.md");
|
|
5057
|
+
if (fs13.existsSync(hubDashboardSrc)) {
|
|
5058
|
+
fs13.copyFileSync(hubDashboardSrc, hubDashboardDest);
|
|
4865
5059
|
console.log(chalk4.green(` \u2714 Dashboard page refreshed at ${hubDashboardDest}`));
|
|
4866
5060
|
}
|
|
4867
|
-
const projectsDir =
|
|
4868
|
-
|
|
5061
|
+
const projectsDir = path15.join(hubPath, "projects");
|
|
5062
|
+
fs13.mkdirSync(projectsDir, { recursive: true });
|
|
4869
5063
|
ensureRuntimeSynced({ sourceRoot: pkgRoot, runtimeRoot: configDir });
|
|
4870
5064
|
console.log(chalk4.green(` \u2714 Runtime assets synced to ${configDir}`));
|
|
4871
|
-
const settingsPath =
|
|
5065
|
+
const settingsPath = path15.join(os6.homedir(), ".claude", "settings.json");
|
|
4872
5066
|
try {
|
|
4873
5067
|
let settings = {};
|
|
4874
|
-
if (
|
|
4875
|
-
settings = JSON.parse(
|
|
5068
|
+
if (fs13.existsSync(settingsPath)) {
|
|
5069
|
+
settings = JSON.parse(fs13.readFileSync(settingsPath, "utf-8"));
|
|
4876
5070
|
}
|
|
4877
5071
|
const env = settings.env || {};
|
|
4878
5072
|
if (env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS !== "1") {
|
|
4879
5073
|
settings.env = { ...env, CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS: "1" };
|
|
4880
|
-
|
|
4881
|
-
|
|
5074
|
+
fs13.mkdirSync(path15.dirname(settingsPath), { recursive: true });
|
|
5075
|
+
fs13.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
4882
5076
|
console.log(chalk4.green(" \u2714 Agent Teams enabled in ~/.claude/settings.json"));
|
|
4883
5077
|
} else {
|
|
4884
5078
|
console.log(chalk4.green(" \u2714 Agent Teams already enabled"));
|
|
@@ -4899,7 +5093,7 @@ var initCommand = new Command2("init").description("First-time setup: scaffold h
|
|
|
4899
5093
|
console.log(chalk4.cyan(` ${hubPath}`));
|
|
4900
5094
|
console.log("");
|
|
4901
5095
|
console.log(" 4. Run " + chalk4.cyan("squadrant doctor") + " to verify setup\n");
|
|
4902
|
-
if (!
|
|
5096
|
+
if (!fs13.existsSync("/Applications/cmux.app")) {
|
|
4903
5097
|
console.log(chalk4.yellow(" \u26A0 cmux not found \u2014 download from https://cmux.dev\n"));
|
|
4904
5098
|
}
|
|
4905
5099
|
});
|
|
@@ -4907,26 +5101,26 @@ var initCommand = new Command2("init").description("First-time setup: scaffold h
|
|
|
4907
5101
|
// packages/cli/src/commands/projects.ts
|
|
4908
5102
|
init_dist();
|
|
4909
5103
|
import { Command as Command3 } from "commander";
|
|
4910
|
-
import
|
|
4911
|
-
import
|
|
5104
|
+
import fs14 from "fs";
|
|
5105
|
+
import path16 from "path";
|
|
4912
5106
|
import chalk5 from "chalk";
|
|
4913
5107
|
function findPackageRoot2() {
|
|
4914
|
-
let dir =
|
|
5108
|
+
let dir = path16.dirname(new URL(import.meta.url).pathname);
|
|
4915
5109
|
while (dir !== "/") {
|
|
4916
|
-
if (
|
|
4917
|
-
dir =
|
|
5110
|
+
if (fs14.existsSync(path16.join(dir, "package.json"))) return dir;
|
|
5111
|
+
dir = path16.dirname(dir);
|
|
4918
5112
|
}
|
|
4919
5113
|
return process.cwd();
|
|
4920
5114
|
}
|
|
4921
5115
|
function copyDirRecursive2(src, dest) {
|
|
4922
|
-
|
|
4923
|
-
for (const entry of
|
|
4924
|
-
const srcPath =
|
|
4925
|
-
const destPath =
|
|
5116
|
+
fs14.mkdirSync(dest, { recursive: true });
|
|
5117
|
+
for (const entry of fs14.readdirSync(src, { withFileTypes: true })) {
|
|
5118
|
+
const srcPath = path16.join(src, entry.name);
|
|
5119
|
+
const destPath = path16.join(dest, entry.name);
|
|
4926
5120
|
if (entry.isDirectory()) {
|
|
4927
5121
|
copyDirRecursive2(srcPath, destPath);
|
|
4928
5122
|
} else {
|
|
4929
|
-
|
|
5123
|
+
fs14.copyFileSync(srcPath, destPath);
|
|
4930
5124
|
}
|
|
4931
5125
|
}
|
|
4932
5126
|
}
|
|
@@ -4962,7 +5156,7 @@ var addCmd = new Command3("add").description("Register a project").argument("<na
|
|
|
4962
5156
|
process.exit(1);
|
|
4963
5157
|
}
|
|
4964
5158
|
const resolvedPath = resolveHome(projectPath);
|
|
4965
|
-
if (!
|
|
5159
|
+
if (!fs14.existsSync(path16.join(resolvedPath, ".git"))) {
|
|
4966
5160
|
console.log(chalk5.yellow(`
|
|
4967
5161
|
\u26A0 No .git found at ${resolvedPath}. Make sure this is the project root, not a parent directory.
|
|
4968
5162
|
`));
|
|
@@ -5015,7 +5209,7 @@ var addCmd = new Command3("add").description("Register a project").argument("<na
|
|
|
5015
5209
|
\u26A0 Group '${group}' already has '${primary[0]}' as primary. Overriding.`));
|
|
5016
5210
|
}
|
|
5017
5211
|
}
|
|
5018
|
-
const spokeVault = opts.spoke ? resolveHome(opts.spoke) :
|
|
5212
|
+
const spokeVault = opts.spoke ? resolveHome(opts.spoke) : path16.join(config.hubVault, "spokes", name);
|
|
5019
5213
|
const project = {
|
|
5020
5214
|
path: resolvedPath,
|
|
5021
5215
|
captainName,
|
|
@@ -5029,20 +5223,20 @@ var addCmd = new Command3("add").description("Register a project").argument("<na
|
|
|
5029
5223
|
console.log(chalk5.green(`
|
|
5030
5224
|
\u2714 Project '${name}' registered`));
|
|
5031
5225
|
const pkgRoot = findPackageRoot2();
|
|
5032
|
-
const spokeTemplate =
|
|
5033
|
-
if (
|
|
5226
|
+
const spokeTemplate = path16.join(pkgRoot, "obsidian", "spoke");
|
|
5227
|
+
if (fs14.existsSync(spokeVault)) {
|
|
5034
5228
|
console.log(chalk5.yellow(` \u26A0 Spoke vault already exists at ${spokeVault}, skipping scaffold`));
|
|
5035
|
-
} else if (
|
|
5229
|
+
} else if (fs14.existsSync(spokeTemplate)) {
|
|
5036
5230
|
copyDirRecursive2(spokeTemplate, spokeVault);
|
|
5037
|
-
const statusPath =
|
|
5038
|
-
if (
|
|
5039
|
-
const content =
|
|
5231
|
+
const statusPath = path16.join(spokeVault, "status.md");
|
|
5232
|
+
if (fs14.existsSync(statusPath)) {
|
|
5233
|
+
const content = fs14.readFileSync(statusPath, "utf-8");
|
|
5040
5234
|
const updated = content.replace(/^project: unnamed/m, `project: ${name}`);
|
|
5041
|
-
|
|
5235
|
+
fs14.writeFileSync(statusPath, updated);
|
|
5042
5236
|
}
|
|
5043
5237
|
console.log(chalk5.green(` \u2714 Spoke vault scaffolded at ${spokeVault}`));
|
|
5044
5238
|
} else {
|
|
5045
|
-
|
|
5239
|
+
fs14.mkdirSync(spokeVault, { recursive: true });
|
|
5046
5240
|
console.log(chalk5.yellow(` \u26A0 Spoke template not found; created empty dir at ${spokeVault}`));
|
|
5047
5241
|
}
|
|
5048
5242
|
console.log("");
|
|
@@ -5143,10 +5337,10 @@ init_dist4();
|
|
|
5143
5337
|
init_dist();
|
|
5144
5338
|
import { Command as Command5 } from "commander";
|
|
5145
5339
|
import { execSync as execSync9 } from "child_process";
|
|
5146
|
-
import
|
|
5340
|
+
import path17 from "path";
|
|
5147
5341
|
import os7 from "os";
|
|
5148
5342
|
import chalk7 from "chalk";
|
|
5149
|
-
var TEMPLATES_DIR =
|
|
5343
|
+
var TEMPLATES_DIR = path17.join(os7.homedir(), ".config", "squadrant", "templates");
|
|
5150
5344
|
var TASK_PROMPTS = {
|
|
5151
5345
|
briefing: "Run your daily briefing using the squadrant:command-ops skill. Read all spoke handoffs, yesterday's logs, current status; produce a concise cross-project briefing; save to {hubVault}/daily-logs/YYYY-MM-DD.md; then exit.",
|
|
5152
5346
|
"learnings-review": "Run a learnings review using the squadrant:command-ops skill. Scan {spokeVault}/learnings across all projects, identify cross-project patterns, propose captured-skill or fix actions, and exit when done.",
|
|
@@ -5179,7 +5373,7 @@ async function runCommandSpawn(input) {
|
|
|
5179
5373
|
if (!agent) {
|
|
5180
5374
|
throw new Error(`Unknown agent '${agentName}'. Known: claude, codex, gemini, opencode.`);
|
|
5181
5375
|
}
|
|
5182
|
-
const promptFile =
|
|
5376
|
+
const promptFile = path17.join(TEMPLATES_DIR, `command.${agent.templateSuffix}.md`);
|
|
5183
5377
|
const cliCommand = agent.buildCommand({
|
|
5184
5378
|
prompt,
|
|
5185
5379
|
workdir: process.cwd(),
|
|
@@ -5206,8 +5400,8 @@ var commandCommand = new Command5("command").description("Spawn a one-shot Comma
|
|
|
5206
5400
|
init_dist();
|
|
5207
5401
|
init_dist();
|
|
5208
5402
|
import { Command as Command9 } from "commander";
|
|
5209
|
-
import
|
|
5210
|
-
import
|
|
5403
|
+
import fs15 from "fs";
|
|
5404
|
+
import path18 from "path";
|
|
5211
5405
|
import os8 from "os";
|
|
5212
5406
|
import chalk9 from "chalk";
|
|
5213
5407
|
|
|
@@ -5875,7 +6069,7 @@ function writePerCrewOpencodeConfig(o) {
|
|
|
5875
6069
|
|
|
5876
6070
|
// packages/cli/src/commands/crew.ts
|
|
5877
6071
|
init_dist2();
|
|
5878
|
-
var TEMPLATES_DIR2 =
|
|
6072
|
+
var TEMPLATES_DIR2 = path18.join(os8.homedir(), ".config", "squadrant", "templates");
|
|
5879
6073
|
async function runCrewSpawn(input) {
|
|
5880
6074
|
const config = loadConfig();
|
|
5881
6075
|
const proj = config.projects[input.project];
|
|
@@ -5923,8 +6117,8 @@ async function runCrewSpawn(input) {
|
|
|
5923
6117
|
throw new Error(`Unknown agent '${agentName}'. Known: claude, codex, gemini, opencode.`);
|
|
5924
6118
|
}
|
|
5925
6119
|
if (agentName === "codex") {
|
|
5926
|
-
const codexRoleFile =
|
|
5927
|
-
const roleInstructions =
|
|
6120
|
+
const codexRoleFile = path18.join(TEMPLATES_DIR2, `crew.${agent.templateSuffix}.md`);
|
|
6121
|
+
const roleInstructions = fs15.existsSync(codexRoleFile) ? fs15.readFileSync(codexRoleFile, "utf8") : void 0;
|
|
5928
6122
|
return runCodexInteractiveSpawn({
|
|
5929
6123
|
project: input.project,
|
|
5930
6124
|
task: input.task,
|
|
@@ -5937,7 +6131,7 @@ async function runCrewSpawn(input) {
|
|
|
5937
6131
|
roleInstructions
|
|
5938
6132
|
});
|
|
5939
6133
|
}
|
|
5940
|
-
const promptFile =
|
|
6134
|
+
const promptFile = path18.join(TEMPLATES_DIR2, `crew.${agent.templateSuffix}.md`);
|
|
5941
6135
|
const interactive = agent.name === "claude" || agent.name === "opencode";
|
|
5942
6136
|
const crewRole = config.defaults.roles?.crew;
|
|
5943
6137
|
const configModel = crewRole && crewRole.agent === agent.name ? crewRole.model : void 0;
|
|
@@ -5994,7 +6188,7 @@ ${buildCompletionProtocol(rec.id, input.project)}`, preLaunchScreen);
|
|
|
5994
6188
|
});
|
|
5995
6189
|
const rec = await squadrantdCall(req);
|
|
5996
6190
|
const opencodeConfigPath = writePerCrewOpencodeConfig({
|
|
5997
|
-
stateRoot:
|
|
6191
|
+
stateRoot: path18.join(os8.homedir(), ".config", "squadrant", "state"),
|
|
5998
6192
|
project: input.project,
|
|
5999
6193
|
taskId: rec.id,
|
|
6000
6194
|
// CP3 opt-in: --approval gates bash so the captain approves shell commands.
|
|
@@ -6234,11 +6428,11 @@ init_dist3();
|
|
|
6234
6428
|
init_dist();
|
|
6235
6429
|
init_dist();
|
|
6236
6430
|
import { Command as Command10 } from "commander";
|
|
6237
|
-
import
|
|
6238
|
-
import
|
|
6431
|
+
import fs16 from "fs";
|
|
6432
|
+
import path19 from "path";
|
|
6239
6433
|
import os9 from "os";
|
|
6240
6434
|
import chalk10 from "chalk";
|
|
6241
|
-
var TEMPLATES_DIR3 =
|
|
6435
|
+
var TEMPLATES_DIR3 = path19.join(os9.homedir(), ".config", "squadrant", "templates");
|
|
6242
6436
|
var SIDE_ROLES = ["research", "debug"];
|
|
6243
6437
|
function shellQuote2(p) {
|
|
6244
6438
|
return "'" + p.replace(/'/g, "'\\''") + "'";
|
|
@@ -6329,7 +6523,7 @@ async function runSideSpawn(input) {
|
|
|
6329
6523
|
throw new Error(`Unknown agent '${agentName}'. Known: claude, codex, gemini, opencode.`);
|
|
6330
6524
|
}
|
|
6331
6525
|
const sideModel = sideRole?.model;
|
|
6332
|
-
const promptFile =
|
|
6526
|
+
const promptFile = path19.join(
|
|
6333
6527
|
TEMPLATES_DIR3,
|
|
6334
6528
|
`side.${input.role}.${agent.templateSuffix}.md`
|
|
6335
6529
|
);
|
|
@@ -6340,7 +6534,7 @@ async function runSideSpawn(input) {
|
|
|
6340
6534
|
prompt: input.topic,
|
|
6341
6535
|
workdir: spawnCwd,
|
|
6342
6536
|
role: "side",
|
|
6343
|
-
promptFile:
|
|
6537
|
+
promptFile: fs16.existsSync(promptFile) ? promptFile : void 0,
|
|
6344
6538
|
interactive: true,
|
|
6345
6539
|
permissionMode: config.defaults.permissions?.crew ?? "auto",
|
|
6346
6540
|
...sideModel ? { model: sideModel } : {}
|
|
@@ -6397,7 +6591,7 @@ async function runSideClose(project, name) {
|
|
|
6397
6591
|
project,
|
|
6398
6592
|
name
|
|
6399
6593
|
);
|
|
6400
|
-
if (
|
|
6594
|
+
if (fs16.existsSync(wtPath)) {
|
|
6401
6595
|
try {
|
|
6402
6596
|
removeWorktree(proj.path, wtPath);
|
|
6403
6597
|
} catch (e) {
|
|
@@ -6625,8 +6819,8 @@ function renderDashboard(rows, opts) {
|
|
|
6625
6819
|
|
|
6626
6820
|
// packages/web/dist/sync-hub.js
|
|
6627
6821
|
init_dist();
|
|
6628
|
-
import
|
|
6629
|
-
import
|
|
6822
|
+
import fs17 from "fs";
|
|
6823
|
+
import path20 from "path";
|
|
6630
6824
|
function buildMirrorMarkdown(s) {
|
|
6631
6825
|
const fenced = "```";
|
|
6632
6826
|
return [
|
|
@@ -6652,15 +6846,15 @@ function buildMirrorMarkdown(s) {
|
|
|
6652
6846
|
function syncHub(deps) {
|
|
6653
6847
|
if (!deps.config.hubVault)
|
|
6654
6848
|
return [];
|
|
6655
|
-
const writeFile5 = deps.writeFile ?? ((p, c) =>
|
|
6656
|
-
const mkdir5 = deps.mkdir ?? ((p) =>
|
|
6657
|
-
const projectsDir =
|
|
6849
|
+
const writeFile5 = deps.writeFile ?? ((p, c) => fs17.writeFileSync(p, c));
|
|
6850
|
+
const mkdir5 = deps.mkdir ?? ((p) => fs17.mkdirSync(p, { recursive: true }));
|
|
6851
|
+
const projectsDir = path20.join(resolveHome(deps.config.hubVault), "projects");
|
|
6658
6852
|
mkdir5(projectsDir);
|
|
6659
6853
|
const out = [];
|
|
6660
6854
|
for (const s of deps.statuses) {
|
|
6661
6855
|
if (s.state === "unknown")
|
|
6662
6856
|
continue;
|
|
6663
|
-
const hubPath =
|
|
6857
|
+
const hubPath = path20.join(projectsDir, `${s.project}.md`);
|
|
6664
6858
|
try {
|
|
6665
6859
|
writeFile5(hubPath, buildMirrorMarkdown(s));
|
|
6666
6860
|
out.push({ project: s.project, hubPath });
|
|
@@ -7549,13 +7743,13 @@ init_dist3();
|
|
|
7549
7743
|
init_dist2();
|
|
7550
7744
|
import { Command as Command12 } from "commander";
|
|
7551
7745
|
import { execSync as execSync11 } from "child_process";
|
|
7552
|
-
import
|
|
7553
|
-
import
|
|
7746
|
+
import fs18 from "fs";
|
|
7747
|
+
import path21 from "path";
|
|
7554
7748
|
import os10 from "os";
|
|
7555
7749
|
import chalk13 from "chalk";
|
|
7556
7750
|
var CMUX_APP = "/Applications/cmux.app";
|
|
7557
|
-
var TEMPLATES_DIR4 =
|
|
7558
|
-
var SESSIONS_PATH2 =
|
|
7751
|
+
var TEMPLATES_DIR4 = path21.join(os10.homedir(), ".config", "squadrant", "templates");
|
|
7752
|
+
var SESSIONS_PATH2 = path21.join(os10.homedir(), ".config", "squadrant", "sessions.json");
|
|
7559
7753
|
function ensureCmuxReady() {
|
|
7560
7754
|
if (isInsideCmux()) return;
|
|
7561
7755
|
console.log(chalk13.yellow("\n Not running inside cmux. Opening cmux app...\n"));
|
|
@@ -7662,12 +7856,12 @@ var launchCommand = new Command12("launch").description(
|
|
|
7662
7856
|
}
|
|
7663
7857
|
if (opts.all) {
|
|
7664
7858
|
const hubPath = resolveHome(config.hubVault);
|
|
7665
|
-
|
|
7859
|
+
fs18.mkdirSync(hubPath, { recursive: true });
|
|
7666
7860
|
console.log(chalk13.bold("\nLaunching all captain workspaces\n"));
|
|
7667
7861
|
for (const [name, proj] of Object.entries(config.projects)) {
|
|
7668
7862
|
const projPath = resolveHome(proj.path);
|
|
7669
7863
|
const spokePath = resolveHome(proj.spokeVault);
|
|
7670
|
-
if (!
|
|
7864
|
+
if (!fs18.existsSync(spokePath)) {
|
|
7671
7865
|
const spokeDriver = new WorkspaceRegistry({ obsidian: createObsidianDriver }).forProject(name, config);
|
|
7672
7866
|
await ensureSpokeLayout(spokeDriver);
|
|
7673
7867
|
console.log(chalk13.cyan(` \u2714 Created spoke vault at ${spokePath}`));
|
|
@@ -7698,7 +7892,7 @@ var launchCommand = new Command12("launch").description(
|
|
|
7698
7892
|
const proj = config.projects[project];
|
|
7699
7893
|
const projPath = resolveHome(proj.path);
|
|
7700
7894
|
const spokePath = resolveHome(proj.spokeVault);
|
|
7701
|
-
if (!
|
|
7895
|
+
if (!fs18.existsSync(spokePath)) {
|
|
7702
7896
|
const spokeDriver = new WorkspaceRegistry({ obsidian: createObsidianDriver }).forProject(project, config);
|
|
7703
7897
|
await ensureSpokeLayout(spokeDriver);
|
|
7704
7898
|
console.log(chalk13.cyan(` \u2714 Created spoke vault at ${spokePath}`));
|
|
@@ -7833,24 +8027,24 @@ Shutting down captain workspace for '${project}'...
|
|
|
7833
8027
|
// packages/cli/src/commands/feedback.ts
|
|
7834
8028
|
init_dist();
|
|
7835
8029
|
import { Command as Command14 } from "commander";
|
|
7836
|
-
import
|
|
8030
|
+
import fs19 from "fs";
|
|
7837
8031
|
import os11 from "os";
|
|
7838
|
-
import
|
|
8032
|
+
import path22 from "path";
|
|
7839
8033
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
7840
8034
|
import { execSync as execSync12 } from "child_process";
|
|
7841
8035
|
import chalk15 from "chalk";
|
|
7842
8036
|
var REPO_URL = "https://github.com/tu11aa/squadrant";
|
|
7843
8037
|
function readPkgVersion() {
|
|
7844
8038
|
try {
|
|
7845
|
-
const pkgPath =
|
|
7846
|
-
return JSON.parse(
|
|
8039
|
+
const pkgPath = path22.join(path22.dirname(fileURLToPath3(import.meta.url)), "..", "package.json");
|
|
8040
|
+
return JSON.parse(fs19.readFileSync(pkgPath, "utf-8")).version ?? "unknown";
|
|
7847
8041
|
} catch {
|
|
7848
8042
|
return "unknown";
|
|
7849
8043
|
}
|
|
7850
8044
|
}
|
|
7851
8045
|
function readMetrics(metricsPath) {
|
|
7852
8046
|
try {
|
|
7853
|
-
return JSON.parse(
|
|
8047
|
+
return JSON.parse(fs19.readFileSync(metricsPath, "utf-8"));
|
|
7854
8048
|
} catch {
|
|
7855
8049
|
return {};
|
|
7856
8050
|
}
|
|
@@ -7888,7 +8082,7 @@ function buildIssueUrl(metrics, squadrantVersion) {
|
|
|
7888
8082
|
}
|
|
7889
8083
|
var feedbackCommand = new Command14("feedback").description("Open a pre-filled GitHub issue for feedback or bug reports").action(() => {
|
|
7890
8084
|
const config = loadConfig();
|
|
7891
|
-
const metricsPath = config.metrics?.path ||
|
|
8085
|
+
const metricsPath = config.metrics?.path || path22.join(os11.homedir(), ".config", "squadrant", "metrics.json");
|
|
7892
8086
|
const metrics = readMetrics(metricsPath);
|
|
7893
8087
|
const version = readStamp(config) ?? readPkgVersion();
|
|
7894
8088
|
const issueUrl = buildIssueUrl(metrics, version);
|
|
@@ -7910,8 +8104,8 @@ init_dist();
|
|
|
7910
8104
|
init_dist();
|
|
7911
8105
|
init_dist3();
|
|
7912
8106
|
import { Command as Command15 } from "commander";
|
|
7913
|
-
import
|
|
7914
|
-
import
|
|
8107
|
+
import fs20 from "fs";
|
|
8108
|
+
import path23 from "path";
|
|
7915
8109
|
import chalk16 from "chalk";
|
|
7916
8110
|
import matter3 from "gray-matter";
|
|
7917
8111
|
function getDateStr(yesterday) {
|
|
@@ -7920,11 +8114,11 @@ function getDateStr(yesterday) {
|
|
|
7920
8114
|
async function getProjectStandup(name, project, dateStr, registry, config) {
|
|
7921
8115
|
const workspace = registry.forProject(name, config);
|
|
7922
8116
|
const spokeVault = resolveHome(project.spokeVault);
|
|
7923
|
-
const statusFile =
|
|
8117
|
+
const statusFile = path23.join(spokeVault, "status.md");
|
|
7924
8118
|
let status = {};
|
|
7925
|
-
if (
|
|
8119
|
+
if (fs20.existsSync(statusFile)) {
|
|
7926
8120
|
try {
|
|
7927
|
-
status = matter3(
|
|
8121
|
+
status = matter3(fs20.readFileSync(statusFile, "utf-8")).data;
|
|
7928
8122
|
} catch {
|
|
7929
8123
|
}
|
|
7930
8124
|
}
|
|
@@ -8042,15 +8236,15 @@ init_dist();
|
|
|
8042
8236
|
init_dist();
|
|
8043
8237
|
init_dist3();
|
|
8044
8238
|
import { Command as Command16 } from "commander";
|
|
8045
|
-
import
|
|
8046
|
-
import
|
|
8239
|
+
import fs21 from "fs";
|
|
8240
|
+
import path24 from "path";
|
|
8047
8241
|
import chalk17 from "chalk";
|
|
8048
8242
|
import matter4 from "gray-matter";
|
|
8049
8243
|
function readStatus(spokeVault) {
|
|
8050
|
-
const statusFile =
|
|
8051
|
-
if (!
|
|
8244
|
+
const statusFile = path24.join(spokeVault, "status.md");
|
|
8245
|
+
if (!fs21.existsSync(statusFile)) return {};
|
|
8052
8246
|
try {
|
|
8053
|
-
return matter4(
|
|
8247
|
+
return matter4(fs21.readFileSync(statusFile, "utf-8")).data;
|
|
8054
8248
|
} catch {
|
|
8055
8249
|
return {};
|
|
8056
8250
|
}
|
|
@@ -8360,9 +8554,9 @@ workspaceCommand.command("read").description("Print the contents of a scope-rela
|
|
|
8360
8554
|
const config = loadConfig();
|
|
8361
8555
|
const registry = buildRegistry2();
|
|
8362
8556
|
try {
|
|
8363
|
-
const { projectTarget, path:
|
|
8557
|
+
const { projectTarget, path: path27 } = resolveTargetAndPath(arg1, arg2, !!opts.hub);
|
|
8364
8558
|
const driver = resolveDriver(registry, config, projectTarget, !!opts.hub);
|
|
8365
|
-
const content = await driver.read(
|
|
8559
|
+
const content = await driver.read(path27);
|
|
8366
8560
|
process.stdout.write(content);
|
|
8367
8561
|
} catch (err) {
|
|
8368
8562
|
console.error(chalk19.red(err.message));
|
|
@@ -8374,26 +8568,26 @@ workspaceCommand.command("write").description("Write content to a scope-relative
|
|
|
8374
8568
|
const registry = buildRegistry2();
|
|
8375
8569
|
try {
|
|
8376
8570
|
let projectTarget;
|
|
8377
|
-
let
|
|
8571
|
+
let path27;
|
|
8378
8572
|
let rawContent;
|
|
8379
8573
|
if (opts.hub) {
|
|
8380
8574
|
if (arg3 !== void 0) {
|
|
8381
8575
|
throw new Error("With --hub, pass only the path and content");
|
|
8382
8576
|
}
|
|
8383
8577
|
projectTarget = void 0;
|
|
8384
|
-
|
|
8578
|
+
path27 = arg1;
|
|
8385
8579
|
rawContent = arg2;
|
|
8386
8580
|
} else {
|
|
8387
8581
|
if (arg3 === void 0) {
|
|
8388
8582
|
throw new Error("Missing content \u2014 usage: <project> <path> <content>");
|
|
8389
8583
|
}
|
|
8390
8584
|
projectTarget = arg1;
|
|
8391
|
-
|
|
8585
|
+
path27 = arg2;
|
|
8392
8586
|
rawContent = arg3;
|
|
8393
8587
|
}
|
|
8394
8588
|
const driver = resolveDriver(registry, config, projectTarget, !!opts.hub);
|
|
8395
8589
|
const payload = rawContent === "-" ? await readStdin() : rawContent;
|
|
8396
|
-
await driver.write(
|
|
8590
|
+
await driver.write(path27, payload);
|
|
8397
8591
|
} catch (err) {
|
|
8398
8592
|
console.error(chalk19.red(err.message));
|
|
8399
8593
|
process.exit(1);
|
|
@@ -8403,9 +8597,9 @@ workspaceCommand.command("list").description("List entries in a scope-relative d
|
|
|
8403
8597
|
const config = loadConfig();
|
|
8404
8598
|
const registry = buildRegistry2();
|
|
8405
8599
|
try {
|
|
8406
|
-
const { projectTarget, path:
|
|
8600
|
+
const { projectTarget, path: path27 } = resolveTargetAndPath(arg1, arg2, !!opts.hub);
|
|
8407
8601
|
const driver = resolveDriver(registry, config, projectTarget, !!opts.hub);
|
|
8408
|
-
const entries = await driver.list(
|
|
8602
|
+
const entries = await driver.list(path27);
|
|
8409
8603
|
for (const entry of entries) console.log(entry);
|
|
8410
8604
|
} catch (err) {
|
|
8411
8605
|
console.error(chalk19.red(err.message));
|
|
@@ -8416,9 +8610,9 @@ workspaceCommand.command("exists").description("Exit 0 if path exists, 1 if not"
|
|
|
8416
8610
|
const config = loadConfig();
|
|
8417
8611
|
const registry = buildRegistry2();
|
|
8418
8612
|
try {
|
|
8419
|
-
const { projectTarget, path:
|
|
8613
|
+
const { projectTarget, path: path27 } = resolveTargetAndPath(arg1, arg2, !!opts.hub);
|
|
8420
8614
|
const driver = resolveDriver(registry, config, projectTarget, !!opts.hub);
|
|
8421
|
-
const ok = await driver.exists(
|
|
8615
|
+
const ok = await driver.exists(path27);
|
|
8422
8616
|
process.exit(ok ? 0 : 1);
|
|
8423
8617
|
} catch (err) {
|
|
8424
8618
|
console.error(chalk19.red(err.message));
|
|
@@ -8429,9 +8623,9 @@ workspaceCommand.command("mkdir").description("Recursively create a scope-relati
|
|
|
8429
8623
|
const config = loadConfig();
|
|
8430
8624
|
const registry = buildRegistry2();
|
|
8431
8625
|
try {
|
|
8432
|
-
const { projectTarget, path:
|
|
8626
|
+
const { projectTarget, path: path27 } = resolveTargetAndPath(arg1, arg2, !!opts.hub);
|
|
8433
8627
|
const driver = resolveDriver(registry, config, projectTarget, !!opts.hub);
|
|
8434
|
-
await driver.mkdir(
|
|
8628
|
+
await driver.mkdir(path27);
|
|
8435
8629
|
} catch (err) {
|
|
8436
8630
|
console.error(chalk19.red(err.message));
|
|
8437
8631
|
process.exit(1);
|
|
@@ -8470,8 +8664,8 @@ init_dist3();
|
|
|
8470
8664
|
init_dist();
|
|
8471
8665
|
import { Command as Command20 } from "commander";
|
|
8472
8666
|
import chalk21 from "chalk";
|
|
8473
|
-
import
|
|
8474
|
-
import
|
|
8667
|
+
import fs22 from "fs";
|
|
8668
|
+
import path25 from "path";
|
|
8475
8669
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
8476
8670
|
function parseScope(v) {
|
|
8477
8671
|
if (v !== "user" && v !== "project") {
|
|
@@ -8480,10 +8674,10 @@ function parseScope(v) {
|
|
|
8480
8674
|
return v;
|
|
8481
8675
|
}
|
|
8482
8676
|
function findPackageRoot3() {
|
|
8483
|
-
let dir =
|
|
8677
|
+
let dir = path25.dirname(fileURLToPath4(import.meta.url));
|
|
8484
8678
|
while (dir !== "/" && dir !== "") {
|
|
8485
|
-
if (
|
|
8486
|
-
dir =
|
|
8679
|
+
if (fs22.existsSync(path25.join(dir, "package.json"))) return dir;
|
|
8680
|
+
dir = path25.dirname(dir);
|
|
8487
8681
|
}
|
|
8488
8682
|
return process.cwd();
|
|
8489
8683
|
}
|
|
@@ -8677,12 +8871,12 @@ init_dist();
|
|
|
8677
8871
|
init_dist();
|
|
8678
8872
|
init_dist();
|
|
8679
8873
|
import { Command as Command22 } from "commander";
|
|
8680
|
-
import
|
|
8874
|
+
import fs23 from "fs";
|
|
8681
8875
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
8682
8876
|
import { dirname as dirname5, join as join19 } from "path";
|
|
8683
8877
|
import chalk22 from "chalk";
|
|
8684
8878
|
function runConfigCheck(opts) {
|
|
8685
|
-
const raw = JSON.parse(
|
|
8879
|
+
const raw = JSON.parse(fs23.readFileSync(opts.configPath, "utf-8"));
|
|
8686
8880
|
const def = getDefaultConfig();
|
|
8687
8881
|
const items = detectDrift(raw, def);
|
|
8688
8882
|
let working = raw;
|
|
@@ -8699,10 +8893,40 @@ function runConfigCheck(opts) {
|
|
|
8699
8893
|
stamped = true;
|
|
8700
8894
|
}
|
|
8701
8895
|
if (opts.fix || opts.accept || stamped) {
|
|
8702
|
-
|
|
8896
|
+
fs23.writeFileSync(opts.configPath, JSON.stringify(working, null, 2) + "\n");
|
|
8703
8897
|
}
|
|
8704
8898
|
return { items, applied, remaining, stamped };
|
|
8705
8899
|
}
|
|
8900
|
+
function runConfigGet(key, configPath = DEFAULT_CONFIG_PATH) {
|
|
8901
|
+
const config = loadConfig(configPath);
|
|
8902
|
+
const parts = key.split(".");
|
|
8903
|
+
let node = config;
|
|
8904
|
+
for (const p of parts) {
|
|
8905
|
+
if (node === null || typeof node !== "object" || !(p in node)) {
|
|
8906
|
+
throw new Error(`config key not found: ${key}`);
|
|
8907
|
+
}
|
|
8908
|
+
node = node[p];
|
|
8909
|
+
}
|
|
8910
|
+
return node;
|
|
8911
|
+
}
|
|
8912
|
+
function runConfigSet(key, value, configPath = DEFAULT_CONFIG_PATH) {
|
|
8913
|
+
let parsed;
|
|
8914
|
+
try {
|
|
8915
|
+
parsed = JSON.parse(value);
|
|
8916
|
+
} catch {
|
|
8917
|
+
parsed = value;
|
|
8918
|
+
}
|
|
8919
|
+
const config = loadConfig(configPath);
|
|
8920
|
+
const parts = key.split(".");
|
|
8921
|
+
let node = config;
|
|
8922
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
8923
|
+
const p = parts[i];
|
|
8924
|
+
if (node[p] === null || typeof node[p] !== "object") node[p] = {};
|
|
8925
|
+
node = node[p];
|
|
8926
|
+
}
|
|
8927
|
+
node[parts[parts.length - 1]] = parsed;
|
|
8928
|
+
saveConfig(config, configPath);
|
|
8929
|
+
}
|
|
8706
8930
|
var SEV_COLOR = {
|
|
8707
8931
|
info: chalk22.green,
|
|
8708
8932
|
advisory: chalk22.yellow,
|
|
@@ -8724,7 +8948,7 @@ function printItems(items) {
|
|
|
8724
8948
|
var configCommand = new Command22("config").description("Inspect and reconcile squadrant config");
|
|
8725
8949
|
configCommand.command("check").description("Detect config drift vs the current default schema").option("--fix", "Apply the safe tier (add missing, remove deprecated)", false).option("--accept", "Stamp the current version without changing config (dismiss advisories)", false).option("--json", "Output drift items as JSON", false).action((opts) => {
|
|
8726
8950
|
const pkgVersion = readPkgVersion2();
|
|
8727
|
-
if (!
|
|
8951
|
+
if (!fs23.existsSync(DEFAULT_CONFIG_PATH)) {
|
|
8728
8952
|
console.log(chalk22.yellow("No config found \u2014 run `squadrant init` first."));
|
|
8729
8953
|
return;
|
|
8730
8954
|
}
|
|
@@ -8751,9 +8975,27 @@ ${judgment.length} item(s) need review \u2014 run the config-doctor skill, or \`
|
|
|
8751
8975
|
console.log(chalk22.green("\n\u2714 Config reconciled and stamped."));
|
|
8752
8976
|
}
|
|
8753
8977
|
});
|
|
8978
|
+
configCommand.command("get").description("Read a config value by dotted key (e.g. defaults.effort)").argument("<key>", "dotted config key").action((key) => {
|
|
8979
|
+
try {
|
|
8980
|
+
const value = runConfigGet(key);
|
|
8981
|
+
console.log(typeof value === "string" ? value : JSON.stringify(value));
|
|
8982
|
+
} catch (e) {
|
|
8983
|
+
console.error(chalk22.red(e.message));
|
|
8984
|
+
process.exit(1);
|
|
8985
|
+
}
|
|
8986
|
+
});
|
|
8987
|
+
configCommand.command("set").description("Write a config value by dotted key (e.g. defaults.effort low)").argument("<key>", "dotted config key").argument("<value>", "value (JSON-parsed when possible, else a bare string)").action((key, value) => {
|
|
8988
|
+
try {
|
|
8989
|
+
runConfigSet(key, value);
|
|
8990
|
+
console.log(chalk22.green(`\u2714 set ${key} = ${value}`));
|
|
8991
|
+
} catch (e) {
|
|
8992
|
+
console.error(chalk22.red(e.message));
|
|
8993
|
+
process.exit(1);
|
|
8994
|
+
}
|
|
8995
|
+
});
|
|
8754
8996
|
function readPkgVersion2() {
|
|
8755
8997
|
const pkgPath = join19(dirname5(fileURLToPath5(import.meta.url)), "..", "package.json");
|
|
8756
|
-
return JSON.parse(
|
|
8998
|
+
return JSON.parse(fs23.readFileSync(pkgPath, "utf-8")).version;
|
|
8757
8999
|
}
|
|
8758
9000
|
|
|
8759
9001
|
// packages/cli/src/commands/heal.ts
|
|
@@ -9019,8 +9261,8 @@ var cmuxCommand = new Command25("cmux").description("cmux integration helpers").
|
|
|
9019
9261
|
|
|
9020
9262
|
// packages/cli/src/commands/effort.ts
|
|
9021
9263
|
init_dist();
|
|
9022
|
-
import
|
|
9023
|
-
import
|
|
9264
|
+
import fs24 from "fs";
|
|
9265
|
+
import path26 from "path";
|
|
9024
9266
|
import { Command as Command26 } from "commander";
|
|
9025
9267
|
import chalk26 from "chalk";
|
|
9026
9268
|
var VALID_EFFORTS = ["max", "balance", "low"];
|
|
@@ -9047,9 +9289,9 @@ function runEffortSet(value, configPath = DEFAULT_CONFIG_PATH) {
|
|
|
9047
9289
|
}
|
|
9048
9290
|
function canonical(p) {
|
|
9049
9291
|
try {
|
|
9050
|
-
return
|
|
9292
|
+
return fs24.realpathSync(p);
|
|
9051
9293
|
} catch {
|
|
9052
|
-
return
|
|
9294
|
+
return path26.resolve(p);
|
|
9053
9295
|
}
|
|
9054
9296
|
}
|
|
9055
9297
|
async function notifyCaptainsOfEffort(effort, config, driver, cwd = process.cwd()) {
|
|
@@ -9093,19 +9335,232 @@ var effortCommand = new Command26("effort").description("Get or set the global c
|
|
|
9093
9335
|
}
|
|
9094
9336
|
});
|
|
9095
9337
|
|
|
9338
|
+
// packages/cli/src/commands/telegram.ts
|
|
9339
|
+
init_dist();
|
|
9340
|
+
init_dist2();
|
|
9341
|
+
import { join as join21, dirname as dirname6 } from "path";
|
|
9342
|
+
import { emitKeypressEvents } from "readline";
|
|
9343
|
+
import { Command as Command27 } from "commander";
|
|
9344
|
+
import chalk27 from "chalk";
|
|
9345
|
+
function defaultStateRoot() {
|
|
9346
|
+
return join21(dirname6(DEFAULT_CONFIG_PATH), "state");
|
|
9347
|
+
}
|
|
9348
|
+
function runTelegramStatus(opts) {
|
|
9349
|
+
const tg = opts.config.telegram;
|
|
9350
|
+
const env = opts.env ?? process.env;
|
|
9351
|
+
const tokenSet = !!(tg?.botToken ?? env.TELEGRAM_BOT_TOKEN);
|
|
9352
|
+
const links = Object.entries(loadState(opts.stateRoot).topics).map(([key, topicId]) => {
|
|
9353
|
+
const sep2 = key.indexOf("::");
|
|
9354
|
+
return { project: key.slice(0, sep2), scope: key.slice(sep2 + 2), topicId };
|
|
9355
|
+
});
|
|
9356
|
+
return { tokenSet, supergroupId: tg?.supergroupId ?? null, links };
|
|
9357
|
+
}
|
|
9358
|
+
async function runTelegramSend(opts) {
|
|
9359
|
+
const topicId = loadState(opts.stateRoot).topics[topicKey(opts.project)];
|
|
9360
|
+
if (topicId === void 0) {
|
|
9361
|
+
throw new Error(`project "${opts.project}" is not linked \u2014 run: squadrant telegram link ${opts.project}`);
|
|
9362
|
+
}
|
|
9363
|
+
await opts.client.sendMessage(opts.cfg.supergroupId, topicId, opts.message);
|
|
9364
|
+
return { chatId: opts.cfg.supergroupId, topicId };
|
|
9365
|
+
}
|
|
9366
|
+
async function runTelegramLink(opts) {
|
|
9367
|
+
const existing = loadState(opts.stateRoot).topics[topicKey(opts.project)];
|
|
9368
|
+
if (existing !== void 0) return { topicId: existing, created: false };
|
|
9369
|
+
const topicId = await opts.client.createForumTopic(opts.cfg.supergroupId, topicName(opts.project));
|
|
9370
|
+
setTopic(opts.stateRoot, opts.project, topicId);
|
|
9371
|
+
return { topicId, created: true };
|
|
9372
|
+
}
|
|
9373
|
+
async function questionMasked() {
|
|
9374
|
+
return new Promise((resolve3) => {
|
|
9375
|
+
emitKeypressEvents(process.stdin);
|
|
9376
|
+
process.stdin.setRawMode(true);
|
|
9377
|
+
process.stdin.resume();
|
|
9378
|
+
let answer = "";
|
|
9379
|
+
const onKeypress = (_str, key) => {
|
|
9380
|
+
if (key.ctrl && key.name === "c") {
|
|
9381
|
+
process.stdin.removeListener("keypress", onKeypress);
|
|
9382
|
+
process.stdin.setRawMode(false);
|
|
9383
|
+
process.stdin.pause();
|
|
9384
|
+
process.stdout.write("\n");
|
|
9385
|
+
process.exit(130);
|
|
9386
|
+
} else if (key.name === "return" || key.name === "enter") {
|
|
9387
|
+
process.stdin.removeListener("keypress", onKeypress);
|
|
9388
|
+
process.stdin.setRawMode(false);
|
|
9389
|
+
process.stdin.pause();
|
|
9390
|
+
process.stdout.write("\n");
|
|
9391
|
+
resolve3(answer);
|
|
9392
|
+
} else if (key.name === "backspace") {
|
|
9393
|
+
if (answer.length > 0) {
|
|
9394
|
+
answer = answer.slice(0, -1);
|
|
9395
|
+
process.stdout.write("\b \b");
|
|
9396
|
+
}
|
|
9397
|
+
} else if (!key.ctrl && !key.meta && key.sequence) {
|
|
9398
|
+
answer += key.sequence;
|
|
9399
|
+
process.stdout.write("*");
|
|
9400
|
+
}
|
|
9401
|
+
};
|
|
9402
|
+
process.stdin.on("keypress", onKeypress);
|
|
9403
|
+
});
|
|
9404
|
+
}
|
|
9405
|
+
async function questionYesNo(prompt) {
|
|
9406
|
+
const { createInterface: createInterface2 } = await import("readline");
|
|
9407
|
+
const rl = createInterface2({ input: process.stdin, output: process.stdout });
|
|
9408
|
+
return new Promise((resolve3) => {
|
|
9409
|
+
rl.question(prompt, (ans) => {
|
|
9410
|
+
rl.close();
|
|
9411
|
+
process.stdin.pause();
|
|
9412
|
+
resolve3(/^y(es)?$/i.test(ans.trim()));
|
|
9413
|
+
});
|
|
9414
|
+
});
|
|
9415
|
+
}
|
|
9416
|
+
var telegramCommand = new Command27("telegram").description("Two-way Telegram integration: push crew events to a topic and reply into the captain pane");
|
|
9417
|
+
telegramCommand.command("status").description("Show Telegram config and linked projects").action(() => {
|
|
9418
|
+
const { tokenSet, supergroupId, links } = runTelegramStatus({ config: loadConfig(), stateRoot: defaultStateRoot() });
|
|
9419
|
+
console.log(`token: ${tokenSet ? chalk27.green("set") : chalk27.yellow("unset")}`);
|
|
9420
|
+
console.log(`supergroup: ${supergroupId ?? chalk27.yellow("unset")}`);
|
|
9421
|
+
if (links.length === 0) {
|
|
9422
|
+
console.log("no projects linked");
|
|
9423
|
+
return;
|
|
9424
|
+
}
|
|
9425
|
+
for (const l of links) console.log(` ${l.project} (${l.scope}) \u2192 topic ${l.topicId}`);
|
|
9426
|
+
});
|
|
9427
|
+
telegramCommand.command("link").argument("<project>", "project to bind to a Telegram topic").description("Create (or reuse) a forum topic for a project and bind it").action(async (project) => {
|
|
9428
|
+
const cfg = loadConfig().telegram;
|
|
9429
|
+
if (!cfg) {
|
|
9430
|
+
console.error(chalk27.red("telegram config absent \u2014 add a `telegram` block to ~/.config/squadrant/config.json"));
|
|
9431
|
+
process.exit(1);
|
|
9432
|
+
}
|
|
9433
|
+
const token = cfg.botToken ?? process.env.TELEGRAM_BOT_TOKEN;
|
|
9434
|
+
if (!token) {
|
|
9435
|
+
console.error(chalk27.red("no botToken in config and TELEGRAM_BOT_TOKEN is unset"));
|
|
9436
|
+
process.exit(1);
|
|
9437
|
+
}
|
|
9438
|
+
const client = createTelegramClient({ token });
|
|
9439
|
+
const { topicId, created } = await runTelegramLink({ project, cfg, client, stateRoot: defaultStateRoot() });
|
|
9440
|
+
console.log(chalk27.green(`${created ? "linked" : "already linked"}: ${project} \u2192 topic ${topicId}`));
|
|
9441
|
+
});
|
|
9442
|
+
telegramCommand.command("setup").description("Interactive wizard \u2014 bot token, validate, auto-detect supergroup, write config").action(async () => {
|
|
9443
|
+
if (!process.stdin.isTTY) {
|
|
9444
|
+
console.error(chalk27.red("setup requires a TTY \u2014 pipe input is not supported"));
|
|
9445
|
+
process.exit(1);
|
|
9446
|
+
}
|
|
9447
|
+
console.log();
|
|
9448
|
+
console.log(chalk27.bold("Telegram setup") + " \u2014 connect squadrant to a Telegram bot for notifications + remote control");
|
|
9449
|
+
console.log();
|
|
9450
|
+
console.log("Before you start you need:");
|
|
9451
|
+
console.log(" 1. A bot token from @BotFather (send /newbot)");
|
|
9452
|
+
console.log(" 2. A forum supergroup with the bot added as an admin (Topics enabled)");
|
|
9453
|
+
console.log(" 3. Bot privacy mode set to OFF (@BotFather \u2192 /setprivacy \u2192 Disable)");
|
|
9454
|
+
console.log();
|
|
9455
|
+
console.log(chalk27.bold("Step 1/3 \u2014 Bot token"));
|
|
9456
|
+
console.log("Paste your bot token then press Enter (input is hidden):");
|
|
9457
|
+
const token = await questionMasked();
|
|
9458
|
+
if (!token) {
|
|
9459
|
+
console.error(chalk27.red("token required"));
|
|
9460
|
+
process.exit(1);
|
|
9461
|
+
}
|
|
9462
|
+
const client = createTelegramClient({ token });
|
|
9463
|
+
let botUser;
|
|
9464
|
+
try {
|
|
9465
|
+
botUser = await client.getMe();
|
|
9466
|
+
} catch (e) {
|
|
9467
|
+
console.error(chalk27.red(`token rejected: ${e.message}`));
|
|
9468
|
+
process.exit(1);
|
|
9469
|
+
}
|
|
9470
|
+
console.log(chalk27.green(`Connected as @${botUser.username}`));
|
|
9471
|
+
console.log();
|
|
9472
|
+
console.log(chalk27.bold("Step 2/3 \u2014 Find your group"));
|
|
9473
|
+
console.log("Add the bot to your forum supergroup, then send any message in it.");
|
|
9474
|
+
console.log(chalk27.dim("Waiting for a message (up to 60s)\u2026"));
|
|
9475
|
+
let supergroupId;
|
|
9476
|
+
let userId;
|
|
9477
|
+
try {
|
|
9478
|
+
({ supergroupId, userId } = await detectGroupAndUser(client, { timeoutMs: 6e4 }));
|
|
9479
|
+
} catch {
|
|
9480
|
+
console.error(chalk27.red("Timed out \u2014 no supergroup message received within 60s."));
|
|
9481
|
+
console.error(chalk27.yellow("Check: bot is an admin in the group \xB7 privacy mode is OFF \xB7 Topics enabled"));
|
|
9482
|
+
process.exit(1);
|
|
9483
|
+
}
|
|
9484
|
+
console.log(chalk27.green(`Found group: ${supergroupId}`));
|
|
9485
|
+
console.log();
|
|
9486
|
+
console.log(chalk27.bold("Step 3/3 \u2014 Remote control + Save"));
|
|
9487
|
+
console.log(chalk27.dim("Remote control enables auto-launching captains and the General command channel"));
|
|
9488
|
+
console.log(chalk27.dim("from your phone \u2014 gated to your Telegram user-id only (fail-closed)."));
|
|
9489
|
+
let users;
|
|
9490
|
+
let remoteControl;
|
|
9491
|
+
if (userId === void 0) {
|
|
9492
|
+
console.log(chalk27.yellow("Could not read your user-id from that message \u2014 skipping remote control."));
|
|
9493
|
+
console.log(chalk27.yellow("Re-run setup once it's available, or edit telegram.users in config manually."));
|
|
9494
|
+
} else {
|
|
9495
|
+
const enable = await questionYesNo(
|
|
9496
|
+
`Enable remote control for your user-id ${userId}? [y/N] `
|
|
9497
|
+
);
|
|
9498
|
+
if (enable) {
|
|
9499
|
+
users = [userId];
|
|
9500
|
+
remoteControl = true;
|
|
9501
|
+
}
|
|
9502
|
+
}
|
|
9503
|
+
writeTelegramConfig(DEFAULT_CONFIG_PATH, { token, supergroupId, users, remoteControl });
|
|
9504
|
+
console.log(chalk27.green(`Wrote telegram config \u2014 token: ${maskToken(token)} group: ${supergroupId}`));
|
|
9505
|
+
if (remoteControl) {
|
|
9506
|
+
console.log(chalk27.green(`Remote control: ON (allowlisted user-id ${users?.[0]})`));
|
|
9507
|
+
} else {
|
|
9508
|
+
console.log(chalk27.dim("Remote control: off (default). Re-run setup to enable later."));
|
|
9509
|
+
}
|
|
9510
|
+
console.log();
|
|
9511
|
+
console.log(`Next: ${chalk27.cyan("squadrant telegram link <project>")}`);
|
|
9512
|
+
});
|
|
9513
|
+
telegramCommand.command("send").argument("<project>", "project whose topic receives the message").argument("[message...]", "message text (omit to read from stdin)").description("Send a message to a project's linked Telegram topic").action(async (project, messageParts) => {
|
|
9514
|
+
const cfg = loadConfig().telegram;
|
|
9515
|
+
if (!cfg) {
|
|
9516
|
+
console.error(chalk27.red("telegram config absent \u2014 add a `telegram` block to ~/.config/squadrant/config.json"));
|
|
9517
|
+
process.exit(1);
|
|
9518
|
+
}
|
|
9519
|
+
const token = cfg.botToken ?? process.env.TELEGRAM_BOT_TOKEN;
|
|
9520
|
+
if (!token) {
|
|
9521
|
+
console.error(chalk27.red("no botToken in config and TELEGRAM_BOT_TOKEN is unset"));
|
|
9522
|
+
process.exit(1);
|
|
9523
|
+
}
|
|
9524
|
+
let message;
|
|
9525
|
+
if (messageParts.length > 0) {
|
|
9526
|
+
message = messageParts.join(" ");
|
|
9527
|
+
} else if (!process.stdin.isTTY) {
|
|
9528
|
+
const { createInterface: createInterface2 } = await import("readline");
|
|
9529
|
+
const lines = [];
|
|
9530
|
+
const rl = createInterface2({ input: process.stdin });
|
|
9531
|
+
for await (const line of rl) lines.push(line);
|
|
9532
|
+
message = lines.join("\n").trimEnd();
|
|
9533
|
+
if (!message) {
|
|
9534
|
+
console.error(chalk27.red("no message provided (stdin was empty)"));
|
|
9535
|
+
process.exit(1);
|
|
9536
|
+
}
|
|
9537
|
+
} else {
|
|
9538
|
+
console.error(chalk27.red("message required \u2014 pass as argument or pipe via stdin"));
|
|
9539
|
+
process.exit(1);
|
|
9540
|
+
}
|
|
9541
|
+
const client = createTelegramClient({ token });
|
|
9542
|
+
try {
|
|
9543
|
+
const { chatId, topicId } = await runTelegramSend({ project, message, cfg, client, stateRoot: defaultStateRoot() });
|
|
9544
|
+
console.log(chalk27.green(`sent to group ${chatId} topic ${topicId}`));
|
|
9545
|
+
} catch (e) {
|
|
9546
|
+
console.error(chalk27.red(e.message));
|
|
9547
|
+
process.exit(1);
|
|
9548
|
+
}
|
|
9549
|
+
});
|
|
9550
|
+
|
|
9096
9551
|
// packages/cli/src/index.ts
|
|
9097
9552
|
init_dist();
|
|
9098
9553
|
init_dist();
|
|
9099
9554
|
init_dist();
|
|
9100
|
-
var __dirname =
|
|
9101
|
-
var pkg = JSON.parse(readFileSync11(
|
|
9555
|
+
var __dirname = dirname7(fileURLToPath6(import.meta.url));
|
|
9556
|
+
var pkg = JSON.parse(readFileSync11(join22(__dirname, "..", "package.json"), "utf-8"));
|
|
9102
9557
|
ensureRuntimeSynced({
|
|
9103
|
-
sourceRoot:
|
|
9104
|
-
runtimeRoot:
|
|
9558
|
+
sourceRoot: join22(__dirname, ".."),
|
|
9559
|
+
runtimeRoot: join22(homedir14(), ".config", "squadrant")
|
|
9105
9560
|
});
|
|
9106
9561
|
if (process.argv[2] !== "config") {
|
|
9107
9562
|
try {
|
|
9108
|
-
const cfgPath =
|
|
9563
|
+
const cfgPath = join22(homedir14(), ".config", "squadrant", "config.json");
|
|
9109
9564
|
if (existsSync10(cfgPath)) {
|
|
9110
9565
|
const cfg = JSON.parse(readFileSync11(cfgPath, "utf-8"));
|
|
9111
9566
|
if (needsCheck(cfg, pkg.version)) {
|
|
@@ -9130,7 +9585,7 @@ if (process.argv[2] !== "config") {
|
|
|
9130
9585
|
if (!process.env.SQUADRANT_DAEMON_SKIP) {
|
|
9131
9586
|
ensureDaemon();
|
|
9132
9587
|
}
|
|
9133
|
-
var program = new
|
|
9588
|
+
var program = new Command28();
|
|
9134
9589
|
program.name("squadrant").description("Multi-project orchestration for your coding agents (Claude, Codex, opencode, Gemini)").version(pkg.version);
|
|
9135
9590
|
program.addCommand(doctorCommand);
|
|
9136
9591
|
program.addCommand(initCommand);
|
|
@@ -9156,6 +9611,7 @@ program.addCommand(healCommand);
|
|
|
9156
9611
|
program.addCommand(groupCommand);
|
|
9157
9612
|
program.addCommand(cmuxCommand);
|
|
9158
9613
|
program.addCommand(effortCommand);
|
|
9614
|
+
program.addCommand(telegramCommand);
|
|
9159
9615
|
program.parseAsync().catch((e) => {
|
|
9160
9616
|
process.stderr.write(`error: ${e instanceof Error ? e.message : String(e)}
|
|
9161
9617
|
`);
|