@cmmd-center/forge 0.9.14 → 0.9.16
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/bin.mjs
CHANGED
|
@@ -22,7 +22,7 @@ import { createCipheriv, createDecipheriv, createHash, createHmac, createPublicK
|
|
|
22
22
|
import * as FS$1 from "node:fs";
|
|
23
23
|
import fs, { accessSync, chmodSync, constants, createReadStream, existsSync, mkdirSync, mkdtempSync, promises, readFile, readFileSync, readdir, readdirSync, realpathSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
24
24
|
import * as NodeOS from "node:os";
|
|
25
|
-
import
|
|
25
|
+
import $U, { homedir, networkInterfaces, tmpdir } from "node:os";
|
|
26
26
|
import * as Path$1 from "node:path";
|
|
27
27
|
import path, { basename, delimiter, dirname, extname, isAbsolute, join, posix, relative, resolve, sep } from "node:path";
|
|
28
28
|
import { pathToFileURL } from "node:url";
|
|
@@ -49482,7 +49482,7 @@ function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
|
|
|
49482
49482
|
const min = forceColor || 0;
|
|
49483
49483
|
if (env.TERM === "dumb") return min;
|
|
49484
49484
|
if (process$1.platform === "win32") {
|
|
49485
|
-
const osRelease =
|
|
49485
|
+
const osRelease = $U.release().split(".");
|
|
49486
49486
|
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
49487
49487
|
return 1;
|
|
49488
49488
|
}
|
|
@@ -51925,7 +51925,7 @@ var require_ProcessDetector = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
51925
51925
|
exports.processDetector = void 0;
|
|
51926
51926
|
const api_1 = (init_esm$1(), __toCommonJS(esm_exports$1));
|
|
51927
51927
|
const semconv_1 = require_semconv$1();
|
|
51928
|
-
const os$
|
|
51928
|
+
const os$3 = __require("os");
|
|
51929
51929
|
/**
|
|
51930
51930
|
* ProcessDetector will be used to detect the resources related current process running
|
|
51931
51931
|
* and being instrumented from the NodeJS Process module.
|
|
@@ -51947,7 +51947,7 @@ var require_ProcessDetector = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
51947
51947
|
};
|
|
51948
51948
|
if (process.argv.length > 1) attributes[semconv_1.ATTR_PROCESS_COMMAND] = process.argv[1];
|
|
51949
51949
|
try {
|
|
51950
|
-
const userInfo = os$
|
|
51950
|
+
const userInfo = os$3.userInfo();
|
|
51951
51951
|
attributes[semconv_1.ATTR_PROCESS_OWNER] = userInfo.username;
|
|
51952
51952
|
} catch (e) {
|
|
51953
51953
|
api_1.diag.debug(`error obtaining process owner: ${e}`);
|
|
@@ -64870,7 +64870,7 @@ function normalizeNumberish(value) {
|
|
|
64870
64870
|
}
|
|
64871
64871
|
//#endregion
|
|
64872
64872
|
//#region package.json
|
|
64873
|
-
var version$1 = "0.9.
|
|
64873
|
+
var version$1 = "0.9.16";
|
|
64874
64874
|
//#endregion
|
|
64875
64875
|
//#region src/sentry.ts
|
|
64876
64876
|
const SERVER_APP_NAME = "forge-server";
|
|
@@ -66692,13 +66692,13 @@ function validateCommandBootstrapPayload(payload) {
|
|
|
66692
66692
|
});
|
|
66693
66693
|
const payloadIdentity = normalizeCmmdUserIdentity(payload.user);
|
|
66694
66694
|
if (payloadIdentity) {
|
|
66695
|
-
const cmmdIdentity = payloadIdentity.avatarUrl ? payloadIdentity : mergeCmmdUserIdentity(payloadIdentity, yield* fetchOptionalCmmdIdentityForAccessToken(payload
|
|
66695
|
+
const cmmdIdentity = payloadIdentity.avatarUrl ? payloadIdentity : mergeCmmdUserIdentity(payloadIdentity, yield* fetchOptionalCmmdIdentityForAccessToken(cmmdUserCredential(payload)));
|
|
66696
66696
|
return {
|
|
66697
66697
|
subjectUserId: cmmdIdentity.id,
|
|
66698
66698
|
cmmdIdentity
|
|
66699
66699
|
};
|
|
66700
66700
|
}
|
|
66701
|
-
const tokenIdentity = yield* fetchCmmdIdentityForAccessToken(payload
|
|
66701
|
+
const tokenIdentity = yield* fetchCmmdIdentityForAccessToken(cmmdUserCredential(payload));
|
|
66702
66702
|
if (tokenIdentity) return {
|
|
66703
66703
|
subjectUserId: tokenIdentity.id,
|
|
66704
66704
|
cmmdIdentity: tokenIdentity
|
|
@@ -66791,6 +66791,23 @@ function isCmmdJwtToken(token) {
|
|
|
66791
66791
|
return token?.startsWith("eyJ") ?? false;
|
|
66792
66792
|
}
|
|
66793
66793
|
/**
|
|
66794
|
+
* The credential CMMD's userinfo accepts.
|
|
66795
|
+
*
|
|
66796
|
+
* Since CMMD's OAuth update, `access_token` is a JWT and the personal access
|
|
66797
|
+
* token arrives separately as `mcp_token`. userinfo authenticates the PAT and
|
|
66798
|
+
* rejects the JWT with `INVALID_OR_NON_USER_TOKEN`, so presenting the JWT
|
|
66799
|
+
* resolves no identity: the bootstrap then finds no subject and answers 401,
|
|
66800
|
+
* even though the sign-in itself succeeded and the caller did nothing wrong.
|
|
66801
|
+
*
|
|
66802
|
+
* `resolveCmmdTokenBundleCredentials` already draws this distinction for the
|
|
66803
|
+
* owner lanes. This is the same rule for the bootstrap lane, which had only ever
|
|
66804
|
+
* seen the pre-update shape where `access_token` was itself the PAT.
|
|
66805
|
+
*/
|
|
66806
|
+
function cmmdUserCredential(payload) {
|
|
66807
|
+
const pat = payload.mcpToken?.trim();
|
|
66808
|
+
return isCmmdJwtToken(payload.accessToken) && pat ? pat : payload.accessToken;
|
|
66809
|
+
}
|
|
66810
|
+
/**
|
|
66794
66811
|
* Read one CMMD token-exchange response into the credential set Forge stores.
|
|
66795
66812
|
*
|
|
66796
66813
|
* Both owner lanes redeem the same `cmmd-forge-web` authorization code — the
|
|
@@ -73483,7 +73500,7 @@ var require_node_gyp_build = /* @__PURE__ */ __commonJSMin(((exports, module) =>
|
|
|
73483
73500
|
var fs$6 = __require("fs");
|
|
73484
73501
|
var path$5 = __require("path");
|
|
73485
73502
|
var url$1 = __require("url");
|
|
73486
|
-
var os$
|
|
73503
|
+
var os$2 = __require("os");
|
|
73487
73504
|
var runtimeRequire = typeof __webpack_require__ === "function" ? __non_webpack_require__ : __require;
|
|
73488
73505
|
var vars = process.config && process.config.variables || {};
|
|
73489
73506
|
var prebuildsOnly = !!process.env.PREBUILDS_ONLY;
|
|
@@ -73491,8 +73508,8 @@ var require_node_gyp_build = /* @__PURE__ */ __commonJSMin(((exports, module) =>
|
|
|
73491
73508
|
var abi = versions.modules;
|
|
73492
73509
|
if (versions.deno || process.isBun) abi = "unsupported";
|
|
73493
73510
|
var runtime = isElectron() ? "electron" : isNwjs() ? "node-webkit" : "node";
|
|
73494
|
-
var arch = process.env.npm_config_arch || os$
|
|
73495
|
-
var platform = process.env.npm_config_platform || os$
|
|
73511
|
+
var arch = process.env.npm_config_arch || os$2.arch();
|
|
73512
|
+
var platform = process.env.npm_config_platform || os$2.platform();
|
|
73496
73513
|
var libc = process.env.LIBC || (isMusl(platform) ? "musl" : "glibc");
|
|
73497
73514
|
var armv = process.env.ARM_VERSION || (arch === "arm64" ? "8" : vars.arm_version) || "";
|
|
73498
73515
|
var uv = (versions.uv || "").split(".")[0];
|
|
@@ -91150,7 +91167,7 @@ const launchDetached = (launch) => gen(function* () {
|
|
|
91150
91167
|
});
|
|
91151
91168
|
const OpenLive = effect(Open, gen(function* () {
|
|
91152
91169
|
const open = yield* tryPromise({
|
|
91153
|
-
try: () => import("./open-
|
|
91170
|
+
try: () => import("./open-D8mGyWmt.mjs"),
|
|
91154
91171
|
catch: (cause) => new OpenError$1({
|
|
91155
91172
|
message: "failed to load browser opener",
|
|
91156
91173
|
cause
|
|
@@ -91947,8 +91964,8 @@ const ProjectionThread = Struct({
|
|
|
91947
91964
|
createdAt: IsoDateTime,
|
|
91948
91965
|
updatedAt: IsoDateTime,
|
|
91949
91966
|
archivedAt: NullOr(IsoDateTime),
|
|
91950
|
-
settledAt:
|
|
91951
|
-
settledOverride:
|
|
91967
|
+
settledAt: NullOr(IsoDateTime),
|
|
91968
|
+
settledOverride: NullOr(Literals(["settled", "active"])),
|
|
91952
91969
|
latestUserMessageAt: NullOr(IsoDateTime),
|
|
91953
91970
|
pendingApprovalCount: NonNegativeInt,
|
|
91954
91971
|
pendingUserInputCount: NonNegativeInt,
|
|
@@ -92133,16 +92150,23 @@ const FORGE_GIT_COMMIT_PATTERN = /^[0-9a-f]{7,40}$/i;
|
|
|
92133
92150
|
/**
|
|
92134
92151
|
* Resolve the commit this forge checkout actually booted from, so the
|
|
92135
92152
|
* heartbeat can report it and CMMD can tell a stale Sprite from a current
|
|
92136
|
-
* one.
|
|
92137
|
-
*
|
|
92138
|
-
*
|
|
92139
|
-
*
|
|
92140
|
-
*
|
|
92141
|
-
*
|
|
92142
|
-
*
|
|
92143
|
-
*
|
|
92144
|
-
*
|
|
92145
|
-
*
|
|
92153
|
+
* one. The commit cannot change for the life of the process, so resolve it
|
|
92154
|
+
* once and cache it.
|
|
92155
|
+
*
|
|
92156
|
+
* This comment used to say Sprites clone forge at bootstrap and read their
|
|
92157
|
+
* commit from that checkout. They do not. A cloud runtime installs the
|
|
92158
|
+
* published `@cmmd-center/forge` tarball and has no `.git` anywhere near it,
|
|
92159
|
+
* which is why its descriptor reported no commit at all until the server
|
|
92160
|
+
* started baking one into its bundle. See `../environment/buildIdentity.ts`,
|
|
92161
|
+
* which calls this only as its last rung.
|
|
92162
|
+
*
|
|
92163
|
+
* `git rev-parse HEAD` run with the process's own cwd walks up to find `.git`
|
|
92164
|
+
* on its own, so no `-C` path is needed. That also means a cwd inside some
|
|
92165
|
+
* unrelated repository answers with that repository's HEAD, which is one more
|
|
92166
|
+
* reason this is the last rung rather than the first. Returns `undefined`
|
|
92167
|
+
* (never throws) when there is no checkout to read, so the heartbeat body
|
|
92168
|
+
* omits the field exactly like an older Forge build that does not know about
|
|
92169
|
+
* it yet.
|
|
92146
92170
|
*/
|
|
92147
92171
|
let cached$1 = null;
|
|
92148
92172
|
async function resolveForgeGitCommit(execImpl = (command, args) => execFileAsync$6(command, [...args], { timeout: 5e3 })) {
|
|
@@ -92509,7 +92533,7 @@ function hasValidRuntimeIdentity(value) {
|
|
|
92509
92533
|
}
|
|
92510
92534
|
function decodeRuntime$1(value) {
|
|
92511
92535
|
if (!isRecord$16(value) || !hasValidRuntimeIdentity(value)) return null;
|
|
92512
|
-
if (!nullableString(value.endpointUrl) || value.endpointUrl !== null && !URL.canParse(value.endpointUrl) || !nullableInteger(value.deviceId) || !
|
|
92536
|
+
if (!nullableString(value.endpointUrl) || value.endpointUrl !== null && !URL.canParse(value.endpointUrl) || !nullableInteger(value.deviceId) || !nullableString(value.workspaceRoot) || !nullableString(value.githubRepoFullName) || !(value.lastSeenAt === null || isIsoDateTime(value.lastSeenAt)) || !(value.metadata === null || isRecord$16(value.metadata))) return null;
|
|
92513
92537
|
return value;
|
|
92514
92538
|
}
|
|
92515
92539
|
function decodeProject(value) {
|
|
@@ -92820,8 +92844,6 @@ function replicaRuntimeMatches(left, right) {
|
|
|
92820
92844
|
[left.status, right.status],
|
|
92821
92845
|
[left.endpointUrl, right.endpointUrl],
|
|
92822
92846
|
[left.deviceId, right.deviceId],
|
|
92823
|
-
[left.projectId, right.projectId],
|
|
92824
|
-
[left.projectName, right.projectName],
|
|
92825
92847
|
[left.workspaceRoot, right.workspaceRoot],
|
|
92826
92848
|
[left.githubRepoFullName, right.githubRepoFullName],
|
|
92827
92849
|
[left.lastSeenAt, right.lastSeenAt]
|
|
@@ -184358,7 +184380,7 @@ var Vce = {
|
|
|
184358
184380
|
function Ve() {
|
|
184359
184381
|
return Vce;
|
|
184360
184382
|
}
|
|
184361
|
-
var Us =
|
|
184383
|
+
var Us = $U.homedir(), lk = $U.tmpdir(), { env: Vc } = process$1, Yce = (e) => {
|
|
184362
184384
|
let t = path.join(Us, "Library");
|
|
184363
184385
|
return {
|
|
184364
184386
|
data: path.join(t, "Application Support", e),
|
|
@@ -194558,12 +194580,12 @@ function qZ(e, t) {
|
|
|
194558
194580
|
}
|
|
194559
194581
|
return n;
|
|
194560
194582
|
}
|
|
194561
|
-
var os$
|
|
194583
|
+
var os$1 = "https://code.claude.com/docs/en", kKe = [
|
|
194562
194584
|
{
|
|
194563
194585
|
matches: (e) => e.path === "permissions.defaultMode" && e.code === "invalid_value",
|
|
194564
194586
|
tip: {
|
|
194565
194587
|
suggestion: "Valid modes: \"acceptEdits\" (ask before file changes), \"plan\" (analysis only), \"bypassPermissions\" (auto-accept all), or \"default\" (standard behavior)",
|
|
194566
|
-
docLink: `${os$
|
|
194588
|
+
docLink: `${os$1}/iam#permission-modes`
|
|
194567
194589
|
}
|
|
194568
194590
|
},
|
|
194569
194591
|
{
|
|
@@ -194578,7 +194600,7 @@ var os$2 = "https://code.claude.com/docs/en", kKe = [
|
|
|
194578
194600
|
matches: (e) => e.path.startsWith("env.") && e.code === "invalid_type",
|
|
194579
194601
|
tip: {
|
|
194580
194602
|
suggestion: "Environment variables must be strings. Wrap numbers and booleans in quotes. Example: \"DEBUG\": \"true\", \"PORT\": \"3000\"",
|
|
194581
|
-
docLink: `${os$
|
|
194603
|
+
docLink: `${os$1}/settings#environment-variables`
|
|
194582
194604
|
}
|
|
194583
194605
|
},
|
|
194584
194606
|
{
|
|
@@ -194589,14 +194611,14 @@ var os$2 = "https://code.claude.com/docs/en", kKe = [
|
|
|
194589
194611
|
matches: (e) => e.path.startsWith("hooks.") && e.code === "invalid_key",
|
|
194590
194612
|
tip: {
|
|
194591
194613
|
suggestion: "Not a recognized hook event. Common events: PreToolUse, PostToolUse, UserPromptSubmit, SessionStart, SessionEnd, Stop. Check spelling and capitalization.",
|
|
194592
|
-
docLink: `${os$
|
|
194614
|
+
docLink: `${os$1}/hooks`
|
|
194593
194615
|
}
|
|
194594
194616
|
},
|
|
194595
194617
|
{
|
|
194596
194618
|
matches: (e) => /\.hooks\.\d+\.command$/.test(e.path) && e.code === "invalid_type" && e.received === "undefined",
|
|
194597
194619
|
tip: {
|
|
194598
194620
|
suggestion: "Command hooks require `command`. For exec form (no shell), set `command` to the executable and `args` to its arguments: {\"type\": \"command\", \"command\": \"echo\", \"args\": [\"hi\"]}. For shell form, set `command` to the full shell string: {\"type\": \"command\", \"command\": \"echo hi\"}.",
|
|
194599
|
-
docLink: `${os$
|
|
194621
|
+
docLink: `${os$1}/hooks#exec-form-and-shell-form`
|
|
194600
194622
|
}
|
|
194601
194623
|
},
|
|
194602
194624
|
{
|
|
@@ -194611,7 +194633,7 @@ var os$2 = "https://code.claude.com/docs/en", kKe = [
|
|
|
194611
194633
|
matches: (e) => e.code === "unrecognized_keys",
|
|
194612
194634
|
tip: {
|
|
194613
194635
|
suggestion: "Check for typos or refer to the documentation for valid fields",
|
|
194614
|
-
docLink: `${os$
|
|
194636
|
+
docLink: `${os$1}/settings`
|
|
194615
194637
|
}
|
|
194616
194638
|
},
|
|
194617
194639
|
{
|
|
@@ -194626,13 +194648,13 @@ var os$2 = "https://code.claude.com/docs/en", kKe = [
|
|
|
194626
194648
|
matches: (e) => e.path === "permissions.additionalDirectories" && e.code === "invalid_type",
|
|
194627
194649
|
tip: {
|
|
194628
194650
|
suggestion: "Must be an array of directory paths. Example: [\"~/projects\", \"/tmp/workspace\"]. You can also use --add-dir flag or /add-dir command",
|
|
194629
|
-
docLink: `${os$
|
|
194651
|
+
docLink: `${os$1}/iam#working-directories`
|
|
194630
194652
|
}
|
|
194631
194653
|
}
|
|
194632
194654
|
], AKe = {
|
|
194633
|
-
permissions: `${os$
|
|
194634
|
-
env: `${os$
|
|
194635
|
-
hooks: `${os$
|
|
194655
|
+
permissions: `${os$1}/iam#configuring-permissions`,
|
|
194656
|
+
env: `${os$1}/settings#environment-variables`,
|
|
194657
|
+
hooks: `${os$1}/hooks`
|
|
194636
194658
|
};
|
|
194637
194659
|
function GZ(e) {
|
|
194638
194660
|
let t = kKe.find((r) => r.matches(e));
|
|
@@ -206237,7 +206259,7 @@ function createDevServerMcpServer(deps, threadId) {
|
|
|
206237
206259
|
* per provider — this module only adapts descriptor + result shapes.
|
|
206238
206260
|
*
|
|
206239
206261
|
* Without it a Claude agent has no brokered push path at all and falls back to
|
|
206240
|
-
* raw `git`, which
|
|
206262
|
+
* raw `git`, which has no authenticated remote credentials in the agent runtime.
|
|
206241
206263
|
*
|
|
206242
206264
|
* The catalog is filtered through `applyPluginSkillPermissionsToDynamicTools`,
|
|
206243
206265
|
* exactly as the Codex surface filters its dynamic tools. `settings` is required
|
|
@@ -258885,7 +258907,7 @@ var import_multicast_dns = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMi
|
|
|
258885
258907
|
var dgram = __require("dgram");
|
|
258886
258908
|
var thunky = require_thunky();
|
|
258887
258909
|
var events = __require("events");
|
|
258888
|
-
var os
|
|
258910
|
+
var os = __require("os");
|
|
258889
258911
|
var noop = function() {};
|
|
258890
258912
|
module.exports = function(opts) {
|
|
258891
258913
|
if (!opts) opts = {};
|
|
@@ -259016,14 +259038,14 @@ var import_multicast_dns = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMi
|
|
|
259016
259038
|
return that;
|
|
259017
259039
|
};
|
|
259018
259040
|
function defaultInterface() {
|
|
259019
|
-
var networks = os
|
|
259041
|
+
var networks = os.networkInterfaces();
|
|
259020
259042
|
var names = Object.keys(networks);
|
|
259021
259043
|
for (var i = 0; i < names.length; i++) {
|
|
259022
259044
|
var net = networks[names[i]];
|
|
259023
259045
|
for (var j = 0; j < net.length; j++) {
|
|
259024
259046
|
var iface = net[j];
|
|
259025
259047
|
if (isIPv4(iface.family) && !iface.internal) {
|
|
259026
|
-
if (os
|
|
259048
|
+
if (os.platform() === "darwin" && names[i] === "en0") return iface.address;
|
|
259027
259049
|
return "0.0.0.0";
|
|
259028
259050
|
}
|
|
259029
259051
|
}
|
|
@@ -259031,7 +259053,7 @@ var import_multicast_dns = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMi
|
|
|
259031
259053
|
return "127.0.0.1";
|
|
259032
259054
|
}
|
|
259033
259055
|
function allInterfaces() {
|
|
259034
|
-
var networks = os
|
|
259056
|
+
var networks = os.networkInterfaces();
|
|
259035
259057
|
var names = Object.keys(networks);
|
|
259036
259058
|
var res = [];
|
|
259037
259059
|
for (var i = 0; i < names.length; i++) {
|
|
@@ -287313,13 +287335,32 @@ const ObservabilityLive = unwrap(gen(function* () {
|
|
|
287313
287335
|
//#region ../../packages/shared/src/buildCommit.ts
|
|
287314
287336
|
const COMMIT_SHA_PATTERN$1 = /^[0-9a-f]{40}$/i;
|
|
287315
287337
|
/**
|
|
287338
|
+
* Whether a value is a full commit sha.
|
|
287339
|
+
*
|
|
287340
|
+
* Exported so each surface can keep its own list of env names while sharing one
|
|
287341
|
+
* definition of "valid". Surfaces genuinely differ: Railway injects
|
|
287342
|
+
* RAILWAY_GIT_COMMIT_SHA into the cloud shell build, while the desktop release
|
|
287343
|
+
* workflows pass VITE_SENTRY_COMMIT_SHA. What must not differ is the check.
|
|
287344
|
+
*/
|
|
287345
|
+
function isFullCommitSha(value) {
|
|
287346
|
+
const candidate = value?.trim();
|
|
287347
|
+
return candidate !== void 0 && candidate !== "" && COMMIT_SHA_PATTERN$1.test(candidate);
|
|
287348
|
+
}
|
|
287349
|
+
/**
|
|
287316
287350
|
* Build identity from the environment.
|
|
287317
287351
|
*
|
|
287318
287352
|
* `.dockerignore` excludes `.git`, so `git rev-parse HEAD` cannot resolve inside
|
|
287319
287353
|
* the Railway container — the surface where "which commit is live?" is asked
|
|
287320
287354
|
* most. The commit therefore has to arrive as env there, with git left as the
|
|
287321
|
-
* fallback for surfaces that genuinely are checkouts (
|
|
287322
|
-
*
|
|
287355
|
+
* fallback for surfaces that genuinely are checkouts (desktop and dev run from
|
|
287356
|
+
* a repo).
|
|
287357
|
+
*
|
|
287358
|
+
* A cloud runtime is neither: it installs the published `@cmmd-center/forge`
|
|
287359
|
+
* tarball, so it has no build variables and no `.git`, and both rungs below
|
|
287360
|
+
* return nothing there. That is why the server bakes the commit into its bundle
|
|
287361
|
+
* at build time and reads that first — see `apps/server/src/environment/
|
|
287362
|
+
* buildIdentity.ts`. This comment previously claimed a sprite clones forge at
|
|
287363
|
+
* bootstrap; it does not, and believing it cost a diagnosis.
|
|
287323
287364
|
*
|
|
287324
287365
|
* `RAILWAY_GIT_COMMIT_SHA` is injected by the platform, which is what lets this
|
|
287325
287366
|
* work on the cloud shell with no Dockerfile plumbing. `FORGE_BUILD_COMMIT`
|
|
@@ -287337,6 +287378,30 @@ function resolveBuildCommitFromEnv(env) {
|
|
|
287337
287378
|
}
|
|
287338
287379
|
}
|
|
287339
287380
|
//#endregion
|
|
287381
|
+
//#region src/environment/buildIdentity.ts
|
|
287382
|
+
/**
|
|
287383
|
+
* Which commit this server was built from.
|
|
287384
|
+
*
|
|
287385
|
+
* @module
|
|
287386
|
+
*/
|
|
287387
|
+
/**
|
|
287388
|
+
* The commit baked into this bundle, if it is a bundle at all.
|
|
287389
|
+
*
|
|
287390
|
+
* `typeof` rather than a bare reference: running from source there is no such
|
|
287391
|
+
* binding, and a bare reference is a ReferenceError that would take the whole
|
|
287392
|
+
* environment descriptor down instead of reporting an honest "unknown".
|
|
287393
|
+
*/
|
|
287394
|
+
function readBakedBuildCommit() {
|
|
287395
|
+
return "e65edd4d1b8a361863a52b171b5e73295d691e11";
|
|
287396
|
+
}
|
|
287397
|
+
async function resolveServerBuildCommit(input) {
|
|
287398
|
+
if (isFullCommitSha(input.baked)) return input.baked;
|
|
287399
|
+
const fromEnv = resolveBuildCommitFromEnv(input.env);
|
|
287400
|
+
if (fromEnv !== void 0) return fromEnv;
|
|
287401
|
+
const fromGit = await input.readGitCommit();
|
|
287402
|
+
return isFullCommitSha(fromGit) ? fromGit : void 0;
|
|
287403
|
+
}
|
|
287404
|
+
//#endregion
|
|
287340
287405
|
//#region src/environment/Layers/ServerEnvironmentLabel.ts
|
|
287341
287406
|
function normalizeLabel(value) {
|
|
287342
287407
|
const trimmed = value?.trim();
|
|
@@ -287484,7 +287549,11 @@ const ServerEnvironmentLive = effect(ServerEnvironment, fn$1("makeServerEnvironm
|
|
|
287484
287549
|
const writeMetadata = (metadata) => fileSystem.writeFileString(serverConfig.environmentMetadataPath, `${JSON.stringify(metadata, null, 2)}\n`);
|
|
287485
287550
|
const displayNameOverrideRef = yield* make$47(normalizeDisplayName((yield* readMetadata).displayName ?? null));
|
|
287486
287551
|
const posthog = yield* PosthogPublicConfig.asEffect();
|
|
287487
|
-
const buildCommit =
|
|
287552
|
+
const buildCommit = yield* promise(() => resolveServerBuildCommit({
|
|
287553
|
+
baked: readBakedBuildCommit(),
|
|
287554
|
+
env: process.env,
|
|
287555
|
+
readGitCommit: resolveForgeGitCommit
|
|
287556
|
+
}));
|
|
287488
287557
|
const buildDescriptor = gen(function* () {
|
|
287489
287558
|
const displayNameOverride = yield* get$5(displayNameOverrideRef);
|
|
287490
287559
|
const os = platformOs();
|
|
@@ -296228,6 +296297,71 @@ function selectProviderUsageEnvironment(rawCatalog, ownerUserId) {
|
|
|
296228
296297
|
};
|
|
296229
296298
|
}
|
|
296230
296299
|
//#endregion
|
|
296300
|
+
//#region src/command/claudeUsageRefreshFailure.ts
|
|
296301
|
+
/**
|
|
296302
|
+
* Why a Claude usage refresh failed, in words the Usage page can show.
|
|
296303
|
+
*
|
|
296304
|
+
* CMMD answers a failed refresh with a machine reason (`runtime_not_active`,
|
|
296305
|
+
* `credential_changed`, …). The Shell used to collapse every one of them into
|
|
296306
|
+
* "Claude usage refresh is unavailable.", so the card could only say the
|
|
296307
|
+
* refresh failed, never what to do about it.
|
|
296308
|
+
*
|
|
296309
|
+
* The mapping is a closed allowlist in both directions: a reason CMMD may add
|
|
296310
|
+
* later falls back to the generic code, and the text a client sees is written
|
|
296311
|
+
* here, never forwarded from upstream. That keeps a credential or runtime
|
|
296312
|
+
* detail in a CMMD error body from reaching the browser.
|
|
296313
|
+
*/
|
|
296314
|
+
const FAILURE_TEXT = {
|
|
296315
|
+
CLAUDE_USAGE_ENVIRONMENT_UNAVAILABLE: "Refresh needs your Environment running.",
|
|
296316
|
+
CLAUDE_USAGE_CREDENTIAL_NOT_READY: "The Claude credential is not applied to your Environment yet.",
|
|
296317
|
+
CLAUDE_USAGE_REFRESH_IN_PROGRESS: "A refresh for this account is already running.",
|
|
296318
|
+
CLAUDE_USAGE_PROBE_FAILED: "Your Environment could not read Claude usage.",
|
|
296319
|
+
CLAUDE_USAGE_RECONNECT_REQUIRED: "Reconnect this Claude account to refresh usage.",
|
|
296320
|
+
CLAUDE_USAGE_ACCOUNT_NOT_FOUND: "This Claude account is no longer connected.",
|
|
296321
|
+
CLAUDE_USAGE_REFRESH_UNAVAILABLE: "Claude usage refresh is unavailable."
|
|
296322
|
+
};
|
|
296323
|
+
/** Verbatim from CMMD `personal-claude-usage.ts` and `provider-usage-service.ts`. */
|
|
296324
|
+
const CODE_BY_UPSTREAM_REASON = {
|
|
296325
|
+
runtime_not_active: "CLAUDE_USAGE_ENVIRONMENT_UNAVAILABLE",
|
|
296326
|
+
claude_native_delivery_disabled: "CLAUDE_USAGE_ENVIRONMENT_UNAVAILABLE",
|
|
296327
|
+
runtime_identity_mismatch: "CLAUDE_USAGE_ENVIRONMENT_UNAVAILABLE",
|
|
296328
|
+
credential_generation_not_applied: "CLAUDE_USAGE_CREDENTIAL_NOT_READY",
|
|
296329
|
+
credential_generation_unavailable: "CLAUDE_USAGE_CREDENTIAL_NOT_READY",
|
|
296330
|
+
credential_changed: "CLAUDE_USAGE_CREDENTIAL_NOT_READY",
|
|
296331
|
+
refresh_in_progress: "CLAUDE_USAGE_REFRESH_IN_PROGRESS",
|
|
296332
|
+
usage_probe_failed: "CLAUDE_USAGE_PROBE_FAILED",
|
|
296333
|
+
usage_receipt_invalid: "CLAUDE_USAGE_PROBE_FAILED",
|
|
296334
|
+
usage_output_invalid: "CLAUDE_USAGE_PROBE_FAILED"
|
|
296335
|
+
};
|
|
296336
|
+
function failure(code, status) {
|
|
296337
|
+
return {
|
|
296338
|
+
status,
|
|
296339
|
+
body: {
|
|
296340
|
+
error: FAILURE_TEXT[code],
|
|
296341
|
+
code
|
|
296342
|
+
}
|
|
296343
|
+
};
|
|
296344
|
+
}
|
|
296345
|
+
/**
|
|
296346
|
+
* CMMD sends the reason as `{ "error": "<reason>" }`. Anything else, including
|
|
296347
|
+
* a longer sentence that happens to start with an allowlisted word, is treated
|
|
296348
|
+
* as unknown.
|
|
296349
|
+
*/
|
|
296350
|
+
function readAllowlistedReasonCode(body) {
|
|
296351
|
+
if (body === null || typeof body !== "object") return null;
|
|
296352
|
+
const reason = body.error;
|
|
296353
|
+
if (typeof reason !== "string") return null;
|
|
296354
|
+
return Object.hasOwn(CODE_BY_UPSTREAM_REASON, reason) ? CODE_BY_UPSTREAM_REASON[reason] ?? null : null;
|
|
296355
|
+
}
|
|
296356
|
+
function describeClaudeUsageRefreshFailure(error) {
|
|
296357
|
+
if (!(error instanceof CmmdProxyRequestError)) return failure("CLAUDE_USAGE_REFRESH_UNAVAILABLE", 502);
|
|
296358
|
+
if (error.status === 409) return failure("CLAUDE_USAGE_RECONNECT_REQUIRED", 409);
|
|
296359
|
+
if (error.status === 404) return failure("CLAUDE_USAGE_ACCOUNT_NOT_FOUND", 404);
|
|
296360
|
+
const reasonCode = readAllowlistedReasonCode(error.body);
|
|
296361
|
+
if (reasonCode !== null) return failure(reasonCode, 503);
|
|
296362
|
+
return failure("CLAUDE_USAGE_REFRESH_UNAVAILABLE", error.status === 503 ? 503 : 502);
|
|
296363
|
+
}
|
|
296364
|
+
//#endregion
|
|
296231
296365
|
//#region src/command/wsToken.ts
|
|
296232
296366
|
/**
|
|
296233
296367
|
* Build the WS token response given an optional PAT and the configured CMMD
|
|
@@ -297964,10 +298098,8 @@ function resolveProviderUsageOwnerUserId(session) {
|
|
|
297964
298098
|
return Number.isSafeInteger(userId) && userId > 0 ? userId : null;
|
|
297965
298099
|
}
|
|
297966
298100
|
function buildClaudeUsageRefreshErrorResponse(error) {
|
|
297967
|
-
|
|
297968
|
-
|
|
297969
|
-
code: "CLAUDE_USAGE_REFRESH_UNAVAILABLE"
|
|
297970
|
-
}, { status: error instanceof CmmdProxyRequestError && error.status === 503 ? 503 : 502 });
|
|
298101
|
+
const failure = describeClaudeUsageRefreshFailure(error);
|
|
298102
|
+
return jsonUnsafe(failure.body, { status: failure.status });
|
|
297971
298103
|
}
|
|
297972
298104
|
function makeRefreshProviderUsageHandler(dependencies = {}) {
|
|
297973
298105
|
return gen(function* () {
|
|
@@ -310411,7 +310543,7 @@ const connectLoginCommand = make$32("login", {
|
|
|
310411
310543
|
})).json();
|
|
310412
310544
|
},
|
|
310413
310545
|
openBrowser: async (url) => {
|
|
310414
|
-
const open = (await import("./open-
|
|
310546
|
+
const open = (await import("./open-D8mGyWmt.mjs")).default;
|
|
310415
310547
|
await open(url);
|
|
310416
310548
|
return true;
|
|
310417
310549
|
},
|