@cmmd-center/forge 0.13.16 → 0.13.18
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.cjs +40 -724
- package/dist/bin.mjs +10 -694
- package/dist/client/assets/{CanvasPanel-RpD9Eh_S.js → CanvasPanel-uofZ5KUR.js} +2 -2
- package/dist/client/assets/{CompositeItem-DEIBUHJR.js → CompositeItem-C5YSRi5B.js} +2 -2
- package/dist/client/assets/{DiffPanel-DI782ZMI.js → DiffPanel-DKupDrOL.js} +2 -2
- package/dist/client/assets/{DiffPanel.logic-DtVm1IjE.js → DiffPanel.logic-C7gTWSq9.js} +2 -2
- package/dist/client/assets/{DiffPanelShell-IB1GWoYr.js → DiffPanelShell-DCsvZHj8.js} +6 -6
- package/dist/client/assets/{DiffWorkerPoolProvider-DDMgJC0H.js → DiffWorkerPoolProvider-DJ_pp0NU.js} +2 -2
- package/dist/client/assets/{PullRequestCodePanel-DPwb2trb.js → PullRequestCodePanel-D3hf_E_a.js} +2 -2
- package/dist/client/assets/{Virtualizer-CU-TBcmx.js → Virtualizer-CWyTqi1E.js} +2 -2
- package/dist/client/assets/{canvasStateStore-NrAxDqvM.js → canvasStateStore-IBP3QM_C.js} +2 -2
- package/dist/client/assets/{cmmdAuthRedirect-BahlX0gF.js → cmmdAuthRedirect-Ck1QfYaS.js} +2 -2
- package/dist/client/assets/index-EZbGVDT4.css +1 -0
- package/dist/client/assets/index-rebrBYd5.js +153 -0
- package/dist/client/assets/{popover-Z8Tvl-OD.js → popover-BQaoSlk7.js} +2 -2
- package/dist/client/assets/{src-BU7yHzO9.js → src-Bj8vTcnP.js} +2 -2
- package/dist/client/assets/{toggle-CWYdWYBn.js → toggle-CE2NHkQL.js} +2 -2
- package/dist/client/index.html +11 -11
- package/dist/forge-build.json +1 -1
- package/package.json +1 -1
- package/dist/client/assets/index-B9000khV.css +0 -1
- package/dist/client/assets/index-CB-vPC0y.js +0 -153
package/dist/bin.mjs
CHANGED
|
@@ -25521,160 +25521,6 @@ const WorkspaceEnsureScratchResult = Struct({
|
|
|
25521
25521
|
workspaceRoot: String$1,
|
|
25522
25522
|
title: String$1
|
|
25523
25523
|
});
|
|
25524
|
-
const CodeGraphRelation = Literals([
|
|
25525
|
-
"contains",
|
|
25526
|
-
"imports",
|
|
25527
|
-
"calls",
|
|
25528
|
-
"imports_from",
|
|
25529
|
-
"method",
|
|
25530
|
-
"references",
|
|
25531
|
-
"re_exports",
|
|
25532
|
-
"indirect_call",
|
|
25533
|
-
"dynamic_import",
|
|
25534
|
-
"inherits",
|
|
25535
|
-
"rationale_for",
|
|
25536
|
-
"implements",
|
|
25537
|
-
"cites",
|
|
25538
|
-
"triggers"
|
|
25539
|
-
]);
|
|
25540
|
-
const CodeGraphConfidence = Literals(["EXTRACTED", "INFERRED"]);
|
|
25541
|
-
const CodeGraphEdgeClass = Literals([
|
|
25542
|
-
"containment",
|
|
25543
|
-
"dependency",
|
|
25544
|
-
"behavior"
|
|
25545
|
-
]);
|
|
25546
|
-
/**
|
|
25547
|
-
* Relation to drawn class. Exhaustive over CODE_GRAPH_RELATIONS by construction
|
|
25548
|
-
* — `codeGraph.test.ts` fails if a relation is added without a class.
|
|
25549
|
-
*/
|
|
25550
|
-
const CODE_GRAPH_RELATION_CLASS = {
|
|
25551
|
-
contains: "containment",
|
|
25552
|
-
method: "containment",
|
|
25553
|
-
imports: "dependency",
|
|
25554
|
-
imports_from: "dependency",
|
|
25555
|
-
re_exports: "dependency",
|
|
25556
|
-
dynamic_import: "dependency",
|
|
25557
|
-
inherits: "dependency",
|
|
25558
|
-
implements: "dependency",
|
|
25559
|
-
calls: "behavior",
|
|
25560
|
-
indirect_call: "behavior",
|
|
25561
|
-
references: "behavior",
|
|
25562
|
-
triggers: "behavior",
|
|
25563
|
-
cites: "behavior",
|
|
25564
|
-
rationale_for: "behavior"
|
|
25565
|
-
};
|
|
25566
|
-
const CodeGraphNodeKind = Literals(["file", "symbol"]);
|
|
25567
|
-
/**
|
|
25568
|
-
* One community, positioned.
|
|
25569
|
-
*
|
|
25570
|
-
* Positions are computed server-side and are stable for a given graph build, so
|
|
25571
|
-
* the map does not rearrange itself between openings. A map you have to re-learn
|
|
25572
|
-
* every time is not a map.
|
|
25573
|
-
*/
|
|
25574
|
-
const CodeGraphRegion = Struct({
|
|
25575
|
-
id: NonNegativeInt,
|
|
25576
|
-
label: TrimmedNonEmptyString,
|
|
25577
|
-
nodeCount: PositiveInt,
|
|
25578
|
-
x: Number$1,
|
|
25579
|
-
y: Number$1
|
|
25580
|
-
});
|
|
25581
|
-
/** An aggregated edge between two regions, weighted by how many edges cross. */
|
|
25582
|
-
const CodeGraphRegionLink = Struct({
|
|
25583
|
-
source: NonNegativeInt,
|
|
25584
|
-
target: NonNegativeInt,
|
|
25585
|
-
weight: PositiveInt
|
|
25586
|
-
});
|
|
25587
|
-
/**
|
|
25588
|
-
* The default view: the whole repository as ~120 named regions.
|
|
25589
|
-
*
|
|
25590
|
-
* `truncatedRegions` is not decoration. When a graph has more regions than the
|
|
25591
|
-
* map shows, the surface says so — a view that silently drops a third of the
|
|
25592
|
-
* codebase while looking complete is the failure mode this field exists to
|
|
25593
|
-
* prevent.
|
|
25594
|
-
*/
|
|
25595
|
-
const CodeGraphSummary = Struct({
|
|
25596
|
-
repoLabel: TrimmedNonEmptyString,
|
|
25597
|
-
builtAtCommit: NullOr(String$1),
|
|
25598
|
-
nodeCount: NonNegativeInt,
|
|
25599
|
-
edgeCount: NonNegativeInt,
|
|
25600
|
-
extractedEdgeCount: NonNegativeInt,
|
|
25601
|
-
inferredEdgeCount: NonNegativeInt,
|
|
25602
|
-
regionCount: NonNegativeInt,
|
|
25603
|
-
regions: ArraySchema(CodeGraphRegion),
|
|
25604
|
-
links: ArraySchema(CodeGraphRegionLink),
|
|
25605
|
-
truncatedRegions: NonNegativeInt
|
|
25606
|
-
});
|
|
25607
|
-
/** A node as it appears in a list, a search result, or a neighborhood. */
|
|
25608
|
-
const CodeGraphNodeSummary = Struct({
|
|
25609
|
-
id: TrimmedNonEmptyString,
|
|
25610
|
-
label: TrimmedNonEmptyString,
|
|
25611
|
-
kind: CodeGraphNodeKind,
|
|
25612
|
-
sourceFile: NullOr(String$1),
|
|
25613
|
-
sourceLocation: NullOr(String$1),
|
|
25614
|
-
regionId: NullOr(NonNegativeInt),
|
|
25615
|
-
regionLabel: NullOr(String$1),
|
|
25616
|
-
degree: NonNegativeInt
|
|
25617
|
-
});
|
|
25618
|
-
/** One edge, carrying both the exact relation and the class it is drawn as. */
|
|
25619
|
-
const CodeGraphEdgeView = Struct({
|
|
25620
|
-
source: TrimmedNonEmptyString,
|
|
25621
|
-
target: TrimmedNonEmptyString,
|
|
25622
|
-
relation: CodeGraphRelation,
|
|
25623
|
-
edgeClass: CodeGraphEdgeClass,
|
|
25624
|
-
confidence: CodeGraphConfidence,
|
|
25625
|
-
confidenceScore: Number$1
|
|
25626
|
-
});
|
|
25627
|
-
/**
|
|
25628
|
-
* One node and what surrounds it — the view a person actually works in.
|
|
25629
|
-
*
|
|
25630
|
-
* `truncated` fires when a hub's fan-out exceeds the cap. A god node with
|
|
25631
|
-
* thousands of edges must degrade to "showing 150 of 2,310", never to a frozen
|
|
25632
|
-
* tab or a quietly partial picture.
|
|
25633
|
-
*/
|
|
25634
|
-
const CodeGraphNeighborhood = Struct({
|
|
25635
|
-
root: CodeGraphNodeSummary,
|
|
25636
|
-
nodes: ArraySchema(CodeGraphNodeSummary),
|
|
25637
|
-
edges: ArraySchema(CodeGraphEdgeView),
|
|
25638
|
-
depth: PositiveInt,
|
|
25639
|
-
truncated: Boolean$1,
|
|
25640
|
-
omittedCount: NonNegativeInt
|
|
25641
|
-
});
|
|
25642
|
-
const CodeGraphSearchResult = Struct({
|
|
25643
|
-
nodes: ArraySchema(CodeGraphNodeSummary),
|
|
25644
|
-
truncated: Boolean$1
|
|
25645
|
-
});
|
|
25646
|
-
const CodeGraphSummaryInput = Struct({ cwd: TrimmedNonEmptyString });
|
|
25647
|
-
const CodeGraphNeighborhoodInput = Struct({
|
|
25648
|
-
cwd: TrimmedNonEmptyString,
|
|
25649
|
-
nodeId: TrimmedNonEmptyString,
|
|
25650
|
-
depth: optional$4(PositiveInt)
|
|
25651
|
-
});
|
|
25652
|
-
const CodeGraphSearchInput = Struct({
|
|
25653
|
-
cwd: TrimmedNonEmptyString,
|
|
25654
|
-
query: TrimmedNonEmptyString,
|
|
25655
|
-
limit: optional$4(PositiveInt)
|
|
25656
|
-
});
|
|
25657
|
-
/** Where the extractor writes, relative to the project root. */
|
|
25658
|
-
const CODE_GRAPH_ARTIFACT_PATH = "graphify-out/graph.json";
|
|
25659
|
-
/**
|
|
25660
|
-
* No graph in this checkout, or one that cannot be read.
|
|
25661
|
-
*
|
|
25662
|
-
* Distinct from a read failure on purpose: "not indexed yet" is the normal
|
|
25663
|
-
* first-run state and gets an action, while a malformed or unreadable artifact
|
|
25664
|
-
* is a fault and gets an explanation. Collapsing them would tell a user with a
|
|
25665
|
-
* corrupt file to run a build they have already run.
|
|
25666
|
-
*/
|
|
25667
|
-
var CodeGraphUnavailableError = class extends TaggedErrorClass()("CodeGraphUnavailableError", {
|
|
25668
|
-
reason: Literals([
|
|
25669
|
-
"missing",
|
|
25670
|
-
"unreadable",
|
|
25671
|
-
"malformed",
|
|
25672
|
-
"lfs-pointer"
|
|
25673
|
-
]),
|
|
25674
|
-
message: String$1
|
|
25675
|
-
}) {};
|
|
25676
|
-
/** A node id that is not in this graph — usually a stale link into a rebuilt graph. */
|
|
25677
|
-
var CodeGraphNodeNotFoundError = class extends TaggedErrorClass()("CodeGraphNodeNotFoundError", { nodeId: String$1 }) {};
|
|
25678
25524
|
//#endregion
|
|
25679
25525
|
//#region ../../packages/contracts/src/relay.ts
|
|
25680
25526
|
const RELAY_PROTOCOL_FAMILY = "forge-relay";
|
|
@@ -26055,9 +25901,6 @@ const WS_METHODS = {
|
|
|
26055
25901
|
projectsWriteFile: "projects.writeFile",
|
|
26056
25902
|
projectCheckoutDeletionPreview: "projectCheckoutDeletion.preview",
|
|
26057
25903
|
projectCheckoutDeletionExecute: "projectCheckoutDeletion.execute",
|
|
26058
|
-
codeGraphSummary: "codeGraph.summary",
|
|
26059
|
-
codeGraphNeighborhood: "codeGraph.neighborhood",
|
|
26060
|
-
codeGraphSearch: "codeGraph.search",
|
|
26061
25904
|
workspaceReadFile: "workspace.readFile",
|
|
26062
25905
|
workspaceBeginWriteFile: "workspace.beginWriteFile",
|
|
26063
25906
|
workspaceWriteFileChunk: "workspace.writeFileChunk",
|
|
@@ -26343,21 +26186,6 @@ const WsProjectCheckoutDeletionExecuteRpc = make$30(WS_METHODS.projectCheckoutDe
|
|
|
26343
26186
|
payload: ProjectCheckoutDeletionExecuteInput,
|
|
26344
26187
|
success: ProjectCheckoutDeletionResult
|
|
26345
26188
|
});
|
|
26346
|
-
const WsCodeGraphSummaryRpc = make$30(WS_METHODS.codeGraphSummary, {
|
|
26347
|
-
payload: CodeGraphSummaryInput,
|
|
26348
|
-
success: CodeGraphSummary,
|
|
26349
|
-
error: CodeGraphUnavailableError
|
|
26350
|
-
});
|
|
26351
|
-
const WsCodeGraphNeighborhoodRpc = make$30(WS_METHODS.codeGraphNeighborhood, {
|
|
26352
|
-
payload: CodeGraphNeighborhoodInput,
|
|
26353
|
-
success: CodeGraphNeighborhood,
|
|
26354
|
-
error: Union([CodeGraphUnavailableError, CodeGraphNodeNotFoundError])
|
|
26355
|
-
});
|
|
26356
|
-
const WsCodeGraphSearchRpc = make$30(WS_METHODS.codeGraphSearch, {
|
|
26357
|
-
payload: CodeGraphSearchInput,
|
|
26358
|
-
success: CodeGraphSearchResult,
|
|
26359
|
-
error: CodeGraphUnavailableError
|
|
26360
|
-
});
|
|
26361
26189
|
const WsWorkspaceReadFileRpc = make$30(WS_METHODS.workspaceReadFile, {
|
|
26362
26190
|
payload: BulkTransferReadFileInput,
|
|
26363
26191
|
success: BulkTransferStreamEvent,
|
|
@@ -26807,7 +26635,7 @@ const WsRpcGroup = make$29(WsServerGetConfigRpc, WsServerRefreshProvidersRpc, Ws
|
|
|
26807
26635
|
payload: UsageSummaryInput,
|
|
26808
26636
|
success: UsageSummary,
|
|
26809
26637
|
error: UsageReadError
|
|
26810
|
-
}), WsPullRequestsListRpc, WsPullRequestsListStatsRpc, WsPullRequestsDetailRpc, WsPullRequestsActivityRpc, WsPullRequestsThreadCommentsRpc, WsPullRequestsDiffFileContentsRpc, WsPullRequestsRunActionRpc, WsPullRequestsUpdateRpc, WsPullRequestsCommentRpc, WsPullRequestsUpdateCommentRpc, WsPullRequestsSubmitReviewRpc, WsPullRequestsReplyToThreadRpc, WsPullRequestsSetThreadResolutionRpc, WsPullRequestsSetReactionRpc, WsPullRequestsInvalidateRpc, WsPullRequestsReviewerCandidatesRpc, WsPullRequestsRequestReviewersRpc, WsProjectsSearchContentsRpc, WsProjectsSearchEntriesRpc, WsProjectsWriteFileRpc, WsProjectCheckoutDeletionPreviewRpc, WsProjectCheckoutDeletionExecuteRpc,
|
|
26638
|
+
}), WsPullRequestsListRpc, WsPullRequestsListStatsRpc, WsPullRequestsDetailRpc, WsPullRequestsActivityRpc, WsPullRequestsThreadCommentsRpc, WsPullRequestsDiffFileContentsRpc, WsPullRequestsRunActionRpc, WsPullRequestsUpdateRpc, WsPullRequestsCommentRpc, WsPullRequestsUpdateCommentRpc, WsPullRequestsSubmitReviewRpc, WsPullRequestsReplyToThreadRpc, WsPullRequestsSetThreadResolutionRpc, WsPullRequestsSetReactionRpc, WsPullRequestsInvalidateRpc, WsPullRequestsReviewerCandidatesRpc, WsPullRequestsRequestReviewersRpc, WsProjectsSearchContentsRpc, WsProjectsSearchEntriesRpc, WsProjectsWriteFileRpc, WsProjectCheckoutDeletionPreviewRpc, WsProjectCheckoutDeletionExecuteRpc, WsWorkspaceReadFileRpc, WsWorkspaceBeginWriteFileRpc, WsWorkspaceWriteFileChunkRpc, WsWorkspaceCommitWriteFileRpc, WsWorkspaceCancelWriteFileRpc, WsShellOpenInEditorRpc, WsSubscribeGitStatusRpc, WsGitPullRpc, WsGitRefreshStatusRpc, WsGitRunStackedActionRpc, WsGitResolvePullRequestRpc, WsGitPreparePullRequestThreadRpc, WsGitListBranchesRpc, WsVcsListRefsRpc, WsVcsRefreshStatusRpc, WsSubscribeVcsStatusRpc, WsVcsPullRpc, WsVcsCreateWorktreeRpc, WsVcsRemoveWorktreeRpc, WsVcsCreateRefRpc, WsVcsSwitchRefRpc, WsVcsInitRpc, WsGitCreateWorktreeRpc, WsGitRemoveWorktreeRpc, WsGitCreateBranchRpc, WsGitCheckoutRpc, WsGitInitRpc, WsFilesystemBrowseRpc, WsProjectsReadFileRpc, WsReviewGetDiffPreviewRpc, WsCloudListRuntimesRpc, WsTerminalOpenRpc, WsTerminalAttachRpc, WsTerminalWriteRpc, WsTerminalResizeRpc, WsTerminalSignalRpc, WsTerminalClearRpc, WsTerminalRestartRpc, WsTerminalCloseRpc, WsBrowserOpenSessionRpc, WsBrowserListSessionsRpc, WsBrowserCloseSessionRpc, WsBrowserGetSessionRpc, WsBrowserCommandRpc, WsBrowserClearBrowsingDataRpc, WsBrowserAttachDisplayRpc, WsBrowserAddDisplayIceCandidateRpc, WsComputerInputRpc, WsDevTunnelRegisterRpc, WsDevTunnelUnregisterRpc, WsDevTunnelListRpc, WsThreadDevRuntimeGetRpc, WsThreadDevRuntimeAllocatePortRpc, WsThreadDevRuntimeReleaseRpc, WsWorkspaceEnvironmentPreflightRpc, WsWorkspaceEnsureScratchRpc, WsSubscribeTerminalEventsRpc, WsSubscribeTerminalMetadataRpc, WsProjectsListEntriesRpc, WsServerDiscoverSourceControlRpc, WsServerReportClientActivityRpc, WsSubscribeBrowserEventsRpc, WsSubscribeServerConfigRpc, WsSubscribeServerLifecycleRpc, WsSubscribeAuthAccessRpc, WsSubscribeWorkspaceReadinessRpc, WsOrchestrationDispatchCommandRpc, WsOrchestrationGetTurnDiffRpc, WsOrchestrationGetFullThreadDiffRpc, WsOrchestrationStreamTurnDiffRpc, WsOrchestrationStreamFullThreadDiffRpc, WsOrchestrationReplayEventsRpc, WsOrchestrationGetArchivedShellSnapshotRpc, WsOrchestrationSubscribeShellRpc, WsOrchestrationSubscribeThreadRpc, make$30(WS_METHODS.assetsCreateUrl, {
|
|
26811
26639
|
payload: AssetsRpcSchemas.createUrl.input,
|
|
26812
26640
|
success: AssetsRpcSchemas.createUrl.output,
|
|
26813
26641
|
error: AssetAccessError
|
|
@@ -31496,21 +31324,6 @@ const RELAY_METHOD_POLICY_BASES = [
|
|
|
31496
31324
|
requiredScope: "runtime.read",
|
|
31497
31325
|
deliveryClass: "read"
|
|
31498
31326
|
},
|
|
31499
|
-
{
|
|
31500
|
-
method: WS_METHODS.codeGraphSummary,
|
|
31501
|
-
requiredScope: "workspace.read",
|
|
31502
|
-
deliveryClass: "read"
|
|
31503
|
-
},
|
|
31504
|
-
{
|
|
31505
|
-
method: WS_METHODS.codeGraphNeighborhood,
|
|
31506
|
-
requiredScope: "workspace.read",
|
|
31507
|
-
deliveryClass: "read"
|
|
31508
|
-
},
|
|
31509
|
-
{
|
|
31510
|
-
method: WS_METHODS.codeGraphSearch,
|
|
31511
|
-
requiredScope: "workspace.read",
|
|
31512
|
-
deliveryClass: "read"
|
|
31513
|
-
},
|
|
31514
31327
|
{
|
|
31515
31328
|
method: WS_METHODS.projectsWriteFile,
|
|
31516
31329
|
requiredScope: "workspace.write",
|
|
@@ -66123,7 +65936,7 @@ function normalizeNumberish(value) {
|
|
|
66123
65936
|
}
|
|
66124
65937
|
//#endregion
|
|
66125
65938
|
//#region package.json
|
|
66126
|
-
var version$1 = "0.13.
|
|
65939
|
+
var version$1 = "0.13.18";
|
|
66127
65940
|
//#endregion
|
|
66128
65941
|
//#region src/sentry.ts
|
|
66129
65942
|
const SERVER_APP_NAME = "forge-server";
|
|
@@ -67161,7 +66974,7 @@ function toPersistenceDecodeDefect(operation) {
|
|
|
67161
66974
|
const isPersistenceError = (u) => is$1(PersistenceSqlError)(u) || is$1(PersistenceDecodeError)(u);
|
|
67162
66975
|
//#endregion
|
|
67163
66976
|
//#region src/cmmdConnection/CmmdConnectionStore.ts
|
|
67164
|
-
const cache
|
|
66977
|
+
const cache = /* @__PURE__ */ new Map();
|
|
67165
66978
|
const jwtCache = /* @__PURE__ */ new Map();
|
|
67166
66979
|
const jwtExpiryCache = /* @__PURE__ */ new Map();
|
|
67167
66980
|
const refreshTokenCache = /* @__PURE__ */ new Map();
|
|
@@ -67302,7 +67115,7 @@ const hydrateCommandAccessTokenStore = gen(function* () {
|
|
|
67302
67115
|
session_grant AS "sessionGrant"
|
|
67303
67116
|
FROM command_access_tokens
|
|
67304
67117
|
`.pipe(mapError(toPersistenceSqlError("CommandAccessTokenStore.hydrate:query")))).pipe(mapError(toPersistenceDecodeError("CommandAccessTokenStore.hydrate:decodeRows")));
|
|
67305
|
-
cache
|
|
67118
|
+
cache.clear();
|
|
67306
67119
|
jwtCache.clear();
|
|
67307
67120
|
jwtExpiryCache.clear();
|
|
67308
67121
|
refreshTokenCache.clear();
|
|
@@ -67312,7 +67125,7 @@ const hydrateCommandAccessTokenStore = gen(function* () {
|
|
|
67312
67125
|
try: () => {
|
|
67313
67126
|
for (const row of decoded) {
|
|
67314
67127
|
const sessionId = row.sessionId;
|
|
67315
|
-
cache
|
|
67128
|
+
cache.set(sessionId, decodeSensitiveValue(ACCESS_TOKEN_SCOPE, row.accessToken));
|
|
67316
67129
|
const jwtToken = decryptNullable(JWT_TOKEN_SCOPE, row.jwtToken);
|
|
67317
67130
|
if (jwtToken) jwtCache.set(sessionId, jwtToken);
|
|
67318
67131
|
if (row.jwtExpiresAt) jwtExpiryCache.set(sessionId, row.jwtExpiresAt);
|
|
@@ -67332,7 +67145,7 @@ const hydrateCommandAccessTokenStore = gen(function* () {
|
|
|
67332
67145
|
* Returns `null` when the session has no paired CMMD token.
|
|
67333
67146
|
*/
|
|
67334
67147
|
function readCommandAccessTokenForSession(sessionId) {
|
|
67335
|
-
return cache
|
|
67148
|
+
return cache.get(sessionId) ?? null;
|
|
67336
67149
|
}
|
|
67337
67150
|
const threadSessions = /* @__PURE__ */ new Map();
|
|
67338
67151
|
/**
|
|
@@ -67709,7 +67522,7 @@ const promoteMostRecentOwnerCommandAuthToSession = (sessionId) => gen(function*
|
|
|
67709
67522
|
cmmd_user_identity = excluded.cmmd_user_identity,
|
|
67710
67523
|
updated_at = excluded.updated_at
|
|
67711
67524
|
`.pipe(mapError(toPersistenceSqlError("CommandAccessTokenStore.promoteLatestOwnerAuth:upsert")));
|
|
67712
|
-
cache
|
|
67525
|
+
cache.set(sessionId, accessToken);
|
|
67713
67526
|
if (jwtToken) jwtCache.set(sessionId, jwtToken);
|
|
67714
67527
|
else jwtCache.delete(sessionId);
|
|
67715
67528
|
if (row.jwtExpiresAt) jwtExpiryCache.set(sessionId, row.jwtExpiresAt);
|
|
@@ -67754,7 +67567,7 @@ const setCommandAccessTokenForSession = (sessionId, accessToken) => gen(function
|
|
|
67754
67567
|
access_token = excluded.access_token,
|
|
67755
67568
|
updated_at = excluded.updated_at
|
|
67756
67569
|
`.pipe(mapError(toPersistenceSqlError("CommandAccessTokenStore.set:query")));
|
|
67757
|
-
cache
|
|
67570
|
+
cache.set(sessionId, token);
|
|
67758
67571
|
});
|
|
67759
67572
|
/**
|
|
67760
67573
|
* Remove the PAT for a session from both durable persistence and the in-memory cache.
|
|
@@ -67767,7 +67580,7 @@ const clearCommandAccessTokenForSession = (sessionId) => gen(function* () {
|
|
|
67767
67580
|
forgetCommandAccessTokenCachesForSession(sessionId);
|
|
67768
67581
|
});
|
|
67769
67582
|
function forgetCommandAccessTokenCachesForSession(sessionId) {
|
|
67770
|
-
cache
|
|
67583
|
+
cache.delete(sessionId);
|
|
67771
67584
|
jwtCache.delete(sessionId);
|
|
67772
67585
|
jwtExpiryCache.delete(sessionId);
|
|
67773
67586
|
refreshTokenCache.delete(sessionId);
|
|
@@ -77318,500 +77131,6 @@ const makeSocketProtocol = /* @__PURE__ */ gen(function* () {
|
|
|
77318
77131
|
};
|
|
77319
77132
|
});
|
|
77320
77133
|
//#endregion
|
|
77321
|
-
//#region src/codeGraph/aggregate.ts
|
|
77322
|
-
/**
|
|
77323
|
-
* Turning a 26 MB graph into slices small enough to draw.
|
|
77324
|
-
*
|
|
77325
|
-
* Pure functions over an already-parsed graph, deliberately free of Effect, the
|
|
77326
|
-
* filesystem and the RPC layer, so the interesting parts — capping, ranking,
|
|
77327
|
-
* hub suppression — are testable without a runtime or a fixture file on disk.
|
|
77328
|
-
*
|
|
77329
|
-
* The whole module exists because of one number: this repo's graph is 34,102
|
|
77330
|
-
* nodes and 86,347 edges. Nothing here ever returns more than a few hundred of
|
|
77331
|
-
* either. A view that tries to show everything shows nothing.
|
|
77332
|
-
*/
|
|
77333
|
-
function pushInto(map, key, link) {
|
|
77334
|
-
const existing = map.get(key);
|
|
77335
|
-
if (existing === void 0) {
|
|
77336
|
-
map.set(key, [link]);
|
|
77337
|
-
return;
|
|
77338
|
-
}
|
|
77339
|
-
existing.push(link);
|
|
77340
|
-
}
|
|
77341
|
-
function isKnownRelation(relation) {
|
|
77342
|
-
return Object.hasOwn(CODE_GRAPH_RELATION_CLASS, relation);
|
|
77343
|
-
}
|
|
77344
|
-
/**
|
|
77345
|
-
* Index a parsed graph once so every later query is a map lookup.
|
|
77346
|
-
*
|
|
77347
|
-
* Edges naming a node the artifact does not define are dropped rather than
|
|
77348
|
-
* synthesised. Graphify does emit these — a call into a module outside the scan
|
|
77349
|
-
* root — and inventing a placeholder node for one would put a file in the map
|
|
77350
|
-
* that is not in the repository.
|
|
77351
|
-
*/
|
|
77352
|
-
function indexGraph(raw, repoLabel) {
|
|
77353
|
-
const nodes = /* @__PURE__ */ new Map();
|
|
77354
|
-
for (const node of raw.nodes) nodes.set(node.id, node);
|
|
77355
|
-
const outbound = /* @__PURE__ */ new Map();
|
|
77356
|
-
const inbound = /* @__PURE__ */ new Map();
|
|
77357
|
-
const degree = /* @__PURE__ */ new Map();
|
|
77358
|
-
const unknownRelations = /* @__PURE__ */ new Set();
|
|
77359
|
-
let extractedEdgeCount = 0;
|
|
77360
|
-
let inferredEdgeCount = 0;
|
|
77361
|
-
let edgeCount = 0;
|
|
77362
|
-
for (const link of raw.links) {
|
|
77363
|
-
if (!nodes.has(link.source) || !nodes.has(link.target)) continue;
|
|
77364
|
-
const relation = link.relation ?? "";
|
|
77365
|
-
if (relation !== "" && !isKnownRelation(relation)) {
|
|
77366
|
-
unknownRelations.add(relation);
|
|
77367
|
-
continue;
|
|
77368
|
-
}
|
|
77369
|
-
edgeCount += 1;
|
|
77370
|
-
if (link.confidence === "INFERRED") inferredEdgeCount += 1;
|
|
77371
|
-
else extractedEdgeCount += 1;
|
|
77372
|
-
pushInto(outbound, link.source, link);
|
|
77373
|
-
pushInto(inbound, link.target, link);
|
|
77374
|
-
degree.set(link.source, (degree.get(link.source) ?? 0) + 1);
|
|
77375
|
-
degree.set(link.target, (degree.get(link.target) ?? 0) + 1);
|
|
77376
|
-
}
|
|
77377
|
-
return {
|
|
77378
|
-
repoLabel,
|
|
77379
|
-
builtAtCommit: raw.built_at_commit ?? null,
|
|
77380
|
-
nodes,
|
|
77381
|
-
outbound,
|
|
77382
|
-
inbound,
|
|
77383
|
-
degree,
|
|
77384
|
-
edgeCount,
|
|
77385
|
-
extractedEdgeCount,
|
|
77386
|
-
inferredEdgeCount,
|
|
77387
|
-
unknownRelations: [...unknownRelations].toSorted()
|
|
77388
|
-
};
|
|
77389
|
-
}
|
|
77390
|
-
/**
|
|
77391
|
-
* Deterministic sunflower placement.
|
|
77392
|
-
*
|
|
77393
|
-
* A phyllotaxis spiral rather than a force simulation, for three reasons: it
|
|
77394
|
-
* needs no dependency, it is O(n), and — the one that actually matters — it is
|
|
77395
|
-
* *stable*. The same graph opens to the same picture every time, so the spatial
|
|
77396
|
-
* memory a person builds up survives closing the panel. A force layout reshuffles
|
|
77397
|
-
* on every mount and quietly costs them that.
|
|
77398
|
-
*
|
|
77399
|
-
* Index 0 lands nearest the centre, so ordering regions by size puts the
|
|
77400
|
-
* architectural core where the eye starts.
|
|
77401
|
-
*/
|
|
77402
|
-
function spiralPosition(index, total) {
|
|
77403
|
-
const goldenAngle = Math.PI * (3 - Math.sqrt(5));
|
|
77404
|
-
const radius = total <= 1 ? 0 : Math.sqrt(index / (total - 1));
|
|
77405
|
-
const angle = index * goldenAngle;
|
|
77406
|
-
return {
|
|
77407
|
-
x: .5 + radius * Math.cos(angle) * .44,
|
|
77408
|
-
y: .5 + radius * Math.sin(angle) * .44
|
|
77409
|
-
};
|
|
77410
|
-
}
|
|
77411
|
-
/** Group nodes into their communities, and remember which community each is in. */
|
|
77412
|
-
function accumulateRegions(graph) {
|
|
77413
|
-
const accumulators = /* @__PURE__ */ new Map();
|
|
77414
|
-
const regionOfNode = /* @__PURE__ */ new Map();
|
|
77415
|
-
for (const node of graph.nodes.values()) {
|
|
77416
|
-
const community = node.community;
|
|
77417
|
-
if (community === void 0) continue;
|
|
77418
|
-
regionOfNode.set(node.id, community);
|
|
77419
|
-
const existing = accumulators.get(community);
|
|
77420
|
-
if (existing === void 0) {
|
|
77421
|
-
accumulators.set(community, {
|
|
77422
|
-
id: community,
|
|
77423
|
-
label: node.community_name ?? `Region ${String(community)}`,
|
|
77424
|
-
nodeCount: 1
|
|
77425
|
-
});
|
|
77426
|
-
continue;
|
|
77427
|
-
}
|
|
77428
|
-
existing.nodeCount += 1;
|
|
77429
|
-
}
|
|
77430
|
-
return {
|
|
77431
|
-
ordered: [...accumulators.values()].toSorted((a, b) => b.nodeCount - a.nodeCount || a.id - b.id),
|
|
77432
|
-
regionOfNode
|
|
77433
|
-
};
|
|
77434
|
-
}
|
|
77435
|
-
/**
|
|
77436
|
-
* Collapse node-level edges into weighted links between drawn regions.
|
|
77437
|
-
*
|
|
77438
|
-
* Undirected: "these two areas talk" is the question at this altitude, and
|
|
77439
|
-
* drawing both arcs doubles the ink for no added meaning.
|
|
77440
|
-
*/
|
|
77441
|
-
function aggregateRegionLinks(graph, regionOfNode, shownIds) {
|
|
77442
|
-
const linkWeights = /* @__PURE__ */ new Map();
|
|
77443
|
-
for (const links of graph.outbound.values()) for (const link of links) {
|
|
77444
|
-
const from = regionOfNode.get(link.source);
|
|
77445
|
-
const to = regionOfNode.get(link.target);
|
|
77446
|
-
if (from === void 0 || to === void 0 || from === to) continue;
|
|
77447
|
-
if (!shownIds.has(from) || !shownIds.has(to)) continue;
|
|
77448
|
-
const key = `${String(Math.min(from, to))}:${String(Math.max(from, to))}`;
|
|
77449
|
-
linkWeights.set(key, (linkWeights.get(key) ?? 0) + 1);
|
|
77450
|
-
}
|
|
77451
|
-
return [...linkWeights.entries()].map(([key, weight]) => {
|
|
77452
|
-
const [source, target] = key.split(":");
|
|
77453
|
-
return {
|
|
77454
|
-
source: Number(source),
|
|
77455
|
-
target: Number(target),
|
|
77456
|
-
weight
|
|
77457
|
-
};
|
|
77458
|
-
});
|
|
77459
|
-
}
|
|
77460
|
-
/**
|
|
77461
|
-
* The default view: the repository as named regions.
|
|
77462
|
-
*
|
|
77463
|
-
* Regions come from graphify's own community detection, and their names come
|
|
77464
|
-
* from the community's hub node — so a region is labelled `AIGateway.ts` or
|
|
77465
|
-
* `IStorage`, something a person recognises, rather than "Community 469".
|
|
77466
|
-
*/
|
|
77467
|
-
function buildSummary(graph) {
|
|
77468
|
-
const { ordered, regionOfNode } = accumulateRegions(graph);
|
|
77469
|
-
const shown = ordered.slice(0, 120);
|
|
77470
|
-
const shownIds = new Set(shown.map((region) => region.id));
|
|
77471
|
-
const regions = shown.map((region, index) => {
|
|
77472
|
-
const position = spiralPosition(index, shown.length);
|
|
77473
|
-
return {
|
|
77474
|
-
id: region.id,
|
|
77475
|
-
label: region.label,
|
|
77476
|
-
nodeCount: region.nodeCount,
|
|
77477
|
-
x: position.x,
|
|
77478
|
-
y: position.y
|
|
77479
|
-
};
|
|
77480
|
-
});
|
|
77481
|
-
return {
|
|
77482
|
-
repoLabel: graph.repoLabel,
|
|
77483
|
-
builtAtCommit: graph.builtAtCommit,
|
|
77484
|
-
nodeCount: graph.nodes.size,
|
|
77485
|
-
edgeCount: graph.edgeCount,
|
|
77486
|
-
extractedEdgeCount: graph.extractedEdgeCount,
|
|
77487
|
-
inferredEdgeCount: graph.inferredEdgeCount,
|
|
77488
|
-
regionCount: ordered.length,
|
|
77489
|
-
regions,
|
|
77490
|
-
links: aggregateRegionLinks(graph, regionOfNode, shownIds),
|
|
77491
|
-
truncatedRegions: Math.max(0, ordered.length - shown.length)
|
|
77492
|
-
};
|
|
77493
|
-
}
|
|
77494
|
-
function summariseNode(graph, node) {
|
|
77495
|
-
return {
|
|
77496
|
-
id: node.id,
|
|
77497
|
-
label: node.label ?? node.id,
|
|
77498
|
-
kind: node._callable === true ? "symbol" : "file",
|
|
77499
|
-
sourceFile: node.source_file ?? null,
|
|
77500
|
-
sourceLocation: node.source_location ?? null,
|
|
77501
|
-
regionId: node.community ?? null,
|
|
77502
|
-
regionLabel: node.community_name ?? null,
|
|
77503
|
-
degree: graph.degree.get(node.id) ?? 0
|
|
77504
|
-
};
|
|
77505
|
-
}
|
|
77506
|
-
function toEdgeView(link) {
|
|
77507
|
-
const relation = link.relation ?? "";
|
|
77508
|
-
if (!isKnownRelation(relation)) return null;
|
|
77509
|
-
const confidence = link.confidence === "INFERRED" ? "INFERRED" : "EXTRACTED";
|
|
77510
|
-
return {
|
|
77511
|
-
source: link.source,
|
|
77512
|
-
target: link.target,
|
|
77513
|
-
relation,
|
|
77514
|
-
edgeClass: CODE_GRAPH_RELATION_CLASS[relation],
|
|
77515
|
-
confidence,
|
|
77516
|
-
confidenceScore: link.confidence_score ?? 1
|
|
77517
|
-
};
|
|
77518
|
-
}
|
|
77519
|
-
/**
|
|
77520
|
-
* Pull one node's neighbours into the result; return how many it had to drop.
|
|
77521
|
-
*
|
|
77522
|
-
* Split out of `buildNeighborhood` because the two read differently: the caller
|
|
77523
|
-
* owns *how far to walk*, this owns *what one step collects*. Together they sat
|
|
77524
|
-
* well past the repo's cognitive-complexity gate.
|
|
77525
|
-
*/
|
|
77526
|
-
/** Links touching a node, most-connected neighbour first. */
|
|
77527
|
-
function rankNeighbourLinks(graph, current) {
|
|
77528
|
-
return [...graph.outbound.get(current) ?? [], ...graph.inbound.get(current) ?? []].toSorted((a, b) => {
|
|
77529
|
-
const aOther = a.source === current ? a.target : a.source;
|
|
77530
|
-
const bOther = b.source === current ? b.target : b.source;
|
|
77531
|
-
return (graph.degree.get(bOther) ?? 0) - (graph.degree.get(aOther) ?? 0);
|
|
77532
|
-
});
|
|
77533
|
-
}
|
|
77534
|
-
/** Take a neighbour into the result. False means the budget is spent. */
|
|
77535
|
-
function admitNeighbour(state, id, node) {
|
|
77536
|
-
if (state.included.has(id)) return true;
|
|
77537
|
-
if (state.included.size >= 150) return false;
|
|
77538
|
-
state.included.set(id, node);
|
|
77539
|
-
state.next.push(id);
|
|
77540
|
-
return true;
|
|
77541
|
-
}
|
|
77542
|
-
/** Record an edge once, dropping any relation this build cannot classify. */
|
|
77543
|
-
function recordEdge(state, link) {
|
|
77544
|
-
const edgeKey = `${link.source}>${link.target}:${link.relation ?? ""}`;
|
|
77545
|
-
if (state.seenEdges.has(edgeKey)) return;
|
|
77546
|
-
const view = toEdgeView(link);
|
|
77547
|
-
if (view === null) return;
|
|
77548
|
-
state.seenEdges.add(edgeKey);
|
|
77549
|
-
state.edges.push(view);
|
|
77550
|
-
}
|
|
77551
|
-
/**
|
|
77552
|
-
* Pull one node's neighbours into the result; return how many it had to drop.
|
|
77553
|
-
*
|
|
77554
|
-
* Split out of `buildNeighborhood` because the two read differently: the caller
|
|
77555
|
-
* owns *how far to walk*, this owns *what one step collects*.
|
|
77556
|
-
*/
|
|
77557
|
-
function expandNode(graph, current, state) {
|
|
77558
|
-
let omitted = 0;
|
|
77559
|
-
for (const link of rankNeighbourLinks(graph, current)) {
|
|
77560
|
-
const other = link.source === current ? link.target : link.source;
|
|
77561
|
-
const otherNode = graph.nodes.get(other);
|
|
77562
|
-
if (otherNode === void 0) continue;
|
|
77563
|
-
if (!admitNeighbour(state, other, otherNode)) {
|
|
77564
|
-
omitted += 1;
|
|
77565
|
-
continue;
|
|
77566
|
-
}
|
|
77567
|
-
recordEdge(state, link);
|
|
77568
|
-
}
|
|
77569
|
-
return omitted;
|
|
77570
|
-
}
|
|
77571
|
-
/**
|
|
77572
|
-
* One node and what surrounds it.
|
|
77573
|
-
*
|
|
77574
|
-
* Two caps, and they do different jobs. `CODE_GRAPH_MAX_NEIGHBORS` bounds the
|
|
77575
|
-
* answer so the canvas stays drawable. `CODE_GRAPH_MAX_FANOUT` bounds the
|
|
77576
|
-
* *traversal*: a hub is included as a neighbor but never expanded through, so
|
|
77577
|
-
* one `logger.ts` in the second ring cannot drag the entire repository in
|
|
77578
|
-
* behind it. Without the second cap the first one is reached instantly and the
|
|
77579
|
-
* result is 150 arbitrary nodes rather than the 150 nearest ones.
|
|
77580
|
-
*/
|
|
77581
|
-
function buildNeighborhood(graph, nodeId, requestedDepth) {
|
|
77582
|
-
const root = graph.nodes.get(nodeId);
|
|
77583
|
-
if (root === void 0) return null;
|
|
77584
|
-
const depth = Math.min(Math.max(1, requestedDepth), 2);
|
|
77585
|
-
const included = new Map([[root.id, root]]);
|
|
77586
|
-
const seenEdges = /* @__PURE__ */ new Set();
|
|
77587
|
-
const edges = [];
|
|
77588
|
-
let omittedCount = 0;
|
|
77589
|
-
let frontier = [root.id];
|
|
77590
|
-
for (let level = 0; level < depth; level += 1) {
|
|
77591
|
-
const next = [];
|
|
77592
|
-
for (const current of frontier) {
|
|
77593
|
-
const fanout = graph.degree.get(current) ?? 0;
|
|
77594
|
-
if (current !== root.id && fanout > 200) continue;
|
|
77595
|
-
omittedCount += expandNode(graph, current, {
|
|
77596
|
-
included,
|
|
77597
|
-
seenEdges,
|
|
77598
|
-
edges,
|
|
77599
|
-
next
|
|
77600
|
-
});
|
|
77601
|
-
}
|
|
77602
|
-
frontier = next;
|
|
77603
|
-
if (frontier.length === 0) break;
|
|
77604
|
-
}
|
|
77605
|
-
const nodes = [...included.values()].filter((node) => node.id !== root.id).map((node) => summariseNode(graph, node)).toSorted((a, b) => b.degree - a.degree || a.label.localeCompare(b.label));
|
|
77606
|
-
return {
|
|
77607
|
-
root: summariseNode(graph, root),
|
|
77608
|
-
nodes,
|
|
77609
|
-
edges: edges.filter((edge) => included.has(edge.source) && included.has(edge.target)),
|
|
77610
|
-
depth,
|
|
77611
|
-
truncated: omittedCount > 0,
|
|
77612
|
-
omittedCount
|
|
77613
|
-
};
|
|
77614
|
-
}
|
|
77615
|
-
/**
|
|
77616
|
-
* Rank one node against a query: lower is better, negative means no match.
|
|
77617
|
-
*
|
|
77618
|
-
* A file-path hit ranks last because "the query appears somewhere in this path"
|
|
77619
|
-
* is much weaker evidence than "this thing is called that".
|
|
77620
|
-
*/
|
|
77621
|
-
function matchScore(node, query) {
|
|
77622
|
-
const label = (node.label ?? node.id).toLowerCase();
|
|
77623
|
-
if (label === query) return 0;
|
|
77624
|
-
if (label.startsWith(query)) return 1;
|
|
77625
|
-
if (label.includes(query)) return 2;
|
|
77626
|
-
return (node.source_file ?? "").toLowerCase().includes(query) ? 3 : -1;
|
|
77627
|
-
}
|
|
77628
|
-
/**
|
|
77629
|
-
* Find a node by name or path.
|
|
77630
|
-
*
|
|
77631
|
-
* Entry to this surface is search, not the canvas — you usually arrive already
|
|
77632
|
-
* knowing what you are looking for, and clicking around 34,000 nodes to find it
|
|
77633
|
-
* is not a workflow. Ranking is exact, then prefix, then substring, with degree
|
|
77634
|
-
* breaking ties so the `logger.ts` everything imports outranks a test fixture
|
|
77635
|
-
* that merely shares the word.
|
|
77636
|
-
*/
|
|
77637
|
-
function searchNodes(graph, rawQuery, limit = 40) {
|
|
77638
|
-
const query = rawQuery.trim().toLowerCase();
|
|
77639
|
-
if (query === "") return {
|
|
77640
|
-
nodes: [],
|
|
77641
|
-
truncated: false
|
|
77642
|
-
};
|
|
77643
|
-
const scored = [];
|
|
77644
|
-
for (const node of graph.nodes.values()) {
|
|
77645
|
-
const score = matchScore(node, query);
|
|
77646
|
-
if (score < 0) continue;
|
|
77647
|
-
scored.push({
|
|
77648
|
-
node,
|
|
77649
|
-
score
|
|
77650
|
-
});
|
|
77651
|
-
}
|
|
77652
|
-
const ranked = scored.toSorted((a, b) => a.score - b.score || (graph.degree.get(b.node.id) ?? 0) - (graph.degree.get(a.node.id) ?? 0) || (a.node.label ?? a.node.id).localeCompare(b.node.label ?? b.node.id));
|
|
77653
|
-
const capped = ranked.slice(0, limit);
|
|
77654
|
-
return {
|
|
77655
|
-
nodes: capped.map((entry) => summariseNode(graph, entry.node)),
|
|
77656
|
-
truncated: ranked.length > capped.length
|
|
77657
|
-
};
|
|
77658
|
-
}
|
|
77659
|
-
//#endregion
|
|
77660
|
-
//#region src/codeGraph/graphArtifact.ts
|
|
77661
|
-
/**
|
|
77662
|
-
* Reading `graphify-out/graph.json` off disk, once.
|
|
77663
|
-
*
|
|
77664
|
-
* The artifact is 26 MB here and 40 MB for CMMD's server tree, and parsing it
|
|
77665
|
-
* costs roughly a second. Every panel open would pay that again without a cache,
|
|
77666
|
-
* so one indexed graph is held per project and reused until the file changes.
|
|
77667
|
-
*
|
|
77668
|
-
* Kept free of Effect on purpose: the failure modes worth distinguishing are all
|
|
77669
|
-
* filesystem-shaped, and a plain promise keeps this unit-testable against real
|
|
77670
|
-
* fixtures without constructing a runtime. `ws.ts` wraps it at the boundary.
|
|
77671
|
-
*/
|
|
77672
|
-
const cache = /* @__PURE__ */ new Map();
|
|
77673
|
-
/** Git LFS writes a pointer file that is valid text and useless as a graph. */
|
|
77674
|
-
const LFS_POINTER_PREFIX = "version https://git-lfs.github.com/spec/v1";
|
|
77675
|
-
function codeGraphArtifactPath(cwd) {
|
|
77676
|
-
return path.join(cwd, CODE_GRAPH_ARTIFACT_PATH);
|
|
77677
|
-
}
|
|
77678
|
-
function isRawGraph(value) {
|
|
77679
|
-
if (typeof value !== "object" || value === null) return false;
|
|
77680
|
-
const candidate = value;
|
|
77681
|
-
return Array.isArray(candidate.nodes) && Array.isArray(candidate.links);
|
|
77682
|
-
}
|
|
77683
|
-
/**
|
|
77684
|
-
* Load and index the graph for one project checkout.
|
|
77685
|
-
*
|
|
77686
|
-
* The LFS-pointer case is called out separately rather than folded into
|
|
77687
|
-
* "malformed" because it is the single most likely failure on a fresh clone —
|
|
77688
|
-
* the file is present, tracked, and 133 bytes of metadata. Telling someone their
|
|
77689
|
-
* graph is corrupt when they simply have not run `git lfs pull` sends them to
|
|
77690
|
-
* rebuild something that is fine.
|
|
77691
|
-
*/
|
|
77692
|
-
async function loadIndexedGraph(cwd) {
|
|
77693
|
-
const artifactPath = codeGraphArtifactPath(cwd);
|
|
77694
|
-
let stats;
|
|
77695
|
-
try {
|
|
77696
|
-
stats = await stat(artifactPath);
|
|
77697
|
-
} catch {
|
|
77698
|
-
return {
|
|
77699
|
-
ok: false,
|
|
77700
|
-
failure: {
|
|
77701
|
-
kind: "missing",
|
|
77702
|
-
artifactPath
|
|
77703
|
-
}
|
|
77704
|
-
};
|
|
77705
|
-
}
|
|
77706
|
-
if (!stats.isFile()) return {
|
|
77707
|
-
ok: false,
|
|
77708
|
-
failure: {
|
|
77709
|
-
kind: "missing",
|
|
77710
|
-
artifactPath
|
|
77711
|
-
}
|
|
77712
|
-
};
|
|
77713
|
-
const cached = cache.get(artifactPath);
|
|
77714
|
-
if (cached !== void 0 && cached.mtimeMs === stats.mtimeMs && cached.size === stats.size) return {
|
|
77715
|
-
ok: true,
|
|
77716
|
-
graph: cached.graph
|
|
77717
|
-
};
|
|
77718
|
-
let contents;
|
|
77719
|
-
try {
|
|
77720
|
-
contents = await readFile$1(artifactPath, "utf8");
|
|
77721
|
-
} catch (error) {
|
|
77722
|
-
return {
|
|
77723
|
-
ok: false,
|
|
77724
|
-
failure: {
|
|
77725
|
-
kind: "unreadable",
|
|
77726
|
-
artifactPath,
|
|
77727
|
-
detail: error instanceof Error ? error.message : String(error)
|
|
77728
|
-
}
|
|
77729
|
-
};
|
|
77730
|
-
}
|
|
77731
|
-
if (contents.startsWith(LFS_POINTER_PREFIX)) return {
|
|
77732
|
-
ok: false,
|
|
77733
|
-
failure: {
|
|
77734
|
-
kind: "lfs-pointer",
|
|
77735
|
-
artifactPath
|
|
77736
|
-
}
|
|
77737
|
-
};
|
|
77738
|
-
let parsed;
|
|
77739
|
-
try {
|
|
77740
|
-
parsed = JSON.parse(contents);
|
|
77741
|
-
} catch (error) {
|
|
77742
|
-
return {
|
|
77743
|
-
ok: false,
|
|
77744
|
-
failure: {
|
|
77745
|
-
kind: "malformed",
|
|
77746
|
-
artifactPath,
|
|
77747
|
-
detail: error instanceof Error ? error.message : String(error)
|
|
77748
|
-
}
|
|
77749
|
-
};
|
|
77750
|
-
}
|
|
77751
|
-
if (!isRawGraph(parsed)) return {
|
|
77752
|
-
ok: false,
|
|
77753
|
-
failure: {
|
|
77754
|
-
kind: "malformed",
|
|
77755
|
-
artifactPath,
|
|
77756
|
-
detail: "Expected an object with `nodes` and `links` arrays."
|
|
77757
|
-
}
|
|
77758
|
-
};
|
|
77759
|
-
const graph = indexGraph(parsed, path.basename(cwd));
|
|
77760
|
-
cache.set(artifactPath, {
|
|
77761
|
-
mtimeMs: stats.mtimeMs,
|
|
77762
|
-
size: stats.size,
|
|
77763
|
-
graph
|
|
77764
|
-
});
|
|
77765
|
-
return {
|
|
77766
|
-
ok: true,
|
|
77767
|
-
graph
|
|
77768
|
-
};
|
|
77769
|
-
}
|
|
77770
|
-
//#endregion
|
|
77771
|
-
//#region src/codeGraph/service.ts
|
|
77772
|
-
/**
|
|
77773
|
-
* The code-graph RPC surface, as Effects.
|
|
77774
|
-
*
|
|
77775
|
-
* A thin seam between `ws.ts` and the pure aggregator: load the artifact, turn
|
|
77776
|
-
* a filesystem failure into the tagged error the client can act on, and slice.
|
|
77777
|
-
*
|
|
77778
|
-
* The failure mapping is the substance here. Each reason produces different
|
|
77779
|
-
* advice — pull LFS, run the extractor, report a corrupt file — so collapsing
|
|
77780
|
-
* them into one "graph unavailable" would send people to fix the wrong thing.
|
|
77781
|
-
*/
|
|
77782
|
-
function toUnavailable(failure) {
|
|
77783
|
-
switch (failure.kind) {
|
|
77784
|
-
case "missing": return new CodeGraphUnavailableError({
|
|
77785
|
-
reason: "missing",
|
|
77786
|
-
message: `No code graph in this checkout. Run \`graphify update .\` to build ${failure.artifactPath}.`
|
|
77787
|
-
});
|
|
77788
|
-
case "lfs-pointer": return new CodeGraphUnavailableError({
|
|
77789
|
-
reason: "lfs-pointer",
|
|
77790
|
-
message: `The graph is a Git LFS pointer, not the graph itself. Run \`git lfs pull\` to fetch it.`
|
|
77791
|
-
});
|
|
77792
|
-
case "malformed": return new CodeGraphUnavailableError({
|
|
77793
|
-
reason: "malformed",
|
|
77794
|
-
message: `The graph file could not be parsed: ${failure.detail}`
|
|
77795
|
-
});
|
|
77796
|
-
case "unreadable": return new CodeGraphUnavailableError({
|
|
77797
|
-
reason: "unreadable",
|
|
77798
|
-
message: `The graph file could not be read: ${failure.detail}`
|
|
77799
|
-
});
|
|
77800
|
-
}
|
|
77801
|
-
}
|
|
77802
|
-
function withGraph(cwd, use) {
|
|
77803
|
-
return flatMap(promise(() => loadIndexedGraph(cwd)), (result) => result.ok ? succeed(use(result.graph)) : fail(toUnavailable(result.failure)));
|
|
77804
|
-
}
|
|
77805
|
-
function readCodeGraphSummary(input) {
|
|
77806
|
-
return withGraph(input.cwd, buildSummary);
|
|
77807
|
-
}
|
|
77808
|
-
function readCodeGraphNeighborhood(input) {
|
|
77809
|
-
return flatMap(withGraph(input.cwd, (graph) => buildNeighborhood(graph, input.nodeId, input.depth ?? 1)), (neighborhood) => neighborhood === null ? fail(new CodeGraphNodeNotFoundError({ nodeId: input.nodeId })) : succeed(neighborhood));
|
|
77810
|
-
}
|
|
77811
|
-
function readCodeGraphSearch(input) {
|
|
77812
|
-
return withGraph(input.cwd, (graph) => searchNodes(graph, input.query, input.limit ?? 40));
|
|
77813
|
-
}
|
|
77814
|
-
//#endregion
|
|
77815
77134
|
//#region src/checkpointing/Services/CheckpointDiffQuery.ts
|
|
77816
77135
|
/**
|
|
77817
77136
|
* CheckpointDiffQuery - Service tag for checkpoint diff queries.
|
|
@@ -107314,9 +106633,6 @@ const makeWsRpcLayer = (currentSessionId, currentUserId) => WsRpcGroup.toLayer(g
|
|
|
107314
106633
|
}))), { "rpc.aggregate": "workspace" }),
|
|
107315
106634
|
[WS_METHODS.serverDiscoverSourceControl]: () => observeRpcEffect(WS_METHODS.serverDiscoverSourceControl, discoverSourceControl, { "rpc.aggregate": "server" }),
|
|
107316
106635
|
[WS_METHODS.serverReportClientActivity]: () => observeRpcEffect(WS_METHODS.serverReportClientActivity, void_$1, { "rpc.aggregate": "server" }),
|
|
107317
|
-
[WS_METHODS.codeGraphSummary]: (input) => observeRpcEffect(WS_METHODS.codeGraphSummary, readCodeGraphSummary(input), { "rpc.aggregate": "codeGraph" }),
|
|
107318
|
-
[WS_METHODS.codeGraphNeighborhood]: (input) => observeRpcEffect(WS_METHODS.codeGraphNeighborhood, readCodeGraphNeighborhood(input), { "rpc.aggregate": "codeGraph" }),
|
|
107319
|
-
[WS_METHODS.codeGraphSearch]: (input) => observeRpcEffect(WS_METHODS.codeGraphSearch, readCodeGraphSearch(input), { "rpc.aggregate": "codeGraph" }),
|
|
107320
106636
|
[WS_METHODS.projectsWriteFile]: (input) => observeRpcEffect(WS_METHODS.projectsWriteFile, workspaceFileSystem.writeFile(input).pipe(mapError((cause) => {
|
|
107321
106637
|
return new ProjectWriteFileError({
|
|
107322
106638
|
message: is$1(WorkspacePathOutsideRootError)(cause) ? "Workspace file path must stay within the project root." : "Failed to write workspace file",
|
|
@@ -298327,7 +297643,7 @@ function resolveBuildCommitFromEnv(env) {
|
|
|
298327
297643
|
* environment descriptor down instead of reporting an honest "unknown".
|
|
298328
297644
|
*/
|
|
298329
297645
|
function readBakedBuildCommit() {
|
|
298330
|
-
return "
|
|
297646
|
+
return "ccfffcbf86c28599b61bac158032499398ed9713";
|
|
298331
297647
|
}
|
|
298332
297648
|
async function resolveServerBuildCommit(input) {
|
|
298333
297649
|
if (isFullCommitSha(input.baked)) return input.baked;
|