nomoreide 0.1.101 → 0.1.102

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 (141) hide show
  1. package/dist/core/agent-profiles/types.d.ts +3 -3
  2. package/dist/core/cloudflare-actions.d.ts +90 -0
  3. package/dist/core/cloudflare-actions.js +178 -0
  4. package/dist/core/cloudflare-actions.js.map +1 -0
  5. package/dist/core/cloudflare-auth.d.ts +61 -0
  6. package/dist/core/cloudflare-auth.js +149 -0
  7. package/dist/core/cloudflare-auth.js.map +1 -0
  8. package/dist/core/cloudflare-context.d.ts +2 -0
  9. package/dist/core/cloudflare-context.js +106 -0
  10. package/dist/core/cloudflare-context.js.map +1 -0
  11. package/dist/core/cloudflare-manager.d.ts +256 -0
  12. package/dist/core/cloudflare-manager.js +409 -0
  13. package/dist/core/cloudflare-manager.js.map +1 -0
  14. package/dist/core/cloudflare-provider.d.ts +64 -0
  15. package/dist/core/cloudflare-provider.js +343 -0
  16. package/dist/core/cloudflare-provider.js.map +1 -0
  17. package/dist/core/config-store.d.ts +14 -14
  18. package/dist/core/config-store.js +129 -42
  19. package/dist/core/config-store.js.map +1 -1
  20. package/dist/core/context-library.js +105 -10
  21. package/dist/core/context-library.js.map +1 -1
  22. package/dist/core/extensions.d.ts +78 -0
  23. package/dist/core/extensions.js +41 -0
  24. package/dist/core/extensions.js.map +1 -0
  25. package/dist/core/log-store.d.ts +10 -0
  26. package/dist/core/log-store.js +10 -1
  27. package/dist/core/log-store.js.map +1 -1
  28. package/dist/core/log-volume.d.ts +41 -0
  29. package/dist/core/log-volume.js +81 -0
  30. package/dist/core/log-volume.js.map +1 -0
  31. package/dist/core/project-overview.d.ts +2 -2
  32. package/dist/core/project-overview.js +3 -3
  33. package/dist/core/project-overview.js.map +1 -1
  34. package/dist/core/providers/credentials.d.ts +93 -0
  35. package/dist/core/providers/credentials.js +88 -0
  36. package/dist/core/providers/credentials.js.map +1 -0
  37. package/dist/core/providers/deploy-provider.d.ts +327 -0
  38. package/dist/core/providers/deploy-provider.js +25 -0
  39. package/dist/core/providers/deploy-provider.js.map +1 -0
  40. package/dist/core/providers/egress.d.ts +58 -0
  41. package/dist/core/providers/egress.js +115 -0
  42. package/dist/core/providers/egress.js.map +1 -0
  43. package/dist/core/providers/host-bridge.d.ts +20 -0
  44. package/dist/core/providers/host-bridge.js +57 -0
  45. package/dist/core/providers/host-bridge.js.map +1 -0
  46. package/dist/core/providers/host-provider.d.ts +160 -0
  47. package/dist/core/providers/host-provider.js +2 -0
  48. package/dist/core/providers/host-provider.js.map +1 -0
  49. package/dist/core/providers/oauth.d.ts +97 -0
  50. package/dist/core/providers/oauth.js +238 -0
  51. package/dist/core/providers/oauth.js.map +1 -0
  52. package/dist/core/providers/project-resolution.d.ts +81 -0
  53. package/dist/core/providers/project-resolution.js +101 -0
  54. package/dist/core/providers/project-resolution.js.map +1 -0
  55. package/dist/core/providers/registry.d.ts +73 -0
  56. package/dist/core/providers/registry.js +53 -0
  57. package/dist/core/providers/registry.js.map +1 -0
  58. package/dist/core/providers/strings.d.ts +95 -0
  59. package/dist/core/providers/strings.js +59 -0
  60. package/dist/core/providers/strings.js.map +1 -0
  61. package/dist/core/repo-onboard.d.ts +2 -2
  62. package/dist/core/ssh-servers.d.ts +16 -1
  63. package/dist/core/ssh-servers.js +23 -8
  64. package/dist/core/ssh-servers.js.map +1 -1
  65. package/dist/core/types.d.ts +25 -14
  66. package/dist/core/vercel-auth.d.ts +18 -36
  67. package/dist/core/vercel-auth.js +33 -75
  68. package/dist/core/vercel-auth.js.map +1 -1
  69. package/dist/core/vercel-context.d.ts +2 -25
  70. package/dist/core/vercel-context.js +73 -119
  71. package/dist/core/vercel-context.js.map +1 -1
  72. package/dist/core/vercel-manager.d.ts +13 -0
  73. package/dist/core/vercel-manager.js +3 -5
  74. package/dist/core/vercel-manager.js.map +1 -1
  75. package/dist/core/vercel-oauth.d.ts +24 -62
  76. package/dist/core/vercel-oauth.js +27 -199
  77. package/dist/core/vercel-oauth.js.map +1 -1
  78. package/dist/core/vercel-provider.d.ts +23 -0
  79. package/dist/core/vercel-provider.js +271 -0
  80. package/dist/core/vercel-provider.js.map +1 -0
  81. package/dist/core/vultr-actions.d.ts +52 -0
  82. package/dist/core/vultr-actions.js +62 -0
  83. package/dist/core/vultr-actions.js.map +1 -0
  84. package/dist/core/vultr-auth.d.ts +32 -0
  85. package/dist/core/vultr-auth.js +54 -0
  86. package/dist/core/vultr-auth.js.map +1 -0
  87. package/dist/core/vultr-context.d.ts +2 -0
  88. package/dist/core/vultr-context.js +55 -0
  89. package/dist/core/vultr-context.js.map +1 -0
  90. package/dist/core/vultr-manager.d.ts +105 -0
  91. package/dist/core/vultr-manager.js +159 -0
  92. package/dist/core/vultr-manager.js.map +1 -0
  93. package/dist/core/vultr-provider.d.ts +69 -0
  94. package/dist/core/vultr-provider.js +224 -0
  95. package/dist/core/vultr-provider.js.map +1 -0
  96. package/dist/mcp/tools/docs.js +1 -1
  97. package/dist/mcp/tools/docs.js.map +1 -1
  98. package/dist/mcp/tools/index.d.ts +1 -1
  99. package/dist/mcp/tools/index.js +3 -3
  100. package/dist/mcp/tools/index.js.map +1 -1
  101. package/dist/mcp/tools/provider.d.ts +16 -0
  102. package/dist/mcp/tools/provider.js +110 -0
  103. package/dist/mcp/tools/provider.js.map +1 -0
  104. package/dist/web/client/assets/{code-editor-rHWIXkKg.js → code-editor-gBOtcWXO.js} +1 -1
  105. package/dist/web/client/assets/context-graph-CTQ1LK6k.js +7 -0
  106. package/dist/web/client/assets/index-D_Lc5VHW.css +1 -0
  107. package/dist/web/client/assets/index-eKrMwpX9.js +352 -0
  108. package/dist/web/client/assets/{system-process-table-S4umMSEK.js → system-process-table-DOHmN7d0.js} +1 -1
  109. package/dist/web/client/index.html +2 -2
  110. package/dist/web/dashboard.d.ts +21 -2
  111. package/dist/web/dashboard.js +48 -4
  112. package/dist/web/dashboard.js.map +1 -1
  113. package/dist/web/routes/extensions-routes.d.ts +14 -0
  114. package/dist/web/routes/extensions-routes.js +21 -0
  115. package/dist/web/routes/extensions-routes.js.map +1 -0
  116. package/dist/web/routes/host-routes.d.ts +2 -0
  117. package/dist/web/routes/host-routes.js +188 -0
  118. package/dist/web/routes/host-routes.js.map +1 -0
  119. package/dist/web/routes/index.js +6 -2
  120. package/dist/web/routes/index.js.map +1 -1
  121. package/dist/web/routes/metrics-routes.js +19 -2
  122. package/dist/web/routes/metrics-routes.js.map +1 -1
  123. package/dist/web/routes/provider-routes.d.ts +2 -0
  124. package/dist/web/routes/provider-routes.js +558 -0
  125. package/dist/web/routes/provider-routes.js.map +1 -0
  126. package/dist/web/routes/shell-routes.d.ts +11 -0
  127. package/dist/web/routes/shell-routes.js +23 -3
  128. package/dist/web/routes/shell-routes.js.map +1 -1
  129. package/dist/web/routes/ssh-server-routes.d.ts +8 -1
  130. package/dist/web/routes/ssh-server-routes.js +15 -5
  131. package/dist/web/routes/ssh-server-routes.js.map +1 -1
  132. package/package.json +1 -1
  133. package/dist/mcp/tools/vercel.d.ts +0 -12
  134. package/dist/mcp/tools/vercel.js +0 -103
  135. package/dist/mcp/tools/vercel.js.map +0 -1
  136. package/dist/web/client/assets/context-graph-CcfJNAob.js +0 -7
  137. package/dist/web/client/assets/index-BnFtcUqj.js +0 -352
  138. package/dist/web/client/assets/index-CqsghUD9.css +0 -1
  139. package/dist/web/routes/vercel-routes.d.ts +0 -2
  140. package/dist/web/routes/vercel-routes.js +0 -476
  141. package/dist/web/routes/vercel-routes.js.map +0 -1
