@treeseed/sdk 0.4.13 → 0.5.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 (82) hide show
  1. package/dist/control-plane-client.d.ts +60 -1
  2. package/dist/control-plane-client.js +59 -0
  3. package/dist/control-plane.d.ts +1 -1
  4. package/dist/control-plane.js +11 -4
  5. package/dist/d1-store.d.ts +58 -0
  6. package/dist/d1-store.js +64 -0
  7. package/dist/dispatch.js +6 -0
  8. package/dist/graph/schema.js +4 -0
  9. package/dist/index.d.ts +5 -1
  10. package/dist/index.js +32 -0
  11. package/dist/knowledge-coop.d.ts +223 -0
  12. package/dist/knowledge-coop.js +82 -0
  13. package/dist/model-registry.js +79 -0
  14. package/dist/operations/providers/default.js +126 -7
  15. package/dist/operations/services/config-runtime.d.ts +102 -24
  16. package/dist/operations/services/config-runtime.js +896 -160
  17. package/dist/operations/services/deploy.d.ts +223 -15
  18. package/dist/operations/services/deploy.js +626 -55
  19. package/dist/operations/services/github-automation.d.ts +60 -0
  20. package/dist/operations/services/github-automation.js +138 -0
  21. package/dist/operations/services/key-agent.d.ts +118 -0
  22. package/dist/operations/services/key-agent.js +476 -0
  23. package/dist/operations/services/knowledge-coop-launch.d.ts +90 -0
  24. package/dist/operations/services/knowledge-coop-launch.js +753 -0
  25. package/dist/operations/services/knowledge-coop-packaging.d.ts +59 -0
  26. package/dist/operations/services/knowledge-coop-packaging.js +234 -0
  27. package/dist/operations/services/local-dev.d.ts +0 -1
  28. package/dist/operations/services/local-dev.js +1 -14
  29. package/dist/operations/services/project-platform.d.ts +42 -182
  30. package/dist/operations/services/project-platform.js +162 -59
  31. package/dist/operations/services/railway-deploy.d.ts +1 -0
  32. package/dist/operations/services/railway-deploy.js +31 -13
  33. package/dist/operations/services/runtime-tools.d.ts +52 -5
  34. package/dist/operations/services/runtime-tools.js +186 -26
  35. package/dist/operations/services/watch-dev.js +2 -4
  36. package/dist/operations/services/workspace-preflight.d.ts +4 -4
  37. package/dist/operations/services/workspace-preflight.js +22 -20
  38. package/dist/operations-registry.js +7 -2
  39. package/dist/platform/contracts.d.ts +39 -3
  40. package/dist/platform/deploy-config.d.ts +12 -1
  41. package/dist/platform/deploy-config.js +214 -15
  42. package/dist/platform/deploy-runtime.d.ts +1 -0
  43. package/dist/platform/deploy-runtime.js +10 -2
  44. package/dist/platform/env.yaml +93 -61
  45. package/dist/platform/environment.d.ts +13 -2
  46. package/dist/platform/environment.js +90 -20
  47. package/dist/platform/plugins/constants.d.ts +1 -0
  48. package/dist/platform/plugins/constants.js +7 -6
  49. package/dist/platform/tenant/runtime-config.js +8 -1
  50. package/dist/platform/tenant-config.js +4 -0
  51. package/dist/platform/utils/site-config-schema.js +18 -0
  52. package/dist/plugin-default.js +2 -2
  53. package/dist/scripts/key-agent.js +165 -0
  54. package/dist/scripts/tenant-build.js +4 -1
  55. package/dist/scripts/tenant-check.js +4 -1
  56. package/dist/scripts/tenant-deploy.js +43 -4
  57. package/dist/scripts/tenant-dev.js +0 -1
  58. package/dist/sdk-types.d.ts +2 -2
  59. package/dist/sdk-types.js +2 -0
  60. package/dist/sdk.d.ts +13 -0
  61. package/dist/sdk.js +40 -0
  62. package/dist/stores/knowledge-coop-store.d.ts +56 -0
  63. package/dist/stores/knowledge-coop-store.js +482 -0
  64. package/dist/treeseed/template-catalog/templates/starter-basic/template/package.json +6 -2
  65. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/api/server.js +4 -0
  66. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/config.yaml +25 -0
  67. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/decisions/adopt-initial-proposal-loop.mdx +22 -0
  68. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/people/starter-steward.mdx +11 -0
  69. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/proposals/establish-initial-proposal-loop.mdx +17 -0
  70. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/manifest.yaml +17 -10
  71. package/dist/treeseed/template-catalog/templates/starter-basic/template/treeseed.site.yaml +69 -7
  72. package/dist/treeseed/template-catalog/templates/starter-basic/template.config.json +1 -0
  73. package/dist/workflow/operations.d.ts +98 -0
  74. package/dist/workflow/operations.js +229 -7
  75. package/dist/workflow-state.d.ts +54 -2
  76. package/dist/workflow-state.js +170 -24
  77. package/dist/workflow-support.d.ts +1 -1
  78. package/dist/workflow-support.js +32 -2
  79. package/dist/workflow.d.ts +29 -0
  80. package/package.json +1 -1
  81. package/templates/github/deploy.workflow.yml +11 -1
  82. package/dist/scripts/sync-dev-vars.js +0 -6
