@treeseed/sdk 0.8.10 → 0.8.11

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.
package/dist/d1-store.js CHANGED
@@ -120,6 +120,9 @@ class MemoryAgentDatabase {
120
120
  if (model === "task") {
121
121
  return [...this.tasks.values()];
122
122
  }
123
+ if (model === "task_output") {
124
+ return [...this.taskOutputs.values()].flat();
125
+ }
123
126
  if (model === "graph_run") {
124
127
  return [...this.graphRuns.values()];
125
128
  }
@@ -160,6 +163,9 @@ class MemoryAgentDatabase {
160
163
  if (request.model === "task") {
161
164
  return this.tasks.get(key) ?? null;
162
165
  }
166
+ if (request.model === "task_output") {
167
+ return [...this.taskOutputs.values()].flat().find((output) => output.id === key) ?? null;
168
+ }
163
169
  if (request.model === "graph_run") {
164
170
  return this.graphRuns.get(key) ?? null;
165
171
  }
@@ -52,8 +52,10 @@ class GitRuntime {
52
52
  try {
53
53
  await execFileAsync("git", ["commit", "-m", commitMessage], { cwd: worktreePath });
54
54
  } catch (error) {
55
- const message = error && typeof error === "object" && "stderr" in error ? String(error.stderr ?? "") : "";
56
- if (!message.includes("nothing to commit")) {
55
+ const stderr = error && typeof error === "object" && "stderr" in error ? String(error.stderr ?? "") : "";
56
+ const stdout2 = error && typeof error === "object" && "stdout" in error ? String(error.stdout ?? "") : "";
57
+ if (!`${stdout2}
58
+ ${stderr}`.includes("nothing to commit")) {
57
59
  throw error;
58
60
  }
59
61
  }
@@ -0,0 +1,48 @@
1
+ import type { SdkContextPack, SdkContextPackRequest, SdkGraphQueryStage, SdkGraphQueryView } from '../sdk-types.ts';
2
+ export type DeclarativeContextQueryPurpose = 'plan' | 'research' | 'generate' | 'optimize' | 'implement' | 'review' | 'release' | string;
3
+ export type DeclarativeContextQueryFormat = 'summary' | 'full' | 'sources' | 'list' | 'brief' | 'map' | string;
4
+ export interface DeclarativeContextQuery {
5
+ id: string;
6
+ purpose: DeclarativeContextQueryPurpose;
7
+ query: string;
8
+ scope?: string;
9
+ relations?: string[];
10
+ depth?: number;
11
+ budget?: number;
12
+ format?: DeclarativeContextQueryFormat;
13
+ filters?: Record<string, unknown>;
14
+ required?: boolean;
15
+ }
16
+ export type HandlerContextPackSource = 'agent_spec' | 'content_frontmatter' | 'work_package' | 'task_payload' | 'default_role_context';
17
+ export interface DeclarativeContextQuerySourceRef {
18
+ source: HandlerContextPackSource;
19
+ ref?: string;
20
+ priority: number;
21
+ }
22
+ export interface CompiledDeclarativeContextQuery {
23
+ query: DeclarativeContextQuery;
24
+ request: SdkContextPackRequest;
25
+ warnings: string[];
26
+ }
27
+ export interface DeclarativeContextQueryCompileResult {
28
+ ok: boolean;
29
+ compiled: CompiledDeclarativeContextQuery | null;
30
+ errors: string[];
31
+ warnings: string[];
32
+ }
33
+ export interface ResolvedHandlerContextPack {
34
+ id: string;
35
+ purpose: string;
36
+ source: HandlerContextPackSource;
37
+ sourceRef?: string;
38
+ query: DeclarativeContextQuery;
39
+ request: SdkContextPackRequest;
40
+ pack: SdkContextPack;
41
+ warnings: string[];
42
+ }
43
+ export declare function declarativeContextPurposeToGraphStage(purpose: string): SdkGraphQueryStage;
44
+ export declare function declarativeContextFormatToGraphView(format: string | undefined): SdkGraphQueryView;
45
+ export declare function compileDeclarativeContextQuery(query: DeclarativeContextQuery, options?: {
46
+ defaultLimit?: number;
47
+ maxDepth?: number;
48
+ }): DeclarativeContextQueryCompileResult;
@@ -0,0 +1,126 @@
1
+ const VALID_RELATIONS = [
2
+ "related",
3
+ "depends_on",
4
+ "implements",
5
+ "references",
6
+ "parent",
7
+ "child",
8
+ "supersedes"
9
+ ];
10
+ const PURPOSE_TO_STAGE = {
11
+ plan: "plan",
12
+ research: "research",
13
+ implement: "implement",
14
+ debug: "debug",
15
+ review: "review"
16
+ };
17
+ const FORMAT_TO_VIEW = {
18
+ summary: "brief",
19
+ brief: "brief",
20
+ full: "full",
21
+ sources: "list",
22
+ list: "list",
23
+ map: "map"
24
+ };
25
+ function asPositiveInteger(value) {
26
+ return typeof value === "number" && Number.isInteger(value) && value > 0;
27
+ }
28
+ function normalizeString(value) {
29
+ return value.trim();
30
+ }
31
+ function declarativeContextPurposeToGraphStage(purpose) {
32
+ return PURPOSE_TO_STAGE[purpose.trim().toLowerCase()] ?? "plan";
33
+ }
34
+ function declarativeContextFormatToGraphView(format) {
35
+ return FORMAT_TO_VIEW[(format ?? "summary").trim().toLowerCase()] ?? "brief";
36
+ }
37
+ function compileDeclarativeContextQuery(query, options = {}) {
38
+ const errors = [];
39
+ const warnings = [];
40
+ const maxDepth = options.maxDepth ?? 3;
41
+ const defaultLimit = options.defaultLimit ?? 8;
42
+ const id = normalizeString(query.id ?? "");
43
+ if (!id) {
44
+ errors.push("Context query id is required.");
45
+ }
46
+ const purpose = normalizeString(query.purpose ?? "");
47
+ if (!purpose) {
48
+ errors.push(`Context query "${id || "<unknown>"}" purpose is required.`);
49
+ }
50
+ const textQuery = normalizeString(query.query ?? "");
51
+ if (!textQuery) {
52
+ errors.push(`Context query "${id || "<unknown>"}" query is required.`);
53
+ }
54
+ const depth = query.depth ?? 1;
55
+ if (!Number.isInteger(depth) || depth < 0 || depth > maxDepth) {
56
+ errors.push(`Context query "${id || "<unknown>"}" depth must be an integer between 0 and ${maxDepth}.`);
57
+ }
58
+ if (query.budget !== void 0 && !asPositiveInteger(query.budget)) {
59
+ errors.push(`Context query "${id || "<unknown>"}" budget must be a positive integer.`);
60
+ }
61
+ const scope = query.scope === void 0 ? void 0 : normalizeString(query.scope);
62
+ if (scope !== void 0 && (!scope || !scope.startsWith("/"))) {
63
+ errors.push(`Context query "${id || "<unknown>"}" scope must start with "/".`);
64
+ }
65
+ const relations = (query.relations ?? ["related", "references"]).map((entry) => entry.trim().toLowerCase());
66
+ const invalidRelations = relations.filter((relation) => !VALID_RELATIONS.includes(relation));
67
+ if (invalidRelations.length > 0) {
68
+ errors.push(`Context query "${id || "<unknown>"}" has invalid relations: ${invalidRelations.join(", ")}.`);
69
+ }
70
+ const uniqueRelations = [...new Set(relations)];
71
+ if (uniqueRelations.length !== relations.length) {
72
+ warnings.push(`Context query "${id || "<unknown>"}" included duplicate relations; duplicates were removed.`);
73
+ }
74
+ const stage = declarativeContextPurposeToGraphStage(purpose);
75
+ if (stage === "plan" && !["plan", ""].includes(purpose.toLowerCase()) && !PURPOSE_TO_STAGE[purpose.toLowerCase()]) {
76
+ warnings.push(`Context query "${id || "<unknown>"}" purpose "${purpose}" is not a graph stage; using "plan".`);
77
+ }
78
+ const view = declarativeContextFormatToGraphView(query.format);
79
+ if (query.format && !FORMAT_TO_VIEW[query.format.trim().toLowerCase()]) {
80
+ warnings.push(`Context query "${id || "<unknown>"}" format "${query.format}" is not a graph view; using "brief".`);
81
+ }
82
+ if (errors.length > 0) {
83
+ return { ok: false, compiled: null, errors, warnings };
84
+ }
85
+ const request = {
86
+ query: textQuery,
87
+ stage,
88
+ relations: uniqueRelations,
89
+ view,
90
+ options: {
91
+ depth,
92
+ limit: defaultLimit,
93
+ maxNodes: defaultLimit
94
+ }
95
+ };
96
+ if (scope) {
97
+ request.scopePaths = [scope];
98
+ }
99
+ if (query.budget !== void 0) {
100
+ request.budget = {
101
+ maxTokens: query.budget
102
+ };
103
+ }
104
+ return {
105
+ ok: true,
106
+ compiled: {
107
+ query: {
108
+ ...query,
109
+ id,
110
+ purpose,
111
+ query: textQuery,
112
+ scope,
113
+ relations: uniqueRelations
114
+ },
115
+ request,
116
+ warnings
117
+ },
118
+ errors: [],
119
+ warnings
120
+ };
121
+ }
122
+ export {
123
+ compileDeclarativeContextQuery,
124
+ declarativeContextFormatToGraphView,
125
+ declarativeContextPurposeToGraphStage
126
+ };
package/dist/index.d.ts CHANGED
@@ -13,6 +13,7 @@ export { PUBLISHED_CONTENT_MANIFEST_SCHEMA_VERSION, EDITORIAL_PREVIEW_COOKIE, Te
13
13
  export { createFilesystemContentSource, createPublishedContentPipeline, } from './platform/published-content-pipeline.ts';
14
14
  export { loadTreeseedManifest, loadTreeseedTenantManifest, resolveTreeseedTenantRoot, getTenantContentRoot, tenantFeatureEnabled, tenantModelRendered, } from './platform/tenant-config.ts';
15
15
  export { parseGraphDsl } from './graph/dsl.ts';
16
+ export { compileDeclarativeContextQuery, declarativeContextFormatToGraphView, declarativeContextPurposeToGraphStage, type CompiledDeclarativeContextQuery, type DeclarativeContextQuery, type DeclarativeContextQueryCompileResult, type DeclarativeContextQueryFormat, type DeclarativeContextQueryPurpose, type DeclarativeContextQuerySourceRef, type HandlerContextPackSource, type ResolvedHandlerContextPack, } from './graph/context-query-contracts.ts';
16
17
  export { createDefaultGraphRankingProvider, DEFAULT_GRAPH_RANKING_PROVIDER } from './graph/ranking.ts';
17
18
  export { BUILTIN_MODEL_REGISTRY, MODEL_REGISTRY, buildBuiltinModelRegistry, buildModelRegistry, buildScopedModelRegistry, mergeModelRegistries, resolveModelDefinition, } from './model-registry.ts';
18
19
  export { normalizeAgentCliOptions, buildCopilotAllowToolArgs } from './cli-tools.ts';
@@ -20,6 +21,7 @@ export { collectTreeseedDependencyStatus, collectTreeseedToolStatus, createTrees
20
21
  export { runTreeseedCopilotTask, type TreeseedCopilotTaskInput, type TreeseedCopilotTaskResult, } from './copilot.ts';
21
22
  export { findDispatchCapability, listSdkDispatchCapabilities, listWorkflowDispatchCapabilities, } from './dispatch.ts';
22
23
  export { executeSdkOperation, findSdkOperation, listSdkOperationNames, } from './sdk-dispatch.ts';
24
+ export { AGENT_OPERATION_MODES, AGENT_OPERATION_NAMES, createAgentOperationEvent, decideAgentOperationPermission, deniedAgentOperationResult, isAgentOperationName, resolveAgentOperationGrant, type AgentDeterministicOperationStep, type AgentOperationApprovalRef, type AgentOperationEvent, type AgentOperationGrant, type AgentOperationMergeFailure, type AgentOperationMode, type AgentOperationName, type AgentOperationPermissionCode, type AgentOperationPermissionDecision, type AgentOperationRequest, type AgentOperationResult, type AgentOperationStatus, } from './operations/agent-tools.ts';
23
25
  export { resolveSdkRecordVersion } from './sdk-version.ts';
24
26
  export { normalizeAliasedRecord, preprocessAliasedRecord, resolveAliasedField, } from './field-aliases.ts';
25
27
  export { canonicalizeFrontmatter, normalizeFilterFields, normalizeMutationData, normalizeRecordToCanonicalShape, normalizeSortFields, readCanonicalFieldValue, resolveModelField, validateModelFieldAliases, } from './sdk-fields.ts';
package/dist/index.js CHANGED
@@ -94,6 +94,11 @@ import {
94
94
  tenantModelRendered
95
95
  } from "./platform/tenant-config.js";
96
96
  import { parseGraphDsl } from "./graph/dsl.js";
97
+ import {
98
+ compileDeclarativeContextQuery,
99
+ declarativeContextFormatToGraphView,
100
+ declarativeContextPurposeToGraphStage
101
+ } from "./graph/context-query-contracts.js";
97
102
  import { createDefaultGraphRankingProvider, DEFAULT_GRAPH_RANKING_PROVIDER } from "./graph/ranking.js";
98
103
  import {
99
104
  BUILTIN_MODEL_REGISTRY,
@@ -127,6 +132,15 @@ import {
127
132
  findSdkOperation,
128
133
  listSdkOperationNames
129
134
  } from "./sdk-dispatch.js";
135
+ import {
136
+ AGENT_OPERATION_MODES,
137
+ AGENT_OPERATION_NAMES,
138
+ createAgentOperationEvent,
139
+ decideAgentOperationPermission,
140
+ deniedAgentOperationResult,
141
+ isAgentOperationName,
142
+ resolveAgentOperationGrant
143
+ } from "./operations/agent-tools.js";
130
144
  import { resolveSdkRecordVersion } from "./sdk-version.js";
131
145
  import {
132
146
  normalizeAliasedRecord,
@@ -200,6 +214,8 @@ import { getTreeseedVerifyDriverStatus, runTreeseedVerifyDriver } from "./verifi
200
214
  import { CloudflareHttpD1Database } from "./d1-http.js";
201
215
  export {
202
216
  AGENT_MESSAGE_KINDS,
217
+ AGENT_OPERATION_MODES,
218
+ AGENT_OPERATION_NAMES,
203
219
  AgentSdk,
204
220
  BUILTIN_MODEL_REGISTRY,
205
221
  CloudflareHttpD1Database,
@@ -250,6 +266,8 @@ export {
250
266
  collectTreeseedDependencyStatus,
251
267
  collectTreeseedReconcileStatus,
252
268
  collectTreeseedToolStatus,
269
+ compileDeclarativeContextQuery,
270
+ createAgentOperationEvent,
253
271
  createControlPlaneReporter,
254
272
  createDefaultGraphRankingProvider,
255
273
  createFilesystemContentSource,
@@ -260,7 +278,11 @@ export {
260
278
  createTeamScopedR2OverlayContentRuntimeProvider,
261
279
  createTreeseedManagedToolEnv,
262
280
  createTreeseedReconcileRegistry,
281
+ decideAgentOperationPermission,
282
+ declarativeContextFormatToGraphView,
283
+ declarativeContextPurposeToGraphStage,
263
284
  defaultHubContentResolutionPolicy,
285
+ deniedAgentOperationResult,
264
286
  deriveTreeseedDesiredUnits,
265
287
  destroyTreeseedTargetUnits,
266
288
  ensureRailwayEnvironment,
@@ -278,6 +300,7 @@ export {
278
300
  getTreeseedVerifyDriverStatus,
279
301
  importKnowledgePack,
280
302
  installTreeseedDependencies,
303
+ isAgentOperationName,
281
304
  isTeamScopedR2ContentEnabled,
282
305
  listIntegratedMarketCatalog,
283
306
  listRailwayEnvironments,
@@ -320,6 +343,7 @@ export {
320
343
  removeMarketProfile,
321
344
  reservationHasCapacity,
322
345
  reserveCreditsForEstimate,
346
+ resolveAgentOperationGrant,
323
347
  resolveAliasedField,
324
348
  resolveCatalogMarketProfiles,
325
349
  resolveCloudflareR2Bucket,
@@ -0,0 +1,114 @@
1
+ export declare const AGENT_OPERATION_NAMES: readonly ["switch", "dev", "verify", "save", "stage", "merge_to_staging", "close", "release"];
2
+ export declare const AGENT_OPERATION_MODES: readonly ["dry_run", "read_only", "mutating"];
3
+ export type AgentOperationName = (typeof AGENT_OPERATION_NAMES)[number];
4
+ export type AgentOperationMode = (typeof AGENT_OPERATION_MODES)[number];
5
+ export type AgentOperationStatus = 'completed' | 'waiting' | 'failed' | 'skipped' | 'retry_created';
6
+ export interface AgentOperationApprovalRef {
7
+ id: string;
8
+ kind?: string;
9
+ state: 'pending' | 'approved' | 'rejected' | 'expired' | 'superseded';
10
+ }
11
+ export interface AgentOperationRequest {
12
+ operation: AgentOperationName;
13
+ mode: AgentOperationMode;
14
+ taskId: string;
15
+ taskKind?: string;
16
+ workDayId?: string;
17
+ agentSlug: string;
18
+ agentRole: string;
19
+ projectId: string;
20
+ environment: string;
21
+ repoRoot: string;
22
+ worktreeRoot?: string;
23
+ featureBranch?: string;
24
+ stagingBranch?: string;
25
+ approvalId?: string;
26
+ approval?: AgentOperationApprovalRef;
27
+ permissionGrantId?: string;
28
+ allowedPaths?: string[];
29
+ forbiddenPaths?: string[];
30
+ changedPaths?: string[];
31
+ input: Record<string, unknown>;
32
+ }
33
+ export interface AgentDeterministicOperationStep {
34
+ id: string;
35
+ operation: AgentOperationName;
36
+ stage: 'before_mutation' | 'during_mutation' | 'after_mutation' | 'after_verification_passes' | 'after_verification_fails' | 'after_staging_merge_fails' | 'closeout' | string;
37
+ mode: AgentOperationMode;
38
+ required?: boolean;
39
+ }
40
+ export interface AgentOperationGrant {
41
+ id: string;
42
+ state?: 'active' | 'paused' | 'revoked';
43
+ operations: AgentOperationName[];
44
+ modes: AgentOperationMode[];
45
+ agentRoles?: string[];
46
+ taskKinds?: string[];
47
+ projectIds?: string[];
48
+ environments?: string[];
49
+ allowedPaths?: string[];
50
+ forbiddenPaths?: string[];
51
+ requiresApproval?: boolean;
52
+ approvalIds?: string[];
53
+ expiresAt?: string;
54
+ metadata?: Record<string, unknown>;
55
+ }
56
+ export interface AgentOperationMergeFailure {
57
+ targetBranch: string;
58
+ featureBranch: string;
59
+ conflictedPaths: string[];
60
+ message: string;
61
+ repairTaskId?: string;
62
+ }
63
+ export interface AgentOperationResult {
64
+ operation: AgentOperationName;
65
+ status: AgentOperationStatus;
66
+ summary: string;
67
+ changedPaths: string[];
68
+ stagedPaths: string[];
69
+ mergedToStaging?: boolean;
70
+ mergeFailure?: AgentOperationMergeFailure;
71
+ commandsRun: string[];
72
+ artifacts: Array<{
73
+ kind: string;
74
+ ref: string;
75
+ }>;
76
+ error?: {
77
+ code: string;
78
+ message: string;
79
+ retryable: boolean;
80
+ };
81
+ metadata: Record<string, unknown>;
82
+ }
83
+ export type AgentOperationPermissionCode = 'allowed' | 'invalid_operation' | 'operation_permission_required' | 'operation_grant_inactive' | 'operation_grant_expired' | 'operation_mode_not_granted' | 'operation_role_not_granted' | 'operation_task_kind_not_granted' | 'operation_project_not_granted' | 'operation_environment_not_granted' | 'operation_approval_required' | 'operation_release_approval_required' | 'operation_worktree_required' | 'operation_allowed_paths_required' | 'operation_path_not_allowed' | 'operation_path_forbidden';
84
+ export interface AgentOperationPermissionDecision {
85
+ allowed: boolean;
86
+ status: 'completed' | 'waiting' | 'failed';
87
+ code: AgentOperationPermissionCode;
88
+ summary: string;
89
+ grant?: AgentOperationGrant;
90
+ metadata: Record<string, unknown>;
91
+ }
92
+ export interface AgentOperationEvent {
93
+ operation: AgentOperationName;
94
+ mode: AgentOperationMode;
95
+ agentRole: string;
96
+ taskId: string;
97
+ permissionGrantId?: string;
98
+ inputSummary: Record<string, unknown>;
99
+ result: AgentOperationResult;
100
+ createdAt: string;
101
+ }
102
+ export declare function isAgentOperationName(value: string): value is AgentOperationName;
103
+ export declare function resolveAgentOperationGrant(request: AgentOperationRequest, grants: readonly AgentOperationGrant[], now?: Date): AgentOperationGrant | null;
104
+ export declare function decideAgentOperationPermission(input: {
105
+ request: AgentOperationRequest;
106
+ grants: readonly AgentOperationGrant[];
107
+ now?: Date;
108
+ }): AgentOperationPermissionDecision;
109
+ export declare function deniedAgentOperationResult(request: AgentOperationRequest, decision: AgentOperationPermissionDecision): AgentOperationResult;
110
+ export declare function createAgentOperationEvent(input: {
111
+ request: AgentOperationRequest;
112
+ result: AgentOperationResult;
113
+ createdAt?: string;
114
+ }): AgentOperationEvent;
@@ -0,0 +1,183 @@
1
+ const AGENT_OPERATION_NAMES = [
2
+ "switch",
3
+ "dev",
4
+ "verify",
5
+ "save",
6
+ "stage",
7
+ "merge_to_staging",
8
+ "close",
9
+ "release"
10
+ ];
11
+ const AGENT_OPERATION_MODES = ["dry_run", "read_only", "mutating"];
12
+ function normalizePath(value) {
13
+ return value.replace(/\\/gu, "/").replace(/^\.?\//u, "").replace(/\/+/gu, "/");
14
+ }
15
+ function matchesPattern(path, pattern) {
16
+ const normalizedPath = normalizePath(path);
17
+ const normalizedPattern = normalizePath(pattern);
18
+ if (normalizedPattern.endsWith("/**")) {
19
+ const prefix = normalizedPattern.slice(0, -3);
20
+ return normalizedPath === prefix || normalizedPath.startsWith(`${prefix}/`);
21
+ }
22
+ if (normalizedPattern.endsWith("/")) {
23
+ return normalizedPath.startsWith(normalizedPattern);
24
+ }
25
+ return normalizedPath === normalizedPattern || normalizedPath.startsWith(`${normalizedPattern}/`);
26
+ }
27
+ function listMatches(value, allowed) {
28
+ return !allowed?.length || value !== void 0 && allowed.includes(value);
29
+ }
30
+ function grantActive(grant, now) {
31
+ if ((grant.state ?? "active") !== "active") {
32
+ return "operation_grant_inactive";
33
+ }
34
+ if (grant.expiresAt && Date.parse(grant.expiresAt) <= now.valueOf()) {
35
+ return "operation_grant_expired";
36
+ }
37
+ return null;
38
+ }
39
+ function deny(code, summary, options = {}) {
40
+ return {
41
+ allowed: false,
42
+ status: options.status ?? "waiting",
43
+ code,
44
+ summary,
45
+ grant: options.grant,
46
+ metadata: options.metadata ?? {}
47
+ };
48
+ }
49
+ function allow(grant, metadata = {}) {
50
+ return {
51
+ allowed: true,
52
+ status: "completed",
53
+ code: "allowed",
54
+ summary: `Operation grant ${grant.id} allows this request.`,
55
+ grant,
56
+ metadata
57
+ };
58
+ }
59
+ function isAgentOperationName(value) {
60
+ return AGENT_OPERATION_NAMES.includes(value);
61
+ }
62
+ function resolveAgentOperationGrant(request, grants, now = /* @__PURE__ */ new Date()) {
63
+ return grants.find((grant) => {
64
+ if (request.permissionGrantId && grant.id !== request.permissionGrantId) return false;
65
+ if (grantActive(grant, now)) return false;
66
+ if (!grant.operations.includes(request.operation)) return false;
67
+ return true;
68
+ }) ?? null;
69
+ }
70
+ function decideAgentOperationPermission(input) {
71
+ const { request } = input;
72
+ const now = input.now ?? /* @__PURE__ */ new Date();
73
+ if (!isAgentOperationName(request.operation)) {
74
+ return deny("invalid_operation", `Unsupported agent operation "${String(request.operation)}".`, { status: "failed" });
75
+ }
76
+ if (request.operation === "release") {
77
+ const approval = request.approval;
78
+ if (!approval || approval.state !== "approved" || request.approvalId && approval.id !== request.approvalId) {
79
+ return deny("operation_release_approval_required", "Release requires an explicit approved release approval.");
80
+ }
81
+ }
82
+ const grant = resolveAgentOperationGrant(request, input.grants, now);
83
+ if (!grant) {
84
+ return deny("operation_permission_required", `No operation grant allows ${request.agentRole} to run ${request.operation}.`);
85
+ }
86
+ const activeCode = grantActive(grant, now);
87
+ if (activeCode) {
88
+ return deny(activeCode, `Operation grant ${grant.id} is not active.`, { grant });
89
+ }
90
+ if (!grant.modes.includes(request.mode)) {
91
+ return deny("operation_mode_not_granted", `Operation grant ${grant.id} does not allow ${request.mode} mode.`, { grant });
92
+ }
93
+ if (!listMatches(request.agentRole, grant.agentRoles)) {
94
+ return deny("operation_role_not_granted", `Operation grant ${grant.id} does not allow role ${request.agentRole}.`, { grant });
95
+ }
96
+ if (!listMatches(request.taskKind, grant.taskKinds)) {
97
+ return deny("operation_task_kind_not_granted", `Operation grant ${grant.id} does not allow task kind ${request.taskKind ?? "<none>"}.`, { grant });
98
+ }
99
+ if (!listMatches(request.projectId, grant.projectIds)) {
100
+ return deny("operation_project_not_granted", `Operation grant ${grant.id} does not allow project ${request.projectId}.`, { grant });
101
+ }
102
+ if (!listMatches(request.environment, grant.environments)) {
103
+ return deny("operation_environment_not_granted", `Operation grant ${grant.id} does not allow environment ${request.environment}.`, { grant });
104
+ }
105
+ if (grant.requiresApproval && (!request.approval || request.approval.state !== "approved")) {
106
+ return deny("operation_approval_required", `Operation grant ${grant.id} requires approval.`, { grant });
107
+ }
108
+ if (grant.approvalIds?.length && (!request.approval || !grant.approvalIds.includes(request.approval.id) || request.approval.state !== "approved")) {
109
+ return deny("operation_approval_required", `Operation grant ${grant.id} requires one of its approved approval ids.`, { grant });
110
+ }
111
+ if (request.mode === "mutating" && !request.worktreeRoot && request.operation !== "release") {
112
+ return deny("operation_worktree_required", `Mutating operation ${request.operation} requires an assigned worktree root.`, { grant });
113
+ }
114
+ const allowedPaths = request.allowedPaths?.length ? request.allowedPaths : grant.allowedPaths ?? [];
115
+ const forbiddenPaths = [...grant.forbiddenPaths ?? [], ...request.forbiddenPaths ?? []];
116
+ const changedPaths = request.changedPaths ?? [];
117
+ if ((request.operation === "stage" || request.operation === "merge_to_staging") && allowedPaths.length === 0) {
118
+ return deny("operation_allowed_paths_required", `${request.operation} requires allowed paths.`, { grant });
119
+ }
120
+ for (const changedPath of changedPaths) {
121
+ if (forbiddenPaths.some((pattern) => matchesPattern(changedPath, pattern))) {
122
+ return deny("operation_path_forbidden", `${changedPath} is forbidden.`, {
123
+ grant,
124
+ status: "failed",
125
+ metadata: { changedPath, forbiddenPaths }
126
+ });
127
+ }
128
+ if (allowedPaths.length > 0 && !allowedPaths.some((pattern) => matchesPattern(changedPath, pattern))) {
129
+ return deny("operation_path_not_allowed", `${changedPath} is outside allowed paths.`, {
130
+ grant,
131
+ status: "failed",
132
+ metadata: { changedPath, allowedPaths }
133
+ });
134
+ }
135
+ }
136
+ return allow(grant, { allowedPaths, forbiddenPaths });
137
+ }
138
+ function deniedAgentOperationResult(request, decision) {
139
+ return {
140
+ operation: request.operation,
141
+ status: decision.status,
142
+ summary: decision.summary,
143
+ changedPaths: request.changedPaths ?? [],
144
+ stagedPaths: [],
145
+ commandsRun: [],
146
+ artifacts: [],
147
+ error: {
148
+ code: decision.code,
149
+ message: decision.summary,
150
+ retryable: decision.status === "waiting"
151
+ },
152
+ metadata: {
153
+ permission: decision
154
+ }
155
+ };
156
+ }
157
+ function createAgentOperationEvent(input) {
158
+ return {
159
+ operation: input.request.operation,
160
+ mode: input.request.mode,
161
+ agentRole: input.request.agentRole,
162
+ taskId: input.request.taskId,
163
+ permissionGrantId: input.request.permissionGrantId,
164
+ inputSummary: {
165
+ projectId: input.request.projectId,
166
+ environment: input.request.environment,
167
+ allowedPaths: input.request.allowedPaths ?? [],
168
+ forbiddenPaths: input.request.forbiddenPaths ?? [],
169
+ changedPaths: input.request.changedPaths ?? []
170
+ },
171
+ result: input.result,
172
+ createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
173
+ };
174
+ }
175
+ export {
176
+ AGENT_OPERATION_MODES,
177
+ AGENT_OPERATION_NAMES,
178
+ createAgentOperationEvent,
179
+ decideAgentOperationPermission,
180
+ deniedAgentOperationResult,
181
+ isAgentOperationName,
182
+ resolveAgentOperationGrant
183
+ };
@@ -29,7 +29,7 @@ const danglingSubjectEndings = /* @__PURE__ */ new Set([
29
29
  "update",
30
30
  "with"
31
31
  ]);
32
- const defaultTimeoutMs = 3e4;
32
+ const defaultTimeoutMs = 6e4;
33
33
  const defaultMaxDiffChars = 12e3;
34
34
  const subjectMaxLength = 72;
35
35
  function envValue(env, key) {
@@ -352,7 +352,7 @@ function applyManagedProjectDefaults(projectRoot, input) {
352
352
  ...config.providers ?? {},
353
353
  forms: config.providers?.forms ?? "store_only",
354
354
  agents: {
355
- execution: "copilot",
355
+ execution: "codex",
356
356
  mutation: "local_branch",
357
357
  repository: "git",
358
358
  verification: "local",
@@ -37,7 +37,7 @@ const TREESEED_DEFAULT_PLUGIN_REFERENCES = [
37
37
  const TREESEED_DEFAULT_PROVIDER_SELECTIONS = {
38
38
  forms: "store_only",
39
39
  agents: {
40
- execution: "copilot",
40
+ execution: "codex",
41
41
  mutation: "local_branch",
42
42
  repository: "git",
43
43
  verification: "local",
@@ -5,5 +5,6 @@ export { TreeseedOperationsSdk } from './operations/runtime.ts';
5
5
  export type { HubContentResolutionPolicy, KnowledgeHubLaunchIntent, KnowledgeHubLaunchPhase, KnowledgeHubLaunchPlan, KnowledgeHubLaunchResult, KnowledgeHubRepositoryPlan, RepositoryHost, } from './operations/services/hub-launch.ts';
6
6
  export type { TreeseedOperationContext, TreeseedOperationImplementation, TreeseedOperationId, TreeseedOperationMetadata, TreeseedOperationProvider, TreeseedOperationProviderId, TreeseedOperationRequest, TreeseedOperationResult, TreeseedOperationGroup, } from './operations-types.ts';
7
7
  export { TreeseedOperationError } from './operations-types.ts';
8
+ export { AGENT_OPERATION_MODES, AGENT_OPERATION_NAMES, createAgentOperationEvent, decideAgentOperationPermission, deniedAgentOperationResult, isAgentOperationName, resolveAgentOperationGrant, type AgentDeterministicOperationStep, type AgentOperationApprovalRef, type AgentOperationEvent, type AgentOperationGrant, type AgentOperationMergeFailure, type AgentOperationMode, type AgentOperationName, type AgentOperationPermissionCode, type AgentOperationPermissionDecision, type AgentOperationRequest, type AgentOperationResult, type AgentOperationStatus, } from './operations/agent-tools.ts';
8
9
  export { TreeseedWorkflowSdk } from './workflow.ts';
9
10
  export type * from './workflow.ts';
@@ -15,20 +15,36 @@ import {
15
15
  } from "./operations/services/hub-launch.js";
16
16
  import { TreeseedOperationsSdk } from "./operations/runtime.js";
17
17
  import { TreeseedOperationError } from "./operations-types.js";
18
+ import {
19
+ AGENT_OPERATION_MODES,
20
+ AGENT_OPERATION_NAMES,
21
+ createAgentOperationEvent,
22
+ decideAgentOperationPermission,
23
+ deniedAgentOperationResult,
24
+ isAgentOperationName,
25
+ resolveAgentOperationGrant
26
+ } from "./operations/agent-tools.js";
18
27
  import { TreeseedWorkflowSdk } from "./workflow.js";
19
28
  export {
29
+ AGENT_OPERATION_MODES,
30
+ AGENT_OPERATION_NAMES,
20
31
  TRESEED_OPERATION_SPECS,
21
32
  TreeseedOperationError,
22
33
  TreeseedOperationsSdk,
23
34
  TreeseedWorkflowSdk,
24
35
  collectTreeseedConfigSeedValues,
36
+ createAgentOperationEvent,
25
37
  createKnowledgeHubRepositories,
38
+ decideAgentOperationPermission,
26
39
  defaultHubContentResolutionPolicy,
40
+ deniedAgentOperationResult,
27
41
  executeKnowledgeHubLaunch,
28
42
  findTreeseedOperation,
43
+ isAgentOperationName,
29
44
  listTreeseedOperationNames,
30
45
  normalizeKnowledgeHubLaunchIntent,
31
46
  planKnowledgeHubLaunch,
32
47
  planKnowledgeHubRepositories,
48
+ resolveAgentOperationGrant,
33
49
  validateRepositoryHost
34
50
  };
@@ -106,6 +106,10 @@ function processingPlaneEnabled(context) {
106
106
  function formsEnabled(context) {
107
107
  return webSurfaceEnabled(context) && (context.deployConfig.providers?.forms ?? "store_only") !== "none";
108
108
  }
109
+ function codexExecutionSelected(context) {
110
+ const execution = context.deployConfig.providers?.agents?.execution ?? "codex";
111
+ return execution === "codex" || execution === "codex_subscription";
112
+ }
109
113
  function railwayManagedEnabled(context) {
110
114
  if (!workflowPlaneAllows("processing")) {
111
115
  return false;
@@ -333,6 +337,7 @@ const PREDICATES = {
333
337
  apiSurfaceEnabled: (context) => apiSurfaceEnabled(context),
334
338
  processingPlaneEnabled: (context) => processingPlaneEnabled(context),
335
339
  formsEnabled: (context) => formsEnabled(context),
340
+ codexExecutionSelected: (context) => codexExecutionSelected(context),
336
341
  railwayManagedEnabled: (context) => railwayManagedEnabled(context),
337
342
  hubTreeseedHosted: (context) => resolveHubMode(context) === "treeseed_hosted",
338
343
  hubCustomerHosted: (context) => resolveHubMode(context) === "customer_hosted",
@@ -3,7 +3,7 @@ const TREESEED_DEFAULT_PROVIDER_SELECTIONS = {
3
3
  forms: "store_only",
4
4
  operations: "default",
5
5
  agents: {
6
- execution: "copilot",
6
+ execution: "codex",
7
7
  mutation: "local_branch",
8
8
  repository: "git",
9
9
  verification: "local",
@@ -6,7 +6,7 @@ var plugin_default_default = defineTreeseedPlugin({
6
6
  forms: ["store_only", "notify_admin", "full_email"],
7
7
  operations: ["default"],
8
8
  agents: {
9
- execution: ["stub", "manual", "copilot"],
9
+ execution: ["stub", "manual", "copilot", "codex", "codex_subscription"],
10
10
  mutation: ["local_branch"],
11
11
  repository: ["stub", "git"],
12
12
  verification: ["stub", "local"],
@@ -72,7 +72,7 @@ plugins:
72
72
  providers:
73
73
  forms: store_only
74
74
  agents:
75
- execution: copilot
75
+ execution: codex
76
76
  mutation: local_branch
77
77
  repository: git
78
78
  verification: local
@@ -27,6 +27,18 @@ export interface AgentOutputContract {
27
27
  modelMutations: string[];
28
28
  }
29
29
  export interface AgentExecutionConfig {
30
+ provider?: string;
31
+ model?: string;
32
+ approvalPolicy?: 'never' | 'on_request' | 'always' | string;
33
+ sandboxMode?: 'read_only' | 'workspace_write' | string;
34
+ reasoningEffort?: 'low' | 'medium' | 'high' | string;
35
+ allowedPaths?: string[];
36
+ forbiddenPaths?: string[];
37
+ worktree?: {
38
+ enabled?: boolean;
39
+ root?: string;
40
+ branchPrefix?: string;
41
+ };
30
42
  maxConcurrency: number;
31
43
  timeoutSeconds: number;
32
44
  cooldownSeconds: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@treeseed/sdk",
3
- "version": "0.8.10",
3
+ "version": "0.8.11",
4
4
  "description": "Shared Treeseed SDK for content-backed and D1-backed object models.",
5
5
  "license": "AGPL-3.0-only",
6
6
  "repository": {
@@ -96,6 +96,10 @@
96
96
  "types": "./dist/operations.d.ts",
97
97
  "default": "./dist/operations.js"
98
98
  },
99
+ "./operations/agent-tools": {
100
+ "types": "./dist/operations/agent-tools.d.ts",
101
+ "default": "./dist/operations/agent-tools.js"
102
+ },
99
103
  "./workflow": {
100
104
  "types": "./dist/workflow.d.ts",
101
105
  "default": "./dist/workflow.js"
@@ -197,6 +201,10 @@
197
201
  "types": "./dist/graph.d.ts",
198
202
  "default": "./dist/graph.js"
199
203
  },
204
+ "./graph/context-query-contracts": {
205
+ "types": "./dist/graph/context-query-contracts.d.ts",
206
+ "default": "./dist/graph/context-query-contracts.js"
207
+ },
200
208
  "./sdk-filters": {
201
209
  "types": "./dist/sdk-filters.d.ts",
202
210
  "default": "./dist/sdk-filters.js"