nolo-cli 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (183) hide show
  1. package/_executeModel-UD44KGZ4.js +203 -0
  2. package/action-ZJWE3Y5S.js +28 -0
  3. package/addContentAction-TVDBNJM5.js +26 -0
  4. package/addDialogAgentAction-EKH774VT.js +68 -0
  5. package/agentDeleteCommand-TCPEFJTF.js +327 -0
  6. package/agentEmailCommands-CZ3UILZ4.js +626 -0
  7. package/agentListCommands-SJKO2FFB.js +223 -0
  8. package/agentMachineCommands-PSNABISZ.js +425 -0
  9. package/agentPullCommand-O2MTUAFR.js +122 -0
  10. package/agentRecordCommands-MH2JKFHS.js +94 -0
  11. package/agentRunCommand-4KH6MIZR.js +110 -0
  12. package/agentRunControl-K4VKNEHF.js +57 -0
  13. package/agentRuntimeLocal-SKHJUWSS.js +104 -0
  14. package/agentSlice-3WXXN4VK.js +42 -0
  15. package/authCommand-PXFX6JDT.js +581 -0
  16. package/authCommands-356AYWEK.js +35 -0
  17. package/chunk-2EISRLRC.js +238 -0
  18. package/chunk-2FTTDCD4.js +675 -0
  19. package/chunk-2K2ECKSG.js +222 -0
  20. package/chunk-2PUGVR6E.js +19 -0
  21. package/chunk-3ASDTTEI.js +1774 -0
  22. package/chunk-3EUW3WEO.js +8 -0
  23. package/chunk-3LY4F7SV.js +9293 -0
  24. package/chunk-3TZDXYSF.js +71 -0
  25. package/chunk-3WYQEUBI.js +34 -0
  26. package/chunk-4CQLVGRV.js +50 -0
  27. package/chunk-4IJYA27C.js +342 -0
  28. package/chunk-4K2KKCSD.js +577 -0
  29. package/chunk-4SN6J65J.js +38 -0
  30. package/chunk-4VNS5WPM.js +42 -0
  31. package/chunk-4ZDM73SD.js +34 -0
  32. package/chunk-5CS33IBL.js +301 -0
  33. package/chunk-5KLGBAAR.js +386 -0
  34. package/chunk-5MIDPSSK.js +206 -0
  35. package/chunk-5MMAK75Q.js +15 -0
  36. package/chunk-5PJ3VWCS.js +360 -0
  37. package/chunk-63SLEOLK.js +175 -0
  38. package/chunk-63W5N6P3.js +150 -0
  39. package/chunk-6GANEXVO.js +231 -0
  40. package/chunk-6HYVJV7B.js +102 -0
  41. package/chunk-6WD3OOJS.js +20 -0
  42. package/chunk-7OOXPE3N.js +628 -0
  43. package/chunk-7QRKCBOP.js +1078 -0
  44. package/chunk-ATNTHIZI.js +13 -0
  45. package/chunk-AUQ747NZ.js +902 -0
  46. package/chunk-AVMKZHBC.js +85 -0
  47. package/chunk-AZPCASRE.js +36 -0
  48. package/chunk-BBYVOSU2.js +792 -0
  49. package/chunk-C3RUNRHT.js +51 -0
  50. package/chunk-CF2WZF4N.js +134 -0
  51. package/chunk-CF7PE763.js +10 -0
  52. package/chunk-CKOJQDKR.js +198 -0
  53. package/chunk-COMXDWNM.js +807 -0
  54. package/chunk-CPB2YM4D.js +171 -0
  55. package/chunk-CWMSB67P.js +34 -0
  56. package/chunk-DCOA4QSN.js +105 -0
  57. package/chunk-DFFIZ25G.js +30 -0
  58. package/chunk-DWLEOOGR.js +8 -0
  59. package/chunk-DZ3XJVET.js +231 -0
  60. package/chunk-EHLHSX7R.js +1433 -0
  61. package/chunk-ELRRLDWI.js +478 -0
  62. package/chunk-EXTIQUCI.js +482 -0
  63. package/chunk-EYEEHCU4.js +3066 -0
  64. package/chunk-G3SUCT4W.js +8 -0
  65. package/chunk-G43KEVSC.js +1447 -0
  66. package/chunk-GAKEBQD6.js +30 -0
  67. package/chunk-GBRG75BQ.js +86 -0
  68. package/chunk-GG4AJPSR.js +191 -0
  69. package/chunk-H33743XH.js +25 -0
  70. package/chunk-HNMXYYJR.js +12 -0
  71. package/chunk-I42VC5KR.js +15 -0
  72. package/chunk-IDZTNRP2.js +85 -0
  73. package/chunk-ISNCLGUZ.js +146 -0
  74. package/chunk-IWX4UW2E.js +548 -0
  75. package/chunk-JBTJAPUF.js +35 -0
  76. package/chunk-JEXVIMYZ.js +55 -0
  77. package/chunk-JRKKFRAV.js +537 -0
  78. package/chunk-JZPBVBIY.js +94 -0
  79. package/chunk-KKY4B2Q2.js +21 -0
  80. package/chunk-KOCA5FCS.js +4750 -0
  81. package/chunk-KQHGZWSV.js +63 -0
  82. package/chunk-KTVVPRJS.js +138 -0
  83. package/chunk-KUG52IAP.js +8 -0
  84. package/chunk-KX6YBIHG.js +8 -0
  85. package/chunk-LARL2V6G.js +9017 -0
  86. package/chunk-LCBAMY2M.js +60 -0
  87. package/chunk-LM6IYQ3F.js +16 -0
  88. package/chunk-M76ECQRD.js +13658 -0
  89. package/chunk-MGOJ5R6J.js +113 -0
  90. package/chunk-MKMWT7SA.js +27196 -0
  91. package/chunk-MRC4Q34M.js +188 -0
  92. package/chunk-OLZBQWZU.js +6 -0
  93. package/chunk-OPZYGHUC.js +89 -0
  94. package/chunk-OWOHNGCN.js +50 -0
  95. package/chunk-PAKN26FP.js +239 -0
  96. package/chunk-PCWC3JTN.js +91 -0
  97. package/chunk-PG5PNA7Y.js +939 -0
  98. package/chunk-Q2YZULBH.js +104 -0
  99. package/chunk-QSJ3HFEF.js +8 -0
  100. package/chunk-QYXLLLGL.js +4519 -0
  101. package/chunk-ROWQEJRP.js +139 -0
  102. package/chunk-S7Z2HMCN.js +25 -0
  103. package/chunk-SBR32ZZS.js +1901 -0
  104. package/chunk-SH2CFQOH.js +3391 -0
  105. package/chunk-SL35K7AH.js +226 -0
  106. package/chunk-TILFE6LV.js +381 -0
  107. package/chunk-TSS3XJY4.js +2052 -0
  108. package/chunk-U4TRT5V4.js +246 -0
  109. package/chunk-U6VC4MU4.js +8 -0
  110. package/chunk-UAD2WT54.js +64 -0
  111. package/chunk-UUJDGGAK.js +421 -0
  112. package/chunk-VF4K2QE6.js +21 -0
  113. package/chunk-VHBWHNVT.js +59 -0
  114. package/chunk-VIDPVFP3.js +20 -0
  115. package/chunk-VP4WJWKW.js +8882 -0
  116. package/chunk-W4NVOSFF.js +37 -0
  117. package/chunk-WKM6FH35.js +190 -0
  118. package/chunk-WWC7I6TA.js +8 -0
  119. package/chunk-X7W4TNB4.js +1550 -0
  120. package/chunk-XE635NI4.js +1948 -0
  121. package/chunk-XKIMRZO2.js +221 -0
  122. package/chunk-XS466O7S.js +933 -0
  123. package/chunk-Y5GCAMGP.js +9 -0
  124. package/chunk-YBWOP46I.js +3272 -0
  125. package/chunk-YPRZSPF3.js +148 -0
  126. package/chunk-YYUCRDOK.js +69 -0
  127. package/chunk-Z4NR32XR.js +50 -0
  128. package/chunk-ZIG5LJ7X.js +24765 -0
  129. package/chunk-ZNFJWEN4.js +56 -0
  130. package/chunk-ZQ2UM4KG.js +2878 -0
  131. package/cliExecutor-DNE7TCC4.js +36 -0
  132. package/clipboardy-BVE3LVEH.js +12001 -0
  133. package/createAgentAutomationAction-63OIP6X5.js +866 -0
  134. package/createDialogAction-ZLYZDYBB.js +54 -0
  135. package/createPageAction-AL5FSDCK.js +171 -0
  136. package/db-HCJ5PRB5.js +271 -0
  137. package/dbSlice-PR44QPXY.js +60 -0
  138. package/deleteFile-4SKGPHOZ.js +41 -0
  139. package/dialogCommands-F6YI5742.js +63 -0
  140. package/dialogSlice-JSBNZRLR.js +148 -0
  141. package/docCreateCommands-4CTO7ERT.js +219 -0
  142. package/docDeleteCommands-VBWERDRG.js +180 -0
  143. package/docReadCommands-KNP4MFYB.js +133 -0
  144. package/docStore-ADP5VYY4.js +98 -0
  145. package/docUpdateCommands-4BCBJQHA.js +317 -0
  146. package/fetchMessages-U6ZHN56A.js +17 -0
  147. package/getPricing-3E6UNPKL.js +30 -0
  148. package/handleSendMessageAction-IJDQ6ARA.js +185 -0
  149. package/index.js +188 -112943
  150. package/lib-FYYBQIXS.js +19839 -0
  151. package/localDialogRead-Z5UTAJPU.js +26 -0
  152. package/localFirstLog-DHNOY2NA.js +19 -0
  153. package/localRuntimeAuthority-TEGCOWX4.js +471 -0
  154. package/localRuntimeDb-LGDF6FQP.js +12 -0
  155. package/machineCommands-EA3M4XTN.js +779 -0
  156. package/machineInfo-M6KB6HZN.js +10 -0
  157. package/machineWsRunDispatch-NAPKE5ZA.js +110 -0
  158. package/memoryCommands-O4MIPIWQ.js +476 -0
  159. package/models-4OPOOLFS.js +9 -0
  160. package/offlineMarxistsAgentCommand-BCPJITJL.js +242 -0
  161. package/package.json +3 -25
  162. package/read-RIJCIVKX.js +17 -0
  163. package/readDocTool-GZD2N3LO.js +16 -0
  164. package/readlineWorkspace-KMWT4T4S.js +5509 -0
  165. package/removeDialogAgentAction-GJQJNDW6.js +73 -0
  166. package/runAgentClientLoop-U5Q6NDTJ.js +291 -0
  167. package/runtimeDoctorCommands-LRHLPDRC.js +289 -0
  168. package/setDialogExtraReferencesAction-M7OQG54N.js +60 -0
  169. package/setPrimaryDialogAgentAction-46UNFJDL.js +80 -0
  170. package/settingSlice-FVUUH4JA.js +199 -0
  171. package/skillSummaryMarker-42HKSXYY.js +9 -0
  172. package/slateToRenderMarkdown-Y5IYN73U.js +7 -0
  173. package/slateUtils-2M7MUTWX.js +19 -0
  174. package/spaceCommands-E2CFRPZJ.js +454 -0
  175. package/spaceSlice-L3R6IMXE.js +147 -0
  176. package/streamAgentChatTurn-UBDAOQWE.js +4528 -0
  177. package/tableCommands-GOFP7QKA.js +1286 -0
  178. package/toolApiClient-QI3YBNWB.js +26 -0
  179. package/tools-TMJXZTCA.js +85 -0
  180. package/tuiSummaryLlmCaller-RV3THLZF.js +78 -0
  181. package/understanding-GQKNDDWM.js +271 -0
  182. package/updateCommands-VOSPKXFF.js +31 -0
  183. package/updateDialogTitleAction-ZTWRDXI2.js +188 -0