@@ -283,8 +283,8 @@ export declare const credentialSpecSchema: z.ZodObject<{
283
283
  required: z.ZodDefault<z.ZodBoolean>;
284
284
  description: z.ZodOptional<z.ZodString>;
285
285
  }, "strip", z.ZodTypeAny, {
286
- key: string;
287
286
  required: boolean;
287
+ key: string;
288
288
  description?: string | undefined;
289
289
  }, {
290
290
  key: string;
@@ -311,8 +311,8 @@ export declare const profileManifestSchema: z.ZodObject<{
311
311
  required: z.ZodDefault<z.ZodBoolean>;
312
312
  description: z.ZodOptional<z.ZodString>;
313
313
  }, "strip", z.ZodTypeAny, {
314
- key: string;
315
314
  required: boolean;
315
+ key: string;
316
316
  description?: string | undefined;
317
317
  }, {
318
318
  key: string;
@@ -327,8 +327,8 @@ export declare const profileManifestSchema: z.ZodObject<{
327
327
  tool: string;
328
328
  } | undefined;
329
329
  credentials?: {
330
- key: string;
331
330
  required: boolean;
331
+ key: string;
332
332
  description?: string | undefined;
333
333
  }[] | undefined;
334
334
  }, {
@@ -0,0 +1,90 @@
1
+ import { type CloudflareEnvVar, type CloudflareRequestAuth } from "./cloudflare-manager.js";
2
+ /**
3
+ * Write-capable Cloudflare Pages operations, deliberately separate from the
4
+ * read-safe {@link ./cloudflare-manager.js CloudflareManager} — the same split
5
+ * as `git-manager` / `git-actions` and `db-peek` / `db-write`.
6
+ *
7
+ * Everything here changes what the internet is serving, so none of it is
8
+ * exposed as an MCP tool: these are reached only from the dashboard's own
9
+ * routes, where a human clicked the button.
10
+ *
11
+ * Still intentionally excludes the irreversible ones — Cloudflare's
12
+ * `DELETE .../deployments/{id}` and project deletion — which would need their
13
+ * own guarded surface.
14
+ */
15
+ /** The only two environments Pages has. A third would be silently created by a PATCH. */
16
+ export declare const CLOUDFLARE_ENVIRONMENTS: readonly ["production", "preview"];
17
+ export type CloudflareEnvironment = (typeof CLOUDFLARE_ENVIRONMENTS)[number];
18
+ export declare class CloudflareActions {
19
+ private readonly auth;
20
+ private readonly accountId;
21
+ constructor(auth: CloudflareRequestAuth, accountId: string);
22
+ /**
23
+ * Rebuild an existing deployment.
24
+ *
25
+ * Cloudflare calls this "retry" and mints a new deployment id, inheriting the
26
+ * original's branch, commit and environment — so, unlike Vercel's redeploy,
27
+ * nothing has to be carried through by the caller to keep a production retry
28
+ * in production.
29
+ */
30
+ retry(projectName: string, deploymentId: string): Promise<{
31
+ id: string;
32
+ url: string | null;
33
+ }>;
34
+ /**
35
+ * Point the project's production alias at an earlier deployment without
36
+ * rebuilding it. Cloudflare records this as a rollback, and it takes effect
37
+ * immediately.
38
+ */
39
+ rollback(projectName: string, deploymentId: string): Promise<{
40
+ id: string;
41
+ url: string | null;
42
+ }>;
43
+ /**
44
+ * Add a variable. `secret` (Vercel's "encrypted") is the default, and its
45
+ * value never reads back over the API afterwards.
46
+ */
47
+ createEnv(projectName: string, input: {
48
+ key: string;
49
+ value: string;
50
+ environments: string[];
51
+ secret?: boolean;
52
+ }): Promise<CloudflareEnvVar>;
53
+ /**
54
+ * Change a variable's value and/or the environments it applies to.
55
+ *
56
+ * Adding an environment needs a value: Cloudflare stores the variable
57
+ * separately per environment and never hands back a secret's value, so there
58
+ * is nothing to copy across. Saying that is better than writing an empty
59
+ * string into the new environment.
60
+ */
61
+ updateEnv(projectName: string, key: string, input: {
62
+ value?: string;
63
+ environments?: string[];
64
+ }): Promise<CloudflareEnvVar>;
65
+ /** Remove a variable from every environment it is set in. */
66
+ deleteEnv(projectName: string, key: string): Promise<void>;
67
+ /**
68
+ * The one write to a project's variables.
69
+ *
70
+ * Cloudflare merges the `env_vars` map it is sent — a key set to `null` is
71
+ * deleted, and keys the patch does not mention are untouched — so this never
72
+ * has to read-modify-write the whole map and cannot clobber a variable added
73
+ * between the read and the write.
74
+ */
75
+ private patchEnv;
76
+ private patchProject;
77
+ private currentEnv;
78
+ private projectPath;
79
+ private request;
80
+ }
81
+ /**
82
+ * Cloudflare's action vocabulary, mapped onto the names the shared UI already
83
+ * knows. "retry" is Cloudflare's word for what Vercel calls a redeploy, and
84
+ * there is no cancel endpoint for a Pages build at all — so the manifest is
85
+ * two actions, not four, and the deployment row hides what it cannot do.
86
+ */
87
+ export declare const CLOUDFLARE_ACTIONS: readonly ["redeploy", "rollback"];
88
+ export type CloudflareActionName = (typeof CLOUDFLARE_ACTIONS)[number];
89
+ /** Actions that change what production serves — the UI confirms these first. */
90
+ export declare const PRODUCTION_AFFECTING_ACTIONS: ReadonlySet<CloudflareActionName>;
@@ -0,0 +1,178 @@
1
+ import { cloudflareRequest, } from "./cloudflare-manager.js";
2
+ /**
3
+ * Write-capable Cloudflare Pages operations, deliberately separate from the
4
+ * read-safe {@link ./cloudflare-manager.js CloudflareManager} — the same split
5
+ * as `git-manager` / `git-actions` and `db-peek` / `db-write`.
6
+ *
7
+ * Everything here changes what the internet is serving, so none of it is
8
+ * exposed as an MCP tool: these are reached only from the dashboard's own
9
+ * routes, where a human clicked the button.
10
+ *
11
+ * Still intentionally excludes the irreversible ones — Cloudflare's
12
+ * `DELETE .../deployments/{id}` and project deletion — which would need their
13
+ * own guarded surface.
14
+ */
15
+ /** The only two environments Pages has. A third would be silently created by a PATCH. */
16
+ export const CLOUDFLARE_ENVIRONMENTS = ["production", "preview"];
17
+ export class CloudflareActions {
18
+ auth;
19
+ accountId;
20
+ constructor(auth, accountId) {
21
+ this.auth = auth;
22
+ this.accountId = accountId;
23
+ }
24
+ /**
25
+ * Rebuild an existing deployment.
26
+ *
27
+ * Cloudflare calls this "retry" and mints a new deployment id, inheriting the
28
+ * original's branch, commit and environment — so, unlike Vercel's redeploy,
29
+ * nothing has to be carried through by the caller to keep a production retry
30
+ * in production.
31
+ */
32
+ async retry(projectName, deploymentId) {
33
+ const created = await this.request(`${this.projectPath(projectName)}/deployments/${encodeURIComponent(deploymentId)}/retry`, { method: "POST" });
34
+ return { id: created.id ?? "", url: created.url ?? null };
35
+ }
36
+ /**
37
+ * Point the project's production alias at an earlier deployment without
38
+ * rebuilding it. Cloudflare records this as a rollback, and it takes effect
39
+ * immediately.
40
+ */
41
+ async rollback(projectName, deploymentId) {
42
+ const rolled = await this.request(`${this.projectPath(projectName)}/deployments/${encodeURIComponent(deploymentId)}/rollback`, { method: "POST" });
43
+ return { id: rolled.id ?? deploymentId, url: rolled.url ?? null };
44
+ }
45
+ /**
46
+ * Add a variable. `secret` (Vercel's "encrypted") is the default, and its
47
+ * value never reads back over the API afterwards.
48
+ */
49
+ createEnv(projectName, input) {
50
+ const type = input.secret === false ? "plain_text" : "secret_text";
51
+ const patch = {};
52
+ for (const environment of requireEnvironments(input.environments)) {
53
+ patch[environment] = { [input.key]: { type, value: input.value } };
54
+ }
55
+ return this.patchEnv(projectName, input.key, patch);
56
+ }
57
+ /**
58
+ * Change a variable's value and/or the environments it applies to.
59
+ *
60
+ * Adding an environment needs a value: Cloudflare stores the variable
61
+ * separately per environment and never hands back a secret's value, so there
62
+ * is nothing to copy across. Saying that is better than writing an empty
63
+ * string into the new environment.
64
+ */
65
+ async updateEnv(projectName, key, input) {
66
+ const current = await this.currentEnv(projectName, key);
67
+ const wanted = input.environments
68
+ ? requireEnvironments(input.environments)
69
+ : current.environments;
70
+ const patch = {};
71
+ for (const environment of wanted) {
72
+ if (input.value !== undefined) {
73
+ patch[environment] = { [key]: { type: current.type, value: input.value } };
74
+ }
75
+ else if (!current.environments.includes(environment)) {
76
+ throw new Error(`Adding "${key}" to ${environment} needs a value — Cloudflare stores it separately per environment.`);
77
+ }
78
+ }
79
+ for (const environment of current.environments) {
80
+ if (!wanted.includes(environment)) {
81
+ patch[environment] = { [key]: null };
82
+ }
83
+ }
84
+ return this.patchEnv(projectName, key, patch);
85
+ }
86
+ /** Remove a variable from every environment it is set in. */
87
+ async deleteEnv(projectName, key) {
88
+ const current = await this.currentEnv(projectName, key);
89
+ const patch = {};
90
+ for (const environment of current.environments)
91
+ patch[environment] = { [key]: null };
92
+ await this.patchProject(projectName, patch);
93
+ }
94
+ /**
95
+ * The one write to a project's variables.
96
+ *
97
+ * Cloudflare merges the `env_vars` map it is sent — a key set to `null` is
98
+ * deleted, and keys the patch does not mention are untouched — so this never
99
+ * has to read-modify-write the whole map and cannot clobber a variable added
100
+ * between the read and the write.
101
+ */
102
+ async patchEnv(projectName, key, patch) {
103
+ const updated = await this.patchProject(projectName, patch);
104
+ const found = updated.find((entry) => entry.key === key);
105
+ if (!found)
106
+ throw new Error(`Cloudflare did not report "${key}" after the update.`);
107
+ return found;
108
+ }
109
+ async patchProject(projectName, patch) {
110
+ const deploymentConfigs = {};
111
+ for (const [environment, envVars] of Object.entries(patch)) {
112
+ if (envVars)
113
+ deploymentConfigs[environment] = { env_vars: envVars };
114
+ }
115
+ const project = await this.request(this.projectPath(projectName), {
116
+ method: "PATCH",
117
+ body: { deployment_configs: deploymentConfigs },
118
+ });
119
+ return mergeEnvVars(project.deployment_configs);
120
+ }
121
+ async currentEnv(projectName, key) {
122
+ const project = await this.request(this.projectPath(projectName));
123
+ const found = mergeEnvVars(project.deployment_configs).find((entry) => entry.key === key);
124
+ if (!found)
125
+ throw new Error(`No variable named "${key}" on this project.`);
126
+ return found;
127
+ }
128
+ projectPath(projectName) {
129
+ return `/accounts/${this.accountId}/pages/projects/${encodeURIComponent(projectName)}`;
130
+ }
131
+ request(path, opts) {
132
+ return cloudflareRequest(this.auth, path, opts);
133
+ }
134
+ }
135
+ /**
136
+ * Rejects anything that is not one of Pages' two environments. Vercel's env
137
+ * dialog offers `development` as well, and a PATCH naming it would quietly
138
+ * create a third deployment config that nothing ever reads.
139
+ */
140
+ function requireEnvironments(environments) {
141
+ const invalid = environments.filter((entry) => !CLOUDFLARE_ENVIRONMENTS.includes(entry));
142
+ if (invalid.length > 0) {
143
+ throw new Error(`Cloudflare Pages only has ${CLOUDFLARE_ENVIRONMENTS.join(" and ")} environments, not ${invalid.join(", ")}.`);
144
+ }
145
+ return environments;
146
+ }
147
+ /** The read side's flattening, applied to whatever a write handed back. */
148
+ function mergeEnvVars(configs) {
149
+ const merged = new Map();
150
+ for (const [environment, config] of Object.entries(configs ?? {})) {
151
+ for (const [key, entry] of Object.entries(config?.env_vars ?? {})) {
152
+ if (!entry)
153
+ continue;
154
+ const type = entry.type === "plain_text" ? "plain_text" : "secret_text";
155
+ const existing = merged.get(key);
156
+ if (existing) {
157
+ existing.environments.push(environment);
158
+ if (type === "secret_text")
159
+ existing.type = "secret_text";
160
+ continue;
161
+ }
162
+ merged.set(key, { key, environments: [environment], type, value: entry.value });
163
+ }
164
+ }
165
+ return [...merged.values()].sort((a, b) => a.key.localeCompare(b.key));
166
+ }
167
+ /**
168
+ * Cloudflare's action vocabulary, mapped onto the names the shared UI already
169
+ * knows. "retry" is Cloudflare's word for what Vercel calls a redeploy, and
170
+ * there is no cancel endpoint for a Pages build at all — so the manifest is
171
+ * two actions, not four, and the deployment row hides what it cannot do.
172
+ */
173
+ export const CLOUDFLARE_ACTIONS = ["redeploy", "rollback"];
174
+ /** Actions that change what production serves — the UI confirms these first. */
175
+ export const PRODUCTION_AFFECTING_ACTIONS = new Set([
176
+ "rollback",
177
+ ]);
178
+ //# sourceMappingURL=cloudflare-actions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudflare-actions.js","sourceRoot":"","sources":["../../src/core/cloudflare-actions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ import { type ProviderAuthSpec, type ProviderCliSession, type ProviderCliStatus } from "./providers/credentials.js";
2
+ /** Provider id this integration stores its connection under. */
3
+ export declare const CLOUDFLARE_PROVIDER_ID = "cloudflare";
4
+ /**
5
+ * Candidate locations of Wrangler's `config/default.toml`, newest convention
6
+ * first. Wrangler resolves these through `xdg-app-paths` under the app name
7
+ * `.wrangler`; the trailing entry is the pre-XDG path that long-lived installs
8
+ * still carry, and `WRANGLER_HOME` overrides all of them.
9
+ */
10
+ export declare function wranglerConfigDirs(env?: NodeJS.ProcessEnv): string[];
11
+ /**
12
+ * The ambient Cloudflare credential, or null when there is none.
13
+ *
14
+ * Two sources, in the order Wrangler itself prefers them:
15
+ *
16
+ * 1. `CLOUDFLARE_API_TOKEN` in the environment, which is how Wrangler runs in
17
+ * CI and in most shells that have been set up for it;
18
+ * 2. the OAuth token `wrangler login` wrote to `config/default.toml`.
19
+ *
20
+ * Neither is ever copied into NoMoreIDE's config — that is the shared `cli`
21
+ * policy, and it is what makes `wrangler logout` revoke us too.
22
+ *
23
+ * An expired stored token reads as "not logged in" rather than being handed
24
+ * out: Wrangler refreshes it roughly hourly and rotates the refresh token when
25
+ * it does, so renewing it here would invalidate Wrangler's own copy.
26
+ */
27
+ export declare function readWranglerSession(env?: NodeJS.ProcessEnv): Promise<ProviderCliSession | null>;
28
+ /**
29
+ * Cloudflare's half of the shared credential resolver.
30
+ *
31
+ * **No `oauth` block — because of how our flow works, not because Cloudflare
32
+ * has no OAuth.** The shared `providers/oauth.ts` mints its own client at
33
+ * runtime via dynamic client registration (RFC 7591), which is what lets
34
+ * NoMoreIDE ship no client id at all. Cloudflare has no registration endpoint,
35
+ * so `registerOAuthClient()` would throw before a browser ever opened.
36
+ *
37
+ * That is a narrower obstacle than it was, and narrower than this comment used
38
+ * to claim: Cloudflare *does* serve OIDC discovery, at
39
+ * `dash.cloudflare.com/.well-known/openid-configuration`. It advertises PKCE
40
+ * (S256), `none` for token endpoint auth, and both the `authorization_code` and
41
+ * `refresh_token` grants — but no `registration_endpoint`. Since 2026-06-03 you
42
+ * register the client yourself instead, and a *public* client needs no secret.
43
+ *
44
+ * Adopting it is therefore a change of model rather than a new provider entry:
45
+ * NoMoreIDE would ship a pre-registered client id, which `ProviderAuthSpec`
46
+ * has no way to express, and public visibility additionally requires a verified
47
+ * client domain and is irreversible once granted.
48
+ *
49
+ * Loopback redirect URIs are accepted — verified against a live client, and the
50
+ * thing that would otherwise have ruled this out. Cloudflare also exposes a
51
+ * device authorization endpoint, so a provider that ever *does* refuse loopback
52
+ * has a redirect-free path available.
53
+ *
54
+ * Until then Cloudflare connects with an API token or by inheriting Wrangler's
55
+ * own login. The three-source model survives contact with provider #2; only
56
+ * this provider's subset of it is smaller.
57
+ *
58
+ * @see docs/plans/2026-08-13-provider-registry-design.md §11
59
+ */
60
+ export declare const CLOUDFLARE_AUTH: ProviderAuthSpec;
61
+ export declare function cloudflareCliStatus(env?: NodeJS.ProcessEnv): Promise<ProviderCliStatus>;
@@ -0,0 +1,149 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { homedir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { providerCliStatus, } from "./providers/credentials.js";
5
+ /** Provider id this integration stores its connection under. */
6
+ export const CLOUDFLARE_PROVIDER_ID = "cloudflare";
7
+ /**
8
+ * Candidate locations of Wrangler's `config/default.toml`, newest convention
9
+ * first. Wrangler resolves these through `xdg-app-paths` under the app name
10
+ * `.wrangler`; the trailing entry is the pre-XDG path that long-lived installs
11
+ * still carry, and `WRANGLER_HOME` overrides all of them.
12
+ */
13
+ export function wranglerConfigDirs(env = process.env) {
14
+ // `env.HOME` rather than `homedir()` so an overridden environment redirects
15
+ // every candidate, not just the XDG one — otherwise a caller that points
16
+ // XDG_CONFIG_HOME somewhere still falls through to the real user's login.
17
+ const home = env.HOME?.trim() || homedir();
18
+ const dirs = [];
19
+ const wranglerHome = env.WRANGLER_HOME?.trim();
20
+ if (wranglerHome)
21
+ dirs.push(wranglerHome);
22
+ const xdgConfigHome = env.XDG_CONFIG_HOME?.trim();
23
+ if (xdgConfigHome)
24
+ dirs.push(join(xdgConfigHome, ".wrangler"));
25
+ if (process.platform === "darwin") {
26
+ dirs.push(join(home, "Library", "Preferences", ".wrangler"));
27
+ }
28
+ else if (process.platform === "win32") {
29
+ const appData = env.APPDATA?.trim();
30
+ if (appData)
31
+ dirs.push(join(appData, ".wrangler", "Config"));
32
+ }
33
+ dirs.push(join(home, ".config", ".wrangler"));
34
+ dirs.push(join(home, ".wrangler"));
35
+ return dirs;
36
+ }
37
+ /**
38
+ * The ambient Cloudflare credential, or null when there is none.
39
+ *
40
+ * Two sources, in the order Wrangler itself prefers them:
41
+ *
42
+ * 1. `CLOUDFLARE_API_TOKEN` in the environment, which is how Wrangler runs in
43
+ * CI and in most shells that have been set up for it;
44
+ * 2. the OAuth token `wrangler login` wrote to `config/default.toml`.
45
+ *
46
+ * Neither is ever copied into NoMoreIDE's config — that is the shared `cli`
47
+ * policy, and it is what makes `wrangler logout` revoke us too.
48
+ *
49
+ * An expired stored token reads as "not logged in" rather than being handed
50
+ * out: Wrangler refreshes it roughly hourly and rotates the refresh token when
51
+ * it does, so renewing it here would invalidate Wrangler's own copy.
52
+ */
53
+ export async function readWranglerSession(env = process.env) {
54
+ const currentScope = env.CLOUDFLARE_ACCOUNT_ID?.trim() || env.CF_ACCOUNT_ID?.trim() || undefined;
55
+ const envToken = env.CLOUDFLARE_API_TOKEN?.trim() || env.CF_API_TOKEN?.trim();
56
+ if (envToken)
57
+ return { token: envToken, currentScope };
58
+ for (const dir of wranglerConfigDirs(env)) {
59
+ const config = await readTomlFields(join(dir, "config", "default.toml"));
60
+ const token = config.oauth_token;
61
+ if (!token)
62
+ continue;
63
+ const expiresAt = Date.parse(config.expiration_time ?? "");
64
+ if (Number.isFinite(expiresAt) && expiresAt <= Date.now())
65
+ return null;
66
+ return { token, currentScope };
67
+ }
68
+ return null;
69
+ }
70
+ /**
71
+ * The top-level `key = "value"` pairs of a TOML file, or `{}` if anything goes
72
+ * wrong.
73
+ *
74
+ * Deliberately not a TOML parser and deliberately not shared: Wrangler's auth
75
+ * file is flat and quoted, and the only reason this exists rather than
76
+ * `readJsonField` is that Cloudflare's CLI happens to store its login as TOML.
77
+ * A malformed or missing file must read as "not logged in", never as an error
78
+ * the UI has to explain.
79
+ */
80
+ async function readTomlFields(path) {
81
+ const fields = {};
82
+ try {
83
+ const raw = await readFile(path, "utf8");
84
+ for (const line of raw.split("\n")) {
85
+ // Stop at the first table header: everything Wrangler stores is top-level,
86
+ // and a nested table's keys are not the same keys.
87
+ if (/^\s*\[/.test(line))
88
+ break;
89
+ const match = /^\s*([A-Za-z_][\w-]*)\s*=\s*"([^"]*)"\s*$/.exec(line);
90
+ if (match?.[2])
91
+ fields[match[1]] = match[2];
92
+ }
93
+ }
94
+ catch {
95
+ /* an unreadable file is "not logged in" */
96
+ }
97
+ return fields;
98
+ }
99
+ /**
100
+ * Cloudflare's half of the shared credential resolver.
101
+ *
102
+ * **No `oauth` block — because of how our flow works, not because Cloudflare
103
+ * has no OAuth.** The shared `providers/oauth.ts` mints its own client at
104
+ * runtime via dynamic client registration (RFC 7591), which is what lets
105
+ * NoMoreIDE ship no client id at all. Cloudflare has no registration endpoint,
106
+ * so `registerOAuthClient()` would throw before a browser ever opened.
107
+ *
108
+ * That is a narrower obstacle than it was, and narrower than this comment used
109
+ * to claim: Cloudflare *does* serve OIDC discovery, at
110
+ * `dash.cloudflare.com/.well-known/openid-configuration`. It advertises PKCE
111
+ * (S256), `none` for token endpoint auth, and both the `authorization_code` and
112
+ * `refresh_token` grants — but no `registration_endpoint`. Since 2026-06-03 you
113
+ * register the client yourself instead, and a *public* client needs no secret.
114
+ *
115
+ * Adopting it is therefore a change of model rather than a new provider entry:
116
+ * NoMoreIDE would ship a pre-registered client id, which `ProviderAuthSpec`
117
+ * has no way to express, and public visibility additionally requires a verified
118
+ * client domain and is irreversible once granted.
119
+ *
120
+ * Loopback redirect URIs are accepted — verified against a live client, and the
121
+ * thing that would otherwise have ruled this out. Cloudflare also exposes a
122
+ * device authorization endpoint, so a provider that ever *does* refuse loopback
123
+ * has a redirect-free path available.
124
+ *
125
+ * Until then Cloudflare connects with an API token or by inheriting Wrangler's
126
+ * own login. The three-source model survives contact with provider #2; only
127
+ * this provider's subset of it is smaller.
128
+ *
129
+ * @see docs/plans/2026-08-13-provider-registry-design.md §11
130
+ */
131
+ export const CLOUDFLARE_AUTH = {
132
+ id: CLOUDFLARE_PROVIDER_ID,
133
+ name: "Cloudflare",
134
+ cliSession: readWranglerSession,
135
+ messages: {
136
+ cliMissing: "No Wrangler login found. Run `wrangler login`, or paste a Cloudflare API token instead.",
137
+ noStoredToken: "No Cloudflare token stored. Reconnect Cloudflare with an API token.",
138
+ cliLoggedOut: "Wrangler is no longer logged in. Run `wrangler login` again, or connect with a Cloudflare API token.",
139
+ notConnected: "Cloudflare is not connected. Run `wrangler login`, or add a Cloudflare API token.",
140
+ // Reachable only if a connection were somehow saved as `oauth`; Cloudflare
141
+ // never creates one, so the message points at what does work.
142
+ signInExpired: "Cloudflare has no browser sign-in. Connect with a Cloudflare API token.",
143
+ refreshFailed: "Could not renew your Cloudflare credential ({error}). Add an API token.",
144
+ },
145
+ };
146
+ export function cloudflareCliStatus(env = process.env) {
147
+ return providerCliStatus(CLOUDFLARE_AUTH, env);
148
+ }
149
+ //# sourceMappingURL=cloudflare-auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudflare-auth.js","sourceRoot":"","sources":["../../src/core/cloudflare-auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { RegisteredDeployProvider } from "./providers/registry.js";
2
+ export declare const cloudflareDeployProvider: RegisteredDeployProvider;
@@ -0,0 +1,106 @@
1
+ import { CloudflareActions } from "./cloudflare-actions.js";
2
+ import { CLOUDFLARE_AUTH, CLOUDFLARE_PROVIDER_ID } from "./cloudflare-auth.js";
3
+ import { CloudflareManager } from "./cloudflare-manager.js";
4
+ import { CLOUDFLARE_HOOKS, CLOUDFLARE_MANIFEST, createCloudflareDeployActions, createCloudflareDeployProvider, toProviderProject, } from "./cloudflare-provider.js";
5
+ import { resolveProviderCredential } from "./providers/credentials.js";
6
+ import { createProviderFetch } from "./providers/egress.js";
7
+ import { adoptSoleScope, resolveProviderProject, } from "./providers/project-resolution.js";
8
+ /**
9
+ * Cloudflare's registry entry — how a connected client is built for a working
10
+ * directory, and the write-capable half resolved separately from it.
11
+ *
12
+ * The registry imports this; this must not import the registry, or the two
13
+ * would cycle.
14
+ *
15
+ * Shorter than Vercel's counterpart in one place and longer in another, which
16
+ * is the point of doing provider #2 before publishing anything:
17
+ *
18
+ * - **No token persistence.** Cloudflare has no browser sign-in, so nothing
19
+ * here ever rotates a refresh token — the `onTokensRefreshed` plumbing Vercel
20
+ * needs is simply absent.
21
+ * - **The account is resolved before the project, not after.** Every Pages path
22
+ * contains an account id, so project resolution cannot even begin until the
23
+ * scope is known.
24
+ */
25
+ /**
26
+ * A connected Cloudflare client for the given working directory.
27
+ *
28
+ * Throws when Cloudflare isn't connected. A missing *account* is not an error
29
+ * either: `account()` and `listScopes()` answer without one, which is what lets
30
+ * the dashboard show the account switcher rather than a dead end.
31
+ */
32
+ /**
33
+ * The scoped `fetch` every Cloudflare client here is built with, minted once
34
+ * from the manifest's `api.hosts`. This is the only file that mints it, which
35
+ * is what makes the allowlist a boundary rather than a suggestion — a manager
36
+ * built anywhere else gets global `fetch` and is a test, not a client.
37
+ */
38
+ const cloudflareFetch = createProviderFetch(CLOUDFLARE_MANIFEST);
39
+ async function cloudflareContext(configStore, gitCwd) {
40
+ const config = await configStore.load();
41
+ const credential = await resolveProviderCredential(CLOUDFLARE_AUTH, config, process.env);
42
+ const accountId = credential.scopeId ?? (await adoptDefaultAccount(configStore, credential));
43
+ const manager = new CloudflareManager(credential.token, accountId, undefined, cloudflareFetch);
44
+ const project = await resolveProject(config, manager, gitCwd);
45
+ return {
46
+ // The project is resolved first and handed to the provider: Cloudflare has
47
+ // no global deployment endpoint, so the deployment reads need it.
48
+ provider: createCloudflareDeployProvider(manager, project?.name),
49
+ credential: { ...credential, scopeId: accountId },
50
+ project,
51
+ };
52
+ }
53
+ /**
54
+ * The account to use when the user has never chosen one.
55
+ *
56
+ * `cliSelectsScope: false` because Wrangler has no account switch to inherit —
57
+ * so unlike Vercel, a `cli` credential does adopt the sole account, or a
58
+ * `wrangler login` with one account could never read a single project. It is
59
+ * still not written to config, so `CLOUDFLARE_ACCOUNT_ID` keeps winning.
60
+ */
61
+ function adoptDefaultAccount(configStore, credential) {
62
+ return adoptSoleScope({
63
+ source: credential.source,
64
+ cliSelectsScope: false,
65
+ listScopes: () => new CloudflareManager(credential.token, undefined, undefined, cloudflareFetch)
66
+ .listAccounts()
67
+ .then((accounts) =>
68
+ // Cloudflare accounts have no slug; the id addresses one.
69
+ accounts.map((account) => ({ id: account.id, slug: account.id }))),
70
+ persist: (scope) => configStore.setConnectionScope(CLOUDFLARE_PROVIDER_ID, scope).then(() => undefined),
71
+ });
72
+ }
73
+ /** Write-capable counterpart, resolved the same way but returned separately. */
74
+ async function cloudflareActions(configStore) {
75
+ const config = await configStore.load();
76
+ const credential = await resolveProviderCredential(CLOUDFLARE_AUTH, config, process.env);
77
+ const accountId = credential.scopeId ?? (await adoptDefaultAccount(configStore, credential));
78
+ if (!accountId) {
79
+ throw new Error("Choose a Cloudflare account before changing one of its projects.");
80
+ }
81
+ return createCloudflareDeployActions(new CloudflareActions({ token: credential.token, fetch: cloudflareFetch }, accountId));
82
+ }
83
+ /**
84
+ * Which Cloudflare project this repository deploys — the shared three-tier
85
+ * ladder, with only two of its three tiers in play: Wrangler writes no link
86
+ * file, so an unpinned repo is matched on its git remote.
87
+ */
88
+ async function resolveProject(config, manager, gitCwd) {
89
+ const project = await resolveProviderProject({
90
+ providerId: CLOUDFLARE_PROVIDER_ID,
91
+ hooks: CLOUDFLARE_HOOKS,
92
+ config,
93
+ gitCwd,
94
+ getProject: (id) => manager.getProject(id),
95
+ findByRepoUrl: (repoUrl) => manager.findProjectByRepo(repoUrl),
96
+ });
97
+ return project ? toProviderProject(project) : undefined;
98
+ }
99
+ export const cloudflareDeployProvider = {
100
+ manifest: CLOUDFLARE_MANIFEST,
101
+ auth: CLOUDFLARE_AUTH,
102
+ hooks: CLOUDFLARE_HOOKS,
103
+ context: cloudflareContext,
104
+ actions: cloudflareActions,
105
+ };
106
+ //# sourceMappingURL=cloudflare-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudflare-context.js","sourceRoot":"","sources":["../../src/core/cloudflare-context.ts"],"names":[],"mappings":"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"}