@spacefast/common 0.0.12 → 0.0.17

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 (189) hide show
  1. package/dist/agents/client-registry.d.ts +22 -0
  2. package/dist/agents/client-registry.js +41 -0
  3. package/dist/agents/connect-targets.d.ts +51 -6
  4. package/dist/agents/connect-targets.js +93 -28
  5. package/dist/brand.d.ts +0 -11
  6. package/dist/brand.js +0 -20
  7. package/dist/config/domains.d.ts +15 -6
  8. package/dist/config/domains.js +24 -10
  9. package/dist/config/postgres-budget.d.ts +3 -0
  10. package/dist/config/postgres-budget.js +6 -1
  11. package/dist/config/postgres-budget.json +2 -1
  12. package/dist/contracts/abuse.js +1 -1
  13. package/dist/contracts/access.d.ts +486 -1196
  14. package/dist/contracts/access.js +323 -1054
  15. package/dist/contracts/activity.d.ts +1 -1
  16. package/dist/contracts/activity.js +11 -15
  17. package/dist/contracts/api-keys.d.ts +16 -0
  18. package/dist/contracts/api-keys.js +11 -9
  19. package/dist/contracts/archives.d.ts +1 -2
  20. package/dist/contracts/archives.js +15 -17
  21. package/dist/contracts/beta.js +1 -1
  22. package/dist/contracts/builds.js +14 -14
  23. package/dist/contracts/channels.js +2 -2
  24. package/dist/contracts/comments.d.ts +143 -99
  25. package/dist/contracts/comments.js +194 -79
  26. package/dist/contracts/common.d.ts +12 -12
  27. package/dist/contracts/common.js +33 -30
  28. package/dist/contracts/continuation.js +5 -5
  29. package/dist/contracts/countries.js +2 -7
  30. package/dist/contracts/data-source-routes.d.ts +20 -0
  31. package/dist/contracts/data-source-routes.js +15 -0
  32. package/dist/contracts/device-auth.d.ts +13 -9
  33. package/dist/contracts/device-auth.js +12 -12
  34. package/dist/contracts/docs.d.ts +10 -10
  35. package/dist/contracts/domains.js +39 -33
  36. package/dist/contracts/enums.d.ts +4 -14
  37. package/dist/contracts/enums.js +3 -10
  38. package/dist/contracts/error-code-meta.d.ts +122 -56
  39. package/dist/contracts/error-code-meta.js +43 -19
  40. package/dist/contracts/error-codes.d.ts +7 -4
  41. package/dist/contracts/error-codes.js +48 -24
  42. package/dist/contracts/events.d.ts +22 -15
  43. package/dist/contracts/events.js +33 -5
  44. package/dist/contracts/execution.d.ts +238 -0
  45. package/dist/contracts/execution.js +309 -0
  46. package/dist/contracts/feature-lifecycle.d.ts +39 -188
  47. package/dist/contracts/feature-lifecycle.js +52 -196
  48. package/dist/contracts/features.d.ts +13 -115
  49. package/dist/contracts/features.js +5 -35
  50. package/dist/contracts/functions.d.ts +597 -0
  51. package/dist/contracts/functions.js +475 -0
  52. package/dist/contracts/grants.d.ts +1175 -0
  53. package/dist/contracts/grants.js +783 -0
  54. package/dist/contracts/ids.d.ts +7 -5
  55. package/dist/contracts/ids.js +7 -7
  56. package/dist/contracts/internal.js +2 -2
  57. package/dist/contracts/mcp.d.ts +17 -556
  58. package/dist/contracts/mcp.js +9 -103
  59. package/dist/contracts/me.js +3 -4
  60. package/dist/contracts/notifications.d.ts +108 -0
  61. package/dist/contracts/notifications.js +54 -0
  62. package/dist/contracts/oauth-resources.d.ts +22 -5
  63. package/dist/contracts/oauth-resources.js +23 -2
  64. package/dist/contracts/operations.d.ts +0 -48
  65. package/dist/contracts/operations.js +0 -19
  66. package/dist/contracts/pages.d.ts +10 -14
  67. package/dist/contracts/pages.js +17 -21
  68. package/dist/contracts/plan-policy.d.ts +1 -8
  69. package/dist/contracts/plan-policy.js +1 -4
  70. package/dist/contracts/platform.d.ts +78 -30
  71. package/dist/contracts/platform.js +69 -20
  72. package/dist/contracts/problem-document.d.ts +14 -0
  73. package/dist/contracts/problem-document.js +35 -0
  74. package/dist/contracts/push-new.d.ts +41 -2
  75. package/dist/contracts/push-new.js +4 -0
  76. package/dist/contracts/quotas.d.ts +0 -1
  77. package/dist/contracts/quotas.js +0 -5
  78. package/dist/contracts/repository-connections.d.ts +1 -1
  79. package/dist/contracts/resources.d.ts +16 -71
  80. package/dist/contracts/resources.js +13 -16
  81. package/dist/contracts/runtime-api.d.ts +666 -303
  82. package/dist/contracts/runtime-api.js +272 -113
  83. package/dist/contracts/runtime-app.d.ts +168 -0
  84. package/dist/contracts/runtime-app.js +42 -0
  85. package/dist/contracts/runtime-db.d.ts +424 -0
  86. package/dist/contracts/runtime-db.js +108 -0
  87. package/dist/contracts/runtime-storage.d.ts +120 -0
  88. package/dist/contracts/runtime-storage.js +40 -0
  89. package/dist/contracts/sf-config-v1.d.ts +54 -1
  90. package/dist/contracts/sf-config-v1.js +2 -2
  91. package/dist/contracts/sites.d.ts +6 -0
  92. package/dist/contracts/sites.js +30 -11
  93. package/dist/contracts/space-config.d.ts +91 -121
  94. package/dist/contracts/space-config.js +464 -42
  95. package/dist/contracts/spaces.d.ts +300 -171
  96. package/dist/contracts/spaces.js +128 -98
  97. package/dist/contracts/superadmin-emails.d.ts +2 -2
  98. package/dist/contracts/superadmin-spaces.d.ts +26 -130
  99. package/dist/contracts/superadmin-spaces.js +22 -0
  100. package/dist/contracts/superadmin-tenants.js +4 -4
  101. package/dist/contracts/superadmin.d.ts +4 -0
  102. package/dist/contracts/superadmin.js +14 -1
  103. package/dist/contracts/tags.d.ts +6 -6
  104. package/dist/contracts/tags.js +1 -1
  105. package/dist/contracts/teams.d.ts +9 -9
  106. package/dist/contracts/teams.js +25 -16
  107. package/dist/contracts/theme-json.js +1 -1
  108. package/dist/contracts/transfers.d.ts +0 -1
  109. package/dist/contracts/transfers.js +4 -4
  110. package/dist/contracts/variables.js +3 -3
  111. package/dist/contracts/zero.d.ts +384 -596
  112. package/dist/contracts/zero.js +167 -299
  113. package/dist/dashboard-paths/index.d.ts +18 -3
  114. package/dist/dashboard-paths/index.js +19 -0
  115. package/dist/docs/agent-handoff-document.d.ts +2 -2
  116. package/dist/docs/agent-handoff-document.js +8 -7
  117. package/dist/docs/agent-prose.d.ts +22 -3
  118. package/dist/docs/agent-prose.js +227 -55
  119. package/dist/docs/agent-setup.d.ts +14 -11
  120. package/dist/docs/agent-setup.js +289 -61
  121. package/dist/docs/agent-solutions.d.ts +6 -6
  122. package/dist/docs/agent-solutions.js +24 -22
  123. package/dist/docs/catalog.d.ts +53 -98
  124. package/dist/docs/catalog.js +90 -117
  125. package/dist/docs/error-docs.js +304 -236
  126. package/dist/docs/skill-distribution.d.ts +2 -0
  127. package/dist/docs/skill-distribution.js +7 -4
  128. package/dist/docs/skills.d.ts +546 -0
  129. package/dist/docs/skills.js +340 -0
  130. package/dist/utils/auth-redirect.d.ts +1 -3
  131. package/dist/utils/auth-redirect.js +1 -21
  132. package/dist/utils/browser-credential.d.ts +19 -0
  133. package/dist/utils/browser-credential.js +62 -0
  134. package/dist/utils/build-settings.d.ts +2 -0
  135. package/dist/utils/build-settings.js +61 -9
  136. package/dist/utils/comment-avatars.d.ts +7 -0
  137. package/dist/utils/comment-avatars.js +42 -0
  138. package/dist/utils/content-type.d.ts +3 -3
  139. package/dist/utils/content-type.js +38 -61
  140. package/dist/utils/credential-policy.d.ts +1 -1
  141. package/dist/utils/credential-policy.js +4 -0
  142. package/dist/utils/domain-diagnostics.d.ts +5 -5
  143. package/dist/utils/domain-diagnostics.js +21 -10
  144. package/dist/utils/egress-policy.fixtures.json +1 -1
  145. package/dist/utils/grants.d.ts +53 -0
  146. package/dist/utils/grants.js +160 -0
  147. package/dist/utils/local-space-state.d.ts +78 -4
  148. package/dist/utils/local-space-state.js +384 -82
  149. package/dist/utils/one-shot-replay.d.ts +14 -0
  150. package/dist/utils/one-shot-replay.js +21 -0
  151. package/dist/utils/page-preview.d.ts +7 -0
  152. package/dist/utils/page-preview.js +9 -0
  153. package/dist/utils/pages.d.ts +2 -5
  154. package/dist/utils/pages.js +64 -33
  155. package/dist/utils/publish-form-data.d.ts +22 -0
  156. package/dist/utils/publish-form-data.js +26 -0
  157. package/dist/utils/publish-policy.d.ts +34 -4
  158. package/dist/utils/publish-policy.js +149 -62
  159. package/dist/utils/query-keys.d.ts +8 -10
  160. package/dist/utils/query-keys.js +14 -10
  161. package/dist/utils/runtime-paths.d.ts +3 -0
  162. package/dist/utils/runtime-paths.js +7 -0
  163. package/dist/utils/secure-local-file.d.ts +73 -0
  164. package/dist/utils/secure-local-file.js +1373 -0
  165. package/dist/utils/space-config.d.ts +17 -4
  166. package/dist/utils/space-config.js +151 -8
  167. package/dist/utils/static-runtime-policy.d.ts +5 -0
  168. package/dist/utils/static-runtime-policy.js +54 -10
  169. package/dist/utils/storage-policy.d.ts +20 -0
  170. package/dist/utils/storage-policy.fixtures.json +174 -0
  171. package/dist/utils/storage-policy.js +193 -0
  172. package/dist/utils/upload-session.d.ts +15 -1
  173. package/dist/utils/upload-session.js +68 -2
  174. package/dist/utils/version-file-browser.d.ts +13 -0
  175. package/dist/utils/version-file-browser.js +59 -0
  176. package/package.json +20 -1
  177. package/dist/contracts/mounts.d.ts +0 -142
  178. package/dist/contracts/mounts.js +0 -56
  179. package/dist/utils/access-grant.d.ts +0 -14
  180. package/dist/utils/access-grant.js +0 -88
  181. package/dist/utils/access-match.d.ts +0 -46
  182. package/dist/utils/access-match.fixtures.json +0 -513
  183. package/dist/utils/access-match.js +0 -312
  184. package/dist/utils/access-verdict.fixtures.json +0 -421
  185. package/dist/utils/asset-fingerprint.d.ts +0 -53
  186. package/dist/utils/asset-fingerprint.js +0 -574
  187. package/dist/utils/sf-config-v1.d.ts +0 -2
  188. package/dist/utils/sf-config-v1.fixtures.json +0 -9
  189. package/dist/utils/sf-config-v1.js +0 -551