@@ -9,6 +9,10 @@ site:
9
9
  items:
10
10
  - label: Handbook
11
11
  href: /knowledge/handbook/
12
+ - label: Proposals
13
+ href: /proposals/
14
+ - label: Decisions
15
+ href: /decisions/
12
16
  - label: Build
13
17
  items:
14
18
  - label: Welcome
@@ -38,3 +42,24 @@ models:
38
42
  docs:
39
43
  defaults:
40
44
  tags: []
45
+ notes:
46
+ defaults:
47
+ author: __SITE_NAME__
48
+ draft: false
49
+ tags: []
50
+ questions:
51
+ defaults:
52
+ draft: false
53
+ tags: []
54
+ objectives:
55
+ defaults:
56
+ draft: false
57
+ tags: []
58
+ proposals:
59
+ defaults:
60
+ draft: false
61
+ tags: []
62
+ decisions:
63
+ defaults:
64
+ draft: false
65
+ tags: []
@@ -0,0 +1,22 @@
1
+ ---
2
+ id: decision:adopt-initial-proposal-loop
3
+ title: Adopt The Initial Proposal Loop
4
+ description: Seed the starter with a decision record alongside the initial proposal.
5
+ date: 2026-04-17
6
+ summary: The starter demonstrates that decisions are first-class records, not hidden implementation residue.
7
+ status: live
8
+ decisionType: approved
9
+ rationale: Teams benefit from a visible pattern for recording what was chosen and why.
10
+ authority: Starter template
11
+ primaryContributor: starter-steward
12
+ relatedObjectives: []
13
+ relatedQuestions: []
14
+ relatedNotes: []
15
+ relatedProposals:
16
+ - establish-initial-proposal-loop
17
+ relatedBooks: []
18
+ implements:
19
+ - starter
20
+ ---
21
+
22
+ This starter decision exists to make the proposal-to-decision loop visible in a freshly generated TreeSeed site.
@@ -0,0 +1,11 @@
1
+ ---
2
+ name: Starter Steward
3
+ role: Maintainer
4
+ affiliation: Starter template
5
+ status: live
6
+ tags:
7
+ - stewardship
8
+ - starter
9
+ ---
10
+
11
+ This placeholder profile exists so the starter can model contributor-linked content from the first commit.
@@ -0,0 +1,17 @@
1
+ ---
2
+ id: proposal:establish-initial-proposal-loop
3
+ title: Establish The Initial Proposal Loop
4
+ description: Seed the starter with a proposal so suggested changes are explicit from day one.
5
+ date: 2026-04-17
6
+ summary: The starter should show how a team can move from questions and objectives into a concrete proposal.
7
+ status: live
8
+ proposalType: strategy
9
+ motivation: New sites should inherit a visible proposal-to-decision pattern instead of recreating it ad hoc.
10
+ primaryContributor: starter-steward
11
+ relatedObjectives: []
12
+ relatedQuestions: []
13
+ relatedNotes: []
14
+ relatedBooks: []
15
+ ---
16
+
17
+ Use this starter proposal as a placeholder for the first concrete change a team wants to make in its site or operating model.
@@ -3,17 +3,24 @@ siteConfigPath: ./src/config.yaml
3
3
  content:
4
4
  docs: ./src/content/knowledge
5
5
  pages: ./src/content/pages
