@treeseed/sdk 0.10.27 → 0.11.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 (168) hide show
  1. package/README.md +207 -6
  2. package/dist/capacity-provider.d.ts +3 -1
  3. package/dist/capacity-provider.js +25 -5
  4. package/dist/control-plane.d.ts +1 -0
  5. package/dist/control-plane.js +38 -13
  6. package/dist/db/market-schema.d.ts +8860 -6172
  7. package/dist/db/market-schema.js +108 -0
  8. package/dist/db/node-sqlite.js +7 -2
  9. package/dist/hosting/apps.d.ts +12 -0
  10. package/dist/hosting/apps.js +107 -0
  11. package/dist/hosting/builtins.d.ts +25 -0
  12. package/dist/hosting/builtins.js +791 -0
  13. package/dist/hosting/contracts.d.ts +207 -0
  14. package/dist/hosting/contracts.js +0 -0
  15. package/dist/hosting/graph.d.ts +192 -0
  16. package/dist/hosting/graph.js +1106 -0
  17. package/dist/hosting/index.d.ts +4 -0
  18. package/dist/hosting/index.js +4 -0
  19. package/dist/index.d.ts +11 -4
  20. package/dist/index.js +71 -7
  21. package/dist/managed-dependencies.js +1 -2
  22. package/dist/market-client.d.ts +63 -3
  23. package/dist/market-client.js +83 -11
  24. package/dist/operations/services/bootstrap-runner.d.ts +3 -1
  25. package/dist/operations/services/bootstrap-runner.js +22 -2
  26. package/dist/operations/services/config-runtime.d.ts +10 -5
  27. package/dist/operations/services/config-runtime.js +209 -66
  28. package/dist/operations/services/deploy.d.ts +70 -7
  29. package/dist/operations/services/deploy.js +579 -64
  30. package/dist/operations/services/deployment-readiness.d.ts +30 -0
  31. package/dist/operations/services/deployment-readiness.js +175 -0
  32. package/dist/operations/services/git-workflow.d.ts +2 -1
  33. package/dist/operations/services/git-workflow.js +9 -3
  34. package/dist/operations/services/github-actions-verification.d.ts +1 -0
  35. package/dist/operations/services/github-actions-verification.js +1 -0
  36. package/dist/operations/services/github-api.js +1 -1
  37. package/dist/operations/services/github-automation.d.ts +1 -1
  38. package/dist/operations/services/github-automation.js +4 -3
  39. package/dist/operations/services/github-credentials.d.ts +13 -0
  40. package/dist/operations/services/github-credentials.js +58 -0
  41. package/dist/operations/services/hosted-service-checks.d.ts +63 -0
  42. package/dist/operations/services/hosted-service-checks.js +327 -0
  43. package/dist/operations/services/hub-provider-launch.js +3 -3
  44. package/dist/operations/services/live-hosted-service-checks.d.ts +25 -0
  45. package/dist/operations/services/live-hosted-service-checks.js +350 -0
  46. package/dist/operations/services/managed-host-security.js +1 -1
  47. package/dist/operations/services/operations-runner-smoke.d.ts +30 -0
  48. package/dist/operations/services/operations-runner-smoke.js +180 -0
  49. package/dist/operations/services/package-adapters.d.ts +95 -0
  50. package/dist/operations/services/package-adapters.js +288 -0
  51. package/dist/operations/services/package-reference-policy.d.ts +1 -0
  52. package/dist/operations/services/package-reference-policy.js +15 -2
  53. package/dist/operations/services/project-platform.d.ts +80 -22
  54. package/dist/operations/services/project-platform.js +49 -8
  55. package/dist/operations/services/project-web-monitor.js +26 -4
  56. package/dist/operations/services/railway-api.d.ts +88 -5
  57. package/dist/operations/services/railway-api.js +626 -35
  58. package/dist/operations/services/railway-deploy.d.ts +46 -40
  59. package/dist/operations/services/railway-deploy.js +261 -293
  60. package/dist/operations/services/release-candidate.d.ts +19 -0
  61. package/dist/operations/services/release-candidate.js +375 -38
  62. package/dist/operations/services/repository-save-orchestrator.d.ts +3 -1
  63. package/dist/operations/services/repository-save-orchestrator.js +279 -66
  64. package/dist/operations/services/runtime-tools.d.ts +1 -0
  65. package/dist/operations/services/runtime-tools.js +10 -9
  66. package/dist/operations/services/template-registry.js +14 -7
  67. package/dist/operations/services/verification-cache.d.ts +25 -0
  68. package/dist/operations/services/verification-cache.js +71 -0
  69. package/dist/operations/services/workspace-dependency-mode.js +9 -1
  70. package/dist/operations/services/workspace-save.js +1 -1
  71. package/dist/operations/services/workspace-tools.js +2 -1
  72. package/dist/platform/contracts.d.ts +32 -1
  73. package/dist/platform/deploy-config.js +73 -8
  74. package/dist/platform/env.yaml +163 -35
  75. package/dist/platform/environment.d.ts +1 -0
  76. package/dist/platform/environment.js +74 -5
  77. package/dist/platform/plugin.d.ts +9 -0
  78. package/dist/platform-operation-store.js +2 -2
  79. package/dist/platform-operations.js +1 -1
  80. package/dist/reconcile/bootstrap-systems.js +2 -2
  81. package/dist/reconcile/builtin-adapters.js +372 -189
  82. package/dist/reconcile/contracts.d.ts +9 -5
  83. package/dist/reconcile/desired-state.d.ts +1 -0
  84. package/dist/reconcile/desired-state.js +5 -5
  85. package/dist/reconcile/engine.d.ts +5 -2
  86. package/dist/reconcile/engine.js +53 -32
  87. package/dist/reconcile/index.d.ts +2 -0
  88. package/dist/reconcile/index.js +2 -0
  89. package/dist/reconcile/live-acceptance.d.ts +79 -0
  90. package/dist/reconcile/live-acceptance.js +1615 -0
  91. package/dist/reconcile/platform.d.ts +104 -0
  92. package/dist/reconcile/platform.js +100 -0
  93. package/dist/reconcile/state.js +4 -4
  94. package/dist/reconcile/units.js +2 -2
  95. package/dist/scripts/deployment-readiness.js +20 -0
  96. package/dist/scripts/generate-treedx-openapi-types.js +186 -0
  97. package/dist/scripts/operations-runner-smoke.js +16 -0
  98. package/dist/scripts/release-verify.js +4 -1
  99. package/dist/scripts/template-catalog.test.js +7 -7
  100. package/dist/scripts/tenant-workflow-action.js +10 -1
  101. package/dist/sdk-types.d.ts +172 -5
  102. package/dist/sdk-types.js +28 -3
  103. package/dist/sdk.d.ts +35 -24
  104. package/dist/sdk.js +186 -17
  105. package/dist/template-launch-requirements.js +9 -0
  106. package/dist/treedx/adapters.d.ts +6 -0
  107. package/dist/treedx/adapters.js +36 -0
  108. package/dist/treedx/client.d.ts +222 -0
  109. package/dist/treedx/client.js +871 -0
  110. package/dist/treedx/errors.d.ts +13 -0
  111. package/dist/treedx/errors.js +17 -0
  112. package/dist/treedx/federated-client.d.ts +27 -0
  113. package/dist/treedx/federated-client.js +158 -0
  114. package/dist/treedx/generated/openapi-types.d.ts +3558 -0
  115. package/dist/treedx/generated/openapi-types.js +0 -0
  116. package/dist/treedx/graph-adapter.d.ts +33 -0
  117. package/dist/treedx/graph-adapter.js +156 -0
  118. package/dist/treedx/index.d.ts +14 -0
  119. package/dist/treedx/index.js +48 -0
  120. package/dist/treedx/market-integration.d.ts +27 -0
  121. package/dist/treedx/market-integration.js +131 -0
  122. package/dist/treedx/ports.d.ts +166 -0
  123. package/dist/treedx/ports.js +231 -0
  124. package/dist/treedx/query-adapter.d.ts +19 -0
  125. package/dist/treedx/query-adapter.js +62 -0
  126. package/dist/treedx/registry-client.d.ts +11 -0
  127. package/dist/treedx/registry-client.js +19 -0
  128. package/dist/treedx/repository-adapter.d.ts +45 -0
  129. package/dist/treedx/repository-adapter.js +308 -0
  130. package/dist/treedx/sdk-integration.d.ts +27 -0
  131. package/dist/treedx/sdk-integration.js +63 -0
  132. package/dist/treedx/types.d.ts +1084 -0
  133. package/dist/treedx/types.js +8 -0
  134. package/dist/treedx/workspace-adapter.d.ts +27 -0
  135. package/dist/treedx/workspace-adapter.js +65 -0
  136. package/dist/treedx-backends.d.ts +218 -0
  137. package/dist/treedx-backends.js +632 -0
  138. package/dist/treedx-client.d.ts +86 -0
  139. package/dist/treedx-client.js +175 -0
  140. package/dist/treeseed/template-catalog/catalog.fixture.json +497 -138
  141. package/dist/workflow/operations.d.ts +119 -13
  142. package/dist/workflow/operations.js +309 -53
  143. package/dist/workflow-state.d.ts +13 -0
  144. package/dist/workflow-state.js +43 -26
  145. package/dist/workflow-support.d.ts +11 -3
  146. package/dist/workflow-support.js +67 -3
  147. package/dist/workflow.d.ts +5 -0
  148. package/drizzle/market/0004_treedx_market_integration.sql +99 -0
  149. package/package.json +34 -3
  150. package/templates/github/deploy-web.workflow.yml +39 -6
  151. package/dist/treeseed/template-catalog/templates/starter-basic/template/astro.config.d.ts +0 -3
  152. package/dist/treeseed/template-catalog/templates/starter-basic/template/astro.config.ts +0 -6
  153. package/dist/treeseed/template-catalog/templates/starter-basic/template/package.json +0 -35
  154. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/api/server.js +0 -4
  155. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/config.yaml +0 -65
  156. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/decisions/adopt-initial-proposal-loop.mdx +0 -22
  157. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/empty/.gitkeep +0 -1
  158. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/knowledge/handbook/index.mdx +0 -11
  159. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/pages/welcome.mdx +0 -11
  160. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/people/starter-steward.mdx +0 -11
  161. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/proposals/establish-initial-proposal-loop.mdx +0 -17
  162. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content.config.d.ts +0 -1
  163. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content.config.ts +0 -3
  164. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/env.yaml +0 -1
  165. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/manifest.yaml +0 -26
  166. package/dist/treeseed/template-catalog/templates/starter-basic/template/treeseed.site.yaml +0 -74
  167. package/dist/treeseed/template-catalog/templates/starter-basic/template/tsconfig.json +0 -9
  168. package/dist/treeseed/template-catalog/templates/starter-basic/template.config.json +0 -103