@@ -3,6 +3,7 @@ export declare const agentSetupUrl: string;
3
3
  export declare const agentSetupTextUrl: string;
4
4
  export declare const agentSetupHostLabel: string;
5
5
  export declare const agentSetupPrompt: string;
6
+ export declare const anonymousPublishCurlCommand: string;
6
7
  /**
7
8
  * Typed, safe decline states for the app-private redemption exchange.
8
9
  * `invalid_handoff` is the single answer for both an unknown document ID and a wrong secret, so a
@@ -31,40 +32,42 @@ export type AgentHandoff = Readonly<{
31
32
  }>;
32
33
  /**
33
34
  * The single shared grammar for handoff links:
34
- * `<app-origin>/agent/<documentId>#<secret>`. The document ID must match
35
- * `[A-Za-z0-9_-]{1,512}` and the secret `[A-Za-z0-9_-]{16,512}` (the minimum keeps secrets
36
- * high-entropy and makes the public-projection leak check meaningful); the two must differ;
37
- * queries and embedded credentials are forbidden. The URL must sit exactly on the caller's
38
- * configured HTTP(S) app origin; that origin pin enforces scheme, hostname, and port without a
39
- * second host allowlist that would reject legitimate dev or container origins.
35
+ * `<access-origin>/agent/<documentId>/<oneUseToken>`. The document ID must match
36
+ * `[A-Za-z0-9_-]{1,512}` and the token `[A-Za-z0-9_-]{16,512}`; the two must differ;
37
+ * queries, fragments, and URL userinfo are forbidden. The URL must sit exactly on the caller's
38
+ * configured HTTP(S) access origin; the clean static document may live on a separate explicitly
39
+ * supplied dashboard origin.
40
40
  * Normalization is part of the contract: the input is WHATWG-URL-normalized first (backslashes,
41
41
  * dot segments, stray tab/CR/LF, empty userinfo, case, default ports), the grammar is enforced on
42
42
  * the normalized URL, and only the reconstructed canonical URL ever leaves this function.
43
43
  * Dashboard minting, CLI ingestion, and control-plane validation must all use this parser so the
44
44
  * grammar can never fork.
45
45
  */
