codeam-cli 2.65.13 → 2.65.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/dist/index.js +99 -55
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,12 @@ All notable changes to `codeam-cli` are documented here.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [2.65.13] — 2026-08-20
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **cli:** Filter non-chat models out of the native ACP model catalog
|
|
12
|
+
|
|
7
13
|
## [2.65.12] — 2026-08-19
|
|
8
14
|
|
|
9
15
|
### CI
|
package/dist/index.js
CHANGED
|
@@ -8079,7 +8079,7 @@ function readAnonId() {
|
|
|
8079
8079
|
}
|
|
8080
8080
|
function superProperties() {
|
|
8081
8081
|
return {
|
|
8082
|
-
cliVersion: true ? "2.65.
|
|
8082
|
+
cliVersion: true ? "2.65.14" : "0.0.0-dev",
|
|
8083
8083
|
nodeVersion: process.version,
|
|
8084
8084
|
platform: process.platform,
|
|
8085
8085
|
arch: process.arch,
|
|
@@ -8321,7 +8321,7 @@ var http = __toESM(require("http"));
|
|
|
8321
8321
|
// package.json
|
|
8322
8322
|
var package_default = {
|
|
8323
8323
|
name: "codeam-cli",
|
|
8324
|
-
version: "2.65.
|
|
8324
|
+
version: "2.65.14",
|
|
8325
8325
|
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.",
|
|
8326
8326
|
type: "commonjs",
|
|
8327
8327
|
main: "dist/index.js",
|
|
@@ -9842,7 +9842,7 @@ var CommandRelayService = class _CommandRelayService {
|
|
|
9842
9842
|
// fresh + clear the "CLI update available" banner after a self-update
|
|
9843
9843
|
// (a codespace that reinstalls @latest reconnects via heartbeat, not
|
|
9844
9844
|
// pair/reconnect). Older backends ignore the extra field.
|
|
9845
|
-
..."2.65.
|
|
9845
|
+
..."2.65.14" ? { ideVersion: "2.65.14" } : {}
|
|
9846
9846
|
}).then(() => log.trace("relay", `heartbeat ok online=${online}`)).catch((err) => log.trace("relay", `heartbeat failed online=${online}`, err));
|
|
9847
9847
|
}
|
|
9848
9848
|
/**
|
|
@@ -21966,7 +21966,7 @@ async function autoUpgradeBeforeCriticalCommand() {
|
|
|
21966
21966
|
if (process.env.NODE_ENV === "test") return;
|
|
21967
21967
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
21968
21968
|
if (process.env.CI) return;
|
|
21969
|
-
const current2 = true ? "2.65.
|
|
21969
|
+
const current2 = true ? "2.65.14" : null;
|
|
21970
21970
|
if (!current2) return;
|
|
21971
21971
|
const cache = readCache();
|
|
21972
21972
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -21983,7 +21983,7 @@ function checkForUpdates() {
|
|
|
21983
21983
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
21984
21984
|
if (process.env.CI) return;
|
|
21985
21985
|
if (!process.stdout.isTTY) return;
|
|
21986
|
-
const current2 = true ? "2.65.
|
|
21986
|
+
const current2 = true ? "2.65.14" : null;
|
|
21987
21987
|
if (!current2) return;
|
|
21988
21988
|
const cache = readCache();
|
|
21989
21989
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -22003,7 +22003,7 @@ var SELF_UPDATE_INTERVAL_MS = 60 * 60 * 1e3;
|
|
|
22003
22003
|
var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
|
|
22004
22004
|
var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
|
|
22005
22005
|
function currentCliVersion() {
|
|
22006
|
-
return true ? "2.65.
|
|
22006
|
+
return true ? "2.65.14" : null;
|
|
22007
22007
|
}
|
|
22008
22008
|
function runCmd(cmd, args2, timeoutMs) {
|
|
22009
22009
|
return new Promise((resolve10) => {
|
|
@@ -33942,6 +33942,10 @@ function createIdleTimeout(idleMs, makeError, activeIdleMs = idleMs) {
|
|
|
33942
33942
|
var path74 = __toESM(require("path"));
|
|
33943
33943
|
var os57 = __toESM(require("os"));
|
|
33944
33944
|
var INTERNAL_TOKENS = [".codeam", "house-claude"];
|
|
33945
|
+
var PROSE_ONLY_TOOL_KINDS = /* @__PURE__ */ new Set(["think", "switch_mode"]);
|
|
33946
|
+
function isProseOnlyToolKind(kind) {
|
|
33947
|
+
return kind != null && PROSE_ONLY_TOOL_KINDS.has(kind);
|
|
33948
|
+
}
|
|
33945
33949
|
var SELF_HOSTED_WORKSPACE_RE = /\.codeam[/\\]self-hosted/gi;
|
|
33946
33950
|
function textReferencesInternal(text) {
|
|
33947
33951
|
if (!text) return false;
|
|
@@ -33956,7 +33960,9 @@ function pathIsInternal(p2, homeDir2 = os57.homedir()) {
|
|
|
33956
33960
|
if (within(path74.join(home, ".codeam", "self-hosted"))) return false;
|
|
33957
33961
|
return within(path74.join(home, ".codeam")) || within(path74.join(home, ".beads")) || abs === path74.join(home, ".codeam-host.log") || abs.includes(`${path74.sep}house-claude${path74.sep}`) || abs.endsWith(`${path74.sep}house-claude`);
|
|
33958
33962
|
}
|
|
33959
|
-
function toolCallReferencesInternal(call) {
|
|
33963
|
+
function toolCallReferencesInternal(call, homeDir2) {
|
|
33964
|
+
if (call.locations?.some((l) => pathIsInternal(l.path, homeDir2))) return true;
|
|
33965
|
+
if (isProseOnlyToolKind(call.kind)) return false;
|
|
33960
33966
|
if (textReferencesInternal(call.title)) return true;
|
|
33961
33967
|
if (call.rawInput != null) {
|
|
33962
33968
|
try {
|
|
@@ -33967,9 +33973,9 @@ function toolCallReferencesInternal(call) {
|
|
|
33967
33973
|
}
|
|
33968
33974
|
return false;
|
|
33969
33975
|
}
|
|
33970
|
-
function internalPathPermissionOutcome(request) {
|
|
33971
|
-
if (!toolCallReferencesInternal(request.toolCall)) return null;
|
|
33972
|
-
const reject = request.options.find((o) => o.kind === "
|
|
33976
|
+
function internalPathPermissionOutcome(request, homeDir2) {
|
|
33977
|
+
if (!toolCallReferencesInternal(request.toolCall, homeDir2)) return null;
|
|
33978
|
+
const reject = request.options.find((o) => o.kind === "reject_once") ?? request.options.find((o) => o.kind === "reject_always");
|
|
33973
33979
|
if (reject) return { outcome: { outcome: "selected", optionId: reject.optionId } };
|
|
33974
33980
|
return { outcome: { outcome: "cancelled" } };
|
|
33975
33981
|
}
|
|
@@ -34029,6 +34035,7 @@ function toolPathIsSecret(p2) {
|
|
|
34029
34035
|
}
|
|
34030
34036
|
var GUARDRAIL_SECRET_READ_BLOCK_REASON = "Reading this secret file is blocked by this session's guardrails (Reading secrets = Deny). Adjust it in the session Guardrails settings if intended.";
|
|
34031
34037
|
function guardrailDecision(request, policy) {
|
|
34038
|
+
if (isProseOnlyToolKind(request.toolCall.kind)) return null;
|
|
34032
34039
|
const hay = haystack(request.toolCall);
|
|
34033
34040
|
if (!hay) return null;
|
|
34034
34041
|
const matched = matchedCategories(hay);
|
|
@@ -36226,6 +36233,73 @@ function humanizeKind(kind) {
|
|
|
36226
36233
|
}
|
|
36227
36234
|
}
|
|
36228
36235
|
|
|
36236
|
+
// src/agents/acp/permission-gate.ts
|
|
36237
|
+
function pickAllowOption(options) {
|
|
36238
|
+
return options.find((o) => o.kind === "allow_always") ?? options.find((o) => o.kind === "allow_once") ?? null;
|
|
36239
|
+
}
|
|
36240
|
+
function describeToolCallForNotice(toolCall) {
|
|
36241
|
+
const title = toolCall.title?.trim();
|
|
36242
|
+
return title ? `"${title}"` : "a tool call";
|
|
36243
|
+
}
|
|
36244
|
+
function internalBlockNotice(toolCall) {
|
|
36245
|
+
return `\u26D4 CodeAgent auto-blocked ${describeToolCallForNotice(toolCall)} \u2014 it targets CodeAgent's own runtime files (~/.codeam), which are off-limits to the agent. This was an automatic block by CodeAgent, not a rejection by you.`;
|
|
36246
|
+
}
|
|
36247
|
+
function guardrailBlockNotice(decision, toolCall) {
|
|
36248
|
+
return `\u26D4 Guardrail auto-blocked ${describeToolCallForNotice(toolCall)} \u2014 ${decision.reason} This session's "${decision.category}" guardrail is set to Deny (adjust it in the session's Guardrails settings if intended). This was an automatic block, not a rejection by you.`;
|
|
36249
|
+
}
|
|
36250
|
+
function createOnRequestPermission(deps) {
|
|
36251
|
+
return async (request) => {
|
|
36252
|
+
let guardrailConfirm = false;
|
|
36253
|
+
if (!deps.isLocal()) {
|
|
36254
|
+
const denied = internalPathPermissionOutcome(request);
|
|
36255
|
+
if (denied) {
|
|
36256
|
+
log.warn(
|
|
36257
|
+
"acpRunner",
|
|
36258
|
+
"internal-path guard \u2014 denying tool call referencing a CodeAgent platform internal"
|
|
36259
|
+
);
|
|
36260
|
+
void deps.publisher.publishOutput({
|
|
36261
|
+
type: "text",
|
|
36262
|
+
content: internalBlockNotice(request.toolCall),
|
|
36263
|
+
done: true
|
|
36264
|
+
});
|
|
36265
|
+
return denied;
|
|
36266
|
+
}
|
|
36267
|
+
const g = guardrailDecision(request, deps.getPolicy());
|
|
36268
|
+
if (g?.kind === "deny") {
|
|
36269
|
+
log.warn("acpRunner", `guardrail [${g.category}] \u2014 denying tool call`);
|
|
36270
|
+
void deps.publisher.publishOutput({
|
|
36271
|
+
type: "text",
|
|
36272
|
+
content: guardrailBlockNotice(g, request.toolCall),
|
|
36273
|
+
done: true
|
|
36274
|
+
});
|
|
36275
|
+
return g.outcome;
|
|
36276
|
+
}
|
|
36277
|
+
if (g?.kind === "confirm") {
|
|
36278
|
+
guardrailConfirm = true;
|
|
36279
|
+
log.info("acpRunner", `guardrail [${g.category}] \u2014 requiring confirmation`);
|
|
36280
|
+
}
|
|
36281
|
+
}
|
|
36282
|
+
if (deps.autoApprovePermissions && !guardrailConfirm) {
|
|
36283
|
+
const allow = pickAllowOption(request.options);
|
|
36284
|
+
if (allow) {
|
|
36285
|
+
log.info(
|
|
36286
|
+
"acpRunner",
|
|
36287
|
+
`AUTO mode \u2014 auto-approving permission (${allow.kind}) optionId=${allow.optionId}`
|
|
36288
|
+
);
|
|
36289
|
+
return { outcome: { outcome: "selected", optionId: allow.optionId } };
|
|
36290
|
+
}
|
|
36291
|
+
log.warn("acpRunner", "AUTO mode \u2014 no allow option offered; falling back to interactive");
|
|
36292
|
+
}
|
|
36293
|
+
const { event, optionIdByLabel } = mapPermissionRequest(request);
|
|
36294
|
+
await deps.publisher.publishAwaitingAnswer(event);
|
|
36295
|
+
return deps.registerPermission({
|
|
36296
|
+
questionId: event.questionId,
|
|
36297
|
+
labels: event.options ?? [],
|
|
36298
|
+
optionIdByLabel
|
|
36299
|
+
});
|
|
36300
|
+
};
|
|
36301
|
+
}
|
|
36302
|
+
|
|
36229
36303
|
// src/agents/acp/selectPromptExtractor.ts
|
|
36230
36304
|
var MAX_OPTIONS = 6;
|
|
36231
36305
|
var MAX_OPTION_BODY_CHARS = 200;
|
|
@@ -39555,9 +39629,6 @@ var StreamingState = class {
|
|
|
39555
39629
|
}
|
|
39556
39630
|
};
|
|
39557
39631
|
var PERMISSION_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
39558
|
-
function pickAllowOption(options) {
|
|
39559
|
-
return options.find((o) => o.kind === "allow_always") ?? options.find((o) => o.kind === "allow_once") ?? null;
|
|
39560
|
-
}
|
|
39561
39632
|
var AcpHistory = class {
|
|
39562
39633
|
constructor(publisher, opts) {
|
|
39563
39634
|
this.publisher = publisher;
|
|
@@ -39798,46 +39869,19 @@ async function runAcpSession(opts) {
|
|
|
39798
39869
|
// Same guard the baton uses; the happy path never calls loadSession.
|
|
39799
39870
|
beginLoadReplay: () => streaming.beginLoadReplay(),
|
|
39800
39871
|
endLoadReplay: () => streaming.endLoadReplay(),
|
|
39801
|
-
|
|
39802
|
-
|
|
39803
|
-
|
|
39804
|
-
|
|
39805
|
-
|
|
39806
|
-
|
|
39807
|
-
|
|
39808
|
-
|
|
39809
|
-
|
|
39810
|
-
|
|
39811
|
-
|
|
39812
|
-
|
|
39813
|
-
|
|
39814
|
-
log.warn("acpRunner", `guardrail [${g.category}] \u2014 denying tool call`);
|
|
39815
|
-
return g.outcome;
|
|
39816
|
-
}
|
|
39817
|
-
if (g?.kind === "confirm") {
|
|
39818
|
-
guardrailConfirm = true;
|
|
39819
|
-
log.info("acpRunner", `guardrail [${g.category}] \u2014 requiring confirmation`);
|
|
39820
|
-
}
|
|
39821
|
-
}
|
|
39822
|
-
if (opts.autoApprovePermissions && !guardrailConfirm) {
|
|
39823
|
-
const allow = pickAllowOption(request.options);
|
|
39824
|
-
if (allow) {
|
|
39825
|
-
log.info(
|
|
39826
|
-
"acpRunner",
|
|
39827
|
-
`AUTO mode \u2014 auto-approving permission (${allow.kind}) optionId=${allow.optionId}`
|
|
39828
|
-
);
|
|
39829
|
-
return { outcome: { outcome: "selected", optionId: allow.optionId } };
|
|
39830
|
-
}
|
|
39831
|
-
log.warn("acpRunner", "AUTO mode \u2014 no allow option offered; falling back to interactive");
|
|
39832
|
-
}
|
|
39833
|
-
const { event, optionIdByLabel } = mapPermissionRequest(request);
|
|
39834
|
-
await publisher.publishAwaitingAnswer(event);
|
|
39835
|
-
return streaming.registerPermission({
|
|
39836
|
-
questionId: event.questionId,
|
|
39837
|
-
labels: event.options ?? [],
|
|
39838
|
-
optionIdByLabel
|
|
39839
|
-
});
|
|
39840
|
-
},
|
|
39872
|
+
// The full `session/request_permission` decision path (internal-path guard
|
|
39873
|
+
// → guardrails → AUTO auto-approve → interactive prompt) lives in
|
|
39874
|
+
// ./permission-gate.ts so it is unit-tested exactly as it runs here.
|
|
39875
|
+
// HARD RULE enforced there: every auto-REJECT publishes a visible chat
|
|
39876
|
+
// line — a guard must never silently answer for the user (the 2026-08-19
|
|
39877
|
+
// ExitPlanMode silent-rejection P0).
|
|
39878
|
+
onRequestPermission: createOnRequestPermission({
|
|
39879
|
+
autoApprovePermissions: opts.autoApprovePermissions === true,
|
|
39880
|
+
isLocal: isLocalSession,
|
|
39881
|
+
getPolicy: getGuardrailPolicy,
|
|
39882
|
+
publisher,
|
|
39883
|
+
registerPermission: (args2) => streaming.registerPermission(args2)
|
|
39884
|
+
}),
|
|
39841
39885
|
onStderr: (line) => {
|
|
39842
39886
|
recentStderr.push(line);
|
|
39843
39887
|
if (recentStderr.length > 40) recentStderr.shift();
|
|
@@ -45272,7 +45316,7 @@ function checkChokidar() {
|
|
|
45272
45316
|
}
|
|
45273
45317
|
async function doctor(args2 = []) {
|
|
45274
45318
|
const json = args2.includes("--json");
|
|
45275
|
-
const cliVersion = true ? "2.65.
|
|
45319
|
+
const cliVersion = true ? "2.65.14" : "0.0.0-dev";
|
|
45276
45320
|
const apiBase2 = resolveApiBaseUrl();
|
|
45277
45321
|
const diagnosticId = (0, import_node_crypto13.randomUUID)();
|
|
45278
45322
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -45663,7 +45707,7 @@ async function mcpRun(args2) {
|
|
|
45663
45707
|
// src/commands/version.ts
|
|
45664
45708
|
var import_picocolors15 = __toESM(require("picocolors"));
|
|
45665
45709
|
function version2() {
|
|
45666
|
-
const v = true ? "2.65.
|
|
45710
|
+
const v = true ? "2.65.14" : "unknown";
|
|
45667
45711
|
console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
|
|
45668
45712
|
}
|
|
45669
45713
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeam-cli",
|
|
3
|
-
"version": "2.65.
|
|
3
|
+
"version": "2.65.14",
|
|
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",
|