glimmervoid 0.39.0 → 0.40.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.
Files changed (32) hide show
  1. package/README.md +1 -1
  2. package/dist/bin/glimmervoid.js +22 -25
  3. package/dist/chunks/{adapters-B9tP9MXC.js → adapters-B6tbX3Aj.js} +4 -3
  4. package/dist/chunks/{adapters-Buu6yI71.js → adapters-CXQfLoyj.js} +1 -1
  5. package/dist/chunks/agent-api-cli-BBech5lF.js +1 -0
  6. package/dist/chunks/{agent-api-cli-2_RwTTTJ.js → agent-api-cli-BNHJTmNW.js} +46 -17
  7. package/dist/chunks/agent-api-core-DDrJQEdE.js +304 -0
  8. package/dist/chunks/{agent-setup-cli-C1nFdgFg.js → agent-setup-cli-CeBBwKuL.js} +1 -1
  9. package/dist/chunks/config-store-BZpN2djp.js +1 -0
  10. package/dist/chunks/{config-store-n23JDU4E.js → config-store-DqMScSdg.js} +20 -1
  11. package/dist/chunks/contracts-CloExMlS.js +680 -0
  12. package/dist/chunks/{contracts-DYQW11de.js → control-messages-DpBaniJi.js} +1201 -1794
  13. package/dist/chunks/{git-version-DXozXVnb.js → git-version-CJQMfxtZ.js} +1 -1
  14. package/dist/chunks/{grok-DeGAXgZF.js → grok-BLzhApwT.js} +1 -1
  15. package/dist/chunks/{main-D4uwk-_M.js → main-DDU8IvFD.js} +26436 -24806
  16. package/dist/chunks/{pair-cli-D9DZBqk0.js → pair-cli-CsOVTQGJ.js} +2 -2
  17. package/dist/chunks/{remote-config-DiLwnzBq.js → remote-config-HlABuLTp.js} +1 -1
  18. package/dist/chunks/{session-D2EbiysG.js → session-BwB43SCa.js} +103 -43
  19. package/dist/chunks/{session-routes-BQAZzMKZ.js → session-routes-DNJzsckH.js} +23 -3
  20. package/dist/chunks/{settings-cli-DP4t-I9U.js → settings-cli-DkkbK-dj.js} +30 -156
  21. package/dist/chunks/settings-readout-core-DrXT4aWm.js +201 -0
  22. package/dist/chunks/{ssh-sign-cli-D2RIs-iN.js → ssh-sign-cli-CYeKRevK.js} +2 -2
  23. package/dist/client/assets/index-BK9jLR47.js +148 -0
  24. package/dist/client/assets/index-CU_uqJmi.css +2 -0
  25. package/dist/client/index.html +4 -3
  26. package/dist/server/index.js +1 -1
  27. package/package.json +2 -2
  28. package/dist/chunks/agent-api-cli-PfCov-qb.js +0 -1
  29. package/dist/chunks/agent-api-core-D2HLgBEe.js +0 -180
  30. package/dist/chunks/config-store-8Z9vkWvf.js +0 -1
  31. package/dist/client/assets/index-C0YUJwjz.css +0 -2
  32. package/dist/client/assets/index-w8lG-tk2.js +0 -148
@@ -1,6 +1,6 @@
1
1
  import { r as errorMessage } from "./text-DoirglWV.js";
2
- import { c as resolveConfigPath } from "./config-store-n23JDU4E.js";
3
- import { c as defaultPairingsPath, i as REVOCATION_PROPAGATION_SECONDS, l as defaultSeenPath, n as normalizeRemoteConfig, o as createPairingsStore, s as createSeenStore } from "./remote-config-DiLwnzBq.js";
2
+ import { c as resolveConfigPath } from "./config-store-DqMScSdg.js";
3
+ import { c as defaultPairingsPath, i as REVOCATION_PROPAGATION_SECONDS, l as defaultSeenPath, n as normalizeRemoteConfig, o as createPairingsStore, s as createSeenStore } from "./remote-config-HlABuLTp.js";
4
4
  import fs from "node:fs";
5
5
  //#region server/text-format.ts