6
- notes: ./src/content/empty
7
- questions: ./src/content/empty
8
- objectives: ./src/content/empty
9
- people: ./src/content/empty
10
- agents: ./src/content/empty
11
- books: ./src/content/empty
6
+ notes: ./src/content/notes
7
+ questions: ./src/content/questions
8
+ objectives: ./src/content/objectives
9
+ proposals: ./src/content/proposals
10
+ decisions: ./src/content/decisions
11
+ people: ./src/content/people
12
+ agents: ./src/content/agents
13
+ books: ./src/content/books
14
+ templates: ./src/content/templates
15
+ knowledge_packs: ./src/content/knowledge-packs
16
+ workdays: ./src/content/workdays
12
17
  features:
13
18
  docs: true
14
19
  books: false
15
- notes: false
16
- questions: false
17
- objectives: false
18
- agents: false
20
+ notes: true
21
+ questions: true
22
+ objectives: true
23
+ proposals: true
24
+ decisions: true
25
+ agents: true
19
26
  forms: false
@@ -5,12 +5,14 @@ contactEmail: __CONTACT_EMAIL__
5
5
  hosting:
6
6
  kind: hosted_project
7
7
  registration: optional
8
- marketBaseUrl: https://api.treeseed.ai
8
+ marketBaseUrl: https://knowledge.coop
9
9
  teamId: __SITE_SLUG__
10
10
  projectId: __SITE_SLUG__
11
11
  cloudflare:
12
12
  accountId: replace-with-cloudflare-account-id
13
13
  workerName: __SITE_SLUG__
14
+ queueName: __SITE_SLUG__-agent-work
15
+ dlqName: __SITE_SLUG__-agent-work-dlq
14
16
  pages:
15
17
  projectName: __SITE_SLUG__
16
18
  previewProjectName: __SITE_SLUG__-staging
@@ -23,17 +25,77 @@ cloudflare:
23
25
  manifestKeyTemplate: teams/{teamId}/published/common.json
24
26
  previewRootTemplate: teams/{teamId}/previews
25
27
  previewTtlHours: 168
28
+ surfaces:
29
+ web:
30
+ enabled: true
31
+ provider: cloudflare
32
+ rootDir: .
33
+ publicBaseUrl: https://__SITE_SLUG__.pages.dev
34
+ localBaseUrl: http://127.0.0.1:4321
35
+ api:
36
+ enabled: true
37
+ provider: railway
38
+ rootDir: .
39
+ localBaseUrl: http://127.0.0.1:3000
40
+ services:
41
+ api:
42
+ enabled: true
43
+ provider: railway
44
+ rootDir: .
45
+ publicBaseUrl: https://__SITE_SLUG__-api.up.railway.app
46
+ railway:
47
+ serviceName: __SITE_SLUG__-api
48
+ buildCommand: npm run build
49
+ startCommand: node ./src/api/server.js
50
+ environments:
51
+ local:
52
+ baseUrl: http://127.0.0.1:3000
53
+ manager:
54
+ enabled: true
55
+ provider: railway
56
+ railway:
57
+ serviceName: __SITE_SLUG__-manager
58
+ rootDir: .
59
+ buildCommand: npm run build
60
+ startCommand: node ./node_modules/@treeseed/core/dist/services/manager.js
61
+ schedule: '*/5 * * * *'
62
+ worker:
63
+ enabled: true
64
+ provider: railway
65
+ railway:
66
+ serviceName: __SITE_SLUG__-worker
67
+ rootDir: .
68
+ buildCommand: npm run build
69
+ startCommand: node ./node_modules/@treeseed/core/dist/services/worker.js
70
+ workdayStart:
71
+ enabled: true
72
+ provider: railway
73
+ railway:
74
+ serviceName: __SITE_SLUG__-workday-start
75
+ rootDir: .
76
+ buildCommand: npm run build
77
+ startCommand: node ./node_modules/@treeseed/core/dist/services/workday-start.js
78
+ schedule: '0 9 * * 1-5'
79
+ workdayReport:
80
+ enabled: true
81
+ provider: railway
82
+ railway:
83
+ serviceName: __SITE_SLUG__-workday-report
84
+ rootDir: .
85
+ buildCommand: npm run build
86
+ startCommand: node ./node_modules/@treeseed/core/dist/services/workday-report.js
87
+ schedule: '5 17 * * 1-5'
26
88
  plugins:
27
- - package: '@treeseed/sdk/plugin-default'
89
+ - package: '@treeseed/core/plugin-default'
28
90
  providers:
29
91
  forms: store_only
30
92
  agents:
31
- execution: stub
93
+ execution: copilot
32
94
  mutation: local_branch
33
- repository: stub
34
- verification: stub
35
- notification: stub
36
- research: stub
95
+ repository: git
96
+ verification: local
97
+ notification: sdk_message
98
+ research: project_graph
37
99
  deploy: cloudflare
