codeam-cli 2.61.77 → 2.61.79
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 +13 -0
- package/dist/index.js +498 -127
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,19 @@ 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.78] — 2026-07-31
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **shared:** Session-tools wire — SESSION_INTEGRATIONS_CHANGED event + repo stack-detect maps
|
|
12
|
+
- **cli:** Session-tools relay — integrations_sync + integrations_detect handlers
|
|
13
|
+
|
|
14
|
+
## [2.61.77] — 2026-07-31
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- **shared:** Add Convex (convex.dev) database integration
|
|
19
|
+
|
|
7
20
|
## [2.61.76] — 2026-07-30
|
|
8
21
|
|
|
9
22
|
### Added
|
package/dist/index.js
CHANGED
|
@@ -1521,28 +1521,34 @@ var INTEGRATION_REGISTRY = {
|
|
|
1521
1521
|
name: "Convex",
|
|
1522
1522
|
icon: "convex",
|
|
1523
1523
|
category: "database",
|
|
1524
|
-
// LIVE —
|
|
1525
|
-
//
|
|
1526
|
-
//
|
|
1527
|
-
//
|
|
1528
|
-
//
|
|
1529
|
-
//
|
|
1530
|
-
//
|
|
1531
|
-
//
|
|
1532
|
-
//
|
|
1524
|
+
// LIVE — api_key rail (the user pastes a Convex DEPLOY KEY).
|
|
1525
|
+
// ⚠️ Convex's OAuth application token was tried first and DOES NOT WORK with
|
|
1526
|
+
// the MCP: it's a narrow Management-API credential — verified live it fails
|
|
1527
|
+
// `convex mcp start` as BOTH CONVEX_DEPLOY_KEY and CONVEX_OVERRIDE_ACCESS_TOKEN,
|
|
1528
|
+
// and can't even enumerate the team's deployments ("requires a Personal
|
|
1529
|
+
// Access Token"). The Convex MCP's DOCUMENTED headless credential is a
|
|
1530
|
+
// DEPLOY KEY (CONVEX_DEPLOY_KEY=dev:…|… / prod:… / project:…), so the user
|
|
1531
|
+
// pastes one (Convex Dashboard → Project Settings → Deploy Keys), exactly
|
|
1532
|
+
// like Azure DevOps / Datadog / Trello. No OAuth app, no GSM secret.
|
|
1533
1533
|
enabled: true,
|
|
1534
1534
|
auth: {
|
|
1535
|
-
kind: "
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1535
|
+
kind: "api_key",
|
|
1536
|
+
fields: [
|
|
1537
|
+
{
|
|
1538
|
+
key: "accessToken",
|
|
1539
|
+
label: "Convex deploy key",
|
|
1540
|
+
placeholder: "prod:happy-animal-123|eyJ2\u2026",
|
|
1541
|
+
secret: true,
|
|
1542
|
+
help: "Convex Dashboard \u2192 Project Settings \u2192 Deploy Keys \u2192 Generate a deploy key."
|
|
1543
|
+
}
|
|
1544
|
+
]
|
|
1539
1545
|
},
|
|
1540
1546
|
delivery: {
|
|
1541
1547
|
mcp: {
|
|
1542
1548
|
// Convex's OFFICIAL MCP server ships inside the `convex` npm package
|
|
1543
|
-
// (`convex mcp start`). The
|
|
1544
|
-
//
|
|
1545
|
-
//
|
|
1549
|
+
// (`convex mcp start`). The pasted deploy key is fed via CONVEX_DEPLOY_KEY
|
|
1550
|
+
// (env only, never argv) — its documented non-interactive credential.
|
|
1551
|
+
// Version PINNED; bump only after re-verifying headless.
|
|
1546
1552
|
command: "npx",
|
|
1547
1553
|
args: ["-y", "convex@1.42.3", "mcp", "start"],
|
|
1548
1554
|
envMapping: {
|
|
@@ -1666,6 +1672,9 @@ var INTEGRATION_REGISTRY = {
|
|
|
1666
1672
|
}
|
|
1667
1673
|
}
|
|
1668
1674
|
};
|
|
1675
|
+
function getEnabledIntegrations() {
|
|
1676
|
+
return Object.values(INTEGRATION_REGISTRY).filter((m) => m.enabled);
|
|
1677
|
+
}
|
|
1669
1678
|
function getIntegration(id) {
|
|
1670
1679
|
const meta = INTEGRATION_REGISTRY[id];
|
|
1671
1680
|
if (!meta) throw new Error(`Unknown integration id: ${id}`);
|
|
@@ -1675,6 +1684,145 @@ function isKnownIntegrationId(id) {
|
|
|
1675
1684
|
return id in INTEGRATION_REGISTRY;
|
|
1676
1685
|
}
|
|
1677
1686
|
|
|
1687
|
+
// ../../packages/shared/src/integrations/stack-detect.ts
|
|
1688
|
+
var DEP_TO_INTEGRATION = {
|
|
1689
|
+
// errors / observability
|
|
1690
|
+
"@sentry/node": "sentry",
|
|
1691
|
+
"@sentry/react": "sentry",
|
|
1692
|
+
"@sentry/nextjs": "sentry",
|
|
1693
|
+
"@sentry/browser": "sentry",
|
|
1694
|
+
"sentry-sdk": "sentry",
|
|
1695
|
+
"dd-trace": "datadog",
|
|
1696
|
+
"datadog-api-client": "datadog",
|
|
1697
|
+
"datadog-metrics": "datadog",
|
|
1698
|
+
// analytics
|
|
1699
|
+
"posthog-js": "posthog",
|
|
1700
|
+
"posthog-node": "posthog",
|
|
1701
|
+
posthog: "posthog",
|
|
1702
|
+
mixpanel: "mixpanel",
|
|
1703
|
+
"mixpanel-browser": "mixpanel",
|
|
1704
|
+
// database / backend platforms
|
|
1705
|
+
convex: "convex",
|
|
1706
|
+
"@supabase/supabase-js": "supabase",
|
|
1707
|
+
"supabase": "supabase",
|
|
1708
|
+
// infra / deploy
|
|
1709
|
+
vercel: "vercel",
|
|
1710
|
+
"@vercel/node": "vercel",
|
|
1711
|
+
wrangler: "cloudflare",
|
|
1712
|
+
// comms
|
|
1713
|
+
"@slack/web-api": "slack",
|
|
1714
|
+
"@slack/bolt": "slack",
|
|
1715
|
+
"discord.js": "discord",
|
|
1716
|
+
"discord-py": "discord",
|
|
1717
|
+
"discord": "discord",
|
|
1718
|
+
// trackers / docs / design
|
|
1719
|
+
"@linear/sdk": "linear",
|
|
1720
|
+
"@notionhq/client": "notion",
|
|
1721
|
+
"jira.js": "jira",
|
|
1722
|
+
jira: "jira",
|
|
1723
|
+
newman: "postman",
|
|
1724
|
+
"figma-api": "figma",
|
|
1725
|
+
"figma-js": "figma",
|
|
1726
|
+
// email / automation
|
|
1727
|
+
resend: "resend",
|
|
1728
|
+
n8n: "n8n"
|
|
1729
|
+
};
|
|
1730
|
+
var DEP_PREFIX_TO_INTEGRATION = [
|
|
1731
|
+
["@sentry/", "sentry"],
|
|
1732
|
+
["@vercel/", "vercel"],
|
|
1733
|
+
["@cloudflare/", "cloudflare"],
|
|
1734
|
+
["@supabase/", "supabase"],
|
|
1735
|
+
["@slack/", "slack"],
|
|
1736
|
+
["@datadog/", "datadog"],
|
|
1737
|
+
["@linear/", "linear"],
|
|
1738
|
+
["@notionhq/", "notion"]
|
|
1739
|
+
];
|
|
1740
|
+
var FRONTEND_MARKERS = [
|
|
1741
|
+
"react",
|
|
1742
|
+
"react-dom",
|
|
1743
|
+
"next",
|
|
1744
|
+
"vue",
|
|
1745
|
+
"nuxt",
|
|
1746
|
+
"@angular/core",
|
|
1747
|
+
"svelte",
|
|
1748
|
+
"@sveltejs/kit",
|
|
1749
|
+
"solid-js",
|
|
1750
|
+
"astro",
|
|
1751
|
+
"gatsby",
|
|
1752
|
+
"remix",
|
|
1753
|
+
"@remix-run/react"
|
|
1754
|
+
];
|
|
1755
|
+
var MOBILE_MARKERS = ["react-native", "expo", "@react-native/core", "@ionic/core", "flutter"];
|
|
1756
|
+
var BACKEND_MARKERS = [
|
|
1757
|
+
"express",
|
|
1758
|
+
"fastify",
|
|
1759
|
+
"@nestjs/core",
|
|
1760
|
+
"koa",
|
|
1761
|
+
"@hapi/hapi",
|
|
1762
|
+
"django",
|
|
1763
|
+
"flask",
|
|
1764
|
+
"fastapi",
|
|
1765
|
+
"rails",
|
|
1766
|
+
"sinatra",
|
|
1767
|
+
"gin-gonic",
|
|
1768
|
+
"laravel/framework",
|
|
1769
|
+
"actix-web",
|
|
1770
|
+
"spring-boot"
|
|
1771
|
+
];
|
|
1772
|
+
function hasAny(deps, markers) {
|
|
1773
|
+
for (const m of markers) if (deps.has(m)) return true;
|
|
1774
|
+
return false;
|
|
1775
|
+
}
|
|
1776
|
+
function classifyStack(depNames) {
|
|
1777
|
+
const deps = new Set(depNames);
|
|
1778
|
+
const mobile = hasAny(deps, MOBILE_MARKERS);
|
|
1779
|
+
if (mobile) return "mobile";
|
|
1780
|
+
const frontend = hasAny(deps, FRONTEND_MARKERS);
|
|
1781
|
+
const backend = hasAny(deps, BACKEND_MARKERS);
|
|
1782
|
+
if (frontend && backend) return "fullstack";
|
|
1783
|
+
if (frontend) return "frontend";
|
|
1784
|
+
if (backend) return "backend";
|
|
1785
|
+
return "unknown";
|
|
1786
|
+
}
|
|
1787
|
+
function detectedIntegrationsFromDeps(depNames) {
|
|
1788
|
+
const out2 = [];
|
|
1789
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1790
|
+
const push = (id) => {
|
|
1791
|
+
if (!seen.has(id)) {
|
|
1792
|
+
seen.add(id);
|
|
1793
|
+
out2.push(id);
|
|
1794
|
+
}
|
|
1795
|
+
};
|
|
1796
|
+
for (const name of depNames) {
|
|
1797
|
+
const exact = DEP_TO_INTEGRATION[name];
|
|
1798
|
+
if (exact) {
|
|
1799
|
+
push(exact);
|
|
1800
|
+
continue;
|
|
1801
|
+
}
|
|
1802
|
+
for (const [prefix, id] of DEP_PREFIX_TO_INTEGRATION) {
|
|
1803
|
+
if (name.startsWith(prefix)) {
|
|
1804
|
+
push(id);
|
|
1805
|
+
break;
|
|
1806
|
+
}
|
|
1807
|
+
}
|
|
1808
|
+
}
|
|
1809
|
+
return out2;
|
|
1810
|
+
}
|
|
1811
|
+
var STACK_TO_RECOMMENDED = {
|
|
1812
|
+
frontend: ["figma", "sentry", "posthog", "vercel"],
|
|
1813
|
+
backend: ["sentry", "datadog", "supabase", "convex", "cloudflare"],
|
|
1814
|
+
fullstack: ["sentry", "posthog", "vercel", "supabase", "convex"],
|
|
1815
|
+
mobile: ["sentry", "posthog"],
|
|
1816
|
+
unknown: []
|
|
1817
|
+
};
|
|
1818
|
+
function recommendForDeps(depNames) {
|
|
1819
|
+
const stack = classifyStack(depNames);
|
|
1820
|
+
const detected = detectedIntegrationsFromDeps(depNames);
|
|
1821
|
+
const detectedSet = new Set(detected);
|
|
1822
|
+
const recommended = STACK_TO_RECOMMENDED[stack].filter((id) => !detectedSet.has(id));
|
|
1823
|
+
return { stack, detected, recommended, source: "scan" };
|
|
1824
|
+
}
|
|
1825
|
+
|
|
1678
1826
|
// ../../packages/shared/src/skills/code-review.ts
|
|
1679
1827
|
var CODE_REVIEW_BODY = `Use this skill when reviewing a pull request. It defines what a high-signal
|
|
1680
1828
|
review looks like so your inline comments are worth the author's time.
|
|
@@ -2102,6 +2250,14 @@ var USER_EVENTS = {
|
|
|
2102
2250
|
INTEGRATION_LINKED: "integration_linked",
|
|
2103
2251
|
INTEGRATION_UNLINKED: "integration_unlinked",
|
|
2104
2252
|
INTEGRATION_CREDENTIAL_INVALID: "integration_credential_invalid",
|
|
2253
|
+
// Session Tools — add/remove Agent Toolkit integrations on an ALREADY-ACTIVE
|
|
2254
|
+
// session. The backend publishes SESSION_INTEGRATIONS_CHANGED after it persists
|
|
2255
|
+
// the new attached set + relays `integrations_sync` to the box (the CLI rewrites
|
|
2256
|
+
// the manifest + reprovisions the live agent, answered synchronously via the
|
|
2257
|
+
// command result). Drives live UI on the sending device AND any other paired
|
|
2258
|
+
// device on the same session. Mirrored in repo A. (`integrations_detect` is a
|
|
2259
|
+
// pure request/response over the relay — no event.)
|
|
2260
|
+
SESSION_INTEGRATIONS_CHANGED: "session_integrations_changed",
|
|
2105
2261
|
// CodeRabbit reviewer — the CLI posts these to /api/coderabbit/events; the
|
|
2106
2262
|
// backend re-publishes them on the per-user SSE bus (mirrored in repo A).
|
|
2107
2263
|
CODERABBIT_PROGRESS: "coderabbit_progress",
|
|
@@ -2306,11 +2462,11 @@ function quiet(fn) {
|
|
|
2306
2462
|
log.debug(TAG, "ignored sync error", err);
|
|
2307
2463
|
}
|
|
2308
2464
|
}
|
|
2309
|
-
function rmIfExistsQuiet(
|
|
2465
|
+
function rmIfExistsQuiet(path82) {
|
|
2310
2466
|
try {
|
|
2311
|
-
fs2.rmSync(
|
|
2467
|
+
fs2.rmSync(path82, { force: true });
|
|
2312
2468
|
} catch (err) {
|
|
2313
|
-
log.debug(TAG, `rmIfExists failed for ${
|
|
2469
|
+
log.debug(TAG, `rmIfExists failed for ${path82}`, err);
|
|
2314
2470
|
}
|
|
2315
2471
|
}
|
|
2316
2472
|
function killQuiet(target, signal = "SIGTERM") {
|
|
@@ -2494,8 +2650,8 @@ function createGetModuleFromFilename(basePath = process.argv[1] ? (0, import_pat
|
|
|
2494
2650
|
return decodedFile;
|
|
2495
2651
|
};
|
|
2496
2652
|
}
|
|
2497
|
-
function normalizeWindowsPath(
|
|
2498
|
-
return
|
|
2653
|
+
function normalizeWindowsPath(path82) {
|
|
2654
|
+
return path82.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
|
|
2499
2655
|
}
|
|
2500
2656
|
|
|
2501
2657
|
// ../../node_modules/@posthog/core/dist/featureFlagUtils.mjs
|
|
@@ -4975,9 +5131,9 @@ async function addSourceContext(frames) {
|
|
|
4975
5131
|
LRU_FILE_CONTENTS_CACHE.reduce();
|
|
4976
5132
|
return frames;
|
|
4977
5133
|
}
|
|
4978
|
-
function getContextLinesFromFile(
|
|
5134
|
+
function getContextLinesFromFile(path82, ranges, output) {
|
|
4979
5135
|
return new Promise((resolve9) => {
|
|
4980
|
-
const stream = (0, import_node_fs.createReadStream)(
|
|
5136
|
+
const stream = (0, import_node_fs.createReadStream)(path82);
|
|
4981
5137
|
const lineReaded = (0, import_node_readline.createInterface)({
|
|
4982
5138
|
input: stream
|
|
4983
5139
|
});
|
|
@@ -4992,7 +5148,7 @@ function getContextLinesFromFile(path81, ranges, output) {
|
|
|
4992
5148
|
let rangeStart = range[0];
|
|
4993
5149
|
let rangeEnd = range[1];
|
|
4994
5150
|
function onStreamError() {
|
|
4995
|
-
LRU_FILE_CONTENTS_FS_READ_FAILED.set(
|
|
5151
|
+
LRU_FILE_CONTENTS_FS_READ_FAILED.set(path82, 1);
|
|
4996
5152
|
lineReaded.close();
|
|
4997
5153
|
lineReaded.removeAllListeners();
|
|
4998
5154
|
destroyStreamAndResolve();
|
|
@@ -5053,8 +5209,8 @@ function clearLineContext(frame) {
|
|
|
5053
5209
|
delete frame.context_line;
|
|
5054
5210
|
delete frame.post_context;
|
|
5055
5211
|
}
|
|
5056
|
-
function shouldSkipContextLinesForFile(
|
|
5057
|
-
return
|
|
5212
|
+
function shouldSkipContextLinesForFile(path82) {
|
|
5213
|
+
return path82.startsWith("node:") || path82.endsWith(".min.js") || path82.endsWith(".min.cjs") || path82.endsWith(".min.mjs") || path82.startsWith("data:");
|
|
5058
5214
|
}
|
|
5059
5215
|
function shouldSkipContextLinesForFrame(frame) {
|
|
5060
5216
|
if (void 0 !== frame.lineno && frame.lineno > MAX_CONTEXTLINES_LINENO) return true;
|
|
@@ -7208,7 +7364,7 @@ function readAnonId() {
|
|
|
7208
7364
|
}
|
|
7209
7365
|
function superProperties() {
|
|
7210
7366
|
return {
|
|
7211
|
-
cliVersion: true ? "2.61.
|
|
7367
|
+
cliVersion: true ? "2.61.79" : "0.0.0-dev",
|
|
7212
7368
|
nodeVersion: process.version,
|
|
7213
7369
|
platform: process.platform,
|
|
7214
7370
|
arch: process.arch,
|
|
@@ -7389,7 +7545,7 @@ var os4 = __toESM(require("os"));
|
|
|
7389
7545
|
// package.json
|
|
7390
7546
|
var package_default = {
|
|
7391
7547
|
name: "codeam-cli",
|
|
7392
|
-
version: "2.61.
|
|
7548
|
+
version: "2.61.79",
|
|
7393
7549
|
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
7550
|
type: "commonjs",
|
|
7395
7551
|
main: "dist/index.js",
|
|
@@ -8621,7 +8777,7 @@ var CommandRelayService = class _CommandRelayService {
|
|
|
8621
8777
|
// fresh + clear the "CLI update available" banner after a self-update
|
|
8622
8778
|
// (a codespace that reinstalls @latest reconnects via heartbeat, not
|
|
8623
8779
|
// pair/reconnect). Older backends ignore the extra field.
|
|
8624
|
-
..."2.61.
|
|
8780
|
+
..."2.61.79" ? { ideVersion: "2.61.79" } : {}
|
|
8625
8781
|
}).then(() => log.trace("relay", `heartbeat ok online=${online}`)).catch((err) => log.trace("relay", `heartbeat failed online=${online}`, err));
|
|
8626
8782
|
}
|
|
8627
8783
|
/**
|
|
@@ -15230,8 +15386,8 @@ function pickLine(obj) {
|
|
|
15230
15386
|
function toHunk(raw, groupSeverity) {
|
|
15231
15387
|
if (!raw || typeof raw !== "object") return null;
|
|
15232
15388
|
const o = raw;
|
|
15233
|
-
const
|
|
15234
|
-
if (!
|
|
15389
|
+
const path82 = asString(pick(o, ["file_path", "filePath", "file", "path", "filename", "fileName"])) ?? asString(pick(o, ["location"])?.path);
|
|
15390
|
+
if (!path82) return null;
|
|
15235
15391
|
const message = asString(
|
|
15236
15392
|
pick(o, [
|
|
15237
15393
|
"comment",
|
|
@@ -15248,7 +15404,7 @@ function toHunk(raw, groupSeverity) {
|
|
|
15248
15404
|
const severity = normSeverity(pick(o, ["severity", "level", "priority", "impact"])) ?? normSeverity(groupSeverity);
|
|
15249
15405
|
const locObj = pick(o, ["location"]) ?? o;
|
|
15250
15406
|
return {
|
|
15251
|
-
path:
|
|
15407
|
+
path: path82.trim(),
|
|
15252
15408
|
line: pickLine(o) ?? pickLine(locObj),
|
|
15253
15409
|
severity,
|
|
15254
15410
|
message: (title && message ? `${title}: ${message}` : title || message).trim() || "(no message)"
|
|
@@ -15331,10 +15487,10 @@ function parsePlain(stdout) {
|
|
|
15331
15487
|
for (const line of stdout.split(/\r?\n/)) {
|
|
15332
15488
|
const m = line.match(HUNK_LINE_RE);
|
|
15333
15489
|
if (!m) continue;
|
|
15334
|
-
const [,
|
|
15335
|
-
if (!
|
|
15490
|
+
const [, path82, lineNo, sevToken, message] = m;
|
|
15491
|
+
if (!path82 || !lineNo || !message) continue;
|
|
15336
15492
|
hunks.push({
|
|
15337
|
-
path:
|
|
15493
|
+
path: path82.trim(),
|
|
15338
15494
|
line: Number(lineNo),
|
|
15339
15495
|
severity: sevToken ? SEVERITY_MAP[sevToken.toLowerCase()] : void 0,
|
|
15340
15496
|
message: message.trim().replace(/^[*-]\s+/, "")
|
|
@@ -19735,7 +19891,7 @@ async function autoUpgradeBeforeCriticalCommand() {
|
|
|
19735
19891
|
if (process.env.NODE_ENV === "test") return;
|
|
19736
19892
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
19737
19893
|
if (process.env.CI) return;
|
|
19738
|
-
const current = true ? "2.61.
|
|
19894
|
+
const current = true ? "2.61.79" : null;
|
|
19739
19895
|
if (!current) return;
|
|
19740
19896
|
const cache = readCache();
|
|
19741
19897
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -19752,7 +19908,7 @@ function checkForUpdates() {
|
|
|
19752
19908
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
19753
19909
|
if (process.env.CI) return;
|
|
19754
19910
|
if (!process.stdout.isTTY) return;
|
|
19755
|
-
const current = true ? "2.61.
|
|
19911
|
+
const current = true ? "2.61.79" : null;
|
|
19756
19912
|
if (!current) return;
|
|
19757
19913
|
const cache = readCache();
|
|
19758
19914
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -19772,7 +19928,7 @@ var SELF_UPDATE_INTERVAL_MS = 60 * 60 * 1e3;
|
|
|
19772
19928
|
var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
|
|
19773
19929
|
var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
|
|
19774
19930
|
function currentCliVersion() {
|
|
19775
|
-
return true ? "2.61.
|
|
19931
|
+
return true ? "2.61.79" : null;
|
|
19776
19932
|
}
|
|
19777
19933
|
function runCmd(cmd, args2, timeoutMs) {
|
|
19778
19934
|
return new Promise((resolve9) => {
|
|
@@ -25666,11 +25822,11 @@ function resolveTokenValue(args2) {
|
|
|
25666
25822
|
}
|
|
25667
25823
|
const fileFlag = args2.find((a) => a.startsWith("--token-file="));
|
|
25668
25824
|
if (fileFlag) {
|
|
25669
|
-
const
|
|
25825
|
+
const path82 = fileFlag.slice("--token-file=".length);
|
|
25670
25826
|
try {
|
|
25671
|
-
const content = fs59.readFileSync(
|
|
25672
|
-
if (content.length === 0) fail(`--token-file ${
|
|
25673
|
-
rmIfExistsQuiet(
|
|
25827
|
+
const content = fs59.readFileSync(path82, "utf8").trim();
|
|
25828
|
+
if (content.length === 0) fail(`--token-file ${path82} is empty`);
|
|
25829
|
+
rmIfExistsQuiet(path82);
|
|
25674
25830
|
return content;
|
|
25675
25831
|
} catch (err) {
|
|
25676
25832
|
fail(`Could not read --token-file: ${err.message}`);
|
|
@@ -31901,6 +32057,51 @@ var AcpClient = class {
|
|
|
31901
32057
|
if (loaded?.modes !== void 0) this.captureModes(loaded.modes ?? null);
|
|
31902
32058
|
log.info("acpClient", `loadSession \u2190 ok sessionId=${sessionId.slice(0, 8)}`);
|
|
31903
32059
|
}
|
|
32060
|
+
/** The conversation id the agent is currently serving (null before start). */
|
|
32061
|
+
getActiveSessionId() {
|
|
32062
|
+
return this.sessionId;
|
|
32063
|
+
}
|
|
32064
|
+
/**
|
|
32065
|
+
* Re-register the agent's MCP servers on an ALREADY-RUNNING session (Session
|
|
32066
|
+
* Tools — adding/removing an integration mid-session). MCP servers are bound
|
|
32067
|
+
* at `session/new`, and `session/load` on the CURRENTLY-running session wedges
|
|
32068
|
+
* Claude (the self-load guard in {@link loadSession}), so the only reliable way
|
|
32069
|
+
* to add a server to a live session is a controlled RESPAWN that resumes the
|
|
32070
|
+
* conversation: kill the agent → fresh `startOnce()` (a new session S2 bound to
|
|
32071
|
+
* the new `mcpServers`) → `loadSession(prevConversationId)` (S1 ≠ S2, so the
|
|
32072
|
+
* self-load guard doesn't fire) to resume the thread with the new tools live.
|
|
32073
|
+
*
|
|
32074
|
+
* Best-effort + degrade-safe: `this.opts.mcpServers` is updated FIRST (so even
|
|
32075
|
+
* a failed respawn leaves the new set to bind on the next natural
|
|
32076
|
+
* re-establishment — wake/resume/recovery), and any throw resolves to
|
|
32077
|
+
* `'deferred'` rather than tearing down the session. Returns which happened so
|
|
32078
|
+
* the caller can tell the user "active now" vs "active on next restart".
|
|
32079
|
+
*/
|
|
32080
|
+
async reprovisionMcp(servers) {
|
|
32081
|
+
this.opts.mcpServers = servers;
|
|
32082
|
+
const prevConversationId = this.sessionId;
|
|
32083
|
+
if (!this.connection || !prevConversationId) return "deferred";
|
|
32084
|
+
try {
|
|
32085
|
+
log.info(
|
|
32086
|
+
"acpClient",
|
|
32087
|
+
`reprovisionMcp \u2192 respawn to bind ${servers.length} MCP server(s), resuming ${prevConversationId.slice(0, 8)}`
|
|
32088
|
+
);
|
|
32089
|
+
await this.stop();
|
|
32090
|
+
this.stopping = false;
|
|
32091
|
+
await this.startOnce();
|
|
32092
|
+
if (this.supportsLoadSession && prevConversationId !== this.sessionId) {
|
|
32093
|
+
await this.loadSession(prevConversationId);
|
|
32094
|
+
}
|
|
32095
|
+
log.info("acpClient", "reprovisionMcp \u2190 reloaded (tools live)");
|
|
32096
|
+
return "reloaded";
|
|
32097
|
+
} catch (err) {
|
|
32098
|
+
log.warn(
|
|
32099
|
+
"acpClient",
|
|
32100
|
+
`reprovisionMcp respawn failed \u2014 tools apply on next restart: ${err instanceof Error ? err.message : String(err)}`
|
|
32101
|
+
);
|
|
32102
|
+
return "deferred";
|
|
32103
|
+
}
|
|
32104
|
+
}
|
|
31904
32105
|
/**
|
|
31905
32106
|
* Enumerate the workspace's conversations via the ACP `session/list` RPC.
|
|
31906
32107
|
* Agent-agnostic — works for ANY adapter that advertises
|
|
@@ -33275,7 +33476,7 @@ function defaultRunGit(cwd, args2) {
|
|
|
33275
33476
|
});
|
|
33276
33477
|
}
|
|
33277
33478
|
async function discoverRepos(workingDir, maxDepth = 4) {
|
|
33278
|
-
const
|
|
33479
|
+
const fs72 = await import("fs/promises");
|
|
33279
33480
|
const out2 = [];
|
|
33280
33481
|
await walk(workingDir, 0);
|
|
33281
33482
|
return out2;
|
|
@@ -33283,7 +33484,7 @@ async function discoverRepos(workingDir, maxDepth = 4) {
|
|
|
33283
33484
|
if (depth > maxDepth) return;
|
|
33284
33485
|
let entries = [];
|
|
33285
33486
|
try {
|
|
33286
|
-
const dirents = await
|
|
33487
|
+
const dirents = await fs72.readdir(dir, { withFileTypes: true });
|
|
33287
33488
|
entries = dirents.filter((d3) => !d3.name.startsWith(".") || d3.name === ".git").map((d3) => ({ name: d3.name, isDirectory: d3.isDirectory() }));
|
|
33288
33489
|
} catch {
|
|
33289
33490
|
return;
|
|
@@ -33926,6 +34127,146 @@ async function postBudgetReached(opts, fetchImpl = fetch) {
|
|
|
33926
34127
|
}
|
|
33927
34128
|
}
|
|
33928
34129
|
|
|
34130
|
+
// src/integrations/provision.ts
|
|
34131
|
+
function buildMcpServersForStart(ctx) {
|
|
34132
|
+
const manifest = readIntegrationsManifest();
|
|
34133
|
+
if (!manifest || manifest.integrations.length === 0) return [];
|
|
34134
|
+
if (!ctx.pluginAuthToken) {
|
|
34135
|
+
log.warn("integrations", "manifest present but no plugin auth token \u2014 skipping MCP injection");
|
|
34136
|
+
return [];
|
|
34137
|
+
}
|
|
34138
|
+
const servers = [];
|
|
34139
|
+
for (const entry of manifest.integrations) {
|
|
34140
|
+
if (!entry.delivery.mcp) continue;
|
|
34141
|
+
const env = [
|
|
34142
|
+
{ name: "CODEAM_MCP_INTEGRATION_ID", value: entry.id },
|
|
34143
|
+
{ name: "CODEAM_MCP_SESSION_ID", value: ctx.sessionId },
|
|
34144
|
+
{ name: "CODEAM_MCP_PLUGIN_ID", value: ctx.pluginId },
|
|
34145
|
+
// Plugin token in ENV, never argv — argv is visible via `ps`.
|
|
34146
|
+
{ name: "CODEAM_MCP_PLUGIN_TOKEN", value: ctx.pluginAuthToken },
|
|
34147
|
+
...ctx.pollSecret ? [{ name: "CODEAM_MCP_POLL_SECRET", value: ctx.pollSecret }] : []
|
|
34148
|
+
];
|
|
34149
|
+
servers.push({
|
|
34150
|
+
name: entry.id,
|
|
34151
|
+
// Never trust the agent's PATH for the shim binary (beads v2.39.5
|
|
34152
|
+
// lesson) — re-invoke this same Node runtime + CLI entrypoint.
|
|
34153
|
+
command: process.execPath,
|
|
34154
|
+
args: [process.argv[1], "mcp-run", entry.id],
|
|
34155
|
+
env
|
|
34156
|
+
});
|
|
34157
|
+
}
|
|
34158
|
+
if (servers.length) {
|
|
34159
|
+
log.info(
|
|
34160
|
+
"integrations",
|
|
34161
|
+
`injecting ${servers.length} MCP server(s): ${servers.map((s) => s.name).join(", ")}`
|
|
34162
|
+
);
|
|
34163
|
+
}
|
|
34164
|
+
return servers;
|
|
34165
|
+
}
|
|
34166
|
+
|
|
34167
|
+
// src/integrations/detect-stack.ts
|
|
34168
|
+
var import_node_fs11 = __toESM(require("fs"));
|
|
34169
|
+
var import_node_path11 = __toESM(require("path"));
|
|
34170
|
+
function readSafe(cwd, rel) {
|
|
34171
|
+
try {
|
|
34172
|
+
return import_node_fs11.default.readFileSync(import_node_path11.default.join(cwd, rel), "utf8");
|
|
34173
|
+
} catch {
|
|
34174
|
+
return "";
|
|
34175
|
+
}
|
|
34176
|
+
}
|
|
34177
|
+
function collectRepoDeps(cwd) {
|
|
34178
|
+
const names = /* @__PURE__ */ new Set();
|
|
34179
|
+
const pkgRaw = readSafe(cwd, "package.json");
|
|
34180
|
+
if (pkgRaw) {
|
|
34181
|
+
try {
|
|
34182
|
+
const pkg = JSON.parse(pkgRaw);
|
|
34183
|
+
for (const k2 of Object.keys(pkg.dependencies ?? {})) names.add(k2);
|
|
34184
|
+
for (const k2 of Object.keys(pkg.devDependencies ?? {})) names.add(k2);
|
|
34185
|
+
} catch {
|
|
34186
|
+
}
|
|
34187
|
+
}
|
|
34188
|
+
const req = readSafe(cwd, "requirements.txt");
|
|
34189
|
+
for (const line of req.split("\n")) {
|
|
34190
|
+
const name = line.trim().split(/[=<>!~;[\s]/)[0];
|
|
34191
|
+
if (name && !name.startsWith("#") && !name.startsWith("-")) names.add(name.toLowerCase());
|
|
34192
|
+
}
|
|
34193
|
+
const pyproject = readSafe(cwd, "pyproject.toml");
|
|
34194
|
+
for (const m of pyproject.matchAll(/^\s*["']?([A-Za-z0-9._-]+)["']?\s*[=~<>]/gm)) {
|
|
34195
|
+
if (m[1]) names.add(m[1].toLowerCase());
|
|
34196
|
+
}
|
|
34197
|
+
const goMod = readSafe(cwd, "go.mod");
|
|
34198
|
+
for (const m of goMod.matchAll(/^\s*([\w./-]+)\s+v\d/gm)) {
|
|
34199
|
+
if (m[1]) names.add(m[1]);
|
|
34200
|
+
}
|
|
34201
|
+
const gemfile = readSafe(cwd, "Gemfile");
|
|
34202
|
+
for (const m of gemfile.matchAll(/^\s*gem\s+["']([A-Za-z0-9._-]+)["']/gm)) {
|
|
34203
|
+
if (m[1]) names.add(m[1]);
|
|
34204
|
+
}
|
|
34205
|
+
const composerRaw = readSafe(cwd, "composer.json");
|
|
34206
|
+
if (composerRaw) {
|
|
34207
|
+
try {
|
|
34208
|
+
const composer = JSON.parse(composerRaw);
|
|
34209
|
+
for (const k2 of Object.keys(composer.require ?? {})) names.add(k2);
|
|
34210
|
+
for (const k2 of Object.keys(composer["require-dev"] ?? {})) names.add(k2);
|
|
34211
|
+
} catch {
|
|
34212
|
+
}
|
|
34213
|
+
}
|
|
34214
|
+
const cargo = readSafe(cwd, "Cargo.toml");
|
|
34215
|
+
const cargoDepsBlock = cargo.match(/\[(?:dev-)?dependencies\]([\s\S]*?)(?:\n\[|$)/g);
|
|
34216
|
+
if (cargoDepsBlock) {
|
|
34217
|
+
for (const block of cargoDepsBlock) {
|
|
34218
|
+
for (const m of block.matchAll(/^\s*([A-Za-z0-9._-]+)\s*=/gm)) {
|
|
34219
|
+
if (m[1] && m[1] !== "dependencies" && m[1] !== "dev-dependencies") names.add(m[1]);
|
|
34220
|
+
}
|
|
34221
|
+
}
|
|
34222
|
+
}
|
|
34223
|
+
return [...names];
|
|
34224
|
+
}
|
|
34225
|
+
function enabledCatalogIds() {
|
|
34226
|
+
return getEnabledIntegrations().map((m) => m.id);
|
|
34227
|
+
}
|
|
34228
|
+
function parseAgentSuggestions(raw) {
|
|
34229
|
+
const match = raw.match(/\[[\s\S]*?\]/);
|
|
34230
|
+
if (!match) return [];
|
|
34231
|
+
let arr;
|
|
34232
|
+
try {
|
|
34233
|
+
arr = JSON.parse(match[0]);
|
|
34234
|
+
} catch {
|
|
34235
|
+
return [];
|
|
34236
|
+
}
|
|
34237
|
+
if (!Array.isArray(arr)) return [];
|
|
34238
|
+
const enabled = new Set(enabledCatalogIds());
|
|
34239
|
+
const out2 = [];
|
|
34240
|
+
const seen = /* @__PURE__ */ new Set();
|
|
34241
|
+
for (const v of arr) {
|
|
34242
|
+
if (typeof v === "string" && isKnownIntegrationId(v) && enabled.has(v) && !seen.has(v)) {
|
|
34243
|
+
seen.add(v);
|
|
34244
|
+
out2.push(v);
|
|
34245
|
+
}
|
|
34246
|
+
}
|
|
34247
|
+
return out2;
|
|
34248
|
+
}
|
|
34249
|
+
async function detectRepoStack(cwd, runtime) {
|
|
34250
|
+
const deps = collectRepoDeps(cwd);
|
|
34251
|
+
const scan = recommendForDeps(deps);
|
|
34252
|
+
if (scan.detected.length > 0 || scan.recommended.length > 0) return scan;
|
|
34253
|
+
if (!runtime?.generateOneShot) return scan;
|
|
34254
|
+
try {
|
|
34255
|
+
const catalog = enabledCatalogIds().join(", ");
|
|
34256
|
+
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"].`;
|
|
34257
|
+
const reply = await runtime.generateOneShot(prompt, { cwd, timeoutMs: 45e3 });
|
|
34258
|
+
if (!reply) return scan;
|
|
34259
|
+
const recommended = parseAgentSuggestions(reply);
|
|
34260
|
+
return { stack: scan.stack, detected: [], recommended, source: "agent" };
|
|
34261
|
+
} catch (err) {
|
|
34262
|
+
log.warn("integrations", `stack detect agent fallback failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
34263
|
+
return scan;
|
|
34264
|
+
}
|
|
34265
|
+
}
|
|
34266
|
+
|
|
34267
|
+
// src/agents/acp/command-handlers.ts
|
|
34268
|
+
var import_node_child_process30 = require("child_process");
|
|
34269
|
+
|
|
33929
34270
|
// src/agents/acp/buildAcpPromptBlocks.ts
|
|
33930
34271
|
var MIME_FROM_EXT = {
|
|
33931
34272
|
png: "image/png",
|
|
@@ -34537,7 +34878,74 @@ async function legacyOrUnsupportedH(ctx) {
|
|
|
34537
34878
|
});
|
|
34538
34879
|
return;
|
|
34539
34880
|
}
|
|
34881
|
+
async function prewarmNewMcpEntries(manifest, previousIds) {
|
|
34882
|
+
const PREWARMABLE = /* @__PURE__ */ new Set(["npx", "uvx"]);
|
|
34883
|
+
const fresh = manifest.integrations.filter(
|
|
34884
|
+
(e) => !previousIds.has(e.id) && e.delivery.mcp && PREWARMABLE.has(e.delivery.mcp.command)
|
|
34885
|
+
);
|
|
34886
|
+
await Promise.all(
|
|
34887
|
+
fresh.map(
|
|
34888
|
+
(e) => new Promise((resolve9) => {
|
|
34889
|
+
const mcp = e.delivery.mcp;
|
|
34890
|
+
const child = (0, import_node_child_process30.execFile)(
|
|
34891
|
+
mcp.command,
|
|
34892
|
+
[...mcp.args, "--help"],
|
|
34893
|
+
{ timeout: 9e4 },
|
|
34894
|
+
() => resolve9()
|
|
34895
|
+
);
|
|
34896
|
+
child.on("error", () => resolve9());
|
|
34897
|
+
})
|
|
34898
|
+
)
|
|
34899
|
+
);
|
|
34900
|
+
}
|
|
34901
|
+
async function integrationsSyncH(ctx) {
|
|
34902
|
+
const { cmd, relay, opts, client: client3 } = ctx;
|
|
34903
|
+
const manifest = cmd.payload.manifest;
|
|
34904
|
+
if (!manifest || !Array.isArray(manifest.integrations)) {
|
|
34905
|
+
await relay.sendResult(cmd.id, "failed", { error: "integrations_sync: missing manifest" });
|
|
34906
|
+
return;
|
|
34907
|
+
}
|
|
34908
|
+
try {
|
|
34909
|
+
const previousIds = new Set((readIntegrationsManifest()?.integrations ?? []).map((e) => e.id));
|
|
34910
|
+
persistIntegrationsManifest(manifest);
|
|
34911
|
+
await prewarmNewMcpEntries(manifest, previousIds);
|
|
34912
|
+
const servers = buildMcpServersForStart({
|
|
34913
|
+
sessionId: opts.sessionId,
|
|
34914
|
+
pluginId: opts.pluginId,
|
|
34915
|
+
pluginAuthToken: opts.pluginAuthToken,
|
|
34916
|
+
pollSecret: opts.pollSecret
|
|
34917
|
+
});
|
|
34918
|
+
const applied = await client3.reprovisionMcp(servers);
|
|
34919
|
+
await relay.sendResult(cmd.id, "completed", {
|
|
34920
|
+
synced: true,
|
|
34921
|
+
applied,
|
|
34922
|
+
// 'reloaded' (live now) | 'deferred' (next restart)
|
|
34923
|
+
attached: manifest.integrations.map((e) => e.id)
|
|
34924
|
+
});
|
|
34925
|
+
} catch (err) {
|
|
34926
|
+
log.warn("acpRunner", `integrations_sync failed (tools apply next restart): ${describeError(err)}`);
|
|
34927
|
+
await relay.sendResult(cmd.id, "completed", { synced: false, error: describeError(err) });
|
|
34928
|
+
}
|
|
34929
|
+
}
|
|
34930
|
+
async function integrationsDetectH(ctx) {
|
|
34931
|
+
const { cmd, relay, opts } = ctx;
|
|
34932
|
+
try {
|
|
34933
|
+
const runtime = createInteractiveAgentStrategy(opts.agent, createOsStrategy());
|
|
34934
|
+
const detection = await detectRepoStack(opts.cwd, runtime);
|
|
34935
|
+
await relay.sendResult(cmd.id, "completed", detection);
|
|
34936
|
+
} catch (err) {
|
|
34937
|
+
log.warn("acpRunner", `integrations_detect failed: ${describeError(err)}`);
|
|
34938
|
+
await relay.sendResult(cmd.id, "completed", {
|
|
34939
|
+
stack: "unknown",
|
|
34940
|
+
detected: [],
|
|
34941
|
+
recommended: [],
|
|
34942
|
+
source: "scan"
|
|
34943
|
+
});
|
|
34944
|
+
}
|
|
34945
|
+
}
|
|
34540
34946
|
var ACP_COMMAND_HANDLERS = {
|
|
34947
|
+
integrations_sync: integrationsSyncH,
|
|
34948
|
+
integrations_detect: integrationsDetectH,
|
|
34541
34949
|
beads_action: beadsActionH,
|
|
34542
34950
|
start_task: startTaskH,
|
|
34543
34951
|
group_mention_task: groupMentionTaskH,
|
|
@@ -36510,8 +36918,8 @@ function startClaudeCredentialSync(opts) {
|
|
|
36510
36918
|
}
|
|
36511
36919
|
|
|
36512
36920
|
// src/beads/workflow-hint.ts
|
|
36513
|
-
var
|
|
36514
|
-
var
|
|
36921
|
+
var fs68 = __toESM(require("fs"));
|
|
36922
|
+
var path74 = __toESM(require("path"));
|
|
36515
36923
|
var os55 = __toESM(require("os"));
|
|
36516
36924
|
var BEADS_HINT_MARKER = "<!-- codeam:beads-workflow -->";
|
|
36517
36925
|
var BEADS_HINT = `${BEADS_HINT_MARKER}
|
|
@@ -36528,61 +36936,24 @@ This environment uses **bd (beads)** for issue/task tracking and persistent memo
|
|
|
36528
36936
|
${BEADS_HINT_MARKER}`;
|
|
36529
36937
|
function ensureBeadsWorkflowHint(homeDir2 = os55.homedir()) {
|
|
36530
36938
|
try {
|
|
36531
|
-
const file =
|
|
36939
|
+
const file = path74.join(homeDir2, ".claude", "CLAUDE.md");
|
|
36532
36940
|
let existing = "";
|
|
36533
36941
|
try {
|
|
36534
|
-
existing =
|
|
36942
|
+
existing = fs68.readFileSync(file, "utf8");
|
|
36535
36943
|
} catch {
|
|
36536
36944
|
}
|
|
36537
36945
|
if (existing.includes(BEADS_HINT_MARKER)) return;
|
|
36538
|
-
|
|
36946
|
+
fs68.mkdirSync(path74.dirname(file), { recursive: true });
|
|
36539
36947
|
const next = existing.trim() ? `${existing.trimEnd()}
|
|
36540
36948
|
|
|
36541
36949
|
${BEADS_HINT}
|
|
36542
36950
|
` : `${BEADS_HINT}
|
|
36543
36951
|
`;
|
|
36544
|
-
|
|
36952
|
+
fs68.writeFileSync(file, next);
|
|
36545
36953
|
} catch {
|
|
36546
36954
|
}
|
|
36547
36955
|
}
|
|
36548
36956
|
|
|
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
36957
|
// src/skills/provision.ts
|
|
36587
36958
|
var import_node_os13 = __toESM(require("os"));
|
|
36588
36959
|
function provisionSkillsForStart(home = import_node_os13.default.homedir()) {
|
|
@@ -36950,7 +37321,7 @@ var AcpDriver = class {
|
|
|
36950
37321
|
};
|
|
36951
37322
|
|
|
36952
37323
|
// src/baton/transcript-mirror.ts
|
|
36953
|
-
var
|
|
37324
|
+
var fs69 = __toESM(require("fs"));
|
|
36954
37325
|
var TranscriptMirror = class {
|
|
36955
37326
|
constructor(deps) {
|
|
36956
37327
|
this.deps = deps;
|
|
@@ -37017,7 +37388,7 @@ var TranscriptMirror = class {
|
|
|
37017
37388
|
}
|
|
37018
37389
|
};
|
|
37019
37390
|
function defaultWatch(file, onChange) {
|
|
37020
|
-
const w3 =
|
|
37391
|
+
const w3 = fs69.watch(file, { persistent: false }, () => onChange());
|
|
37021
37392
|
return () => w3.close();
|
|
37022
37393
|
}
|
|
37023
37394
|
|
|
@@ -37279,16 +37650,16 @@ function toEpochMs(ts) {
|
|
|
37279
37650
|
}
|
|
37280
37651
|
|
|
37281
37652
|
// src/agents/claude/onboarding.ts
|
|
37282
|
-
var
|
|
37653
|
+
var fs70 = __toESM(require("fs"));
|
|
37283
37654
|
var os57 = __toESM(require("os"));
|
|
37284
|
-
var
|
|
37655
|
+
var path75 = __toESM(require("path"));
|
|
37285
37656
|
var ONBOARDING_VERSION_SENTINEL = "9999.0.0";
|
|
37286
37657
|
function ensureClaudeOnboarded(cwd) {
|
|
37287
37658
|
try {
|
|
37288
|
-
const file =
|
|
37659
|
+
const file = path75.join(os57.homedir(), ".claude.json");
|
|
37289
37660
|
let config = {};
|
|
37290
37661
|
try {
|
|
37291
|
-
config = JSON.parse(
|
|
37662
|
+
config = JSON.parse(fs70.readFileSync(file, "utf8"));
|
|
37292
37663
|
} catch {
|
|
37293
37664
|
}
|
|
37294
37665
|
let changed = false;
|
|
@@ -37313,8 +37684,8 @@ function ensureClaudeOnboarded(cwd) {
|
|
|
37313
37684
|
}
|
|
37314
37685
|
}
|
|
37315
37686
|
if (!changed) return;
|
|
37316
|
-
|
|
37317
|
-
|
|
37687
|
+
fs70.mkdirSync(path75.dirname(file), { recursive: true });
|
|
37688
|
+
fs70.writeFileSync(file, JSON.stringify(config, null, 2));
|
|
37318
37689
|
log.info(
|
|
37319
37690
|
"claude",
|
|
37320
37691
|
`pre-completed Claude onboarding${cwd ? ` + trusted workspace ${cwd}` : ""}`
|
|
@@ -38041,7 +38412,7 @@ var import_picocolors11 = __toESM(require("picocolors"));
|
|
|
38041
38412
|
var import_child_process29 = require("child_process");
|
|
38042
38413
|
var import_util4 = require("util");
|
|
38043
38414
|
var import_picocolors9 = __toESM(require("picocolors"));
|
|
38044
|
-
var
|
|
38415
|
+
var path76 = __toESM(require("path"));
|
|
38045
38416
|
var execFileP6 = (0, import_util4.promisify)(import_child_process29.execFile);
|
|
38046
38417
|
var MAX_BUFFER = 8 * 1024 * 1024;
|
|
38047
38418
|
function resetStdinForChild() {
|
|
@@ -38530,7 +38901,7 @@ var GitHubCodespacesProvider = class {
|
|
|
38530
38901
|
});
|
|
38531
38902
|
}
|
|
38532
38903
|
async uploadFile(workspaceId, remotePath, contents, options = {}) {
|
|
38533
|
-
const remoteDir =
|
|
38904
|
+
const remoteDir = path76.posix.dirname(remotePath);
|
|
38534
38905
|
const parts = [
|
|
38535
38906
|
`mkdir -p ${shellQuote(remoteDir)}`,
|
|
38536
38907
|
`cat > ${shellQuote(remotePath)}`
|
|
@@ -38600,7 +38971,7 @@ function shellQuote(s) {
|
|
|
38600
38971
|
// src/services/providers/gitpod.ts
|
|
38601
38972
|
var import_child_process30 = require("child_process");
|
|
38602
38973
|
var import_util5 = require("util");
|
|
38603
|
-
var
|
|
38974
|
+
var path77 = __toESM(require("path"));
|
|
38604
38975
|
var import_picocolors10 = __toESM(require("picocolors"));
|
|
38605
38976
|
var execFileP7 = (0, import_util5.promisify)(import_child_process30.execFile);
|
|
38606
38977
|
var MAX_BUFFER2 = 8 * 1024 * 1024;
|
|
@@ -38840,7 +39211,7 @@ var GitpodProvider = class {
|
|
|
38840
39211
|
});
|
|
38841
39212
|
}
|
|
38842
39213
|
async uploadFile(workspaceId, remotePath, contents, options = {}) {
|
|
38843
|
-
const remoteDir =
|
|
39214
|
+
const remoteDir = path77.posix.dirname(remotePath);
|
|
38844
39215
|
const parts = [
|
|
38845
39216
|
`mkdir -p ${shellQuote2(remoteDir)}`,
|
|
38846
39217
|
`cat > ${shellQuote2(remotePath)}`
|
|
@@ -38876,7 +39247,7 @@ function shellQuote2(s) {
|
|
|
38876
39247
|
// src/services/providers/gitlab-workspaces.ts
|
|
38877
39248
|
var import_child_process31 = require("child_process");
|
|
38878
39249
|
var import_util6 = require("util");
|
|
38879
|
-
var
|
|
39250
|
+
var path78 = __toESM(require("path"));
|
|
38880
39251
|
var execFileP8 = (0, import_util6.promisify)(import_child_process31.execFile);
|
|
38881
39252
|
var MAX_BUFFER3 = 8 * 1024 * 1024;
|
|
38882
39253
|
var GITLAB_API_BASE = process.env.CODEAM_GITLAB_API_URL ?? "https://gitlab.com/api/v4";
|
|
@@ -39136,7 +39507,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
|
|
|
39136
39507
|
}
|
|
39137
39508
|
async uploadFile(workspaceId, remotePath, contents, options = {}) {
|
|
39138
39509
|
const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
|
|
39139
|
-
const remoteDir =
|
|
39510
|
+
const remoteDir = path78.posix.dirname(remotePath);
|
|
39140
39511
|
const parts = [`mkdir -p ${shellQuote3(remoteDir)}`, `cat > ${shellQuote3(remotePath)}`];
|
|
39141
39512
|
if (options.mode != null) {
|
|
39142
39513
|
parts.push(`chmod ${options.mode.toString(8)} ${shellQuote3(remotePath)}`);
|
|
@@ -39204,7 +39575,7 @@ function shellQuote3(s) {
|
|
|
39204
39575
|
// src/services/providers/railway.ts
|
|
39205
39576
|
var import_child_process32 = require("child_process");
|
|
39206
39577
|
var import_util7 = require("util");
|
|
39207
|
-
var
|
|
39578
|
+
var path79 = __toESM(require("path"));
|
|
39208
39579
|
var execFileP9 = (0, import_util7.promisify)(import_child_process32.execFile);
|
|
39209
39580
|
var MAX_BUFFER4 = 8 * 1024 * 1024;
|
|
39210
39581
|
function resetStdinForChild4() {
|
|
@@ -39440,7 +39811,7 @@ var RailwayProvider = class {
|
|
|
39440
39811
|
if (!projectId || !serviceId) {
|
|
39441
39812
|
throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
|
|
39442
39813
|
}
|
|
39443
|
-
const remoteDir =
|
|
39814
|
+
const remoteDir = path79.posix.dirname(remotePath);
|
|
39444
39815
|
const parts = [`mkdir -p ${shellQuote4(remoteDir)}`, `cat > ${shellQuote4(remotePath)}`];
|
|
39445
39816
|
if (options.mode != null) {
|
|
39446
39817
|
parts.push(`chmod ${options.mode.toString(8)} ${shellQuote4(remotePath)}`);
|
|
@@ -39971,9 +40342,9 @@ async function probeCodeamPair(provider, workspace) {
|
|
|
39971
40342
|
}
|
|
39972
40343
|
async function stopWorkspaceFromLocal(target) {
|
|
39973
40344
|
if (target.provider.id === "github-codespaces") {
|
|
39974
|
-
const { execFile:
|
|
40345
|
+
const { execFile: execFile15 } = await import("child_process");
|
|
39975
40346
|
const { promisify: promisify11 } = await import("util");
|
|
39976
|
-
const execFileP10 = promisify11(
|
|
40347
|
+
const execFileP10 = promisify11(execFile15);
|
|
39977
40348
|
await execFileP10("gh", ["codespace", "stop", "-c", target.id], { maxBuffer: 8 * 1024 * 1024 });
|
|
39978
40349
|
return;
|
|
39979
40350
|
}
|
|
@@ -40086,8 +40457,8 @@ async function invite() {
|
|
|
40086
40457
|
var import_node_dns = require("dns");
|
|
40087
40458
|
var import_node_util5 = require("util");
|
|
40088
40459
|
var import_node_crypto13 = require("crypto");
|
|
40089
|
-
var
|
|
40090
|
-
var
|
|
40460
|
+
var fs71 = __toESM(require("fs"));
|
|
40461
|
+
var path80 = __toESM(require("path"));
|
|
40091
40462
|
var import_picocolors14 = __toESM(require("picocolors"));
|
|
40092
40463
|
var dnsResolveP = (0, import_node_util5.promisify)(import_node_dns.resolve);
|
|
40093
40464
|
async function checkDns(apiBase2) {
|
|
@@ -40143,13 +40514,13 @@ async function checkHealth(apiBase2) {
|
|
|
40143
40514
|
}
|
|
40144
40515
|
}
|
|
40145
40516
|
function checkConfigDir() {
|
|
40146
|
-
const dir =
|
|
40517
|
+
const dir = path80.join(require("os").homedir(), ".codeam");
|
|
40147
40518
|
try {
|
|
40148
|
-
|
|
40149
|
-
const probe =
|
|
40150
|
-
|
|
40151
|
-
const read2 =
|
|
40152
|
-
|
|
40519
|
+
fs71.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
40520
|
+
const probe = path80.join(dir, ".doctor-probe");
|
|
40521
|
+
fs71.writeFileSync(probe, "ok", { mode: 384 });
|
|
40522
|
+
const read2 = fs71.readFileSync(probe, "utf8");
|
|
40523
|
+
fs71.unlinkSync(probe);
|
|
40153
40524
|
if (read2 !== "ok") throw new Error("write/read round-trip mismatch");
|
|
40154
40525
|
return {
|
|
40155
40526
|
id: "config-dir",
|
|
@@ -40213,7 +40584,7 @@ function checkNodePty() {
|
|
|
40213
40584
|
detail: "not required on this platform"
|
|
40214
40585
|
};
|
|
40215
40586
|
}
|
|
40216
|
-
const vendoredPath =
|
|
40587
|
+
const vendoredPath = path80.join(__dirname, "vendor", "node-pty");
|
|
40217
40588
|
for (const target of [vendoredPath, "node-pty"]) {
|
|
40218
40589
|
try {
|
|
40219
40590
|
require(target);
|
|
@@ -40255,7 +40626,7 @@ function checkChokidar() {
|
|
|
40255
40626
|
}
|
|
40256
40627
|
async function doctor(args2 = []) {
|
|
40257
40628
|
const json = args2.includes("--json");
|
|
40258
|
-
const cliVersion = true ? "2.61.
|
|
40629
|
+
const cliVersion = true ? "2.61.79" : "0.0.0-dev";
|
|
40259
40630
|
const apiBase2 = resolveApiBaseUrl();
|
|
40260
40631
|
const diagnosticId = (0, import_node_crypto13.randomUUID)();
|
|
40261
40632
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -40452,10 +40823,10 @@ async function completion(args2) {
|
|
|
40452
40823
|
}
|
|
40453
40824
|
|
|
40454
40825
|
// src/integrations/mcp-run.ts
|
|
40455
|
-
var
|
|
40456
|
-
var
|
|
40826
|
+
var import_node_child_process32 = require("child_process");
|
|
40827
|
+
var import_node_fs12 = require("fs");
|
|
40457
40828
|
var import_node_os14 = __toESM(require("os"));
|
|
40458
|
-
var
|
|
40829
|
+
var import_node_path12 = __toESM(require("path"));
|
|
40459
40830
|
|
|
40460
40831
|
// src/integrations/token-client.ts
|
|
40461
40832
|
var REFRESH_AHEAD_MS = 5 * 60 * 1e3;
|
|
@@ -40508,7 +40879,7 @@ var IntegrationTokenClient = class {
|
|
|
40508
40879
|
};
|
|
40509
40880
|
|
|
40510
40881
|
// src/integrations/stdio-proxy.ts
|
|
40511
|
-
var
|
|
40882
|
+
var import_node_child_process31 = require("child_process");
|
|
40512
40883
|
var import_node_readline3 = __toESM(require("readline"));
|
|
40513
40884
|
var RESTART_CHECK_INTERVAL_MS = 3e4;
|
|
40514
40885
|
var SIGKILL_ESCALATION_MS = 2e3;
|
|
@@ -40629,7 +41000,7 @@ var RestartableStdioProxy = class {
|
|
|
40629
41000
|
}
|
|
40630
41001
|
async spawnChild(stdout, preResolved) {
|
|
40631
41002
|
const spec = preResolved ?? await this.opts.spawnSpec();
|
|
40632
|
-
const spawn44 = this.opts.spawnImpl ??
|
|
41003
|
+
const spawn44 = this.opts.spawnImpl ?? import_node_child_process31.spawn;
|
|
40633
41004
|
const child = spawn44(spec.command, spec.args, {
|
|
40634
41005
|
env: { ...process.env, ...spec.env },
|
|
40635
41006
|
// env only — never argv
|
|
@@ -40669,7 +41040,7 @@ function resolveDelivery(id) {
|
|
|
40669
41040
|
function commandExists(command2) {
|
|
40670
41041
|
try {
|
|
40671
41042
|
const probe = process.platform === "win32" ? "where" : "which";
|
|
40672
|
-
(0,
|
|
41043
|
+
(0, import_node_child_process32.execFileSync)(probe, [command2], { stdio: "ignore" });
|
|
40673
41044
|
return true;
|
|
40674
41045
|
} catch {
|
|
40675
41046
|
return false;
|
|
@@ -40677,13 +41048,13 @@ function commandExists(command2) {
|
|
|
40677
41048
|
}
|
|
40678
41049
|
function localBinCandidates(command2) {
|
|
40679
41050
|
return [
|
|
40680
|
-
|
|
40681
|
-
|
|
41051
|
+
import_node_path12.default.join(import_node_os14.default.homedir(), ".local", "bin", command2),
|
|
41052
|
+
import_node_path12.default.join(import_node_os14.default.homedir(), ".cargo", "bin", command2)
|
|
40682
41053
|
];
|
|
40683
41054
|
}
|
|
40684
41055
|
function resolveLauncherPath(command2, deps = {
|
|
40685
41056
|
commandExists,
|
|
40686
|
-
existsSync:
|
|
41057
|
+
existsSync: import_node_fs12.existsSync
|
|
40687
41058
|
}) {
|
|
40688
41059
|
if (deps.commandExists(command2)) return command2;
|
|
40689
41060
|
for (const candidate of localBinCandidates(command2)) {
|
|
@@ -40702,7 +41073,7 @@ function ensureCommand(command2) {
|
|
|
40702
41073
|
}
|
|
40703
41074
|
if (command2 === "uvx") {
|
|
40704
41075
|
try {
|
|
40705
|
-
(0,
|
|
41076
|
+
(0, import_node_child_process32.execSync)("curl -LsSf https://astral.sh/uv/install.sh | sh", {
|
|
40706
41077
|
stdio: ["ignore", process.stderr, process.stderr],
|
|
40707
41078
|
timeout: 18e4,
|
|
40708
41079
|
env: { ...process.env, UV_NO_MODIFY_PATH: "1" }
|
|
@@ -40711,7 +41082,7 @@ function ensureCommand(command2) {
|
|
|
40711
41082
|
}
|
|
40712
41083
|
if (resolveLauncherPath(command2) !== command2) return;
|
|
40713
41084
|
try {
|
|
40714
|
-
(0,
|
|
41085
|
+
(0, import_node_child_process32.execSync)("python3 -m pip install --user --quiet uv", {
|
|
40715
41086
|
stdio: ["ignore", process.stderr, process.stderr],
|
|
40716
41087
|
timeout: 18e4
|
|
40717
41088
|
});
|
|
@@ -40777,7 +41148,7 @@ async function mcpRun(args2) {
|
|
|
40777
41148
|
// src/commands/version.ts
|
|
40778
41149
|
var import_picocolors15 = __toESM(require("picocolors"));
|
|
40779
41150
|
function version2() {
|
|
40780
|
-
const v = true ? "2.61.
|
|
41151
|
+
const v = true ? "2.61.79" : "unknown";
|
|
40781
41152
|
console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
|
|
40782
41153
|
}
|
|
40783
41154
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeam-cli",
|
|
3
|
-
"version": "2.61.
|
|
3
|
+
"version": "2.61.79",
|
|
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",
|