6
6
  function trimIso(iso) {
@@ -3,7 +3,7 @@ import { n as equalsIgnoringCaseOnWindows } from "./paths-Bu4eH1Yd.js";
3
3
  import { n as isRecord } from "./coerce-NSst8oRP.js";
4
4
  import { n as unrefTimer, t as DEFAULT_TIMER_FNS } from "./timer-deps-u2DAQLok.js";
5
5
  import { a as jsonStateLoadError, d as writeJsonAtomicSync, l as sleepSync, s as loadJsonStateFileSync, u as writeJsonAtomic } from "./json-file-DFCTvPjj.js";
6
- import { o as glimmervoidHomeDir, ot as canonicalizePath } from "./config-store-n23JDU4E.js";
6
+ import { o as glimmervoidHomeDir, ot as canonicalizePath } from "./config-store-DqMScSdg.js";
7
7
  import fs from "node:fs";
8
8
  import path from "node:path";
9
9
  import crypto from "node:crypto";
@@ -13,26 +13,15 @@ var STATES = Object.freeze({
13
13
  });
14
14
  Object.freeze({
15
15
  [STATES.DORMANT]: "Dormant",
16
- [STATES.INITIALIZING]: "Preparing",
16
+ [STATES.INITIALIZING]: "Starting",
17
17
  [STATES.STARTING]: "Starting",
18
18
  [STATES.RUNNING]: "Working",
19
19
  [STATES.WAITING]: "Needs Input",
20
20
  [STATES.IDLE]: "Idle",
21
- [STATES.COMPLETE]: "Complete",
21
+ [STATES.COMPLETE]: "Idle",
22
22
  [STATES.DONE]: "Exited",
23
23
  [STATES.FAILED]: "Failed"
24
24
  });
25
- Object.freeze({
26
- [STATES.DORMANT]: "○",
27
- [STATES.INITIALIZING]: "◴",
28
- [STATES.STARTING]: "◐",
29
- [STATES.RUNNING]: "●",
30
- [STATES.WAITING]: "◆",
31
- [STATES.IDLE]: "◎",
32
- [STATES.FAILED]: "▲",
33
- [STATES.DONE]: "■",
34
- [STATES.COMPLETE]: "◇"
35
- });
36
25
  var KILLABLE_STATES = Object.freeze([
37
26
  STATES.INITIALIZING,
38
27
  STATES.STARTING,
@@ -60,6 +49,10 @@ var githubPollingShape = {
60
49
  isRefreshing: z.boolean().optional(),
61
50
  refreshNotice: z.string().nullable().optional()
62
51
  };
52
+ var GithubPrsFreshness = z.strictObject({
53
+ lastRefreshedAt: z.number().finite().nonnegative().nullable(),
54
+ error: z.string().nullable()
55
+ });
63
56
  var GithubPollingRefreshRequest = z.object({ lane: z.enum([
64
57
  "my-prs",
65
58
  "team-review",
@@ -67,7 +60,8 @@ var GithubPollingRefreshRequest = z.object({ lane: z.enum([
67
60
  ]) });
68
61
  var GithubPollingRefreshResult = z.object({
69
62
  ok: z.boolean(),
70
- error: z.string().optional()
63
+ error: z.string().optional(),
64
+ freshness: GithubPrsFreshness.optional()
71
65
  });
72
66
  //#endregion
73
67
  //#region shared/contracts/github-ids.ts
@@ -92,20 +86,6 @@ function shortSha(sha, { chars = 7, validate = false } = {}) {
92
86
  //#region shared/contracts/team-review.ts
93
87
  var CommitSha = z.string().regex(FULL_SHA_RE);
94
88
  var repoSlug = z.string().regex(/^[^/]+\/[^/]+$/);
95
- var SearchedPr = z.object({
96
- number: z.number().int().positive(),
97
- title: z.string(),
98
- html_url: z.string(),
99
- draft: z.boolean().optional(),
100
- created_at: z.string().optional(),
101
- updated_at: z.string().optional(),
102
- repository_url: z.string(),
103
- user: z.object({
104
- login: z.string(),
105
- type: z.enum(["User", "Bot"])
106
- }).passthrough(),
107
- pull_request: z.object({}).passthrough()
108
- }).passthrough();
109
89
  var PrDetail = z.object({
110
90
  number: z.number().int().positive(),
111
91
  title: z.string(),
@@ -115,6 +95,11 @@ var PrDetail = z.object({
115
95
  login: z.string(),
116
96
  is_bot: z.boolean().optional()
117
97
  }).passthrough(),
98
+ state: z.enum([
99
+ "OPEN",
100
+ "CLOSED",
101
+ "MERGED"
102
+ ]).optional(),
118
103
  isDraft: z.boolean(),
119
104
  isCrossRepository: z.boolean(),
120
105
  baseRefName: z.string(),
@@ -241,6 +226,12 @@ var PriorReview = z.object({
241
226
  comments: z.array(ReviewComment),
242
227
  wasPosted: z.boolean()
243
228
  });
229
+ var EarlierReview = PriorReview.pick({
230
+ head: true,
231
+ verdict: true,
232
+ summary: true,
233
+ wasPosted: true
234
+ }).extend({ comments: z.array(DraftComment) });
244
235
  var ReviewThreadId = z.string().min(1).max(256).regex(NODE_ID_RE);
245
236
  var TeamReviewThreadResult = z.object({
246
237
  addressed: z.boolean(),
@@ -361,7 +352,8 @@ var ReviewDraft = z.object({
361
352
  postedAt: z.number().finite().optional(),
362
353
  postedEvent: PostedReviewEvent.optional(),
363
354
  priorReviewedHead: CommitSha.optional(),
364
- requeuedHead: CommitSha.optional()
355
+ requeuedHead: CommitSha.optional(),
356
+ earlierReview: EarlierReview.optional()
365
357
  });
366
358
  function canApproveAfterComment(draft) {
367
359
  return draft.status === "posted" && draft.postedEvent === "COMMENT";
@@ -435,6 +427,7 @@ var TeamReviewStateEntry = z.object({
435
427
  requeuedHead: CommitSha.optional(),
436
428
  priorReview: PriorReview.optional(),
437
429
  discardedReviewHead: CommitSha.optional(),
430
+ requestedAt: z.number().finite().optional(),
438
431
  updatedAt: z.number().finite()
439
432
  });
440
433
  z.record(z.string(), TeamReviewStateEntry);
@@ -673,6 +666,16 @@ var MyPr = z.object({
673
666
  isMergeQueueHeldForRepairPush: z.boolean().optional(),
674
667
  mergeQueueFailure: MyPrMergeQueueFailure.optional()
675
668
  }).refine((pr) => pr.key === `${pr.repo}#${pr.number}`);
669
+ var MyPrLaneEntry = z.strictObject({
670
+ key: pullRequestKey,
671
+ autoRebase: MyPr.shape.autoRebase,
672
+ keepMergeable: MyPr.shape.keepMergeable,
673
+ keepMergeableAttempt: MyPr.shape.keepMergeableAttempt,
674
+ isKeepMergeableFixInFlight: MyPr.shape.isKeepMergeableFixInFlight,
675
+ mergeQueuePosition: MyPr.shape.mergeQueuePosition,
676
+ isMergeQueueHeldForRepairPush: MyPr.shape.isMergeQueueHeldForRepairPush,
677
+ mergeQueueFailure: MyPr.shape.mergeQueueFailure
678
+ });
676
679
  var MyPrsStatus = z.object({
677
680
  ...githubPollingShape,
678
681
  type: z.literal("my-prs-status"),
@@ -680,11 +683,12 @@ var MyPrsStatus = z.object({
680
683
  configured: z.boolean(),
681
684
  reason: z.string().nullable().optional(),
682
685
  viewer: z.string().nullable(),
683
- prs: z.array(MyPr),
686
+ prs: z.array(MyPrLaneEntry),
684
687
  truncatedNote: z.string().nullable().optional(),
685
688
  isKeepMergeableEnabled: z.boolean().optional(),
686
689
  isMergeQueueEnabled: z.boolean().optional()
687
690
  }).passthrough();
691
+ var MyPrsSnapshot = MyPrsStatus.extend({ prs: z.array(MyPr) });
688
692
  var MyPrMergeRequest = z.object({
689
693
  repo: repositoryName,
690
694
  number: z.number().int().positive(),
@@ -842,7 +846,7 @@ var MyPrMergeStateResponse = z.object({
842
846
  }).nullable() }).nullable() }),
843
847
  errors: z.array(z.unknown()).optional()
844
848
  });
845
- var MyPrSearchResponse = z.object({
849
+ z.object({
846
850
  data: z.object({
847
851
  open: z.object({
848
852
  issueCount: nonnegativeInteger,
@@ -859,7 +863,10 @@ var SESSION_NAME_PATTERN = /^[a-zA-Z0-9_\-. ()]{1,64}$/;
859
863
  var SESSION_NAME_RULE_TEXT = "Session name may only contain letters, numbers, spaces, dashes, dots, underscores, and parentheses (max 64 chars)";
860
864
  var TASK_TITLE_CONTROL_CHARACTERS = /[\x00-\x1f\x7f-\x9f]/;
861
865
  var TaskTitle = z.string().refine((title) => !TASK_TITLE_CONTROL_CHARACTERS.test(title)).trim().max(120);
862
- var RefinedTaskTitle = z.object({ title: z.string().nullable() }).strict();
866
+ var RefinedTaskTitle = z.object({
867
+ title: z.string().nullable(),
868
+ name: z.string().nullable().optional()
869
+ }).strict();
863
870
  var SessionState = z.enum(STATES);
864
871
  var PendingWakeup = z.object({
865
872
  at: z.number().finite().nullable(),
@@ -964,14 +971,19 @@ var SshSignReply = z.union([z.object({
964
971
  ok: z.literal(false),
965
972
  error: z.string()
966
973
  }).strict()]);
967
- var AGENT_API_VERBS = [
974
+ var SESSION_COMMANDS = [
975
+ "push",
968
976
  "spawn",
969
977
  "attention",
970
978
  "board",
971
- "push",
972
979
  "edit",
973
- "limits"
980
+ "review",
981
+ "reviews",
982
+ "prs",
983
+ "link-pr",
984
+ "settings"
974
985
  ];
986
+ var AGENT_API_VERBS = [...SESSION_COMMANDS, "limits"];
975
987
  var AgentSpawnRequest = z.object({
976
988
  prompt: z.string({ error: "prompt must be a string" }).min(1, { error: "prompt must not be empty" }).max(2e4, { error: "prompt must be at most 20000 characters" }).refine((prompt) => !prompt.trimStart().startsWith("-"), { message: "prompt must not start with a dash, which the agent CLI would read as an option" }),
977
989
  name: z.string({ error: "name must be a string" }).min(1, { error: "name must not be empty" }).max(200, { error: "name must be at most 200 characters" }).optional(),
@@ -992,6 +1004,61 @@ z.object({
992
1004
  state: SessionSnapshot.shape.state,
993
1005
  ephemeral: SessionSnapshot.shape.ephemeral
994
1006
  }).strict();
1007
+ var AgentPullRequestRequest = z.object({ pr: z.string({ error: "pr must be a string" }).min(1, { error: "pr must not be empty" }).max(300, { error: "pr must be at most 300 characters" }) }).strict();
1008
+ var AgentSettingsRequest = z.object({
1009
+ command: z.enum(["list", "get"], { error: "command must be list or get" }),
1010
+ path: z.string({ error: "path must be a string" }).min(1, { error: "path must not be empty" }).max(200, { error: "path must be at most 200 characters" }).optional()
1011
+ }).strict();
1012
+ var AgentSettingsReply = z.union([z.object({
1013
+ ok: z.literal(true),
1014
+ text: z.string(),
1015
+ readout: z.unknown()
1016
+ }).strict(), z.object({
1017
+ ok: z.literal(false),
1018
+ error: z.string()
1019
+ }).strict()]);
1020
+ var PullRequestIdentity = QueuedReview.pick({
1021
+ key: true,
1022
+ title: true,
1023
+ url: true,
1024
+ author: true
1025
+ });
1026
+ z.object({
1027
+ ok: z.literal(true),
1028
+ configured: z.boolean(),
1029
+ reason: z.string().nullable(),
1030
+ reviewing: z.array(PullRequestIdentity.extend({ phase: InFlightReview.shape.phase })),
1031
+ queued: z.array(PullRequestIdentity),
1032
+ drafts: z.array(PullRequestIdentity.extend({
1033
+ status: ReviewDraft.shape.status,
1034
+ verdict: z.string(),
1035
+ summary: ReviewDraft.shape.summary,
1036
+ comments: z.number().int().nonnegative(),
1037
+ isOutOfDate: z.boolean()
1038
+ }))
1039
+ }).strict();
1040
+ z.object({
1041
+ ok: z.literal(true),
1042
+ configured: z.boolean(),
1043
+ prs: z.array(z.object({
1044
+ key: MyPr.shape.key,
1045
+ title: MyPr.shape.title,
1046
+ url: MyPr.shape.url,
1047
+ state: MyPr.shape.state,
1048
+ isDraft: MyPr.shape.isDraft,
1049
+ stage: MyPr.shape.stage,
1050
+ reviewDecision: MyPr.shape.reviewDecision,
1051
+ approvals: MyPr.shape.approvals,
1052
+ unresolvedThreads: MyPr.shape.unresolvedThreads,
1053
+ behindBy: MyPr.shape.behindBy,
1054
+ mergeable: MyPr.shape.mergeable,
1055
+ isInMergeQueue: MyPr.shape.isInMergeQueue,
1056
+ checks: MyPr.shape.checks.pick({
1057
+ state: true,
1058
+ failing: true
1059
+ })
1060
+ }).strict())
1061
+ }).strict();
995
1062
  var SESSION_DOC_BODY_CAP_BYTES = 262144;
996
1063
  var SESSION_DOC_PATH_MAX_CHARS = 4096;
997
1064
  var AgentEditRequest = z.object({ path: z.string({ error: "path must be a string" }).min(1, { error: "path must not be empty" }).max(SESSION_DOC_PATH_MAX_CHARS, { error: `path must be at most ${SESSION_DOC_PATH_MAX_CHARS} characters` }) }).strict();
@@ -1000,13 +1067,6 @@ var SessionDoc = z.object({
1000
1067
  name: z.string(),
1001
1068
  surfacedAt: z.number().finite()
1002
1069
  }).strict();
1003
- var SESSION_COMMANDS = [
1004
- "push",
1005
- "spawn",
1006
- "attention",
1007
- "board",
1008
- "edit"
1009
- ];
1010
1070
  var AgentLimitsReply = z.object({
1011
1071
  commands: z.array(z.object({
1012
1072
  name: z.enum(SESSION_COMMANDS),
@@ -1020,4 +1080,4 @@ var AgentLimitsReply = z.object({
1020
1080
  }).strict())
1021
1081
  }).strict().extend({ ok: z.literal(true) }).strict();
1022
1082
  //#endregion
1023
- export { CommitSha as $, SshSignRequest as A, shortSha as At, MyPrMergeRequest as B, RESTARTABLE_STATES as Bt, SESSION_NAME_RULE_TEXT as C, TeamReviewThreadsRepository as Ct, SessionSnapshot as D, hasStandingViewerApproval as Dt, SessionDoc as E, hasRequiredActionHead as Et, MyPrCheckContext as F, GithubPollingRefreshRequest as Ft, MyPrSearchNode as G, MyPrMergeStateResponse as H, MyPrCheckContextsResponse as I, GithubPollingRefreshResult as It, MyPrThreadsResponse as J, MyPrSearchResponse as K, MyPrKeepMergeableRequest as L, githubPollingShape as Lt, TaskTitle as M, NODE_ID_RE as Mt, LinkedPr as N, REPO_SLUG_RE as Nt, SessionState as O, FULL_SHA_RE as Ot, MyPrAutoRebase as P, repoParts as Pt, repositoryName as Q, MyPrKeepMergeableResult as R, KILLABLE_STATES as Rt, SESSION_NAME_PATTERN as S, TeamReviewThreadResult as St, SSH_SIGN_BODY_CAP_BYTES as T, decisionAsIfApprovalRequired as Tt, MyPrMergeWhenReadyRequest as U, MyPrMergeResult as V, STATES as Vt, MyPrMergeWhenReadyResult as W, MyPrsStatus as X, MyPrsState as Y, SessionPrLinks as Z, PendingWakeup as _, TeamReviewCompareFiles as _t, AgentEditRequest as a, PrDetail as at, SESSION_DOC_BODY_CAP_BYTES as b, TeamReviewStatus as bt, COHERENCE_HOOKS_INACTIVE as c, ReviewComment as ct, CONVERSATION_TOOL_RESULT_HOOK_EVENT as d, ReviewResult as dt, DECIDING_REVIEW_STATES as et, CoherenceHooksState as f, ReviewThreadId as ft, ConversationQuestion as g, TeamReviewActionResult as gt, ConversationApprovalDecision as h, TeamReviewActionRequest as ht, AgentAttentionRequest as i, PostingPlan as it, TASK_TITLE_CONTROL_CHARACTERS as j, GH_SEGMENT as jt, SshSignReply as k, HEX_SHA_RE as kt, CONVERSATION_APPROVAL_SUMMARY_MAX_CHARS as l, ReviewDraft as lt, ConversationApproval as m, SearchedPr as mt, AGENT_URL_ENV as n, GithubReviewDecision as nt, AgentLimitsReply as o, QueuedReview as ot, ConversationAnswers as p, ReviewVerdict as pt, MyPrThreadNode as q, ASK_USER_QUESTION_TOOL_NAME as r, GithubReviewState as rt, AgentSpawnRequest as s, ReviewChecksState as st, AGENT_API_VERBS as t, FindingSeverity as tt, CONVERSATION_PERMISSION_HOOK_EVENT as u, ReviewFinding as ut, RefinedTaskTitle as v, TeamReviewResolveResponse as vt, SIGN_URL_ENV as w, canApproveAfterComment as wt, SESSION_DOC_PATH_MAX_CHARS as x, TeamReviewThreadCommentsResponse as xt, SESSION_COMMANDS as y, TeamReviewStateEntry as yt, MyPrMergeMethod as z, MERGEABLE_LIVE_STATES as zt };
1083
+ export { MyPrsSnapshot as $, SessionSnapshot as A, canApproveAfterComment as At, MyPrCheckContextsResponse as B, repoParts as Bt, SESSION_DOC_BODY_CAP_BYTES as C, TeamReviewCompareFiles as Ct, SIGN_URL_ENV as D, TeamReviewThreadCommentsResponse as Dt, SESSION_NAME_RULE_TEXT as E, TeamReviewStatus as Et, TaskTitle as F, HEX_SHA_RE as Ft, MyPrMergeRequest as G, KILLABLE_STATES as Gt, MyPrKeepMergeableResult as H, GithubPollingRefreshResult as Ht, LinkedPr as I, shortSha as It, MyPrMergeWhenReadyRequest as J, STATES as Jt, MyPrMergeResult as K, MERGEABLE_LIVE_STATES as Kt, MyPr as L, GH_SEGMENT as Lt, SshSignReply as M, hasRequiredActionHead as Mt, SshSignRequest as N, hasStandingViewerApproval as Nt, SSH_SIGN_BODY_CAP_BYTES as O, TeamReviewThreadResult as Ot, TASK_TITLE_CONTROL_CHARACTERS as P, FULL_SHA_RE as Pt, MyPrThreadsResponse as Q, MyPrAutoRebase as R, NODE_ID_RE as Rt, SESSION_COMMANDS as S, TeamReviewActionResult as St, SESSION_NAME_PATTERN as T, TeamReviewStateEntry as Tt, MyPrLaneEntry as U, GithubPrsFreshness as Ut, MyPrKeepMergeableRequest as V, GithubPollingRefreshRequest as Vt, MyPrMergeMethod as W, githubPollingShape as Wt, MyPrSearchNode as X, MyPrMergeWhenReadyResult as Y, MyPrThreadNode as Z, ConversationApproval as _, ReviewFinding as _t, AgentEditRequest as a, CommitSha as at, PendingWakeup as b, ReviewVerdict as bt, AgentSettingsReply as c, FindingSeverity as ct, COHERENCE_HOOKS_INACTIVE as d, PostingPlan as dt, MyPrsState as et, CONVERSATION_APPROVAL_SUMMARY_MAX_CHARS as f, PrDetail as ft, ConversationAnswers as g, ReviewDraft as gt, CoherenceHooksState as h, ReviewComment as ht, AgentAttentionRequest as i, repositoryName as it, SessionState as j, decisionAsIfApprovalRequired as jt, SessionDoc as k, TeamReviewThreadsRepository as kt, AgentSettingsRequest as l, GithubReviewDecision as lt, CONVERSATION_TOOL_RESULT_HOOK_EVENT as m, ReviewChecksState as mt, AGENT_URL_ENV as n, SessionPrLinks as nt, AgentLimitsReply as o, DECIDING_REVIEW_STATES as ot, CONVERSATION_PERMISSION_HOOK_EVENT as p, QueuedReview as pt, MyPrMergeStateResponse as q, RESTARTABLE_STATES as qt, ASK_USER_QUESTION_TOOL_NAME as r, pullRequestKeyFormat as rt, AgentPullRequestRequest as s, EarlierReview as st, AGENT_API_VERBS as t, MyPrsStatus as tt, AgentSpawnRequest as u, GithubReviewState as ut, ConversationApprovalDecision as v, ReviewResult as vt, SESSION_DOC_PATH_MAX_CHARS as w, TeamReviewResolveResponse as wt, RefinedTaskTitle as x, TeamReviewActionRequest as xt, ConversationQuestion as y, ReviewThreadId as yt, MyPrCheckContext as z, REPO_SLUG_RE as zt };
@@ -1,4 +1,4 @@
1
- import { y as SESSION_COMMANDS } from "./session-D2EbiysG.js";
1
+ import { S as SESSION_COMMANDS } from "./session-BwB43SCa.js";
2
2
  //#region session/core/session-routes.ts
3
3
  var SUPERVISION_LINE = "Glimmervoid supervises this session. Run glimmervoid --help for the commands it gives you and this session's limits.";
4
4
  var GUARDRAILS_LINE = "Its guardrails are OS-enforced, so a read, write or connection they refuse will not succeed on retry.";
@@ -70,12 +70,32 @@ function editRoute(caller) {
70
70
  reason: "a lane session cannot surface a file, because it has no card for the operator to open the file from"
71
71
  };
72
72
  }
73
+ function operatorStateRoute(caller) {
74
+ if (hasOperatorCard(caller)) return ANSWERS;
75
+ return {
76
+ answers: false,
77
+ reason: "a lane session cannot read or queue the operator's reviews, pull requests or settings, because a lane runs on input the operator has not vetted"
78
+ };
79
+ }
80
+ function linkPrRoute(caller) {
81
+ if (hasOperatorCard(caller)) return ANSWERS;
82
+ return {
83
+ answers: false,
84
+ reason: "a lane session cannot link a pull request, because it has no card to show the link on"
85
+ };
86
+ }
73
87
  var COMMAND_ROUTES = Object.freeze({
74
88
  push: pushRoute,
75
89
  spawn: spawnRoute,
76
90
  attention: attentionRoute,
77
91
  board: () => ANSWERS,
78
- edit: editRoute
92
+ edit: editRoute,
93
+ review: operatorStateRoute,
94
+ reviews: operatorStateRoute,
95
+ prs: operatorStateRoute,
96
+ "link-pr": linkPrRoute,
97
+ settings: operatorStateRoute,
98
+ limits: () => ANSWERS
79
99
  });
80
100
  function commandLimit(name, facts) {
81
101
  const verdict = COMMAND_ROUTES[name](facts);
@@ -119,4 +139,4 @@ function formatSessionLimits({ commands, guarded, deadEnds }) {
119
139
  ];
120
140
  }
121
141
  //#endregion
122
- export { formatSessionLimits as a, spawnRoute as c, editRoute as i, supervisionLine as l, attentionRoute as n, permitsHelpCommand as o, describeSessionLimits as r, pushRoute as s, NO_OWN_WORKTREE_REASON as t };
142
+ export { permitsHelpCommand as a, formatSessionLimits as i, NO_OWN_WORKTREE_REASON as n, supervisionLine as o, describeSessionLimits as r, COMMAND_ROUTES as t };
@@ -1,10 +1,11 @@
1
1
  import { r as errorMessage, t as errorCode } from "./text-DoirglWV.js";
2
- import "./session-D2EbiysG.js";
2
+ import { c as AgentSettingsReply } from "./session-BwB43SCa.js";
3
3
  import { t as renderTable } from "./ascii-figure-core-pDAwtlKO.js";
4
4
  import { n as glimmervoidHomeDir, t as decideConfigPath } from "./config-path-core-DFt-TemS.js";
5
5
  import { n as isRecord } from "./coerce-NSst8oRP.js";
6
- import { A as settingsOf, C as deleteValueAtPath, D as scoreSettingsSearch, E as parsePosthogProjectSelection, M as FILE_ONLY_GROUPS, N as SETTINGS_REGISTRY, O as setValueAtPath, Q as withEnvSecrets, S as cloneValue, T as hasScaledUnit, X as readEnvSecrets, Y as ENV_SECRET_BINDINGS, j as valueAtPath, k as settingsGroupOf, l as saveConfigFileOnce, s as loadConfigFile, u as validateConfig, w as displayText, x as SETTINGS_INDEX } from "./config-store-n23JDU4E.js";
7
- import { Q as BrowserConfig } from "./contracts-DYQW11de.js";
6
+ import { C as deleteValueAtPath, D as scoreSettingsSearch, E as parsePosthogProjectSelection, N as SETTINGS_REGISTRY, O as setValueAtPath, Q as withEnvSecrets, S as cloneValue, X as readEnvSecrets, Y as ENV_SECRET_BINDINGS, j as valueAtPath, l as saveConfigFileOnce, s as loadConfigFile, u as validateConfig } from "./config-store-DqMScSdg.js";
7
+ import { p as BrowserConfig } from "./contracts-CloExMlS.js";
8
+ import { a as fail, c as listSettings, d as renderSectionTables, f as requireConfigFileSetting, g as valueText, h as succeed, i as describeSetting, l as readSetting, m as settingsRequestForServer, n as configFileViewOf, o as fitColumn, p as sectionOf, r as defaultText, s as getSetting, t as ALL_SETTINGS } from "./settings-readout-core-DrXT4aWm.js";
8
9
  import fs from "node:fs";
9
10
  import os from "node:os";
10
11
  import { parseArgs } from "node:util";
@@ -25,132 +26,12 @@ var usage = `glimmervoid settings: read and change config.json from the command
25
26
  A secret (a bot token or API key) is never set or unset here, since a value on the command line lands in shell history;
26
27
  change it in the dashboard settings or through its environment variable.
27
28
  --json machine-readable output`;
28
- var VALUE_COLUMN_WIDTH = 40;
29
29
  var EFFECT_NOTES = Object.freeze({
30
30
  now: "A running Glimmervoid applies it without a restart.",
31
31
  "new-sessions": "Sessions started after this change use it.",
32
32
  restart: "Restart Glimmervoid to apply it."
33
33
  });
34
34
  var HAND_EDITED_SETTING_REASONS = /* @__PURE__ */ new Map([["port", "a listener port that clashes with remote.port stops Glimmervoid from starting"]]);
35
- var SECTION_BY_SETTING_ID = new Map([...SETTINGS_REGISTRY.sections.flatMap((section) => section.settings.map((setting) => [setting.id, {
36
- id: section.id,
37
- title: section.title
38
- }])), ...SETTINGS_REGISTRY.fileOnly.map((setting) => {
39
- const groupId = setting.group ?? "";
40
- return [setting.id, {
41
- id: groupId,
42
- title: settingsGroupOf(groupId)?.title ?? groupId
43
- }];
44
- })]);
45
- var ALL_SETTINGS = [...settingsOf(SETTINGS_REGISTRY.sections), ...SETTINGS_REGISTRY.fileOnly];
46
- var SECTION_ORDER = [...SETTINGS_REGISTRY.sections.map((section) => ({
47
- id: section.id,
48
- title: section.title
49
- })), ...Object.entries(FILE_ONLY_GROUPS).map(([id, group]) => ({
50
- id,
51
- title: group.title
52
- }))];
53
- function fail(message) {
54
- return {
55
- ok: false,
56
- message
57
- };
58
- }
59
- function succeed(value) {
60
- return {
61
- ok: true,
62
- value
63
- };
64
- }
65
- function isConfigFileSetting(setting) {
66
- return setting.scope === "machine" && setting.control !== "readonly";
67
- }
68
- function sectionOf(setting) {
69
- return SECTION_BY_SETTING_ID.get(setting.id) ?? {
70
- id: "",
71
- title: ""
72
- };
73
- }
74
- function describeSetting(setting) {
75
- const descriptor = {
76
- id: setting.id,
77
- path: setting.path,
78
- title: setting.title,
79
- description: setting.description,
80
- type: setting.control,
81
- scope: setting.scope,
82
- access: setting.access,
83
- effect: setting.takesEffect,
84
- default: cloneValue(setting.defaultValue) ?? null,
85
- unit: setting.unit?.storedLabel ?? setting.unit?.label ?? null,
86
- displayUnit: setting.unit?.label ?? null,
87
- storedPerDisplay: setting.unit?.storedPerDisplay ?? 1,
88
- section: sectionOf(setting)
89
- };
90
- if (setting.options) descriptor.options = setting.options.map((option) => option.value);
91
- if (setting.range) descriptor.range = setting.range;
92
- if (setting.fileOnlyReason) descriptor.fileOnlyReason = setting.fileOnlyReason;
93
- return descriptor;
94
- }
95
- function isStoredSecret(value) {
96
- return typeof value === "string" && value.length > 0;
97
- }
98
- function readSetting(setting, view) {
99
- const stored = valueAtPath(view.config, setting.path);
100
- const source = view.secretSources[setting.path] ?? (stored !== void 0 ? "config.json" : "default");
101
- const readout = {
102
- ...describeSetting(setting),
103
- secret: setting.control === "password",
104
- source
105
- };
106
- if (readout.secret) {
107
- readout.configured = isStoredSecret(stored);
108
- return readout;
109
- }
110
- readout.value = stored !== void 0 ? cloneValue(stored) : readout.default;
111
- return readout;
112
- }
113
- function fitColumn(text) {
114
- if (text.length <= VALUE_COLUMN_WIDTH) return text;
115
- return `${text.slice(0, 37)}...`;
116
- }
117
- function storedValueText(setting, value) {
118
- if (setting.valueKind) return displayText(setting, value);
119
- const stored = JSON.stringify(value ?? null);
120
- if (typeof value !== "number" || !hasScaledUnit(setting)) return stored;
121
- return `${stored} (${displayText(setting, value)})`;
122
- }
123
- function valueText(readout, setting) {
124
- if (readout.secret) return readout.configured ? "configured" : "not configured";
125
- return storedValueText(setting, readout.value);
126
- }
127
- function defaultText(setting) {
128
- return storedValueText(setting, setting.defaultValue);
129
- }
130
- function settingsBySection(settings) {
131
- return SECTION_ORDER.map((section) => ({
132
- section,
133
- settings: settings.filter((setting) => sectionOf(setting).id === section.id)
134
- })).filter((group) => group.settings.length > 0);
135
- }
136
- function renderSectionTables(settings, headers, rowOf) {
137
- return settingsBySection(settings).map(({ section, settings: grouped }) => renderTable({
138
- title: section.title,
139
- headers,
140
- rows: grouped.map(rowOf),
141
- align: headers.map(() => "left")
142
- })).join("\n\n");
143
- }
144
- function resolveSetting(argument) {
145
- return SETTINGS_INDEX.byPath.get(argument) ?? SETTINGS_INDEX.byId.get(argument) ?? null;
146
- }
147
- function requireConfigFileSetting(argument, configPath) {
148
- const setting = resolveSetting(argument);
149
- if (!setting) return fail(`${argument} is not a setting in the registry, so this command cannot read or change it; edit config.json at ${configPath} by hand`);
150
- if (setting.scope === "browser") return fail(`${setting.id} is a browser preference saved in each browser, not in config.json; change it in the dashboard under Settings > ${sectionOf(setting).title}`);
151
- if (setting.control === "readonly") return fail(`${setting.id} is a read-only status row under Settings > ${sectionOf(setting).title}; it has no config.json key`);
152
- return succeed(setting);
153
- }
154
35
  function requirePositional(positionals, index, name) {
155
36
  const value = positionals[index];
156
37
  if (value === void 0) throw new Error(`missing <${name}>\n\n${usage}`);
@@ -284,12 +165,7 @@ function openConfigFile() {
284
165
  if (!decided.path) return fail(`no config.json at ${decided.homePath}. Start Glimmervoid once to create it; glimmervoid settings schema needs no config file`);
285
166
  const loaded = readConfigFile(decided.path, homeDir);
286
167
  if (!loaded.ok) return fail(loaded.message);
287
- const secretSources = Object.fromEntries(readEnvSecrets(env).map((secret) => [`${secret.blockName}.${secret.secretKey}`, secret.environmentVariable]));
288
- return succeed({
289
- configPath: decided.path,
290
- config: loaded.value,
291
- secretSources
292
- });
168
+ return succeed(configFileViewOf(decided.path, loaded.value, env));
293
169
  }
294
170
  function print(context, jsonValue, text) {
295
171
  context.writeOutput(`${context.isJson ? JSON.stringify(jsonValue, null, 2) : text}\n`);
@@ -324,35 +200,13 @@ function requireWritableSetting(context, view) {
324
200
  }
325
201
  var commands = {
326
202
  list: (context) => {
327
- const view = requireView();
328
- const settings = ALL_SETTINGS.filter(isConfigFileSetting);
329
- const readouts = settings.map((setting) => readSetting(setting, view));
330
- const readoutById = new Map(readouts.map((readout) => [readout.id, readout]));
331
- const rowOf = (setting) => {
332
- const readout = readoutById.get(setting.id);
333
- if (!readout) return [
334
- setting.path,
335
- "",
336
- ""
337
- ];
338
- return [
339
- setting.path,
340
- fitColumn(valueText(readout, setting)),
341
- readout.source
342
- ];
343
- };
344
- return print(context, readouts, renderSectionTables(settings, [
345
- "Setting",
346
- "Value",
347
- "Source"
348
- ], rowOf));
203
+ const report = listSettings(requireView());
204
+ return print(context, report.readout, report.text);
349
205
  },
350
206
  get: (context) => {
351
207
  const view = requireView();
352
- const setting = requireSetting(context, view);
353
- const readout = readSetting(setting, view);
354
- const sourceNote = readout.secret && !readout.configured ? "" : ` (${readout.source})`;
355
- return print(context, readout, `${setting.path} = ${valueText(readout, setting)}${sourceNote}`);
208
+ const report = getSetting(view, requireSetting(context, view));
209
+ return print(context, report.readout, report.text);
356
210
  },
357
211
  set: (context) => {
358
212
  const view = requireView();
@@ -472,6 +326,26 @@ function processIo() {
472
326
  writeError: (text) => process.stderr.write(text)
473
327
  };
474
328
  }
329
+ async function runSettingsCli(commandArguments, io = processIo()) {
330
+ const serverRequest = settingsRequestForServer(commandArguments, process.env);
331
+ if (!serverRequest) return runSettingsCommand(commandArguments, io);
332
+ const { askAgentApi } = await import("./agent-api-cli-BBech5lF.js");
333
+ const reply = AgentSettingsReply.safeParse(await askAgentApi("settings", serverRequest).catch((error) => ({
334
+ ok: false,
335
+ error: errorMessage(error)
336
+ })));
337
+ if (!reply.success) {
338
+ io.writeError("settings: Glimmervoid sent a reply this command cannot read\n");
339
+ return 1;
340
+ }
341
+ if (!reply.data.ok) {
342
+ io.writeError(`settings: ${reply.data.error}\n`);
343
+ return 1;
344
+ }
345
+ const isJson = commandArguments.includes("--json");
346
+ io.writeOutput(`${isJson ? JSON.stringify(reply.data.readout, null, 2) : reply.data.text}\n`);
347
+ return 0;
348
+ }
475
349
  function runSettingsCommand(commandArguments, io = processIo()) {
476
350
  try {
477
351
  return runCommandLine(commandArguments, io);
@@ -481,4 +355,4 @@ function runSettingsCommand(commandArguments, io = processIo()) {
481
355
  }
482
356
  }
483
357
  //#endregion
484
- export { runSettingsCommand };
358
+ export { runSettingsCli };