38
100
  content:
39
101
  runtime: team_scoped_r2_overlay
@@ -78,6 +78,7 @@
78
78
  "astro.config.ts",
79
79
  "tsconfig.json",
80
80
  "treeseed.site.yaml",
81
+ "src/api/server.js",
81
82
  "src/content.config.ts",
82
83
  "src/config.yaml",
83
84
  "src/manifest.yaml",
@@ -45,8 +45,81 @@ type WorkflowRepoReport = {
45
45
  export declare function workflowStatus(helpers: WorkflowOperationHelpers): Promise<TreeseedWorkflowResult<import("../workflow-state.ts").TreeseedWorkflowState>>;
46
46
  export declare function workflowTasks(helpers: WorkflowOperationHelpers): Promise<TreeseedWorkflowResult<{
47
47
  tasks: TreeseedTaskBranchMetadata[];
48
+ workstreams: Array<{
49
+ id: string;
50
+ title: string;
51
+ linkedDirectRefs: Array<{
52
+ model: "objective" | "question" | "note";
53
+ id: string;
54
+ }>;
55
+ branch: string;
56
+ local: boolean;
57
+ remote: boolean;
58
+ current: boolean;
59
+ previewUrl: string | null;
60
+ lastSaveAt: string | null;
61
+ verificationResult: "ready" | "needs_attention" | "unknown";
62
+ stagingCandidate: boolean;
63
+ archived: boolean;
64
+ }>;
48
65
  }>>;
49
66
  export declare function workflowConfig(helpers: WorkflowOperationHelpers, input?: TreeseedConfigInput): Promise<TreeseedWorkflowResult<{
67
+ mode: string;
68
+ scopes: ("local" | "staging" | "prod")[];
69
+ sync: "none" | "cloudflare" | "railway" | "github" | "all" | undefined;
70
+ configPath: string;
71
+ keyPath: string;
72
+ repairs: unknown[];
73
+ preflight: {
74
+ ok: boolean;
75
+ requireAuth: boolean;
76
+ missingCommands: string[];
77
+ failingAuth: string[];
78
+ checks: {
79
+ commands: {
80
+ [k: string]: {
81
+ installed: boolean;
82
+ path: string | null;
83
+ };
84
+ };
85
+ auth: {};
86
+ };
87
+ };
88
+ toolHealth: {
89
+ githubCli: {
90
+ name: any;
91
+ available: any;
92
+ detail: any;
93
+ };
94
+ ghActExtension: {
95
+ name: any;
96
+ available: any;
97
+ detail: any;
98
+ };
99
+ dockerDaemon: {
100
+ name: any;
101
+ available: any;
102
+ detail: any;
103
+ };
104
+ wranglerCli: {
105
+ name: any;
106
+ available: any;
107
+ detail: any;
108
+ };
109
+ railwayCli: {
110
+ name: any;
111
+ available: any;
112
+ detail: any;
113
+ };
114
+ actVerificationReady: any;
115
+ remediation: string[];
116
+ };
117
+ market: any;
118
+ connection: import("../sdk-types.ts").ProjectConnection | null;
119
+ runnerTokenIssued: boolean;
120
+ } & {
121
+ finalState?: WorkflowStatePayload;
122
+ }> | TreeseedWorkflowResult<{
50
123
  mode: string;
51
124
  scopes: ("local" | "staging" | "prod")[];
52
125
  sync: "none" | "cloudflare" | "railway" | "github" | "all";
@@ -66,6 +139,7 @@ export declare function workflowConfig(helpers: WorkflowOperationHelpers, input?
66
139
  ready: any;
67
140
  detail: any;
68
141
  }[];
142
+ issues: any[];
69
143
  };
70
144
  }[];
71
145
  repairs: import("../operations/services/config-runtime.ts").TreeseedRepairAction[];
@@ -100,9 +174,21 @@ export declare function workflowConfig(helpers: WorkflowOperationHelpers, input?
100
174
  available: any;
101
175
  detail: any;
102
176
  };
177
+ wranglerCli: {
178
+ name: any;
179
+ available: any;
180
+ detail: any;
181
+ };
182
+ railwayCli: {
183
+ name: any;
184
+ available: any;
185
+ detail: any;
186
+ };
103
187
  actVerificationReady: any;
104
188
  remediation: string[];
105
189
  };
