@treeseed/sdk 0.5.3 → 0.6.1

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 (66) hide show
  1. package/dist/index.d.ts +2 -0
  2. package/dist/index.js +46 -0
  3. package/dist/operations/providers/default.js +1 -1
  4. package/dist/operations/services/config-runtime.d.ts +49 -42
  5. package/dist/operations/services/config-runtime.js +449 -136
  6. package/dist/operations/services/deploy.d.ts +298 -0
  7. package/dist/operations/services/deploy.js +381 -137
  8. package/dist/operations/services/git-workflow.d.ts +9 -0
  9. package/dist/operations/services/git-workflow.js +32 -0
  10. package/dist/operations/services/github-api.d.ts +115 -0
  11. package/dist/operations/services/github-api.js +455 -0
  12. package/dist/operations/services/github-automation.d.ts +19 -33
  13. package/dist/operations/services/github-automation.js +44 -131
  14. package/dist/operations/services/key-agent.d.ts +20 -1
  15. package/dist/operations/services/key-agent.js +267 -102
  16. package/dist/operations/services/knowledge-coop-launch.d.ts +2 -3
  17. package/dist/operations/services/knowledge-coop-launch.js +26 -12
  18. package/dist/operations/services/project-platform.d.ts +157 -150
  19. package/dist/operations/services/project-platform.js +129 -26
  20. package/dist/operations/services/railway-api.d.ts +244 -0
  21. package/dist/operations/services/railway-api.js +882 -0
  22. package/dist/operations/services/railway-deploy.d.ts +171 -27
  23. package/dist/operations/services/railway-deploy.js +672 -172
  24. package/dist/operations/services/runtime-tools.d.ts +18 -0
  25. package/dist/operations/services/runtime-tools.js +19 -6
  26. package/dist/operations/services/workspace-preflight.js +2 -2
  27. package/dist/platform/contracts.d.ts +7 -0
  28. package/dist/platform/deploy-config.js +23 -0
  29. package/dist/platform/deploy-runtime.d.ts +1 -0
  30. package/dist/platform/deploy-runtime.js +7 -9
  31. package/dist/platform/env.yaml +10 -9
  32. package/dist/platform/environment.js +4 -0
  33. package/dist/platform/plugin.d.ts +6 -0
  34. package/dist/platform/plugins/constants.d.ts +1 -0
  35. package/dist/platform/plugins/constants.js +1 -0
  36. package/dist/platform/plugins/runtime.d.ts +4 -0
  37. package/dist/platform/plugins/runtime.js +8 -1
  38. package/dist/platform/published-content.js +27 -4
  39. package/dist/platform/tenant/runtime-config.js +33 -24
  40. package/dist/plugin-default.d.ts +1 -0
  41. package/dist/plugin-default.js +1 -0
  42. package/dist/reconcile/builtin-adapters.d.ts +3 -0
  43. package/dist/reconcile/builtin-adapters.js +2116 -0
  44. package/dist/reconcile/contracts.d.ts +155 -0
  45. package/dist/reconcile/contracts.js +0 -0
  46. package/dist/reconcile/desired-state.d.ts +179 -0
  47. package/dist/reconcile/desired-state.js +319 -0
  48. package/dist/reconcile/engine.d.ts +405 -0
  49. package/dist/reconcile/engine.js +356 -0
  50. package/dist/reconcile/errors.d.ts +5 -0
  51. package/dist/reconcile/errors.js +13 -0
  52. package/dist/reconcile/index.d.ts +7 -0
  53. package/dist/reconcile/index.js +7 -0
  54. package/dist/reconcile/registry.d.ts +7 -0
  55. package/dist/reconcile/registry.js +64 -0
  56. package/dist/reconcile/state.d.ts +7 -0
  57. package/dist/reconcile/state.js +303 -0
  58. package/dist/reconcile/units.d.ts +6 -0
  59. package/dist/reconcile/units.js +68 -0
  60. package/dist/scripts/config-treeseed.js +27 -19
  61. package/dist/scripts/tenant-deploy.js +35 -14
  62. package/dist/workflow/operations.js +127 -22
  63. package/dist/workflow-support.d.ts +3 -1
  64. package/dist/workflow-support.js +50 -0
  65. package/dist/workflow.d.ts +2 -0
  66. package/package.json +7 -1
