@treeseed/sdk 0.1.1 → 0.3.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 (228) hide show
  1. package/README.md +97 -494
  2. package/dist/{src/cli-tools.d.ts → cli-tools.d.ts} +1 -1
  3. package/dist/cli-tools.js +5 -3
  4. package/dist/{src/content-store.d.ts → content-store.d.ts} +3 -2
  5. package/dist/content-store.js +52 -20
  6. package/dist/{src/d1-store.d.ts → d1-store.d.ts} +62 -1
  7. package/dist/d1-store.js +625 -65
  8. package/dist/field-aliases.d.ts +11 -0
  9. package/dist/field-aliases.js +41 -0
  10. package/dist/graph/build.d.ts +19 -0
  11. package/dist/graph/build.js +949 -0
  12. package/dist/graph/dsl.d.ts +2 -0
  13. package/dist/graph/dsl.js +243 -0
  14. package/dist/graph/query.d.ts +47 -0
  15. package/dist/graph/query.js +447 -0
  16. package/dist/graph/ranking.d.ts +3 -0
  17. package/dist/graph/ranking.js +483 -0
  18. package/dist/graph/schema.d.ts +142 -0
  19. package/dist/graph/schema.js +133 -0
  20. package/dist/graph.d.ts +52 -0
  21. package/dist/graph.js +133 -0
  22. package/dist/index.d.ts +27 -0
  23. package/dist/index.js +90 -2
  24. package/dist/model-registry.d.ts +8 -0
  25. package/dist/model-registry.js +351 -25
  26. package/dist/operations/providers/default.d.ts +10 -0
  27. package/dist/operations/providers/default.js +514 -0
  28. package/dist/operations/runtime.d.ts +7 -0
  29. package/dist/operations/runtime.js +60 -0
  30. package/dist/operations/services/config-runtime.d.ts +269 -0
  31. package/dist/operations/services/config-runtime.js +1397 -0
  32. package/dist/operations/services/d1-migration.d.ts +6 -0
  33. package/dist/operations/services/d1-migration.js +89 -0
  34. package/dist/operations/services/deploy.d.ts +371 -0
  35. package/dist/operations/services/deploy.js +981 -0
  36. package/dist/operations/services/git-workflow.d.ts +49 -0
  37. package/dist/operations/services/git-workflow.js +218 -0
  38. package/dist/operations/services/github-automation.d.ts +156 -0
  39. package/dist/operations/services/github-automation.js +256 -0
  40. package/dist/operations/services/local-dev.d.ts +9 -0
  41. package/dist/operations/services/local-dev.js +106 -0
  42. package/dist/operations/services/mailpit-runtime.d.ts +4 -0
  43. package/dist/operations/services/mailpit-runtime.js +59 -0
  44. package/dist/operations/services/railway-deploy.d.ts +53 -0
  45. package/dist/operations/services/railway-deploy.js +123 -0
  46. package/dist/operations/services/runtime-paths.d.ts +19 -0
  47. package/dist/operations/services/runtime-paths.js +54 -0
  48. package/dist/operations/services/runtime-tools.d.ts +117 -0
  49. package/dist/operations/services/runtime-tools.js +358 -0
  50. package/dist/operations/services/save-deploy-preflight.d.ts +34 -0
  51. package/dist/operations/services/save-deploy-preflight.js +76 -0
  52. package/dist/operations/services/template-registry.d.ts +88 -0
  53. package/dist/operations/services/template-registry.js +407 -0
  54. package/dist/operations/services/watch-dev.d.ts +21 -0
  55. package/dist/operations/services/watch-dev.js +284 -0
  56. package/dist/operations/services/workspace-preflight.d.ts +40 -0
  57. package/dist/operations/services/workspace-preflight.js +165 -0
  58. package/dist/operations/services/workspace-save.d.ts +42 -0
  59. package/dist/operations/services/workspace-save.js +235 -0
  60. package/dist/operations/services/workspace-tools.d.ts +16 -0
  61. package/dist/operations/services/workspace-tools.js +270 -0
  62. package/dist/operations-registry.d.ts +5 -0
  63. package/dist/operations-registry.js +68 -0
  64. package/dist/operations-types.d.ts +71 -0
  65. package/dist/operations-types.js +17 -0
  66. package/dist/operations.d.ts +6 -0
  67. package/dist/operations.js +16 -0
  68. package/dist/platform/books-data.d.ts +1 -0
  69. package/dist/platform/books-data.js +1 -0
  70. package/dist/platform/contracts.d.ts +158 -0
  71. package/dist/platform/contracts.js +0 -0
  72. package/dist/platform/deploy/config.d.ts +4 -0
  73. package/dist/platform/deploy/config.js +222 -0
  74. package/dist/platform/deploy-config.d.ts +1 -0
  75. package/dist/platform/deploy-config.js +1 -0
  76. package/dist/platform/env.yaml +394 -0
  77. package/dist/platform/environment.d.ts +130 -0
  78. package/dist/platform/environment.js +331 -0
  79. package/dist/platform/plugin.d.ts +2 -0
  80. package/dist/platform/plugin.js +4 -0
  81. package/dist/platform/plugins/constants.d.ts +22 -0
  82. package/dist/platform/plugins/constants.js +29 -0
  83. package/dist/platform/plugins/plugin.d.ts +51 -0
  84. package/dist/platform/plugins/plugin.js +6 -0
  85. package/dist/platform/plugins/runtime.d.ts +35 -0
  86. package/dist/platform/plugins/runtime.js +142 -0
  87. package/dist/platform/plugins.d.ts +5 -0
  88. package/dist/platform/plugins.js +16 -0
  89. package/dist/platform/site-config-schema.js +1 -0
  90. package/dist/platform/tenant/config.d.ts +9 -0
  91. package/dist/platform/tenant/config.js +154 -0
  92. package/dist/platform/tenant/runtime-config.d.ts +4 -0
  93. package/dist/platform/tenant/runtime-config.js +20 -0
  94. package/dist/platform/tenant-config.d.ts +1 -0
  95. package/dist/platform/tenant-config.js +1 -0
  96. package/dist/platform/utils/books-data.d.ts +29 -0
  97. package/dist/platform/utils/books-data.js +82 -0
  98. package/dist/platform/utils/site-config-schema.js +321 -0
  99. package/dist/remote.d.ts +175 -0
  100. package/dist/remote.js +202 -0
  101. package/dist/runtime.js +50 -3
  102. package/dist/scripts/aggregate-book.js +121 -0
  103. package/dist/scripts/build-dist.js +57 -13
  104. package/dist/scripts/build-tenant-worker.js +36 -0
  105. package/dist/scripts/cleanup-markdown.js +373 -0
  106. package/dist/scripts/cli-test-fixtures.js +48 -0
  107. package/dist/scripts/config-treeseed.js +95 -0
  108. package/dist/scripts/ensure-mailpit.js +29 -0
  109. package/dist/scripts/local-dev.js +129 -0
  110. package/dist/scripts/logs-mailpit.js +2 -0
  111. package/dist/scripts/patch-starlight-content-path.js +172 -0
  112. package/dist/scripts/release-verify.js +34 -5
  113. package/dist/scripts/run-fixture-astro-command.js +18 -0
  114. package/dist/scripts/scaffold-site.js +65 -0
  115. package/dist/scripts/stop-mailpit.js +5 -0
  116. package/dist/scripts/sync-dev-vars.js +6 -0
  117. package/dist/scripts/sync-template.js +20 -0
  118. package/dist/scripts/template-catalog.test.js +100 -0
  119. package/dist/scripts/template-command.js +31 -0
  120. package/dist/scripts/tenant-astro-command.js +3 -0
  121. package/dist/scripts/tenant-build.js +16 -0
  122. package/dist/scripts/tenant-check.js +7 -0
  123. package/dist/scripts/tenant-d1-migrate-local.js +11 -0
  124. package/dist/scripts/tenant-deploy.js +180 -0
  125. package/dist/scripts/tenant-destroy.js +104 -0
  126. package/dist/scripts/tenant-dev.js +171 -0
  127. package/dist/scripts/tenant-lint.js +4 -0
  128. package/dist/scripts/tenant-test.js +4 -0
  129. package/dist/scripts/test-cloudflare-local.js +212 -0
  130. package/dist/scripts/test-scaffold.js +314 -0
  131. package/dist/scripts/test-smoke.js +71 -13
  132. package/dist/scripts/treeseed-assert-release-tag-version.js +21 -0
  133. package/dist/scripts/treeseed-build-dist.js +134 -0
  134. package/dist/scripts/treeseed-publish-package.js +19 -0
  135. package/dist/scripts/treeseed-release-verify.js +131 -0
  136. package/dist/scripts/treeseed-run-ts.js +45 -0
  137. package/dist/scripts/validate-templates.js +6 -0
  138. package/dist/scripts/verify-driver.js +29 -0
  139. package/dist/scripts/workflow-commands.test.js +39 -0
  140. package/dist/scripts/workspace-close.js +24 -0
  141. package/dist/scripts/workspace-command-e2e.js +718 -0
  142. package/dist/scripts/workspace-lint.js +9 -0
  143. package/dist/scripts/workspace-preflight.js +22 -0
  144. package/dist/scripts/workspace-publish-changed-packages.js +16 -0
  145. package/dist/scripts/workspace-release-verify.js +81 -0
  146. package/dist/scripts/workspace-release.js +42 -0
  147. package/dist/scripts/workspace-save.js +124 -0
  148. package/dist/scripts/workspace-start-warning.js +3 -0
  149. package/dist/scripts/workspace-start.js +71 -0
  150. package/dist/scripts/workspace-test-unit.js +4 -0
  151. package/dist/scripts/workspace-test.js +11 -0
  152. package/dist/sdk-fields.d.ts +11 -0
  153. package/dist/sdk-fields.js +169 -0
  154. package/dist/sdk-filters.d.ts +4 -0
  155. package/dist/sdk-filters.js +12 -15
  156. package/dist/sdk-types.d.ts +796 -0
  157. package/dist/sdk-types.js +7 -1
  158. package/dist/sdk-version.d.ts +2 -0
  159. package/dist/sdk-version.js +42 -0
  160. package/dist/sdk.d.ts +215 -0
  161. package/dist/sdk.js +235 -11
  162. package/dist/stores/cursor-store.js +9 -3
  163. package/dist/stores/lease-store.js +8 -2
  164. package/dist/{src/stores → stores}/message-store.d.ts +1 -1
  165. package/dist/stores/message-store.js +27 -3
  166. package/dist/stores/operational-store.d.ts +24 -0
  167. package/dist/stores/operational-store.js +279 -0
  168. package/dist/stores/run-store.js +8 -1
  169. package/dist/stores/subscription-store.js +7 -5
  170. package/dist/template-catalog.d.ts +13 -0
  171. package/dist/template-catalog.js +141 -0
  172. package/dist/treeseed/services/compose.yml +7 -0
  173. package/dist/treeseed/template-catalog/catalog.fixture.json +55 -0
  174. package/dist/treeseed/template-catalog/templates/starter-basic/template/astro.config.d.ts +2 -0
  175. package/dist/treeseed/template-catalog/templates/starter-basic/template/astro.config.ts +3 -0
  176. package/dist/treeseed/template-catalog/templates/starter-basic/template/package.json +32 -0
  177. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/config.yaml +40 -0
  178. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/empty/.gitkeep +1 -0
  179. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/knowledge/handbook/index.mdx +11 -0
  180. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/pages/welcome.mdx +11 -0
  181. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content.config.d.ts +1 -0
  182. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content.config.ts +3 -0
  183. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/env.yaml +1 -0
  184. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/manifest.yaml +19 -0
  185. package/dist/treeseed/template-catalog/templates/starter-basic/template/treeseed.site.yaml +26 -0
  186. package/dist/treeseed/template-catalog/templates/starter-basic/template/tsconfig.json +9 -0
  187. package/dist/treeseed/template-catalog/templates/starter-basic/template.config.json +90 -0
  188. package/dist/verification.d.ts +20 -0
  189. package/dist/verification.js +98 -0
  190. package/dist/workflow/operations.d.ts +396 -0
  191. package/dist/workflow/operations.js +841 -0
  192. package/dist/workflow-state.d.ts +56 -0
  193. package/dist/workflow-state.js +195 -0
  194. package/dist/workflow-support.d.ts +9 -0
  195. package/dist/workflow-support.js +176 -0
  196. package/dist/workflow.d.ts +111 -0
  197. package/dist/workflow.js +97 -0
  198. package/package.json +97 -5
  199. package/scripts/verify-driver.mjs +29 -0
  200. package/dist/scripts/.ts-run-1775616845195-odh4xzphk3l.js +0 -22
  201. package/dist/scripts/.ts-run-1775616848931-9386s6kwrl.js +0 -126
  202. package/dist/scripts/assert-release-tag-version.d.ts +0 -1
  203. package/dist/scripts/build-dist.d.ts +0 -1
  204. package/dist/scripts/package-tools.d.ts +0 -15
  205. package/dist/scripts/publish-package.d.ts +0 -1
  206. package/dist/scripts/release-verify.d.ts +0 -1
  207. package/dist/scripts/test-smoke.d.ts +0 -1
  208. package/dist/src/index.d.ts +0 -6
  209. package/dist/src/model-registry.d.ts +0 -4
  210. package/dist/src/sdk-filters.d.ts +0 -4
  211. package/dist/src/sdk-types.d.ts +0 -285
  212. package/dist/src/sdk.d.ts +0 -109
  213. package/dist/test/test-fixture.d.ts +0 -1
  214. package/dist/test/utils/envelopes.test.d.ts +0 -1
  215. package/dist/test/utils/sdk.test.d.ts +0 -1
  216. package/dist/vitest.config.d.ts +0 -2
  217. /package/dist/{src/frontmatter.d.ts → frontmatter.d.ts} +0 -0
  218. /package/dist/{src/git-runtime.d.ts → git-runtime.d.ts} +0 -0
  219. /package/dist/{src/runtime.d.ts → runtime.d.ts} +0 -0
  220. /package/dist/{src/stores → stores}/cursor-store.d.ts +0 -0
  221. /package/dist/{src/stores → stores}/envelopes.d.ts +0 -0
  222. /package/dist/{src/stores → stores}/helpers.d.ts +0 -0
  223. /package/dist/{src/stores → stores}/lease-store.d.ts +0 -0
  224. /package/dist/{src/stores → stores}/run-store.d.ts +0 -0
  225. /package/dist/{src/stores → stores}/subscription-store.d.ts +0 -0
  226. /package/dist/{src/types → types}/agents.d.ts +0 -0
  227. /package/dist/{src/types → types}/cloudflare.d.ts +0 -0
  228. /package/dist/{src/wrangler-d1.d.ts → wrangler-d1.d.ts} +0 -0