190
+ context: import("../operations/services/config-runtime.ts").TreeseedCollectedConfigContext;
191
+ secretSession: import("../operations/services/config-runtime.ts").TreeseedConfigSecretSessionBootstrap;
106
192
  } & {
107
193
  finalState?: WorkflowStatePayload;
108
194
  }> | TreeseedWorkflowResult<{
@@ -142,9 +228,21 @@ export declare function workflowConfig(helpers: WorkflowOperationHelpers, input?
142
228
  available: any;
143
229
  detail: any;
144
230
  };
231
+ wranglerCli: {
232
+ name: any;
233
+ available: any;
234
+ detail: any;
235
+ };
236
+ railwayCli: {
237
+ name: any;
238
+ available: any;
239
+ detail: any;
240
+ };
145
241
  actVerificationReady: any;
146
242
  remediation: string[];
147
243
  };
244
+ context: import("../operations/services/config-runtime.ts").TreeseedCollectedConfigContext;
245
+ secretSession: import("../operations/services/config-runtime.ts").TreeseedConfigSecretSessionBootstrap;
148
246
  } & {
149
247
  finalState?: WorkflowStatePayload;
150
248
  }>>;
@@ -9,12 +9,20 @@ import {
9
9
  checkTreeseedProviderConnections,
10
10
  collectTreeseedConfigContext,
11
11
  collectTreeseedPrintEnvReport,
12
+ ensureTreeseedSecretSessionForConfig,
12
13
  ensureTreeseedActVerificationTooling,
13
14
  ensureTreeseedGitignoreEntries,
14
15
  finalizeTreeseedConfig,
15
16
  getTreeseedMachineConfigPaths,
16
- rotateTreeseedMachineKey
17
+ inspectTreeseedKeyAgentStatus,
18
+ loadTreeseedMachineConfig,
19
+ resolveTreeseedLaunchEnvironment,
20
+ resolveTreeseedRemoteSession,
21
+ rotateTreeseedMachineKey,
22
+ setTreeseedRemoteSession,
23
+ writeTreeseedMachineConfig
17
24
  } from "../operations/services/config-runtime.js";
25
+ import { ControlPlaneClient } from "../control-plane-client.js";
18
26
  import { exportTreeseedCodebase } from "../operations/services/export-runtime.js";
19
27
  import {
20
28
  assertDeploymentInitialized,
@@ -338,7 +346,175 @@ function createTasksResult(cwd) {
338
346
  packages
339
347
  };
340
348
  });
