squadrant 0.9.1 → 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 +667 -201
- 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/"))
|
|
@@ -1499,7 +1499,8 @@ function buildCompletionProtocol(taskId, project) {
|
|
|
1499
1499
|
"COMPLETION PROTOCOL (required): When this task is fully complete, your FINAL action MUST be to run exactly:",
|
|
1500
1500
|
` squadrant crew signal done --task-id ${taskId} --project ${project} --message "<one-line summary>"`,
|
|
1501
1501
|
"Run it as a discrete final step AFTER you report your results. If you are blocked or need a decision, instead run:",
|
|
1502
|
-
` squadrant crew signal blocked --task-id ${taskId} --project ${project} --question "<your question>"
|
|
1502
|
+
` squadrant crew signal blocked --task-id ${taskId} --project ${project} --question "<your question>"`,
|
|
1503
|
+
"If this task failed because of a defect in squadrant itself (not an API/infra blip, a config/user error, or an expected failure), say so in your signal done/blocked message so the captain can check tu11aa/squadrant and file it. Don't file issues from the crew."
|
|
1503
1504
|
].join("\n");
|
|
1504
1505
|
}
|
|
1505
1506
|
function shellQuote(p) {
|
|
@@ -1570,6 +1571,199 @@ var init_crew_lifecycle = __esm({
|
|
|
1570
1571
|
}
|
|
1571
1572
|
});
|
|
1572
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
|
+
|
|
1573
1767
|
// packages/core/dist/index.js
|
|
1574
1768
|
var init_dist2 = __esm({
|
|
1575
1769
|
"packages/core/dist/index.js"() {
|
|
@@ -1595,6 +1789,7 @@ var init_dist2 = __esm({
|
|
|
1595
1789
|
init_session_freshness();
|
|
1596
1790
|
init_crew_protocol();
|
|
1597
1791
|
init_crew_lifecycle();
|
|
1792
|
+
init_telegram();
|
|
1598
1793
|
}
|
|
1599
1794
|
});
|
|
1600
1795
|
|
|
@@ -2113,13 +2308,13 @@ var init_notifiers = __esm({
|
|
|
2113
2308
|
});
|
|
2114
2309
|
|
|
2115
2310
|
// packages/workspaces/dist/workspaces/obsidian.js
|
|
2116
|
-
import
|
|
2311
|
+
import fs10 from "fs/promises";
|
|
2117
2312
|
import { existsSync as existsSync8 } from "fs";
|
|
2118
|
-
import
|
|
2313
|
+
import path8 from "path";
|
|
2119
2314
|
function resolveInRoot(root, relative) {
|
|
2120
|
-
const joined =
|
|
2121
|
-
const normalized =
|
|
2122
|
-
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)) {
|
|
2123
2318
|
throw new Error(`Path '${relative}' escapes workspace root`);
|
|
2124
2319
|
}
|
|
2125
2320
|
return joined;
|
|
@@ -2138,16 +2333,16 @@ function createObsidianDriver(scope) {
|
|
|
2138
2333
|
};
|
|
2139
2334
|
},
|
|
2140
2335
|
async read(rel) {
|
|
2141
|
-
return
|
|
2336
|
+
return fs10.readFile(resolveInRoot(root, rel), "utf-8");
|
|
2142
2337
|
},
|
|
2143
2338
|
async write(rel, content) {
|
|
2144
2339
|
const abs = resolveInRoot(root, rel);
|
|
2145
|
-
await
|
|
2146
|
-
await
|
|
2340
|
+
await fs10.mkdir(path8.dirname(abs), { recursive: true });
|
|
2341
|
+
await fs10.writeFile(abs, content);
|
|
2147
2342
|
},
|
|
2148
2343
|
async exists(rel) {
|
|
2149
2344
|
try {
|
|
2150
|
-
await
|
|
2345
|
+
await fs10.access(resolveInRoot(root, rel));
|
|
2151
2346
|
return true;
|
|
2152
2347
|
} catch {
|
|
2153
2348
|
return false;
|
|
@@ -2155,13 +2350,13 @@ function createObsidianDriver(scope) {
|
|
|
2155
2350
|
},
|
|
2156
2351
|
async list(rel) {
|
|
2157
2352
|
try {
|
|
2158
|
-
return await
|
|
2353
|
+
return await fs10.readdir(resolveInRoot(root, rel));
|
|
2159
2354
|
} catch {
|
|
2160
2355
|
return [];
|
|
2161
2356
|
}
|
|
2162
2357
|
},
|
|
2163
2358
|
async mkdir(rel) {
|
|
2164
|
-
await
|
|
2359
|
+
await fs10.mkdir(resolveInRoot(root, rel), { recursive: true });
|
|
2165
2360
|
}
|
|
2166
2361
|
};
|
|
2167
2362
|
}
|
|
@@ -2830,8 +3025,8 @@ var init_registry4 = __esm({
|
|
|
2830
3025
|
});
|
|
2831
3026
|
|
|
2832
3027
|
// packages/agents/dist/drivers/launch-cmd.js
|
|
2833
|
-
import
|
|
2834
|
-
import
|
|
3028
|
+
import fs11 from "fs";
|
|
3029
|
+
import path9 from "path";
|
|
2835
3030
|
function buildAgentCmd(agentName, registry, role, fresh, permissionMode, model, templatesDir) {
|
|
2836
3031
|
const driver = registry.getDriver(agentName);
|
|
2837
3032
|
if (driver.name === "claude") {
|
|
@@ -2847,27 +3042,27 @@ function buildAgentCmd(agentName, registry, role, fresh, permissionMode, model,
|
|
|
2847
3042
|
cmd += ` --model ${model}`;
|
|
2848
3043
|
}
|
|
2849
3044
|
if (templatesDir) {
|
|
2850
|
-
const roleFile2 =
|
|
2851
|
-
const legacyRoleFile =
|
|
2852
|
-
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;
|
|
2853
3048
|
if (actualRoleFile) {
|
|
2854
3049
|
cmd += ` --append-system-prompt-file ${actualRoleFile}`;
|
|
2855
3050
|
}
|
|
2856
|
-
const pluginDir =
|
|
2857
|
-
if (
|
|
3051
|
+
const pluginDir = path9.join(templatesDir, "..", "plugin");
|
|
3052
|
+
if (fs11.existsSync(pluginDir)) {
|
|
2858
3053
|
cmd += ` --plugin-dir ${pluginDir}`;
|
|
2859
3054
|
}
|
|
2860
3055
|
}
|
|
2861
3056
|
return cmd;
|
|
2862
3057
|
}
|
|
2863
|
-
const roleFile = templatesDir ?
|
|
3058
|
+
const roleFile = templatesDir ? path9.join(templatesDir, `${role}.${driver.templateSuffix}.md`) : void 0;
|
|
2864
3059
|
return driver.buildCommand({
|
|
2865
3060
|
prompt: `You are a squadrant ${role}. Read your instructions from ${roleFile ?? role} and begin.`,
|
|
2866
3061
|
workdir: process.cwd(),
|
|
2867
3062
|
role,
|
|
2868
3063
|
model,
|
|
2869
3064
|
autoApprove: true,
|
|
2870
|
-
promptFile: roleFile &&
|
|
3065
|
+
promptFile: roleFile && fs11.existsSync(roleFile) ? roleFile : void 0
|
|
2871
3066
|
});
|
|
2872
3067
|
}
|
|
2873
3068
|
var init_launch_cmd = __esm({
|
|
@@ -2890,7 +3085,7 @@ var init_drivers = __esm({
|
|
|
2890
3085
|
|
|
2891
3086
|
// packages/agents/dist/projection/cursor.js
|
|
2892
3087
|
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
2893
|
-
import
|
|
3088
|
+
import path10 from "path";
|
|
2894
3089
|
import os2 from "os";
|
|
2895
3090
|
function renderMdc(source) {
|
|
2896
3091
|
const skillSections = source.skills.map((s) => `## Skill: ${s.name}
|
|
@@ -2939,7 +3134,7 @@ function createCursorEmitter() {
|
|
|
2939
3134
|
if (scope === "user") {
|
|
2940
3135
|
return [
|
|
2941
3136
|
{
|
|
2942
|
-
path:
|
|
3137
|
+
path: path10.join(os2.homedir(), ".cursor/rules/squadrant-global.mdc"),
|
|
2943
3138
|
shared: false,
|
|
2944
3139
|
format: "mdc"
|
|
2945
3140
|
}
|
|
@@ -2949,7 +3144,7 @@ function createCursorEmitter() {
|
|
|
2949
3144
|
return [];
|
|
2950
3145
|
return [
|
|
2951
3146
|
{
|
|
2952
|
-
path:
|
|
3147
|
+
path: path10.join(projectRoot, ".cursor/rules/squadrant.mdc"),
|
|
2953
3148
|
shared: false,
|
|
2954
3149
|
format: "mdc"
|
|
2955
3150
|
}
|
|
@@ -2966,7 +3161,7 @@ function createCursorEmitter() {
|
|
|
2966
3161
|
diff: buildDiff(existing, generated)
|
|
2967
3162
|
};
|
|
2968
3163
|
}
|
|
2969
|
-
await mkdir(
|
|
3164
|
+
await mkdir(path10.dirname(dest.path), { recursive: true });
|
|
2970
3165
|
await writeFile(dest.path, generated, "utf-8");
|
|
2971
3166
|
return {
|
|
2972
3167
|
written: true,
|
|
@@ -3017,7 +3212,7 @@ var init_marker = __esm({
|
|
|
3017
3212
|
|
|
3018
3213
|
// packages/agents/dist/projection/codex.js
|
|
3019
3214
|
import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
3020
|
-
import
|
|
3215
|
+
import path11 from "path";
|
|
3021
3216
|
import os3 from "os";
|
|
3022
3217
|
function renderMarkdown(source) {
|
|
3023
3218
|
const skillSections = source.skills.map((s) => `## Skill: ${s.name}
|
|
@@ -3042,7 +3237,7 @@ function createCodexEmitter() {
|
|
|
3042
3237
|
destinations(scope, projectRoot) {
|
|
3043
3238
|
if (scope === "user") {
|
|
3044
3239
|
return [{
|
|
3045
|
-
path:
|
|
3240
|
+
path: path11.join(os3.homedir(), ".codex/AGENTS.md"),
|
|
3046
3241
|
shared: true,
|
|
3047
3242
|
format: "markdown"
|
|
3048
3243
|
}];
|
|
@@ -3050,7 +3245,7 @@ function createCodexEmitter() {
|
|
|
3050
3245
|
if (!projectRoot)
|
|
3051
3246
|
return [];
|
|
3052
3247
|
return [{
|
|
3053
|
-
path:
|
|
3248
|
+
path: path11.join(projectRoot, "AGENTS.md"),
|
|
3054
3249
|
shared: true,
|
|
3055
3250
|
format: "markdown"
|
|
3056
3251
|
}];
|
|
@@ -3071,7 +3266,7 @@ ${existing ?? ""}
|
|
|
3071
3266
|
${generated}`
|
|
3072
3267
|
};
|
|
3073
3268
|
}
|
|
3074
|
-
await mkdir2(
|
|
3269
|
+
await mkdir2(path11.dirname(dest.path), { recursive: true });
|
|
3075
3270
|
await writeFile2(dest.path, generated, "utf-8");
|
|
3076
3271
|
return {
|
|
3077
3272
|
written: true,
|
|
@@ -3089,7 +3284,7 @@ var init_codex2 = __esm({
|
|
|
3089
3284
|
|
|
3090
3285
|
// packages/agents/dist/projection/gemini.js
|
|
3091
3286
|
import { mkdir as mkdir3, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
|
|
3092
|
-
import
|
|
3287
|
+
import path12 from "path";
|
|
3093
3288
|
import os4 from "os";
|
|
3094
3289
|
function renderMarkdown2(source) {
|
|
3095
3290
|
const skillSections = source.skills.map((s) => `## Skill: ${s.name}
|
|
@@ -3114,7 +3309,7 @@ function createGeminiEmitter() {
|
|
|
3114
3309
|
destinations(scope, projectRoot) {
|
|
3115
3310
|
if (scope === "user") {
|
|
3116
3311
|
return [{
|
|
3117
|
-
path:
|
|
3312
|
+
path: path12.join(os4.homedir(), ".gemini/GEMINI.md"),
|
|
3118
3313
|
shared: true,
|
|
3119
3314
|
format: "markdown"
|
|
3120
3315
|
}];
|
|
@@ -3122,7 +3317,7 @@ function createGeminiEmitter() {
|
|
|
3122
3317
|
if (!projectRoot)
|
|
3123
3318
|
return [];
|
|
3124
3319
|
return [{
|
|
3125
|
-
path:
|
|
3320
|
+
path: path12.join(projectRoot, "GEMINI.md"),
|
|
3126
3321
|
shared: true,
|
|
3127
3322
|
format: "markdown"
|
|
3128
3323
|
}];
|
|
@@ -3143,7 +3338,7 @@ ${existing ?? ""}
|
|
|
3143
3338
|
${generated}`
|
|
3144
3339
|
};
|
|
3145
3340
|
}
|
|
3146
|
-
await mkdir3(
|
|
3341
|
+
await mkdir3(path12.dirname(dest.path), { recursive: true });
|
|
3147
3342
|
await writeFile3(dest.path, generated, "utf-8");
|
|
3148
3343
|
return {
|
|
3149
3344
|
written: true,
|
|
@@ -3161,7 +3356,7 @@ var init_gemini2 = __esm({
|
|
|
3161
3356
|
|
|
3162
3357
|
// packages/agents/dist/projection/opencode.js
|
|
3163
3358
|
import { mkdir as mkdir4, readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
|
|
3164
|
-
import
|
|
3359
|
+
import path13 from "path";
|
|
3165
3360
|
import os5 from "os";
|
|
3166
3361
|
function renderMarkdown3(source) {
|
|
3167
3362
|
const skillSections = source.skills.map((s) => `## Skill: ${s.name}
|
|
@@ -3186,7 +3381,7 @@ function createOpencodeEmitter() {
|
|
|
3186
3381
|
destinations(scope, projectRoot) {
|
|
3187
3382
|
if (scope === "user") {
|
|
3188
3383
|
return [{
|
|
3189
|
-
path:
|
|
3384
|
+
path: path13.join(os5.homedir(), ".config", "opencode", "AGENTS.md"),
|
|
3190
3385
|
shared: true,
|
|
3191
3386
|
format: "markdown"
|
|
3192
3387
|
}];
|
|
@@ -3194,7 +3389,7 @@ function createOpencodeEmitter() {
|
|
|
3194
3389
|
if (!projectRoot)
|
|
3195
3390
|
return [];
|
|
3196
3391
|
return [{
|
|
3197
|
-
path:
|
|
3392
|
+
path: path13.join(projectRoot, "AGENTS.md"),
|
|
3198
3393
|
shared: true,
|
|
3199
3394
|
format: "markdown"
|
|
3200
3395
|
}];
|
|
@@ -3215,7 +3410,7 @@ ${existing ?? ""}
|
|
|
3215
3410
|
${generated}`
|
|
3216
3411
|
};
|
|
3217
3412
|
}
|
|
3218
|
-
await mkdir4(
|
|
3413
|
+
await mkdir4(path13.dirname(dest.path), { recursive: true });
|
|
3219
3414
|
await writeFile4(dest.path, generated, "utf-8");
|
|
3220
3415
|
return {
|
|
3221
3416
|
written: true,
|
|
@@ -4080,8 +4275,8 @@ function resolveLastAssistantText(payload) {
|
|
|
4080
4275
|
const derived = deriveTranscriptPath(p?.session_id, cwd);
|
|
4081
4276
|
if (derived)
|
|
4082
4277
|
candidates.push(derived);
|
|
4083
|
-
for (const
|
|
4084
|
-
const text = readLastAssistantText(
|
|
4278
|
+
for (const path27 of candidates) {
|
|
4279
|
+
const text = readLastAssistantText(path27);
|
|
4085
4280
|
if (text != null)
|
|
4086
4281
|
return text;
|
|
4087
4282
|
}
|
|
@@ -4480,10 +4675,10 @@ var init_dist4 = __esm({
|
|
|
4480
4675
|
// packages/cli/src/index.ts
|
|
4481
4676
|
init_dist();
|
|
4482
4677
|
init_dist2();
|
|
4483
|
-
import { Command as
|
|
4678
|
+
import { Command as Command28 } from "commander";
|
|
4484
4679
|
import { readFileSync as readFileSync11, existsSync as existsSync10, writeFileSync as writeFileSync9 } from "fs";
|
|
4485
|
-
import { fileURLToPath as
|
|
4486
|
-
import { dirname as
|
|
4680
|
+
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
4681
|
+
import { dirname as dirname7, join as join22 } from "path";
|
|
4487
4682
|
import { homedir as homedir14 } from "os";
|
|
4488
4683
|
|
|
4489
4684
|
// packages/cli/src/commands/doctor.ts
|
|
@@ -4493,9 +4688,9 @@ init_dist();
|
|
|
4493
4688
|
init_dist3();
|
|
4494
4689
|
import { Command } from "commander";
|
|
4495
4690
|
import { execSync as execSync8 } from "child_process";
|
|
4496
|
-
import
|
|
4691
|
+
import fs12 from "fs";
|
|
4497
4692
|
import { stat } from "fs/promises";
|
|
4498
|
-
import
|
|
4693
|
+
import path14 from "path";
|
|
4499
4694
|
import chalk3 from "chalk";
|
|
4500
4695
|
|
|
4501
4696
|
// packages/cli/src/commands/health-view.ts
|
|
@@ -4597,7 +4792,7 @@ function settingsHaveAgentTeams() {
|
|
|
4597
4792
|
try {
|
|
4598
4793
|
const home = process.env.HOME || "";
|
|
4599
4794
|
const settings = JSON.parse(
|
|
4600
|
-
|
|
4795
|
+
fs12.readFileSync(`${home}/.claude/settings.json`, "utf-8")
|
|
4601
4796
|
);
|
|
4602
4797
|
return settings?.env?.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS === "1";
|
|
4603
4798
|
} catch {
|
|
@@ -4608,7 +4803,7 @@ function pluginInstalled(pluginKey) {
|
|
|
4608
4803
|
try {
|
|
4609
4804
|
const home = process.env.HOME || "";
|
|
4610
4805
|
const plugins = JSON.parse(
|
|
4611
|
-
|
|
4806
|
+
fs12.readFileSync(
|
|
4612
4807
|
`${home}/.claude/plugins/installed_plugins.json`,
|
|
4613
4808
|
"utf-8"
|
|
4614
4809
|
)
|
|
@@ -4640,7 +4835,7 @@ var doctorCommand = new Command("doctor").description("Check system health and p
|
|
|
4640
4835
|
const results = [];
|
|
4641
4836
|
results.push(check("Claude Code installed", commandExists("claude")));
|
|
4642
4837
|
results.push(check(`Claude Code version >= ${compatManifest.tools.claude.min}`, claudeVersionOk()));
|
|
4643
|
-
results.push(check("Obsidian installed", commandExists("obsidian") ||
|
|
4838
|
+
results.push(check("Obsidian installed", commandExists("obsidian") || fs12.existsSync("/Applications/Obsidian.app")));
|
|
4644
4839
|
results.push(check("Node.js >= 18", nodeVersionOk()));
|
|
4645
4840
|
results.push(
|
|
4646
4841
|
check(
|
|
@@ -4713,7 +4908,7 @@ var doctorCommand = new Command("doctor").description("Check system health and p
|
|
|
4713
4908
|
const emitter = projectionRegistry.get(name);
|
|
4714
4909
|
const [userDest] = emitter.destinations("user");
|
|
4715
4910
|
if (!userDest) continue;
|
|
4716
|
-
const dir =
|
|
4911
|
+
const dir = path14.dirname(userDest.path);
|
|
4717
4912
|
let status;
|
|
4718
4913
|
try {
|
|
4719
4914
|
await stat(dir);
|
|
@@ -4726,7 +4921,7 @@ var doctorCommand = new Command("doctor").description("Check system health and p
|
|
|
4726
4921
|
results.push(
|
|
4727
4922
|
check(
|
|
4728
4923
|
"Squadrant config exists",
|
|
4729
|
-
|
|
4924
|
+
fs12.existsSync(
|
|
4730
4925
|
process.env.SQUADRANT_CONFIG || `${process.env.HOME}/.config/squadrant/config.json`
|
|
4731
4926
|
)
|
|
4732
4927
|
)
|
|
@@ -4799,39 +4994,39 @@ init_dist();
|
|
|
4799
4994
|
init_dist3();
|
|
4800
4995
|
init_dist();
|
|
4801
4996
|
import { Command as Command2 } from "commander";
|
|
4802
|
-
import
|
|
4803
|
-
import
|
|
4997
|
+
import fs13 from "fs";
|
|
4998
|
+
import path15 from "path";
|
|
4804
4999
|
import os6 from "os";
|
|
4805
5000
|
import chalk4 from "chalk";
|
|
4806
5001
|
function findPackageRoot() {
|
|
4807
|
-
let dir =
|
|
5002
|
+
let dir = path15.dirname(new URL(import.meta.url).pathname);
|
|
4808
5003
|
while (dir !== "/") {
|
|
4809
|
-
if (
|
|
4810
|
-
dir =
|
|
5004
|
+
if (fs13.existsSync(path15.join(dir, "package.json"))) return dir;
|
|
5005
|
+
dir = path15.dirname(dir);
|
|
4811
5006
|
}
|
|
4812
5007
|
return process.cwd();
|
|
4813
5008
|
}
|
|
4814
5009
|
function copyDirRecursive(src, dest) {
|
|
4815
|
-
|
|
4816
|
-
for (const entry of
|
|
4817
|
-
const srcPath =
|
|
4818
|
-
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);
|
|
4819
5014
|
if (entry.isDirectory()) {
|
|
4820
5015
|
copyDirRecursive(srcPath, destPath);
|
|
4821
5016
|
} else {
|
|
4822
|
-
|
|
5017
|
+
fs13.copyFileSync(srcPath, destPath);
|
|
4823
5018
|
}
|
|
4824
5019
|
}
|
|
4825
5020
|
}
|
|
4826
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) => {
|
|
4827
5022
|
const hubPath = resolveHome(opts.hub);
|
|
4828
5023
|
const pkgRoot = findPackageRoot();
|
|
4829
|
-
const configDir =
|
|
5024
|
+
const configDir = path15.join(os6.homedir(), ".config", "squadrant");
|
|
4830
5025
|
console.log(chalk4.bold("\nSquadrant Init\n"));
|
|
4831
5026
|
const registry = new WorkspaceRegistry({ obsidian: createObsidianDriver });
|
|
4832
5027
|
try {
|
|
4833
|
-
if (
|
|
4834
|
-
const existing = JSON.parse(
|
|
5028
|
+
if (fs13.existsSync(DEFAULT_CONFIG_PATH)) {
|
|
5029
|
+
const existing = JSON.parse(fs13.readFileSync(DEFAULT_CONFIG_PATH, "utf-8"));
|
|
4835
5030
|
const wsName = existing.workspace ?? "obsidian";
|
|
4836
5031
|
registry.get(wsName);
|
|
4837
5032
|
}
|
|
@@ -4839,7 +5034,7 @@ var initCommand = new Command2("init").description("First-time setup: scaffold h
|
|
|
4839
5034
|
console.log(chalk4.red(` \u2718 ${err.message}`));
|
|
4840
5035
|
return;
|
|
4841
5036
|
}
|
|
4842
|
-
if (
|
|
5037
|
+
if (fs13.existsSync(DEFAULT_CONFIG_PATH)) {
|
|
4843
5038
|
console.log(chalk4.yellow(" \u26A0 Config already exists, skipping creation"));
|
|
4844
5039
|
} else {
|
|
4845
5040
|
const config = getDefaultConfig();
|
|
@@ -4847,37 +5042,37 @@ var initCommand = new Command2("init").description("First-time setup: scaffold h
|
|
|
4847
5042
|
saveConfig(config);
|
|
4848
5043
|
console.log(chalk4.green(` \u2714 Config created at ${DEFAULT_CONFIG_PATH}`));
|
|
4849
5044
|
}
|
|
4850
|
-
const hubTemplate =
|
|
4851
|
-
if (
|
|
5045
|
+
const hubTemplate = path15.join(pkgRoot, "obsidian", "hub");
|
|
5046
|
+
if (fs13.existsSync(hubPath)) {
|
|
4852
5047
|
console.log(chalk4.yellow(` \u26A0 Hub vault already exists at ${hubPath}, skipping`));
|
|
4853
|
-
} else if (
|
|
5048
|
+
} else if (fs13.existsSync(hubTemplate)) {
|
|
4854
5049
|
copyDirRecursive(hubTemplate, hubPath);
|
|
4855
5050
|
console.log(chalk4.green(` \u2714 Hub vault scaffolded at ${hubPath}`));
|
|
4856
5051
|
} else {
|
|
4857
|
-
|
|
5052
|
+
fs13.mkdirSync(hubPath, { recursive: true });
|
|
4858
5053
|
console.log(chalk4.yellow(` \u26A0 Hub template not found; created empty dir at ${hubPath}`));
|
|
4859
5054
|
}
|
|
4860
|
-
const hubDashboardSrc =
|
|
4861
|
-
const hubDashboardDest =
|
|
4862
|
-
if (
|
|
4863
|
-
|
|
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);
|
|
4864
5059
|
console.log(chalk4.green(` \u2714 Dashboard page refreshed at ${hubDashboardDest}`));
|
|
4865
5060
|
}
|
|
4866
|
-
const projectsDir =
|
|
4867
|
-
|
|
5061
|
+
const projectsDir = path15.join(hubPath, "projects");
|
|
5062
|
+
fs13.mkdirSync(projectsDir, { recursive: true });
|
|
4868
5063
|
ensureRuntimeSynced({ sourceRoot: pkgRoot, runtimeRoot: configDir });
|
|
4869
5064
|
console.log(chalk4.green(` \u2714 Runtime assets synced to ${configDir}`));
|
|
4870
|
-
const settingsPath =
|
|
5065
|
+
const settingsPath = path15.join(os6.homedir(), ".claude", "settings.json");
|
|
4871
5066
|
try {
|
|
4872
5067
|
let settings = {};
|
|
4873
|
-
if (
|
|
4874
|
-
settings = JSON.parse(
|
|
5068
|
+
if (fs13.existsSync(settingsPath)) {
|
|
5069
|
+
settings = JSON.parse(fs13.readFileSync(settingsPath, "utf-8"));
|
|
4875
5070
|
}
|
|
4876
5071
|
const env = settings.env || {};
|
|
4877
5072
|
if (env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS !== "1") {
|
|
4878
5073
|
settings.env = { ...env, CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS: "1" };
|
|
4879
|
-
|
|
4880
|
-
|
|
5074
|
+
fs13.mkdirSync(path15.dirname(settingsPath), { recursive: true });
|
|
5075
|
+
fs13.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
4881
5076
|
console.log(chalk4.green(" \u2714 Agent Teams enabled in ~/.claude/settings.json"));
|
|
4882
5077
|
} else {
|
|
4883
5078
|
console.log(chalk4.green(" \u2714 Agent Teams already enabled"));
|
|
@@ -4898,7 +5093,7 @@ var initCommand = new Command2("init").description("First-time setup: scaffold h
|
|
|
4898
5093
|
console.log(chalk4.cyan(` ${hubPath}`));
|
|
4899
5094
|
console.log("");
|
|
4900
5095
|
console.log(" 4. Run " + chalk4.cyan("squadrant doctor") + " to verify setup\n");
|
|
4901
|
-
if (!
|
|
5096
|
+
if (!fs13.existsSync("/Applications/cmux.app")) {
|
|
4902
5097
|
console.log(chalk4.yellow(" \u26A0 cmux not found \u2014 download from https://cmux.dev\n"));
|
|
4903
5098
|
}
|
|
4904
5099
|
});
|
|
@@ -4906,26 +5101,26 @@ var initCommand = new Command2("init").description("First-time setup: scaffold h
|
|
|
4906
5101
|
// packages/cli/src/commands/projects.ts
|
|
4907
5102
|
init_dist();
|
|
4908
5103
|
import { Command as Command3 } from "commander";
|
|
4909
|
-
import
|
|
4910
|
-
import
|
|
5104
|
+
import fs14 from "fs";
|
|
5105
|
+
import path16 from "path";
|
|
4911
5106
|
import chalk5 from "chalk";
|
|
4912
5107
|
function findPackageRoot2() {
|
|
4913
|
-
let dir =
|
|
5108
|
+
let dir = path16.dirname(new URL(import.meta.url).pathname);
|
|
4914
5109
|
while (dir !== "/") {
|
|
4915
|
-
if (
|
|
4916
|
-
dir =
|
|
5110
|
+
if (fs14.existsSync(path16.join(dir, "package.json"))) return dir;
|
|
5111
|
+
dir = path16.dirname(dir);
|
|
4917
5112
|
}
|
|
4918
5113
|
return process.cwd();
|
|
4919
5114
|
}
|
|
4920
5115
|
function copyDirRecursive2(src, dest) {
|
|
4921
|
-
|
|
4922
|
-
for (const entry of
|
|
4923
|
-
const srcPath =
|
|
4924
|
-
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);
|
|
4925
5120
|
if (entry.isDirectory()) {
|
|
4926
5121
|
copyDirRecursive2(srcPath, destPath);
|
|
4927
5122
|
} else {
|
|
4928
|
-
|
|
5123
|
+
fs14.copyFileSync(srcPath, destPath);
|
|
4929
5124
|
}
|
|
4930
5125
|
}
|
|
4931
5126
|
}
|
|
@@ -4961,7 +5156,7 @@ var addCmd = new Command3("add").description("Register a project").argument("<na
|
|
|
4961
5156
|
process.exit(1);
|
|
4962
5157
|
}
|
|
4963
5158
|
const resolvedPath = resolveHome(projectPath);
|
|
4964
|
-
if (!
|
|
5159
|
+
if (!fs14.existsSync(path16.join(resolvedPath, ".git"))) {
|
|
4965
5160
|
console.log(chalk5.yellow(`
|
|
4966
5161
|
\u26A0 No .git found at ${resolvedPath}. Make sure this is the project root, not a parent directory.
|
|
4967
5162
|
`));
|
|
@@ -5014,7 +5209,7 @@ var addCmd = new Command3("add").description("Register a project").argument("<na
|
|
|
5014
5209
|
\u26A0 Group '${group}' already has '${primary[0]}' as primary. Overriding.`));
|
|
5015
5210
|
}
|
|
5016
5211
|
}
|
|
5017
|
-
const spokeVault = opts.spoke ? resolveHome(opts.spoke) :
|
|
5212
|
+
const spokeVault = opts.spoke ? resolveHome(opts.spoke) : path16.join(config.hubVault, "spokes", name);
|
|
5018
5213
|
const project = {
|
|
5019
5214
|
path: resolvedPath,
|
|
5020
5215
|
captainName,
|
|
@@ -5028,20 +5223,20 @@ var addCmd = new Command3("add").description("Register a project").argument("<na
|
|
|
5028
5223
|
console.log(chalk5.green(`
|
|
5029
5224
|
\u2714 Project '${name}' registered`));
|
|
5030
5225
|
const pkgRoot = findPackageRoot2();
|
|
5031
|
-
const spokeTemplate =
|
|
5032
|
-
if (
|
|
5226
|
+
const spokeTemplate = path16.join(pkgRoot, "obsidian", "spoke");
|
|
5227
|
+
if (fs14.existsSync(spokeVault)) {
|
|
5033
5228
|
console.log(chalk5.yellow(` \u26A0 Spoke vault already exists at ${spokeVault}, skipping scaffold`));
|
|
5034
|
-
} else if (
|
|
5229
|
+
} else if (fs14.existsSync(spokeTemplate)) {
|
|
5035
5230
|
copyDirRecursive2(spokeTemplate, spokeVault);
|
|
5036
|
-
const statusPath =
|
|
5037
|
-
if (
|
|
5038
|
-
const content =
|
|
5231
|
+
const statusPath = path16.join(spokeVault, "status.md");
|
|
5232
|
+
if (fs14.existsSync(statusPath)) {
|
|
5233
|
+
const content = fs14.readFileSync(statusPath, "utf-8");
|
|
5039
5234
|
const updated = content.replace(/^project: unnamed/m, `project: ${name}`);
|
|
5040
|
-
|
|
5235
|
+
fs14.writeFileSync(statusPath, updated);
|
|
5041
5236
|
}
|
|
5042
5237
|
console.log(chalk5.green(` \u2714 Spoke vault scaffolded at ${spokeVault}`));
|
|
5043
5238
|
} else {
|
|
5044
|
-
|
|
5239
|
+
fs14.mkdirSync(spokeVault, { recursive: true });
|
|
5045
5240
|
console.log(chalk5.yellow(` \u26A0 Spoke template not found; created empty dir at ${spokeVault}`));
|
|
5046
5241
|
}
|
|
5047
5242
|
console.log("");
|
|
@@ -5142,10 +5337,10 @@ init_dist4();
|
|
|
5142
5337
|
init_dist();
|
|
5143
5338
|
import { Command as Command5 } from "commander";
|
|
5144
5339
|
import { execSync as execSync9 } from "child_process";
|
|
5145
|
-
import
|
|
5340
|
+
import path17 from "path";
|
|
5146
5341
|
import os7 from "os";
|
|
5147
5342
|
import chalk7 from "chalk";
|
|
5148
|
-
var TEMPLATES_DIR =
|
|
5343
|
+
var TEMPLATES_DIR = path17.join(os7.homedir(), ".config", "squadrant", "templates");
|
|
5149
5344
|
var TASK_PROMPTS = {
|
|
5150
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.",
|
|
5151
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.",
|
|
@@ -5178,7 +5373,7 @@ async function runCommandSpawn(input) {
|
|
|
5178
5373
|
if (!agent) {
|
|
5179
5374
|
throw new Error(`Unknown agent '${agentName}'. Known: claude, codex, gemini, opencode.`);
|
|
5180
5375
|
}
|
|
5181
|
-
const promptFile =
|
|
5376
|
+
const promptFile = path17.join(TEMPLATES_DIR, `command.${agent.templateSuffix}.md`);
|
|
5182
5377
|
const cliCommand = agent.buildCommand({
|
|
5183
5378
|
prompt,
|
|
5184
5379
|
workdir: process.cwd(),
|
|
@@ -5205,8 +5400,8 @@ var commandCommand = new Command5("command").description("Spawn a one-shot Comma
|
|
|
5205
5400
|
init_dist();
|
|
5206
5401
|
init_dist();
|
|
5207
5402
|
import { Command as Command9 } from "commander";
|
|
5208
|
-
import
|
|
5209
|
-
import
|
|
5403
|
+
import fs15 from "fs";
|
|
5404
|
+
import path18 from "path";
|
|
5210
5405
|
import os8 from "os";
|
|
5211
5406
|
import chalk9 from "chalk";
|
|
5212
5407
|
|
|
@@ -5874,7 +6069,7 @@ function writePerCrewOpencodeConfig(o) {
|
|
|
5874
6069
|
|
|
5875
6070
|
// packages/cli/src/commands/crew.ts
|
|
5876
6071
|
init_dist2();
|
|
5877
|
-
var TEMPLATES_DIR2 =
|
|
6072
|
+
var TEMPLATES_DIR2 = path18.join(os8.homedir(), ".config", "squadrant", "templates");
|
|
5878
6073
|
async function runCrewSpawn(input) {
|
|
5879
6074
|
const config = loadConfig();
|
|
5880
6075
|
const proj = config.projects[input.project];
|
|
@@ -5922,8 +6117,8 @@ async function runCrewSpawn(input) {
|
|
|
5922
6117
|
throw new Error(`Unknown agent '${agentName}'. Known: claude, codex, gemini, opencode.`);
|
|
5923
6118
|
}
|
|
5924
6119
|
if (agentName === "codex") {
|
|
5925
|
-
const codexRoleFile =
|
|
5926
|
-
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;
|
|
5927
6122
|
return runCodexInteractiveSpawn({
|
|
5928
6123
|
project: input.project,
|
|
5929
6124
|
task: input.task,
|
|
@@ -5936,7 +6131,7 @@ async function runCrewSpawn(input) {
|
|
|
5936
6131
|
roleInstructions
|
|
5937
6132
|
});
|
|
5938
6133
|
}
|
|
5939
|
-
const promptFile =
|
|
6134
|
+
const promptFile = path18.join(TEMPLATES_DIR2, `crew.${agent.templateSuffix}.md`);
|
|
5940
6135
|
const interactive = agent.name === "claude" || agent.name === "opencode";
|
|
5941
6136
|
const crewRole = config.defaults.roles?.crew;
|
|
5942
6137
|
const configModel = crewRole && crewRole.agent === agent.name ? crewRole.model : void 0;
|
|
@@ -5993,7 +6188,7 @@ ${buildCompletionProtocol(rec.id, input.project)}`, preLaunchScreen);
|
|
|
5993
6188
|
});
|
|
5994
6189
|
const rec = await squadrantdCall(req);
|
|
5995
6190
|
const opencodeConfigPath = writePerCrewOpencodeConfig({
|
|
5996
|
-
stateRoot:
|
|
6191
|
+
stateRoot: path18.join(os8.homedir(), ".config", "squadrant", "state"),
|
|
5997
6192
|
project: input.project,
|
|
5998
6193
|
taskId: rec.id,
|
|
5999
6194
|
// CP3 opt-in: --approval gates bash so the captain approves shell commands.
|
|
@@ -6233,11 +6428,11 @@ init_dist3();
|
|
|
6233
6428
|
init_dist();
|
|
6234
6429
|
init_dist();
|
|
6235
6430
|
import { Command as Command10 } from "commander";
|
|
6236
|
-
import
|
|
6237
|
-
import
|
|
6431
|
+
import fs16 from "fs";
|
|
6432
|
+
import path19 from "path";
|
|
6238
6433
|
import os9 from "os";
|
|
6239
6434
|
import chalk10 from "chalk";
|
|
6240
|
-
var TEMPLATES_DIR3 =
|
|
6435
|
+
var TEMPLATES_DIR3 = path19.join(os9.homedir(), ".config", "squadrant", "templates");
|
|
6241
6436
|
var SIDE_ROLES = ["research", "debug"];
|
|
6242
6437
|
function shellQuote2(p) {
|
|
6243
6438
|
return "'" + p.replace(/'/g, "'\\''") + "'";
|
|
@@ -6328,7 +6523,7 @@ async function runSideSpawn(input) {
|
|
|
6328
6523
|
throw new Error(`Unknown agent '${agentName}'. Known: claude, codex, gemini, opencode.`);
|
|
6329
6524
|
}
|
|
6330
6525
|
const sideModel = sideRole?.model;
|
|
6331
|
-
const promptFile =
|
|
6526
|
+
const promptFile = path19.join(
|
|
6332
6527
|
TEMPLATES_DIR3,
|
|
6333
6528
|
`side.${input.role}.${agent.templateSuffix}.md`
|
|
6334
6529
|
);
|
|
@@ -6339,7 +6534,7 @@ async function runSideSpawn(input) {
|
|
|
6339
6534
|
prompt: input.topic,
|
|
6340
6535
|
workdir: spawnCwd,
|
|
6341
6536
|
role: "side",
|
|
6342
|
-
promptFile:
|
|
6537
|
+
promptFile: fs16.existsSync(promptFile) ? promptFile : void 0,
|
|
6343
6538
|
interactive: true,
|
|
6344
6539
|
permissionMode: config.defaults.permissions?.crew ?? "auto",
|
|
6345
6540
|
...sideModel ? { model: sideModel } : {}
|
|
@@ -6396,7 +6591,7 @@ async function runSideClose(project, name) {
|
|
|
6396
6591
|
project,
|
|
6397
6592
|
name
|
|
6398
6593
|
);
|
|
6399
|
-
if (
|
|
6594
|
+
if (fs16.existsSync(wtPath)) {
|
|
6400
6595
|
try {
|
|
6401
6596
|
removeWorktree(proj.path, wtPath);
|
|
6402
6597
|
} catch (e) {
|
|
@@ -6624,8 +6819,8 @@ function renderDashboard(rows, opts) {
|
|
|
6624
6819
|
|
|
6625
6820
|
// packages/web/dist/sync-hub.js
|
|
6626
6821
|
init_dist();
|
|
6627
|
-
import
|
|
6628
|
-
import
|
|
6822
|
+
import fs17 from "fs";
|
|
6823
|
+
import path20 from "path";
|
|
6629
6824
|
function buildMirrorMarkdown(s) {
|
|
6630
6825
|
const fenced = "```";
|
|
6631
6826
|
return [
|
|
@@ -6651,15 +6846,15 @@ function buildMirrorMarkdown(s) {
|
|
|
6651
6846
|
function syncHub(deps) {
|
|
6652
6847
|
if (!deps.config.hubVault)
|
|
6653
6848
|
return [];
|
|
6654
|
-
const writeFile5 = deps.writeFile ?? ((p, c) =>
|
|
6655
|
-
const mkdir5 = deps.mkdir ?? ((p) =>
|
|
6656
|
-
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");
|
|
6657
6852
|
mkdir5(projectsDir);
|
|
6658
6853
|
const out = [];
|
|
6659
6854
|
for (const s of deps.statuses) {
|
|
6660
6855
|
if (s.state === "unknown")
|
|
6661
6856
|
continue;
|
|
6662
|
-
const hubPath =
|
|
6857
|
+
const hubPath = path20.join(projectsDir, `${s.project}.md`);
|
|
6663
6858
|
try {
|
|
6664
6859
|
writeFile5(hubPath, buildMirrorMarkdown(s));
|
|
6665
6860
|
out.push({ project: s.project, hubPath });
|
|
@@ -7548,13 +7743,13 @@ init_dist3();
|
|
|
7548
7743
|
init_dist2();
|
|
7549
7744
|
import { Command as Command12 } from "commander";
|
|
7550
7745
|
import { execSync as execSync11 } from "child_process";
|
|
7551
|
-
import
|
|
7552
|
-
import
|
|
7746
|
+
import fs18 from "fs";
|
|
7747
|
+
import path21 from "path";
|
|
7553
7748
|
import os10 from "os";
|
|
7554
7749
|
import chalk13 from "chalk";
|
|
7555
7750
|
var CMUX_APP = "/Applications/cmux.app";
|
|
7556
|
-
var TEMPLATES_DIR4 =
|
|
7557
|
-
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");
|
|
7558
7753
|
function ensureCmuxReady() {
|
|
7559
7754
|
if (isInsideCmux()) return;
|
|
7560
7755
|
console.log(chalk13.yellow("\n Not running inside cmux. Opening cmux app...\n"));
|
|
@@ -7661,12 +7856,12 @@ var launchCommand = new Command12("launch").description(
|
|
|
7661
7856
|
}
|
|
7662
7857
|
if (opts.all) {
|
|
7663
7858
|
const hubPath = resolveHome(config.hubVault);
|
|
7664
|
-
|
|
7859
|
+
fs18.mkdirSync(hubPath, { recursive: true });
|
|
7665
7860
|
console.log(chalk13.bold("\nLaunching all captain workspaces\n"));
|
|
7666
7861
|
for (const [name, proj] of Object.entries(config.projects)) {
|
|
7667
7862
|
const projPath = resolveHome(proj.path);
|
|
7668
7863
|
const spokePath = resolveHome(proj.spokeVault);
|
|
7669
|
-
if (!
|
|
7864
|
+
if (!fs18.existsSync(spokePath)) {
|
|
7670
7865
|
const spokeDriver = new WorkspaceRegistry({ obsidian: createObsidianDriver }).forProject(name, config);
|
|
7671
7866
|
await ensureSpokeLayout(spokeDriver);
|
|
7672
7867
|
console.log(chalk13.cyan(` \u2714 Created spoke vault at ${spokePath}`));
|
|
@@ -7697,7 +7892,7 @@ var launchCommand = new Command12("launch").description(
|
|
|
7697
7892
|
const proj = config.projects[project];
|
|
7698
7893
|
const projPath = resolveHome(proj.path);
|
|
7699
7894
|
const spokePath = resolveHome(proj.spokeVault);
|
|
7700
|
-
if (!
|
|
7895
|
+
if (!fs18.existsSync(spokePath)) {
|
|
7701
7896
|
const spokeDriver = new WorkspaceRegistry({ obsidian: createObsidianDriver }).forProject(project, config);
|
|
7702
7897
|
await ensureSpokeLayout(spokeDriver);
|
|
7703
7898
|
console.log(chalk13.cyan(` \u2714 Created spoke vault at ${spokePath}`));
|
|
@@ -7832,23 +8027,31 @@ Shutting down captain workspace for '${project}'...
|
|
|
7832
8027
|
// packages/cli/src/commands/feedback.ts
|
|
7833
8028
|
init_dist();
|
|
7834
8029
|
import { Command as Command14 } from "commander";
|
|
7835
|
-
import
|
|
8030
|
+
import fs19 from "fs";
|
|
7836
8031
|
import os11 from "os";
|
|
7837
|
-
import
|
|
8032
|
+
import path22 from "path";
|
|
8033
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
7838
8034
|
import { execSync as execSync12 } from "child_process";
|
|
7839
8035
|
import chalk15 from "chalk";
|
|
7840
8036
|
var REPO_URL = "https://github.com/tu11aa/squadrant";
|
|
8037
|
+
function readPkgVersion() {
|
|
8038
|
+
try {
|
|
8039
|
+
const pkgPath = path22.join(path22.dirname(fileURLToPath3(import.meta.url)), "..", "package.json");
|
|
8040
|
+
return JSON.parse(fs19.readFileSync(pkgPath, "utf-8")).version ?? "unknown";
|
|
8041
|
+
} catch {
|
|
8042
|
+
return "unknown";
|
|
8043
|
+
}
|
|
8044
|
+
}
|
|
7841
8045
|
function readMetrics(metricsPath) {
|
|
7842
8046
|
try {
|
|
7843
|
-
return JSON.parse(
|
|
8047
|
+
return JSON.parse(fs19.readFileSync(metricsPath, "utf-8"));
|
|
7844
8048
|
} catch {
|
|
7845
8049
|
return {};
|
|
7846
8050
|
}
|
|
7847
8051
|
}
|
|
7848
|
-
function buildIssueUrl(metrics) {
|
|
8052
|
+
function buildIssueUrl(metrics, squadrantVersion) {
|
|
7849
8053
|
const nodeVersion = process.versions.node;
|
|
7850
8054
|
const platform = process.platform;
|
|
7851
|
-
const squadrantVersion = "0.1.0";
|
|
7852
8055
|
const body = [
|
|
7853
8056
|
"## Feedback / Bug Report",
|
|
7854
8057
|
"",
|
|
@@ -7879,9 +8082,10 @@ function buildIssueUrl(metrics) {
|
|
|
7879
8082
|
}
|
|
7880
8083
|
var feedbackCommand = new Command14("feedback").description("Open a pre-filled GitHub issue for feedback or bug reports").action(() => {
|
|
7881
8084
|
const config = loadConfig();
|
|
7882
|
-
const metricsPath = config.metrics?.path ||
|
|
8085
|
+
const metricsPath = config.metrics?.path || path22.join(os11.homedir(), ".config", "squadrant", "metrics.json");
|
|
7883
8086
|
const metrics = readMetrics(metricsPath);
|
|
7884
|
-
const
|
|
8087
|
+
const version = readStamp(config) ?? readPkgVersion();
|
|
8088
|
+
const issueUrl = buildIssueUrl(metrics, version);
|
|
7885
8089
|
console.log(chalk15.bold("\nOpening feedback issue in browser...\n"));
|
|
7886
8090
|
console.log(chalk15.dim(` URL: ${issueUrl.substring(0, 80)}...
|
|
7887
8091
|
`));
|
|
@@ -7900,8 +8104,8 @@ init_dist();
|
|
|
7900
8104
|
init_dist();
|
|
7901
8105
|
init_dist3();
|
|
7902
8106
|
import { Command as Command15 } from "commander";
|
|
7903
|
-
import
|
|
7904
|
-
import
|
|
8107
|
+
import fs20 from "fs";
|
|
8108
|
+
import path23 from "path";
|
|
7905
8109
|
import chalk16 from "chalk";
|
|
7906
8110
|
import matter3 from "gray-matter";
|
|
7907
8111
|
function getDateStr(yesterday) {
|
|
@@ -7910,11 +8114,11 @@ function getDateStr(yesterday) {
|
|
|
7910
8114
|
async function getProjectStandup(name, project, dateStr, registry, config) {
|
|
7911
8115
|
const workspace = registry.forProject(name, config);
|
|
7912
8116
|
const spokeVault = resolveHome(project.spokeVault);
|
|
7913
|
-
const statusFile =
|
|
8117
|
+
const statusFile = path23.join(spokeVault, "status.md");
|
|
7914
8118
|
let status = {};
|
|
7915
|
-
if (
|
|
8119
|
+
if (fs20.existsSync(statusFile)) {
|
|
7916
8120
|
try {
|
|
7917
|
-
status = matter3(
|
|
8121
|
+
status = matter3(fs20.readFileSync(statusFile, "utf-8")).data;
|
|
7918
8122
|
} catch {
|
|
7919
8123
|
}
|
|
7920
8124
|
}
|
|
@@ -8032,15 +8236,15 @@ init_dist();
|
|
|
8032
8236
|
init_dist();
|
|
8033
8237
|
init_dist3();
|
|
8034
8238
|
import { Command as Command16 } from "commander";
|
|
8035
|
-
import
|
|
8036
|
-
import
|
|
8239
|
+
import fs21 from "fs";
|
|
8240
|
+
import path24 from "path";
|
|
8037
8241
|
import chalk17 from "chalk";
|
|
8038
8242
|
import matter4 from "gray-matter";
|
|
8039
8243
|
function readStatus(spokeVault) {
|
|
8040
|
-
const statusFile =
|
|
8041
|
-
if (!
|
|
8244
|
+
const statusFile = path24.join(spokeVault, "status.md");
|
|
8245
|
+
if (!fs21.existsSync(statusFile)) return {};
|
|
8042
8246
|
try {
|
|
8043
|
-
return matter4(
|
|
8247
|
+
return matter4(fs21.readFileSync(statusFile, "utf-8")).data;
|
|
8044
8248
|
} catch {
|
|
8045
8249
|
return {};
|
|
8046
8250
|
}
|
|
@@ -8350,9 +8554,9 @@ workspaceCommand.command("read").description("Print the contents of a scope-rela
|
|
|
8350
8554
|
const config = loadConfig();
|
|
8351
8555
|
const registry = buildRegistry2();
|
|
8352
8556
|
try {
|
|
8353
|
-
const { projectTarget, path:
|
|
8557
|
+
const { projectTarget, path: path27 } = resolveTargetAndPath(arg1, arg2, !!opts.hub);
|
|
8354
8558
|
const driver = resolveDriver(registry, config, projectTarget, !!opts.hub);
|
|
8355
|
-
const content = await driver.read(
|
|
8559
|
+
const content = await driver.read(path27);
|
|
8356
8560
|
process.stdout.write(content);
|
|
8357
8561
|
} catch (err) {
|
|
8358
8562
|
console.error(chalk19.red(err.message));
|
|
@@ -8364,26 +8568,26 @@ workspaceCommand.command("write").description("Write content to a scope-relative
|
|
|
8364
8568
|
const registry = buildRegistry2();
|
|
8365
8569
|
try {
|
|
8366
8570
|
let projectTarget;
|
|
8367
|
-
let
|
|
8571
|
+
let path27;
|
|
8368
8572
|
let rawContent;
|
|
8369
8573
|
if (opts.hub) {
|
|
8370
8574
|
if (arg3 !== void 0) {
|
|
8371
8575
|
throw new Error("With --hub, pass only the path and content");
|
|
8372
8576
|
}
|
|
8373
8577
|
projectTarget = void 0;
|
|
8374
|
-
|
|
8578
|
+
path27 = arg1;
|
|
8375
8579
|
rawContent = arg2;
|
|
8376
8580
|
} else {
|
|
8377
8581
|
if (arg3 === void 0) {
|
|
8378
8582
|
throw new Error("Missing content \u2014 usage: <project> <path> <content>");
|
|
8379
8583
|
}
|
|
8380
8584
|
projectTarget = arg1;
|
|
8381
|
-
|
|
8585
|
+
path27 = arg2;
|
|
8382
8586
|
rawContent = arg3;
|
|
8383
8587
|
}
|
|
8384
8588
|
const driver = resolveDriver(registry, config, projectTarget, !!opts.hub);
|
|
8385
8589
|
const payload = rawContent === "-" ? await readStdin() : rawContent;
|
|
8386
|
-
await driver.write(
|
|
8590
|
+
await driver.write(path27, payload);
|
|
8387
8591
|
} catch (err) {
|
|
8388
8592
|
console.error(chalk19.red(err.message));
|
|
8389
8593
|
process.exit(1);
|
|
@@ -8393,9 +8597,9 @@ workspaceCommand.command("list").description("List entries in a scope-relative d
|
|
|
8393
8597
|
const config = loadConfig();
|
|
8394
8598
|
const registry = buildRegistry2();
|
|
8395
8599
|
try {
|
|
8396
|
-
const { projectTarget, path:
|
|
8600
|
+
const { projectTarget, path: path27 } = resolveTargetAndPath(arg1, arg2, !!opts.hub);
|
|
8397
8601
|
const driver = resolveDriver(registry, config, projectTarget, !!opts.hub);
|
|
8398
|
-
const entries = await driver.list(
|
|
8602
|
+
const entries = await driver.list(path27);
|
|
8399
8603
|
for (const entry of entries) console.log(entry);
|
|
8400
8604
|
} catch (err) {
|
|
8401
8605
|
console.error(chalk19.red(err.message));
|
|
@@ -8406,9 +8610,9 @@ workspaceCommand.command("exists").description("Exit 0 if path exists, 1 if not"
|
|
|
8406
8610
|
const config = loadConfig();
|
|
8407
8611
|
const registry = buildRegistry2();
|
|
8408
8612
|
try {
|
|
8409
|
-
const { projectTarget, path:
|
|
8613
|
+
const { projectTarget, path: path27 } = resolveTargetAndPath(arg1, arg2, !!opts.hub);
|
|
8410
8614
|
const driver = resolveDriver(registry, config, projectTarget, !!opts.hub);
|
|
8411
|
-
const ok = await driver.exists(
|
|
8615
|
+
const ok = await driver.exists(path27);
|
|
8412
8616
|
process.exit(ok ? 0 : 1);
|
|
8413
8617
|
} catch (err) {
|
|
8414
8618
|
console.error(chalk19.red(err.message));
|
|
@@ -8419,9 +8623,9 @@ workspaceCommand.command("mkdir").description("Recursively create a scope-relati
|
|
|
8419
8623
|
const config = loadConfig();
|
|
8420
8624
|
const registry = buildRegistry2();
|
|
8421
8625
|
try {
|
|
8422
|
-
const { projectTarget, path:
|
|
8626
|
+
const { projectTarget, path: path27 } = resolveTargetAndPath(arg1, arg2, !!opts.hub);
|
|
8423
8627
|
const driver = resolveDriver(registry, config, projectTarget, !!opts.hub);
|
|
8424
|
-
await driver.mkdir(
|
|
8628
|
+
await driver.mkdir(path27);
|
|
8425
8629
|
} catch (err) {
|
|
8426
8630
|
console.error(chalk19.red(err.message));
|
|
8427
8631
|
process.exit(1);
|
|
@@ -8460,9 +8664,9 @@ init_dist3();
|
|
|
8460
8664
|
init_dist();
|
|
8461
8665
|
import { Command as Command20 } from "commander";
|
|
8462
8666
|
import chalk21 from "chalk";
|
|
8463
|
-
import
|
|
8464
|
-
import
|
|
8465
|
-
import { fileURLToPath as
|
|
8667
|
+
import fs22 from "fs";
|
|
8668
|
+
import path25 from "path";
|
|
8669
|
+
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
8466
8670
|
function parseScope(v) {
|
|
8467
8671
|
if (v !== "user" && v !== "project") {
|
|
8468
8672
|
throw new Error("--scope must be 'user' or 'project'");
|
|
@@ -8470,10 +8674,10 @@ function parseScope(v) {
|
|
|
8470
8674
|
return v;
|
|
8471
8675
|
}
|
|
8472
8676
|
function findPackageRoot3() {
|
|
8473
|
-
let dir =
|
|
8677
|
+
let dir = path25.dirname(fileURLToPath4(import.meta.url));
|
|
8474
8678
|
while (dir !== "/" && dir !== "") {
|
|
8475
|
-
if (
|
|
8476
|
-
dir =
|
|
8679
|
+
if (fs22.existsSync(path25.join(dir, "package.json"))) return dir;
|
|
8680
|
+
dir = path25.dirname(dir);
|
|
8477
8681
|
}
|
|
8478
8682
|
return process.cwd();
|
|
8479
8683
|
}
|
|
@@ -8667,12 +8871,12 @@ init_dist();
|
|
|
8667
8871
|
init_dist();
|
|
8668
8872
|
init_dist();
|
|
8669
8873
|
import { Command as Command22 } from "commander";
|
|
8670
|
-
import
|
|
8671
|
-
import { fileURLToPath as
|
|
8874
|
+
import fs23 from "fs";
|
|
8875
|
+
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
8672
8876
|
import { dirname as dirname5, join as join19 } from "path";
|
|
8673
8877
|
import chalk22 from "chalk";
|
|
8674
8878
|
function runConfigCheck(opts) {
|
|
8675
|
-
const raw = JSON.parse(
|
|
8879
|
+
const raw = JSON.parse(fs23.readFileSync(opts.configPath, "utf-8"));
|
|
8676
8880
|
const def = getDefaultConfig();
|
|
8677
8881
|
const items = detectDrift(raw, def);
|
|
8678
8882
|
let working = raw;
|
|
@@ -8689,10 +8893,40 @@ function runConfigCheck(opts) {
|
|
|
8689
8893
|
stamped = true;
|
|
8690
8894
|
}
|
|
8691
8895
|
if (opts.fix || opts.accept || stamped) {
|
|
8692
|
-
|
|
8896
|
+
fs23.writeFileSync(opts.configPath, JSON.stringify(working, null, 2) + "\n");
|
|
8693
8897
|
}
|
|
8694
8898
|
return { items, applied, remaining, stamped };
|
|
8695
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
|
+
}
|
|
8696
8930
|
var SEV_COLOR = {
|
|
8697
8931
|
info: chalk22.green,
|
|
8698
8932
|
advisory: chalk22.yellow,
|
|
@@ -8713,8 +8947,8 @@ function printItems(items) {
|
|
|
8713
8947
|
}
|
|
8714
8948
|
var configCommand = new Command22("config").description("Inspect and reconcile squadrant config");
|
|
8715
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) => {
|
|
8716
|
-
const pkgVersion =
|
|
8717
|
-
if (!
|
|
8950
|
+
const pkgVersion = readPkgVersion2();
|
|
8951
|
+
if (!fs23.existsSync(DEFAULT_CONFIG_PATH)) {
|
|
8718
8952
|
console.log(chalk22.yellow("No config found \u2014 run `squadrant init` first."));
|
|
8719
8953
|
return;
|
|
8720
8954
|
}
|
|
@@ -8741,9 +8975,27 @@ ${judgment.length} item(s) need review \u2014 run the config-doctor skill, or \`
|
|
|
8741
8975
|
console.log(chalk22.green("\n\u2714 Config reconciled and stamped."));
|
|
8742
8976
|
}
|
|
8743
8977
|
});
|
|
8744
|
-
|
|
8745
|
-
|
|
8746
|
-
|
|
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
|
+
});
|
|
8996
|
+
function readPkgVersion2() {
|
|
8997
|
+
const pkgPath = join19(dirname5(fileURLToPath5(import.meta.url)), "..", "package.json");
|
|
8998
|
+
return JSON.parse(fs23.readFileSync(pkgPath, "utf-8")).version;
|
|
8747
8999
|
}
|
|
8748
9000
|
|
|
8749
9001
|
// packages/cli/src/commands/heal.ts
|
|
@@ -9009,8 +9261,8 @@ var cmuxCommand = new Command25("cmux").description("cmux integration helpers").
|
|
|
9009
9261
|
|
|
9010
9262
|
// packages/cli/src/commands/effort.ts
|
|
9011
9263
|
init_dist();
|
|
9012
|
-
import
|
|
9013
|
-
import
|
|
9264
|
+
import fs24 from "fs";
|
|
9265
|
+
import path26 from "path";
|
|
9014
9266
|
import { Command as Command26 } from "commander";
|
|
9015
9267
|
import chalk26 from "chalk";
|
|
9016
9268
|
var VALID_EFFORTS = ["max", "balance", "low"];
|
|
@@ -9037,9 +9289,9 @@ function runEffortSet(value, configPath = DEFAULT_CONFIG_PATH) {
|
|
|
9037
9289
|
}
|
|
9038
9290
|
function canonical(p) {
|
|
9039
9291
|
try {
|
|
9040
|
-
return
|
|
9292
|
+
return fs24.realpathSync(p);
|
|
9041
9293
|
} catch {
|
|
9042
|
-
return
|
|
9294
|
+
return path26.resolve(p);
|
|
9043
9295
|
}
|
|
9044
9296
|
}
|
|
9045
9297
|
async function notifyCaptainsOfEffort(effort, config, driver, cwd = process.cwd()) {
|
|
@@ -9083,19 +9335,232 @@ var effortCommand = new Command26("effort").description("Get or set the global c
|
|
|
9083
9335
|
}
|
|
9084
9336
|
});
|
|
9085
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
|
+
|
|
9086
9551
|
// packages/cli/src/index.ts
|
|
9087
9552
|
init_dist();
|
|
9088
9553
|
init_dist();
|
|
9089
9554
|
init_dist();
|
|
9090
|
-
var __dirname =
|
|
9091
|
-
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"));
|
|
9092
9557
|
ensureRuntimeSynced({
|
|
9093
|
-
sourceRoot:
|
|
9094
|
-
runtimeRoot:
|
|
9558
|
+
sourceRoot: join22(__dirname, ".."),
|
|
9559
|
+
runtimeRoot: join22(homedir14(), ".config", "squadrant")
|
|
9095
9560
|
});
|
|
9096
9561
|
if (process.argv[2] !== "config") {
|
|
9097
9562
|
try {
|
|
9098
|
-
const cfgPath =
|
|
9563
|
+
const cfgPath = join22(homedir14(), ".config", "squadrant", "config.json");
|
|
9099
9564
|
if (existsSync10(cfgPath)) {
|
|
9100
9565
|
const cfg = JSON.parse(readFileSync11(cfgPath, "utf-8"));
|
|
9101
9566
|
if (needsCheck(cfg, pkg.version)) {
|
|
@@ -9120,7 +9585,7 @@ if (process.argv[2] !== "config") {
|
|
|
9120
9585
|
if (!process.env.SQUADRANT_DAEMON_SKIP) {
|
|
9121
9586
|
ensureDaemon();
|
|
9122
9587
|
}
|
|
9123
|
-
var program = new
|
|
9588
|
+
var program = new Command28();
|
|
9124
9589
|
program.name("squadrant").description("Multi-project orchestration for your coding agents (Claude, Codex, opencode, Gemini)").version(pkg.version);
|
|
9125
9590
|
program.addCommand(doctorCommand);
|
|
9126
9591
|
program.addCommand(initCommand);
|
|
@@ -9146,6 +9611,7 @@ program.addCommand(healCommand);
|
|
|
9146
9611
|
program.addCommand(groupCommand);
|
|
9147
9612
|
program.addCommand(cmuxCommand);
|
|
9148
9613
|
program.addCommand(effortCommand);
|
|
9614
|
+
program.addCommand(telegramCommand);
|
|
9149
9615
|
program.parseAsync().catch((e) => {
|
|
9150
9616
|
process.stderr.write(`error: ${e instanceof Error ? e.message : String(e)}
|
|
9151
9617
|
`);
|