@@ -0,0 +1,175 @@
1
+ export declare const TREESEED_REMOTE_CONTRACT_VERSION = 1;
2
+ export declare const TREESEED_REMOTE_CONTRACT_HEADER = "x-treeseed-remote-contract-version";
3
+ export type ApiScope = string;
4
+ export interface ApiPrincipal {
5
+ id: string;
6
+ displayName?: string;
7
+ scopes: ApiScope[];
8
+ metadata?: Record<string, unknown>;
9
+ }
10
+ export interface RemoteTreeseedHost {
11
+ id: string;
12
+ baseUrl: string;
13
+ label?: string;
14
+ official?: boolean;
15
+ priority?: number;
16
+ }
17
+ export interface RemoteTreeseedPoolOptions {
18
+ strategy?: 'active-first' | 'priority';
19
+ maxAttempts?: number;
20
+ }
21
+ export interface RemoteTreeseedConfig {
22
+ hosts: RemoteTreeseedHost[];
23
+ activeHostId: string;
24
+ executionMode?: 'prefer-local' | 'prefer-remote' | 'remote-only';
25
+ auth?: {
26
+ accessToken?: string;
27
+ refreshToken?: string;
28
+ expiresAt?: string;
29
+ principal?: ApiPrincipal | null;
30
+ };
31
+ pool?: RemoteTreeseedPoolOptions;
32
+ }
33
+ export interface DeviceCodeStartRequest {
34
+ clientName?: string;
35
+ scopes?: ApiScope[];
36
+ }
37
+ export interface DeviceCodeStartResponse {
38
+ ok: true;
39
+ deviceCode: string;
40
+ userCode: string;
41
+ verificationUri: string;
42
+ verificationUriComplete: string;
43
+ intervalSeconds: number;
44
+ expiresAt: string;
45
+ expiresInSeconds: number;
46
+ }
47
+ export type DeviceCodePollResponse = {
48
+ ok: true;
49
+ status: 'pending';
50
+ intervalSeconds: number;
51
+ } | {
52
+ ok: true;
53
+ status: 'approved';
54
+ accessToken: string;
55
+ refreshToken: string;
56
+ tokenType: 'Bearer';
57
+ expiresAt: string;
58
+ expiresInSeconds: number;
59
+ principal: ApiPrincipal;
60
+ } | {
61
+ ok: false;
62
+ status: 'expired' | 'invalid' | 'already_used';
63
+ error: string;
64
+ };
65
+ export interface DeviceCodePollRequest {
66
+ deviceCode: string;
67
+ }
68
+ export interface DeviceCodeApproveRequest {
69
+ userCode: string;
70
+ principalId: string;
71
+ displayName?: string;
72
+ scopes?: ApiScope[];
73
+ metadata?: Record<string, unknown>;
74
+ }
75
+ export interface TokenRefreshRequest {
76
+ refreshToken: string;
77
+ }
78
+ export interface TokenRefreshResponse {
79
+ ok: true;
80
+ accessToken: string;
81
+ refreshToken: string;
82
+ tokenType: 'Bearer';
83
+ expiresAt: string;
84
+ expiresInSeconds: number;
85
+ principal: ApiPrincipal;
86
+ }
87
+ export interface RemoteSdkOperationRequest {
88
+ input?: Record<string, unknown>;
89
+ repoRoot?: string;
90
+ }
91
+ export type RemoteSdkOperationResponse<T = unknown> = T;
92
+ export interface RemoteGatewayRequest {
93
+ method?: 'GET' | 'POST';
94
+ body?: unknown;
95
+ }
96
+ export interface RemoteWorkflowOperationRequest {
97
+ input?: Record<string, unknown>;
98
+ cwd?: string;
99
+ env?: Record<string, string>;
100
+ }
101
+ export interface RemoteWorkflowNextStep {
102
+ operation: string;
103
+ reason?: string;
104
+ input?: Record<string, unknown>;
105
+ }
106
+ export interface RemoteWorkflowOperationResponse {
107
+ ok: boolean;
108
+ operation: string;
109
+ payload?: Record<string, unknown> | null;
110
+ nextSteps?: RemoteWorkflowNextStep[];
111
+ }
112
+ export declare class RemoteTreeseedClient {
113
+ readonly config: RemoteTreeseedConfig;
114
+ private readonly fetchImpl;
115
+ constructor(config: RemoteTreeseedConfig, options?: {
116
+ fetchImpl?: typeof fetch;
117
+ });
118
+ activeHost(): RemoteTreeseedHost;
119
+ requestJson<T>(path: string, options?: {
120
+ method?: 'GET' | 'POST';
121
+ body?: unknown;
122
+ headers?: Record<string, string>;
123
+ requireAuth?: boolean;
124
+ }): Promise<T>;
125
+ }
126
+ export declare class RemoteTreeseedAuthClient {
127
+ private readonly client;
128
+ constructor(client: RemoteTreeseedClient);
129
+ startDeviceFlow(request: DeviceCodeStartRequest): Promise<DeviceCodeStartResponse>;
130
+ pollDeviceFlow(request: DeviceCodePollRequest): Promise<DeviceCodePollResponse>;
131
+ refreshAccessToken(request: TokenRefreshRequest): Promise<TokenRefreshResponse>;
132
+ whoAmI(): Promise<{
133
+ ok: true;
134
+ payload: ApiPrincipal;
135
+ }>;
136
+ }
137
+ export declare class RemoteTreeseedSdkClient {
138
+ private readonly client;
139
+ constructor(client: RemoteTreeseedClient);
140
+ execute<T = unknown>(operation: string, request: RemoteSdkOperationRequest): Promise<T>;
141
+ }
142
+ export declare class TreeseedGatewayClient {
143
+ private readonly baseUrl;
144
+ private readonly token;
145
+ private readonly fetchImpl;
146
+ constructor(config: import('./sdk-types.ts').SdkGatewayClientConfig);
147
+ requestJson<T>(path: string, options?: RemoteGatewayRequest): Promise<T & {
148
+ error?: string;
149
+ }>;
150
+ }
151
+ export declare class CloudflareQueuePullClient {
152
+ private readonly baseUrl;
153
+ private readonly token;
154
+ private readonly fetchImpl;
155
+ constructor(config: import('./sdk-types.ts').SdkQueuePullClientConfig);
156
+ private request;
157
+ pull(request?: import('./sdk-types.ts').SdkQueuePullRequest): Promise<{
158
+ messages: {
159
+ leaseId: string;
160
+ attempts: number;
161
+ rawBody: string;
162
+ body: import("./sdk-types.ts").SdkQueueMessageEnvelope;
163
+ }[];
164
+ }>;
165
+ ack(acks: string[]): Promise<unknown>;
166
+ retry(retries: Array<{
167
+ leaseId: string;
168
+ delaySeconds?: number;
169
+ }>): Promise<unknown>;
170
+ }
171
+ export declare class RemoteTreeseedOperationsClient {
172
+ private readonly client;
173
+ constructor(client: RemoteTreeseedClient);
174
+ execute(operation: string, request: RemoteWorkflowOperationRequest): Promise<RemoteWorkflowOperationResponse>;
175
+ }
package/dist/remote.js ADDED
@@ -0,0 +1,202 @@
1
+ const TREESEED_REMOTE_CONTRACT_VERSION = 1;
2
+ const TREESEED_REMOTE_CONTRACT_HEADER = "x-treeseed-remote-contract-version";
3
+ function normalizeBaseUrl(baseUrl) {
4
+ return baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
5
+ }
6
+ function resolveActiveHost(config) {
7
+ const host = config.hosts.find((entry) => entry.id === config.activeHostId) ?? config.hosts[0];
8
+ if (!host) {
9
+ throw new Error("Remote Treeseed configuration is missing a usable host.");
10
+ }
11
+ return {
12
+ ...host,
13
+ baseUrl: normalizeBaseUrl(host.baseUrl)
14
+ };
15
+ }
16
+ class RemoteTreeseedClient {
17
+ config;
18
+ fetchImpl;
19
+ constructor(config, options = {}) {
20
+ this.config = config;
21
+ this.fetchImpl = options.fetchImpl ?? fetch;
22
+ }
23
+ activeHost() {
24
+ return resolveActiveHost(this.config);
25
+ }
26
+ async requestJson(path, options = {}) {
27
+ const host = this.activeHost();
28
+ const headers = {
29
+ accept: "application/json",
30
+ [TREESEED_REMOTE_CONTRACT_HEADER]: String(TREESEED_REMOTE_CONTRACT_VERSION),
31
+ ...options.headers ?? {}
32
+ };
33
+ if (options.body !== void 0) {
34
+ headers["content-type"] = "application/json";
35
+ }
36
+ if (options.requireAuth && this.config.auth?.accessToken) {
37
+ headers.authorization = `Bearer ${this.config.auth.accessToken}`;
38
+ }
39
+ const response = await this.fetchImpl(`${host.baseUrl}${path}`, {
40
+ method: options.method ?? "GET",
41
+ headers,
42
+ body: options.body === void 0 ? void 0 : JSON.stringify(options.body)
43
+ });
44
+ const contractVersion = response.headers.get(TREESEED_REMOTE_CONTRACT_HEADER);
45
+ if (contractVersion && Number(contractVersion) !== TREESEED_REMOTE_CONTRACT_VERSION) {
46
+ throw new Error(
47
+ `Remote Treeseed contract mismatch. Client=${TREESEED_REMOTE_CONTRACT_VERSION}, server=${contractVersion}.`
48
+ );
49
+ }
50
+ const payload = await response.json().catch(() => ({}));
51
+ if (!response.ok) {
52
+ const message = typeof payload.error === "string" ? String(payload.error) : `Remote request failed with ${response.status}.`;
53
+ throw new Error(message);
54
+ }
55
+ return payload;
56
+ }
57
+ }
58
+ class RemoteTreeseedAuthClient {
59
+ constructor(client) {
60
+ this.client = client;
61
+ }
62
+ client;
63
+ startDeviceFlow(request) {
64
+ return this.client.requestJson("/auth/device/start", {
65
+ method: "POST",
66
+ body: request
67
+ });
68
+ }
69
+ pollDeviceFlow(request) {
70
+ return this.client.requestJson("/auth/device/poll", {
71
+ method: "POST",
72
+ body: request
73
+ });
74
+ }
75
+ refreshAccessToken(request) {
76
+ return this.client.requestJson("/auth/token/refresh", {
77
+ method: "POST",
78
+ body: request
79
+ });
80
+ }
81
+ whoAmI() {
82
+ return this.client.requestJson("/auth/me", {
83
+ requireAuth: true
84
+ });
85
+ }
86
+ }
87
+ class RemoteTreeseedSdkClient {
88
+ constructor(client) {
89
+ this.client = client;
90
+ }
91
+ client;
92
+ execute(operation, request) {
93
+ return this.client.requestJson(`/sdk/${encodeURIComponent(operation)}`, {
94
+ method: "POST",
95
+ body: request,
96
+ requireAuth: true
97
+ });
98
+ }
99
+ }
100
+ function normalizeExternalBaseUrl(baseUrl) {
101
+ return baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
102
+ }
103
+ class TreeseedGatewayClient {
104
+ baseUrl;
105
+ token;
106
+ fetchImpl;
107
+ constructor(config) {
108
+ this.baseUrl = normalizeExternalBaseUrl(config.baseUrl);
109
+ this.token = config.bearerToken;
110
+ this.fetchImpl = config.fetchImpl ?? fetch;
111
+ }
112
+ async requestJson(path, options = {}) {
113
+ const response = await this.fetchImpl(`${this.baseUrl}${path}`, {
114
+ method: options.method ?? "POST",
115
+ headers: {
116
+ accept: "application/json",
117
+ authorization: `Bearer ${this.token}`,
118
+ ...options.body === void 0 ? {} : { "content-type": "application/json" }
119
+ },
120
+ body: options.body === void 0 ? void 0 : JSON.stringify(options.body)
121
+ });
122
+ const payload = await response.json().catch(() => ({}));
123
+ if (!response.ok) {
124
+ throw new Error(typeof payload.error === "string" ? payload.error : `Gateway request failed with ${response.status}.`);
125
+ }
126
+ return payload;
127
+ }
128
+ }
129
+ class CloudflareQueuePullClient {
130
+ baseUrl;
131
+ token;
132
+ fetchImpl;
133
+ constructor(config) {
134
+ const apiBaseUrl = config.apiBaseUrl ?? "https://api.cloudflare.com/client/v4/accounts";
135
+ this.baseUrl = `${normalizeExternalBaseUrl(apiBaseUrl)}/${config.accountId}/queues/${config.queueId}`;
136
+ this.token = config.token;
137
+ this.fetchImpl = config.fetchImpl ?? fetch;
138
+ }
139
+ async request(path, body) {
140
+ const response = await this.fetchImpl(`${this.baseUrl}${path}`, {
141
+ method: "POST",
142
+ headers: {
143
+ accept: "application/json",
144
+ authorization: `Bearer ${this.token}`,
145
+ "content-type": "application/json"
146
+ },
147
+ body: JSON.stringify(body)
148
+ });
149
+ const payload = await response.json().catch(() => ({}));
150
+ if (!response.ok || payload.success === false) {
151
+ throw new Error(payload.errors?.[0]?.message ?? `Queue request failed with ${response.status}.`);
152
+ }
153
+ return payload.result;
154
+ }
155
+ async pull(request = {}) {
156
+ const result = await this.request("/messages/pull", {
157
+ batch_size: request.batchSize ?? 1,
158
+ visibility_timeout_ms: request.visibilityTimeoutMs ?? 12e4
159
+ });
160
+ const messages = (result.messages ?? []).map((entry) => ({
161
+ leaseId: entry.lease_id,
162
+ attempts: Number(entry.attempts ?? 0),
163
+ rawBody: String(entry.body ?? "{}"),
164
+ body: JSON.parse(String(entry.body ?? "{}"))
165
+ }));
166
+ return { messages };
167
+ }
168
+ ack(acks) {
169
+ return this.request("/messages/ack", { acks });
170
+ }
171
+ retry(retries) {
172
+ return this.request("/messages/ack", {
173
+ retries: retries.map((entry) => ({
174
+ lease_id: entry.leaseId,
175
+ delay_secs: entry.delaySeconds ?? 0
176
+ }))
177
+ });
178
+ }
179
+ }
180
+ class RemoteTreeseedOperationsClient {
181
+ constructor(client) {
182
+ this.client = client;
183
+ }
184
+ client;
185
+ execute(operation, request) {
186
+ return this.client.requestJson(`/operations/${encodeURIComponent(operation)}`, {
187
+ method: "POST",
188
+ body: request,
189
+ requireAuth: true
190
+ });
191
+ }
192
+ }
193
+ export {
194
+ CloudflareQueuePullClient,
195
+ RemoteTreeseedAuthClient,
196
+ RemoteTreeseedClient,
197
+ RemoteTreeseedOperationsClient,
198
+ RemoteTreeseedSdkClient,
199
+ TREESEED_REMOTE_CONTRACT_HEADER,
200
+ TREESEED_REMOTE_CONTRACT_VERSION,
201
+ TreeseedGatewayClient
202
+ };
package/dist/runtime.js CHANGED
@@ -1,10 +1,57 @@
1
- import { existsSync } from "node:fs";
1
+ import { existsSync, readFileSync, readdirSync } from "node:fs";
2
2
  import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ const DEFAULT_FIXTURE_ID = "treeseed-working-site";