@@ -0,0 +1,71 @@
1
+ import {
2
+ createMemoryKey,
3
+ createMemoryOwnerIndexKey,
4
+ createMemorySubjectKindIndexKey,
5
+ ulid
6
+ } from "./chunk-SH2CFQOH.js";
7
+
8
+ // packages/ai/memory/storeShared.ts
9
+ var createMemoryItem = (input) => {
10
+ const now = (/* @__PURE__ */ new Date()).toISOString();
11
+ return {
12
+ id: ulid(),
13
+ createdAt: now,
14
+ lastActivatedAt: now,
15
+ activationCount: 0,
16
+ ...input
17
+ };
18
+ };
19
+ var writeMemoryItemWithIndexesToDb = async (db, item) => {
20
+ const batch = db.batch();
21
+ batch.put(createMemoryKey(item.ownerType, item.ownerId, item.id), item);
22
+ batch.put(
23
+ createMemoryOwnerIndexKey(
24
+ item.ownerType,
25
+ item.ownerId,
26
+ item.createdAt,
27
+ item.id
28
+ ),
29
+ {
30
+ memoryKey: createMemoryKey(item.ownerType, item.ownerId, item.id),
31
+ ownerType: item.ownerType,
32
+ ownerId: item.ownerId,
33
+ memoryId: item.id
34
+ }
35
+ );
36
+ batch.put(
37
+ createMemorySubjectKindIndexKey(
38
+ item.subjectType,
39
+ item.subjectId,
40
+ item.kind,
41
+ item.createdAt,
42
+ item.id
43
+ ),
44
+ {
45
+ memoryKey: createMemoryKey(item.ownerType, item.ownerId, item.id),
46
+ subjectType: item.subjectType,
47
+ subjectId: item.subjectId,
48
+ kind: item.kind,
49
+ memoryId: item.id
50
+ }
51
+ );
52
+ await batch.write();
53
+ };
54
+ var touchMemoryItemsInDb = async (db, items, now = (/* @__PURE__ */ new Date()).toISOString()) => {
55
+ if (items.length === 0) return;
56
+ const batch = db.batch();
57
+ for (const item of items) {
58
+ batch.put(createMemoryKey(item.ownerType, item.ownerId, item.id), {
59
+ ...item,
60
+ lastActivatedAt: now,
61
+ activationCount: (item.activationCount ?? 0) + 1
62
+ });
63
+ }
64
+ await batch.write();
65
+ };
66
+
67
+ export {
68
+ createMemoryItem,
69
+ writeMemoryItemWithIndexesToDb,
70
+ touchMemoryItemsInDb
71
+ };
@@ -0,0 +1,34 @@
1
+ import {
2
+ fetchReferenceContents,
3
+ resolveReferenceAssets
4
+ } from "./chunk-SBR32ZZS.js";
5
+
6
+ // packages/ai/agent/fetchAgentContexts.ts
7
+ async function fetchAgentContexts(references, dispatch) {
8
+ if (!Array.isArray(references)) {
9
+ return { botInstructionsContext: "", botKnowledgeContext: "" };
10
+ }
11
+ const { references: normalizedRefs, contentByKey } = await resolveReferenceAssets(references, dispatch);
12
+ const instructionKeys = /* @__PURE__ */ new Set();
13
+ const knowledgeKeys = /* @__PURE__ */ new Set();
14
+ normalizedRefs.forEach((ref) => {
15
+ if (!ref.dbKey) return;
16
+ ref.type === "instruction" ? instructionKeys.add(ref.dbKey) : knowledgeKeys.add(ref.dbKey);
17
+ });
18
+ const [instructionsMap, knowledgeMap] = await Promise.all([
19
+ fetchReferenceContents(Array.from(instructionKeys), dispatch, {
20
+ preloaded: contentByKey
21
+ }),
22
+ fetchReferenceContents(Array.from(knowledgeKeys), dispatch, {
23
+ preloaded: contentByKey
24
+ })
25
+ ]);
26
+ return {
27
+ botInstructionsContext: Array.from(instructionsMap.values()).join(""),
28
+ botKnowledgeContext: Array.from(knowledgeMap.values()).join("")
29
+ };
30
+ }
31
+
32
+ export {
33
+ fetchAgentContexts
34
+ };
@@ -0,0 +1,50 @@
1
+ import {
2
+ asOptionalTrimmedString
3
+ } from "./chunk-G3SUCT4W.js";
4
+ import {
5
+ isRecord
6
+ } from "./chunk-KUG52IAP.js";
7
+
8
+ // packages/cli/cliSpaceHelpers.ts
9
+ function normalizeSpaceIdInput(rawInput) {
10
+ const raw = rawInput.trim();
11
+ if (!raw) return "";
12
+ let candidate = raw;
13
+ if (raw.startsWith("http://") || raw.startsWith("https://")) {
14
+ const match = new URL(raw).pathname.match(/^\/space\/([^/?#]+)/);
15
+ if (!match?.[1]) return "";
16
+ candidate = decodeURIComponent(match[1]);
17
+ }
18
+ return candidate.startsWith("space-") ? candidate.slice("space-".length) : candidate;
19
+ }
20
+ function buildSpaceLookup(rawInput) {
21
+ const spaceId = normalizeSpaceIdInput(rawInput);
22
+ return {
23
+ spaceId,
24
+ spaceKey: spaceId ? `space-${spaceId}` : ""
25
+ };
26
+ }
27
+ function getSpaceContentKeys(spaceRecord) {
28
+ const keys = /* @__PURE__ */ new Set();
29
+ const contents = spaceRecord?.contents;
30
+ if (!contents || typeof contents !== "object") return keys;
31
+ for (const [entryKey, value] of Object.entries(contents)) {
32
+ const trimmedEntryKey = asOptionalTrimmedString(entryKey);
33
+ if (trimmedEntryKey) {
34
+ keys.add(trimmedEntryKey);
35
+ }
36
+ if (isRecord(value)) {
37
+ const contentKey = asOptionalTrimmedString(value.contentKey);
38
+ if (contentKey) {
39
+ keys.add(contentKey);
40
+ }
41
+ }
42
+ }
43
+ return keys;
44
+ }
45
+
46
+ export {
47
+ normalizeSpaceIdInput,
48
+ buildSpaceLookup,
49
+ getSpaceContentKeys
50
+ };
@@ -0,0 +1,342 @@
1
+ import {
2
+ generatePkcePair,
3
+ startCallbackServer
4
+ } from "./chunk-EHLHSX7R.js";
5
+ import {
6
+ toErrorMessage
7
+ } from "./chunk-HNMXYYJR.js";
8
+ import {
9
+ asOptionalFiniteNumber
10
+ } from "./chunk-WWC7I6TA.js";
11
+
12
+ // packages/cli/oauth/flows/cloudflare.ts
13
+ var CLOUDFLARE_OAUTH_AUTH_ENDPOINT = "https://dash.cloudflare.com/oauth2/auth";
14
+ var CLOUDFLARE_OAUTH_TOKEN_ENDPOINT = "https://dash.cloudflare.com/oauth2/token";
15
+ var CLOUDFLARE_API_BASE = "https://api.cloudflare.com/client/v4";
16
+ var CLOUDFLARE_OAUTH_REDIRECT_HOST = "127.0.0.1";
17
+ var CLOUDFLARE_OAUTH_REDIRECT_PORT = 56122;
18
+ var CLOUDFLARE_OAUTH_REDIRECT_PATH = "/callback";
19
+ var ACCESS_TOKEN_CLIENT_SKEW_MS = 5 * 60 * 1e3;
20
+ var TOKEN_REQUEST_TIMEOUT_MS = 2e4;
21
+ var DEFAULT_SCOPE = "account:read zone:read zone:edit user:read user:edit";
22
+ function generateState() {
23
+ const bytes = new Uint8Array(16);
24
+ crypto.getRandomValues(bytes);
25
+ return Array.from(bytes).map((value) => value.toString(16).padStart(2, "0")).join("");
26
+ }
27
+ function getClientId(args) {
28
+ const value = args?.clientId?.trim() || process.env.CLOUDFLARE_OAUTH_CLIENT_ID?.trim();
29
+ if (!value) {
30
+ throw new Error(
31
+ "Cloudflare OAuth client ID is required. Set CLOUDFLARE_OAUTH_CLIENT_ID or pass --client-id."
32
+ );
33
+ }
34
+ return value;
35
+ }
36
+ function getScope(args) {
37
+ return args?.scope?.trim() || process.env.CLOUDFLARE_OAUTH_SCOPE?.trim() || DEFAULT_SCOPE;
38
+ }
39
+ function buildCloudflareAuthorizeUrl(opts) {
40
+ const params = new URLSearchParams({
41
+ response_type: "code",
42
+ client_id: opts.clientId,
43
+ redirect_uri: opts.redirectUri,
44
+ scope: opts.scope,
45
+ code_challenge: opts.codeChallenge,
46
+ code_challenge_method: "S256",
47
+ state: opts.state
48
+ });
49
+ return `${CLOUDFLARE_OAUTH_AUTH_ENDPOINT}?${params.toString()}`;
50
+ }
51
+ async function exchangeCloudflareToken(fetchImpl, code, redirectUri, verifier, clientId) {
52
+ const body = new URLSearchParams({
53
+ grant_type: "authorization_code",
54
+ client_id: clientId,
55
+ code,
56
+ redirect_uri: redirectUri,
57
+ code_verifier: verifier
58
+ });
59
+ const response = await fetchImpl(CLOUDFLARE_OAUTH_TOKEN_ENDPOINT, {
60
+ method: "POST",
61
+ headers: {
62
+ "Content-Type": "application/x-www-form-urlencoded",
63
+ Accept: "application/json"
64
+ },
65
+ body,
66
+ signal: AbortSignal.timeout(TOKEN_REQUEST_TIMEOUT_MS)
67
+ });
68
+ if (!response.ok) {
69
+ let detail = "";
70
+ try {
71
+ detail = (await response.text()).trim();
72
+ } catch {
73
+ }
74
+ throw new Error(
75
+ `Cloudflare token exchange failed: ${response.status}${detail ? ` ${detail}` : ""}`
76
+ );
77
+ }
78
+ const data = await response.json();
79
+ if (typeof data.access_token !== "string" || !data.access_token) {
80
+ throw new Error("Cloudflare token exchange response missing access_token");
81
+ }
82
+ return {
83
+ accessToken: data.access_token,
84
+ refreshToken: typeof data.refresh_token === "string" ? data.refresh_token : void 0,
85
+ expiresIn: asOptionalFiniteNumber(data.expires_in),
86
+ scope: typeof data.scope === "string" ? data.scope : void 0,
87
+ idToken: typeof data.id_token === "string" ? data.id_token : void 0
88
+ };
89
+ }
90
+ async function runCloudflareOAuthLogin(deps = {}) {
91
+ const fetchImpl = deps.fetchImpl ?? fetch;
92
+ const output = deps.output ?? console;
93
+ const error = deps.error ?? console;
94
+ const clientId = getClientId(deps);
95
+ const scope = getScope(deps);
96
+ const redirectUri = `http://${CLOUDFLARE_OAUTH_REDIRECT_HOST}:${CLOUDFLARE_OAUTH_REDIRECT_PORT}${CLOUDFLARE_OAUTH_REDIRECT_PATH}`;
97
+ let handle;
98
+ try {
99
+ handle = await startCallbackServer({
100
+ port: CLOUDFLARE_OAUTH_REDIRECT_PORT,
101
+ hostname: CLOUDFLARE_OAUTH_REDIRECT_HOST,
102
+ timeoutMs: 5 * 6e4
103
+ });
104
+ } catch (err) {
105
+ throw new Error(
106
+ `Failed to start Cloudflare OAuth callback server on ${CLOUDFLARE_OAUTH_REDIRECT_PORT}: ${toErrorMessage(err)}`
107
+ );
108
+ }
109
+ try {
110
+ const state = generateState();
111
+ const pkce = await generatePkcePair();
112
+ const authUrl = buildCloudflareAuthorizeUrl({
113
+ redirectUri,
114
+ codeChallenge: pkce.challenge,
115
+ state,
116
+ clientId,
117
+ scope
118
+ });
119
+ output.log(
120
+ `Open the following URL in your browser to authorize Cloudflare access:
121
+ ${authUrl}
122
+
123
+ Requested scopes: ${scope}`
124
+ );
125
+ if (deps.openBrowser) {
126
+ try {
127
+ await deps.openBrowser(authUrl);
128
+ } catch (err) {
129
+ error.error(
130
+ `Failed to open browser automatically: ${toErrorMessage(err)}`
131
+ );
132
+ }
133
+ }
134
+ const callback = await handle.waitForCode();
135
+ const token = await exchangeCloudflareToken(
136
+ fetchImpl,
137
+ callback.code,
138
+ redirectUri,
139
+ pkce.verifier,
140
+ clientId
141
+ );
142
+ const now = (deps.now ?? Date.now)();
143
+ const expiresIn = token.expiresIn;
144
+ return {
145
+ provider: "cloudflare",
146
+ accessToken: token.accessToken,
147
+ refreshToken: token.refreshToken,
148
+ expiresAt: typeof expiresIn === "number" ? now + expiresIn * 1e3 - ACCESS_TOKEN_CLIENT_SKEW_MS : void 0,
149
+ scope: token.scope,
150
+ idToken: token.idToken,
151
+ obtainedAt: now
152
+ };
153
+ } finally {
154
+ await handle.close();
155
+ }
156
+ }
157
+ async function createCloudflareApiToken(input) {
158
+ const fetchImpl = input.fetchImpl ?? fetch;
159
+ const response = await fetchImpl(`${CLOUDFLARE_API_BASE}/user/tokens`, {
160
+ method: "POST",
161
+ headers: {
162
+ "Content-Type": "application/json",
163
+ Authorization: `Bearer ${input.accessToken}`
164
+ },
165
+ body: JSON.stringify({
166
+ name: input.name,
167
+ policies: input.policies
168
+ }),
169
+ signal: AbortSignal.timeout(TOKEN_REQUEST_TIMEOUT_MS)
170
+ });
171
+ if (!response.ok) {
172
+ let detail = "";
173
+ try {
174
+ detail = (await response.text()).trim();
175
+ } catch {
176
+ }
177
+ throw new Error(
178
+ `Cloudflare API token creation failed: ${response.status}${detail ? ` ${detail}` : ""}`
179
+ );
180
+ }
181
+ const data = await response.json();
182
+ const tokenValue = data.result?.value;
183
+ if (typeof tokenValue !== "string" || !tokenValue) {
184
+ throw new Error(
185
+ "Cloudflare API token creation response did not contain a token value"
186
+ );
187
+ }
188
+ return tokenValue;
189
+ }
190
+ async function listCloudflarePermissionGroups(accessToken, fetchImpl = fetch) {
191
+ const response = await fetchImpl(
192
+ `${CLOUDFLARE_API_BASE}/user/tokens/permission_groups`,
193
+ {
194
+ method: "GET",
195
+ headers: {
196
+ Authorization: `Bearer ${accessToken}`,
197
+ Accept: "application/json"
198
+ },
199
+ signal: AbortSignal.timeout(TOKEN_REQUEST_TIMEOUT_MS)
200
+ }
201
+ );
202
+ if (!response.ok) {
203
+ let detail = "";
204
+ try {
205
+ detail = (await response.text()).trim();
206
+ } catch {
207
+ }
208
+ throw new Error(
209
+ `Cloudflare permission groups lookup failed: ${response.status}${detail ? ` ${detail}` : ""}`
210
+ );
211
+ }
212
+ const data = await response.json();
213
+ if (!Array.isArray(data.result)) {
214
+ throw new Error("Cloudflare permission groups response missing result array");
215
+ }
216
+ return data.result.filter(
217
+ (group) => typeof group.id === "string" && typeof group.name === "string" && Array.isArray(group.permissions)
218
+ ).map((group) => ({
219
+ id: group.id,
220
+ name: group.name,
221
+ permissions: group.permissions
222
+ }));
223
+ }
224
+ async function findCloudflareZoneIdByName(accessToken, zoneName, fetchImpl = fetch) {
225
+ const response = await fetchImpl(
226
+ `${CLOUDFLARE_API_BASE}/zones?name=${encodeURIComponent(zoneName)}`,
227
+ {
228
+ method: "GET",
229
+ headers: {
230
+ Authorization: `Bearer ${accessToken}`,
231
+ Accept: "application/json"
232
+ },
233
+ signal: AbortSignal.timeout(TOKEN_REQUEST_TIMEOUT_MS)
234
+ }
235
+ );
236
+ if (!response.ok) {
237
+ let detail = "";
238
+ try {
239
+ detail = (await response.text()).trim();
240
+ } catch {
241
+ }
242
+ throw new Error(
243
+ `Cloudflare zone lookup failed: ${response.status}${detail ? ` ${detail}` : ""}`
244
+ );
245
+ }
246
+ const data = await response.json();
247
+ if (!Array.isArray(data.result)) {
248
+ throw new Error("Cloudflare zone lookup response missing result array");
249
+ }
250
+ const zone = data.result.find((z) => z.name === zoneName);
251
+ return zone?.id ?? null;
252
+ }
253
+ async function generateCloudflareEmailRoutingToken(input) {
254
+ const fetchImpl = input.fetchImpl ?? fetch;
255
+ const zoneId = await findCloudflareZoneIdByName(
256
+ input.accessToken,
257
+ input.zoneName,
258
+ fetchImpl
259
+ );
260
+ if (!zoneId) {
261
+ throw new Error(`Cloudflare zone "${input.zoneName}" not found`);
262
+ }
263
+ const groups = await listCloudflarePermissionGroups(
264
+ input.accessToken,
265
+ fetchImpl
266
+ );
267
+ const emailRoutingGroup = groups.find(
268
+ (g) => g.name.toLowerCase().includes("email routing")
269
+ );
270
+ if (!emailRoutingGroup) {
271
+ throw new Error(
272
+ "Cloudflare Email Routing Edit permission group not found for this account."
273
+ );
274
+ }
275
+ const token = await createCloudflareApiToken({
276
+ name: input.tokenName ?? `nolo-email-routing-${input.zoneName}-${Date.now()}`,
277
+ policies: [buildEmailRoutingPolicy(zoneId, [emailRoutingGroup.id])],
278
+ accessToken: input.accessToken,
279
+ fetchImpl
280
+ });
281
+ return { token, zoneId };
282
+ }
283
+ function buildEmailRoutingPolicy(zoneId, emailRoutingPermissionGroupIds) {
284
+ if (emailRoutingPermissionGroupIds.length === 0) {
285
+ throw new Error(
286
+ "Email routing permission group IDs are required. Resolve them with listCloudflarePermissionGroups."
287
+ );
288
+ }
289
+ return {
290
+ effect: "allow",
291
+ resources: {
292
+ "com.cloudflare.api.account": "*",
293
+ "com.cloudflare.api.zone": zoneId
294
+ },
295
+ permission_groups: emailRoutingPermissionGroupIds.map((id) => ({ id }))
296
+ };
297
+ }
298
+
299
+ // packages/cli/oauth/envFile.ts
300
+ import { readFileSync, writeFileSync, existsSync } from "node:fs";
301
+ import { resolve } from "node:path";
302
+ function upsertEnvVariable(filePath, key, value) {
303
+ const normalizedPath = resolve(filePath);
304
+ let content = "";
305
+ if (existsSync(normalizedPath)) {
306
+ content = readFileSync(normalizedPath, "utf8");
307
+ }
308
+ const lines = content.length > 0 ? content.split("\n") : [];
309
+ const keyPrefix = `${key}=`;
310
+ let replaced = false;
311
+ const newLines = lines.map((line) => {
312
+ const trimmed = line.trim();
313
+ if (trimmed.startsWith(keyPrefix) || trimmed.startsWith(`${key} =`)) {
314
+ replaced = true;
315
+ return `${key}=${value}`;
316
+ }
317
+ return line;
318
+ });
319
+ if (!replaced) {
320
+ if (newLines.length > 0 && newLines[newLines.length - 1] !== "") {
321
+ newLines.push("");
322
+ }
323
+ newLines.push(`${key}=${value}`);
324
+ }
325
+ writeFileSync(normalizedPath, newLines.join("\n"), "utf8");
326
+ }
327
+ function parseFlagWithOptionalValue(args, flag) {
328
+ const index = args.indexOf(flag);
329
+ if (index === -1) return void 0;
330
+ const next = args[index + 1];
331
+ if (next && !next.startsWith("--")) {
332
+ return next;
333
+ }
334
+ return true;
335
+ }
336
+
337
+ export {
338
+ runCloudflareOAuthLogin,
339
+ generateCloudflareEmailRoutingToken,
340
+ upsertEnvVariable,
341
+ parseFlagWithOptionalValue
342
+ };