@4pm/cli 1.31.0-b → 1.32.0
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/dist/index.js +109 -9
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -28708,6 +28708,13 @@ var ErrorCode = {
|
|
|
28708
28708
|
WORKER_POOL_NAME_TAKEN: "WORKER_POOL_NAME_TAKEN",
|
|
28709
28709
|
WORKER_POOL_ATTACHED: "WORKER_POOL_ATTACHED",
|
|
28710
28710
|
WORKER_POOL_ALREADY_ATTACHED: "WORKER_POOL_ALREADY_ATTACHED",
|
|
28711
|
+
// A pool can't be both a project pool and the org AI pool (ADR-0376 mutual exclusivity).
|
|
28712
|
+
AI_POOL_CONFLICT: "AI_POOL_CONFLICT",
|
|
28713
|
+
// No org AI pool configured (Settings) for a project-less org AI task (ADR-0376).
|
|
28714
|
+
AI_POOL_NOT_CONFIGURED: "AI_POOL_NOT_CONFIGURED",
|
|
28715
|
+
// Change-request (ADR-0379) not found / already resolved.
|
|
28716
|
+
CHANGE_REQUEST_NOT_FOUND: "CHANGE_REQUEST_NOT_FOUND",
|
|
28717
|
+
CHANGE_REQUEST_ALREADY_RESOLVED: "CHANGE_REQUEST_ALREADY_RESOLVED",
|
|
28711
28718
|
MACHINE_ALREADY_IN_POOL: "MACHINE_ALREADY_IN_POOL",
|
|
28712
28719
|
NOT_MACHINE_USER: "NOT_MACHINE_USER",
|
|
28713
28720
|
// worker · physic project
|
|
@@ -39010,6 +39017,11 @@ var WsChannels = {
|
|
|
39010
39017
|
// entries, commits, pushes a branch, opens a PR, then wipes the token/clone, and replies with the
|
|
39011
39018
|
// PR URL. The write token never persists on the worker (leak-safety on release/reassign).
|
|
39012
39019
|
FAQ_COMPOSE: "faq.compose",
|
|
39020
|
+
// Org-level "AI author checklist items" (ADR-0376): server (picks an idle cli of the org AI pool) →
|
|
39021
|
+
// cli request–reply. The server forwards a ready-built prompt; the worker runs claude one-shot (no
|
|
39022
|
+
// tools, empty dir — like support-answer) and replies with the raw output for the web to parse. No
|
|
39023
|
+
// project is involved (checklists are org-scoped).
|
|
39024
|
+
CHECKLIST_AUTHOR: "checklist.author",
|
|
39013
39025
|
// Shared AI memory (ADR-0245): cli → server one-way write-back of the compacted rolling memory for
|
|
39014
39026
|
// the project it serves (persisted per project × machine-user link). The read direction rides
|
|
39015
39027
|
// `ws_token` (seeds the cli cache on connect); this channel only carries updates.
|
|
@@ -39961,7 +39973,8 @@ function planUnifiedRun(prompt, config, workingCredential, resume, oneShot, over
|
|
|
39961
39973
|
key,
|
|
39962
39974
|
args: buildRunArgs(cred, cmd, resume.get(key), oneShot, override, readOnly, bypass, [...allAiProfileDirs(config), dir2]),
|
|
39963
39975
|
stdin: prompt,
|
|
39964
|
-
env: envVar ? { ...baseEnv, [envVar]: dir2, ...overrideEnv(cmd, override) } : { ...baseEnv, ...overrideEnv(cmd, override) }
|
|
39976
|
+
env: envVar ? { ...baseEnv, [envVar]: dir2, ...overrideEnv(cmd, override) } : { ...baseEnv, ...overrideEnv(cmd, override) },
|
|
39977
|
+
...cred.apiKey ? { apiKey: cred.apiKey } : {}
|
|
39965
39978
|
}));
|
|
39966
39979
|
return { cmd: attempts[0]?.cmd ?? DEFAULT_AI_CLI, attempts };
|
|
39967
39980
|
}
|
|
@@ -39991,7 +40004,8 @@ function planLegacyRun(prompt, config, workingDir, resume, oneShot, override, re
|
|
|
39991
40004
|
key,
|
|
39992
40005
|
args: buildRunArgs(profile, cmd, resume.get(key), oneShot, override, readOnly, bypass, [...allAiProfileDirs(config), dir2]),
|
|
39993
40006
|
stdin: prompt,
|
|
39994
|
-
env: { ...baseEnv, [envVar]: dir2, ...overrideEnv(cmd, override) }
|
|
40007
|
+
env: { ...baseEnv, [envVar]: dir2, ...overrideEnv(cmd, override) },
|
|
40008
|
+
...profile.apiKey ? { apiKey: profile.apiKey } : {}
|
|
39995
40009
|
};
|
|
39996
40010
|
});
|
|
39997
40011
|
return { cmd, attempts };
|
|
@@ -40807,6 +40821,16 @@ async function runClaudeWithFailover(prompt, ai2, imageDir, timeoutMs = ANSWER_T
|
|
|
40807
40821
|
}
|
|
40808
40822
|
throw new Error(`claude ${lastReason}`);
|
|
40809
40823
|
}
|
|
40824
|
+
async function runChecklistAuthor(req, ai2) {
|
|
40825
|
+
try {
|
|
40826
|
+
const { text } = await runClaudeWithFailover(req.prompt, ai2);
|
|
40827
|
+
if (!text) return { error: "empty output" };
|
|
40828
|
+
return { output: text };
|
|
40829
|
+
} catch (err) {
|
|
40830
|
+
logger.warn("checklist.author.failed", { error: String(err) });
|
|
40831
|
+
return { error: String(err) };
|
|
40832
|
+
}
|
|
40833
|
+
}
|
|
40810
40834
|
async function runSupportAnswer(req, ai2, profileDir2) {
|
|
40811
40835
|
let imageDir;
|
|
40812
40836
|
let question = req.question;
|
|
@@ -42211,6 +42235,58 @@ async function runCommand(dispatch, emitRaw, opts) {
|
|
|
42211
42235
|
});
|
|
42212
42236
|
}
|
|
42213
42237
|
|
|
42238
|
+
// src/core/resolve-api-key.ts
|
|
42239
|
+
var cache = /* @__PURE__ */ new Map();
|
|
42240
|
+
async function loadAws(pkg) {
|
|
42241
|
+
const spec = pkg;
|
|
42242
|
+
return await import(spec);
|
|
42243
|
+
}
|
|
42244
|
+
async function fetchSsm(d) {
|
|
42245
|
+
const aws = await loadAws("@aws-sdk/client-ssm");
|
|
42246
|
+
const SSMClient = aws.SSMClient;
|
|
42247
|
+
const GetParameterCommand = aws.GetParameterCommand;
|
|
42248
|
+
const client = new SSMClient(d.region ? { region: d.region } : {});
|
|
42249
|
+
const res = await client.send(new GetParameterCommand({ Name: d.name, WithDecryption: true }));
|
|
42250
|
+
return res.Parameter?.Value?.trim() || null;
|
|
42251
|
+
}
|
|
42252
|
+
async function fetchSecretsManager(d) {
|
|
42253
|
+
const aws = await loadAws("@aws-sdk/client-secrets-manager");
|
|
42254
|
+
const SecretsManagerClient = aws.SecretsManagerClient;
|
|
42255
|
+
const GetSecretValueCommand = aws.GetSecretValueCommand;
|
|
42256
|
+
const client = new SecretsManagerClient(d.region ? { region: d.region } : {});
|
|
42257
|
+
const res = await client.send(new GetSecretValueCommand({ SecretId: d.secretId }));
|
|
42258
|
+
const raw = (res.SecretString ?? "").trim();
|
|
42259
|
+
if (!raw) return null;
|
|
42260
|
+
if (d.jsonKey) {
|
|
42261
|
+
try {
|
|
42262
|
+
const obj = JSON.parse(raw);
|
|
42263
|
+
const v2 = obj[d.jsonKey];
|
|
42264
|
+
return typeof v2 === "string" && v2.trim() ? v2.trim() : null;
|
|
42265
|
+
} catch {
|
|
42266
|
+
return null;
|
|
42267
|
+
}
|
|
42268
|
+
}
|
|
42269
|
+
return raw;
|
|
42270
|
+
}
|
|
42271
|
+
async function resolveApiKey(desc) {
|
|
42272
|
+
if (!desc || !desc.source) return null;
|
|
42273
|
+
if (desc.source === "inline") return desc.value?.trim() || null;
|
|
42274
|
+
const cacheKey = JSON.stringify(desc);
|
|
42275
|
+
const hit = cache.get(cacheKey);
|
|
42276
|
+
if (hit) return hit;
|
|
42277
|
+
try {
|
|
42278
|
+
const val = desc.source === "ssm" ? await fetchSsm(desc) : desc.source === "secretsManager" ? await fetchSecretsManager(desc) : null;
|
|
42279
|
+
if (val) {
|
|
42280
|
+
cache.set(cacheKey, val);
|
|
42281
|
+
return val;
|
|
42282
|
+
}
|
|
42283
|
+
return null;
|
|
42284
|
+
} catch (err) {
|
|
42285
|
+
logger.warn("ai.apiKey.resolve.failed", { source: desc.source, error: String(err) });
|
|
42286
|
+
return null;
|
|
42287
|
+
}
|
|
42288
|
+
}
|
|
42289
|
+
|
|
42214
42290
|
// src/core/ai-runner.ts
|
|
42215
42291
|
var TIMEOUT_EXIT = 124;
|
|
42216
42292
|
function isAuthFailure(text) {
|
|
@@ -42259,7 +42335,9 @@ async function runAiFailover(plan, commandId, cwd2, handlers, timeoutMs = 0, sig
|
|
|
42259
42335
|
handlers.onChunk(text);
|
|
42260
42336
|
}
|
|
42261
42337
|
};
|
|
42262
|
-
|
|
42338
|
+
const resolvedKey = attempt.apiKey ? await resolveApiKey(attempt.apiKey) : null;
|
|
42339
|
+
const attemptEnv = resolvedKey ? { ...attempt.env, ANTHROPIC_API_KEY: resolvedKey } : attempt.env;
|
|
42340
|
+
finalExit = await runAttempt(commandId, attempt.cmd, attempt.args, attempt.stdin, cwd2, attemptEnv, emit, timeoutMs, signal);
|
|
42263
42341
|
const tail = parser.flush();
|
|
42264
42342
|
if (tail) {
|
|
42265
42343
|
captured += tail;
|
|
@@ -45837,6 +45915,28 @@ function handleSupportChannels(ctx, message, payload) {
|
|
|
45837
45915
|
}).finally(() => ctx.bus.endBusy("faq-compose"));
|
|
45838
45916
|
return true;
|
|
45839
45917
|
}
|
|
45918
|
+
case WsChannels.CHECKLIST_AUTHOR: {
|
|
45919
|
+
const creq = payload;
|
|
45920
|
+
const ccfg = readProfileConfig(ctx.profileDir);
|
|
45921
|
+
const ccmd = ccfg.aiCli || "claude";
|
|
45922
|
+
const cai = {
|
|
45923
|
+
cmd: ccmd,
|
|
45924
|
+
profiles: resolveClaudeProfiles(ccfg, getWorkingProfile(ctx.profileDir, ccmd)),
|
|
45925
|
+
env: ccfg.aiEnv
|
|
45926
|
+
};
|
|
45927
|
+
ctx.bus.push({ source: "server", kind: "aireq", text: `${ccmd} \u2039 author checklist items` });
|
|
45928
|
+
ctx.bus.startBusy("checklist-author");
|
|
45929
|
+
void runChecklistAuthor(creq, cai).then((reply) => {
|
|
45930
|
+
if (reply.error) {
|
|
45931
|
+
ctx.bus.push({ source: "server", kind: "log", text: `checklist-author failed: ${reply.error}`, level: "warn" });
|
|
45932
|
+
} else {
|
|
45933
|
+
ctx.bus.push({ source: "server", kind: "aires", text: `${ccmd} \u203A` });
|
|
45934
|
+
}
|
|
45935
|
+
reportToolResult(ccmd, !reply.error, reply.error);
|
|
45936
|
+
ctx.send(WsChannels.CHECKLIST_AUTHOR, reply, message.id);
|
|
45937
|
+
}).finally(() => ctx.bus.endBusy("checklist-author"));
|
|
45938
|
+
return true;
|
|
45939
|
+
}
|
|
45840
45940
|
default:
|
|
45841
45941
|
return false;
|
|
45842
45942
|
}
|
|
@@ -50527,7 +50627,7 @@ function widestLine(string) {
|
|
|
50527
50627
|
}
|
|
50528
50628
|
|
|
50529
50629
|
// ../../node_modules/.pnpm/ink@5.2.1_@types+react@18.3.31_react@18.3.1/node_modules/ink/build/measure-text.js
|
|
50530
|
-
var
|
|
50630
|
+
var cache2 = {};
|
|
50531
50631
|
var measureText = (text) => {
|
|
50532
50632
|
if (text.length === 0) {
|
|
50533
50633
|
return {
|
|
@@ -50535,13 +50635,13 @@ var measureText = (text) => {
|
|
|
50535
50635
|
height: 0
|
|
50536
50636
|
};
|
|
50537
50637
|
}
|
|
50538
|
-
const cachedDimensions =
|
|
50638
|
+
const cachedDimensions = cache2[text];
|
|
50539
50639
|
if (cachedDimensions) {
|
|
50540
50640
|
return cachedDimensions;
|
|
50541
50641
|
}
|
|
50542
50642
|
const width = widestLine(text);
|
|
50543
50643
|
const height = text.split("\n").length;
|
|
50544
|
-
|
|
50644
|
+
cache2[text] = { width, height };
|
|
50545
50645
|
return { width, height };
|
|
50546
50646
|
};
|
|
50547
50647
|
var measure_text_default = measureText;
|
|
@@ -51066,10 +51166,10 @@ function cliTruncate(text, columns, options = {}) {
|
|
|
51066
51166
|
}
|
|
51067
51167
|
|
|
51068
51168
|
// ../../node_modules/.pnpm/ink@5.2.1_@types+react@18.3.31_react@18.3.1/node_modules/ink/build/wrap-text.js
|
|
51069
|
-
var
|
|
51169
|
+
var cache3 = {};
|
|
51070
51170
|
var wrapText = (text, maxWidth, wrapType) => {
|
|
51071
51171
|
const cacheKey = text + String(maxWidth) + String(wrapType);
|
|
51072
|
-
const cachedText =
|
|
51172
|
+
const cachedText = cache3[cacheKey];
|
|
51073
51173
|
if (cachedText) {
|
|
51074
51174
|
return cachedText;
|
|
51075
51175
|
}
|
|
@@ -51090,7 +51190,7 @@ var wrapText = (text, maxWidth, wrapType) => {
|
|
|
51090
51190
|
}
|
|
51091
51191
|
wrappedText = cliTruncate(text, maxWidth, { position });
|
|
51092
51192
|
}
|
|
51093
|
-
|
|
51193
|
+
cache3[cacheKey] = wrappedText;
|
|
51094
51194
|
return wrappedText;
|
|
51095
51195
|
};
|
|
51096
51196
|
var wrap_text_default = wrapText;
|