5
+ const runtimeFile = fileURLToPath(import.meta.url);
6
+ const sdkPackageRoot = path.resolve(path.dirname(runtimeFile), "..");
7
+ function fixtureRootCandidates(start) {
8
+ const candidates = [];
9
+ if (process.env.TREESEED_FIXTURES_ROOT) {
10
+ candidates.push(path.resolve(process.env.TREESEED_FIXTURES_ROOT));
11
+ }
12
+ candidates.push(path.join(sdkPackageRoot, ".fixtures", "treeseed-fixtures"));
13
+ candidates.push(path.join(start, ".fixtures", "treeseed-fixtures"));
14
+ return [...new Set(candidates)];
15
+ }
16
+ function resolveSharedFixtureRoot(start) {
17
+ const requestedFixtureId = process.env.TREESEED_FIXTURE_ID?.trim() || DEFAULT_FIXTURE_ID;
18
+ for (const fixturesRoot of fixtureRootCandidates(start)) {
19
+ const directRoot = path.join(fixturesRoot, "sites", "working-site");
20
+ const directManifestPath = path.join(directRoot, "fixture.manifest.json");
21
+ if (existsSync(path.join(directRoot, "src", "content")) && existsSync(directManifestPath)) {
22
+ return directRoot;
23
+ }
24
+ const sitesRoot = path.join(fixturesRoot, "sites");
25
+ if (!existsSync(sitesRoot)) {
26
+ continue;
27
+ }
28
+ for (const entry of readdirSync(sitesRoot, { withFileTypes: true }).filter((item) => item.isDirectory()).map((item) => item.name)) {
29
+ const fixtureRoot = path.join(sitesRoot, entry);
30
+ const manifestPath = path.join(fixtureRoot, "fixture.manifest.json");
31
+ if (!existsSync(manifestPath)) {
32
+ continue;
33
+ }
34
+ try {
35
+ const manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
36
+ if (manifest.id === requestedFixtureId) {
37
+ const root = path.resolve(fixtureRoot, manifest.root ?? ".");
38
+ if (existsSync(path.join(root, "src", "content"))) {
39
+ return root;
40
+ }
41
+ }
42
+ } catch {
43
+ continue;
44
+ }
45
+ }
46
+ }
47
+ return null;
48
+ }
3
49
  function findContentRoot(start) {
4
50
  let current = path.resolve(start);
5
51
  for (; ; ) {
6
- if (existsSync(path.join(current, "fixture", "src", "content"))) {
7
- return path.join(current, "fixture");
52
+ const sharedFixtureRoot = resolveSharedFixtureRoot(current);
53
+ if (sharedFixtureRoot) {
54
+ return sharedFixtureRoot;
8
55
  }
9
56
  if (existsSync(path.join(current, "src", "content"))) {
10
57
  return current;
@@ -0,0 +1,121 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { buildTenantBookRuntime } from '../platform/utils/books-data.js';
4
+ import { loadTreeseedManifest } from '../platform/tenant/config.js';
5
+ const PROJECT_TENANT = loadTreeseedManifest();
6
+ const { BOOKS, TREESEED_LIBRARY_DOWNLOAD } = buildTenantBookRuntime(PROJECT_TENANT, {
7
+ projectRoot: PROJECT_TENANT.__tenantRoot ?? process.cwd(),
8
+ docsLibraryDownload: {
9
+ downloadFileName: 'karyon-knowledge.md',
10
+ downloadHref: '/books/karyon-knowledge.md',
11
+ downloadTitle: 'Karyon Knowledge Library',
12
+ },
13
+ });
14
+ const projectRoot = PROJECT_TENANT.__tenantRoot ?? process.cwd();
15
+ const outputDir = path.join(projectRoot, 'public', 'books');
16
+ const legacyOutputFile = path.join(projectRoot, 'public', 'book.md');
17
+ function sortPaths(paths) {
18
+ return [...paths].sort((left, right) => left.localeCompare(right, undefined, { numeric: true, sensitivity: 'base' }));
19
+ }
20
+ function getSidebarOrder(filePath) {
21
+ const rawContent = fs.readFileSync(filePath, 'utf8');
22
+ const frontmatterMatch = rawContent.match(/^---\r?\n([\s\S]*?)\r?\n---/);
23
+ if (!frontmatterMatch)
24
+ return Number.POSITIVE_INFINITY;
25
+ const orderMatch = frontmatterMatch[1].match(/^\s{2}order:\s*(\d+)\s*$/m);
26
+ return orderMatch ? Number.parseInt(orderMatch[1], 10) : Number.POSITIVE_INFINITY;
27
+ }
28
+ function collectMarkdownFiles(rootPath) {
29
+ if (!fs.existsSync(rootPath)) {
30
+ throw new Error(`Book export root not found: ${rootPath}`);
31
+ }
32
+ const stats = fs.statSync(rootPath);
33
+ if (stats.isFile()) {
34
+ return [rootPath];
35
+ }
36
+ const entries = fs.readdirSync(rootPath, { withFileTypes: true });
37
+ return sortPaths(entries.flatMap((entry) => {
38
+ const fullPath = path.join(rootPath, entry.name);
39
+ if (entry.isDirectory()) {
40
+ return collectMarkdownFiles(fullPath);
41
+ }
42
+ if (entry.isFile() && (entry.name.endsWith('.md') || entry.name.endsWith('.mdx'))) {
43
+ return [fullPath];
44
+ }
45
+ return [];
46
+ }));
47
+ }
48
+ function stripFrontmatter(content) {
49
+ return content.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/, '').trim();
50
+ }
51
+ function stripMdxOnlySyntax(content) {
52
+ return content
53
+ .replace(/^import\s.+$/gm, '')
54
+ .replace(/^\s*<\/?[A-Z][^>]*>\s*$/gm, '')
55
+ .replace(/\n{3,}/g, '\n\n')
56
+ .trim();
57
+ }
58
+ function inferExportRootFromBasePath(book) {
59
+ const normalizedBasePath = String(book.basePath || '').trim();
60
+ const knowledgePrefix = '/knowledge/';
61
+ if (!normalizedBasePath.startsWith(knowledgePrefix)) {
62
+ throw new Error(`Book basePath must start with "${knowledgePrefix}" to infer exports: ${book.basePath}`);
63
+ }
64
+ const relativeKnowledgePath = normalizedBasePath
65
+ .slice(knowledgePrefix.length)
66
+ .replace(/^\/+|\/+$/g, '');
67
+ if (!relativeKnowledgePath) {
68
+ throw new Error(`Book basePath must identify a knowledge directory: ${book.basePath}`);
69
+ }
70
+ return path.join(PROJECT_TENANT.content.docs, relativeKnowledgePath);
71
+ }
72
+ function resolveExportRoots(book) {
73
+ if (Array.isArray(book.exportRoots) && book.exportRoots.length > 0) {
74
+ return book.exportRoots;
75
+ }
76
+ return [inferExportRootFromBasePath(book)];
77
+ }
78
+ function resolveBookFiles(book) {
79
+ const files = resolveExportRoots(book).flatMap((root) => collectMarkdownFiles(path.resolve(projectRoot, root)).sort((left, right) => {
80
+ const orderDelta = getSidebarOrder(left) - getSidebarOrder(right);
81
+ if (orderDelta !== 0)
82
+ return orderDelta;
83
+ return left.localeCompare(right, undefined, { numeric: true, sensitivity: 'base' });
84
+ }));
85
+ return Array.from(new Set(files));
86
+ }
87
+ function buildBookMarkdown(book) {
88
+ const sections = resolveBookFiles(book).map((filePath) => {
89
+ const rawContent = fs.readFileSync(filePath, 'utf8');
90
+ return stripMdxOnlySyntax(stripFrontmatter(rawContent));
91
+ });
92
+ return `# ${book.downloadTitle}\n\n> This document is auto-generated from the Karyon knowledge source.\n\n${sections.join('\n\n---\n\n')}\n`;
93
+ }
94
+ function ensureOutputDir() {
95
+ fs.mkdirSync(outputDir, { recursive: true });
96
+ }
97
+ function writeBookOutput(fileName, content) {
98
+ const outputPath = path.join(outputDir, fileName);
99
+ fs.writeFileSync(outputPath, content);
100
+ return outputPath;
101
+ }
102
+ function main() {
103
+ console.log('Generating contextual Karyon knowledge exports...');
104
+ ensureOutputDir();
105
+ const bookOutputs = BOOKS.map((book) => {
106
+ const content = buildBookMarkdown(book);
107
+ const outputPath = writeBookOutput(book.downloadFileName, content);
108
+ console.log(`Generated ${path.relative(projectRoot, outputPath)}`);
109
+ return { book, content };
110
+ });
111
+ const compositeContent = `# ${TREESEED_LIBRARY_DOWNLOAD.downloadTitle}\n\n> This document is auto-generated from the Karyon knowledge source.\n\n${bookOutputs
112
+ .map(({ content }) => content.trim())
113
+ .join('\n\n---\n\n')}\n`;
114
+ const compositeOutputPath = writeBookOutput(TREESEED_LIBRARY_DOWNLOAD.downloadFileName, compositeContent);
115
+ console.log(`Generated ${path.relative(projectRoot, compositeOutputPath)}`);
116
+ if (fs.existsSync(legacyOutputFile)) {
117
+ fs.rmSync(legacyOutputFile);
118
+ console.log(`Removed legacy export ${path.relative(projectRoot, legacyOutputFile)}`);
119
+ }
120
+ }
121
+ main();
@@ -1,12 +1,14 @@
1
1
  import { copyFileSync, existsSync, mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
2
- import { dirname, extname, join, relative, resolve } from 'node:path';
2
+ import { basename, dirname, extname, join, relative, resolve } from 'node:path';
3
3
  import { build } from 'esbuild';
4
4
  import ts from 'typescript';
5
5
  import { packageRoot } from './package-tools.js';
6
6
  const srcRoot = resolve(packageRoot, 'src');
7
7
  const scriptsRoot = resolve(packageRoot, 'scripts');
8
8
  const distRoot = resolve(packageRoot, 'dist');
9
- const COPY_EXTENSIONS = new Set(['.d.js', '.json', '.md']);
9
+ const treeseedTemplateCatalogSourceRoot = resolve(srcRoot, 'treeseed', 'template-catalog');
10
+ const treeseedServicesSourceRoot = resolve(srcRoot, 'treeseed', 'services');
11
+ const COPY_EXTENSIONS = new Set(['.json', '.md', '.js', '.d.js', '.yaml', '.yml']);
10
12
  function walkFiles(root) {
11
13
  const files = [];
12
14
  for (const entry of readdirSync(root, { withFileTypes: true })) {
@@ -25,6 +27,17 @@ function ensureDir(filePath) {
25
27
  function rewriteRuntimeSpecifiers(contents) {
26
28
  return contents.replace(/(['"`])(\.[^'"`\n]+)\.(mjs|ts)\1/g, '$1$2.js$1');
27
29
  }
30
+ function rewriteScriptRuntimeSpecifiers(contents) {
31
+ return rewriteRuntimeSpecifiers(contents)
32
+ .replace(/(['"`])\.\.\/src\//g, '$1../')
33
+ .replace(/(['"`])\.\/src\//g, '$1./');
34
+ }
35
+ function isTypeScriptSource(filePath) {
36
+ return filePath.endsWith('.ts') && !filePath.endsWith('.d.js');
37
+ }
38
+ function isDeclarationAsset(filePath) {
39
+ return filePath.endsWith('.d.js');
40
+ }
28
41
  async function compileModule(filePath, sourceRoot, outputRoot) {
29
42
  const relativePath = relative(sourceRoot, filePath);
30
43
  const outputFile = resolve(outputRoot, relativePath.replace(/\.(mjs|ts)$/u, '.js'));
@@ -44,14 +57,25 @@ function copyAsset(filePath, sourceRoot, outputRoot) {
44
57
  const outputFile = resolve(outputRoot, relative(sourceRoot, filePath));
45
58
  ensureDir(outputFile);
46
59
  copyFileSync(filePath, outputFile);
47
- if (outputFile.endsWith('.d.js')) {
60
+ if (outputFile.endsWith('.d.js') || outputFile.endsWith('.js')) {
48
61
  const contents = readFileSync(outputFile, 'utf8');
49
62
  writeFileSync(outputFile, rewriteRuntimeSpecifiers(contents), 'utf8');
50
63
  }
51
64
  }
65
+ function copyAssetTree(sourceRoot, outputRoot) {
66
+ for (const filePath of walkFiles(sourceRoot)) {
67
+ copyAsset(filePath, sourceRoot, outputRoot);
68
+ }
69
+ }
52
70
  function transpileScript(filePath) {
71
+ if (basename(filePath).startsWith('.ts-run-')) {
72
+ return;
73
+ }
53
74
  const source = readFileSync(filePath, 'utf8');
54
75
  const relativePath = relative(scriptsRoot, filePath);
76
+ if (relativePath === 'fixture-tools.ts') {
77
+ return;
78
+ }
55
79
  const outputFile = resolve(distRoot, 'scripts', relativePath.replace(/\.(mjs|ts)$/u, '.js'));
56
80
  const transformed = extname(filePath) === '.ts'
57
81
  ? ts.transpileModule(source, {
@@ -62,22 +86,24 @@ function transpileScript(filePath) {
62
86
  }).outputText
63
87
  : source;
64
88
  ensureDir(outputFile);
65
- writeFileSync(outputFile, rewriteRuntimeSpecifiers(transformed), 'utf8');
89
+ writeFileSync(outputFile, rewriteScriptRuntimeSpecifiers(transformed), 'utf8');
66
90
  }
67
91
  function emitDeclarations() {
68
- const configPath = ts.findConfigFile(packageRoot, ts.sys.fileExists, 'tsconfig.json');
69
- if (!configPath) {
70
- throw new Error('Unable to locate tsconfig.json for declaration build.');
71
- }
72
- const configFile = ts.readConfigFile(configPath, ts.sys.readFile);
73
- const parsed = ts.parseJsonConfigFileContent(configFile.config, ts.sys, packageRoot);
92
+ const rootNames = walkFiles(srcRoot).filter(isTypeScriptSource);
74
93
  const program = ts.createProgram({
75
- rootNames: parsed.fileNames,
94
+ rootNames,
76
95
  options: {
77
- ...parsed.options,
96
+ allowImportingTsExtensions: true,
97
+ module: ts.ModuleKind.ESNext,
98
+ moduleResolution: ts.ModuleResolutionKind.Bundler,
99
+ target: ts.ScriptTarget.ES2022,
100
+ strict: true,
101
+ skipLibCheck: true,
102
+ types: ['node'],
78
103
  declaration: true,
79
104
  emitDeclarationOnly: true,
80
105
  declarationDir: distRoot,
106
+ rootDir: srcRoot,
81
107
  noEmit: false,
82
108
  },
83
109
  });
@@ -93,8 +119,15 @@ function emitDeclarations() {
93
119
  }
94
120
  rmSync(distRoot, { recursive: true, force: true });
95
121
  for (const filePath of walkFiles(srcRoot)) {
122
+ if (filePath.startsWith(`${treeseedTemplateCatalogSourceRoot}/`)) {
123
+ continue;
124
+ }
96
125
  const extension = extname(filePath);
97
- if (extension === '.ts') {
126
+ if (isDeclarationAsset(filePath)) {
127
+ copyAsset(filePath, srcRoot, distRoot);
128
+ continue;
129
+ }
130
+ if (isTypeScriptSource(filePath)) {
98
131
  await compileModule(filePath, srcRoot, distRoot);
99
132
  continue;
100
133
  }
@@ -102,6 +135,12 @@ for (const filePath of walkFiles(srcRoot)) {
102
135
  copyAsset(filePath, srcRoot, distRoot);
103
136
  }
104
137
  }
138
+ if (existsSync(treeseedTemplateCatalogSourceRoot)) {
139
+ copyAssetTree(treeseedTemplateCatalogSourceRoot, resolve(distRoot, 'treeseed', 'template-catalog'));
140
+ }
141
+ if (existsSync(treeseedServicesSourceRoot)) {
142
+ copyAssetTree(treeseedServicesSourceRoot, resolve(distRoot, 'treeseed', 'services'));
143
+ }
105
144
  for (const filePath of walkFiles(scriptsRoot)) {
106
145
  const extension = extname(filePath);
107
146
  if (extension === '.ts' || extension === '.mjs') {
@@ -109,6 +148,11 @@ for (const filePath of walkFiles(scriptsRoot)) {
109
148
  }
110
149
  }
111
150
  emitDeclarations();
151
+ for (const filePath of walkFiles(distRoot)) {
152
+ if (filePath.endsWith('.d.js')) {
153
+ rmSync(filePath, { force: true });
154
+ }
155
+ }
112
156
  if (existsSync(resolve(packageRoot, 'README.md'))) {
113
157
  copyFileSync(resolve(packageRoot, 'README.md'), resolve(distRoot, '..', 'README.md'));
114
158
  }