341
- return buildWorkflowResult("tasks", cwd, { tasks }, { includeFinalState: false });
349
+ const workstreams = tasks.map((task) => ({
350
+ id: task.name,
351
+ title: task.name.replace(/^task\//u, "").replace(/[-_]+/gu, " "),
352
+ linkedDirectRefs: [],
353
+ branch: task.name,
354
+ local: task.local,
355
+ remote: task.remote,
356
+ current: task.current,
357
+ previewUrl: task.preview.url,
358
+ lastSaveAt: task.lastCommitDate ?? null,
359
+ verificationResult: task.dirtyCurrent ? "needs_attention" : task.head ? "ready" : "unknown",
360
+ stagingCandidate: task.name === STAGING_BRANCH,
361
+ archived: false
362
+ }));
363
+ return buildWorkflowResult("tasks", cwd, { tasks, workstreams }, { includeFinalState: false });
364
+ }
365
+ function normalizeOptionalString(value) {
366
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
367
+ }
368
+ async function connectTreeseedMarketProject(helpers, tenantRoot, input, context) {
369
+ const machineConfig = loadTreeseedMachineConfig(tenantRoot);
370
+ const marketSettings = machineConfig.settings?.market && typeof machineConfig.settings.market === "object" ? machineConfig.settings.market : {};
371
+ const remoteSettings = machineConfig.settings?.remote && typeof machineConfig.settings.remote === "object" ? machineConfig.settings.remote : { activeHostId: "official", executionMode: "prefer-local", hosts: [] };
372
+ const baseUrl = normalizeOptionalString(input.marketBaseUrl) ?? normalizeOptionalString(marketSettings.baseUrl) ?? normalizeOptionalString(remoteSettings.hosts?.find?.((entry) => entry?.official === true)?.baseUrl) ?? normalizeOptionalString(remoteSettings.hosts?.find?.((entry) => entry?.id === remoteSettings.activeHostId)?.baseUrl);
373
+ if (!baseUrl) {
374
+ workflowError(
375
+ "config",
376
+ "validation_failed",
377
+ "Treeseed config --connect-market requires a market base URL. Pass --market-base-url or configure an authenticated remote host first."
378
+ );
379
+ }
380
+ const hostId = normalizeOptionalString(marketSettings.hostId) ?? "knowledge-coop";
381
+ const activeRemoteSession = resolveTreeseedRemoteSession(tenantRoot, hostId) ?? resolveTreeseedRemoteSession(tenantRoot, remoteSettings.activeHostId) ?? resolveTreeseedRemoteSession(tenantRoot, "official");
382
+ const accessToken = normalizeOptionalString(input.marketAccessToken) ?? normalizeOptionalString(activeRemoteSession?.accessToken);
383
+ if (!accessToken) {
384
+ workflowError(
385
+ "config",
386
+ "validation_failed",
387
+ "Treeseed config --connect-market requires a market access token. Authenticate to the Knowledge Coop control-plane first or pass --market-access-token."
388
+ );
389
+ }
390
+ const projectId = normalizeOptionalString(input.marketProjectId) ?? normalizeOptionalString(marketSettings.projectId);
391
+ if (!projectId) {
392
+ workflowError(
393
+ "config",
394
+ "validation_failed",
395
+ "Treeseed config --connect-market requires --market-project-id or an existing settings.market.projectId value."
396
+ );
397
+ }
398
+ const teamId = normalizeOptionalString(input.marketTeamId) ?? normalizeOptionalString(marketSettings.teamId);
399
+ const projectSlug = normalizeOptionalString(input.marketProjectSlug) ?? normalizeOptionalString(marketSettings.projectSlug) ?? normalizeOptionalString(machineConfig.project?.slug) ?? projectId;
400
+ const teamSlug = normalizeOptionalString(input.marketTeamSlug) ?? normalizeOptionalString(marketSettings.teamSlug);
401
+ const projectApiBaseUrl = normalizeOptionalString(input.marketProjectApiBaseUrl) ?? normalizeOptionalString(marketSettings.projectApiBaseUrl);
402
+ const client = new ControlPlaneClient({
403
+ baseUrl,
404
+ accessToken
405
+ });
406
+ const connectionResult = await client.upsertProjectConnection(projectId, {
407
+ mode: "hybrid",
408
+ projectApiBaseUrl,
409
+ executionOwner: "project_runner",
410
+ metadata: {
411
+ pairingSource: "treeseed_config_connect_market",
412
+ tenantRoot,
413
+ tenantSlug: normalizeOptionalString(machineConfig.project?.slug),
414
+ repoSlug: normalizeOptionalString(machineConfig.project?.slug),
415
+ teamId,
416
+ teamSlug,
417
+ projectSlug,
418
+ connectedAt: (/* @__PURE__ */ new Date()).toISOString()
419
+ },
420
+ rotateRunnerToken: input.rotateRunnerToken === true
421
+ });
422
+ const hosts = Array.isArray(remoteSettings.hosts) ? [...remoteSettings.hosts] : [];
423
+ const updatedHost = {
424
+ id: hostId,
425
+ label: "Knowledge Coop",
426
+ baseUrl,
427
+ official: false
428
+ };
429
+ const existingHostIndex = hosts.findIndex(
430
+ (entry) => String(entry?.id ?? "") === hostId || String(entry?.baseUrl ?? "").replace(/\/+$/u, "") === baseUrl.replace(/\/+$/u, "")
431
+ );
432
+ if (existingHostIndex >= 0) {
433
+ hosts.splice(existingHostIndex, 1, {
434
+ ...hosts[existingHostIndex],
435
+ ...updatedHost
436
+ });
437
+ } else {
438
+ hosts.unshift(updatedHost);
439
+ }
440
+ if (normalizeOptionalString(input.marketAccessToken)) {
441
+ setTreeseedRemoteSession(tenantRoot, {
442
+ hostId,
443
+ accessToken,
444
+ refreshToken: activeRemoteSession?.refreshToken ?? "",
445
+ expiresAt: activeRemoteSession?.expiresAt ?? "",
446
+ principal: activeRemoteSession?.principal ?? null
447
+ });
448
+ }
449
+ const runnerHostId = `market-runner:${projectId}`;
450
+ if (connectionResult.runnerToken) {
451
+ setTreeseedRemoteSession(tenantRoot, {
452
+ hostId: runnerHostId,
453
+ accessToken: connectionResult.runnerToken,
454
+ refreshToken: "",
455
+ expiresAt: "",
456
+ principal: {
457
+ id: `runner:${projectId}`,
458
+ displayName: "Knowledge Coop Project Runner",
459
+ scopes: [],
460
+ roles: ["project_runner"],
461
+ permissions: [],
462
+ metadata: { projectId }
463
+ }
464
+ });
465
+ }
466
+ machineConfig.settings.remote = {
467
+ ...remoteSettings,
468
+ activeHostId: hostId,
469
+ hosts
470
+ };
471
+ machineConfig.settings.market = {
472
+ baseUrl,
473
+ hostId,
474
+ teamId,
475
+ teamSlug,
476
+ projectId,
477
+ projectSlug,
478
+ projectApiBaseUrl: connectionResult.connection?.projectApiBaseUrl ?? projectApiBaseUrl ?? null,
479
+ connectionMode: connectionResult.connection?.mode ?? "hybrid",
480
+ executionOwner: connectionResult.connection?.executionOwner ?? "project_runner",
481
+ runnerHostId,
482
+ runnerReady: Boolean(connectionResult.runnerToken || resolveTreeseedRemoteSession(tenantRoot, runnerHostId)?.accessToken),
483
+ runnerRegisteredAt: connectionResult.connection?.runnerRegisteredAt ?? null,
484
+ runnerLastSeenAt: connectionResult.connection?.runnerLastSeenAt ?? null,
485
+ launchPhase: null,
486
+ lastSuccessfulPhase: null,
487
+ githubRepository: null,
488
+ workflowBootstrapReady: false,
489
+ approvalBlockers: [],
490
+ connectedAt: (/* @__PURE__ */ new Date()).toISOString()
491
+ };
492
+ writeTreeseedMachineConfig(tenantRoot, machineConfig);
493
+ const { configPath, keyPath } = getTreeseedMachineConfigPaths(tenantRoot);
494
+ return buildWorkflowResult(
495
+ "config",
496
+ tenantRoot,
497
+ {
498
+ mode: "connect-market",
499
+ scopes: context.scopes,
500
+ sync: context.sync,
501
+ configPath,
502
+ keyPath,
503
+ repairs: context.repairs,
504
+ preflight: context.preflight,
505
+ toolHealth: context.toolHealth,
506
+ market: machineConfig.settings.market,
507
+ connection: connectionResult.connection,
508
+ runnerTokenIssued: Boolean(connectionResult.runnerToken)
509
+ },
510
+ {
511
+ summary: "Knowledge Coop project pairing completed.",
512
+ nextSteps: createNextSteps([
513
+ { operation: "status", reason: "Confirm the new market connection, runner health, and current workstream posture." },
514
+ { operation: "tasks", reason: "Inspect the branch-backed workstreams that will now sync into the Knowledge Coop UI." }
515
+ ])
516
+ }
517
+ );
342
518
  }