46
- export declare function parseAgentHandoffUrl(value: string, expectedOrigin: string): Readonly<{
46
+ export declare function parseAgentHandoffUrl(value: string, expectedOrigin: string, documentOrigin?: string): Readonly<{
47
47
  documentId: string;
48
48
  documentUrl: string;
49
+ handoffUrl: string;
49
50
  secret: string;
50
51
  }>;
51
52
  /** Connect targets whose handoff continues through the CLI stdin exchange. */
52
53
  export declare const AGENT_HANDOFF_CLI_TARGET_IDS: readonly ConnectTargetId[];
53
- export declare const AGENT_HANDOFF_PREAMBLE = "Talk to the user before installing tools or publishing. Confirm the file or folder they want to make public.";
54
+ export declare const AGENT_HANDOFF_PREAMBLE = "Talk to the user before installing tools or publishing. Confirm the file or folder they want to publish.";
54
55
  /** The fetch-safety contract: reading the document never consumes or leaks a handoff. */
55
- export declare const AGENT_HANDOFF_FETCH_SAFETY = "Keep the original handoff link private. Fetching this document did not use the link or send its fragment secret; the secret is spent only by one successful exchange. An expired, used, or revoked link fails safely, so ask the user for a fresh one from the dashboard.";
56
- export declare const AGENT_HANDOFF_FRAGMENT_HYGIENE = "Keep its fragment out of commands, request URLs, logs, and replies.";
56
+ export declare const AGENT_HANDOFF_FETCH_SAFETY = "Keep the original handoff link private. Fetching this clean document URL did not use or send its credential; the credential is spent only by one successful exchange. An expired, used, or revoked link fails safely, so ask the user for a fresh one from the dashboard.";
57
+ export declare const AGENT_HANDOFF_CREDENTIAL_HYGIENE = "Keep the private handoff URL out of commands, request URLs, logs, and replies.";
57
58
  export declare const AGENT_HANDOFF_CLI_APPROVAL_GUIDANCE: string;
58
59
  export declare const AGENT_HANDOFF_BROWSER_APPROVAL_GUIDANCE = "When the client opens browser approval, ask the user to approve there before publishing.";
59
- export declare const AGENT_HANDOFF_PUBLISH_PROSE = "After approval, confirm the selected Space and permissions, then publish only the files the user approved. Share the live URL and immutable version URL from the receipt.";
60
+ export declare const AGENT_HANDOFF_PUBLISH_PROSE = "After approval, confirm the selected Space and permissions, then publish only the files the user approved. Report the bare Live and immutable Version addresses separately from the private Access URL; create a scoped Link when a recipient needs access.";
60
61
  /** One target's Connect prose: blurb, copyable setup blocks, deeplink/download lines. */
61
62
  export declare function agentHandoffConnectSections(target: ConnectTarget): string[];
62
63
  /** Builds every copy-ready handoff artifact from one validated URL and target catalog row. */
63
64
  export declare function buildAgentHandoff(input: {
64
65
  expectedOrigin: string;
66
+ documentOrigin?: string;
65
67
  mcpEndpoint: string;
66
68
  targetId: ConnectTargetId;
67
69
  url: string;
68
70
  }): AgentHandoff;
69
71
  export declare function renderAgentSetupTemplate(value: string): string;
70
72
  export declare function aiInstructionsText(): string;
73
+ export declare function agentSetupMarkdown(): string;
@@ -1,16 +1,29 @@
1
- import { getConnectTarget, } from "../agents/connect-targets.js";
1
+ import { buildClaudeMcpAddCommand, buildHermesMcpAddCommand, cursorHostedMcpDeeplink, cursorHostedMcpServersJson, getConnectTarget, opencodeHostedMcpConfig, vscodeHostedMcpDeeplink, vscodeHostedMcpServersJson, } from "../agents/connect-targets.js";
2
2
  import { BRAND } from "../brand.js";
3
+ import { serviceOrigin } from "../config/domains.js";
4
+ import { createBrowserCredentialUrl, parseBrowserCredentialUrl, } from "../utils/browser-credential.js";
3
5
  import { CHECK_BEFORE_PUBLISH_PROSE, CONTINUE_AFTER_CLAIM_PROSE, ENV_NOTES_PROSE, FAILURE_CONDUCT_PROSE, HOW_TO_RESEARCH_PROSE, LANE_PICKER_PROSE, POSITIONING_PROSE, PUBLISH_SEQUENCE_PROSE, RECEIPT_SHAPE_PROSE, SAVE_STATE_PROSE, SECRET_RULES_PROSE, SIGNED_UPLOAD_PROSE, UPDATE_SPACE_PROSE, } from "./agent-prose.js";
4
- import { spacefastInstallCurlCommand, spacefastInstallPowerShellCommand, spacefastSkillFetchCommand, spacefastSkillInstallCommand, spacefastSkillUrl, } from "./skill-distribution.js";
5
- export const agentSetupUrl = `${BRAND.agentSetupOrigin}/ai`;
6
- export const agentSetupTextUrl = `${BRAND.agentSetupOrigin}/ai.txt`;
6
+ import { spacefastClaudePluginAddCommand, spacefastClaudeDesktopExtensionUrl, spacefastClaudePluginInstallCommand, spacefastCodexPluginAddCommand, spacefastCodexPluginInstallCommand, spacefastInstallCurlCommand, spacefastInstallPowerShellCommand, spacefastSkillFetchCommand, spacefastSkillInstallCommand, spacefastSkillUrl, } from "./skill-distribution.js";
7
+ // The one URL every agent prompt points at. /setup.md is the actionable front
8
+ // door (publish now, then set up your client); /ai.txt stays the deep
9
+ // reference contract it links out to.
10
+ export const agentSetupUrl = `${serviceOrigin("www", "prod")}/setup.md`;
11
+ export const agentSetupTextUrl = `${serviceOrigin("www", "prod")}/ai.txt`;
7
12
  const agentSetupParsedUrl = new URL(agentSetupUrl);
8
13
  export const agentSetupHostLabel = agentSetupParsedUrl.host + agentSetupParsedUrl.pathname;
9
- export const agentSetupPrompt = `Fetch ${agentSetupUrl} and follow it to publish this project — or update it if it's already on ${BRAND.productName}. Ask me what I want to publish if it isn't obvious.`;
14
+ // Deliberately bare: the document itself tells the agent to ask what to
15
+ // publish when it isn't obvious and to update an existing space, so the prompt
16
+ // stays a single gesture that works in any client.
17
+ export const agentSetupPrompt = `Fetch ${agentSetupUrl}`;
18
+ // The no-install publish: one POST, no account. Single-sourced so the
19
+ // marketing pages and the setup doc can never show different commands.
20
+ export const anonymousPublishCurlCommand = `curl -F "files=@index.html" ${serviceOrigin("api", "prod")}/v1/publish`;
10
21
  /*
11
- * Agent handoff contract: links use https://<app-origin>/agent/<documentId>#<secret>, with
12
- * opaque document IDs and secrets. The fragment is the secret, so ordinary document fetches
13
- * never send or reveal it. Fetching never consumes a handoff; exactly one successful redemption
22
+ * Agent handoff contract: private links carry a one-use path token on
23
+ * https://<access-origin>/agent/<documentId>/<token>; durable agent credentials stay encrypted at
24
+ * the broker. Agents fetch the reconstructed clean dashboard document URL, never the private
25
+ * handoff URL. Fetching never consumes a
26
+ * handoff; exactly one successful redemption
14
27
  * does. Redemption is app-private, reuses the existing device/OAuth approval service, and returns
15
28
  * the already-approved finite Space-scoped credential: there is no public AgentGrant resource,
16
29
  * durable key table, or team-wide publisher key. The CLI accepts links only through stdin or a
@@ -47,19 +60,18 @@ function isSafeHttpUrl(url) {
47
60
  }
48
61
  /**
49
62
  * The single shared grammar for handoff links:
50
- * `<app-origin>/agent/<documentId>#<secret>`. The document ID must match
51
- * `[A-Za-z0-9_-]{1,512}` and the secret `[A-Za-z0-9_-]{16,512}` (the minimum keeps secrets
52
- * high-entropy and makes the public-projection leak check meaningful); the two must differ;
53
- * queries and embedded credentials are forbidden. The URL must sit exactly on the caller's
54
- * configured HTTP(S) app origin; that origin pin enforces scheme, hostname, and port without a
55
- * second host allowlist that would reject legitimate dev or container origins.
63
+ * `<access-origin>/agent/<documentId>/<oneUseToken>`. The document ID must match
64
+ * `[A-Za-z0-9_-]{1,512}` and the token `[A-Za-z0-9_-]{16,512}`; the two must differ;
65
+ * queries, fragments, and URL userinfo are forbidden. The URL must sit exactly on the caller's
66
+ * configured HTTP(S) access origin; the clean static document may live on a separate explicitly
67
+ * supplied dashboard origin.
56
68
  * Normalization is part of the contract: the input is WHATWG-URL-normalized first (backslashes,
57
69
  * dot segments, stray tab/CR/LF, empty userinfo, case, default ports), the grammar is enforced on
58
70
  * the normalized URL, and only the reconstructed canonical URL ever leaves this function.
59
71
  * Dashboard minting, CLI ingestion, and control-plane validation must all use this parser so the
60
72
  * grammar can never fork.
61
73
  */
62
- export function parseAgentHandoffUrl(value, expectedOrigin) {
74
+ export function parseAgentHandoffUrl(value, expectedOrigin, documentOrigin = expectedOrigin) {
63
75
  let expectedUrl;
64
76
  try {
65
77
  expectedUrl = new URL(expectedOrigin);
@@ -71,26 +83,54 @@ export function parseAgentHandoffUrl(value, expectedOrigin) {
71
83
  throw new TypeError("Agent handoff expectedOrigin must be an HTTP(S) origin.");
72
84
  }
73
85
  const canonicalExpectedOrigin = expectedUrl.origin;
86
+ let canonicalDocumentOrigin;
87
+ try {
88
+ const documentUrl = new URL(documentOrigin);
89
+ if (!isSafeHttpUrl(documentUrl) ||
90
+ documentUrl.username ||
91
+ documentUrl.password ||
92
+ documentUrl.pathname !== "/" ||
93
+ documentUrl.search ||
94
+ documentUrl.hash) {
95
+ throw new TypeError("invalid_document_origin");
96
+ }
97
+ canonicalDocumentOrigin = documentUrl.origin;
98
+ }
99
+ catch {
100
+ throw new TypeError("Agent handoff documentOrigin must be a clean HTTP(S) origin.");
101
+ }
74
102
  let url;
103
+ let parsedCredential;
75
104
  try {
76
105
  url = new URL(value);
106
+ parsedCredential = parseBrowserCredentialUrl(value);
77
107
  }
78
108
  catch {
79
- throw new TypeError("Agent handoff URL must be a valid HTTP(S) URL.");
109
+ throw new TypeError("Agent handoff URL must be a valid private HTTP(S) URL.");
80
110
  }
81
- const documentId = /^\/agent\/([^/]+)$/.exec(url.pathname)?.[1];
82
- const secret = url.hash.slice(1);
111
+ const documentId = /^\/agent\/([^/]+)\/[^/]+$/.exec(url.pathname)?.[1];
112
+ const secret = parsedCredential.credential;
83
113
  if (url.origin !== canonicalExpectedOrigin ||
84
- url.username !== "" ||
85
- url.password !== "" ||
86
114
  value.includes("?") ||
115
+ url.hash !== "" ||
87
116
  !documentId ||
88
117
  !opaqueHandoffDocumentId.test(documentId) ||
89
118
  !opaqueHandoffSecret.test(secret) ||
90
119
  documentId === secret) {
91
- throw new TypeError("Agent handoff URL must be an /agent/<id> URL on the app origin with one opaque fragment secret (16-512 chars, distinct from the id) and no credentials or query.");
120
+ throw new TypeError("Agent handoff URL must be a private /agent/<id>/<token> URL on the access origin with one opaque token (16-512 chars, distinct from the id) and no userinfo, query, or fragment.");
92
121
  }
93
- return { documentId, documentUrl: `${url.origin}${url.pathname}`, secret };
122
+ const handoffUrl = createBrowserCredentialUrl({
123
+ origin: canonicalExpectedOrigin,
124
+ path: "/agent",
125
+ publicId: documentId,
126
+ credential: secret,
127
+ });
128
+ return {
129
+ documentId,
130
+ documentUrl: new URL(`/agent/${encodeURIComponent(documentId)}`, canonicalDocumentOrigin).toString(),
131
+ handoffUrl,
132
+ secret,
133
+ };
94
134
  }
95
135
  function validateMcpEndpoint(value) {
96
136
  let url;
@@ -112,13 +152,13 @@ function validateMcpEndpoint(value) {
112
152
  */
113
153
  /** Connect targets whose handoff continues through the CLI stdin exchange. */
114
154
  export const AGENT_HANDOFF_CLI_TARGET_IDS = ["claude-code", "codex"];
115
- export const AGENT_HANDOFF_PREAMBLE = "Talk to the user before installing tools or publishing. Confirm the file or folder they want to make public.";
155
+ export const AGENT_HANDOFF_PREAMBLE = "Talk to the user before installing tools or publishing. Confirm the file or folder they want to publish.";
116
156
  /** The fetch-safety contract: reading the document never consumes or leaks a handoff. */
117
- export const AGENT_HANDOFF_FETCH_SAFETY = "Keep the original handoff link private. Fetching this document did not use the link or send its fragment secret; the secret is spent only by one successful exchange. An expired, used, or revoked link fails safely, so ask the user for a fresh one from the dashboard.";
118
- export const AGENT_HANDOFF_FRAGMENT_HYGIENE = "Keep its fragment out of commands, request URLs, logs, and replies.";
157
+ export const AGENT_HANDOFF_FETCH_SAFETY = "Keep the original handoff link private. Fetching this clean document URL did not use or send its credential; the credential is spent only by one successful exchange. An expired, used, or revoked link fails safely, so ask the user for a fresh one from the dashboard.";
158
+ export const AGENT_HANDOFF_CREDENTIAL_HYGIENE = "Keep the private handoff URL out of commands, request URLs, logs, and replies.";
119
159
  export const AGENT_HANDOFF_CLI_APPROVAL_GUIDANCE = `Run \`sf setup agent\` to initiate the handoff exchange; if \`sf\` is missing, install it first (macOS/Linux: \`${spacefastInstallCurlCommand}\`; Windows PowerShell: \`${spacefastInstallPowerShellCommand}\`). When it asks for the handoff link on stdin, paste the original link into that prompt; never pass the link as an argv value. Ask the user to approve in the browser, then wait for the CLI's approval result before publishing.`;
120
160
  export const AGENT_HANDOFF_BROWSER_APPROVAL_GUIDANCE = "When the client opens browser approval, ask the user to approve there before publishing.";
121
- export const AGENT_HANDOFF_PUBLISH_PROSE = "After approval, confirm the selected Space and permissions, then publish only the files the user approved. Share the live URL and immutable version URL from the receipt.";
161
+ export const AGENT_HANDOFF_PUBLISH_PROSE = "After approval, confirm the selected Space and permissions, then publish only the files the user approved. Report the bare Live and immutable Version addresses separately from the private Access URL; create a scoped Link when a recipient needs access.";
122
162
  /** One target's Connect prose: blurb, copyable setup blocks, deeplink/download lines. */
123
163
  export function agentHandoffConnectSections(target) {
124
164
  const setupSections = [target.primary, target.config].flatMap((setup) => setup ? [[setup.label, `\`\`\`${setup.language}`, setup.value, "```"].join("\n")] : []);
@@ -142,7 +182,7 @@ function renderAgentHandoffInstructions(documentUrl, target) {
142
182
  "## Continue the approved handoff",
143
183
  AGENT_HANDOFF_FETCH_SAFETY,
144
184
  approvalGuidance,
145
- AGENT_HANDOFF_FRAGMENT_HYGIENE,
185
+ AGENT_HANDOFF_CREDENTIAL_HYGIENE,
146
186
  ].join("\n\n"),
147
187
  ["## Publish", AGENT_HANDOFF_PUBLISH_PROSE].join("\n\n"),
148
188
  `General agent instructions: ${agentSetupTextUrl}`,
@@ -151,12 +191,12 @@ function renderAgentHandoffInstructions(documentUrl, target) {
151
191
  }
152
192
  /** Builds every copy-ready handoff artifact from one validated URL and target catalog row. */
153
193
  export function buildAgentHandoff(input) {
154
- const { documentUrl, secret } = parseAgentHandoffUrl(input.url, input.expectedOrigin);
194
+ const { documentUrl, handoffUrl, secret } = parseAgentHandoffUrl(input.url, input.expectedOrigin, input.documentOrigin);
155
195
  const mcpEndpoint = validateMcpEndpoint(input.mcpEndpoint);
156
196
  const target = getConnectTarget(input.targetId, {
157
197
  mcpEndpoint,
158
198
  });
159
- const prompt = `Fetch ${documentUrl}#${secret} and follow the ${target.name} setup instructions to publish with ${BRAND.productName}. Ask me what I want to publish if it isn't obvious.`;
199
+ const prompt = `Fetch ${documentUrl} and follow the ${target.name} setup instructions to publish with ${BRAND.productName}. Use this private one-use handoff only for the exchange step: ${handoffUrl}. Do not fetch the private handoff URL. Ask me what I want to publish if it isn't obvious.`;
160
200
  const instructions = renderAgentHandoffInstructions(documentUrl, target);
161
201
  const actions = [
162
202
  { kind: "copy", label: "Copy for my agent", sensitive: true, value: prompt },
@@ -188,7 +228,7 @@ export function buildAgentHandoff(input) {
188
228
  }),
189
229
  ];
190
230
  if (publicProjections.some((projection) => projection.includes(secret))) {
191
- throw new TypeError("Agent handoff inputs would leak the fragment secret into a public projection.");
231
+ throw new TypeError("Agent handoff inputs would leak the private credential into a public projection.");
192
232
  }
193
233
  return { actions, documentUrl, instructions, prompt };
194
234
  }
@@ -244,13 +284,13 @@ export function aiInstructionsText() {
244
284
  HOW_TO_RESEARCH_PROSE,
245
285
  "",
246
286
  'Add a bearer access token with `-H "Authorization: Bearer ..."` to publish into the user\'s',
247
- "team instead of anonymously. Agent clients should prefer OAuth client credentials. Errors come back as JSON with stable `code` values and a",
248
- "`docsUrl`; fetch the `docsUrl` when you need recovery steps.",
287
+ "team instead of anonymously. Agent clients should prefer OAuth client credentials. Errors come back as RFC 9457 problem documents with stable `code` values and a",
288
+ "`type` URL; fetch the `type` URL when you need recovery steps.",
249
289
  "",
250
290
  "## Install the CLI (On-Device files, updates, versions, rollback, and the rest)",
251
291
  "",
252
292
  "The CLI is the full surface: incremental publishes, version history, rollback,",
253
- "passwords, domains, logs, and diagnostics. Install it when the user will keep",
293
+ "sharing, domains, logs, and diagnostics. Install it when the user will keep",
254
294
  "working on the space:",
255
295
  "",
256
296
  "```bash",
@@ -282,7 +322,7 @@ export function aiInstructionsText() {
282
322
  LANE_PICKER_PROSE,
283
323
  "",
284
324
  "Hosted MCP is the no-download cloud lane for ChatGPT, Codex, Claude, Cursor, and browser",
285
- "clients that can authenticate with OAuth/API bearer credentials:",
325
+ "clients that can authenticate with OAuth:",
286
326
  "",
287
327
  "```text",
288
328
  "https://mcp.spacefast.com",
@@ -291,26 +331,19 @@ export function aiInstructionsText() {
291
331
  "Request `mcp:tools` plus the API scopes the tools need: `teams:read` for team context,",
292
332
  "`teams:create` for creating teams,",
293
333
  "`spaces:read` for status, versions, diffs, and logs, `spaces:write` for claim/create/update,",
294
- "`publish:write` for publish and rollback, and `domains:read`/`domains:write` for domain",
295
- "inventory, DNS diagnostics, assignment, verification, and mutation. Hosted MCP does not read",
296
- "local paths; its workspace tools operate on a durable virtual workspace attached to the MCP",
297
- "session.",
298
- "",
299
- "For hosted MCP, prefer `prepare_publish`, `resume_publish`, and `finalize_publish` for large",
300
- "artifacts so the agent uploads to signed URLs instead of stuffing bytes into tool calls. Use",
301
- "`import_from_url` when the archive already has an HTTPS URL. Hosted MCP is the right path for",
334
+ "`spaces:rename` for slug and managed-address renames, `publish:write` for publish and rollback,",
335
+ "and `domains:read`/`domains:write` for domain",
336
+ "inventory, DNS diagnostics, assignment, verification, and mutation. Hosted MCP has no",
337
+ "filesystem access.",
338
+ "",
339
+ "For hosted MCP, call `publish` with inline files. For larger artifacts, use `execute` to",
340
+ "discover and invoke the catalog publish operations. Hosted MCP is the right path for",
302
341
  "ChatGPT/browser agents because it requires no download and never claims local filesystem access.",
303
- "For generated files, use `workspace_write` or `workspace_import`, review with",
304
- "`workspace_manifest` / `workspace_diff`, hand off with `workspace_export`, and publish the",
305
- 'virtual workspace with `publish({ path: "." })`.',
306
- "Before acting on authenticated spaces, load MCP resources such as",
307
- "`spacefast://account/current`, `spacefast://teams/current`, `spacefast://spaces/recent`,",
308
- "`spacefast://spaces/{spaceId}`, and `spacefast://policy/current` for bounded read-only",
309
- "context.",
310
- "`execute` is dry-run-first; mutating multi-step workflows can return",
311
- "`approval_required` and continue through `resume` after the user approves.",
312
- "",
313
- "Use On-Device MCP when the agent needs the user's checkout, path-based publish, or file edits:",
342
+ "`execute` runs code in Spacefast's secure QuickJS sandbox. Mutating OpenAPI calls pause before HTTP",
343
+ "and return an execution ID; continue the same live execution with `resume` and an",
344
+ "`accept`, `decline`, or `cancel` action.",
345
+ "",
346
+ "Use On-Device MCP when the agent needs path-based publish from the user's checkout:",
314
347
  "",
315
348
  "```bash",
316
349
  "sf setup agent --agent auto --connect",
@@ -329,8 +362,10 @@ export function aiInstructionsText() {
329
362
  "",
330
363
  "## After publishing",
331
364
  "",
332
- "- Share the live URL, the immutable version URL when ready, and for anonymous spaces —",
333
- " the claim link with its expiry. If the receipt's immutable URL is null, poll the",
365
+ "- Report the bare Live URL, the immutable Version URL when ready, the private Access URL, and",
366
+ " — for anonymous spaces — the claim link with its expiry. Bare Live and Version URLs carry",
367
+ " no authority for a private Space; create a scoped Link when a recipient needs access.",
368
+ " If the receipt's immutable URL is null, poll the",
334
369
  " operation and version links with the claim token as bearer auth until the version is ready.",
335
370
  "- Never print access tokens, claim tokens, auth files, or `.spacefast/state.json`.",
336
371
  "",
@@ -342,16 +377,16 @@ export function aiInstructionsText() {
342
377
  "",
343
378
  "- `_redirects` — redirects, rewrites, SPA fallbacks, custom 404 rules, and external",
344
379
  " `200` proxy rules.",
345
- "- `_headers` — response headers and Basic Auth rules.",
380
+ "- `_headers` — supported response headers.",
346
381
  "- `404.html` — custom not-found page.",
347
- "- `sf.jsonc` — serving config (index, fallback, listing, meta) and the optional",
348
- " `space` link. JSON Schema: https://spacefast.com/schemas/sf.json",
382
+ "- `sf.jsonc` — serving config (index, fallback, listing, meta), the optional `space`",
383
+ " link, and `redirects` / `rewrites` / `headers` arrays in the same matcher grammar",
384
+ " the files use. JSON Schema: https://spacefast.com/schemas/sf.json",
349
385
  "- `/llms.txt` and `/ai.txt` — publish these in the user's site when it should be",
350
386
  " agent-readable too.",
351
387
  "- Plan limits surface as diagnostics, not failures you should guess at: publish the",
352
388
  " intended artifact, then read and report what the CLI or API says. When a feature",
353
- ' is plan-gated, say: "Not available on Free. Available on Personal and Work." For',
354
- " simple gated access, `sf password set` needs no plan and no `_headers` rule.",
389
+ ' is plan-gated, say: "Not available on Free. Available on Personal and Work."',
355
390
  "",
356
391
  "## Agent-aware routing",
357
392
  "",
@@ -366,7 +401,7 @@ export function aiInstructionsText() {
366
401
  "",
367
402
  "- Docs index for agents: https://spacefast.com/llms.txt",
368
403
  "- One-click connect (Claude Code, Claude, Codex, Cursor, VS Code): https://spacefast.com/agents",
369
- "- Agent guide: https://spacefast.com/docs/agents",
404
+ "- Agent guide: https://spacefast.com/docs/getting-started/agents",
370
405
  "- CLI reference: https://spacefast.com/docs/cli",
371
406
  "- REST API + OpenAPI: https://spacefast.com/docs/api",
372
407
  "- Publish contract (machine-readable): https://spacefast.com/publish-spec.json",
@@ -382,3 +417,196 @@ export function aiInstructionsText() {
382
417
  "",
383
418
  ].join("\n");
384
419
  }
420
+ /*
421
+ * The /setup.md document — the one URL every agent prompt points at. Modeled
422
+ * on the Cloudflare/here.now agent-setup prompts: publish first with zero
423
+ * install, then per-client setup for repeat use. Every command, endpoint,
424
+ * deeplink, and config here is derived from the same canonical constants as
425
+ * the plugin tree and the agent card, so this document can never drift from
426
+ * what we ship. Keep it short enough that an agent reads it whole; the deep
427
+ * contract stays in aiInstructionsText() (/ai.txt).
428
+ */
429
+ export function agentSetupMarkdown() {
430
+ const mcpEndpoint = serviceOrigin("mcp", "prod");
431
+ const dropUrl = `${serviceOrigin("dashboard", "prod")}/drop`;
432
+ return [
433
+ `# ${BRAND.productName} agent setup`,
434
+ "",
435
+ `These are official instructions from ${BRAND.productName} for AI agents. Follow them to publish the user's file, folder, site, or app to a live URL — then, optionally, set up your own client so the next publish is one word. Every command on this page is validated by ${BRAND.productName} and ready to run.`,
436
+ "",
437
+ "Talk to the user before publishing. Confirm the file or folder they want to publish; if it isn't obvious, ask.",
438
+ "",
439
+ "## Before you publish — reuse an existing space",
440
+ "",
441
+ CHECK_BEFORE_PUBLISH_PROSE,
442
+ "",
443
+ "## Publish now — no install, no account",
444
+ "",
445
+ "Publish a single file with one POST:",
446
+ "",
447
+ "```bash",
448
+ anonymousPublishCurlCommand,
449
+ "```",
450
+ "",
451
+ "For a folder, zip the public output only — never a repository root, never `.env*`,",
452
+ "credentials, `.git`, or `.spacefast` — and send it as `-F archive=@site.zip` to the same",
453
+ "endpoint. Fetch the full contract when a publish goes beyond the happy path:",
454
+ `${agentSetupTextUrl}.`,
455
+ "",
456
+ "The JSON receipt is the result:",
457
+ "",
458
+ "- `data.space.liveUrl` — the live URL. Lead the reply with it.",
459
+ "- `data.version.immutableUrl` — the permanent address of this version.",
460
+ "- `data.claim.url` and `data.claim.expiresAt` — an anonymous space expires unless claimed.",
461
+ " Always show the claim link and its deadline.",
462
+ "- `data.claim.token` — a secret. Use it as the bearer to update the same `spaceId`;",
463
+ " never print it.",
464
+ "",
465
+ "## If you can't act on this page",
466
+ "",
467
+ "Reading this but unable to run commands or make HTTP requests — no shell, no",
468
+ "fetch-and-POST tool? Then this surface can't publish. Say that plainly and tell the",
469
+ "user what unlocks it:",
470
+ "",
471
+ "- In ChatGPT: switch to Work mode or the desktop app (paid plans). The Free plan",
472
+ " can't publish.",
473
+ "- In any other client: enable its tool/agent mode, or pick a client from",
474
+ ` ${serviceOrigin("www", "prod")}/setup.`,
475
+ "",
476
+ "Don't fall back to generating files for the user to download and re-upload by hand",
477
+ "unless they ask for exactly that.",
478
+ "",
479
+ "## Set up your agent (optional, for repeat use)",
480
+ "",
481
+ 'Use the section for your client. If yours isn\'t listed, use "Every other agent".',
482
+ "",
483
+ "### Claude Code",
484
+ "",
485
+ "The plugin ships the publish skill plus MCP in one install:",
486
+ "",
487
+ "```bash",
488
+ spacefastClaudePluginAddCommand,
489
+ spacefastClaudePluginInstallCommand,
490
+ "```",
491
+ "",
492
+ "Restart Claude Code (or run `/reload-plugins`) to activate it. MCP-only alternative:",
493
+ "",
494
+ "```bash",
495
+ buildClaudeMcpAddCommand(mcpEndpoint),
496
+ "```",
497
+ "",
498
+ "### Codex",
499
+ "",
500
+ "```bash",
501
+ spacefastCodexPluginAddCommand,
502
+ spacefastCodexPluginInstallCommand,
503
+ "```",
504
+ "",
505
+ "Or teach every task in a repository with one AGENTS.md line:",
506
+ "",
507
+ "```text",
508
+ `To publish, fetch ${agentSetupUrl} and follow the instructions.`,
509
+ "```",
510
+ "",
511
+ "### Cursor",
512
+ "",
513
+ `One click: ${cursorHostedMcpDeeplink(mcpEndpoint)}`,
514
+ "",
515
+ "Or add to `~/.cursor/mcp.json`:",
516
+ "",
517
+ "```json",
518
+ JSON.stringify(cursorHostedMcpServersJson(mcpEndpoint), null, 2),
519
+ "```",
520
+ "",
521
+ "### VS Code",
522
+ "",
523
+ `One click: ${vscodeHostedMcpDeeplink(mcpEndpoint)}`,
524
+ "",
525
+ "Or add to `.vscode/mcp.json`:",
526
+ "",
527
+ "```json",
528
+ JSON.stringify(vscodeHostedMcpServersJson(mcpEndpoint), null, 2),
529
+ "```",
530
+ "",
531
+ "### Claude (web, desktop, and Cowork)",
532
+ "",
533
+ "Settings → Connectors → Add custom connector, paste the endpoint. Approve once in the",
534
+ "browser, nothing to install:",
535
+ "",
536
+ "```text",
537
+ mcpEndpoint,
538
+ "```",
539
+ "",
540
+ "On desktop, the extension is a double-click install:",
541
+ spacefastClaudeDesktopExtensionUrl,
542
+ "",
543
+ "### ChatGPT and ChatGPT Work",
544
+ "",
545
+ // TODO(plugin-directory): once the Spacefast listing is live, lead this
546
+ // section with the one-click Plugin Directory install instead.
547
+ "Publishing works from Work mode or the desktop app (paid plans) — follow the",
548
+ "publish-now section above; nothing to install. On ChatGPT Work, an admin can add",
549
+ "Spacefast once as a workspace app (Workspace settings → Apps) with the endpoint",
550
+ "below and deploy it to the whole team:",
551
+ "",
552
+ "```text",
553
+ mcpEndpoint,
554
+ "```",
555
+ "",
556
+ "If this ChatGPT can't run tools (Free plan, plain Chat), say so and point the user",
557
+ "at Work mode or the desktop app — see “If you can't act on this page”.",
558
+ "",
559
+ "### Every other agent (OpenClaw, Hermes, Raycast, Pi, OpenCode, Devin, Poke, Indent, …)",
560
+ "",
561
+ "Install the publish skill:",
562
+ "",
563
+ "```bash",
564
+ spacefastSkillInstallCommand,
565
+ "```",
566
+ "",
567
+ "Clients that speak MCP add the hosted server; sign-in happens once on first tool use.",
568
+ "Hermes — one command:",
569
+ "",
570
+ "```bash",
571
+ buildHermesMcpAddCommand(mcpEndpoint),
572
+ "```",
573
+ "",
574
+ "OpenCode V2 — merge this schema-pinned config into `~/.config/opencode/opencode.jsonc`:",
575
+ "",
576
+ "```json",
577
+ JSON.stringify(opencodeHostedMcpConfig(mcpEndpoint), null, 2),
578
+ "```",
579
+ "",
580
+ 'Any other MCP client, under `"mcpServers"`:',
581
+ "",
582
+ "```json",
583
+ `"spacefast": { "url": "${mcpEndpoint}" }`,
584
+ "```",
585
+ "",
586
+ `Chat agents without tools (Pi, Poke): create a self-contained index.html and upload it at ${dropUrl}.`,
587
+ "",
588
+ "## After publishing",
589
+ "",
590
+ "- Report the live URL first, then the immutable version URL, then the claim link with",
591
+ " its expiry.",
592
+ "- Persist the space id and credential so the next publish updates the same space instead",
593
+ " of creating a new one. The CLI and On-Device MCP do this automatically in `.spacefast/`.",
594
+ " Hosted MCP is stateless between publishes: retain the receipt's `spaceId` in conversation",
595
+ " or project context and pass it explicitly on the next publish.",
596
+ "- To update, post to the same endpoint with `--form-string 'spaceId=<spc_id>'` and the",
597
+ " saved bearer token.",
598
+ "- Recommend the matching setup above so the next publish is one word.",
599
+ "",
600
+ "## Resources",
601
+ "",
602
+ `- Full publishing contract for agents: ${agentSetupTextUrl}`,
603
+ `- One-POST publish spec (machine-readable): ${serviceOrigin("www", "prod")}/publish-spec.json`,
604
+ `- Docs index for agents: ${serviceOrigin("www", "prod")}/llms.txt`,
605
+ `- Human setup guides, per agent: ${serviceOrigin("www", "prod")}/setup`,
606
+ `- CLI (versions, rollback, domains, logs): \`${spacefastInstallCurlCommand}\` — Windows PowerShell: \`${spacefastInstallPowerShellCommand}\``,
607
+ "- Every API error code: https://spacefast.com/docs/errors",
608
+ "",
609
+ `These instructions are published at ${agentSetupUrl} so you can re-verify their authenticity at any time.`,
610
+ "",
611
+ ].join("\n");
612
+ }
@@ -52,9 +52,9 @@ export declare const agentSolutions: readonly [{
52
52
  readonly aliases: readonly ["chatgpt", "custom gpt", "openai apps"];
53
53
  readonly lane: "hosted-mcp";
54
54
  readonly summary: "Recommended: direct hosted MCP.";
55
- readonly description: "Connect ChatGPT-style cloud agents to Spacefast through hosted MCP; use the virtual workspace or signed uploads instead of local paths.";
55
+ readonly description: "Connect ChatGPT-style cloud agents to Spacefast through hosted MCP; use inline files or signed uploads instead of local paths.";
56
56
  readonly commands: readonly ["https://mcp.spacefast.com"];
57
- readonly guideUrl: `${string}/docs/agents`;
57
+ readonly guideUrl: `${string}/getting-started/agents`;
58
58
  readonly setupText: string;
59
59
  }, {
60
60
  readonly id: "claude-ai";
@@ -64,7 +64,7 @@ export declare const agentSolutions: readonly [{
64
64
  readonly summary: "Recommended: direct hosted MCP.";
65
65
  readonly description: "Connect the web Claude app to Spacefast through hosted MCP when it cannot read your local checkout.";
66
66
  readonly commands: readonly ["https://mcp.spacefast.com"];
67
- readonly guideUrl: `${string}/docs/agents`;
67
+ readonly guideUrl: `${string}/getting-started/agents`;
68
68
  readonly setupText: string;
69
69
  }, {
70
70
  readonly id: "raycast";
@@ -74,7 +74,7 @@ export declare const agentSolutions: readonly [{
74
74
  readonly summary: "Recommended: direct hosted MCP.";
75
75
  readonly description: "Use hosted MCP for Raycast and similar clients that can connect to a remote MCP server but should not need a local Spacefast install.";
76
76
  readonly commands: readonly ["https://mcp.spacefast.com"];
77
- readonly guideUrl: `${string}/docs/agents`;
77
+ readonly guideUrl: `${string}/getting-started/agents`;
78
78
  readonly setupText: string;
79
79
  }, {
80
80
  readonly id: "cursor";
@@ -84,7 +84,7 @@ export declare const agentSolutions: readonly [{
84
84
  readonly summary: "Recommended: local MCP when it needs the checkout.";
85
85
  readonly description: "Use On-Device MCP for editor agents that need local files; use hosted MCP instead when they only need cloud-safe tools.";
86
86
  readonly commands: readonly ["sf setup agent --agent auto --connect", "sf mcp install --agent auto --mode local --transport stdio --connect"];
87
- readonly guideUrl: `${string}/docs/agents`;
87
+ readonly guideUrl: `${string}/getting-started/agents`;
88
88
  readonly setupText: string;
89
89
  }, {
90
90
  readonly id: "terminal";
@@ -94,7 +94,7 @@ export declare const agentSolutions: readonly [{
94
94
  readonly summary: "Recommended: Spacefast CLI.";
95
95
  readonly description: "Use the CLI for repeat publishes, CI jobs, JSON output, rollback, logs, and domains.";
96
96
  readonly commands: readonly [string, "sf login", "sf publish {file-or-dir} --json"];
97
- readonly guideUrl: `${string}/docs/cli`;
97
+ readonly guideUrl: `${string}/cli`;
98
98
  readonly setupText: string;
99
99
  }, {
100
100
  readonly id: "generic";