@@ -21,7 +21,7 @@ export declare function parseGitHubRepositoryFromRemote(remoteUrl: any): string
21
21
  export declare function resolveGitHubRepositorySlug(tenantRoot: any): string;
22
22
  export declare function maybeResolveGitHubRepositorySlug(tenantRoot: any): string | null;
23
23
  export declare function resolveDefaultGitHubOwner(): string;
24
- export declare function createGitHubRepository(input: any): {
24
+ export declare function createGitHubRepository(input: any): Promise<import("./github-api.ts").GitHubRepositorySummary | {
25
25
  visibility: any;
26
26
  defaultBranch: string;
27
27
  mode: string;
@@ -31,16 +31,7 @@ export declare function createGitHubRepository(input: any): {
31
31
  sshUrl: string;
32
32
  httpsUrl: string;
33
33
  url: string;
34
- } | {
35
- owner: string;
36
- name: string;
37
- url: string;
38
- visibility: string;
39
- defaultBranch: string;
40
- slug: string;
41
- sshUrl: string;
42
- httpsUrl: string;
43
- };
34
+ }>;
44
35
  export declare function initializeGitHubRepositoryWorkingTree(cwd: any, repository: any, { defaultBranch, createStaging, commitMessage, remoteName, push, }?: {
45
36
  defaultBranch?: string | undefined;
46
37
  createStaging?: boolean | undefined;
@@ -110,12 +101,12 @@ export declare function ensureStandardizedGitHubWorkflows(tenantRoot: any): ({
110
101
  changed: boolean;
111
102
  mode?: undefined;
112
103
  })[];
113
- export declare function listGitHubSecretNames(repository: any, tenantRoot: any): Set<unknown>;
114
- export declare function listGitHubVariableNames(repository: any, tenantRoot: any): Set<unknown>;
104
+ export declare function listGitHubSecretNames(repository: any, tenantRoot: any): Promise<Set<string>>;
105
+ export declare function listGitHubVariableNames(repository: any, tenantRoot: any): Promise<Set<string>>;
115
106
  export declare function formatMissingSecretsReport(repository: any, missingSecrets: any, reason?: string): string;
116
107
  export declare function ensureGitHubSecrets(tenantRoot: any, { dryRun }?: {
117
108
  dryRun?: boolean | undefined;
118
- }): {
109
+ }): Promise<{
119
110
  existing: never[];
120
111
  created: never[];
121
112
  } | {
@@ -124,12 +115,12 @@ export declare function ensureGitHubSecrets(tenantRoot: any, { dryRun }?: {
124
115
  } | {
125
116
  existing: string[];
126
117
  created: string[];
127
- };
118
+ }>;
128
119
  export declare function ensureGitHubEnvironment(tenantRoot: any, { dryRun, scope, purpose }?: {
129
120
  dryRun?: boolean | undefined;
130
121
  scope?: string | undefined;
131
122
  purpose?: string | undefined;
132
- }): {
123
+ }): Promise<{
133
124
  repository: string | null;
134
125
  secrets: {
135
126
  existing: never[];
@@ -165,10 +156,10 @@ export declare function ensureGitHubEnvironment(tenantRoot: any, { dryRun, scope
165
156
  };
166
157
  skipped?: undefined;
167
158
  mode?: undefined;
168
- };
159
+ }>;
169
160
  export declare function ensureGitHubDeployAutomation(tenantRoot: any, { dryRun }?: {
170
161
  dryRun?: boolean | undefined;
171
- }): {
162
+ }): Promise<{
172
163
  mode: string;
173
164
  workflow: {
174
165
  workflowPath: string;
@@ -249,29 +240,24 @@ export declare function ensureGitHubDeployAutomation(tenantRoot: any, { dryRun }
249
240
  skipped?: undefined;
250
241
  mode?: undefined;
251
242
  };
252
- };
243
+ }>;
253
244
  export declare function waitForGitHubWorkflowCompletion(tenantRoot: any, { repository, workflow, headSha, branch, timeoutSeconds, pollSeconds, }?: {
254
245
  workflow?: string | undefined;
255
246
  timeoutSeconds?: number | undefined;
256
247
  pollSeconds?: number | undefined;
257
- }): {
248
+ }): Promise<{
258
249
  status: string;
259
- reason: string;
260
- repository: any;
250
+ repository: string;
261
251
  workflow: string;
262
- headSha: any;
263
- branch: any;
264
- runId?: undefined;
265
- conclusion?: undefined;
266
- url?: undefined;
252
+ runId: number;
253
+ headSha: string | null;
254
+ conclusion: string | null;
255
+ url: string | null;
267
256
  } | {
268
257
  status: string;
258
+ reason: string;
269
259
  repository: any;
270
260
  workflow: string;
271
- runId: any;
272
261
  headSha: any;
273
- conclusion: any;
274
- url: any;
275
- reason?: undefined;
276
- branch?: undefined;
277
- };
262
+ branch: any;
263
+ }>;
@@ -3,6 +3,15 @@ import { dirname, relative, resolve } from "node:path";
3
3
  import { spawnSync } from "node:child_process";