343
519
  function maybePrint(write, line, stream = "stdout") {
344
520
  if (!line) return;
@@ -846,13 +1022,27 @@ async function workflowConfig(helpers, input = {}) {
846
1022
  const revealSecrets = input.showSecrets === true;
847
1023
  const printEnvOnly = input.printEnvOnly === true;
848
1024
  const rotateMachineKeyFlag = input.rotateMachineKey === true;
1025
+ const connectMarketFlag = input.connectMarket === true;
1026
+ const nonInteractive = input.nonInteractive === true;
849
1027
  const repairs = input.repair === false ? [] : resolveTreeseedWorkflowState(tenantRoot).deployConfigPresent ? applyTreeseedSafeRepairs(tenantRoot) : [];
850
1028
  const toolHealth = ensureTreeseedActVerificationTooling({
851
1029
  tenantRoot,
852
- installIfMissing: true,
1030
+ installIfMissing: input.installMissingTooling === true,
853
1031
  env: helpers.context.env,
854
1032
  write: (line) => maybePrint(helpers.write, line)
855
1033
  });
1034
+ const secretSession = printEnvOnly && !revealSecrets ? {
1035
+ status: inspectTreeseedKeyAgentStatus(tenantRoot),
1036
+ createdWrappedKey: false,
1037
+ migratedWrappedKey: false,
1038
+ unlockSource: "existing-session"
1039
+ } : await ensureTreeseedSecretSessionForConfig({
1040
+ tenantRoot,
1041
+ interactive: false,
1042
+ env: helpers.context.env,
1043
+ createIfMissing: true,
1044
+ allowMigration: true
1045
+ });
856
1046
  ensureTreeseedGitignoreEntries(tenantRoot);
857
1047
  const preflight = collectCliPreflight({ cwd: tenantRoot, requireAuth: false });
858
1048
  const contextSnapshot = collectTreeseedConfigContext({
@@ -882,7 +1072,9 @@ async function workflowConfig(helpers, input = {}) {
882
1072
  reports: reports2,
883
1073
  repairs,
884
1074
  preflight,
885
- toolHealth
1075
+ toolHealth,
1076
+ context: contextSnapshot,
1077
+ secretSession
886
1078
  },
887
1079
  {
888
1080
  nextSteps: createNextSteps([
@@ -903,7 +1095,9 @@ async function workflowConfig(helpers, input = {}) {
903
1095
  keyPath: result.keyPath,
904
1096
  repairs,
905
1097
  preflight,
906
- toolHealth
1098
+ toolHealth,
1099
+ context: contextSnapshot,
1100
+ secretSession
907
1101
  },
908
1102
  {
909
1103
  nextSteps: createNextSteps([
@@ -912,12 +1106,28 @@ async function workflowConfig(helpers, input = {}) {
912
1106
  }
913
1107
  );
914
1108
  }
1109
+ if (connectMarketFlag) {
1110
+ return connectTreeseedMarketProject(helpers, tenantRoot, input, {
1111
+ scopes,
1112
+ sync,
1113
+ repairs,
1114
+ preflight,
1115
+ toolHealth
1116
+ });
1117
+ }
915
1118
  const explicitUpdates = Array.isArray(input.updates) ? input.updates.map((update) => ({
916
1119
  scope: update.scope,
917
1120
  entryId: String(update.entryId ?? ""),
918
1121
  value: typeof update.value === "string" ? update.value : "",
919
1122
  reused: update.reused === true
920
1123
  })) : null;
1124
+ if (!explicitUpdates && !nonInteractive) {
1125
+ workflowError(
1126
+ "config",
1127
+ "validation_failed",
1128
+ "Treeseed config requires interactive input or explicit updates. Re-run in a TTY, or use --non-interactive/--json from the CLI when you want resolved values applied automatically."
1129
+ );
1130
+ }
921
1131
  const autoUpdates = scopes.flatMap(
922
1132
  (scope) => contextSnapshot.entriesByScope[scope].map((entry) => ({
923
1133
  scope,
@@ -926,6 +1136,7 @@ async function workflowConfig(helpers, input = {}) {
926
1136
  reused: entry.currentValue.length > 0 || entry.suggestedValue.length > 0
927
1137
  }))
928
1138
  );
1139
+ maybePrint(helpers.write, "Saving resolved configuration values to machine config...");
929
1140
  const applyResult = applyTreeseedConfigValues({
930
1141
  tenantRoot,
931
1142
  updates: explicitUpdates ?? autoUpdates
@@ -934,6 +1145,12 @@ async function workflowConfig(helpers, input = {}) {
934
1145
  tenantRoot,
935
1146
  scopes,
936
1147
  sync,
1148
+ env: helpers.context.env,
1149
+ onProgress: (line) => maybePrint(helpers.write, line)
1150
+ });
1151
+ const refreshedContext = collectTreeseedConfigContext({
1152
+ tenantRoot,
1153
+ scopes,
937
1154
  env: helpers.context.env
938
1155
  });
939
1156
  const reports = printEnv ? scopes.map((scope) => ({
@@ -960,7 +1177,8 @@ async function workflowConfig(helpers, input = {}) {
960
1177
  repairs,
961
1178
  preflight,
962
1179
  toolHealth,
963
- context: contextSnapshot,
1180
+ secretSession,
1181
+ context: refreshedContext,
964
1182
  result: {
965
1183
  ...applyResult,
966
1184
  ...finalizeResult
@@ -1170,7 +1388,11 @@ async function workflowDev(helpers, input = {}) {
1170
1388
  if (input.port !== void 0) {
1171
1389
  args.push("--port", String(input.port));
1172
1390
  }
1173
- const env = { ...process.env, ...helpers.context.env ?? {} };
1391
+ const env = resolveTreeseedLaunchEnvironment({
1392
+ tenantRoot,
1393
+ scope: "local",
1394
+ baseEnv: { ...process.env, ...helpers.context.env ?? {} }
1395
+ });
1174
1396
  if (input.background) {
1175
1397
  const child = spawn(process.execPath, args, {
1176
1398
  cwd: tenantRoot,