@4pm/cli 0.8.3 → 0.9.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 +148 -24
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -28276,13 +28276,13 @@ function defaultProfileConfig() {
|
|
|
28276
28276
|
return {
|
|
28277
28277
|
aiCli: "claude",
|
|
28278
28278
|
// Lists so failover across profiles is discoverable (ADR-0057) — add more objects.
|
|
28279
|
-
// `args` are
|
|
28279
|
+
// `args` here are EXTRA args only (empty by default) — the token-metering flags
|
|
28280
|
+
// (claude stream-json / codex `exec --json`) are hardcoded in source and always
|
|
28281
|
+
// injected (ADR-0158, ADR-0072), so they cannot be dropped by editing this file.
|
|
28280
28282
|
// `model` = the CLI's `--model` flag; default "sonnet" — the balanced mid-price tier
|
|
28281
28283
|
// (cheaper than opus, more capable than haiku). "" ⇒ the CLI's own default model.
|
|
28282
|
-
claudeHome: [
|
|
28283
|
-
|
|
28284
|
-
],
|
|
28285
|
-
codexHome: [{ profile: ".codex", args: ["exec"], model: "" }],
|
|
28284
|
+
claudeHome: [{ profile: ".claude", args: [], model: "sonnet" }],
|
|
28285
|
+
codexHome: [{ profile: ".codex", args: [], model: "" }],
|
|
28286
28286
|
antigravityHome: [],
|
|
28287
28287
|
autoUpdate: true,
|
|
28288
28288
|
commandHistoryUploadMinutes: 10,
|
|
@@ -28585,6 +28585,7 @@ async function updateViaDownload(tarballUrl, checksum, signature) {
|
|
|
28585
28585
|
});
|
|
28586
28586
|
}
|
|
28587
28587
|
async function updateToLatest(serverUrl) {
|
|
28588
|
+
if (CLI_VERSION.startsWith("0.0.0")) return { action: "dev-build", version: CLI_VERSION };
|
|
28588
28589
|
const meta = await fetchCliVersion(serverUrl);
|
|
28589
28590
|
if (compareSemver(CLI_VERSION, meta.latest) >= 0) {
|
|
28590
28591
|
return { action: "already-latest", version: CLI_VERSION };
|
|
@@ -28819,7 +28820,10 @@ var PermissionCode = {
|
|
|
28819
28820
|
INTEGRATION_PAGE_WRITE: "integration.page_write",
|
|
28820
28821
|
// community "4rum" news/forum (MEMO) — every role reads/posts (org-scoped)
|
|
28821
28822
|
COMMUNITY_READ: "community.read",
|
|
28822
|
-
COMMUNITY_POST: "community.post"
|
|
28823
|
+
COMMUNITY_POST: "community.post",
|
|
28824
|
+
// support & AI help (ADR-0167/0168) — self-scoped baseline for every role
|
|
28825
|
+
SUPPORT_USE: "support.use",
|
|
28826
|
+
HELP_USE: "help.use"
|
|
28823
28827
|
};
|
|
28824
28828
|
var ALL_PERMISSION_CODES = Object.values(PermissionCode);
|
|
28825
28829
|
var GrantSubjectType = {
|
|
@@ -28838,7 +28842,10 @@ var COMMON = [
|
|
|
28838
28842
|
P.SEARCH_QUERY,
|
|
28839
28843
|
// community 4rum — read + post (org-scoped — MEMO)
|
|
28840
28844
|
P.COMMUNITY_READ,
|
|
28841
|
-
P.COMMUNITY_POST
|
|
28845
|
+
P.COMMUNITY_POST,
|
|
28846
|
+
// file/read own support tickets + ask the AI Help agent (ADR-0167/0168)
|
|
28847
|
+
P.SUPPORT_USE,
|
|
28848
|
+
P.HELP_USE
|
|
28842
28849
|
];
|
|
28843
28850
|
var ROLE_DEFAULT_PERMISSIONS = {
|
|
28844
28851
|
// ADMIN: full permissions
|
|
@@ -33196,7 +33203,10 @@ var registerRequestSchema = external_exports.object({
|
|
|
33196
33203
|
phone: phoneSchema,
|
|
33197
33204
|
ipAllowlist: ipAllowlistSchema.optional(),
|
|
33198
33205
|
planCode: external_exports.string().min(1).max(50).optional(),
|
|
33199
|
-
provider: paymentProviderSchema.optional()
|
|
33206
|
+
provider: paymentProviderSchema.optional(),
|
|
33207
|
+
// One-time token from an SSO "prefill" round-trip (ADR-0161): a verified provider profile
|
|
33208
|
+
// whose email must match `email`; on success the identity is linked to the new account.
|
|
33209
|
+
ssoToken: hexTokenSchema.optional()
|
|
33200
33210
|
});
|
|
33201
33211
|
var mailTokenRequestSchema = external_exports.object({
|
|
33202
33212
|
token: hexTokenSchema
|
|
@@ -33405,6 +33415,7 @@ var updateMemoItemSchema = external_exports.object({
|
|
|
33405
33415
|
}).refine((v) => v.content !== void 0 || v.done !== void 0, {
|
|
33406
33416
|
message: "content or done required"
|
|
33407
33417
|
});
|
|
33418
|
+
var HTTP_JSON_BODY_LIMIT_BYTES = 2 * 1048576;
|
|
33408
33419
|
var putSpecDraftRequestSchema = external_exports.object({
|
|
33409
33420
|
spec: external_exports.record(external_exports.unknown()),
|
|
33410
33421
|
specVersion: external_exports.number().int().positive().optional()
|
|
@@ -33633,7 +33644,16 @@ var COMMAND_MAX_LEN = 8e3;
|
|
|
33633
33644
|
var AI_PROMPT_MAX_LEN = 2e5;
|
|
33634
33645
|
var dispatchCommandRequestSchema = external_exports.object({
|
|
33635
33646
|
projectId: external_exports.string().uuid(),
|
|
33636
|
-
|
|
33647
|
+
// Target cli. Required unless `pick` is set — with `pick:"idle"` the server chooses the
|
|
33648
|
+
// target from the project's pool, so the client omits it (ADR-0171).
|
|
33649
|
+
machineLinkId: external_exports.string().uuid().optional(),
|
|
33650
|
+
/**
|
|
33651
|
+
* Server-side idle-cli pick (ADR-0171): `"idle"` ⇒ omit `machineLinkId` and let the server
|
|
33652
|
+
* select + atomically claim an idle cli from the project's pool (machine-users + org
|
|
33653
|
+
* orchestrator). Used by the wizard's AI ops so parallel suggests spread across the pool
|
|
33654
|
+
* without double-booking a busy cli; no idle cli ⇒ `ALL_CLIS_BUSY`.
|
|
33655
|
+
*/
|
|
33656
|
+
pick: external_exports.enum(["idle"]).optional(),
|
|
33637
33657
|
// In AI mode `command` carries the raw prompt (can be long — the spec-assist prompts
|
|
33638
33658
|
// embed the whole self-describing spec envelope, ADR-0106), else an executable name.
|
|
33639
33659
|
command: external_exports.string().min(1).max(AI_PROMPT_MAX_LEN),
|
|
@@ -33656,6 +33676,13 @@ var dispatchCommandRequestSchema = external_exports.object({
|
|
|
33656
33676
|
*/
|
|
33657
33677
|
gitOp: external_exports.enum(["read", "write"]).optional()
|
|
33658
33678
|
}).superRefine((v, ctx) => {
|
|
33679
|
+
if (v.machineLinkId == null === (v.pick == null)) {
|
|
33680
|
+
ctx.addIssue({
|
|
33681
|
+
code: external_exports.ZodIssueCode.custom,
|
|
33682
|
+
path: ["machineLinkId"],
|
|
33683
|
+
message: "Provide exactly one of machineLinkId or pick."
|
|
33684
|
+
});
|
|
33685
|
+
}
|
|
33659
33686
|
if (!v.ai && v.command.length > COMMAND_MAX_LEN) {
|
|
33660
33687
|
ctx.addIssue({
|
|
33661
33688
|
code: external_exports.ZodIssueCode.too_big,
|
|
@@ -33866,6 +33893,62 @@ var createCommunityPostSchema = external_exports.object({
|
|
|
33866
33893
|
authorName: external_exports.string().max(100).optional()
|
|
33867
33894
|
});
|
|
33868
33895
|
|
|
33896
|
+
// ../../22-packages/11-shared/31-dto/src/support.ts
|
|
33897
|
+
var SUPPORT_CATEGORIES = [
|
|
33898
|
+
"bug",
|
|
33899
|
+
"billing",
|
|
33900
|
+
"how_to",
|
|
33901
|
+
"account",
|
|
33902
|
+
"other"
|
|
33903
|
+
];
|
|
33904
|
+
var SUPPORT_STATUSES = [
|
|
33905
|
+
"open",
|
|
33906
|
+
"in_progress",
|
|
33907
|
+
"resolved",
|
|
33908
|
+
"closed"
|
|
33909
|
+
];
|
|
33910
|
+
var supportContextSchema = external_exports.object({
|
|
33911
|
+
route: external_exports.string().max(512).optional(),
|
|
33912
|
+
orgId: external_exports.string().max(64).optional(),
|
|
33913
|
+
projectId: external_exports.string().max(64).optional(),
|
|
33914
|
+
appVersion: external_exports.string().max(64).optional(),
|
|
33915
|
+
locale: external_exports.string().max(16).optional()
|
|
33916
|
+
}).optional();
|
|
33917
|
+
var createSupportTicketRequestSchema = external_exports.object({
|
|
33918
|
+
category: external_exports.enum(SUPPORT_CATEGORIES),
|
|
33919
|
+
subject: external_exports.string().min(1).max(160),
|
|
33920
|
+
body: external_exports.string().min(1).max(1e4),
|
|
33921
|
+
attachments: external_exports.array(external_exports.string().max(512)).max(10).optional(),
|
|
33922
|
+
context: supportContextSchema
|
|
33923
|
+
});
|
|
33924
|
+
var listSupportTicketsQuerySchema = baseRequestSchema.extend({
|
|
33925
|
+
status: external_exports.enum(SUPPORT_STATUSES).optional(),
|
|
33926
|
+
category: external_exports.enum(SUPPORT_CATEGORIES).optional()
|
|
33927
|
+
});
|
|
33928
|
+
var replySupportTicketRequestSchema = external_exports.object({
|
|
33929
|
+
body: external_exports.string().min(1).max(1e4),
|
|
33930
|
+
attachments: external_exports.array(external_exports.string().max(512)).max(10).optional()
|
|
33931
|
+
});
|
|
33932
|
+
var adminListSupportTicketsQuerySchema = baseRequestSchema.extend({
|
|
33933
|
+
status: external_exports.enum(SUPPORT_STATUSES).optional(),
|
|
33934
|
+
category: external_exports.enum(SUPPORT_CATEGORIES).optional(),
|
|
33935
|
+
orgId: external_exports.string().uuid().optional()
|
|
33936
|
+
});
|
|
33937
|
+
var adminReplySupportTicketRequestSchema = external_exports.object({
|
|
33938
|
+
body: external_exports.string().min(1).max(1e4),
|
|
33939
|
+
status: external_exports.enum(SUPPORT_STATUSES).optional(),
|
|
33940
|
+
assign: external_exports.boolean().optional(),
|
|
33941
|
+
// the acting platform admin's GitHub id (author trace), filled by admin-server.
|
|
33942
|
+
by: external_exports.string().max(64).optional()
|
|
33943
|
+
});
|
|
33944
|
+
|
|
33945
|
+
// ../../22-packages/11-shared/31-dto/src/help.ts
|
|
33946
|
+
var askHelpRequestSchema = external_exports.object({
|
|
33947
|
+
question: external_exports.string().min(1).max(2e3),
|
|
33948
|
+
// continue an existing conversation; omit ⇒ a new thread.
|
|
33949
|
+
threadId: external_exports.string().uuid().optional()
|
|
33950
|
+
});
|
|
33951
|
+
|
|
33869
33952
|
// ../../22-packages/21-protocol/21-websocket/src/channels/index.ts
|
|
33870
33953
|
var WsChannels = {
|
|
33871
33954
|
...WsChannel,
|
|
@@ -34336,18 +34419,11 @@ function assistantText(ev) {
|
|
|
34336
34419
|
}
|
|
34337
34420
|
function createAiStreamParser(cli) {
|
|
34338
34421
|
const isClaude = cli.includes("claude");
|
|
34422
|
+
const isCodex = cli.includes("codex");
|
|
34423
|
+
const isJson = isClaude || isCodex;
|
|
34339
34424
|
let buffer = "";
|
|
34340
34425
|
const acc = { tokens: 0, input: 0, output: 0, cacheRead: 0, cacheCreation: 0 };
|
|
34341
|
-
function
|
|
34342
|
-
const trimmed = line.trim();
|
|
34343
|
-
if (!isClaude || !trimmed.startsWith("{")) return null;
|
|
34344
|
-
let ev;
|
|
34345
|
-
try {
|
|
34346
|
-
ev = JSON.parse(trimmed);
|
|
34347
|
-
} catch {
|
|
34348
|
-
return null;
|
|
34349
|
-
}
|
|
34350
|
-
if (typeof ev.type !== "string") return null;
|
|
34426
|
+
function handleClaude(ev) {
|
|
34351
34427
|
if (ev.type === "result" && ev.usage) {
|
|
34352
34428
|
acc.input = ev.usage.input_tokens ?? 0;
|
|
34353
34429
|
acc.output = ev.usage.output_tokens ?? 0;
|
|
@@ -34364,6 +34440,34 @@ function createAiStreamParser(cli) {
|
|
|
34364
34440
|
}
|
|
34365
34441
|
return "";
|
|
34366
34442
|
}
|
|
34443
|
+
function handleCodex(ev) {
|
|
34444
|
+
if (ev.type === "turn.completed" && ev.usage) {
|
|
34445
|
+
acc.input = ev.usage.input_tokens ?? 0;
|
|
34446
|
+
acc.output = (ev.usage.output_tokens ?? 0) + (ev.usage.reasoning_output_tokens ?? 0);
|
|
34447
|
+
acc.cacheRead = ev.usage.cached_input_tokens ?? 0;
|
|
34448
|
+
acc.cacheCreation = 0;
|
|
34449
|
+
acc.tokens = acc.input + acc.output;
|
|
34450
|
+
return "";
|
|
34451
|
+
}
|
|
34452
|
+
if (ev.type === "item.completed" && ev.item?.type === "agent_message") {
|
|
34453
|
+
const text = ev.item.text;
|
|
34454
|
+
return text ? `${text}
|
|
34455
|
+
` : "";
|
|
34456
|
+
}
|
|
34457
|
+
return "";
|
|
34458
|
+
}
|
|
34459
|
+
function handleLine(line) {
|
|
34460
|
+
const trimmed = line.trim();
|
|
34461
|
+
if (!isJson || !trimmed.startsWith("{")) return null;
|
|
34462
|
+
let ev;
|
|
34463
|
+
try {
|
|
34464
|
+
ev = JSON.parse(trimmed);
|
|
34465
|
+
} catch {
|
|
34466
|
+
return null;
|
|
34467
|
+
}
|
|
34468
|
+
if (typeof ev.type !== "string") return null;
|
|
34469
|
+
return isCodex ? handleCodex(ev) : handleClaude(ev);
|
|
34470
|
+
}
|
|
34367
34471
|
return {
|
|
34368
34472
|
push(raw) {
|
|
34369
34473
|
buffer += raw;
|
|
@@ -34476,10 +34580,16 @@ function setWorkingProfile(profileDir2, cmd, dir2) {
|
|
|
34476
34580
|
import { readFileSync as readFileSync8 } from "fs";
|
|
34477
34581
|
import { homedir as homedir3 } from "os";
|
|
34478
34582
|
import { basename, isAbsolute, join as join8 } from "path";
|
|
34479
|
-
var
|
|
34583
|
+
var REQUIRED_AI_ARGS = {
|
|
34480
34584
|
claude: ["-p", "--output-format", "stream-json", "--verbose"],
|
|
34481
|
-
codex: ["exec"]
|
|
34585
|
+
codex: ["exec", "--json"],
|
|
34586
|
+
antigravity: []
|
|
34482
34587
|
};
|
|
34588
|
+
function requiredArgs(cmd) {
|
|
34589
|
+
if (cmd.includes("claude")) return REQUIRED_AI_ARGS.claude;
|
|
34590
|
+
if (cmd.includes("codex")) return REQUIRED_AI_ARGS.codex;
|
|
34591
|
+
return REQUIRED_AI_ARGS.antigravity;
|
|
34592
|
+
}
|
|
34483
34593
|
var DEFAULT_AI_CLI = "claude";
|
|
34484
34594
|
function resolveHomePath(value) {
|
|
34485
34595
|
if (value.startsWith("~")) return join8(homedir3(), value.slice(1).replace(/^[/\\]/, ""));
|
|
@@ -34491,10 +34601,10 @@ function profileDirs(profiles) {
|
|
|
34491
34601
|
return profiles.map((p) => p.profile).filter((v) => v && v.trim()).map(resolveHomePath);
|
|
34492
34602
|
}
|
|
34493
34603
|
function buildRunArgs(profile, cmd, prompt) {
|
|
34494
|
-
const
|
|
34604
|
+
const extras = profile.args ?? [];
|
|
34495
34605
|
const model = profile.model?.trim();
|
|
34496
34606
|
const modelArgs = model ? ["--model", model] : [];
|
|
34497
|
-
return [...
|
|
34607
|
+
return [...requiredArgs(cmd), ...extras, ...modelArgs, prompt];
|
|
34498
34608
|
}
|
|
34499
34609
|
function claudeHomeDirs(config) {
|
|
34500
34610
|
const dirs = profileDirs(config.claudeHome);
|
|
@@ -44283,17 +44393,31 @@ async function runUnlink(profileDir2, profileName) {
|
|
|
44283
44393
|
}
|
|
44284
44394
|
|
|
44285
44395
|
// src/commands/update.ts
|
|
44396
|
+
function isConnectionError(err) {
|
|
44397
|
+
return err instanceof TypeError && err.message === "fetch failed";
|
|
44398
|
+
}
|
|
44286
44399
|
async function runUpdate(profileDir2, profileName, serverUrlFlag) {
|
|
44287
44400
|
const serverUrl = (serverUrlFlag || readCredential(profileDir2, profileName)?.serverUrl || process.env.FOURPM_SERVER || "http://localhost:42001").replace(/\/$/, "");
|
|
44288
44401
|
let result;
|
|
44289
44402
|
try {
|
|
44290
44403
|
result = await updateToLatest(serverUrl);
|
|
44291
44404
|
} catch (err) {
|
|
44292
|
-
|
|
44405
|
+
if (isConnectionError(err)) {
|
|
44406
|
+
console.error(
|
|
44407
|
+
`Could not reach the server at ${serverUrl} \u2014 is it running? Set the server with \`--server <url>\` or the FOURPM_SERVER env var.`
|
|
44408
|
+
);
|
|
44409
|
+
} else {
|
|
44410
|
+
console.error(`Could not check for updates: ${err}`);
|
|
44411
|
+
}
|
|
44293
44412
|
process.exitCode = 1;
|
|
44294
44413
|
return;
|
|
44295
44414
|
}
|
|
44296
44415
|
switch (result.action) {
|
|
44416
|
+
case "dev-build":
|
|
44417
|
+
console.log(
|
|
44418
|
+
`Running a local dev build (${result.version}) \u2014 update it by rebuilding the repo (\`pnpm --filter @4pm/cli build\`), not \`4pm update\`.`
|
|
44419
|
+
);
|
|
44420
|
+
break;
|
|
44297
44421
|
case "already-latest":
|
|
44298
44422
|
console.log(`Already up to date (${result.version}).`);
|
|
44299
44423
|
break;
|