@treeseed/sdk 0.13.0-rc.17 → 0.13.0-rc.18

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.
@@ -650,8 +650,8 @@ export declare function validatePortableContentData(model: string, value: unknow
650
650
  }>, "many">>;
651
651
  requiresArtifactKinds: import("zod").ZodOptional<import("zod").ZodEffects<import("zod").ZodArray<import("zod").ZodString, "many">, string[], string[]>>;
652
652
  }, "strict", import("zod").ZodTypeAny, {
653
- stage?: "closeout" | "revision" | "discovery" | "synthesis" | "deliberation" | "evaluation" | undefined;
654
653
  objective?: string | undefined;
654
+ stage?: "closeout" | "revision" | "discovery" | "synthesis" | "deliberation" | "evaluation" | undefined;
655
655
  proposalTypes?: string[] | undefined;
656
656
  artifactKind?: string | undefined;
657
657
  subjectModel?: string | undefined;
@@ -681,8 +681,8 @@ export declare function validatePortableContentData(model: string, value: unknow
681
681
  }[] | undefined;
682
682
  requiresArtifactKinds?: string[] | undefined;
683
683
  }, {
684
- stage?: "closeout" | "revision" | "discovery" | "synthesis" | "deliberation" | "evaluation" | undefined;
685
684
  objective?: string | undefined;
685
+ stage?: "closeout" | "revision" | "discovery" | "synthesis" | "deliberation" | "evaluation" | undefined;
686
686
  proposalTypes?: string[] | undefined;
687
687
  artifactKind?: string | undefined;
688
688
  subjectModel?: string | undefined;
@@ -728,8 +728,8 @@ export declare function validatePortableContentData(model: string, value: unknow
728
728
  }, "strict", import("zod").ZodTypeAny, {
729
729
  kind: "team-human" | "human-or-agent" | "specific-human" | "specific-agent";
730
730
  projectId?: string | undefined;
731
- teamId?: string | undefined;
732
731
  agentSlug?: string | undefined;
732
+ teamId?: string | undefined;
733
733
  requiredRoles?: string[] | undefined;
734
734
  allowedRoles?: string[] | undefined;
735
735
  allowedAgentIds?: string[] | undefined;
@@ -739,8 +739,8 @@ export declare function validatePortableContentData(model: string, value: unknow
739
739
  }, {
740
740
  kind: "team-human" | "human-or-agent" | "specific-human" | "specific-agent";
741
741
  projectId?: string | undefined;
742
- teamId?: string | undefined;
743
742
  agentSlug?: string | undefined;
743
+ teamId?: string | undefined;
744
744
  requiredRoles?: string[] | undefined;
745
745
  allowedRoles?: string[] | undefined;
746
746
  allowedAgentIds?: string[] | undefined;
@@ -752,8 +752,8 @@ export declare function validatePortableContentData(model: string, value: unknow
752
752
  defaultAnswerPolicy?: {
753
753
  kind: "team-human" | "human-or-agent" | "specific-human" | "specific-agent";
754
754
  projectId?: string | undefined;
755
- teamId?: string | undefined;
756
755
  agentSlug?: string | undefined;
756
+ teamId?: string | undefined;
757
757
  requiredRoles?: string[] | undefined;
758
758
  allowedRoles?: string[] | undefined;
759
759
  allowedAgentIds?: string[] | undefined;
@@ -766,8 +766,8 @@ export declare function validatePortableContentData(model: string, value: unknow
766
766
  defaultAnswerPolicy?: {
767
767
  kind: "team-human" | "human-or-agent" | "specific-human" | "specific-agent";
768
768
  projectId?: string | undefined;
769
- teamId?: string | undefined;
770
769
  agentSlug?: string | undefined;
770
+ teamId?: string | undefined;
771
771
  requiredRoles?: string[] | undefined;
772
772
  allowedRoles?: string[] | undefined;
773
773
  allowedAgentIds?: string[] | undefined;
@@ -976,8 +976,8 @@ export declare function validatePortableContentData(model: string, value: unknow
976
976
  publishes?: string[] | undefined;
977
977
  } | undefined;
978
978
  planningIntent?: {
979
- stage?: "closeout" | "revision" | "discovery" | "synthesis" | "deliberation" | "evaluation" | undefined;
980
979
  objective?: string | undefined;
980
+ stage?: "closeout" | "revision" | "discovery" | "synthesis" | "deliberation" | "evaluation" | undefined;
981
981
  proposalTypes?: string[] | undefined;
982
982
  artifactKind?: string | undefined;
983
983
  subjectModel?: string | undefined;
@@ -1011,8 +1011,8 @@ export declare function validatePortableContentData(model: string, value: unknow
1011
1011
  defaultAnswerPolicy?: {
1012
1012
  kind: "team-human" | "human-or-agent" | "specific-human" | "specific-agent";
1013
1013
  projectId?: string | undefined;
1014
- teamId?: string | undefined;
1015
1014
  agentSlug?: string | undefined;
1015
+ teamId?: string | undefined;
1016
1016
  requiredRoles?: string[] | undefined;
1017
1017
  allowedRoles?: string[] | undefined;
1018
1018
  allowedAgentIds?: string[] | undefined;
@@ -1149,8 +1149,8 @@ export declare function validatePortableContentData(model: string, value: unknow
1149
1149
  publishes?: string[] | undefined;
1150
1150
  } | undefined;
1151
1151
  planningIntent?: {
1152
- stage?: "closeout" | "revision" | "discovery" | "synthesis" | "deliberation" | "evaluation" | undefined;
1153
1152
  objective?: string | undefined;
1153
+ stage?: "closeout" | "revision" | "discovery" | "synthesis" | "deliberation" | "evaluation" | undefined;
1154
1154
  proposalTypes?: string[] | undefined;
1155
1155
  artifactKind?: string | undefined;
1156
1156
  subjectModel?: string | undefined;
@@ -1184,8 +1184,8 @@ export declare function validatePortableContentData(model: string, value: unknow
1184
1184
  defaultAnswerPolicy?: {
1185
1185
  kind: "team-human" | "human-or-agent" | "specific-human" | "specific-agent";
1186
1186
  projectId?: string | undefined;
1187
- teamId?: string | undefined;
1188
1187
  agentSlug?: string | undefined;
1188
+ teamId?: string | undefined;
1189
1189
  requiredRoles?: string[] | undefined;
1190
1190
  allowedRoles?: string[] | undefined;
1191
1191
  allowedAgentIds?: string[] | undefined;
@@ -1322,8 +1322,8 @@ export declare function validatePortableContentData(model: string, value: unknow
1322
1322
  publishes?: string[] | undefined;
1323
1323
  } | undefined;
1324
1324
  planningIntent?: {
1325
- stage?: "closeout" | "revision" | "discovery" | "synthesis" | "deliberation" | "evaluation" | undefined;
1326
1325
  objective?: string | undefined;
1326
+ stage?: "closeout" | "revision" | "discovery" | "synthesis" | "deliberation" | "evaluation" | undefined;
1327
1327
  proposalTypes?: string[] | undefined;
1328
1328
  artifactKind?: string | undefined;
1329
1329
  subjectModel?: string | undefined;
@@ -1357,8 +1357,8 @@ export declare function validatePortableContentData(model: string, value: unknow
1357
1357
  defaultAnswerPolicy?: {
1358
1358
  kind: "team-human" | "human-or-agent" | "specific-human" | "specific-agent";
1359
1359
  projectId?: string | undefined;
1360
- teamId?: string | undefined;
1361
1360
  agentSlug?: string | undefined;
1361
+ teamId?: string | undefined;
1362
1362
  requiredRoles?: string[] | undefined;
1363
1363
  allowedRoles?: string[] | undefined;
1364
1364
  allowedAgentIds?: string[] | undefined;
@@ -1495,8 +1495,8 @@ export declare function validatePortableContentData(model: string, value: unknow
1495
1495
  publishes?: string[] | undefined;
1496
1496
  } | undefined;
1497
1497
  planningIntent?: {
1498
- stage?: "closeout" | "revision" | "discovery" | "synthesis" | "deliberation" | "evaluation" | undefined;
1499
1498
  objective?: string | undefined;
1499
+ stage?: "closeout" | "revision" | "discovery" | "synthesis" | "deliberation" | "evaluation" | undefined;
1500
1500
  proposalTypes?: string[] | undefined;
1501
1501
  artifactKind?: string | undefined;
1502
1502
  subjectModel?: string | undefined;
@@ -1530,8 +1530,8 @@ export declare function validatePortableContentData(model: string, value: unknow
1530
1530
  defaultAnswerPolicy?: {
1531
1531
  kind: "team-human" | "human-or-agent" | "specific-human" | "specific-agent";
1532
1532
  projectId?: string | undefined;
1533
- teamId?: string | undefined;
1534
1533
  agentSlug?: string | undefined;
1534
+ teamId?: string | undefined;
1535
1535
  requiredRoles?: string[] | undefined;
1536
1536
  allowedRoles?: string[] | undefined;
1537
1537
  allowedAgentIds?: string[] | undefined;
@@ -1568,10 +1568,10 @@ export declare function validatePortableContentData(model: string, value: unknow
1568
1568
  model: string;
1569
1569
  priority: number;
1570
1570
  status?: string | undefined;
1571
+ reason?: string | undefined;
1571
1572
  title?: string | undefined;
1572
1573
  slug?: string | undefined;
1573
1574
  estimatedCredits?: number | undefined;
1574
- reason?: string | undefined;
1575
1575
  }[];
1576
1576
  totalTasks: number;
1577
1577
  completedTasks: number;
@@ -1709,9 +1709,9 @@ export declare function validatePortableContentData(model: string, value: unknow
1709
1709
  id: string;
1710
1710
  required: boolean;
1711
1711
  description: string;
1712
+ query: string;
1712
1713
  title: string;
1713
1714
  revision: number;
1714
- query: string;
1715
1715
  filters: Record<string, unknown>;
1716
1716
  target: {
1717
1717
  kind: "code" | "content" | "mixed" | "graph";
@@ -1763,15 +1763,15 @@ export declare function validatePortableContentData(model: string, value: unknow
1763
1763
  id: string;
1764
1764
  status: "active" | "completed" | "ready" | "superseded" | "draft";
1765
1765
  projectId: string;
1766
+ teamId: string;
1767
+ objective: string;
1766
1768
  completed: {
1767
1769
  id: string;
1768
1770
  description: string;
1769
1771
  title: string;
1770
1772
  }[];
1771
- teamId: string;
1772
1773
  title: string;
1773
1774
  revision: number;
1774
- objective: string;
1775
1775
  createdAt: Date;
1776
1776
  remaining: {
1777
1777
  id: string;
@@ -1804,10 +1804,10 @@ export declare function validatePortableContentData(model: string, value: unknow
1804
1804
  sequence: number;
1805
1805
  phase: string;
1806
1806
  description?: string | undefined;
1807
+ reason?: string | undefined;
1807
1808
  assignmentId?: string | undefined;
1808
1809
  updatedAt?: Date | undefined;
1809
1810
  workdayId?: string | undefined;
1810
- reason?: string | undefined;
1811
1811
  previousStatusRef?: {
1812
1812
  id: string;
1813
1813
  revision: number;
@@ -1,5 +1,6 @@
1
1
  import type { ControlPlaneOperationBinding, ControlPlaneOperationBody, ControlPlaneOperationOutput, ControlPlaneOperationPath, ControlPlaneOperationQuery, OAuthScope } from '../../operator-contracts/control-plane-operation.js';
2
2
  import type { ApiPrincipal } from '../../operator-contracts/oauth.js';
3
+ import type { InputRequired } from '../../operator-contracts/mcp.js';
3
4
  export declare const DEFAULT_CONTROL_PLANE_BASE_URL = "http://127.0.0.1:3002";
4
5
  export declare const CONTROL_PLANE_BASE_URL_ENV = "TREESEED_API_BASE_URL";
5
6
  export interface ControlPlaneServerProfile {
@@ -58,6 +59,7 @@ export interface ProblemDetails {
58
59
  requestId?: string;
59
60
  traceId?: string;
60
61
  fields?: Record<string, string[]>;
62
+ inputRequired?: InputRequired;
61
63
  }
62
64
  export interface ControlPlaneCallOptions {
63
65
  method?: 'DELETE' | 'GET' | 'PATCH' | 'POST' | 'PUT';
@@ -67,7 +67,8 @@ function problemFrom(payload, status) {
67
67
  code: typeof source.code === "string" ? source.code : "control_plane_request_failed",
68
68
  requestId: typeof source.requestId === "string" ? source.requestId : void 0,
69
69
  traceId: typeof source.traceId === "string" ? source.traceId : void 0,
70
- fields: source.fields && typeof source.fields === "object" ? source.fields : void 0
70
+ fields: source.fields && typeof source.fields === "object" ? source.fields : void 0,
71
+ inputRequired: source.inputRequired && typeof source.inputRequired === "object" ? source.inputRequired : void 0
71
72
  };
72
73
  }
73
74
  class ControlPlaneClient {
@@ -132,7 +133,12 @@ class ControlPlaneClient {
132
133
  async exchangeOAuthToken(values, signal) {
133
134
  const response = await this.fetchImpl(`${this.baseUrl}/oauth/token`, { method: "POST", headers: { accept: "application/json", "content-type": "application/x-www-form-urlencoded" }, body: new URLSearchParams(values), signal });
134
135
  const payload = await responsePayload(response);
135
- if (!response.ok) throw new ControlPlaneClientError(String(payload.error_description ?? payload.error ?? "OAuth token exchange failed."), response.status, problemFrom(payload, response.status), response.headers);
136
+ if (!response.ok) {
137
+ const problem = problemFrom(payload, response.status);
138
+ problem.code = typeof payload.error === "string" ? payload.error : problem.code;
139
+ problem.detail = typeof payload.error_description === "string" ? payload.error_description : problem.detail;
140
+ throw new ControlPlaneClientError(problem.detail ?? problem.code, response.status, problem, response.headers);
141
+ }
136
142
  return { tokenType: "Bearer", accessToken: String(payload.access_token), refreshToken: typeof payload.refresh_token === "string" ? payload.refresh_token : void 0, expiresIn: Number(payload.expires_in), scope: String(payload.scope ?? "").split(/\s+/u).filter(Boolean), audience: String(payload.audience ?? this.baseUrl), principal: payload.principal && typeof payload.principal === "object" ? payload.principal : void 0 };
137
143
  }
138
144
  async request(options) {
@@ -1,3 +1,53 @@
1
+ const unavailable = (reason = "This capability is not enabled until its control-plane operation is accepted.") => ({
2
+ kind: "unavailable",
3
+ code: "standards_migration_not_enabled",
4
+ reason
5
+ });
6
+ const protocol = (handlerId) => ({ kind: "protocol", handlerId });
7
+ const local = (handlerId) => ({ kind: "local", handlerId });
8
+ const field = (target, name, source, sourceName = name, required = false, transform = "identity") => ({ target, field: name, source, name: sourceName, required, transform });
9
+ const operation = (operationId, input = []) => ({ kind: "operation", operationId, input });
10
+ const page = () => [field("query", "status", "option"), field("query", "limit", "option", "limit", false, "integer"), field("query", "cursor", "option")];
11
+ const operationBindings = {
12
+ "auth login": protocol("protocol.oauth.device.login"),
13
+ "auth logout": protocol("protocol.oauth.revoke"),
14
+ "auth status": operation("accounts.current.show"),
15
+ "secrets list": local("local.secrets.list"),
16
+ "secrets status": local("local.secrets.status"),
17
+ "secrets unlock": local("local.secrets.unlock"),
18
+ "secrets lock": local("local.secrets.lock"),
19
+ "secrets rotate": local("local.secrets.rotate"),
20
+ "agents list": operation("agents.list", [field("path", "projectId", "context", "project", true), ...page()]),
21
+ "agents show": operation("agents.show", [field("path", "projectId", "context", "project", true), field("path", "agentSlug", "argument", "agent", true)]),
22
+ "agents classes list": operation("agents.classes.list", [field("path", "projectId", "context", "project", true)]),
23
+ "agents classes show": operation("agents.classes.show", [field("path", "projectId", "context", "project", true), field("path", "classId", "argument", "class", true)]),
24
+ "providers list": operation("services.providers.list", page()),
25
+ "providers show": operation("services.connections.show", [field("path", "teamId", "context", "team", true), field("path", "connectionId", "argument", "provider", true)]),
26
+ "providers status": operation("services.connections.show", [field("path", "teamId", "context", "team", true), field("path", "connectionId", "argument", "provider", true)]),
27
+ "providers connect": operation("services.connections.create", [field("path", "teamId", "context", "team", true), field("body", "providerId", "option", "provider", true)]),
28
+ "providers disconnect": operation("services.connections.disconnect", [field("path", "teamId", "context", "team", true), field("path", "connectionId", "argument", "connection", true), field("body", "reason", "option")]),
29
+ "providers credentials status": operation("services.credential.authorities.list", [field("path", "teamId", "context", "team", true), field("path", "connectionId", "argument", "connection", true)]),
30
+ "capacity status": operation("capacity.status", [field("path", "teamId", "context", "team", true), ...page()]),
31
+ "capacity usage": operation("capacity.usage", [field("path", "teamId", "context", "team", true)]),
32
+ "capacity ledger": operation("capacity.ledger", [field("path", "teamId", "context", "team", true), ...page()]),
33
+ "plans list": operation("plans.list", [field("path", "decisionId", "option", "decision", true), ...page()]),
34
+ "plans show": operation("plans.show", [field("path", "capacityPlanId", "argument", "plan", true)]),
35
+ "workdays plan": operation("workdays.plan", [field("path", "teamId", "context", "team", true), field("body", "profile", "option"), field("body", "projects", "option", "projects", false, "csv"), field("body", "start", "option"), field("body", "end", "option"), field("body", "duration", "option", "duration", false, "integer"), field("body", "objective", "option")]),
36
+ "workdays start": operation("workdays.start", [field("path", "teamId", "context", "team", true), field("body", "preflightId", "option", "preflight", true), field("body", "digest", "option", "digest", true)]),
37
+ "workdays list": operation("workdays.list", [field("path", "teamId", "context", "team", true), ...page()]),
38
+ "workdays show": operation("workdays.show", [field("path", "teamId", "context", "team", true), field("path", "runId", "argument", "workday", true)]),
39
+ "workdays schedules list": operation("workdays.schedules.list", [field("path", "teamId", "context", "team", true)]),
40
+ "workdays schedules start": operation("workdays.schedules.create", [field("path", "teamId", "context", "team", true), field("body", "profile", "option"), field("body", "projects", "option", "projects", false, "csv"), field("body", "duration", "option", "duration", false, "integer")]),
41
+ "assignments list": operation("assignments.list", [field("path", "teamId", "context", "team", true), ...page()]),
42
+ "assignments show": operation("assignments.show", [field("path", "teamId", "context", "team", true), field("path", "assignmentId", "argument", "assignment", true)]),
43
+ "assignments explain": operation("assignments.explain", [field("path", "teamId", "context", "team", true), field("path", "assignmentId", "argument", "assignment", true)]),
44
+ "assignments retry": operation("assignments.retry", [field("path", "teamId", "context", "team", true), field("path", "assignmentId", "argument", "assignment", true), field("body", "reason", "option")]),
45
+ "assignments cancel": operation("assignments.cancel", [field("path", "teamId", "context", "team", true), field("path", "assignmentId", "argument", "assignment", true), field("body", "reason", "option")]),
46
+ "status": operation("status.show"),
47
+ "save": unavailable("Unified GitHub-backed save is intentionally fail-closed during this cutover."),
48
+ "stage": unavailable("Unified GitHub-backed stage is intentionally fail-closed during this cutover."),
49
+ "release": unavailable("Production release is intentionally fail-closed during this cutover.")
50
+ };
1
51
  const planOption = { name: "--plan", description: "Return the exact proposed outcome without mutation.", type: "boolean" };
2
52
  function leaf(segment, kind = "read", argument, confirmation = "never") {
3
53
  const value = {
@@ -7,14 +57,15 @@ function leaf(segment, kind = "read", argument, confirmation = "never") {
7
57
  arguments: argument ? [{ name: argument, description: `${argument} identity or path.`, required: true }] : void 0,
8
58
  options: kind === "mutation" ? [planOption] : void 0,
9
59
  authorization: kind === "mutation" ? { capability: `command.${segment}`, confirmation } : void 0,
10
- resultSchemaId: `treeseed.command.${segment}/v1`
60
+ resultSchemaId: `treeseed.command.${segment}/v1`,
61
+ execution: unavailable()
11
62
  };
12
63
  return { nodeType: "leaf", ...value };
13
64
  }
14
65
  function branch(segment, children) {
15
66
  return { nodeType: "branch", segment, description: `${segment[0].toUpperCase()}${segment.slice(1)} operations.`, children };
16
67
  }
17
- const TREESEED_COMMAND_TREE_V1 = {
68
+ const commandTree = {
18
69
  schemaVersion: "treeseed.command-tree/v1",
19
70
  executable: "trsd",
20
71
  commands: [
@@ -41,10 +92,10 @@ const TREESEED_COMMAND_TREE_V1 = {
41
92
  branch("offers", [leaf("show", "read", "connection"), leaf("validate", "read", "file"), leaf("plan", "read", "file"), leaf("apply", "mutation", "file", "authority")])
42
93
  ]),
43
94
  branch("capacity", [leaf("status"), leaf("explain"), leaf("usage"), leaf("ledger"), leaf("audit")]),
44
- branch("plans", [leaf("list"), leaf("show", "read", "plan"), leaf("explain", "read", "plan"), { nodeType: "leaf", segment: "diff", description: "Compare two API-derived plans.", kind: "read", arguments: [{ name: "left", description: "Left plan identity.", required: true }, { name: "right", description: "Right plan identity.", required: true }], resultSchemaId: "treeseed.command.plans.diff/v1" }]),
95
+ branch("plans", [leaf("list"), leaf("show", "read", "plan"), leaf("explain", "read", "plan"), { nodeType: "leaf", segment: "diff", description: "Compare two API-derived plans.", kind: "read", arguments: [{ name: "left", description: "Left plan identity.", required: true }, { name: "right", description: "Right plan identity.", required: true }], resultSchemaId: "treeseed.command.plans.diff/v1", execution: unavailable() }]),
45
96
  branch("workdays", [
46
97
  branch("profiles", [leaf("list"), leaf("show", "read", "profile"), leaf("validate", "read", "file")]),
47
- leaf("plan"),
98
+ leaf("plan", "mutation"),
48
99
  leaf("start", "mutation", void 0, "authority"),
49
100
  leaf("list"),
50
101
  leaf("show", "read", "workday"),
@@ -63,6 +114,15 @@ const TREESEED_COMMAND_TREE_V1 = {
63
114
  leaf("diagnose")
64
115
  ]
65
116
  };
117
+ function attachExecution(nodes, parent = []) {
118
+ for (const node of nodes) {
119
+ const path = [...parent, node.segment];
120
+ if (node.nodeType === "branch") attachExecution(node.children, path);
121
+ else node.execution = operationBindings[path.join(" ")] ?? node.execution;
122
+ }
123
+ }
124
+ attachExecution(commandTree.commands);
125
+ const TREESEED_COMMAND_TREE_V1 = commandTree;
66
126
  function listCommandPaths(tree = TREESEED_COMMAND_TREE_V1) {
67
127
  const paths = [];
68
128
  const visit = (nodes, parent) => {
@@ -1,3 +1,4 @@
1
+ import type { ControlPlaneOperationBinding } from './control-plane-operation.js';
1
2
  export type CommandOperationKind = 'read' | 'mutation';
2
3
  export type CommandExecutionMode = 'execute' | 'plan';
3
4
  export type CommandErrorCategory = 'unknown_command' | 'invalid_input' | 'ambiguous_context' | 'authentication_required' | 'authorization_denied' | 'confirmation_required' | 'policy_blocked' | 'stale_preflight' | 'conflict' | 'not_found' | 'provider_unavailable' | 'rate_limited' | 'internal_error';
@@ -19,6 +20,31 @@ export interface CommandAuthorizationDescriptor {
19
20
  capability: string;
20
21
  confirmation: 'never' | 'destructive' | 'credential' | 'authority' | 'production' | 'irreversible';
21
22
  }
23
+ export type CommandInputSource = 'argument' | 'context' | 'option';
24
+ export type CommandInputTarget = 'path' | 'query' | 'body';
25
+ export interface CommandInputBinding {
26
+ field: string;
27
+ source: CommandInputSource;
28
+ name: string;
29
+ target: CommandInputTarget;
30
+ required?: boolean;
31
+ transform?: 'identity' | 'integer' | 'csv';
32
+ }
33
+ export type CommandExecutionBinding = {
34
+ kind: 'operation';
35
+ operationId: `${string}.${string}`;
36
+ input: CommandInputBinding[];
37
+ } | {
38
+ kind: 'protocol';
39
+ handlerId: `protocol.${string}`;
40
+ } | {
41
+ kind: 'local';
42
+ handlerId: `local.${string}`;
43
+ } | {
44
+ kind: 'unavailable';
45
+ code: string;
46
+ reason: string;
47
+ };
22
48
  export interface CommandLeafDescriptor {
23
49
  segment: string;
24
50
  description: string;
@@ -27,6 +53,7 @@ export interface CommandLeafDescriptor {
27
53
  options?: CommandOptionDescriptor[];
28
54
  authorization?: CommandAuthorizationDescriptor;
29
55
  resultSchemaId: string;
56
+ execution: CommandExecutionBinding;
30
57
  }
31
58
  export interface CommandBranchDescriptor {
32
59
  segment: string;
@@ -76,4 +103,5 @@ export interface CommandTreeDiagnostic {
76
103
  message: string;
77
104
  }
78
105
  export declare function validateCommandTree(tree: CommandTreeDescriptor): CommandTreeDiagnostic[];
106
+ export declare function validateCommandOperationBindings(tree: CommandTreeDescriptor, operations: readonly ControlPlaneOperationBinding<any, any, any, any>[]): CommandTreeDiagnostic[];
79
107
  export declare function createCommandResult<TResult>(input: Omit<CommandResultEnvelope<TResult>, 'schemaVersion'>): CommandResultEnvelope<TResult>;
@@ -1,3 +1,4 @@
1
+ import { ZodUndefined } from "zod";
1
2
  const SEGMENT = /^[a-z][a-z0-9]*$/;
2
3
  const FORBIDDEN_AGENT_MANAGEMENT_OPTIONS = /* @__PURE__ */ new Set([
3
4
  "--commit",
@@ -31,6 +32,17 @@ function validateCommandTree(tree) {
31
32
  }
32
33
  if ("children" in raw) diagnostics.push({ code: "command_node_ambiguous", path: diagnosticPath, message: "Leaf command nodes cannot contain child commands." });
33
34
  if (!node.resultSchemaId.trim()) diagnostics.push({ code: "result_schema_required", path: `${diagnosticPath}.resultSchemaId`, message: "Leaf commands require a stable result schema." });
35
+ if (!node.execution) diagnostics.push({ code: "command_execution_required", path: `${diagnosticPath}.execution`, message: "Every leaf must declare one authoritative execution binding." });
36
+ if (node.execution?.kind === "operation") {
37
+ const targets = /* @__PURE__ */ new Set();
38
+ for (const binding of node.execution.input) {
39
+ const key = `${binding.target}.${binding.field}`;
40
+ if (targets.has(key)) diagnostics.push({ code: "command_input_target_duplicate", path: `${diagnosticPath}.execution.input`, message: `Duplicate command input target ${key}.` });
41
+ targets.add(key);
42
+ if (!binding.field.trim() || !binding.name.trim()) diagnostics.push({ code: "command_input_binding_invalid", path: `${diagnosticPath}.execution.input`, message: "Command input bindings require field and source names." });
43
+ }
44
+ }
45
+ if (node.execution?.kind === "unavailable" && (!node.execution.code.trim() || !node.execution.reason.trim())) diagnostics.push({ code: "command_unavailable_reason_required", path: `${diagnosticPath}.execution`, message: "Unavailable commands require a stable code and explanation." });
34
46
  const optionNames = /* @__PURE__ */ new Set();
35
47
  for (const option of node.options ?? []) {
36
48
  if (optionNames.has(option.name)) diagnostics.push({ code: "command_option_duplicate", path: `${diagnosticPath}.options.${index}`, message: `Duplicate option ${option.name}.` });
@@ -44,10 +56,47 @@ function validateCommandTree(tree) {
44
56
  visit(tree.commands, []);
45
57
  return diagnostics;
46
58
  }
59
+ function validateCommandOperationBindings(tree, operations) {
60
+ const diagnostics = [];
61
+ const catalog = new Map(operations.map((operation) => [operation.descriptor.operationId, operation]));
62
+ const visit = (nodes, parent) => {
63
+ for (const node of nodes) {
64
+ const path = [...parent, node.segment];
65
+ if (node.nodeType === "branch") {
66
+ visit(node.children, path);
67
+ continue;
68
+ }
69
+ if (node.execution.kind !== "operation") continue;
70
+ const binding = catalog.get(node.execution.operationId);
71
+ const diagnosticPath = `commands.${path.join(".")}.execution`;
72
+ if (!binding) {
73
+ diagnostics.push({ code: "command_operation_unknown", path: diagnosticPath, message: `Unknown control-plane operation ${node.execution.operationId}.` });
74
+ continue;
75
+ }
76
+ if (!binding.descriptor.surfaces.includes("cli")) diagnostics.push({ code: "command_operation_surface_missing", path: diagnosticPath, message: `Operation ${node.execution.operationId} does not declare the CLI surface.` });
77
+ if (binding.descriptor.kind !== node.kind) diagnostics.push({ code: "command_operation_kind_mismatch", path: diagnosticPath, message: `Command and operation ${node.execution.operationId} disagree about mutation behavior.` });
78
+ const expectedConfirmation = binding.descriptor.confirmation === "input_required" ? binding.descriptor.riskClass : "never";
79
+ if ((node.authorization?.confirmation ?? "never") !== expectedConfirmation) diagnostics.push({ code: "command_operation_confirmation_mismatch", path: diagnosticPath, message: `Command and operation ${node.execution.operationId} disagree about confirmation.` });
80
+ const shapes = {
81
+ path: "shape" in binding.schema.path ? Object.keys(binding.schema.path.shape) : null,
82
+ query: "shape" in binding.schema.query ? Object.keys(binding.schema.query.shape) : null,
83
+ body: "shape" in binding.schema.body ? Object.keys(binding.schema.body.shape) : null
84
+ };
85
+ for (const input of node.execution.input) {
86
+ const keys = shapes[input.target];
87
+ const undefinedSchema = binding.schema[input.target] instanceof ZodUndefined;
88
+ if (keys !== null && !keys.includes(input.field) || undefinedSchema) diagnostics.push({ code: "command_operation_input_unknown", path: `${diagnosticPath}.input.${input.target}.${input.field}`, message: `Operation ${node.execution.operationId} does not accept ${input.target} field ${input.field}.` });
89
+ }
90
+ }
91
+ };
92
+ visit(tree.commands, []);
93
+ return diagnostics.sort((left, right) => `${left.path}:${left.code}`.localeCompare(`${right.path}:${right.code}`));
94
+ }
47
95
  function createCommandResult(input) {
48
96
  return { schemaVersion: "treeseed.command-result/v1", ...input };
49
97
  }
50
98
  export {
51
99
  createCommandResult,
100
+ validateCommandOperationBindings,
52
101
  validateCommandTree
53
102
  };
@@ -10,8 +10,8 @@ export declare const CONTROL_PLANE_OPERATIONS: {
10
10
  readonly projects: {
11
11
  readonly list: ControlPlaneOperationBinding<{}, {
12
12
  cursor?: string | undefined;
13
- teamId?: string | undefined;
14
13
  limit?: number | undefined;
14
+ teamId?: string | undefined;
15
15
  }, undefined, Record<string, unknown>>;
16
16
  readonly show: ControlPlaneOperationBinding<{
17
17
  projectId: string;
@@ -413,8 +413,8 @@ export declare const CONTROL_PLANE_OPERATIONS: {
413
413
  }, {}, Record<string, unknown> | undefined, Record<string, unknown>>;
414
414
  readonly putAuthority: ControlPlaneOperationBinding<{
415
415
  teamId: string;
416
- profileId: string;
417
416
  connectionId: string;
417
+ profileId: string;
418
418
  }, {}, Record<string, unknown> | undefined, Record<string, unknown>>;
419
419
  };
420
420
  readonly agents: {
@@ -274,7 +274,7 @@ const CONTROL_PLANE_OPERATIONS = {
274
274
  providers: resource("services.providers.list", "GET", "/v1/service-providers", {}, { capability: "services.read", surfaces: ["rest", "cli", "mcp_tool"] }),
275
275
  connections: resource("services.connections.list", "GET", "/v1/teams/{teamId}/services", { teamId: z.string().min(1) }, { capability: "services.read", surfaces: ["rest", "cli", "mcp_tool"], pagination: "cursor" }),
276
276
  connection: resource("services.connections.show", "GET", "/v1/teams/{teamId}/services/{connectionId}", { teamId: z.string().min(1), connectionId: z.string().min(1) }, { capability: "services.read", surfaces: ["rest", "cli", "mcp_resource"] }),
277
- createConnection: resource("services.connections.create", "POST", "/v1/teams/{teamId}/services", { teamId: z.string().min(1) }, { capability: "services.write", surfaces: ["rest", "cli", "mcp_tool"] }),
277
+ createConnection: resource("services.connections.create", "POST", "/v1/teams/{teamId}/services", { teamId: z.string().min(1) }, { capability: "services.write", surfaces: ["rest", "cli", "mcp_tool"], risk: "credential" }),
278
278
  updateConnection: resource("services.connections.update", "PUT", "/v1/teams/{teamId}/services/{connectionId}", { teamId: z.string().min(1), connectionId: z.string().min(1) }, { capability: "services.write", surfaces: ["rest", "cli", "mcp_tool"], concurrency: true }),
279
279
  disconnect: resource("services.connections.disconnect", "DELETE", "/v1/teams/{teamId}/services/{connectionId}", { teamId: z.string().min(1), connectionId: z.string().min(1) }, { capability: "services.write", surfaces: ["rest", "cli", "mcp_tool"], risk: "destructive", concurrency: true }),
280
280
  authorities: resource("services.credential.authorities.list", "GET", "/v1/teams/{teamId}/services/{connectionId}/credential-authorities", { teamId: z.string().min(1), connectionId: z.string().min(1) }, { capability: "secrets.read", surfaces: ["rest", "cli"], pagination: "cursor" }),
@@ -310,11 +310,11 @@ const CONTROL_PLANE_OPERATIONS = {
310
310
  workdays: {
311
311
  list: resource("workdays.list", "GET", "/v1/teams/{teamId}/workday-runs", { teamId: z.string().min(1) }, { capability: "workdays.read", surfaces: ["rest", "cli", "mcp_tool"], pagination: "cursor" }),
312
312
  preflight: resource("workdays.plan", "POST", "/v1/teams/{teamId}/workday-runs/preflight", { teamId: z.string().min(1) }, { capability: "workdays.execute", scopes: ["treeseed:execution"], surfaces: ["rest", "cli", "mcp_tool"] }),
313
- start: resource("workdays.start", "POST", "/v1/teams/{teamId}/workday-runs", { teamId: z.string().min(1) }, { capability: "workdays.execute", scopes: ["treeseed:execution"], surfaces: ["rest", "cli", "mcp_tool"] }),
313
+ start: resource("workdays.start", "POST", "/v1/teams/{teamId}/workday-runs", { teamId: z.string().min(1) }, { capability: "workdays.execute", scopes: ["treeseed:execution"], surfaces: ["rest", "cli", "mcp_tool"], risk: "authority" }),
314
314
  show: resource("workdays.show", "GET", "/v1/teams/{teamId}/workday-runs/{runId}", { teamId: z.string().min(1), runId: z.string().min(1) }, { capability: "workdays.read", surfaces: ["rest", "cli", "mcp_resource"] }),
315
315
  events: resource("workdays.events.list", "GET", "/v1/teams/{teamId}/workday-runs/{runId}/events", { teamId: z.string().min(1), runId: z.string().min(1) }, { capability: "workdays.read", pagination: "cursor" }),
316
316
  schedules: resource("workdays.schedules.list", "GET", "/v1/teams/{teamId}/workday-schedules", { teamId: z.string().min(1) }, { capability: "workdays.read", surfaces: ["rest", "cli"], pagination: "cursor" }),
317
- createSchedule: resource("workdays.schedules.create", "POST", "/v1/teams/{teamId}/workday-schedules", { teamId: z.string().min(1) }, { capability: "workdays.execute", scopes: ["treeseed:execution"], surfaces: ["rest", "cli"] }),
317
+ createSchedule: resource("workdays.schedules.create", "POST", "/v1/teams/{teamId}/workday-schedules", { teamId: z.string().min(1) }, { capability: "workdays.execute", scopes: ["treeseed:execution"], surfaces: ["rest", "cli"], risk: "authority" }),
318
318
  updateSchedule: resource("workdays.schedules.update", "PATCH", "/v1/teams/{teamId}/workday-schedules/{scheduleId}", { teamId: z.string().min(1), scheduleId: z.string().min(1) }, { capability: "workdays.execute", scopes: ["treeseed:execution"], surfaces: ["rest", "cli"], concurrency: true })
319
319
  },
320
320
  assignments: {
@@ -322,7 +322,7 @@ const CONTROL_PLANE_OPERATIONS = {
322
322
  show: resource("assignments.show", "GET", "/v1/teams/{teamId}/capacity/assignments/{assignmentId}", { teamId: z.string().min(1), assignmentId: z.string().min(1) }, { capability: "assignments.read", surfaces: ["rest", "cli", "mcp_resource"] }),
323
323
  explain: resource("assignments.explain", "GET", "/v1/teams/{teamId}/capacity/assignments/{assignmentId}/explanation", { teamId: z.string().min(1), assignmentId: z.string().min(1) }, { capability: "assignments.read", surfaces: ["rest", "cli", "mcp_tool"] }),
324
324
  cancel: resource("assignments.cancel", "POST", "/v1/teams/{teamId}/capacity/assignments/{assignmentId}/cancel", { teamId: z.string().min(1), assignmentId: z.string().min(1) }, { capability: "assignments.execute", scopes: ["treeseed:execution"], surfaces: ["rest", "cli", "mcp_tool"], risk: "destructive" }),
325
- retry: resource("assignments.retry", "POST", "/v1/teams/{teamId}/capacity/assignments/{assignmentId}/requeue", { teamId: z.string().min(1), assignmentId: z.string().min(1) }, { capability: "assignments.execute", scopes: ["treeseed:execution"], surfaces: ["rest", "cli", "mcp_tool"] })
325
+ retry: resource("assignments.retry", "POST", "/v1/teams/{teamId}/capacity/assignments/{assignmentId}/requeue", { teamId: z.string().min(1), assignmentId: z.string().min(1) }, { capability: "assignments.execute", scopes: ["treeseed:execution"], surfaces: ["rest", "cli", "mcp_tool"], risk: "authority" })
326
326
  },
327
327
  operations: {
328
328
  list: resource("operations.list", "GET", "/v1/platform/operations", {}, { capability: "operations.read", surfaces: ["rest", "mcp_tool"], pagination: "cursor" }),
@@ -34,6 +34,7 @@ export interface InputRequired {
34
34
  prompt: string;
35
35
  confirmation: ConfirmationState;
36
36
  }
37
+ export declare function encodeConfirmationState(state: ConfirmationState): string;
37
38
  export interface McpToolDescriptor {
38
39
  name: string;
39
40
  description: string;
@@ -1,4 +1,10 @@
1
1
  const MCP_PROTOCOL_VERSION = "2026-07-28";
2
+ function encodeConfirmationState(state) {
3
+ const bytes = new TextEncoder().encode(JSON.stringify(state));
4
+ let binary = "";
5
+ for (const byte of bytes) binary += String.fromCharCode(byte);
6
+ return btoa(binary).replace(/\+/gu, "-").replace(/\//gu, "_").replace(/=+$/gu, "");
7
+ }
2
8
  const TREESEED_MCP_PROMPTS = [
3
9
  { name: "operate", description: "Operate TreeSeed through currently discoverable capabilities.", argumentSchemaId: "treeseed.prompt.objective/v1", requiredScopes: ["treeseed:read"] },
4
10
  { name: "research", description: "Research a governed TreeSeed question and accumulate knowledge.", argumentSchemaId: "treeseed.prompt.objective/v1", requiredScopes: ["treeseed:read"] },
@@ -72,6 +78,7 @@ export {
72
78
  buildMcpCatalog,
73
79
  buildMcpResources,
74
80
  buildMcpTools,
81
+ encodeConfirmationState,
75
82
  operationToMcpResource,
76
83
  operationToMcpTool
77
84
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@treeseed/sdk",
3
- "version": "0.13.0-rc.17",
3
+ "version": "0.13.0-rc.18",
4
4
  "description": "Portable TreeSeed contracts, standards, and typed remote control-plane clients.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {