codeam-cli 2.61.77 → 2.61.78
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/dist/index.js +476 -111
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,12 @@ All notable changes to `codeam-cli` are documented here.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [2.61.77] — 2026-07-31
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **shared:** Add Convex (convex.dev) database integration
|
|
12
|
+
|
|
7
13
|
## [2.61.76] — 2026-07-30
|
|
8
14
|
|
|
9
15
|
### Added
|
package/dist/index.js
CHANGED
|
@@ -1666,6 +1666,9 @@ var INTEGRATION_REGISTRY = {
|
|
|
1666
1666
|
}
|
|
1667
1667
|
}
|
|
1668
1668
|
};
|
|
1669
|
+
function getEnabledIntegrations() {
|
|
1670
|
+
return Object.values(INTEGRATION_REGISTRY).filter((m) => m.enabled);
|
|
1671
|
+
}
|
|
1669
1672
|
function getIntegration(id) {
|
|
1670
1673
|
const meta = INTEGRATION_REGISTRY[id];
|
|
1671
1674
|
if (!meta) throw new Error(`Unknown integration id: ${id}`);
|
|
@@ -1675,6 +1678,145 @@ function isKnownIntegrationId(id) {
|
|
|
1675
1678
|
return id in INTEGRATION_REGISTRY;
|
|
1676
1679
|
}
|
|
1677
1680
|
|
|
1681
|
+
// ../../packages/shared/src/integrations/stack-detect.ts
|
|
1682
|
+
var DEP_TO_INTEGRATION = {
|
|
1683
|
+
// errors / observability
|
|
1684
|
+
"@sentry/node": "sentry",
|
|
1685
|
+
"@sentry/react": "sentry",
|
|
1686
|
+
"@sentry/nextjs": "sentry",
|
|
1687
|
+
"@sentry/browser": "sentry",
|
|
1688
|
+
"sentry-sdk": "sentry",
|
|
1689
|
+
"dd-trace": "datadog",
|
|
1690
|
+
"datadog-api-client": "datadog",
|
|
1691
|
+
"datadog-metrics": "datadog",
|
|
1692
|
+
// analytics
|
|
1693
|
+
"posthog-js": "posthog",
|
|
1694
|
+
"posthog-node": "posthog",
|
|
1695
|
+
posthog: "posthog",
|
|
1696
|
+
mixpanel: "mixpanel",
|
|
1697
|
+
"mixpanel-browser": "mixpanel",
|
|
1698
|
+
// database / backend platforms
|
|
1699
|
+
convex: "convex",
|
|
1700
|
+
"@supabase/supabase-js": "supabase",
|
|
1701
|
+
"supabase": "supabase",
|
|
1702
|
+
// infra / deploy
|
|
1703
|
+
vercel: "vercel",
|
|
1704
|
+
"@vercel/node": "vercel",
|
|
1705
|
+
wrangler: "cloudflare",
|
|
1706
|
+
// comms
|
|
1707
|
+
"@slack/web-api": "slack",
|
|
1708
|
+
"@slack/bolt": "slack",
|
|
1709
|
+
"discord.js": "discord",
|
|
1710
|
+
"discord-py": "discord",
|
|
1711
|
+
"discord": "discord",
|
|
1712
|
+
// trackers / docs / design
|
|
1713
|
+
"@linear/sdk": "linear",
|
|
1714
|
+
"@notionhq/client": "notion",
|
|
1715
|
+
"jira.js": "jira",
|
|
1716
|
+
jira: "jira",
|
|
1717
|
+
newman: "postman",
|
|
1718
|
+
"figma-api": "figma",
|
|
1719
|
+
"figma-js": "figma",
|
|
1720
|
+
// email / automation
|
|
1721
|
+
resend: "resend",
|
|
1722
|
+
n8n: "n8n"
|
|
1723
|
+
};
|
|
1724
|
+
var DEP_PREFIX_TO_INTEGRATION = [
|
|
1725
|
+
["@sentry/", "sentry"],
|
|
1726
|
+
["@vercel/", "vercel"],
|
|
1727
|
+
["@cloudflare/", "cloudflare"],
|
|
1728
|
+
["@supabase/", "supabase"],
|
|
1729
|
+
["@slack/", "slack"],
|
|
1730
|
+
["@datadog/", "datadog"],
|
|
1731
|
+
["@linear/", "linear"],
|
|
1732
|
+
["@notionhq/", "notion"]
|
|
1733
|
+
];
|
|
1734
|
+
var FRONTEND_MARKERS = [
|
|
1735
|
+
"react",
|
|
1736
|
+
"react-dom",
|
|
1737
|
+
"next",
|
|
1738
|
+
"vue",
|
|
1739
|
+
"nuxt",
|
|
1740
|
+
"@angular/core",
|
|
1741
|
+
"svelte",
|
|
1742
|
+
"@sveltejs/kit",
|
|
1743
|
+
"solid-js",
|
|
1744
|
+
"astro",
|
|
1745
|
+
"gatsby",
|
|
1746
|
+
"remix",
|
|
1747
|
+
"@remix-run/react"
|
|
1748
|
+
];
|
|
1749
|
+
var MOBILE_MARKERS = ["react-native", "expo", "@react-native/core", "@ionic/core", "flutter"];
|
|
1750
|
+
var BACKEND_MARKERS = [
|
|
1751
|
+
"express",
|
|
1752
|
+
"fastify",
|
|
1753
|
+
"@nestjs/core",
|
|
1754
|
+
"koa",
|
|
1755
|
+
"@hapi/hapi",
|
|
1756
|
+
"django",
|
|
1757
|
+
"flask",
|
|
1758
|
+
"fastapi",
|
|
1759
|
+
"rails",
|
|
1760
|
+
"sinatra",
|
|
1761
|
+
"gin-gonic",
|
|
1762
|
+
"laravel/framework",
|
|
1763
|
+
"actix-web",
|
|
1764
|
+
"spring-boot"
|
|
1765
|
+
];
|
|
1766
|
+
function hasAny(deps, markers) {
|
|
1767
|
+
for (const m of markers) if (deps.has(m)) return true;
|
|
1768
|
+
return false;
|
|
1769
|
+
}
|
|
1770
|
+
function classifyStack(depNames) {
|
|
1771
|
+
const deps = new Set(depNames);
|
|
1772
|
+
const mobile = hasAny(deps, MOBILE_MARKERS);
|
|
1773
|
+
if (mobile) return "mobile";
|
|
1774
|
+
const frontend = hasAny(deps, FRONTEND_MARKERS);
|
|
1775
|
+
const backend = hasAny(deps, BACKEND_MARKERS);
|
|
1776
|
+
if (frontend && backend) return "fullstack";
|
|
1777
|
+
if (frontend) return "frontend";
|
|
1778
|
+
if (backend) return "backend";
|
|
1779
|
+
return "unknown";
|
|
1780
|
+
}
|
|
1781
|
+
function detectedIntegrationsFromDeps(depNames) {
|
|
1782
|
+
const out2 = [];
|
|
1783
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1784
|
+
const push = (id) => {
|
|
1785
|
+
if (!seen.has(id)) {
|
|
1786
|
+
seen.add(id);
|
|
1787
|
+
out2.push(id);
|
|
1788
|
+
}
|
|
1789
|
+
};
|
|
1790
|
+
for (const name of depNames) {
|
|
1791
|
+
const exact = DEP_TO_INTEGRATION[name];
|
|
1792
|
+
if (exact) {
|
|
1793
|
+
push(exact);
|
|
1794
|
+
continue;
|
|
1795
|
+
}
|
|
1796
|
+
for (const [prefix, id] of DEP_PREFIX_TO_INTEGRATION) {
|
|
1797
|
+
if (name.startsWith(prefix)) {
|
|
1798
|
+
push(id);
|
|
1799
|
+
break;
|
|
1800
|
+
}
|
|
1801
|
+
}
|
|
1802
|
+
}
|
|
1803
|
+
return out2;
|
|
1804
|
+
}
|
|
1805
|
+
var STACK_TO_RECOMMENDED = {
|
|
1806
|
+
frontend: ["figma", "sentry", "posthog", "vercel"],
|
|
1807
|
+
backend: ["sentry", "datadog", "supabase", "convex", "cloudflare"],
|
|
1808
|
+
fullstack: ["sentry", "posthog", "vercel", "supabase", "convex"],
|
|
1809
|
+
mobile: ["sentry", "posthog"],
|
|
1810
|
+
unknown: []
|
|
1811
|
+
};
|
|
1812
|
+
function recommendForDeps(depNames) {
|
|
1813
|
+
const stack = classifyStack(depNames);
|
|
1814
|
+
const detected = detectedIntegrationsFromDeps(depNames);
|
|
1815
|
+
const detectedSet = new Set(detected);
|
|
1816
|
+
const recommended = STACK_TO_RECOMMENDED[stack].filter((id) => !detectedSet.has(id));
|
|
1817
|
+
return { stack, detected, recommended, source: "scan" };
|
|
1818
|
+
}
|
|
1819
|
+
|
|
1678
1820
|
// ../../packages/shared/src/skills/code-review.ts
|
|
1679
1821
|
var CODE_REVIEW_BODY = `Use this skill when reviewing a pull request. It defines what a high-signal
|
|
1680
1822
|
review looks like so your inline comments are worth the author's time.
|
|
@@ -2102,6 +2244,14 @@ var USER_EVENTS = {
|
|
|
2102
2244
|
INTEGRATION_LINKED: "integration_linked",
|
|
2103
2245
|
INTEGRATION_UNLINKED: "integration_unlinked",
|
|
2104
2246
|
INTEGRATION_CREDENTIAL_INVALID: "integration_credential_invalid",
|
|
2247
|
+
// Session Tools — add/remove Agent Toolkit integrations on an ALREADY-ACTIVE
|
|
2248
|
+
// session. The backend publishes SESSION_INTEGRATIONS_CHANGED after it persists
|
|
2249
|
+
// the new attached set + relays `integrations_sync` to the box (the CLI rewrites
|
|
2250
|
+
// the manifest + reprovisions the live agent, answered synchronously via the
|
|
2251
|
+
// command result). Drives live UI on the sending device AND any other paired
|
|
2252
|
+
// device on the same session. Mirrored in repo A. (`integrations_detect` is a
|
|
2253
|
+
// pure request/response over the relay — no event.)
|
|
2254
|
+
SESSION_INTEGRATIONS_CHANGED: "session_integrations_changed",
|
|
2105
2255
|
// CodeRabbit reviewer — the CLI posts these to /api/coderabbit/events; the
|
|
2106
2256
|
// backend re-publishes them on the per-user SSE bus (mirrored in repo A).
|
|
2107
2257
|
CODERABBIT_PROGRESS: "coderabbit_progress",
|
|
@@ -2306,11 +2456,11 @@ function quiet(fn) {
|
|
|
2306
2456
|
log.debug(TAG, "ignored sync error", err);
|
|
2307
2457
|
}
|
|
2308
2458
|
}
|
|
2309
|
-
function rmIfExistsQuiet(
|
|
2459
|
+
function rmIfExistsQuiet(path82) {
|
|
2310
2460
|
try {
|
|
2311
|
-
fs2.rmSync(
|
|
2461
|
+
fs2.rmSync(path82, { force: true });
|
|
2312
2462
|
} catch (err) {
|
|
2313
|
-
log.debug(TAG, `rmIfExists failed for ${
|
|
2463
|
+
log.debug(TAG, `rmIfExists failed for ${path82}`, err);
|
|
2314
2464
|
}
|
|
2315
2465
|
}
|
|
2316
2466
|
function killQuiet(target, signal = "SIGTERM") {
|
|
@@ -2494,8 +2644,8 @@ function createGetModuleFromFilename(basePath = process.argv[1] ? (0, import_pat
|
|
|
2494
2644
|
return decodedFile;
|
|
2495
2645
|
};
|
|
2496
2646
|
}
|
|
2497
|
-
function normalizeWindowsPath(
|
|
2498
|
-
return
|
|
2647
|
+
function normalizeWindowsPath(path82) {
|
|
2648
|
+
return path82.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
|
|
2499
2649
|
}
|
|
2500
2650
|
|
|
2501
2651
|
// ../../node_modules/@posthog/core/dist/featureFlagUtils.mjs
|
|
@@ -4975,9 +5125,9 @@ async function addSourceContext(frames) {
|
|
|
4975
5125
|
LRU_FILE_CONTENTS_CACHE.reduce();
|
|
4976
5126
|
return frames;
|
|
4977
5127
|
}
|
|
4978
|
-
function getContextLinesFromFile(
|
|
5128
|
+
function getContextLinesFromFile(path82, ranges, output) {
|
|
4979
5129
|
return new Promise((resolve9) => {
|
|
4980
|
-
const stream = (0, import_node_fs.createReadStream)(
|
|
5130
|
+
const stream = (0, import_node_fs.createReadStream)(path82);
|
|
4981
5131
|
const lineReaded = (0, import_node_readline.createInterface)({
|
|
4982
5132
|
input: stream
|
|
4983
5133
|
});
|
|
@@ -4992,7 +5142,7 @@ function getContextLinesFromFile(path81, ranges, output) {
|
|
|
4992
5142
|
let rangeStart = range[0];
|
|
4993
5143
|
let rangeEnd = range[1];
|
|
4994
5144
|
function onStreamError() {
|
|
4995
|
-
LRU_FILE_CONTENTS_FS_READ_FAILED.set(
|
|
5145
|
+
LRU_FILE_CONTENTS_FS_READ_FAILED.set(path82, 1);
|
|
4996
5146
|
lineReaded.close();
|
|
4997
5147
|
lineReaded.removeAllListeners();
|
|
4998
5148
|
destroyStreamAndResolve();
|
|
@@ -5053,8 +5203,8 @@ function clearLineContext(frame) {
|
|
|
5053
5203
|
delete frame.context_line;
|
|
5054
5204
|
delete frame.post_context;
|
|
5055
5205
|
}
|
|
5056
|
-
function shouldSkipContextLinesForFile(
|
|
5057
|
-
return
|
|
5206
|
+
function shouldSkipContextLinesForFile(path82) {
|
|
5207
|
+
return path82.startsWith("node:") || path82.endsWith(".min.js") || path82.endsWith(".min.cjs") || path82.endsWith(".min.mjs") || path82.startsWith("data:");
|
|
5058
5208
|
}
|
|
5059
5209
|
function shouldSkipContextLinesForFrame(frame) {
|
|
5060
5210
|
if (void 0 !== frame.lineno && frame.lineno > MAX_CONTEXTLINES_LINENO) return true;
|
|
@@ -7208,7 +7358,7 @@ function readAnonId() {
|
|
|
7208
7358
|
}
|
|
7209
7359
|
function superProperties() {
|
|
7210
7360
|
return {
|
|
7211
|
-
cliVersion: true ? "2.61.
|
|
7361
|
+
cliVersion: true ? "2.61.78" : "0.0.0-dev",
|
|
7212
7362
|
nodeVersion: process.version,
|
|
7213
7363
|
platform: process.platform,
|
|
7214
7364
|
arch: process.arch,
|
|
@@ -7389,7 +7539,7 @@ var os4 = __toESM(require("os"));
|
|
|
7389
7539
|
// package.json
|
|
7390
7540
|
var package_default = {
|
|
7391
7541
|
name: "codeam-cli",
|
|
7392
|
-
version: "2.61.
|
|
7542
|
+
version: "2.61.78",
|
|
7393
7543
|
description: "Workflow-continuity bridge for AI coding agents. Wrap Claude Code or Codex in a PTY and supervise, approve, and redirect the session from any device \u2014 async. The terminal companion for CodeAgent Mobile.",
|
|
7394
7544
|
type: "commonjs",
|
|
7395
7545
|
main: "dist/index.js",
|
|
@@ -8621,7 +8771,7 @@ var CommandRelayService = class _CommandRelayService {
|
|
|
8621
8771
|
// fresh + clear the "CLI update available" banner after a self-update
|
|
8622
8772
|
// (a codespace that reinstalls @latest reconnects via heartbeat, not
|
|
8623
8773
|
// pair/reconnect). Older backends ignore the extra field.
|
|
8624
|
-
..."2.61.
|
|
8774
|
+
..."2.61.78" ? { ideVersion: "2.61.78" } : {}
|
|
8625
8775
|
}).then(() => log.trace("relay", `heartbeat ok online=${online}`)).catch((err) => log.trace("relay", `heartbeat failed online=${online}`, err));
|
|
8626
8776
|
}
|
|
8627
8777
|
/**
|
|
@@ -15230,8 +15380,8 @@ function pickLine(obj) {
|
|
|
15230
15380
|
function toHunk(raw, groupSeverity) {
|
|
15231
15381
|
if (!raw || typeof raw !== "object") return null;
|
|
15232
15382
|
const o = raw;
|
|
15233
|
-
const
|
|
15234
|
-
if (!
|
|
15383
|
+
const path82 = asString(pick(o, ["file_path", "filePath", "file", "path", "filename", "fileName"])) ?? asString(pick(o, ["location"])?.path);
|
|
15384
|
+
if (!path82) return null;
|
|
15235
15385
|
const message = asString(
|
|
15236
15386
|
pick(o, [
|
|
15237
15387
|
"comment",
|
|
@@ -15248,7 +15398,7 @@ function toHunk(raw, groupSeverity) {
|
|
|
15248
15398
|
const severity = normSeverity(pick(o, ["severity", "level", "priority", "impact"])) ?? normSeverity(groupSeverity);
|
|
15249
15399
|
const locObj = pick(o, ["location"]) ?? o;
|
|
15250
15400
|
return {
|
|
15251
|
-
path:
|
|
15401
|
+
path: path82.trim(),
|
|
15252
15402
|
line: pickLine(o) ?? pickLine(locObj),
|
|
15253
15403
|
severity,
|
|
15254
15404
|
message: (title && message ? `${title}: ${message}` : title || message).trim() || "(no message)"
|
|
@@ -15331,10 +15481,10 @@ function parsePlain(stdout) {
|
|
|
15331
15481
|
for (const line of stdout.split(/\r?\n/)) {
|
|
15332
15482
|
const m = line.match(HUNK_LINE_RE);
|
|
15333
15483
|
if (!m) continue;
|
|
15334
|
-
const [,
|
|
15335
|
-
if (!
|
|
15484
|
+
const [, path82, lineNo, sevToken, message] = m;
|
|
15485
|
+
if (!path82 || !lineNo || !message) continue;
|
|
15336
15486
|
hunks.push({
|
|
15337
|
-
path:
|
|
15487
|
+
path: path82.trim(),
|
|
15338
15488
|
line: Number(lineNo),
|
|
15339
15489
|
severity: sevToken ? SEVERITY_MAP[sevToken.toLowerCase()] : void 0,
|
|
15340
15490
|
message: message.trim().replace(/^[*-]\s+/, "")
|
|
@@ -19735,7 +19885,7 @@ async function autoUpgradeBeforeCriticalCommand() {
|
|
|
19735
19885
|
if (process.env.NODE_ENV === "test") return;
|
|
19736
19886
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
19737
19887
|
if (process.env.CI) return;
|
|
19738
|
-
const current = true ? "2.61.
|
|
19888
|
+
const current = true ? "2.61.78" : null;
|
|
19739
19889
|
if (!current) return;
|
|
19740
19890
|
const cache = readCache();
|
|
19741
19891
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -19752,7 +19902,7 @@ function checkForUpdates() {
|
|
|
19752
19902
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
19753
19903
|
if (process.env.CI) return;
|
|
19754
19904
|
if (!process.stdout.isTTY) return;
|
|
19755
|
-
const current = true ? "2.61.
|
|
19905
|
+
const current = true ? "2.61.78" : null;
|
|
19756
19906
|
if (!current) return;
|
|
19757
19907
|
const cache = readCache();
|
|
19758
19908
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -19772,7 +19922,7 @@ var SELF_UPDATE_INTERVAL_MS = 60 * 60 * 1e3;
|
|
|
19772
19922
|
var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
|
|
19773
19923
|
var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
|
|
19774
19924
|
function currentCliVersion() {
|
|
19775
|
-
return true ? "2.61.
|
|
19925
|
+
return true ? "2.61.78" : null;
|
|
19776
19926
|
}
|
|
19777
19927
|
function runCmd(cmd, args2, timeoutMs) {
|
|
19778
19928
|
return new Promise((resolve9) => {
|
|
@@ -25666,11 +25816,11 @@ function resolveTokenValue(args2) {
|
|
|
25666
25816
|
}
|
|
25667
25817
|
const fileFlag = args2.find((a) => a.startsWith("--token-file="));
|
|
25668
25818
|
if (fileFlag) {
|
|
25669
|
-
const
|
|
25819
|
+
const path82 = fileFlag.slice("--token-file=".length);
|
|
25670
25820
|
try {
|
|
25671
|
-
const content = fs59.readFileSync(
|
|
25672
|
-
if (content.length === 0) fail(`--token-file ${
|
|
25673
|
-
rmIfExistsQuiet(
|
|
25821
|
+
const content = fs59.readFileSync(path82, "utf8").trim();
|
|
25822
|
+
if (content.length === 0) fail(`--token-file ${path82} is empty`);
|
|
25823
|
+
rmIfExistsQuiet(path82);
|
|
25674
25824
|
return content;
|
|
25675
25825
|
} catch (err) {
|
|
25676
25826
|
fail(`Could not read --token-file: ${err.message}`);
|
|
@@ -31901,6 +32051,51 @@ var AcpClient = class {
|
|
|
31901
32051
|
if (loaded?.modes !== void 0) this.captureModes(loaded.modes ?? null);
|
|
31902
32052
|
log.info("acpClient", `loadSession \u2190 ok sessionId=${sessionId.slice(0, 8)}`);
|
|
31903
32053
|
}
|
|
32054
|
+
/** The conversation id the agent is currently serving (null before start). */
|
|
32055
|
+
getActiveSessionId() {
|
|
32056
|
+
return this.sessionId;
|
|
32057
|
+
}
|
|
32058
|
+
/**
|
|
32059
|
+
* Re-register the agent's MCP servers on an ALREADY-RUNNING session (Session
|
|
32060
|
+
* Tools — adding/removing an integration mid-session). MCP servers are bound
|
|
32061
|
+
* at `session/new`, and `session/load` on the CURRENTLY-running session wedges
|
|
32062
|
+
* Claude (the self-load guard in {@link loadSession}), so the only reliable way
|
|
32063
|
+
* to add a server to a live session is a controlled RESPAWN that resumes the
|
|
32064
|
+
* conversation: kill the agent → fresh `startOnce()` (a new session S2 bound to
|
|
32065
|
+
* the new `mcpServers`) → `loadSession(prevConversationId)` (S1 ≠ S2, so the
|
|
32066
|
+
* self-load guard doesn't fire) to resume the thread with the new tools live.
|
|
32067
|
+
*
|
|
32068
|
+
* Best-effort + degrade-safe: `this.opts.mcpServers` is updated FIRST (so even
|
|
32069
|
+
* a failed respawn leaves the new set to bind on the next natural
|
|
32070
|
+
* re-establishment — wake/resume/recovery), and any throw resolves to
|
|
32071
|
+
* `'deferred'` rather than tearing down the session. Returns which happened so
|
|
32072
|
+
* the caller can tell the user "active now" vs "active on next restart".
|
|
32073
|
+
*/
|
|
32074
|
+
async reprovisionMcp(servers) {
|
|
32075
|
+
this.opts.mcpServers = servers;
|
|
32076
|
+
const prevConversationId = this.sessionId;
|
|
32077
|
+
if (!this.connection || !prevConversationId) return "deferred";
|
|
32078
|
+
try {
|
|
32079
|
+
log.info(
|
|
32080
|
+
"acpClient",
|
|
32081
|
+
`reprovisionMcp \u2192 respawn to bind ${servers.length} MCP server(s), resuming ${prevConversationId.slice(0, 8)}`
|
|
32082
|
+
);
|
|
32083
|
+
await this.stop();
|
|
32084
|
+
this.stopping = false;
|
|
32085
|
+
await this.startOnce();
|
|
32086
|
+
if (this.supportsLoadSession && prevConversationId !== this.sessionId) {
|
|
32087
|
+
await this.loadSession(prevConversationId);
|
|
32088
|
+
}
|
|
32089
|
+
log.info("acpClient", "reprovisionMcp \u2190 reloaded (tools live)");
|
|
32090
|
+
return "reloaded";
|
|
32091
|
+
} catch (err) {
|
|
32092
|
+
log.warn(
|
|
32093
|
+
"acpClient",
|
|
32094
|
+
`reprovisionMcp respawn failed \u2014 tools apply on next restart: ${err instanceof Error ? err.message : String(err)}`
|
|
32095
|
+
);
|
|
32096
|
+
return "deferred";
|
|
32097
|
+
}
|
|
32098
|
+
}
|
|
31904
32099
|
/**
|
|
31905
32100
|
* Enumerate the workspace's conversations via the ACP `session/list` RPC.
|
|
31906
32101
|
* Agent-agnostic — works for ANY adapter that advertises
|
|
@@ -33275,7 +33470,7 @@ function defaultRunGit(cwd, args2) {
|
|
|
33275
33470
|
});
|
|
33276
33471
|
}
|
|
33277
33472
|
async function discoverRepos(workingDir, maxDepth = 4) {
|
|
33278
|
-
const
|
|
33473
|
+
const fs72 = await import("fs/promises");
|
|
33279
33474
|
const out2 = [];
|
|
33280
33475
|
await walk(workingDir, 0);
|
|
33281
33476
|
return out2;
|
|
@@ -33283,7 +33478,7 @@ async function discoverRepos(workingDir, maxDepth = 4) {
|
|
|
33283
33478
|
if (depth > maxDepth) return;
|
|
33284
33479
|
let entries = [];
|
|
33285
33480
|
try {
|
|
33286
|
-
const dirents = await
|
|
33481
|
+
const dirents = await fs72.readdir(dir, { withFileTypes: true });
|
|
33287
33482
|
entries = dirents.filter((d3) => !d3.name.startsWith(".") || d3.name === ".git").map((d3) => ({ name: d3.name, isDirectory: d3.isDirectory() }));
|
|
33288
33483
|
} catch {
|
|
33289
33484
|
return;
|
|
@@ -33926,6 +34121,146 @@ async function postBudgetReached(opts, fetchImpl = fetch) {
|
|
|
33926
34121
|
}
|
|
33927
34122
|
}
|
|
33928
34123
|
|
|
34124
|
+
// src/integrations/provision.ts
|
|
34125
|
+
function buildMcpServersForStart(ctx) {
|
|
34126
|
+
const manifest = readIntegrationsManifest();
|
|
34127
|
+
if (!manifest || manifest.integrations.length === 0) return [];
|
|
34128
|
+
if (!ctx.pluginAuthToken) {
|
|
34129
|
+
log.warn("integrations", "manifest present but no plugin auth token \u2014 skipping MCP injection");
|
|
34130
|
+
return [];
|
|
34131
|
+
}
|
|
34132
|
+
const servers = [];
|
|
34133
|
+
for (const entry of manifest.integrations) {
|
|
34134
|
+
if (!entry.delivery.mcp) continue;
|
|
34135
|
+
const env = [
|
|
34136
|
+
{ name: "CODEAM_MCP_INTEGRATION_ID", value: entry.id },
|
|
34137
|
+
{ name: "CODEAM_MCP_SESSION_ID", value: ctx.sessionId },
|
|
34138
|
+
{ name: "CODEAM_MCP_PLUGIN_ID", value: ctx.pluginId },
|
|
34139
|
+
// Plugin token in ENV, never argv — argv is visible via `ps`.
|
|
34140
|
+
{ name: "CODEAM_MCP_PLUGIN_TOKEN", value: ctx.pluginAuthToken },
|
|
34141
|
+
...ctx.pollSecret ? [{ name: "CODEAM_MCP_POLL_SECRET", value: ctx.pollSecret }] : []
|
|
34142
|
+
];
|
|
34143
|
+
servers.push({
|
|
34144
|
+
name: entry.id,
|
|
34145
|
+
// Never trust the agent's PATH for the shim binary (beads v2.39.5
|
|
34146
|
+
// lesson) — re-invoke this same Node runtime + CLI entrypoint.
|
|
34147
|
+
command: process.execPath,
|
|
34148
|
+
args: [process.argv[1], "mcp-run", entry.id],
|
|
34149
|
+
env
|
|
34150
|
+
});
|
|
34151
|
+
}
|
|
34152
|
+
if (servers.length) {
|
|
34153
|
+
log.info(
|
|
34154
|
+
"integrations",
|
|
34155
|
+
`injecting ${servers.length} MCP server(s): ${servers.map((s) => s.name).join(", ")}`
|
|
34156
|
+
);
|
|
34157
|
+
}
|
|
34158
|
+
return servers;
|
|
34159
|
+
}
|
|
34160
|
+
|
|
34161
|
+
// src/integrations/detect-stack.ts
|
|
34162
|
+
var import_node_fs11 = __toESM(require("fs"));
|
|
34163
|
+
var import_node_path11 = __toESM(require("path"));
|
|
34164
|
+
function readSafe(cwd, rel) {
|
|
34165
|
+
try {
|
|
34166
|
+
return import_node_fs11.default.readFileSync(import_node_path11.default.join(cwd, rel), "utf8");
|
|
34167
|
+
} catch {
|
|
34168
|
+
return "";
|
|
34169
|
+
}
|
|
34170
|
+
}
|
|
34171
|
+
function collectRepoDeps(cwd) {
|
|
34172
|
+
const names = /* @__PURE__ */ new Set();
|
|
34173
|
+
const pkgRaw = readSafe(cwd, "package.json");
|
|
34174
|
+
if (pkgRaw) {
|
|
34175
|
+
try {
|
|
34176
|
+
const pkg = JSON.parse(pkgRaw);
|
|
34177
|
+
for (const k2 of Object.keys(pkg.dependencies ?? {})) names.add(k2);
|
|
34178
|
+
for (const k2 of Object.keys(pkg.devDependencies ?? {})) names.add(k2);
|
|
34179
|
+
} catch {
|
|
34180
|
+
}
|
|
34181
|
+
}
|
|
34182
|
+
const req = readSafe(cwd, "requirements.txt");
|
|
34183
|
+
for (const line of req.split("\n")) {
|
|
34184
|
+
const name = line.trim().split(/[=<>!~;[\s]/)[0];
|
|
34185
|
+
if (name && !name.startsWith("#") && !name.startsWith("-")) names.add(name.toLowerCase());
|
|
34186
|
+
}
|
|
34187
|
+
const pyproject = readSafe(cwd, "pyproject.toml");
|
|
34188
|
+
for (const m of pyproject.matchAll(/^\s*["']?([A-Za-z0-9._-]+)["']?\s*[=~<>]/gm)) {
|
|
34189
|
+
if (m[1]) names.add(m[1].toLowerCase());
|
|
34190
|
+
}
|
|
34191
|
+
const goMod = readSafe(cwd, "go.mod");
|
|
34192
|
+
for (const m of goMod.matchAll(/^\s*([\w./-]+)\s+v\d/gm)) {
|
|
34193
|
+
if (m[1]) names.add(m[1]);
|
|
34194
|
+
}
|
|
34195
|
+
const gemfile = readSafe(cwd, "Gemfile");
|
|
34196
|
+
for (const m of gemfile.matchAll(/^\s*gem\s+["']([A-Za-z0-9._-]+)["']/gm)) {
|
|
34197
|
+
if (m[1]) names.add(m[1]);
|
|
34198
|
+
}
|
|
34199
|
+
const composerRaw = readSafe(cwd, "composer.json");
|
|
34200
|
+
if (composerRaw) {
|
|
34201
|
+
try {
|
|
34202
|
+
const composer = JSON.parse(composerRaw);
|
|
34203
|
+
for (const k2 of Object.keys(composer.require ?? {})) names.add(k2);
|
|
34204
|
+
for (const k2 of Object.keys(composer["require-dev"] ?? {})) names.add(k2);
|
|
34205
|
+
} catch {
|
|
34206
|
+
}
|
|
34207
|
+
}
|
|
34208
|
+
const cargo = readSafe(cwd, "Cargo.toml");
|
|
34209
|
+
const cargoDepsBlock = cargo.match(/\[(?:dev-)?dependencies\]([\s\S]*?)(?:\n\[|$)/g);
|
|
34210
|
+
if (cargoDepsBlock) {
|
|
34211
|
+
for (const block of cargoDepsBlock) {
|
|
34212
|
+
for (const m of block.matchAll(/^\s*([A-Za-z0-9._-]+)\s*=/gm)) {
|
|
34213
|
+
if (m[1] && m[1] !== "dependencies" && m[1] !== "dev-dependencies") names.add(m[1]);
|
|
34214
|
+
}
|
|
34215
|
+
}
|
|
34216
|
+
}
|
|
34217
|
+
return [...names];
|
|
34218
|
+
}
|
|
34219
|
+
function enabledCatalogIds() {
|
|
34220
|
+
return getEnabledIntegrations().map((m) => m.id);
|
|
34221
|
+
}
|
|
34222
|
+
function parseAgentSuggestions(raw) {
|
|
34223
|
+
const match = raw.match(/\[[\s\S]*?\]/);
|
|
34224
|
+
if (!match) return [];
|
|
34225
|
+
let arr;
|
|
34226
|
+
try {
|
|
34227
|
+
arr = JSON.parse(match[0]);
|
|
34228
|
+
} catch {
|
|
34229
|
+
return [];
|
|
34230
|
+
}
|
|
34231
|
+
if (!Array.isArray(arr)) return [];
|
|
34232
|
+
const enabled = new Set(enabledCatalogIds());
|
|
34233
|
+
const out2 = [];
|
|
34234
|
+
const seen = /* @__PURE__ */ new Set();
|
|
34235
|
+
for (const v of arr) {
|
|
34236
|
+
if (typeof v === "string" && isKnownIntegrationId(v) && enabled.has(v) && !seen.has(v)) {
|
|
34237
|
+
seen.add(v);
|
|
34238
|
+
out2.push(v);
|
|
34239
|
+
}
|
|
34240
|
+
}
|
|
34241
|
+
return out2;
|
|
34242
|
+
}
|
|
34243
|
+
async function detectRepoStack(cwd, runtime) {
|
|
34244
|
+
const deps = collectRepoDeps(cwd);
|
|
34245
|
+
const scan = recommendForDeps(deps);
|
|
34246
|
+
if (scan.detected.length > 0 || scan.recommended.length > 0) return scan;
|
|
34247
|
+
if (!runtime?.generateOneShot) return scan;
|
|
34248
|
+
try {
|
|
34249
|
+
const catalog = enabledCatalogIds().join(", ");
|
|
34250
|
+
const prompt = `Inspect this repository (frameworks, languages, services it integrates with) and suggest which of these developer tools would be most useful to connect. Respond with ONLY a JSON array of ids chosen from this exact set: [${catalog}]. No prose, no ids outside the set. Example: ["sentry","posthog"].`;
|
|
34251
|
+
const reply = await runtime.generateOneShot(prompt, { cwd, timeoutMs: 45e3 });
|
|
34252
|
+
if (!reply) return scan;
|
|
34253
|
+
const recommended = parseAgentSuggestions(reply);
|
|
34254
|
+
return { stack: scan.stack, detected: [], recommended, source: "agent" };
|
|
34255
|
+
} catch (err) {
|
|
34256
|
+
log.warn("integrations", `stack detect agent fallback failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
34257
|
+
return scan;
|
|
34258
|
+
}
|
|
34259
|
+
}
|
|
34260
|
+
|
|
34261
|
+
// src/agents/acp/command-handlers.ts
|
|
34262
|
+
var import_node_child_process30 = require("child_process");
|
|
34263
|
+
|
|
33929
34264
|
// src/agents/acp/buildAcpPromptBlocks.ts
|
|
33930
34265
|
var MIME_FROM_EXT = {
|
|
33931
34266
|
png: "image/png",
|
|
@@ -34537,7 +34872,74 @@ async function legacyOrUnsupportedH(ctx) {
|
|
|
34537
34872
|
});
|
|
34538
34873
|
return;
|
|
34539
34874
|
}
|
|
34875
|
+
async function prewarmNewMcpEntries(manifest, previousIds) {
|
|
34876
|
+
const PREWARMABLE = /* @__PURE__ */ new Set(["npx", "uvx"]);
|
|
34877
|
+
const fresh = manifest.integrations.filter(
|
|
34878
|
+
(e) => !previousIds.has(e.id) && e.delivery.mcp && PREWARMABLE.has(e.delivery.mcp.command)
|
|
34879
|
+
);
|
|
34880
|
+
await Promise.all(
|
|
34881
|
+
fresh.map(
|
|
34882
|
+
(e) => new Promise((resolve9) => {
|
|
34883
|
+
const mcp = e.delivery.mcp;
|
|
34884
|
+
const child = (0, import_node_child_process30.execFile)(
|
|
34885
|
+
mcp.command,
|
|
34886
|
+
[...mcp.args, "--help"],
|
|
34887
|
+
{ timeout: 9e4 },
|
|
34888
|
+
() => resolve9()
|
|
34889
|
+
);
|
|
34890
|
+
child.on("error", () => resolve9());
|
|
34891
|
+
})
|
|
34892
|
+
)
|
|
34893
|
+
);
|
|
34894
|
+
}
|
|
34895
|
+
async function integrationsSyncH(ctx) {
|
|
34896
|
+
const { cmd, relay, opts, client: client3 } = ctx;
|
|
34897
|
+
const manifest = cmd.payload.manifest;
|
|
34898
|
+
if (!manifest || !Array.isArray(manifest.integrations)) {
|
|
34899
|
+
await relay.sendResult(cmd.id, "failed", { error: "integrations_sync: missing manifest" });
|
|
34900
|
+
return;
|
|
34901
|
+
}
|
|
34902
|
+
try {
|
|
34903
|
+
const previousIds = new Set((readIntegrationsManifest()?.integrations ?? []).map((e) => e.id));
|
|
34904
|
+
persistIntegrationsManifest(manifest);
|
|
34905
|
+
await prewarmNewMcpEntries(manifest, previousIds);
|
|
34906
|
+
const servers = buildMcpServersForStart({
|
|
34907
|
+
sessionId: opts.sessionId,
|
|
34908
|
+
pluginId: opts.pluginId,
|
|
34909
|
+
pluginAuthToken: opts.pluginAuthToken,
|
|
34910
|
+
pollSecret: opts.pollSecret
|
|
34911
|
+
});
|
|
34912
|
+
const applied = await client3.reprovisionMcp(servers);
|
|
34913
|
+
await relay.sendResult(cmd.id, "completed", {
|
|
34914
|
+
synced: true,
|
|
34915
|
+
applied,
|
|
34916
|
+
// 'reloaded' (live now) | 'deferred' (next restart)
|
|
34917
|
+
attached: manifest.integrations.map((e) => e.id)
|
|
34918
|
+
});
|
|
34919
|
+
} catch (err) {
|
|
34920
|
+
log.warn("acpRunner", `integrations_sync failed (tools apply next restart): ${describeError(err)}`);
|
|
34921
|
+
await relay.sendResult(cmd.id, "completed", { synced: false, error: describeError(err) });
|
|
34922
|
+
}
|
|
34923
|
+
}
|
|
34924
|
+
async function integrationsDetectH(ctx) {
|
|
34925
|
+
const { cmd, relay, opts } = ctx;
|
|
34926
|
+
try {
|
|
34927
|
+
const runtime = createInteractiveAgentStrategy(opts.agent, createOsStrategy());
|
|
34928
|
+
const detection = await detectRepoStack(opts.cwd, runtime);
|
|
34929
|
+
await relay.sendResult(cmd.id, "completed", detection);
|
|
34930
|
+
} catch (err) {
|
|
34931
|
+
log.warn("acpRunner", `integrations_detect failed: ${describeError(err)}`);
|
|
34932
|
+
await relay.sendResult(cmd.id, "completed", {
|
|
34933
|
+
stack: "unknown",
|
|
34934
|
+
detected: [],
|
|
34935
|
+
recommended: [],
|
|
34936
|
+
source: "scan"
|
|
34937
|
+
});
|
|
34938
|
+
}
|
|
34939
|
+
}
|
|
34540
34940
|
var ACP_COMMAND_HANDLERS = {
|
|
34941
|
+
integrations_sync: integrationsSyncH,
|
|
34942
|
+
integrations_detect: integrationsDetectH,
|
|
34541
34943
|
beads_action: beadsActionH,
|
|
34542
34944
|
start_task: startTaskH,
|
|
34543
34945
|
group_mention_task: groupMentionTaskH,
|
|
@@ -36510,8 +36912,8 @@ function startClaudeCredentialSync(opts) {
|
|
|
36510
36912
|
}
|
|
36511
36913
|
|
|
36512
36914
|
// src/beads/workflow-hint.ts
|
|
36513
|
-
var
|
|
36514
|
-
var
|
|
36915
|
+
var fs68 = __toESM(require("fs"));
|
|
36916
|
+
var path74 = __toESM(require("path"));
|
|
36515
36917
|
var os55 = __toESM(require("os"));
|
|
36516
36918
|
var BEADS_HINT_MARKER = "<!-- codeam:beads-workflow -->";
|
|
36517
36919
|
var BEADS_HINT = `${BEADS_HINT_MARKER}
|
|
@@ -36528,61 +36930,24 @@ This environment uses **bd (beads)** for issue/task tracking and persistent memo
|
|
|
36528
36930
|
${BEADS_HINT_MARKER}`;
|
|
36529
36931
|
function ensureBeadsWorkflowHint(homeDir2 = os55.homedir()) {
|
|
36530
36932
|
try {
|
|
36531
|
-
const file =
|
|
36933
|
+
const file = path74.join(homeDir2, ".claude", "CLAUDE.md");
|
|
36532
36934
|
let existing = "";
|
|
36533
36935
|
try {
|
|
36534
|
-
existing =
|
|
36936
|
+
existing = fs68.readFileSync(file, "utf8");
|
|
36535
36937
|
} catch {
|
|
36536
36938
|
}
|
|
36537
36939
|
if (existing.includes(BEADS_HINT_MARKER)) return;
|
|
36538
|
-
|
|
36940
|
+
fs68.mkdirSync(path74.dirname(file), { recursive: true });
|
|
36539
36941
|
const next = existing.trim() ? `${existing.trimEnd()}
|
|
36540
36942
|
|
|
36541
36943
|
${BEADS_HINT}
|
|
36542
36944
|
` : `${BEADS_HINT}
|
|
36543
36945
|
`;
|
|
36544
|
-
|
|
36946
|
+
fs68.writeFileSync(file, next);
|
|
36545
36947
|
} catch {
|
|
36546
36948
|
}
|
|
36547
36949
|
}
|
|
36548
36950
|
|
|
36549
|
-
// src/integrations/provision.ts
|
|
36550
|
-
function buildMcpServersForStart(ctx) {
|
|
36551
|
-
const manifest = readIntegrationsManifest();
|
|
36552
|
-
if (!manifest || manifest.integrations.length === 0) return [];
|
|
36553
|
-
if (!ctx.pluginAuthToken) {
|
|
36554
|
-
log.warn("integrations", "manifest present but no plugin auth token \u2014 skipping MCP injection");
|
|
36555
|
-
return [];
|
|
36556
|
-
}
|
|
36557
|
-
const servers = [];
|
|
36558
|
-
for (const entry of manifest.integrations) {
|
|
36559
|
-
if (!entry.delivery.mcp) continue;
|
|
36560
|
-
const env = [
|
|
36561
|
-
{ name: "CODEAM_MCP_INTEGRATION_ID", value: entry.id },
|
|
36562
|
-
{ name: "CODEAM_MCP_SESSION_ID", value: ctx.sessionId },
|
|
36563
|
-
{ name: "CODEAM_MCP_PLUGIN_ID", value: ctx.pluginId },
|
|
36564
|
-
// Plugin token in ENV, never argv — argv is visible via `ps`.
|
|
36565
|
-
{ name: "CODEAM_MCP_PLUGIN_TOKEN", value: ctx.pluginAuthToken },
|
|
36566
|
-
...ctx.pollSecret ? [{ name: "CODEAM_MCP_POLL_SECRET", value: ctx.pollSecret }] : []
|
|
36567
|
-
];
|
|
36568
|
-
servers.push({
|
|
36569
|
-
name: entry.id,
|
|
36570
|
-
// Never trust the agent's PATH for the shim binary (beads v2.39.5
|
|
36571
|
-
// lesson) — re-invoke this same Node runtime + CLI entrypoint.
|
|
36572
|
-
command: process.execPath,
|
|
36573
|
-
args: [process.argv[1], "mcp-run", entry.id],
|
|
36574
|
-
env
|
|
36575
|
-
});
|
|
36576
|
-
}
|
|
36577
|
-
if (servers.length) {
|
|
36578
|
-
log.info(
|
|
36579
|
-
"integrations",
|
|
36580
|
-
`injecting ${servers.length} MCP server(s): ${servers.map((s) => s.name).join(", ")}`
|
|
36581
|
-
);
|
|
36582
|
-
}
|
|
36583
|
-
return servers;
|
|
36584
|
-
}
|
|
36585
|
-
|
|
36586
36951
|
// src/skills/provision.ts
|
|
36587
36952
|
var import_node_os13 = __toESM(require("os"));
|
|
36588
36953
|
function provisionSkillsForStart(home = import_node_os13.default.homedir()) {
|
|
@@ -36950,7 +37315,7 @@ var AcpDriver = class {
|
|
|
36950
37315
|
};
|
|
36951
37316
|
|
|
36952
37317
|
// src/baton/transcript-mirror.ts
|
|
36953
|
-
var
|
|
37318
|
+
var fs69 = __toESM(require("fs"));
|
|
36954
37319
|
var TranscriptMirror = class {
|
|
36955
37320
|
constructor(deps) {
|
|
36956
37321
|
this.deps = deps;
|
|
@@ -37017,7 +37382,7 @@ var TranscriptMirror = class {
|
|
|
37017
37382
|
}
|
|
37018
37383
|
};
|
|
37019
37384
|
function defaultWatch(file, onChange) {
|
|
37020
|
-
const w3 =
|
|
37385
|
+
const w3 = fs69.watch(file, { persistent: false }, () => onChange());
|
|
37021
37386
|
return () => w3.close();
|
|
37022
37387
|
}
|
|
37023
37388
|
|
|
@@ -37279,16 +37644,16 @@ function toEpochMs(ts) {
|
|
|
37279
37644
|
}
|
|
37280
37645
|
|
|
37281
37646
|
// src/agents/claude/onboarding.ts
|
|
37282
|
-
var
|
|
37647
|
+
var fs70 = __toESM(require("fs"));
|
|
37283
37648
|
var os57 = __toESM(require("os"));
|
|
37284
|
-
var
|
|
37649
|
+
var path75 = __toESM(require("path"));
|
|
37285
37650
|
var ONBOARDING_VERSION_SENTINEL = "9999.0.0";
|
|
37286
37651
|
function ensureClaudeOnboarded(cwd) {
|
|
37287
37652
|
try {
|
|
37288
|
-
const file =
|
|
37653
|
+
const file = path75.join(os57.homedir(), ".claude.json");
|
|
37289
37654
|
let config = {};
|
|
37290
37655
|
try {
|
|
37291
|
-
config = JSON.parse(
|
|
37656
|
+
config = JSON.parse(fs70.readFileSync(file, "utf8"));
|
|
37292
37657
|
} catch {
|
|
37293
37658
|
}
|
|
37294
37659
|
let changed = false;
|
|
@@ -37313,8 +37678,8 @@ function ensureClaudeOnboarded(cwd) {
|
|
|
37313
37678
|
}
|
|
37314
37679
|
}
|
|
37315
37680
|
if (!changed) return;
|
|
37316
|
-
|
|
37317
|
-
|
|
37681
|
+
fs70.mkdirSync(path75.dirname(file), { recursive: true });
|
|
37682
|
+
fs70.writeFileSync(file, JSON.stringify(config, null, 2));
|
|
37318
37683
|
log.info(
|
|
37319
37684
|
"claude",
|
|
37320
37685
|
`pre-completed Claude onboarding${cwd ? ` + trusted workspace ${cwd}` : ""}`
|
|
@@ -38041,7 +38406,7 @@ var import_picocolors11 = __toESM(require("picocolors"));
|
|
|
38041
38406
|
var import_child_process29 = require("child_process");
|
|
38042
38407
|
var import_util4 = require("util");
|
|
38043
38408
|
var import_picocolors9 = __toESM(require("picocolors"));
|
|
38044
|
-
var
|
|
38409
|
+
var path76 = __toESM(require("path"));
|
|
38045
38410
|
var execFileP6 = (0, import_util4.promisify)(import_child_process29.execFile);
|
|
38046
38411
|
var MAX_BUFFER = 8 * 1024 * 1024;
|
|
38047
38412
|
function resetStdinForChild() {
|
|
@@ -38530,7 +38895,7 @@ var GitHubCodespacesProvider = class {
|
|
|
38530
38895
|
});
|
|
38531
38896
|
}
|
|
38532
38897
|
async uploadFile(workspaceId, remotePath, contents, options = {}) {
|
|
38533
|
-
const remoteDir =
|
|
38898
|
+
const remoteDir = path76.posix.dirname(remotePath);
|
|
38534
38899
|
const parts = [
|
|
38535
38900
|
`mkdir -p ${shellQuote(remoteDir)}`,
|
|
38536
38901
|
`cat > ${shellQuote(remotePath)}`
|
|
@@ -38600,7 +38965,7 @@ function shellQuote(s) {
|
|
|
38600
38965
|
// src/services/providers/gitpod.ts
|
|
38601
38966
|
var import_child_process30 = require("child_process");
|
|
38602
38967
|
var import_util5 = require("util");
|
|
38603
|
-
var
|
|
38968
|
+
var path77 = __toESM(require("path"));
|
|
38604
38969
|
var import_picocolors10 = __toESM(require("picocolors"));
|
|
38605
38970
|
var execFileP7 = (0, import_util5.promisify)(import_child_process30.execFile);
|
|
38606
38971
|
var MAX_BUFFER2 = 8 * 1024 * 1024;
|
|
@@ -38840,7 +39205,7 @@ var GitpodProvider = class {
|
|
|
38840
39205
|
});
|
|
38841
39206
|
}
|
|
38842
39207
|
async uploadFile(workspaceId, remotePath, contents, options = {}) {
|
|
38843
|
-
const remoteDir =
|
|
39208
|
+
const remoteDir = path77.posix.dirname(remotePath);
|
|
38844
39209
|
const parts = [
|
|
38845
39210
|
`mkdir -p ${shellQuote2(remoteDir)}`,
|
|
38846
39211
|
`cat > ${shellQuote2(remotePath)}`
|
|
@@ -38876,7 +39241,7 @@ function shellQuote2(s) {
|
|
|
38876
39241
|
// src/services/providers/gitlab-workspaces.ts
|
|
38877
39242
|
var import_child_process31 = require("child_process");
|
|
38878
39243
|
var import_util6 = require("util");
|
|
38879
|
-
var
|
|
39244
|
+
var path78 = __toESM(require("path"));
|
|
38880
39245
|
var execFileP8 = (0, import_util6.promisify)(import_child_process31.execFile);
|
|
38881
39246
|
var MAX_BUFFER3 = 8 * 1024 * 1024;
|
|
38882
39247
|
var GITLAB_API_BASE = process.env.CODEAM_GITLAB_API_URL ?? "https://gitlab.com/api/v4";
|
|
@@ -39136,7 +39501,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
|
|
|
39136
39501
|
}
|
|
39137
39502
|
async uploadFile(workspaceId, remotePath, contents, options = {}) {
|
|
39138
39503
|
const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
|
|
39139
|
-
const remoteDir =
|
|
39504
|
+
const remoteDir = path78.posix.dirname(remotePath);
|
|
39140
39505
|
const parts = [`mkdir -p ${shellQuote3(remoteDir)}`, `cat > ${shellQuote3(remotePath)}`];
|
|
39141
39506
|
if (options.mode != null) {
|
|
39142
39507
|
parts.push(`chmod ${options.mode.toString(8)} ${shellQuote3(remotePath)}`);
|
|
@@ -39204,7 +39569,7 @@ function shellQuote3(s) {
|
|
|
39204
39569
|
// src/services/providers/railway.ts
|
|
39205
39570
|
var import_child_process32 = require("child_process");
|
|
39206
39571
|
var import_util7 = require("util");
|
|
39207
|
-
var
|
|
39572
|
+
var path79 = __toESM(require("path"));
|
|
39208
39573
|
var execFileP9 = (0, import_util7.promisify)(import_child_process32.execFile);
|
|
39209
39574
|
var MAX_BUFFER4 = 8 * 1024 * 1024;
|
|
39210
39575
|
function resetStdinForChild4() {
|
|
@@ -39440,7 +39805,7 @@ var RailwayProvider = class {
|
|
|
39440
39805
|
if (!projectId || !serviceId) {
|
|
39441
39806
|
throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
|
|
39442
39807
|
}
|
|
39443
|
-
const remoteDir =
|
|
39808
|
+
const remoteDir = path79.posix.dirname(remotePath);
|
|
39444
39809
|
const parts = [`mkdir -p ${shellQuote4(remoteDir)}`, `cat > ${shellQuote4(remotePath)}`];
|
|
39445
39810
|
if (options.mode != null) {
|
|
39446
39811
|
parts.push(`chmod ${options.mode.toString(8)} ${shellQuote4(remotePath)}`);
|
|
@@ -39971,9 +40336,9 @@ async function probeCodeamPair(provider, workspace) {
|
|
|
39971
40336
|
}
|
|
39972
40337
|
async function stopWorkspaceFromLocal(target) {
|
|
39973
40338
|
if (target.provider.id === "github-codespaces") {
|
|
39974
|
-
const { execFile:
|
|
40339
|
+
const { execFile: execFile15 } = await import("child_process");
|
|
39975
40340
|
const { promisify: promisify11 } = await import("util");
|
|
39976
|
-
const execFileP10 = promisify11(
|
|
40341
|
+
const execFileP10 = promisify11(execFile15);
|
|
39977
40342
|
await execFileP10("gh", ["codespace", "stop", "-c", target.id], { maxBuffer: 8 * 1024 * 1024 });
|
|
39978
40343
|
return;
|
|
39979
40344
|
}
|
|
@@ -40086,8 +40451,8 @@ async function invite() {
|
|
|
40086
40451
|
var import_node_dns = require("dns");
|
|
40087
40452
|
var import_node_util5 = require("util");
|
|
40088
40453
|
var import_node_crypto13 = require("crypto");
|
|
40089
|
-
var
|
|
40090
|
-
var
|
|
40454
|
+
var fs71 = __toESM(require("fs"));
|
|
40455
|
+
var path80 = __toESM(require("path"));
|
|
40091
40456
|
var import_picocolors14 = __toESM(require("picocolors"));
|
|
40092
40457
|
var dnsResolveP = (0, import_node_util5.promisify)(import_node_dns.resolve);
|
|
40093
40458
|
async function checkDns(apiBase2) {
|
|
@@ -40143,13 +40508,13 @@ async function checkHealth(apiBase2) {
|
|
|
40143
40508
|
}
|
|
40144
40509
|
}
|
|
40145
40510
|
function checkConfigDir() {
|
|
40146
|
-
const dir =
|
|
40511
|
+
const dir = path80.join(require("os").homedir(), ".codeam");
|
|
40147
40512
|
try {
|
|
40148
|
-
|
|
40149
|
-
const probe =
|
|
40150
|
-
|
|
40151
|
-
const read2 =
|
|
40152
|
-
|
|
40513
|
+
fs71.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
40514
|
+
const probe = path80.join(dir, ".doctor-probe");
|
|
40515
|
+
fs71.writeFileSync(probe, "ok", { mode: 384 });
|
|
40516
|
+
const read2 = fs71.readFileSync(probe, "utf8");
|
|
40517
|
+
fs71.unlinkSync(probe);
|
|
40153
40518
|
if (read2 !== "ok") throw new Error("write/read round-trip mismatch");
|
|
40154
40519
|
return {
|
|
40155
40520
|
id: "config-dir",
|
|
@@ -40213,7 +40578,7 @@ function checkNodePty() {
|
|
|
40213
40578
|
detail: "not required on this platform"
|
|
40214
40579
|
};
|
|
40215
40580
|
}
|
|
40216
|
-
const vendoredPath =
|
|
40581
|
+
const vendoredPath = path80.join(__dirname, "vendor", "node-pty");
|
|
40217
40582
|
for (const target of [vendoredPath, "node-pty"]) {
|
|
40218
40583
|
try {
|
|
40219
40584
|
require(target);
|
|
@@ -40255,7 +40620,7 @@ function checkChokidar() {
|
|
|
40255
40620
|
}
|
|
40256
40621
|
async function doctor(args2 = []) {
|
|
40257
40622
|
const json = args2.includes("--json");
|
|
40258
|
-
const cliVersion = true ? "2.61.
|
|
40623
|
+
const cliVersion = true ? "2.61.78" : "0.0.0-dev";
|
|
40259
40624
|
const apiBase2 = resolveApiBaseUrl();
|
|
40260
40625
|
const diagnosticId = (0, import_node_crypto13.randomUUID)();
|
|
40261
40626
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -40452,10 +40817,10 @@ async function completion(args2) {
|
|
|
40452
40817
|
}
|
|
40453
40818
|
|
|
40454
40819
|
// src/integrations/mcp-run.ts
|
|
40455
|
-
var
|
|
40456
|
-
var
|
|
40820
|
+
var import_node_child_process32 = require("child_process");
|
|
40821
|
+
var import_node_fs12 = require("fs");
|
|
40457
40822
|
var import_node_os14 = __toESM(require("os"));
|
|
40458
|
-
var
|
|
40823
|
+
var import_node_path12 = __toESM(require("path"));
|
|
40459
40824
|
|
|
40460
40825
|
// src/integrations/token-client.ts
|
|
40461
40826
|
var REFRESH_AHEAD_MS = 5 * 60 * 1e3;
|
|
@@ -40508,7 +40873,7 @@ var IntegrationTokenClient = class {
|
|
|
40508
40873
|
};
|
|
40509
40874
|
|
|
40510
40875
|
// src/integrations/stdio-proxy.ts
|
|
40511
|
-
var
|
|
40876
|
+
var import_node_child_process31 = require("child_process");
|
|
40512
40877
|
var import_node_readline3 = __toESM(require("readline"));
|
|
40513
40878
|
var RESTART_CHECK_INTERVAL_MS = 3e4;
|
|
40514
40879
|
var SIGKILL_ESCALATION_MS = 2e3;
|
|
@@ -40629,7 +40994,7 @@ var RestartableStdioProxy = class {
|
|
|
40629
40994
|
}
|
|
40630
40995
|
async spawnChild(stdout, preResolved) {
|
|
40631
40996
|
const spec = preResolved ?? await this.opts.spawnSpec();
|
|
40632
|
-
const spawn44 = this.opts.spawnImpl ??
|
|
40997
|
+
const spawn44 = this.opts.spawnImpl ?? import_node_child_process31.spawn;
|
|
40633
40998
|
const child = spawn44(spec.command, spec.args, {
|
|
40634
40999
|
env: { ...process.env, ...spec.env },
|
|
40635
41000
|
// env only — never argv
|
|
@@ -40669,7 +41034,7 @@ function resolveDelivery(id) {
|
|
|
40669
41034
|
function commandExists(command2) {
|
|
40670
41035
|
try {
|
|
40671
41036
|
const probe = process.platform === "win32" ? "where" : "which";
|
|
40672
|
-
(0,
|
|
41037
|
+
(0, import_node_child_process32.execFileSync)(probe, [command2], { stdio: "ignore" });
|
|
40673
41038
|
return true;
|
|
40674
41039
|
} catch {
|
|
40675
41040
|
return false;
|
|
@@ -40677,13 +41042,13 @@ function commandExists(command2) {
|
|
|
40677
41042
|
}
|
|
40678
41043
|
function localBinCandidates(command2) {
|
|
40679
41044
|
return [
|
|
40680
|
-
|
|
40681
|
-
|
|
41045
|
+
import_node_path12.default.join(import_node_os14.default.homedir(), ".local", "bin", command2),
|
|
41046
|
+
import_node_path12.default.join(import_node_os14.default.homedir(), ".cargo", "bin", command2)
|
|
40682
41047
|
];
|
|
40683
41048
|
}
|
|
40684
41049
|
function resolveLauncherPath(command2, deps = {
|
|
40685
41050
|
commandExists,
|
|
40686
|
-
existsSync:
|
|
41051
|
+
existsSync: import_node_fs12.existsSync
|
|
40687
41052
|
}) {
|
|
40688
41053
|
if (deps.commandExists(command2)) return command2;
|
|
40689
41054
|
for (const candidate of localBinCandidates(command2)) {
|
|
@@ -40702,7 +41067,7 @@ function ensureCommand(command2) {
|
|
|
40702
41067
|
}
|
|
40703
41068
|
if (command2 === "uvx") {
|
|
40704
41069
|
try {
|
|
40705
|
-
(0,
|
|
41070
|
+
(0, import_node_child_process32.execSync)("curl -LsSf https://astral.sh/uv/install.sh | sh", {
|
|
40706
41071
|
stdio: ["ignore", process.stderr, process.stderr],
|
|
40707
41072
|
timeout: 18e4,
|
|
40708
41073
|
env: { ...process.env, UV_NO_MODIFY_PATH: "1" }
|
|
@@ -40711,7 +41076,7 @@ function ensureCommand(command2) {
|
|
|
40711
41076
|
}
|
|
40712
41077
|
if (resolveLauncherPath(command2) !== command2) return;
|
|
40713
41078
|
try {
|
|
40714
|
-
(0,
|
|
41079
|
+
(0, import_node_child_process32.execSync)("python3 -m pip install --user --quiet uv", {
|
|
40715
41080
|
stdio: ["ignore", process.stderr, process.stderr],
|
|
40716
41081
|
timeout: 18e4
|
|
40717
41082
|
});
|
|
@@ -40777,7 +41142,7 @@ async function mcpRun(args2) {
|
|
|
40777
41142
|
// src/commands/version.ts
|
|
40778
41143
|
var import_picocolors15 = __toESM(require("picocolors"));
|
|
40779
41144
|
function version2() {
|
|
40780
|
-
const v = true ? "2.61.
|
|
41145
|
+
const v = true ? "2.61.78" : "unknown";
|
|
40781
41146
|
console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
|
|
40782
41147
|
}
|
|
40783
41148
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeam-cli",
|
|
3
|
-
"version": "2.61.
|
|
3
|
+
"version": "2.61.78",
|
|
4
4
|
"description": "Workflow-continuity bridge for AI coding agents. Wrap Claude Code or Codex in a PTY and supervise, approve, and redirect the session from any device — async. The terminal companion for CodeAgent Mobile.",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "dist/index.js",
|