codeam-cli 2.75.9 → 2.75.10
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 +80 -34
- 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.75.9] — 2026-09-23
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **cli:** Agent packs — structured Reviewer findings, in-place resume, rehydration after restart
|
|
12
|
+
|
|
7
13
|
## [2.75.8] — 2026-09-23
|
|
8
14
|
|
|
9
15
|
### Fixed
|
package/dist/index.js
CHANGED
|
@@ -10509,7 +10509,7 @@ function readAnonId() {
|
|
|
10509
10509
|
}
|
|
10510
10510
|
function superProperties() {
|
|
10511
10511
|
return {
|
|
10512
|
-
cliVersion: true ? "2.75.
|
|
10512
|
+
cliVersion: true ? "2.75.10" : "0.0.0-dev",
|
|
10513
10513
|
nodeVersion: process.version,
|
|
10514
10514
|
platform: process.platform,
|
|
10515
10515
|
arch: process.arch,
|
|
@@ -10751,7 +10751,7 @@ var http = __toESM(require("http"));
|
|
|
10751
10751
|
// package.json
|
|
10752
10752
|
var package_default = {
|
|
10753
10753
|
name: "codeam-cli",
|
|
10754
|
-
version: "2.75.
|
|
10754
|
+
version: "2.75.10",
|
|
10755
10755
|
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.",
|
|
10756
10756
|
type: "commonjs",
|
|
10757
10757
|
main: "dist/index.js",
|
|
@@ -12081,7 +12081,7 @@ var CommandRelayService = class _CommandRelayService {
|
|
|
12081
12081
|
// fresh + clear the "CLI update available" banner after a self-update
|
|
12082
12082
|
// (a codespace that reinstalls @latest reconnects via heartbeat, not
|
|
12083
12083
|
// pair/reconnect). Older backends ignore the extra field.
|
|
12084
|
-
..."2.75.
|
|
12084
|
+
..."2.75.10" ? { ideVersion: "2.75.10" } : {}
|
|
12085
12085
|
};
|
|
12086
12086
|
try {
|
|
12087
12087
|
const res = await _postJson(`${API_BASE2}/api/plugin/heartbeat`, body);
|
|
@@ -33795,7 +33795,7 @@ function internalPathPermissionOutcome(request2, homeDir2) {
|
|
|
33795
33795
|
var INTERNAL_BLOCK_REASON = "This path is a CodeAgent platform internal (CodeAgent's own runtime plumbing, not part of the user's project) and is off-limits. Continue with the user's own project files.";
|
|
33796
33796
|
|
|
33797
33797
|
// src/agents/acp/guardrails.ts
|
|
33798
|
-
var SECRET_RE = /(^|[\s"'`=(/\\])(\.env(\.[\w.-]+)?|[\w.-]+\.(pem|key|pfx|p12|jks|keystore)|id_rsa|id_ed25519|\.npmrc|\.pgpass|\.netrc|\.git-credentials|kubeconfig
|
|
33798
|
+
var SECRET_RE = /(^|[\s"'`=(/\\])(\.env(\.[\w.-]+)?|[\w.-]+\.(pem|key|pfx|p12|jks|keystore)|id_rsa|id_ed25519|\.npmrc|\.pgpass|\.netrc|\.git-credentials|kubeconfig|\.credentials(\.[\w-]+)?)\b|[/\\]credentials(\.[\w-]+)?\b/i;
|
|
33799
33799
|
var DESTRUCTIVE_RES = [
|
|
33800
33800
|
/\brm\s+-[a-z]*f/i,
|
|
33801
33801
|
// rm -rf / -fr / -f
|
|
@@ -33821,6 +33821,15 @@ var OUTWARD_RES = [
|
|
|
33821
33821
|
/\bnetlify\s+deploy\b/i,
|
|
33822
33822
|
/\beas\s+(submit|build)\b/i
|
|
33823
33823
|
];
|
|
33824
|
+
function editTargetHaystack(call) {
|
|
33825
|
+
const parts = [typeof call.title === "string" ? call.title : ""];
|
|
33826
|
+
if (call.rawInput && typeof call.rawInput === "object" && !Array.isArray(call.rawInput)) {
|
|
33827
|
+
for (const [key, value] of Object.entries(call.rawInput)) {
|
|
33828
|
+
if (typeof value === "string" && /path|file|dest|target/i.test(key)) parts.push(value);
|
|
33829
|
+
}
|
|
33830
|
+
}
|
|
33831
|
+
return parts.join("\n");
|
|
33832
|
+
}
|
|
33824
33833
|
function haystack(call) {
|
|
33825
33834
|
let s = typeof call.title === "string" ? call.title : "";
|
|
33826
33835
|
if (call.rawInput != null) {
|
|
@@ -33849,7 +33858,7 @@ function toolPathIsSecret(p2) {
|
|
|
33849
33858
|
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.";
|
|
33850
33859
|
function guardrailDecision(request2, policy) {
|
|
33851
33860
|
if (isProseOnlyToolKind(request2.toolCall.kind)) return null;
|
|
33852
|
-
const hay = haystack(request2.toolCall);
|
|
33861
|
+
const hay = request2.toolCall.kind === "edit" ? editTargetHaystack(request2.toolCall) : haystack(request2.toolCall);
|
|
33853
33862
|
if (!hay) return null;
|
|
33854
33863
|
const matched = matchedCategories(hay);
|
|
33855
33864
|
if (matched.size === 0) return null;
|
|
@@ -33873,7 +33882,11 @@ function guardrailDecision(request2, policy) {
|
|
|
33873
33882
|
};
|
|
33874
33883
|
}
|
|
33875
33884
|
if (confirmCat) {
|
|
33876
|
-
return {
|
|
33885
|
+
return {
|
|
33886
|
+
kind: "confirm",
|
|
33887
|
+
category: confirmCat,
|
|
33888
|
+
reason: GUARDRAIL_CATEGORY_META[confirmCat].description
|
|
33889
|
+
};
|
|
33877
33890
|
}
|
|
33878
33891
|
return null;
|
|
33879
33892
|
}
|
|
@@ -38054,7 +38067,7 @@ var PackRunner = class _PackRunner {
|
|
|
38054
38067
|
previousAttemptError
|
|
38055
38068
|
});
|
|
38056
38069
|
const displayLine = `\u25B6 ${this.pack.name} \u2014 stage ${index + 1}/${this.pack.stages.length}: ${stageDef.name}`;
|
|
38057
|
-
turn = await this.drive(prompt, displayLine);
|
|
38070
|
+
turn = await this.drive(prompt, displayLine, index);
|
|
38058
38071
|
}
|
|
38059
38072
|
if (this.aborted()) {
|
|
38060
38073
|
await this.settle("aborted");
|
|
@@ -38069,7 +38082,7 @@ var PackRunner = class _PackRunner {
|
|
|
38069
38082
|
return this.recordHandoff(
|
|
38070
38083
|
index,
|
|
38071
38084
|
stageDef,
|
|
38072
|
-
await this.noChangeHandoff(startSha, text, startedMs)
|
|
38085
|
+
await this.noChangeHandoff(stageDef, startSha, text, startedMs)
|
|
38073
38086
|
);
|
|
38074
38087
|
}
|
|
38075
38088
|
if (!this.state.stages[index].conversationId) {
|
|
@@ -38078,7 +38091,7 @@ var PackRunner = class _PackRunner {
|
|
|
38078
38091
|
"stage produced no commit \u2014 Retry stage to run it again in a fresh conversation"
|
|
38079
38092
|
);
|
|
38080
38093
|
}
|
|
38081
|
-
const nudged = await this.drive(NUDGE_PROMPT, "\u25B6 Waiting for the stage commit\u2026");
|
|
38094
|
+
const nudged = await this.drive(NUDGE_PROMPT, "\u25B6 Waiting for the stage commit\u2026", index);
|
|
38082
38095
|
if (this.aborted()) {
|
|
38083
38096
|
await this.settle("aborted");
|
|
38084
38097
|
return false;
|
|
@@ -38091,7 +38104,7 @@ var PackRunner = class _PackRunner {
|
|
|
38091
38104
|
return this.recordHandoff(
|
|
38092
38105
|
index,
|
|
38093
38106
|
stageDef,
|
|
38094
|
-
await this.noChangeHandoff(startSha, text, startedMs)
|
|
38107
|
+
await this.noChangeHandoff(stageDef, startSha, text, startedMs)
|
|
38095
38108
|
);
|
|
38096
38109
|
}
|
|
38097
38110
|
return this.stall(index, "stage produced no commit", text);
|
|
@@ -38123,10 +38136,13 @@ var PackRunner = class _PackRunner {
|
|
|
38123
38136
|
aborted() {
|
|
38124
38137
|
return this.control === "abort";
|
|
38125
38138
|
}
|
|
38126
|
-
async drive(prompt, displayLine) {
|
|
38139
|
+
async drive(prompt, displayLine, index) {
|
|
38127
38140
|
this.inTurn = true;
|
|
38128
38141
|
try {
|
|
38129
|
-
return await this.deps.driver.runTurn(prompt, displayLine)
|
|
38142
|
+
return await this.deps.driver.runTurn(prompt, displayLine, (pending) => {
|
|
38143
|
+
this.patchStage(index, { awaitingUser: pending ? true : void 0 });
|
|
38144
|
+
void this.publish();
|
|
38145
|
+
});
|
|
38130
38146
|
} finally {
|
|
38131
38147
|
this.inTurn = false;
|
|
38132
38148
|
}
|
|
@@ -38138,13 +38154,19 @@ var PackRunner = class _PackRunner {
|
|
|
38138
38154
|
if (fresh.length > 0) this.deps.driver.mountSkills(fresh);
|
|
38139
38155
|
this.mountedSkills = next.slice();
|
|
38140
38156
|
}
|
|
38141
|
-
async noChangeHandoff(startSha, text, startedMs) {
|
|
38157
|
+
async noChangeHandoff(stageDef, startSha, text, startedMs) {
|
|
38142
38158
|
const reviewedCommit = startSha ? await this.deps.gates.canonicalCommit(startSha) : null;
|
|
38143
38159
|
return {
|
|
38144
38160
|
commit: reviewedCommit ?? "(no changes)",
|
|
38145
38161
|
summary: summarizeReply(text),
|
|
38146
38162
|
diffStat: "reviewed \u2014 no changes needed",
|
|
38147
|
-
durationMs: Date.now() - startedMs
|
|
38163
|
+
durationMs: Date.now() - startedMs,
|
|
38164
|
+
// A findings-producing stage that hands off without a commit never
|
|
38165
|
+
// wrote its findings file (its contract says: commit it even when
|
|
38166
|
+
// empty). Say so — the next stage must not assume a clean bill.
|
|
38167
|
+
...stageDef.producesFindings ? {
|
|
38168
|
+
findingsNote: `no ${PACK_FINDINGS_FILE} committed \u2014 the stage handed off without structured findings`
|
|
38169
|
+
} : {}
|
|
38148
38170
|
};
|
|
38149
38171
|
}
|
|
38150
38172
|
/**
|
|
@@ -38253,15 +38275,20 @@ function buildPackRunnerDeps(ctx) {
|
|
|
38253
38275
|
ctx.onActiveSessionChanged?.(id);
|
|
38254
38276
|
return id;
|
|
38255
38277
|
},
|
|
38256
|
-
runTurn: async (prompt, displayLine) => {
|
|
38278
|
+
runTurn: async (prompt, displayLine, onAwaiting) => {
|
|
38257
38279
|
await ctx.streaming.beginTurn();
|
|
38258
38280
|
ctx.history.appendUserPrompt(displayLine);
|
|
38259
|
-
|
|
38260
|
-
|
|
38261
|
-
|
|
38262
|
-
|
|
38263
|
-
|
|
38264
|
-
|
|
38281
|
+
ctx.streaming.setPendingListener(onAwaiting ?? null);
|
|
38282
|
+
try {
|
|
38283
|
+
await ctx.client.prompt(prompt);
|
|
38284
|
+
const text = ctx.streaming.getCurrentText();
|
|
38285
|
+
const awaitingUser = await ctx.streaming.closeTurnWithInteractiveDetection();
|
|
38286
|
+
ctx.history.appendAgentReply(text);
|
|
38287
|
+
await ctx.history.flush();
|
|
38288
|
+
return { text, awaitingUser };
|
|
38289
|
+
} finally {
|
|
38290
|
+
ctx.streaming.setPendingListener(null);
|
|
38291
|
+
}
|
|
38265
38292
|
},
|
|
38266
38293
|
cancel: () => ctx.client.cancel(),
|
|
38267
38294
|
mountSkills: (skillIds) => {
|
|
@@ -40064,6 +40091,25 @@ var StreamingState = class {
|
|
|
40064
40091
|
*/
|
|
40065
40092
|
text = "";
|
|
40066
40093
|
pending = null;
|
|
40094
|
+
/** Observer for "is a question pending?" flips. The Agent Packs runner marks
|
|
40095
|
+
* its stage `awaitingUser` while a permission prompt waits on the user
|
|
40096
|
+
* MID-turn, instead of a stage that looks silently "working" for the 5-min
|
|
40097
|
+
* permission TTL (live run 2026-09-23). Never throws into the turn. */
|
|
40098
|
+
pendingListener = null;
|
|
40099
|
+
setPendingListener(listener) {
|
|
40100
|
+
this.pendingListener = listener;
|
|
40101
|
+
}
|
|
40102
|
+
setPending(next) {
|
|
40103
|
+
const was = this.pending !== null;
|
|
40104
|
+
this.pending = next;
|
|
40105
|
+
const is = next !== null;
|
|
40106
|
+
if (was !== is) {
|
|
40107
|
+
try {
|
|
40108
|
+
this.pendingListener?.(is);
|
|
40109
|
+
} catch {
|
|
40110
|
+
}
|
|
40111
|
+
}
|
|
40112
|
+
}
|
|
40067
40113
|
/**
|
|
40068
40114
|
* While true, {@link append} drops incoming session/update deltas instead of
|
|
40069
40115
|
* publishing them. Used by the baton {@link AcpDriver} to swallow the
|
|
@@ -40166,7 +40212,7 @@ var StreamingState = class {
|
|
|
40166
40212
|
"acpRunner",
|
|
40167
40213
|
`permission ${args2.questionId.slice(0, 8)} TTL expired \u2014 auto-cancel`
|
|
40168
40214
|
);
|
|
40169
|
-
this.
|
|
40215
|
+
this.setPending(null);
|
|
40170
40216
|
void this.publisher.publishOutput({
|
|
40171
40217
|
type: "text",
|
|
40172
40218
|
content: permissionExpiredNotice(),
|
|
@@ -40175,13 +40221,13 @@ var StreamingState = class {
|
|
|
40175
40221
|
resolve11({ outcome: { outcome: "cancelled" } });
|
|
40176
40222
|
}
|
|
40177
40223
|
}, PERMISSION_TIMEOUT_MS);
|
|
40178
|
-
this.
|
|
40224
|
+
this.setPending({
|
|
40179
40225
|
kind: "permission",
|
|
40180
40226
|
questionId: args2.questionId,
|
|
40181
40227
|
options: args2.options,
|
|
40182
40228
|
resolve: resolve11,
|
|
40183
40229
|
timeoutTimer
|
|
40184
|
-
};
|
|
40230
|
+
});
|
|
40185
40231
|
});
|
|
40186
40232
|
}
|
|
40187
40233
|
/**
|
|
@@ -40190,7 +40236,7 @@ var StreamingState = class {
|
|
|
40190
40236
|
* `resolveSelection()` (user picked).
|
|
40191
40237
|
*/
|
|
40192
40238
|
registerFreeformOptions(options) {
|
|
40193
|
-
this.
|
|
40239
|
+
this.setPending({ kind: "free-form", options });
|
|
40194
40240
|
}
|
|
40195
40241
|
/**
|
|
40196
40242
|
* Apply a `select_option` command (delivered via the CLI's SSE
|
|
@@ -40217,7 +40263,7 @@ var StreamingState = class {
|
|
|
40217
40263
|
const picked = byId ?? this.pending.options[index];
|
|
40218
40264
|
clearTimeout(this.pending.timeoutTimer);
|
|
40219
40265
|
const resolve11 = this.pending.resolve;
|
|
40220
|
-
this.
|
|
40266
|
+
this.setPending(null);
|
|
40221
40267
|
if (!picked) {
|
|
40222
40268
|
log.warn("acpRunner", `select_option index=${index} out of bounds \u2014 cancel`);
|
|
40223
40269
|
resolve11({ outcome: { outcome: "cancelled" } });
|
|
@@ -40227,7 +40273,7 @@ var StreamingState = class {
|
|
|
40227
40273
|
return { kind: "resolved", optionId: picked.optionId };
|
|
40228
40274
|
}
|
|
40229
40275
|
const text = this.pending.options[index];
|
|
40230
|
-
this.
|
|
40276
|
+
this.setPending(null);
|
|
40231
40277
|
if (!text) {
|
|
40232
40278
|
log.warn("acpRunner", `select_option index=${index} out of bounds (free-form) \u2014 drop`);
|
|
40233
40279
|
return { kind: "none" };
|
|
@@ -40283,7 +40329,7 @@ var StreamingState = class {
|
|
|
40283
40329
|
if (this.pending?.kind === "permission") {
|
|
40284
40330
|
clearTimeout(this.pending.timeoutTimer);
|
|
40285
40331
|
}
|
|
40286
|
-
this.
|
|
40332
|
+
this.setPending(null);
|
|
40287
40333
|
if (opts?.clear !== false) {
|
|
40288
40334
|
await this.publisher.publishOutput({ type: "clear" });
|
|
40289
40335
|
}
|
|
@@ -40470,7 +40516,7 @@ var StreamingState = class {
|
|
|
40470
40516
|
done: true
|
|
40471
40517
|
});
|
|
40472
40518
|
}
|
|
40473
|
-
this.
|
|
40519
|
+
this.setPending({ kind: "free-form", options: extracted.options });
|
|
40474
40520
|
await this.publisher.publishOutput({
|
|
40475
40521
|
type: "select_prompt",
|
|
40476
40522
|
content: extracted.question ?? "Pick an option",
|
|
@@ -47014,7 +47060,7 @@ async function autoUpgradeBeforeCriticalCommand() {
|
|
|
47014
47060
|
if (process.env.NODE_ENV === "test") return;
|
|
47015
47061
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
47016
47062
|
if (process.env.CI) return;
|
|
47017
|
-
const current2 = true ? "2.75.
|
|
47063
|
+
const current2 = true ? "2.75.10" : null;
|
|
47018
47064
|
if (!current2) return;
|
|
47019
47065
|
const cache = readCache();
|
|
47020
47066
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -47031,7 +47077,7 @@ function checkForUpdates() {
|
|
|
47031
47077
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
47032
47078
|
if (process.env.CI) return;
|
|
47033
47079
|
if (!process.stdout.isTTY) return;
|
|
47034
|
-
const current2 = true ? "2.75.
|
|
47080
|
+
const current2 = true ? "2.75.10" : null;
|
|
47035
47081
|
if (!current2) return;
|
|
47036
47082
|
const cache = readCache();
|
|
47037
47083
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -47054,7 +47100,7 @@ var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
|
|
|
47054
47100
|
var SELF_UPDATE_LS_TIMEOUT_MS = 15e3;
|
|
47055
47101
|
var SUDO_PREFLIGHT_TIMEOUT_MS = 5e3;
|
|
47056
47102
|
function currentCliVersion() {
|
|
47057
|
-
return true ? "2.75.
|
|
47103
|
+
return true ? "2.75.10" : null;
|
|
47058
47104
|
}
|
|
47059
47105
|
async function installedVersion(deps) {
|
|
47060
47106
|
const ls = await deps.run(
|
|
@@ -48794,7 +48840,7 @@ function checkChokidar() {
|
|
|
48794
48840
|
}
|
|
48795
48841
|
async function doctor(args2 = []) {
|
|
48796
48842
|
const json = args2.includes("--json");
|
|
48797
|
-
const cliVersion = true ? "2.75.
|
|
48843
|
+
const cliVersion = true ? "2.75.10" : "0.0.0-dev";
|
|
48798
48844
|
const apiBase2 = resolveApiBaseUrl();
|
|
48799
48845
|
const diagnosticId = (0, import_node_crypto12.randomUUID)();
|
|
48800
48846
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -49318,7 +49364,7 @@ async function mcpWarm(argv = [], opts = {}) {
|
|
|
49318
49364
|
// src/commands/version.ts
|
|
49319
49365
|
var import_picocolors15 = __toESM(require("picocolors"));
|
|
49320
49366
|
function version2() {
|
|
49321
|
-
const v = true ? "2.75.
|
|
49367
|
+
const v = true ? "2.75.10" : "unknown";
|
|
49322
49368
|
console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
|
|
49323
49369
|
}
|
|
49324
49370
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeam-cli",
|
|
3
|
-
"version": "2.75.
|
|
3
|
+
"version": "2.75.10",
|
|
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",
|