4
4
  import { resolveTreeseedEnvironmentRegistry } from "../../platform/environment.js";
5
5
  import { packageRoot, loadCliDeployConfig } from "./runtime-tools.js";
6
+ import {
7
+ createGitHubApiClient,
8
+ ensureGitHubRepository,
9
+ listGitHubRepositorySecretNames,
10
+ listGitHubRepositoryVariableNames,
11
+ upsertGitHubRepositorySecret,
12
+ upsertGitHubRepositoryVariable,
13
+ waitForGitHubWorkflowRunCompletion
14
+ } from "./github-api.js";
6
15
  function envOrNull(key) {
7
16
  const value = process.env[key];
8
17
  return typeof value === "string" && value.length > 0 ? value : null;
@@ -41,21 +50,6 @@ function runGit(args, { cwd, allowFailure = false, capture = true } = {}) {
41
50
  }
42
51
  return result;
43
52
  }
44
- function runGh(args, { cwd, allowFailure = false, capture = true, input } = {}) {
45
- const result = spawnSync("gh", args, {
46
- cwd,
47
- stdio: capture || input !== void 0 ? ["pipe", "pipe", "pipe"] : "inherit",
48
- encoding: "utf8",
49
- input
50
- });
51
- if (result.error && result.error.code === "ENOENT") {
52
- throw new Error("GitHub CLI `gh` is required for Treeseed GitHub automation.");
53
- }
54
- if (result.status !== 0 && !allowFailure) {
55
- throw new Error(result.stderr?.trim() || result.stdout?.trim() || `gh ${args.join(" ")} failed`);
56
- }
57
- return result;
58
- }
59
53
  function sleepSeconds(seconds) {
60
54
  if (!Number.isFinite(seconds) || seconds <= 0) {
61
55
  return;
@@ -116,7 +110,7 @@ function resolveDefaultGitHubOwner() {
116
110
  }
117
111
  return "treeseed-ai";
118
112
  }
119
- function createGitHubRepository(input) {
113
+ async function createGitHubRepository(input) {
120
114
  const visibility = input.visibility ?? "private";
121
115
  const remotes = resolveGitHubRemoteUrls(input.owner, input.name);
122
116
  if (isGitHubAutomationStubbed()) {
@@ -127,42 +121,16 @@ function createGitHubRepository(input) {
127
121
  mode: "stub"
128
122
  };
129
123
  }
130
- const existing = runGh(["repo", "view", remotes.slug, "--json", "name,owner,url,isPrivate,defaultBranchRef,visibility"], {
131
- allowFailure: true
124
+ return await ensureGitHubRepository({
125
+ owner: remotes.owner,
126
+ name: remotes.name,
127
+ description: input.description ?? null,
128
+ homepageUrl: input.homepageUrl ?? null,
129
+ visibility,
130
+ topics: Array.isArray(input.topics) ? input.topics.map((topic) => slugifySegment(topic, "treeseed")) : []
131
+ }, {
132
+ client: createGitHubApiClient()
132
133
  });
133
- if (existing.status !== 0) {
134
- const args = ["repo", "create", remotes.slug, "--disable-wiki", "--confirm"];
135
- if (visibility === "public") {
136
- args.push("--public");
137
- } else if (visibility === "internal") {
138
- args.push("--internal");
139
- } else {
140
- args.push("--private");
141
- }
142
- if (input.description) {
143
- args.push("--description", input.description);
144
- }
145
- if (input.homepageUrl) {
146
- args.push("--homepage", input.homepageUrl);
147
- }
148
- runGh(args, { capture: false });
149
- }
150
- if (Array.isArray(input.topics) && input.topics.length > 0) {
151
- runGh(
152
- ["repo", "edit", remotes.slug, ...input.topics.flatMap((topic) => ["--add-topic", slugifySegment(topic, "treeseed")])],
153
- { capture: false }
154
- );
155
- }
156
- const viewed = runGh(["repo", "view", remotes.slug, "--json", "name,owner,url,isPrivate,defaultBranchRef,visibility"], {});
157
- const payload = JSON.parse(viewed.stdout || "{}");
158
- return {
159
- ...remotes,
160
- owner: String(payload.owner?.login ?? remotes.owner),
161
- name: String(payload.name ?? remotes.name),
162
- url: String(payload.url ?? remotes.url),
163
- visibility: String(payload.visibility ?? (payload.isPrivate === true ? "private" : visibility)),
164
- defaultBranch: String(payload.defaultBranchRef?.name ?? "main")
165
- };
166
134
  }
167
135
  function initializeGitHubRepositoryWorkingTree(cwd, repository, {
168
136
  defaultBranch = "main",
@@ -317,21 +285,13 @@ function ensureStandardizedGitHubWorkflows(tenantRoot) {
317
285
  }
318
286
  return workflows;
319
287
  }
320
- function listGitHubSecretNames(repository, tenantRoot) {
321
- const result = runGh(["secret", "list", "--repo", repository, "--json", "name"], {
322
- cwd: tenantRoot
323
- });
324
- return new Set(
325
- JSON.parse(result.stdout || "[]").map((entry) => entry?.name).filter((value) => typeof value === "string" && value.length > 0)
326
- );
288
+ async function listGitHubSecretNames(repository, tenantRoot) {
289
+ void tenantRoot;
290
+ return await listGitHubRepositorySecretNames(repository, { client: createGitHubApiClient() });
327
291
  }
328
- function listGitHubVariableNames(repository, tenantRoot) {
329
- const result = runGh(["variable", "list", "--repo", repository, "--json", "name"], {
330
- cwd: tenantRoot
331
- });
332
- return new Set(
333
- JSON.parse(result.stdout || "[]").map((entry) => entry?.name).filter((value) => typeof value === "string" && value.length > 0)
334
- );
292
+ async function listGitHubVariableNames(repository, tenantRoot) {
293
+ void tenantRoot;
294
+ return await listGitHubRepositoryVariableNames(repository, { client: createGitHubApiClient() });
335
295
  }
336
296
  function formatMissingSecretsReport(repository, missingSecrets, reason = "missing_local_env") {
337
297
  const lines = [
@@ -345,10 +305,10 @@ function formatMissingSecretsReport(repository, missingSecrets, reason = "missin
345
305
  }
346
306
  return lines.join("\n");
347
307
  }
348
- function ensureGitHubSecrets(tenantRoot, { dryRun = false } = {}) {
349
- return ensureGitHubEnvironment(tenantRoot, { dryRun }).secrets;
308
+ async function ensureGitHubSecrets(tenantRoot, { dryRun = false } = {}) {
309
+ return (await ensureGitHubEnvironment(tenantRoot, { dryRun })).secrets;
350
310
  }
351
- function ensureGitHubEnvironment(tenantRoot, { dryRun = false, scope = "prod", purpose = "save" } = {}) {
311
+ async function ensureGitHubEnvironment(tenantRoot, { dryRun = false, scope = "prod", purpose = "save" } = {}) {
352
312
  if (isGitHubAutomationStubbed()) {
353
313
  return {
354
314
  repository: maybeResolveGitHubRepositorySlug(tenantRoot),
@@ -379,8 +339,9 @@ function ensureGitHubEnvironment(tenantRoot, { dryRun = false, scope = "prod", p
379
339
  const required = requiredGitHubEnvironment(tenantRoot, { scope, purpose });
380
340
  const requiredSecrets = required.secrets;
381
341
  const requiredVariables = required.variables;
382
- const existingSecrets = listGitHubSecretNames(repository, tenantRoot);
383
- const existingVariables = listGitHubVariableNames(repository, tenantRoot);
342
+ const client = createGitHubApiClient();
343
+ const existingSecrets = await listGitHubRepositorySecretNames(repository, { client });
344
+ const existingVariables = await listGitHubRepositoryVariableNames(repository, { client });
384
345
  const missingRemote = requiredSecrets.filter((name) => !existingSecrets.has(name));
385
346
  const missingRemoteVariables = requiredVariables.filter((name) => !existingVariables.has(name));
386
347
  const missingLocal = missingRemote.filter((name) => !envOrNull(name)).map((name) => ({ name, localEnvPresent: false, remotePresent: false }));
@@ -394,9 +355,7 @@ function ensureGitHubEnvironment(tenantRoot, { dryRun = false, scope = "prod", p
394
355
  createdSecrets.push(name);
395
356
  continue;
396
357
  }
397
- runGh(["secret", "set", name, "--repo", repository, "--body", envOrNull(name) ?? ""], {
398
- cwd: tenantRoot
399
- });
358
+ await upsertGitHubRepositorySecret(repository, name, envOrNull(name) ?? "", { client });
400
359
  createdSecrets.push(name);
401
360
  }
402
361
  const createdVariables = [];
@@ -405,9 +364,7 @@ function ensureGitHubEnvironment(tenantRoot, { dryRun = false, scope = "prod", p
405
364
  createdVariables.push(name);
406
365
  continue;
407
366
  }
408
- runGh(["variable", "set", name, "--repo", repository, "--body", envOrNull(name) ?? ""], {
409
- cwd: tenantRoot
410
- });
367
+ await upsertGitHubRepositoryVariable(repository, name, envOrNull(name) ?? "", { client });
411
368
  createdVariables.push(name);
412
369
  }
413
370
  return {
@@ -422,9 +379,9 @@ function ensureGitHubEnvironment(tenantRoot, { dryRun = false, scope = "prod", p
422
379
  }
423
380
  };
424
381
  }
425
- function ensureGitHubDeployAutomation(tenantRoot, { dryRun = false } = {}) {
382
+ async function ensureGitHubDeployAutomation(tenantRoot, { dryRun = false } = {}) {
426
383
  const workflows = ensureStandardizedGitHubWorkflows(tenantRoot);
427
- const environment = ensureGitHubEnvironment(tenantRoot, { dryRun });
384
+ const environment = await ensureGitHubEnvironment(tenantRoot, { dryRun });
428
385
  return {
429
386
  mode: getGitHubAutomationMode(),
430
387
  workflow: workflows[0],
@@ -434,7 +391,7 @@ function ensureGitHubDeployAutomation(tenantRoot, { dryRun = false } = {}) {
434
391
  environment
435
392
  };
436
393
  }
437
- function waitForGitHubWorkflowCompletion(tenantRoot, {
394
+ async function waitForGitHubWorkflowCompletion(tenantRoot, {
438
395
  repository,
439
396
  workflow = "publish.yml",
440
397
  headSha,
@@ -453,58 +410,14 @@ function waitForGitHubWorkflowCompletion(tenantRoot, {
453
410
  };
454
411
  }
455
412
  const repo = repository ?? resolveGitHubRepositorySlug(tenantRoot);
456
- const startedAt = Date.now();
457
- while (Date.now() - startedAt < timeoutSeconds * 1e3) {
458
- const result = runGh([
459
- "run",
460
- "list",
461
- "--repo",
462
- repo,
463
- "--workflow",
464
- workflow,
465
- "--limit",
466
- "20",
467
- "--json",
468
- "databaseId,headSha,headBranch,status,conclusion,event,displayTitle,url"
469
- ], { cwd: tenantRoot });
470
- const runs = JSON.parse(result.stdout || "[]");
471
- const match = runs.find((run) => {
472
- if (headSha && run?.headSha !== headSha) {
473
- return false;
474
- }
475
- if (branch && run?.headBranch !== branch) {
476
- return false;
477
- }
478
- return true;
479
- });
480
- if (match?.databaseId) {
481
- runGh(["run", "watch", String(match.databaseId), "--repo", repo, "--exit-status"], {
482
- cwd: tenantRoot,
483
- capture: false
484
- });
485
- const finalResult = runGh([
486
- "run",
487
- "view",
488
- String(match.databaseId),
489
- "--repo",
490
- repo,
491
- "--json",
492
- "status,conclusion,url,workflowName,headSha"
493
- ], { cwd: tenantRoot });
494
- const finalRun = JSON.parse(finalResult.stdout || "{}");
495
- return {
496
- status: "completed",
497
- repository: repo,
498
- workflow,
499
- runId: match.databaseId,
500
- headSha: finalRun.headSha ?? match.headSha ?? null,
501
- conclusion: finalRun.conclusion ?? match.conclusion ?? null,
502
- url: finalRun.url ?? match.url ?? null
503
- };
504
- }
505
- sleepSeconds(pollSeconds);
506
- }
507
- throw new Error(`Timed out waiting for GitHub workflow ${workflow} in ${repo}.`);
413
+ return await waitForGitHubWorkflowRunCompletion(repo, {
414
+ client: createGitHubApiClient(),
415
+ workflow,
416
+ headSha,
417
+ branch,
418
+ timeoutSeconds,
419
+ pollSeconds
420
+ });
508
421
  }
509
422
  export {
510
423
  createGitHubRepository,
@@ -35,7 +35,22 @@ export type TreeseedKeyAgentStatus = {
35
35
  idleTimeoutMs: number;
36
36
  idleRemainingMs: number;
37
37
  };
38
+ export type TreeseedKeyAgentDiagnostics = {
39
+ socketPath: string;
40
+ pidPath: string;
41
+ socketPresent: boolean;
42
+ socketKind: 'missing' | 'socket' | 'fifo' | 'file' | 'directory' | 'other';
43
+ socketConnectable: boolean;
44
+ healthOk: boolean;
45
+ daemonPid: number | null;
46
+ lastError: string | null;
47
+ };
38
48
  export type TreeseedKeyAgentCommand = {
49
+ command: 'health';
50
+ keyPath: string;
51
+ socketPath: string;
52
+ idleTimeoutMs: number;
53
+ } | {
39
54
  command: 'status';
40
55
  keyPath: string;
41
56
  socketPath: string;
@@ -70,9 +85,10 @@ export type TreeseedKeyAgentResponse = {
70
85
  message?: string;
71
86
  status?: TreeseedKeyAgentStatus;
72
87
  machineKey?: string;
88
+ diagnostics?: TreeseedKeyAgentDiagnostics;
73
89
  };
74
90
  export declare class TreeseedKeyAgentError extends Error {
75
- code: 'locked' | 'unlock_required' | 'unlock_failed' | 'wrapped_key_missing' | 'wrapped_key_migration_required' | 'interactive_required' | 'daemon_unavailable' | 'corrupt_wrapped_key';
91
+ code: 'locked' | 'unlock_required' | 'unlock_failed' | 'wrapped_key_missing' | 'wrapped_key_migration_required' | 'interactive_required' | 'daemon_unavailable' | 'corrupt_wrapped_key' | 'permission_denied' | 'protocol_error';
76
92
  details?: Record<string, unknown>;
77
93
  constructor(code: TreeseedKeyAgentError['code'], message: string, details?: Record<string, unknown>);
78
94
  }
@@ -102,8 +118,11 @@ export declare function writeWrappedMachineKeyFile(keyPath: string, payload: Tre
102
118
  export declare function replaceWrappedMachineKey(keyPath: string, machineKey: Buffer, passphrase: string): TreeseedWrappedMachineKey;
103
119
  export declare function getTreeseedKeyAgentPaths(): {
104
120
  homeRoot: string;
121
+ runtimeRoot: string;
105
122
  socketPath: string;
123
+ pidPath: string;
106
124
  };
125
+ export declare function inspectTreeseedKeyAgentDiagnostics(socketPath: string): Promise<TreeseedKeyAgentDiagnostics>;
107
126
  export declare function handleTreeseedKeyAgentCommand(command: TreeseedKeyAgentCommand, session: TreeseedKeyAgentSessionState): TreeseedKeyAgentResponse;
108
127
  export declare function requestTreeseedKeyAgent(command: TreeseedKeyAgentCommand): Promise<TreeseedKeyAgentResponse>;
109
128
  export declare function startTreeseedKeyAgentServer(options: {