codeam-cli 2.61.76 → 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 +12 -0
- package/dist/index.js +511 -111
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,18 @@ 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
|
+
|
|
13
|
+
## [2.61.76] — 2026-07-30
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- **shared:** Add code-naming Agent Skill (CodeAesthetic naming guidelines) (#572)
|
|
18
|
+
|
|
7
19
|
## [2.61.75] — 2026-07-29
|
|
8
20
|
|
|
9
21
|
### Fixed
|
package/dist/index.js
CHANGED
|
@@ -1516,6 +1516,41 @@ var INTEGRATION_REGISTRY = {
|
|
|
1516
1516
|
}
|
|
1517
1517
|
}
|
|
1518
1518
|
},
|
|
1519
|
+
convex: {
|
|
1520
|
+
id: "convex",
|
|
1521
|
+
name: "Convex",
|
|
1522
|
+
icon: "convex",
|
|
1523
|
+
category: "database",
|
|
1524
|
+
// LIVE — OAuth 2.0 (authorization code, Confidential). authorize
|
|
1525
|
+
// dashboard.convex.dev/oauth/authorize/team (the scope is the URL PATH —
|
|
1526
|
+
// `team` for team-wide access — NOT a query param); token
|
|
1527
|
+
// api.convex.dev/oauth/token (form-urlencoded, client creds in the BODY).
|
|
1528
|
+
// ⚠️ Convex issues NO refresh token and the team-scoped application token
|
|
1529
|
+
// does not expire, so there is nothing to rotate (refresh() is a re-link
|
|
1530
|
+
// surface). The OAuth app (Team Settings → OAuth Applications) is registered
|
|
1531
|
+
// and CONVEX_OAUTH_CLIENT_ID/SECRET/REDIRECT_URI are in Secret Manager
|
|
1532
|
+
// (prod+dev); the config-gated 503 keeps this safe mid-rollout.
|
|
1533
|
+
enabled: true,
|
|
1534
|
+
auth: {
|
|
1535
|
+
kind: "oauth_redirect",
|
|
1536
|
+
// ⚠️ Convex's scope is the authorize URL path (`/team`), NOT sent in the
|
|
1537
|
+
// authorize URL as a query param — this list is informational.
|
|
1538
|
+
scopes: []
|
|
1539
|
+
},
|
|
1540
|
+
delivery: {
|
|
1541
|
+
mcp: {
|
|
1542
|
+
// Convex's OFFICIAL MCP server ships inside the `convex` npm package
|
|
1543
|
+
// (`convex mcp start`). The team-scoped OAuth application token doubles
|
|
1544
|
+
// as the CLI/MCP deploy key → fed via CONVEX_DEPLOY_KEY (env only, never
|
|
1545
|
+
// argv). Version PINNED; bump only after re-verifying headless.
|
|
1546
|
+
command: "npx",
|
|
1547
|
+
args: ["-y", "convex@1.42.3", "mcp", "start"],
|
|
1548
|
+
envMapping: {
|
|
1549
|
+
CONVEX_DEPLOY_KEY: "accessToken"
|
|
1550
|
+
}
|
|
1551
|
+
}
|
|
1552
|
+
}
|
|
1553
|
+
},
|
|
1519
1554
|
confluence: {
|
|
1520
1555
|
id: "confluence",
|
|
1521
1556
|
name: "Confluence",
|
|
@@ -1631,6 +1666,9 @@ var INTEGRATION_REGISTRY = {
|
|
|
1631
1666
|
}
|
|
1632
1667
|
}
|
|
1633
1668
|
};
|
|
1669
|
+
function getEnabledIntegrations() {
|
|
1670
|
+
return Object.values(INTEGRATION_REGISTRY).filter((m) => m.enabled);
|
|
1671
|
+
}
|
|
1634
1672
|
function getIntegration(id) {
|
|
1635
1673
|
const meta = INTEGRATION_REGISTRY[id];
|
|
1636
1674
|
if (!meta) throw new Error(`Unknown integration id: ${id}`);
|
|
@@ -1640,6 +1678,145 @@ function isKnownIntegrationId(id) {
|
|
|
1640
1678
|
return id in INTEGRATION_REGISTRY;
|
|
1641
1679
|
}
|
|
1642
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
|
+
|
|
1643
1820
|
// ../../packages/shared/src/skills/code-review.ts
|
|
1644
1821
|
var CODE_REVIEW_BODY = `Use this skill when reviewing a pull request. It defines what a high-signal
|
|
1645
1822
|
review looks like so your inline comments are worth the author's time.
|
|
@@ -2067,6 +2244,14 @@ var USER_EVENTS = {
|
|
|
2067
2244
|
INTEGRATION_LINKED: "integration_linked",
|
|
2068
2245
|
INTEGRATION_UNLINKED: "integration_unlinked",
|
|
2069
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",
|
|
2070
2255
|
// CodeRabbit reviewer — the CLI posts these to /api/coderabbit/events; the
|
|
2071
2256
|
// backend re-publishes them on the per-user SSE bus (mirrored in repo A).
|
|
2072
2257
|
CODERABBIT_PROGRESS: "coderabbit_progress",
|
|
@@ -2271,11 +2456,11 @@ function quiet(fn) {
|
|
|
2271
2456
|
log.debug(TAG, "ignored sync error", err);
|
|
2272
2457
|
}
|
|
2273
2458
|
}
|
|
2274
|
-
function rmIfExistsQuiet(
|
|
2459
|
+
function rmIfExistsQuiet(path82) {
|
|
2275
2460
|
try {
|
|
2276
|
-
fs2.rmSync(
|
|
2461
|
+
fs2.rmSync(path82, { force: true });
|
|
2277
2462
|
} catch (err) {
|
|
2278
|
-
log.debug(TAG, `rmIfExists failed for ${
|
|
2463
|
+
log.debug(TAG, `rmIfExists failed for ${path82}`, err);
|
|
2279
2464
|
}
|
|
2280
2465
|
}
|
|
2281
2466
|
function killQuiet(target, signal = "SIGTERM") {
|
|
@@ -2459,8 +2644,8 @@ function createGetModuleFromFilename(basePath = process.argv[1] ? (0, import_pat
|
|
|
2459
2644
|
return decodedFile;
|
|
2460
2645
|
};
|
|
2461
2646
|
}
|
|
2462
|
-
function normalizeWindowsPath(
|
|
2463
|
-
return
|
|
2647
|
+
function normalizeWindowsPath(path82) {
|
|
2648
|
+
return path82.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
|
|
2464
2649
|
}
|
|
2465
2650
|
|
|
2466
2651
|
// ../../node_modules/@posthog/core/dist/featureFlagUtils.mjs
|
|
@@ -4940,9 +5125,9 @@ async function addSourceContext(frames) {
|
|
|
4940
5125
|
LRU_FILE_CONTENTS_CACHE.reduce();
|
|
4941
5126
|
return frames;
|
|
4942
5127
|
}
|
|
4943
|
-
function getContextLinesFromFile(
|
|
5128
|
+
function getContextLinesFromFile(path82, ranges, output) {
|
|
4944
5129
|
return new Promise((resolve9) => {
|
|
4945
|
-
const stream = (0, import_node_fs.createReadStream)(
|
|
5130
|
+
const stream = (0, import_node_fs.createReadStream)(path82);
|
|
4946
5131
|
const lineReaded = (0, import_node_readline.createInterface)({
|
|
4947
5132
|
input: stream
|
|
4948
5133
|
});
|
|
@@ -4957,7 +5142,7 @@ function getContextLinesFromFile(path81, ranges, output) {
|
|
|
4957
5142
|
let rangeStart = range[0];
|
|
4958
5143
|
let rangeEnd = range[1];
|
|
4959
5144
|
function onStreamError() {
|
|
4960
|
-
LRU_FILE_CONTENTS_FS_READ_FAILED.set(
|
|
5145
|
+
LRU_FILE_CONTENTS_FS_READ_FAILED.set(path82, 1);
|
|
4961
5146
|
lineReaded.close();
|
|
4962
5147
|
lineReaded.removeAllListeners();
|
|
4963
5148
|
destroyStreamAndResolve();
|
|
@@ -5018,8 +5203,8 @@ function clearLineContext(frame) {
|
|
|
5018
5203
|
delete frame.context_line;
|
|
5019
5204
|
delete frame.post_context;
|
|
5020
5205
|
}
|
|
5021
|
-
function shouldSkipContextLinesForFile(
|
|
5022
|
-
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:");
|
|
5023
5208
|
}
|
|
5024
5209
|
function shouldSkipContextLinesForFrame(frame) {
|
|
5025
5210
|
if (void 0 !== frame.lineno && frame.lineno > MAX_CONTEXTLINES_LINENO) return true;
|
|
@@ -7173,7 +7358,7 @@ function readAnonId() {
|
|
|
7173
7358
|
}
|
|
7174
7359
|
function superProperties() {
|
|
7175
7360
|
return {
|
|
7176
|
-
cliVersion: true ? "2.61.
|
|
7361
|
+
cliVersion: true ? "2.61.78" : "0.0.0-dev",
|
|
7177
7362
|
nodeVersion: process.version,
|
|
7178
7363
|
platform: process.platform,
|
|
7179
7364
|
arch: process.arch,
|
|
@@ -7354,7 +7539,7 @@ var os4 = __toESM(require("os"));
|
|
|
7354
7539
|
// package.json
|
|
7355
7540
|
var package_default = {
|
|
7356
7541
|
name: "codeam-cli",
|
|
7357
|
-
version: "2.61.
|
|
7542
|
+
version: "2.61.78",
|
|
7358
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.",
|
|
7359
7544
|
type: "commonjs",
|
|
7360
7545
|
main: "dist/index.js",
|
|
@@ -8586,7 +8771,7 @@ var CommandRelayService = class _CommandRelayService {
|
|
|
8586
8771
|
// fresh + clear the "CLI update available" banner after a self-update
|
|
8587
8772
|
// (a codespace that reinstalls @latest reconnects via heartbeat, not
|
|
8588
8773
|
// pair/reconnect). Older backends ignore the extra field.
|
|
8589
|
-
..."2.61.
|
|
8774
|
+
..."2.61.78" ? { ideVersion: "2.61.78" } : {}
|
|
8590
8775
|
}).then(() => log.trace("relay", `heartbeat ok online=${online}`)).catch((err) => log.trace("relay", `heartbeat failed online=${online}`, err));
|
|
8591
8776
|
}
|
|
8592
8777
|
/**
|
|
@@ -15195,8 +15380,8 @@ function pickLine(obj) {
|
|
|
15195
15380
|
function toHunk(raw, groupSeverity) {
|
|
15196
15381
|
if (!raw || typeof raw !== "object") return null;
|
|
15197
15382
|
const o = raw;
|
|
15198
|
-
const
|
|
15199
|
-
if (!
|
|
15383
|
+
const path82 = asString(pick(o, ["file_path", "filePath", "file", "path", "filename", "fileName"])) ?? asString(pick(o, ["location"])?.path);
|
|
15384
|
+
if (!path82) return null;
|
|
15200
15385
|
const message = asString(
|
|
15201
15386
|
pick(o, [
|
|
15202
15387
|
"comment",
|
|
@@ -15213,7 +15398,7 @@ function toHunk(raw, groupSeverity) {
|
|
|
15213
15398
|
const severity = normSeverity(pick(o, ["severity", "level", "priority", "impact"])) ?? normSeverity(groupSeverity);
|
|
15214
15399
|
const locObj = pick(o, ["location"]) ?? o;
|
|
15215
15400
|
return {
|
|
15216
|
-
path:
|
|
15401
|
+
path: path82.trim(),
|
|
15217
15402
|
line: pickLine(o) ?? pickLine(locObj),
|
|
15218
15403
|
severity,
|
|
15219
15404
|
message: (title && message ? `${title}: ${message}` : title || message).trim() || "(no message)"
|
|
@@ -15296,10 +15481,10 @@ function parsePlain(stdout) {
|
|
|
15296
15481
|
for (const line of stdout.split(/\r?\n/)) {
|
|
15297
15482
|
const m = line.match(HUNK_LINE_RE);
|
|
15298
15483
|
if (!m) continue;
|
|
15299
|
-
const [,
|
|
15300
|
-
if (!
|
|
15484
|
+
const [, path82, lineNo, sevToken, message] = m;
|
|
15485
|
+
if (!path82 || !lineNo || !message) continue;
|
|
15301
15486
|
hunks.push({
|
|
15302
|
-
path:
|
|
15487
|
+
path: path82.trim(),
|
|
15303
15488
|
line: Number(lineNo),
|
|
15304
15489
|
severity: sevToken ? SEVERITY_MAP[sevToken.toLowerCase()] : void 0,
|
|
15305
15490
|
message: message.trim().replace(/^[*-]\s+/, "")
|
|
@@ -19700,7 +19885,7 @@ async function autoUpgradeBeforeCriticalCommand() {
|
|
|
19700
19885
|
if (process.env.NODE_ENV === "test") return;
|
|
19701
19886
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
19702
19887
|
if (process.env.CI) return;
|
|
19703
|
-
const current = true ? "2.61.
|
|
19888
|
+
const current = true ? "2.61.78" : null;
|
|
19704
19889
|
if (!current) return;
|
|
19705
19890
|
const cache = readCache();
|
|
19706
19891
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -19717,7 +19902,7 @@ function checkForUpdates() {
|
|
|
19717
19902
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
19718
19903
|
if (process.env.CI) return;
|
|
19719
19904
|
if (!process.stdout.isTTY) return;
|
|
19720
|
-
const current = true ? "2.61.
|
|
19905
|
+
const current = true ? "2.61.78" : null;
|
|
19721
19906
|
if (!current) return;
|
|
19722
19907
|
const cache = readCache();
|
|
19723
19908
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -19737,7 +19922,7 @@ var SELF_UPDATE_INTERVAL_MS = 60 * 60 * 1e3;
|
|
|
19737
19922
|
var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
|
|
19738
19923
|
var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
|
|
19739
19924
|
function currentCliVersion() {
|
|
19740
|
-
return true ? "2.61.
|
|
19925
|
+
return true ? "2.61.78" : null;
|
|
19741
19926
|
}
|
|
19742
19927
|
function runCmd(cmd, args2, timeoutMs) {
|
|
19743
19928
|
return new Promise((resolve9) => {
|
|
@@ -25631,11 +25816,11 @@ function resolveTokenValue(args2) {
|
|
|
25631
25816
|
}
|
|
25632
25817
|
const fileFlag = args2.find((a) => a.startsWith("--token-file="));
|
|
25633
25818
|
if (fileFlag) {
|
|
25634
|
-
const
|
|
25819
|
+
const path82 = fileFlag.slice("--token-file=".length);
|
|
25635
25820
|
try {
|
|
25636
|
-
const content = fs59.readFileSync(
|
|
25637
|
-
if (content.length === 0) fail(`--token-file ${
|
|
25638
|
-
rmIfExistsQuiet(
|
|
25821
|
+
const content = fs59.readFileSync(path82, "utf8").trim();
|
|
25822
|
+
if (content.length === 0) fail(`--token-file ${path82} is empty`);
|
|
25823
|
+
rmIfExistsQuiet(path82);
|
|
25639
25824
|
return content;
|
|
25640
25825
|
} catch (err) {
|
|
25641
25826
|
fail(`Could not read --token-file: ${err.message}`);
|
|
@@ -31866,6 +32051,51 @@ var AcpClient = class {
|
|
|
31866
32051
|
if (loaded?.modes !== void 0) this.captureModes(loaded.modes ?? null);
|
|
31867
32052
|
log.info("acpClient", `loadSession \u2190 ok sessionId=${sessionId.slice(0, 8)}`);
|
|
31868
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
|
+
}
|
|
31869
32099
|
/**
|
|
31870
32100
|
* Enumerate the workspace's conversations via the ACP `session/list` RPC.
|
|
31871
32101
|
* Agent-agnostic — works for ANY adapter that advertises
|
|
@@ -33240,7 +33470,7 @@ function defaultRunGit(cwd, args2) {
|
|
|
33240
33470
|
});
|
|
33241
33471
|
}
|
|
33242
33472
|
async function discoverRepos(workingDir, maxDepth = 4) {
|
|
33243
|
-
const
|
|
33473
|
+
const fs72 = await import("fs/promises");
|
|
33244
33474
|
const out2 = [];
|
|
33245
33475
|
await walk(workingDir, 0);
|
|
33246
33476
|
return out2;
|
|
@@ -33248,7 +33478,7 @@ async function discoverRepos(workingDir, maxDepth = 4) {
|
|
|
33248
33478
|
if (depth > maxDepth) return;
|
|
33249
33479
|
let entries = [];
|
|
33250
33480
|
try {
|
|
33251
|
-
const dirents = await
|
|
33481
|
+
const dirents = await fs72.readdir(dir, { withFileTypes: true });
|
|
33252
33482
|
entries = dirents.filter((d3) => !d3.name.startsWith(".") || d3.name === ".git").map((d3) => ({ name: d3.name, isDirectory: d3.isDirectory() }));
|
|
33253
33483
|
} catch {
|
|
33254
33484
|
return;
|
|
@@ -33891,6 +34121,146 @@ async function postBudgetReached(opts, fetchImpl = fetch) {
|
|
|
33891
34121
|
}
|
|
33892
34122
|
}
|
|
33893
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
|
+
|
|
33894
34264
|
// src/agents/acp/buildAcpPromptBlocks.ts
|
|
33895
34265
|
var MIME_FROM_EXT = {
|
|
33896
34266
|
png: "image/png",
|
|
@@ -34502,7 +34872,74 @@ async function legacyOrUnsupportedH(ctx) {
|
|
|
34502
34872
|
});
|
|
34503
34873
|
return;
|
|
34504
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
|
+
}
|
|
34505
34940
|
var ACP_COMMAND_HANDLERS = {
|
|
34941
|
+
integrations_sync: integrationsSyncH,
|
|
34942
|
+
integrations_detect: integrationsDetectH,
|
|
34506
34943
|
beads_action: beadsActionH,
|
|
34507
34944
|
start_task: startTaskH,
|
|
34508
34945
|
group_mention_task: groupMentionTaskH,
|
|
@@ -36475,8 +36912,8 @@ function startClaudeCredentialSync(opts) {
|
|
|
36475
36912
|
}
|
|
36476
36913
|
|
|
36477
36914
|
// src/beads/workflow-hint.ts
|
|
36478
|
-
var
|
|
36479
|
-
var
|
|
36915
|
+
var fs68 = __toESM(require("fs"));
|
|
36916
|
+
var path74 = __toESM(require("path"));
|
|
36480
36917
|
var os55 = __toESM(require("os"));
|
|
36481
36918
|
var BEADS_HINT_MARKER = "<!-- codeam:beads-workflow -->";
|
|
36482
36919
|
var BEADS_HINT = `${BEADS_HINT_MARKER}
|
|
@@ -36493,61 +36930,24 @@ This environment uses **bd (beads)** for issue/task tracking and persistent memo
|
|
|
36493
36930
|
${BEADS_HINT_MARKER}`;
|
|
36494
36931
|
function ensureBeadsWorkflowHint(homeDir2 = os55.homedir()) {
|
|
36495
36932
|
try {
|
|
36496
|
-
const file =
|
|
36933
|
+
const file = path74.join(homeDir2, ".claude", "CLAUDE.md");
|
|
36497
36934
|
let existing = "";
|
|
36498
36935
|
try {
|
|
36499
|
-
existing =
|
|
36936
|
+
existing = fs68.readFileSync(file, "utf8");
|
|
36500
36937
|
} catch {
|
|
36501
36938
|
}
|
|
36502
36939
|
if (existing.includes(BEADS_HINT_MARKER)) return;
|
|
36503
|
-
|
|
36940
|
+
fs68.mkdirSync(path74.dirname(file), { recursive: true });
|
|
36504
36941
|
const next = existing.trim() ? `${existing.trimEnd()}
|
|
36505
36942
|
|
|
36506
36943
|
${BEADS_HINT}
|
|
36507
36944
|
` : `${BEADS_HINT}
|
|
36508
36945
|
`;
|
|
36509
|
-
|
|
36946
|
+
fs68.writeFileSync(file, next);
|
|
36510
36947
|
} catch {
|
|
36511
36948
|
}
|
|
36512
36949
|
}
|
|
36513
36950
|
|
|
36514
|
-
// src/integrations/provision.ts
|
|
36515
|
-
function buildMcpServersForStart(ctx) {
|
|
36516
|
-
const manifest = readIntegrationsManifest();
|
|
36517
|
-
if (!manifest || manifest.integrations.length === 0) return [];
|
|
36518
|
-
if (!ctx.pluginAuthToken) {
|
|
36519
|
-
log.warn("integrations", "manifest present but no plugin auth token \u2014 skipping MCP injection");
|
|
36520
|
-
return [];
|
|
36521
|
-
}
|
|
36522
|
-
const servers = [];
|
|
36523
|
-
for (const entry of manifest.integrations) {
|
|
36524
|
-
if (!entry.delivery.mcp) continue;
|
|
36525
|
-
const env = [
|
|
36526
|
-
{ name: "CODEAM_MCP_INTEGRATION_ID", value: entry.id },
|
|
36527
|
-
{ name: "CODEAM_MCP_SESSION_ID", value: ctx.sessionId },
|
|
36528
|
-
{ name: "CODEAM_MCP_PLUGIN_ID", value: ctx.pluginId },
|
|
36529
|
-
// Plugin token in ENV, never argv — argv is visible via `ps`.
|
|
36530
|
-
{ name: "CODEAM_MCP_PLUGIN_TOKEN", value: ctx.pluginAuthToken },
|
|
36531
|
-
...ctx.pollSecret ? [{ name: "CODEAM_MCP_POLL_SECRET", value: ctx.pollSecret }] : []
|
|
36532
|
-
];
|
|
36533
|
-
servers.push({
|
|
36534
|
-
name: entry.id,
|
|
36535
|
-
// Never trust the agent's PATH for the shim binary (beads v2.39.5
|
|
36536
|
-
// lesson) — re-invoke this same Node runtime + CLI entrypoint.
|
|
36537
|
-
command: process.execPath,
|
|
36538
|
-
args: [process.argv[1], "mcp-run", entry.id],
|
|
36539
|
-
env
|
|
36540
|
-
});
|
|
36541
|
-
}
|
|
36542
|
-
if (servers.length) {
|
|
36543
|
-
log.info(
|
|
36544
|
-
"integrations",
|
|
36545
|
-
`injecting ${servers.length} MCP server(s): ${servers.map((s) => s.name).join(", ")}`
|
|
36546
|
-
);
|
|
36547
|
-
}
|
|
36548
|
-
return servers;
|
|
36549
|
-
}
|
|
36550
|
-
|
|
36551
36951
|
// src/skills/provision.ts
|
|
36552
36952
|
var import_node_os13 = __toESM(require("os"));
|
|
36553
36953
|
function provisionSkillsForStart(home = import_node_os13.default.homedir()) {
|
|
@@ -36915,7 +37315,7 @@ var AcpDriver = class {
|
|
|
36915
37315
|
};
|
|
36916
37316
|
|
|
36917
37317
|
// src/baton/transcript-mirror.ts
|
|
36918
|
-
var
|
|
37318
|
+
var fs69 = __toESM(require("fs"));
|
|
36919
37319
|
var TranscriptMirror = class {
|
|
36920
37320
|
constructor(deps) {
|
|
36921
37321
|
this.deps = deps;
|
|
@@ -36982,7 +37382,7 @@ var TranscriptMirror = class {
|
|
|
36982
37382
|
}
|
|
36983
37383
|
};
|
|
36984
37384
|
function defaultWatch(file, onChange) {
|
|
36985
|
-
const w3 =
|
|
37385
|
+
const w3 = fs69.watch(file, { persistent: false }, () => onChange());
|
|
36986
37386
|
return () => w3.close();
|
|
36987
37387
|
}
|
|
36988
37388
|
|
|
@@ -37244,16 +37644,16 @@ function toEpochMs(ts) {
|
|
|
37244
37644
|
}
|
|
37245
37645
|
|
|
37246
37646
|
// src/agents/claude/onboarding.ts
|
|
37247
|
-
var
|
|
37647
|
+
var fs70 = __toESM(require("fs"));
|
|
37248
37648
|
var os57 = __toESM(require("os"));
|
|
37249
|
-
var
|
|
37649
|
+
var path75 = __toESM(require("path"));
|
|
37250
37650
|
var ONBOARDING_VERSION_SENTINEL = "9999.0.0";
|
|
37251
37651
|
function ensureClaudeOnboarded(cwd) {
|
|
37252
37652
|
try {
|
|
37253
|
-
const file =
|
|
37653
|
+
const file = path75.join(os57.homedir(), ".claude.json");
|
|
37254
37654
|
let config = {};
|
|
37255
37655
|
try {
|
|
37256
|
-
config = JSON.parse(
|
|
37656
|
+
config = JSON.parse(fs70.readFileSync(file, "utf8"));
|
|
37257
37657
|
} catch {
|
|
37258
37658
|
}
|
|
37259
37659
|
let changed = false;
|
|
@@ -37278,8 +37678,8 @@ function ensureClaudeOnboarded(cwd) {
|
|
|
37278
37678
|
}
|
|
37279
37679
|
}
|
|
37280
37680
|
if (!changed) return;
|
|
37281
|
-
|
|
37282
|
-
|
|
37681
|
+
fs70.mkdirSync(path75.dirname(file), { recursive: true });
|
|
37682
|
+
fs70.writeFileSync(file, JSON.stringify(config, null, 2));
|
|
37283
37683
|
log.info(
|
|
37284
37684
|
"claude",
|
|
37285
37685
|
`pre-completed Claude onboarding${cwd ? ` + trusted workspace ${cwd}` : ""}`
|
|
@@ -38006,7 +38406,7 @@ var import_picocolors11 = __toESM(require("picocolors"));
|
|
|
38006
38406
|
var import_child_process29 = require("child_process");
|
|
38007
38407
|
var import_util4 = require("util");
|
|
38008
38408
|
var import_picocolors9 = __toESM(require("picocolors"));
|
|
38009
|
-
var
|
|
38409
|
+
var path76 = __toESM(require("path"));
|
|
38010
38410
|
var execFileP6 = (0, import_util4.promisify)(import_child_process29.execFile);
|
|
38011
38411
|
var MAX_BUFFER = 8 * 1024 * 1024;
|
|
38012
38412
|
function resetStdinForChild() {
|
|
@@ -38495,7 +38895,7 @@ var GitHubCodespacesProvider = class {
|
|
|
38495
38895
|
});
|
|
38496
38896
|
}
|
|
38497
38897
|
async uploadFile(workspaceId, remotePath, contents, options = {}) {
|
|
38498
|
-
const remoteDir =
|
|
38898
|
+
const remoteDir = path76.posix.dirname(remotePath);
|
|
38499
38899
|
const parts = [
|
|
38500
38900
|
`mkdir -p ${shellQuote(remoteDir)}`,
|
|
38501
38901
|
`cat > ${shellQuote(remotePath)}`
|
|
@@ -38565,7 +38965,7 @@ function shellQuote(s) {
|
|
|
38565
38965
|
// src/services/providers/gitpod.ts
|
|
38566
38966
|
var import_child_process30 = require("child_process");
|
|
38567
38967
|
var import_util5 = require("util");
|
|
38568
|
-
var
|
|
38968
|
+
var path77 = __toESM(require("path"));
|
|
38569
38969
|
var import_picocolors10 = __toESM(require("picocolors"));
|
|
38570
38970
|
var execFileP7 = (0, import_util5.promisify)(import_child_process30.execFile);
|
|
38571
38971
|
var MAX_BUFFER2 = 8 * 1024 * 1024;
|
|
@@ -38805,7 +39205,7 @@ var GitpodProvider = class {
|
|
|
38805
39205
|
});
|
|
38806
39206
|
}
|
|
38807
39207
|
async uploadFile(workspaceId, remotePath, contents, options = {}) {
|
|
38808
|
-
const remoteDir =
|
|
39208
|
+
const remoteDir = path77.posix.dirname(remotePath);
|
|
38809
39209
|
const parts = [
|
|
38810
39210
|
`mkdir -p ${shellQuote2(remoteDir)}`,
|
|
38811
39211
|
`cat > ${shellQuote2(remotePath)}`
|
|
@@ -38841,7 +39241,7 @@ function shellQuote2(s) {
|
|
|
38841
39241
|
// src/services/providers/gitlab-workspaces.ts
|
|
38842
39242
|
var import_child_process31 = require("child_process");
|
|
38843
39243
|
var import_util6 = require("util");
|
|
38844
|
-
var
|
|
39244
|
+
var path78 = __toESM(require("path"));
|
|
38845
39245
|
var execFileP8 = (0, import_util6.promisify)(import_child_process31.execFile);
|
|
38846
39246
|
var MAX_BUFFER3 = 8 * 1024 * 1024;
|
|
38847
39247
|
var GITLAB_API_BASE = process.env.CODEAM_GITLAB_API_URL ?? "https://gitlab.com/api/v4";
|
|
@@ -39101,7 +39501,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
|
|
|
39101
39501
|
}
|
|
39102
39502
|
async uploadFile(workspaceId, remotePath, contents, options = {}) {
|
|
39103
39503
|
const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
|
|
39104
|
-
const remoteDir =
|
|
39504
|
+
const remoteDir = path78.posix.dirname(remotePath);
|
|
39105
39505
|
const parts = [`mkdir -p ${shellQuote3(remoteDir)}`, `cat > ${shellQuote3(remotePath)}`];
|
|
39106
39506
|
if (options.mode != null) {
|
|
39107
39507
|
parts.push(`chmod ${options.mode.toString(8)} ${shellQuote3(remotePath)}`);
|
|
@@ -39169,7 +39569,7 @@ function shellQuote3(s) {
|
|
|
39169
39569
|
// src/services/providers/railway.ts
|
|
39170
39570
|
var import_child_process32 = require("child_process");
|
|
39171
39571
|
var import_util7 = require("util");
|
|
39172
|
-
var
|
|
39572
|
+
var path79 = __toESM(require("path"));
|
|
39173
39573
|
var execFileP9 = (0, import_util7.promisify)(import_child_process32.execFile);
|
|
39174
39574
|
var MAX_BUFFER4 = 8 * 1024 * 1024;
|
|
39175
39575
|
function resetStdinForChild4() {
|
|
@@ -39405,7 +39805,7 @@ var RailwayProvider = class {
|
|
|
39405
39805
|
if (!projectId || !serviceId) {
|
|
39406
39806
|
throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
|
|
39407
39807
|
}
|
|
39408
|
-
const remoteDir =
|
|
39808
|
+
const remoteDir = path79.posix.dirname(remotePath);
|
|
39409
39809
|
const parts = [`mkdir -p ${shellQuote4(remoteDir)}`, `cat > ${shellQuote4(remotePath)}`];
|
|
39410
39810
|
if (options.mode != null) {
|
|
39411
39811
|
parts.push(`chmod ${options.mode.toString(8)} ${shellQuote4(remotePath)}`);
|
|
@@ -39936,9 +40336,9 @@ async function probeCodeamPair(provider, workspace) {
|
|
|
39936
40336
|
}
|
|
39937
40337
|
async function stopWorkspaceFromLocal(target) {
|
|
39938
40338
|
if (target.provider.id === "github-codespaces") {
|
|
39939
|
-
const { execFile:
|
|
40339
|
+
const { execFile: execFile15 } = await import("child_process");
|
|
39940
40340
|
const { promisify: promisify11 } = await import("util");
|
|
39941
|
-
const execFileP10 = promisify11(
|
|
40341
|
+
const execFileP10 = promisify11(execFile15);
|
|
39942
40342
|
await execFileP10("gh", ["codespace", "stop", "-c", target.id], { maxBuffer: 8 * 1024 * 1024 });
|
|
39943
40343
|
return;
|
|
39944
40344
|
}
|
|
@@ -40051,8 +40451,8 @@ async function invite() {
|
|
|
40051
40451
|
var import_node_dns = require("dns");
|
|
40052
40452
|
var import_node_util5 = require("util");
|
|
40053
40453
|
var import_node_crypto13 = require("crypto");
|
|
40054
|
-
var
|
|
40055
|
-
var
|
|
40454
|
+
var fs71 = __toESM(require("fs"));
|
|
40455
|
+
var path80 = __toESM(require("path"));
|
|
40056
40456
|
var import_picocolors14 = __toESM(require("picocolors"));
|
|
40057
40457
|
var dnsResolveP = (0, import_node_util5.promisify)(import_node_dns.resolve);
|
|
40058
40458
|
async function checkDns(apiBase2) {
|
|
@@ -40108,13 +40508,13 @@ async function checkHealth(apiBase2) {
|
|
|
40108
40508
|
}
|
|
40109
40509
|
}
|
|
40110
40510
|
function checkConfigDir() {
|
|
40111
|
-
const dir =
|
|
40511
|
+
const dir = path80.join(require("os").homedir(), ".codeam");
|
|
40112
40512
|
try {
|
|
40113
|
-
|
|
40114
|
-
const probe =
|
|
40115
|
-
|
|
40116
|
-
const read2 =
|
|
40117
|
-
|
|
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);
|
|
40118
40518
|
if (read2 !== "ok") throw new Error("write/read round-trip mismatch");
|
|
40119
40519
|
return {
|
|
40120
40520
|
id: "config-dir",
|
|
@@ -40178,7 +40578,7 @@ function checkNodePty() {
|
|
|
40178
40578
|
detail: "not required on this platform"
|
|
40179
40579
|
};
|
|
40180
40580
|
}
|
|
40181
|
-
const vendoredPath =
|
|
40581
|
+
const vendoredPath = path80.join(__dirname, "vendor", "node-pty");
|
|
40182
40582
|
for (const target of [vendoredPath, "node-pty"]) {
|
|
40183
40583
|
try {
|
|
40184
40584
|
require(target);
|
|
@@ -40220,7 +40620,7 @@ function checkChokidar() {
|
|
|
40220
40620
|
}
|
|
40221
40621
|
async function doctor(args2 = []) {
|
|
40222
40622
|
const json = args2.includes("--json");
|
|
40223
|
-
const cliVersion = true ? "2.61.
|
|
40623
|
+
const cliVersion = true ? "2.61.78" : "0.0.0-dev";
|
|
40224
40624
|
const apiBase2 = resolveApiBaseUrl();
|
|
40225
40625
|
const diagnosticId = (0, import_node_crypto13.randomUUID)();
|
|
40226
40626
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -40417,10 +40817,10 @@ async function completion(args2) {
|
|
|
40417
40817
|
}
|
|
40418
40818
|
|
|
40419
40819
|
// src/integrations/mcp-run.ts
|
|
40420
|
-
var
|
|
40421
|
-
var
|
|
40820
|
+
var import_node_child_process32 = require("child_process");
|
|
40821
|
+
var import_node_fs12 = require("fs");
|
|
40422
40822
|
var import_node_os14 = __toESM(require("os"));
|
|
40423
|
-
var
|
|
40823
|
+
var import_node_path12 = __toESM(require("path"));
|
|
40424
40824
|
|
|
40425
40825
|
// src/integrations/token-client.ts
|
|
40426
40826
|
var REFRESH_AHEAD_MS = 5 * 60 * 1e3;
|
|
@@ -40473,7 +40873,7 @@ var IntegrationTokenClient = class {
|
|
|
40473
40873
|
};
|
|
40474
40874
|
|
|
40475
40875
|
// src/integrations/stdio-proxy.ts
|
|
40476
|
-
var
|
|
40876
|
+
var import_node_child_process31 = require("child_process");
|
|
40477
40877
|
var import_node_readline3 = __toESM(require("readline"));
|
|
40478
40878
|
var RESTART_CHECK_INTERVAL_MS = 3e4;
|
|
40479
40879
|
var SIGKILL_ESCALATION_MS = 2e3;
|
|
@@ -40594,7 +40994,7 @@ var RestartableStdioProxy = class {
|
|
|
40594
40994
|
}
|
|
40595
40995
|
async spawnChild(stdout, preResolved) {
|
|
40596
40996
|
const spec = preResolved ?? await this.opts.spawnSpec();
|
|
40597
|
-
const spawn44 = this.opts.spawnImpl ??
|
|
40997
|
+
const spawn44 = this.opts.spawnImpl ?? import_node_child_process31.spawn;
|
|
40598
40998
|
const child = spawn44(spec.command, spec.args, {
|
|
40599
40999
|
env: { ...process.env, ...spec.env },
|
|
40600
41000
|
// env only — never argv
|
|
@@ -40634,7 +41034,7 @@ function resolveDelivery(id) {
|
|
|
40634
41034
|
function commandExists(command2) {
|
|
40635
41035
|
try {
|
|
40636
41036
|
const probe = process.platform === "win32" ? "where" : "which";
|
|
40637
|
-
(0,
|
|
41037
|
+
(0, import_node_child_process32.execFileSync)(probe, [command2], { stdio: "ignore" });
|
|
40638
41038
|
return true;
|
|
40639
41039
|
} catch {
|
|
40640
41040
|
return false;
|
|
@@ -40642,13 +41042,13 @@ function commandExists(command2) {
|
|
|
40642
41042
|
}
|
|
40643
41043
|
function localBinCandidates(command2) {
|
|
40644
41044
|
return [
|
|
40645
|
-
|
|
40646
|
-
|
|
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)
|
|
40647
41047
|
];
|
|
40648
41048
|
}
|
|
40649
41049
|
function resolveLauncherPath(command2, deps = {
|
|
40650
41050
|
commandExists,
|
|
40651
|
-
existsSync:
|
|
41051
|
+
existsSync: import_node_fs12.existsSync
|
|
40652
41052
|
}) {
|
|
40653
41053
|
if (deps.commandExists(command2)) return command2;
|
|
40654
41054
|
for (const candidate of localBinCandidates(command2)) {
|
|
@@ -40667,7 +41067,7 @@ function ensureCommand(command2) {
|
|
|
40667
41067
|
}
|
|
40668
41068
|
if (command2 === "uvx") {
|
|
40669
41069
|
try {
|
|
40670
|
-
(0,
|
|
41070
|
+
(0, import_node_child_process32.execSync)("curl -LsSf https://astral.sh/uv/install.sh | sh", {
|
|
40671
41071
|
stdio: ["ignore", process.stderr, process.stderr],
|
|
40672
41072
|
timeout: 18e4,
|
|
40673
41073
|
env: { ...process.env, UV_NO_MODIFY_PATH: "1" }
|
|
@@ -40676,7 +41076,7 @@ function ensureCommand(command2) {
|
|
|
40676
41076
|
}
|
|
40677
41077
|
if (resolveLauncherPath(command2) !== command2) return;
|
|
40678
41078
|
try {
|
|
40679
|
-
(0,
|
|
41079
|
+
(0, import_node_child_process32.execSync)("python3 -m pip install --user --quiet uv", {
|
|
40680
41080
|
stdio: ["ignore", process.stderr, process.stderr],
|
|
40681
41081
|
timeout: 18e4
|
|
40682
41082
|
});
|
|
@@ -40742,7 +41142,7 @@ async function mcpRun(args2) {
|
|
|
40742
41142
|
// src/commands/version.ts
|
|
40743
41143
|
var import_picocolors15 = __toESM(require("picocolors"));
|
|
40744
41144
|
function version2() {
|
|
40745
|
-
const v = true ? "2.61.
|
|
41145
|
+
const v = true ? "2.61.78" : "unknown";
|
|
40746
41146
|
console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
|
|
40747
41147
|
}
|
|
40748
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",
|