@@ -0,0 +1,231 @@
1
+ class LocalRepositoryPort {
2
+ constructor(content) {
3
+ this.content = content;
4
+ }
5
+ content;
6
+ list(model) {
7
+ return this.content.list(model);
8
+ }
9
+ get(input) {
10
+ return this.content.get(input);
11
+ }
12
+ search(input) {
13
+ return this.content.search(input);
14
+ }
15
+ follow(input) {
16
+ return this.content.follow(input);
17
+ }
18
+ pick(input) {
19
+ return this.content.pick(input);
20
+ }
21
+ create(input) {
22
+ return this.content.create(input);
23
+ }
24
+ update(input) {
25
+ return this.content.update(input);
26
+ }
27
+ }
28
+ class LocalRepositoryQueryPort {
29
+ constructor(content) {
30
+ this.content = content;
31
+ }
32
+ content;
33
+ search(input) {
34
+ return this.content.search(input);
35
+ }
36
+ query(input) {
37
+ return this.content.search(input);
38
+ }
39
+ }
40
+ class LocalGraphPort {
41
+ constructor(runtime) {
42
+ this.runtime = runtime;
43
+ }
44
+ runtime;
45
+ refresh(input) {
46
+ return this.runtime.refresh(input);
47
+ }
48
+ searchFiles(query, options) {
49
+ return this.runtime.searchFiles(query, options);
50
+ }
51
+ searchSections(query, options) {
52
+ return this.runtime.searchSections(query, options);
53
+ }
54
+ searchEntities(query, options) {
55
+ return this.runtime.searchEntities(query, options);
56
+ }
57
+ getNode(id) {
58
+ return this.runtime.getNode(id);
59
+ }
60
+ query(input) {
61
+ return this.runtime.queryGraph(input);
62
+ }
63
+ buildContext(input) {
64
+ return this.runtime.buildContextPack(input);
65
+ }
66
+ parseDsl(source) {
67
+ return this.runtime.parseGraphDsl(source);
68
+ }
69
+ }
70
+ class TreeDxRepositoryPort {
71
+ constructor(client, content, workspace) {
72
+ this.client = client;
73
+ this.content = content;
74
+ this.workspace = workspace;
75
+ }
76
+ client;
77
+ content;
78
+ workspace;
79
+ createWorkspace(input) {
80
+ return this.client.createWorkspace(input);
81
+ }
82
+ closeWorkspace(workspaceId) {
83
+ return this.client.closeWorkspace(workspaceId);
84
+ }
85
+ listTree(input) {
86
+ return this.client.listTree(input);
87
+ }
88
+ readFile(input) {
89
+ return this.client.readFile(input);
90
+ }
91
+ writeFile(input) {
92
+ return this.client.writeFile(input);
93
+ }
94
+ patchFile(input) {
95
+ return this.client.patchFile(input);
96
+ }
97
+ deleteFile(input) {
98
+ return this.client.deleteFile(input);
99
+ }
100
+ search(input) {
101
+ return this.client.search(input);
102
+ }
103
+ status(input) {
104
+ return this.client.status(input);
105
+ }
106
+ diff(input) {
107
+ return this.client.diff(input);
108
+ }
109
+ commit(input) {
110
+ return this.client.commit(input);
111
+ }
112
+ exec(input) {
113
+ return this.client.exec(input);
114
+ }
115
+ }
116
+ class TreeDxRepositoryQueryPort {
117
+ constructor(client, adapter) {
118
+ this.client = client;
119
+ this.adapter = adapter;
120
+ }
121
+ client;
122
+ adapter;
123
+ read(input) {
124
+ return this.client.readRepositoryFiles(input);
125
+ }
126
+ paths(input) {
127
+ return this.client.listRepositoryPaths(input);
128
+ }
129
+ query(input) {
130
+ return this.adapter?.queryRepository(input) ?? this.client.queryRepository(input);
131
+ }
132
+ search(input) {
133
+ return this.client.searchRepositoryFiles(input);
134
+ }
135
+ }
136
+ class TreeDxGraphPort {
137
+ constructor(adapter) {
138
+ this.adapter = adapter;
139
+ }
140
+ adapter;
141
+ refresh(input) {
142
+ return this.adapter.refresh(input);
143
+ }
144
+ searchFiles(query, options) {
145
+ return this.adapter.searchFiles(query, options);
146
+ }
147
+ searchSections(query, options) {
148
+ return this.adapter.searchSections(query, options);
149
+ }
150
+ searchEntities(query, options) {
151
+ return this.adapter.searchEntities(query, options);
152
+ }
153
+ getNode(id, options) {
154
+ return this.adapter.getNode(id, options);
155
+ }
156
+ query(input) {
157
+ return this.adapter.queryGraph(input);
158
+ }
159
+ buildContext(input) {
160
+ return this.adapter.buildContextPack(input);
161
+ }
162
+ parseDsl(source) {
163
+ return this.adapter.parseGraphDsl(source);
164
+ }
165
+ }
166
+ class TreeDxRegistryPort {
167
+ constructor(client) {
168
+ this.client = client;
169
+ }
170
+ client;
171
+ resolveRepository(repoId) {
172
+ return this.client.resolveRepository(repoId);
173
+ }
174
+ resolveRepositories(repoIds) {
175
+ return this.client.resolveRepositories(repoIds);
176
+ }
177
+ }
178
+ class TreeDxFederatedPort {
179
+ constructor(client) {
180
+ this.client = client;
181
+ }
182
+ client;
183
+ search(input) {
184
+ return this.client.federatedSearch(input);
185
+ }
186
+ query(input) {
187
+ return this.client.federatedQuery(input);
188
+ }
189
+ context(input) {
190
+ return this.client.federatedContext(input);
191
+ }
192
+ graph(input) {
193
+ return this.client.federatedGraph(input);
194
+ }
195
+ }
196
+ class TreeDxExecPort {
197
+ constructor(client) {
198
+ this.client = client;
199
+ }
200
+ client;
201
+ exec(input) {
202
+ return this.client.exec(input);
203
+ }
204
+ }
205
+ class TreeDxArtifactPort {
206
+ constructor(client) {
207
+ this.client = client;
208
+ }
209
+ client;
210
+ buildSnapshot(input = {}) {
211
+ return this.client.buildSnapshot(input);
212
+ }
213
+ exportArtifact(input = {}) {
214
+ return this.client.exportArtifact(input);
215
+ }
216
+ downloadArtifact(input = {}) {
217
+ return this.client.downloadArtifact(input);
218
+ }
219
+ }
220
+ export {
221
+ LocalGraphPort,
222
+ LocalRepositoryPort,
223
+ LocalRepositoryQueryPort,
224
+ TreeDxArtifactPort,
225
+ TreeDxExecPort,
226
+ TreeDxFederatedPort,
227
+ TreeDxGraphPort,
228
+ TreeDxRegistryPort,
229
+ TreeDxRepositoryPort,
230
+ TreeDxRepositoryQueryPort
231
+ };
@@ -0,0 +1,19 @@
1
+ import type { SdkContentEntry, SdkGetRequest, SdkModelRegistry, SdkSearchRequest } from '../sdk-types.ts';
2
+ import { TreeDxClient } from './client.ts';
3
+ import type { TreeDxRepositoryQueryRequest, TreeDxRepositoryQueryResult } from './types.ts';
4
+ export interface TreeDxQueryAdapterOptions {
5
+ client: TreeDxClient;
6
+ models: SdkModelRegistry;
7
+ repoRoot?: string;
8
+ contentPathMap?: Record<string, string>;
9
+ defaultRef?: string;
10
+ }
11
+ export declare class TreeDxQueryAdapter {
12
+ private readonly options;
13
+ constructor(options: TreeDxQueryAdapterOptions);
14
+ readContent(request: SdkGetRequest): Promise<SdkContentEntry | null>;
15
+ search(request: SdkSearchRequest): Promise<SdkContentEntry[]>;
16
+ searchContent(request: SdkSearchRequest): Promise<SdkContentEntry[]>;
17
+ query(input: TreeDxRepositoryQueryRequest): Promise<TreeDxRepositoryQueryResult>;
18
+ queryRepository(input: TreeDxRepositoryQueryRequest): Promise<TreeDxRepositoryQueryResult>;
19
+ }
@@ -0,0 +1,62 @@
1
+ import {
2
+ entryFromTreeDxFile,
3
+ mapFilters,
4
+ mapSort,
5
+ resolveContentDir
6
+ } from "./repository-adapter.js";
7
+ import { resolveModelDefinition } from "../model-registry.js";
8
+ class TreeDxQueryAdapter {
9
+ constructor(options) {
10
+ this.options = options;
11
+ }
12
+ options;
13
+ async readContent(request) {
14
+ const definition = resolveModelDefinition(request.model, this.options.models);
15
+ const contentDir = resolveContentDir(definition, this.options);
16
+ const candidates = [request.id, request.slug, request.key].filter((value) => Boolean(value));
17
+ for (const candidate of candidates) {
18
+ for (const extension of [".mdx", ".md"]) {
19
+ try {
20
+ const response = await this.options.client.readRepositoryFile({
21
+ ref: this.options.defaultRef,
22
+ path: `${contentDir}/${candidate}${extension}`,
23
+ parseFrontmatter: true
24
+ });
25
+ if (response.file) {
26
+ return entryFromTreeDxFile(definition, response.file, contentDir);
27
+ }
28
+ } catch {
29
+ }
30
+ }
31
+ }
32
+ return null;
33
+ }
34
+ async search(request) {
35
+ return this.searchContent(request);
36
+ }
37
+ async searchContent(request) {
38
+ const definition = resolveModelDefinition(request.model, this.options.models);
39
+ const contentDir = resolveContentDir(definition, this.options);
40
+ const response = await this.options.client.searchRepositoryFiles({
41
+ ref: this.options.defaultRef,
42
+ paths: [`${contentDir}/**`],
43
+ query: "",
44
+ filters: mapFilters(definition, request.filters),
45
+ sort: mapSort(definition, request.sort),
46
+ limit: request.limit,
47
+ includeBody: true,
48
+ includeFrontmatter: true
49
+ });
50
+ const results = response.results ?? response.files ?? [];
51
+ return results.map((file) => entryFromTreeDxFile(definition, file, contentDir));
52
+ }
53
+ query(input) {
54
+ return this.options.client.queryRepository(input);
55
+ }
56
+ queryRepository(input) {
57
+ return this.query(input);
58
+ }
59
+ }
60
+ export {
61
+ TreeDxQueryAdapter
62
+ };
@@ -0,0 +1,11 @@
1
+ import { TreeDxClient } from './client.ts';
2
+ import type { TreeDxClientOptions, TreeDxNode, TreeDxRepositoryPlacement } from './types.ts';
3
+ export interface TreeDxRegistryClientOptions extends TreeDxClientOptions {
4
+ }
5
+ export declare class TreeDxRegistryClient {
6
+ readonly client: TreeDxClient;
7
+ constructor(options: TreeDxRegistryClientOptions | TreeDxClient);
8
+ listNodes(): Promise<TreeDxNode[]>;
9
+ resolveRepository(repoId: string): Promise<TreeDxRepositoryPlacement>;
10
+ resolveRepositories(repoIds: string[]): Promise<TreeDxRepositoryPlacement[]>;
11
+ }
@@ -0,0 +1,19 @@
1
+ import { TreeDxClient } from "./client.js";
2
+ class TreeDxRegistryClient {
3
+ client;
4
+ constructor(options) {
5
+ this.client = options instanceof TreeDxClient ? options : new TreeDxClient(options);
6
+ }
7
+ listNodes() {
8
+ return this.client.listNodes();
9
+ }
10
+ resolveRepository(repoId) {
11
+ return this.client.getPlacement(repoId);
12
+ }
13
+ resolveRepositories(repoIds) {
14
+ return Promise.all(repoIds.map((repoId) => this.resolveRepository(repoId)));
15
+ }
16
+ }
17
+ export {
18
+ TreeDxRegistryClient
19
+ };
@@ -0,0 +1,45 @@
1
+ import type { SdkContentEntry, SdkFilterCondition, SdkFollowRequest, SdkGetRequest, SdkModelDefinition, SdkModelRegistry, SdkMutationRequest, SdkPickRequest, SdkPickResult, SdkSearchRequest, SdkSortSpec, SdkUpdateRequest } from '../sdk-types.ts';
2
+ import { TreeDxClient } from './client.ts';
3
+ import type { TreeDxCommitResult } from './types.ts';
4
+ export interface TreeDxRepositoryAdapterOptions {
5
+ client: TreeDxClient;
6
+ models: SdkModelRegistry;
7
+ repoRoot?: string;
8
+ defaultRef?: string;
9
+ defaultAuthor?: {
10
+ name: string;
11
+ email: string;
12
+ };
13
+ contentPathMap?: Record<string, string>;
14
+ branchPrefix?: string;
15
+ }
16
+ export interface TreeDxContentMutationResult {
17
+ item: SdkContentEntry;
18
+ git: TreeDxCommitResult;
19
+ }
20
+ export declare function resolveContentDir(definition: SdkModelDefinition, options: Pick<TreeDxRepositoryAdapterOptions, 'contentPathMap' | 'repoRoot'>): string;
21
+ export declare function mapFilters(definition: SdkModelDefinition, filters?: SdkFilterCondition[]): {
22
+ field: string;
23
+ op: import("../sdk-types.ts").SdkFilterOperator;
24
+ value: unknown;
25
+ }[];
26
+ export declare function mapSort(definition: SdkModelDefinition, sort?: SdkSortSpec[]): {
27
+ field: string;
28
+ direction?: "asc" | "desc";
29
+ }[];
30
+ export declare function entryFromTreeDxFile(definition: SdkModelDefinition, value: unknown, contentDir: string): SdkContentEntry;
31
+ export declare class TreeDxRepositoryAdapter {
32
+ private readonly options;
33
+ constructor(options: TreeDxRepositoryAdapterOptions);
34
+ list(model: string): Promise<SdkContentEntry[]>;
35
+ get(request: SdkGetRequest): Promise<SdkContentEntry | null>;
36
+ search(request: SdkSearchRequest): Promise<SdkContentEntry[]>;
37
+ follow(request: SdkFollowRequest): Promise<{
38
+ items: SdkContentEntry[];
39
+ since: string;
40
+ }>;
41
+ pick(request: SdkPickRequest): Promise<SdkPickResult<SdkContentEntry>>;
42
+ create(request: SdkMutationRequest): Promise<TreeDxContentMutationResult>;
43
+ update(request: SdkUpdateRequest): Promise<TreeDxContentMutationResult>;
44
+ private writeAndCommit;
45
+ }
@@ -0,0 +1,308 @@
1
+ import crypto from "node:crypto";
2
+ import path from "node:path";
3
+ import { resolveModelDefinition } from "../model-registry.js";
4
+ import { serializeFrontmatterDocument } from "../frontmatter.js";
5
+ import {
6
+ canonicalizeFrontmatter,
7
+ normalizeFilterFields,
8
+ normalizeMutationData,
9
+ normalizeRecordToCanonicalShape,
10
+ normalizeSortFields,
11
+ readCanonicalFieldValue
12
+ } from "../sdk-fields.js";
13
+ import { TreeDxApiError } from "./errors.js";
14
+ function isRecord(value) {
15
+ return typeof value === "object" && value !== null && !Array.isArray(value);
16
+ }
17
+ function normalizeRepoPath(value) {
18
+ return value.replace(/\\/g, "/").replace(/^\/+/u, "").replace(/\/+$/u, "");
19
+ }
20
+ function stripExtension(value) {
21
+ return value.replace(/\.(md|mdx)$/iu, "");
22
+ }
23
+ function sanitizeFrontmatterInput(data) {
24
+ const next = { ...data };
25
+ delete next.body;
26
+ delete next.branchPrefix;
27
+ return next;
28
+ }
29
+ function ensureContentModel(definition) {
30
+ if (definition.storage !== "content" || !definition.contentDir) {
31
+ throw new TreeDxApiError(`Model "${definition.name}" is not content-backed.`, {
32
+ status: 400,
33
+ code: "model_not_content_backed"
34
+ });
35
+ }
36
+ }
37
+ function ensureMutationAllowed(definition, operation) {
38
+ if (!definition.operations.includes(operation)) {
39
+ throw new TreeDxApiError(`Model "${definition.name}" does not allow ${operation}.`, {
40
+ status: 403,
41
+ code: "operation_not_allowed"
42
+ });
43
+ }
44
+ }
45
+ function resolveContentDir(definition, options) {
46
+ ensureContentModel(definition);
47
+ const mapped = options.contentPathMap?.[definition.name];
48
+ if (mapped) {
49
+ return normalizeRepoPath(mapped);
50
+ }
51
+ const contentDir = definition.contentDir;
52
+ if (!path.isAbsolute(contentDir)) {
53
+ return normalizeRepoPath(contentDir);
54
+ }
55
+ if (options.repoRoot) {
56
+ return normalizeRepoPath(path.relative(options.repoRoot, contentDir));
57
+ }
58
+ const marker = `${path.sep}src${path.sep}content${path.sep}`;
59
+ const index = contentDir.lastIndexOf(marker);
60
+ if (index >= 0) {
61
+ return normalizeRepoPath(path.join("src", "content", contentDir.slice(index + marker.length)));
62
+ }
63
+ throw new TreeDxApiError(`Model "${definition.name}" needs a TreeDX content path mapping.`, {
64
+ status: 400,
65
+ code: "missing_content_path_mapping"
66
+ });
67
+ }
68
+ function treeDxField(field) {
69
+ if (["path", "name", "extension", "body", "content", "title"].includes(field)) {
70
+ return field;
71
+ }
72
+ return `frontmatter.${field}`;
73
+ }
74
+ function mapFilters(definition, filters = []) {
75
+ return normalizeFilterFields(definition, filters).map((filter) => ({
76
+ ...filter,
77
+ field: treeDxField(filter.field)
78
+ }));
79
+ }
80
+ function mapSort(definition, sort = []) {
81
+ return normalizeSortFields(definition, sort).map((entry) => ({
82
+ ...entry,
83
+ field: treeDxField(entry.field)
84
+ }));
85
+ }
86
+ function titleFrom(definition, frontmatter) {
87
+ const titleField = definition.fields.title ? readCanonicalFieldValue(definition, { frontmatter }, "title") : void 0;
88
+ const nameField = definition.fields.name ? readCanonicalFieldValue(definition, { frontmatter }, "name") : void 0;
89
+ return typeof titleField === "string" ? titleField : typeof nameField === "string" ? nameField : void 0;
90
+ }
91
+ function entryFromTreeDxFile(definition, value, contentDir) {
92
+ const file = isRecord(value) && isRecord(value.file) ? value.file : value;
93
+ if (!isRecord(file)) {
94
+ throw new TreeDxApiError("TreeDX file response was not an object.", {
95
+ status: 500,
96
+ code: "invalid_response",
97
+ payload: value
98
+ });
99
+ }
100
+ const filePath = String(file.path ?? "");
101
+ const frontmatter = isRecord(file.frontmatter) ? file.frontmatter : {};
102
+ const body = typeof file.body === "string" ? file.body : typeof file.content === "string" ? file.content : "";
103
+ const slug = stripExtension(normalizeRepoPath(path.posix.relative(contentDir, filePath)));
104
+ const created = frontmatter.created_at ?? frontmatter.createdAt ?? null;
105
+ const updated = frontmatter.updated_at ?? frontmatter.updatedAt ?? null;
106
+ return {
107
+ id: slug,
108
+ slug,
109
+ model: definition.name,
110
+ title: titleFrom(definition, frontmatter),
111
+ path: filePath,
112
+ body,
113
+ frontmatter,
114
+ createdAt: typeof created === "string" ? created : null,
115
+ updatedAt: typeof updated === "string" ? updated : null
116
+ };
117
+ }
118
+ function pickSortForStrategy(definition, request) {
119
+ switch (request.strategy) {
120
+ case "oldest":
121
+ return [{ field: definition.pickField, direction: "asc" }];
122
+ case "highest_priority":
123
+ if (definition.sortableFields.includes("priority") || definition.filterableFields.includes("priority")) {
124
+ return [
125
+ { field: "priority", direction: "desc" },
126
+ { field: definition.pickField, direction: "desc" }
127
+ ];
128
+ }
129
+ return [{ field: definition.pickField, direction: "desc" }];
130
+ case "latest":
131
+ default:
132
+ return [{ field: definition.pickField, direction: "desc" }];
133
+ }
134
+ }
135
+ class TreeDxRepositoryAdapter {
136
+ constructor(options) {
137
+ this.options = options;
138
+ }
139
+ options;
140
+ async list(model) {
141
+ const definition = resolveModelDefinition(model, this.options.models);
142
+ const contentDir = resolveContentDir(definition, this.options);
143
+ const paths = await this.options.client.listRepositoryPaths({
144
+ ref: this.options.defaultRef,
145
+ paths: [`${contentDir}/**`],
146
+ extensions: [".md", ".mdx"],
147
+ limit: 500
148
+ });
149
+ const filePaths = (paths.entries ?? []).filter(isRecord).map((entry) => String(entry.path ?? "")).filter(Boolean);
150
+ if (filePaths.length === 0) {
151
+ return [];
152
+ }
153
+ const files = await this.options.client.readRepositoryFiles({
154
+ ref: this.options.defaultRef,
155
+ paths: filePaths,
156
+ parseFrontmatter: true
157
+ });
158
+ return (files.files ?? []).map((file) => entryFromTreeDxFile(definition, file, contentDir));
159
+ }
160
+ async get(request) {
161
+ const definition = resolveModelDefinition(request.model, this.options.models);
162
+ const contentDir = resolveContentDir(definition, this.options);
163
+ const candidates = [request.id, request.slug, request.key].filter((value) => Boolean(value));
164
+ for (const candidate of candidates) {
165
+ for (const extension of [".mdx", ".md"]) {
166
+ try {
167
+ const response = await this.options.client.readRepositoryFile({
168
+ ref: this.options.defaultRef,
169
+ path: `${contentDir}/${candidate}${extension}`,
170
+ parseFrontmatter: true
171
+ });
172
+ if (response.file) {
173
+ return entryFromTreeDxFile(definition, response.file, contentDir);
174
+ }
175
+ } catch (error) {
176
+ if (!(error instanceof TreeDxApiError) || error.status !== 404) {
177
+ throw error;
178
+ }
179
+ }
180
+ }
181
+ }
182
+ return null;
183
+ }
184
+ async search(request) {
185
+ const definition = resolveModelDefinition(request.model, this.options.models);
186
+ const contentDir = resolveContentDir(definition, this.options);
187
+ const response = await this.options.client.searchRepositoryFiles({
188
+ ref: this.options.defaultRef,
189
+ paths: [`${contentDir}/**`],
190
+ query: "",
191
+ filters: mapFilters(definition, request.filters),
192
+ sort: mapSort(definition, request.sort),
193
+ limit: request.limit,
194
+ includeBody: true,
195
+ includeFrontmatter: true
196
+ });
197
+ const results = response.results ?? response.files ?? [];
198
+ return results.map((file) => entryFromTreeDxFile(definition, file, contentDir));
199
+ }
200
+ async follow(request) {
201
+ const items = await this.search({
202
+ model: request.model,
203
+ filters: [
204
+ ...request.filters ?? [],
205
+ { field: "updated_at", op: "updated_since", value: request.since }
206
+ ]
207
+ });
208
+ return { items, since: request.since };
209
+ }
210
+ async pick(request) {
211
+ throw new TreeDxApiError("TreeDX remote content leases are not implemented by the TreeDX remote graph adapter.", {
212
+ status: 501,
213
+ code: "not_implemented",
214
+ details: { strategy: request.strategy ?? "latest", sort: pickSortForStrategy(resolveModelDefinition(request.model, this.options.models), request) }
215
+ });
216
+ }
217
+ async create(request) {
218
+ const definition = resolveModelDefinition(request.model, this.options.models);
219
+ ensureMutationAllowed(definition, "create");
220
+ const contentDir = resolveContentDir(definition, this.options);
221
+ const slug = String(request.data.slug ?? request.data.id ?? crypto.randomUUID());
222
+ const extension = definition.name === "knowledge" ? ".md" : ".mdx";
223
+ const filePath = `${contentDir}/${slug}${extension}`;
224
+ const mutationData = normalizeMutationData(definition, sanitizeFrontmatterInput(request.data));
225
+ const body = typeof request.data.body === "string" ? request.data.body : "";
226
+ const frontmatter = canonicalizeFrontmatter(definition, {}, {
227
+ ...mutationData,
228
+ slug,
229
+ updated_at: mutationData.updated_at ?? (/* @__PURE__ */ new Date()).toISOString()
230
+ });
231
+ return this.writeAndCommit(definition, contentDir, filePath, serializeFrontmatterDocument(frontmatter, body), {
232
+ branchName: `refs/heads/${String(request.data.branchPrefix ?? this.options.branchPrefix ?? "agent")}/${definition.name}-${slug}`,
233
+ message: `agent(${definition.name}): create ${slug}`
234
+ });
235
+ }
236
+ async update(request) {
237
+ const definition = resolveModelDefinition(request.model, this.options.models);
238
+ ensureMutationAllowed(definition, "update");
239
+ const contentDir = resolveContentDir(definition, this.options);
240
+ const existing = await this.get(request);
241
+ if (!existing) {
242
+ throw new TreeDxApiError(`No ${request.model} entry found for update.`, {
243
+ status: 404,
244
+ code: "not_found"
245
+ });
246
+ }
247
+ const mutationData = normalizeMutationData(definition, sanitizeFrontmatterInput(request.data));
248
+ const nextFrontmatter = canonicalizeFrontmatter(
249
+ definition,
250
+ normalizeRecordToCanonicalShape(definition, existing.frontmatter),
251
+ {
252
+ ...mutationData,
253
+ updated_at: mutationData.updated_at ?? (/* @__PURE__ */ new Date()).toISOString()
254
+ }
255
+ );
256
+ const nextBody = typeof request.data.body === "string" ? request.data.body : existing.body;
257
+ return this.writeAndCommit(definition, contentDir, existing.path, serializeFrontmatterDocument(nextFrontmatter, nextBody), {
258
+ branchName: `refs/heads/${String(request.data.branchPrefix ?? this.options.branchPrefix ?? "agent")}/${definition.name}-${existing.slug}`,
259
+ message: `agent(${definition.name}): update ${existing.slug}`,
260
+ expectedSha: request.expectedVersion
261
+ });
262
+ }
263
+ async writeAndCommit(definition, contentDir, filePath, content, options) {
264
+ const workspace = await this.options.client.createWorkspace({
265
+ baseRef: this.options.defaultRef ?? "refs/heads/main",
266
+ branchName: options.branchName,
267
+ mode: "writable",
268
+ allowedPaths: [`${contentDir}/**`]
269
+ });
270
+ try {
271
+ await this.options.client.writeFile({
272
+ workspaceId: workspace.workspaceId,
273
+ path: filePath,
274
+ encoding: "utf8",
275
+ content,
276
+ expectedSha: options.expectedSha
277
+ });
278
+ const git = await this.options.client.commit({
279
+ workspaceId: workspace.workspaceId,
280
+ message: options.message,
281
+ author: this.options.defaultAuthor ?? {
282
+ name: "TreeDX SDK",
283
+ email: "sdk@example.invalid"
284
+ }
285
+ });
286
+ const response = await this.options.client.readRepositoryFile({
287
+ ref: git.branchName,
288
+ path: filePath,
289
+ parseFrontmatter: true
290
+ });
291
+ return {
292
+ item: entryFromTreeDxFile(definition, response.file, contentDir),
293
+ git
294
+ };
295
+ } catch (error) {
296
+ await this.options.client.closeWorkspace(workspace.workspaceId).catch(() => {
297
+ });
298
+ throw error;
299
+ }
300
+ }
301
+ }
302
+ export {
303
+ TreeDxRepositoryAdapter,
304
+ entryFromTreeDxFile,
305
+ mapFilters,
306
+ mapSort,
307
+ resolveContentDir
308
+ };