@stigmer/sdk 3.19.0 → 3.19.1-dev.20260920100552

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 (53) hide show
  1. package/README.md +0 -1
  2. package/__tests__/update-input-roundtrip.test.js +0 -20
  3. package/__tests__/update-input-roundtrip.test.js.map +1 -1
  4. package/gen/authorization-config.d.ts.map +1 -1
  5. package/gen/authorization-config.js +0 -1
  6. package/gen/authorization-config.js.map +1 -1
  7. package/gen/client.d.ts +0 -4
  8. package/gen/client.d.ts.map +1 -1
  9. package/gen/client.js +0 -4
  10. package/gen/client.js.map +1 -1
  11. package/gen/resource-availability.d.ts.map +1 -1
  12. package/gen/resource-availability.js +0 -1
  13. package/gen/resource-availability.js.map +1 -1
  14. package/index.d.ts +0 -1
  15. package/index.d.ts.map +1 -1
  16. package/index.js +0 -1
  17. package/index.js.map +1 -1
  18. package/package.json +2 -6
  19. package/src/__tests__/update-input-roundtrip.test.ts +0 -28
  20. package/src/gen/authorization-config.ts +0 -1
  21. package/src/gen/client.ts +0 -5
  22. package/src/gen/resource-availability.ts +0 -1
  23. package/src/index.ts +0 -5
  24. package/gen/project.d.ts +0 -50
  25. package/gen/project.d.ts.map +0 -1
  26. package/gen/project.js +0 -121
  27. package/gen/project.js.map +0 -1
  28. package/src/gen/project.ts +0 -135
  29. package/src/synth/__tests__/synth.test.ts +0 -171
  30. package/src/synth/context.ts +0 -141
  31. package/src/synth/index.ts +0 -85
  32. package/src/synth/writer.ts +0 -100
  33. package/src/synth.ts +0 -8
  34. package/synth/__tests__/synth.test.d.ts +0 -2
  35. package/synth/__tests__/synth.test.d.ts.map +0 -1
  36. package/synth/__tests__/synth.test.js +0 -143
  37. package/synth/__tests__/synth.test.js.map +0 -1
  38. package/synth/context.d.ts +0 -73
  39. package/synth/context.d.ts.map +0 -1
  40. package/synth/context.js +0 -76
  41. package/synth/context.js.map +0 -1
  42. package/synth/index.d.ts +0 -35
  43. package/synth/index.d.ts.map +0 -1
  44. package/synth/index.js +0 -44
  45. package/synth/index.js.map +0 -1
  46. package/synth/writer.d.ts +0 -28
  47. package/synth/writer.d.ts.map +0 -1
  48. package/synth/writer.js +0 -86
  49. package/synth/writer.js.map +0 -1
  50. package/synth.d.ts +0 -2
  51. package/synth.d.ts.map +0 -1
  52. package/synth.js +0 -8
  53. package/synth.js.map +0 -1
package/gen/project.js DELETED
@@ -1,121 +0,0 @@
1
- // Code generated by stigmer-codegen. DO NOT EDIT.
2
- import { wrapError } from "./errors.js";
3
- import { stripUndefined, toResourceRefInputs } from "./proto-utils.js";
4
- import { create } from "@bufbuild/protobuf";
5
- import { createClient } from "@connectrpc/connect";
6
- import { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
7
- import { ApiResourceReferenceSchema } from "@stigmer/protos/ai/stigmer/commons/apiresource/io_pb";
8
- import { ApiResourceMetadataSchema } from "@stigmer/protos/ai/stigmer/commons/apiresource/metadata_pb";
9
- import { ProjectSchema } from "@stigmer/protos/ai/stigmer/tenancy/project/v1/api_pb";
10
- import { ProjectCommandController } from "@stigmer/protos/ai/stigmer/tenancy/project/v1/command_pb";
11
- import { ProjectIdSchema } from "@stigmer/protos/ai/stigmer/tenancy/project/v1/io_pb";
12
- import { ProjectQueryController } from "@stigmer/protos/ai/stigmer/tenancy/project/v1/query_pb";
13
- import { ProjectSpecSchema } from "@stigmer/protos/ai/stigmer/tenancy/project/v1/spec_pb";
14
- /** Provides operations on project resources. */
15
- export class ProjectClient {
16
- command;
17
- query;
18
- constructor(transport) {
19
- this.command = createClient(ProjectCommandController, transport);
20
- this.query = createClient(ProjectQueryController, transport);
21
- }
22
- async apply(input) {
23
- try {
24
- return await this.command.apply(buildProjectProto(input));
25
- }
26
- catch (e) {
27
- throw wrapError(e);
28
- }
29
- }
30
- async create(input) {
31
- try {
32
- return await this.command.create(buildProjectProto(input));
33
- }
34
- catch (e) {
35
- throw wrapError(e);
36
- }
37
- }
38
- async update(input) {
39
- try {
40
- return await this.command.update(buildProjectProto(input));
41
- }
42
- catch (e) {
43
- throw wrapError(e);
44
- }
45
- }
46
- async delete(id) {
47
- try {
48
- return await this.command.delete(create(ProjectIdSchema, { value: id }));
49
- }
50
- catch (e) {
51
- throw wrapError(e);
52
- }
53
- }
54
- async get(id) {
55
- try {
56
- return await this.query.get(create(ProjectIdSchema, { value: id }));
57
- }
58
- catch (e) {
59
- throw wrapError(e);
60
- }
61
- }
62
- async getByReference(ref) {
63
- try {
64
- return await this.query.getByReference(create(ApiResourceReferenceSchema, { ...ref, kind: ApiResourceKind.project }));
65
- }
66
- catch (e) {
67
- throw wrapError(e);
68
- }
69
- }
70
- }
71
- export function buildProjectProto(input) {
72
- const members = input.members?.map(r => create(ApiResourceReferenceSchema, r));
73
- return Object.assign(create(ProjectSchema), {
74
- apiVersion: "tenancy.stigmer.ai/v1",
75
- kind: "Project",
76
- metadata: Object.assign(create(ApiResourceMetadataSchema), {
77
- ...(input.id && { id: input.id }),
78
- name: input.name,
79
- org: input.org,
80
- ...(input.slug && { slug: input.slug }),
81
- ...(input.labels && { labels: input.labels }),
82
- ...(input.visibility && { visibility: input.visibility }),
83
- }),
84
- spec: Object.assign(create(ProjectSpecSchema), stripUndefined({
85
- entryPoint: input.entryPoint,
86
- description: input.description,
87
- members,
88
- })),
89
- });
90
- }
91
- /**
92
- * Maps a fetched {@link Project} to a complete {@link ProjectInput} for `update()`.
93
- *
94
- * The update RPC replaces the ENTIRE spec — spread this mapper's output
95
- * and override only the fields you edit (spread nested objects the same
96
- * way):
97
- *
98
- * await client.update({ ...toProjectUpdateInput(res), description: next });
99
- *
100
- * Proto3 defaults normalize to `undefined`; resource references keep
101
- * `version` (pinned refs) and `kind`.
102
- */
103
- export function toProjectUpdateInput(resource) {
104
- const meta = resource.metadata;
105
- const spec = resource.spec ?? create(ProjectSpecSchema);
106
- return {
107
- // Exact update addressing (id-first in the update pipeline) — for
108
- // platform-scoped (org-less) kinds the org+slug fallback cannot
109
- // match, so the id is the ONLY working address.
110
- id: meta?.id || undefined,
111
- name: meta?.name ?? "",
112
- slug: meta?.slug || undefined,
113
- org: meta?.org ?? "",
114
- labels: meta?.labels && Object.keys(meta.labels).length > 0 ? { ...meta.labels } : undefined,
115
- visibility: meta?.visibility || undefined,
116
- entryPoint: spec.entryPoint || undefined,
117
- description: spec.description || undefined,
118
- members: toResourceRefInputs(spec.members),
119
- };
120
- }
121
- //# sourceMappingURL=project.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"project.js","sourceRoot":"","sources":["../../src/gen/project.ts"],"names":[],"mappings":"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"}
@@ -1,135 +0,0 @@
1
- // Code generated by stigmer-codegen. DO NOT EDIT.
2
-
3
- import { wrapError } from "./errors.js";
4
- import { stripUndefined, toResourceRefInputs } from "./proto-utils.js";
5
- import { type ResourceRef } from "./types.js";
6
- import { create } from "@bufbuild/protobuf";
7
- import { createClient, type Client, type Transport } from "@connectrpc/connect";
8
- import { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
9
- import { ApiResourceVisibility } from "@stigmer/protos/ai/stigmer/commons/apiresource/enum_pb";
10
- import { ApiResourceReferenceSchema } from "@stigmer/protos/ai/stigmer/commons/apiresource/io_pb";
11
- import { ApiResourceMetadataSchema } from "@stigmer/protos/ai/stigmer/commons/apiresource/metadata_pb";
12
- import { ProjectSchema, type Project } from "@stigmer/protos/ai/stigmer/tenancy/project/v1/api_pb";
13
- import { ProjectCommandController } from "@stigmer/protos/ai/stigmer/tenancy/project/v1/command_pb";
14
- import { ProjectIdSchema } from "@stigmer/protos/ai/stigmer/tenancy/project/v1/io_pb";
15
- import { ProjectQueryController } from "@stigmer/protos/ai/stigmer/tenancy/project/v1/query_pb";
16
- import { ProjectSpecSchema } from "@stigmer/protos/ai/stigmer/tenancy/project/v1/spec_pb";
17
-
18
- /** Provides operations on project resources. */
19
- export class ProjectClient {
20
- private readonly command: Client<typeof ProjectCommandController>;
21
- private readonly query: Client<typeof ProjectQueryController>;
22
-
23
- constructor(transport: Transport) {
24
- this.command = createClient(ProjectCommandController, transport);
25
- this.query = createClient(ProjectQueryController, transport);
26
- }
27
-
28
- async apply(input: ProjectInput): Promise<Project> {
29
- try {
30
- return await this.command.apply(buildProjectProto(input));
31
- } catch (e) { throw wrapError(e); }
32
- }
33
-
34
- async create(input: ProjectInput): Promise<Project> {
35
- try {
36
- return await this.command.create(buildProjectProto(input));
37
- } catch (e) { throw wrapError(e); }
38
- }
39
-
40
- async update(input: ProjectInput): Promise<Project> {
41
- try {
42
- return await this.command.update(buildProjectProto(input));
43
- } catch (e) { throw wrapError(e); }
44
- }
45
-
46
- async delete(id: string): Promise<Project> {
47
- try {
48
- return await this.command.delete(create(ProjectIdSchema, { value: id }));
49
- } catch (e) { throw wrapError(e); }
50
- }
51
-
52
- async get(id: string): Promise<Project> {
53
- try {
54
- return await this.query.get(create(ProjectIdSchema, { value: id }));
55
- } catch (e) { throw wrapError(e); }
56
- }
57
-
58
- async getByReference(ref: ResourceRef): Promise<Project> {
59
- try {
60
- return await this.query.getByReference(create(ApiResourceReferenceSchema, { ...ref, kind: ApiResourceKind.project }));
61
- } catch (e) { throw wrapError(e); }
62
- }
63
- }
64
-
65
- /** Input for creating/updating a Project. */
66
- export interface ProjectInput {
67
- /**
68
- * The resource's `metadata.id`, for exact update addressing when set
69
- * from a loaded resource. Required for updates to platform-scoped
70
- * (org-less) kinds, where the org+slug fallback cannot match. On
71
- * create, the cloud server stamps its own id regardless; the OSS
72
- * server honors a caller-supplied id (existing apply semantics).
73
- */
74
- id?: string;
75
- name: string;
76
- slug?: string;
77
- org: string;
78
- labels?: Record<string, string>;
79
- visibility?: ApiResourceVisibility;
80
- entryPoint?: string;
81
- description?: string;
82
- members?: ResourceRef[];
83
- }
84
-
85
- export function buildProjectProto(input: ProjectInput): Project {
86
- const members = input.members?.map(r => create(ApiResourceReferenceSchema, r));
87
- return Object.assign(create(ProjectSchema), {
88
- apiVersion: "tenancy.stigmer.ai/v1",
89
- kind: "Project",
90
- metadata: Object.assign(create(ApiResourceMetadataSchema), {
91
- ...(input.id && { id: input.id }),
92
- name: input.name,
93
- org: input.org,
94
- ...(input.slug && { slug: input.slug }),
95
- ...(input.labels && { labels: input.labels }),
96
- ...(input.visibility && { visibility: input.visibility }),
97
- }),
98
- spec: Object.assign(create(ProjectSpecSchema), stripUndefined({
99
- entryPoint: input.entryPoint,
100
- description: input.description,
101
- members,
102
- })),
103
- }) as Project;
104
- }
105
-
106
- /**
107
- * Maps a fetched {@link Project} to a complete {@link ProjectInput} for `update()`.
108
- *
109
- * The update RPC replaces the ENTIRE spec — spread this mapper's output
110
- * and override only the fields you edit (spread nested objects the same
111
- * way):
112
- *
113
- * await client.update({ ...toProjectUpdateInput(res), description: next });
114
- *
115
- * Proto3 defaults normalize to `undefined`; resource references keep
116
- * `version` (pinned refs) and `kind`.
117
- */
118
- export function toProjectUpdateInput(resource: Project): ProjectInput {
119
- const meta = resource.metadata;
120
- const spec = resource.spec ?? create(ProjectSpecSchema);
121
- return {
122
- // Exact update addressing (id-first in the update pipeline) — for
123
- // platform-scoped (org-less) kinds the org+slug fallback cannot
124
- // match, so the id is the ONLY working address.
125
- id: meta?.id || undefined,
126
- name: meta?.name ?? "",
127
- slug: meta?.slug || undefined,
128
- org: meta?.org ?? "",
129
- labels: meta?.labels && Object.keys(meta.labels).length > 0 ? { ...meta.labels } : undefined,
130
- visibility: meta?.visibility || undefined,
131
- entryPoint: spec.entryPoint || undefined,
132
- description: spec.description || undefined,
133
- members: toResourceRefInputs(spec.members),
134
- };
135
- }
@@ -1,171 +0,0 @@
1
- // Tests for the `@stigmer/sdk/synth` producer: explicit synth writes the
2
- // reader-contract file names in order, each artifact round-trips through
3
- // fromBinary, skills serialize both local and git sources, async builders are
4
- // awaited, and a missing out dir produces actionable guidance.
5
-
6
- import { mkdtempSync, readFileSync, rmSync } from "node:fs";
7
- import { tmpdir } from "node:os";
8
- import { join } from "node:path";
9
- import { fromBinary } from "@bufbuild/protobuf";
10
- import { AgentSchema } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/api_pb";
11
- import { McpServerSchema } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/api_pb";
12
- import { SkillSynthSchema } from "@stigmer/protos/ai/stigmer/agentic/skill/v1/synth_pb";
13
- import { WorkflowSchema } from "@stigmer/protos/ai/stigmer/agentic/workflow/v1/api_pb";
14
- import { afterEach, beforeEach, describe, expect, it } from "vitest";
15
- import { defineProject } from "../index";
16
-
17
- let outDir: string;
18
-
19
- beforeEach(() => {
20
- outDir = mkdtempSync(join(tmpdir(), "stigmer-synth-"));
21
- });
22
-
23
- afterEach(() => {
24
- rmSync(outDir, { recursive: true, force: true });
25
- });
26
-
27
- function readProto<T>(schema: Parameters<typeof fromBinary>[0], name: string): T {
28
- return fromBinary(schema, readFileSync(join(outDir, name))) as T;
29
- }
30
-
31
- describe("defineProject().synth()", () => {
32
- it("writes per-kind, zero-indexed file names in registration order", async () => {
33
- const project = defineProject((ctx) => {
34
- ctx.skill.fromDir("./skills/calculator");
35
- ctx.mcpServer({ name: "fs", org: "acme" });
36
- ctx.agent({ name: "support-bot", org: "acme", instructions: "help" });
37
- ctx.agent({ name: "sales-bot", org: "acme", instructions: "sell" });
38
- ctx.workflow({
39
- name: "onboard",
40
- org: "acme",
41
- document: { namespace: "acme", name: "onboard", version: "1.0.0" },
42
- });
43
- });
44
-
45
- const result = await project.synth({ outDir });
46
-
47
- expect(result.outDir).toBe(outDir);
48
- expect(result.counts).toEqual({ agents: 2, workflows: 1, mcpServers: 1, skills: 1 });
49
- expect(result.files).toEqual([
50
- "skill-0.pb",
51
- "mcpserver-0.pb",
52
- "agent-0.pb",
53
- "agent-1.pb",
54
- "workflow-0.pb",
55
- ]);
56
- });
57
-
58
- it("round-trips each kind through fromBinary", async () => {
59
- const project = defineProject((ctx) => {
60
- ctx.agent({ name: "support-bot", org: "acme", instructions: "be helpful" });
61
- ctx.workflow({
62
- name: "onboard",
63
- org: "acme",
64
- document: { namespace: "acme", name: "onboard", version: "2.1.0" },
65
- });
66
- ctx.mcpServer({ name: "filesystem", org: "acme" });
67
- });
68
-
69
- await project.synth({ outDir });
70
-
71
- const agent = readProto<{ metadata?: { name: string; org: string }; spec?: { instructions: string } }>(
72
- AgentSchema,
73
- "agent-0.pb",
74
- );
75
- expect(agent.metadata?.name).toBe("support-bot");
76
- expect(agent.metadata?.org).toBe("acme");
77
- expect(agent.spec?.instructions).toBe("be helpful");
78
-
79
- const workflow = readProto<{ spec?: { document?: { name: string; version: string } } }>(
80
- WorkflowSchema,
81
- "workflow-0.pb",
82
- );
83
- expect(workflow.spec?.document?.name).toBe("onboard");
84
- expect(workflow.spec?.document?.version).toBe("2.1.0");
85
-
86
- const mcp = readProto<{ metadata?: { name: string } }>(McpServerSchema, "mcpserver-0.pb");
87
- expect(mcp.metadata?.name).toBe("filesystem");
88
- });
89
-
90
- it("serializes skills from a local directory", async () => {
91
- const project = defineProject((ctx) => {
92
- ctx.skill.fromDir("./skills/calculator", { tag: "stable" });
93
- });
94
- await project.synth({ outDir });
95
-
96
- const synth = readProto<{ source: { case: string; value: { path: string } }; tag: string }>(
97
- SkillSynthSchema,
98
- "skill-0.pb",
99
- );
100
- expect(synth.source.case).toBe("local");
101
- expect(synth.source.value.path).toBe("./skills/calculator");
102
- expect(synth.tag).toBe("stable");
103
- });
104
-
105
- it("serializes skills from a git repository", async () => {
106
- const project = defineProject((ctx) => {
107
- ctx.skill.fromGit({ url: "https://github.com/acme/skills.git", ref: "v1", subdir: "calc" });
108
- });
109
- await project.synth({ outDir });
110
-
111
- const synth = readProto<{ source: { case: string; value: { url: string; ref: string; subdir: string } } }>(
112
- SkillSynthSchema,
113
- "skill-0.pb",
114
- );
115
- expect(synth.source.case).toBe("git");
116
- expect(synth.source.value.url).toBe("https://github.com/acme/skills.git");
117
- expect(synth.source.value.ref).toBe("v1");
118
- expect(synth.source.value.subdir).toBe("calc");
119
- });
120
-
121
- it("awaits an async builder", async () => {
122
- const project = defineProject(async (ctx) => {
123
- await Promise.resolve();
124
- ctx.agent({ name: "async-bot", org: "acme", instructions: "later" });
125
- });
126
- const result = await project.synth({ outDir });
127
- expect(result.counts.agents).toBe(1);
128
- expect(readProto<{ metadata?: { name: string } }>(AgentSchema, "agent-0.pb").metadata?.name).toBe("async-bot");
129
- });
130
-
131
- it("defaults org from the synth({ org }) option when a resource omits it", async () => {
132
- const project = defineProject((ctx) => {
133
- ctx.agent({ name: "no-org-bot", org: "", instructions: "x" });
134
- });
135
- await project.synth({ outDir, org: "from-option" });
136
- expect(readProto<{ metadata?: { org: string } }>(AgentSchema, "agent-0.pb").metadata?.org).toBe("from-option");
137
- });
138
-
139
- it("does not run the builder until synth() is called", async () => {
140
- let ran = false;
141
- defineProject(() => {
142
- ran = true;
143
- });
144
- expect(ran).toBe(false);
145
- });
146
-
147
- it("throws actionable guidance when no out dir is resolvable", async () => {
148
- const saved = process.env.STIGMER_OUT_DIR;
149
- delete process.env.STIGMER_OUT_DIR;
150
- try {
151
- const project = defineProject((ctx) => ctx.agent({ name: "x", org: "acme", instructions: "x" }));
152
- await expect(project.synth()).rejects.toThrow(/no synthesis output directory/);
153
- await expect(project.synth()).rejects.toThrow(/stigmer apply/);
154
- } finally {
155
- if (saved !== undefined) process.env.STIGMER_OUT_DIR = saved;
156
- }
157
- });
158
-
159
- it("resolves the out dir from STIGMER_OUT_DIR when no option is passed", async () => {
160
- const saved = process.env.STIGMER_OUT_DIR;
161
- process.env.STIGMER_OUT_DIR = outDir;
162
- try {
163
- const project = defineProject((ctx) => ctx.agent({ name: "env-bot", org: "acme", instructions: "x" }));
164
- const result = await project.synth();
165
- expect(result.outDir).toBe(outDir);
166
- } finally {
167
- if (saved !== undefined) process.env.STIGMER_OUT_DIR = saved;
168
- else delete process.env.STIGMER_OUT_DIR;
169
- }
170
- });
171
- });
@@ -1,141 +0,0 @@
1
- // ProjectContext — the resource-registration surface handed to a
2
- // `defineProject` builder.
3
- //
4
- // Each `ctx.<kind>()` records one ergonomic `*Input` (the very types the
5
- // `@stigmer/sdk` resource clients already accept) in registration order;
6
- // `ctx.skill.fromDir` / `ctx.skill.fromGit` record a `SkillSynth` handover
7
- // message (the SDK→CLI contract from `synth.proto`). The writer later turns
8
- // these registrations into the `.pb` files the CLI consumes. Reusing the
9
- // `*Input` types — not a new authoring vocabulary — keeps the synthesis surface
10
- // identical to the imperative SDK, so there is exactly one way to describe a
11
- // resource in TypeScript (DD-009 §1, §4).
12
- //
13
- // Org defaults from `STIGMER_ORG_ID` when a resource omits it, mirroring the
14
- // CLI's org injection (apply.ts `injectOrg`) so a project authored without an
15
- // explicit org still synthesizes to valid protos when run via `stigmer apply`.
16
-
17
- import { create } from "@bufbuild/protobuf";
18
- import {
19
- GitSchema,
20
- LocalDirSchema,
21
- type SkillSynth,
22
- SkillSynthSchema,
23
- } from "@stigmer/protos/ai/stigmer/agentic/skill/v1/synth_pb";
24
- import type { AgentInput } from "../gen/agent.js";
25
- import type { McpServerInput } from "../gen/mcpserver.js";
26
- import type { WorkflowInput } from "../gen/workflow.js";
27
-
28
- /** Options for registering a skill from a local directory. */
29
- export interface SkillFromDirOptions {
30
- /** Mutable version tag (the CLI defaults this to "latest" at push time). */
31
- readonly tag?: string;
32
- }
33
-
34
- /** Input for registering a skill sourced from a remote git repository. */
35
- export interface SkillFromGitInput {
36
- /** Git repository URL (HTTPS or SSH). */
37
- readonly url: string;
38
- /** Tag, branch, or commit SHA; empty resolves to the default branch. */
39
- readonly ref?: string;
40
- /** Subdirectory within the repo that holds SKILL.md; empty = repo root. */
41
- readonly subdir?: string;
42
- /** Mutable version tag (the CLI defaults this to "latest" at push time). */
43
- readonly tag?: string;
44
- }
45
-
46
- // Opaque registration record returned by ctx.skill.* so the builder reads
47
- // naturally (and to leave room for future linkage ergonomics). Agents reference
48
- // skills by slug via AgentInput.skillRefs, exactly as in the declarative track —
49
- // a skill's slug is its SKILL.md name, which the backend assigns at push time.
50
- export interface SkillHandle {
51
- readonly kind: "skill";
52
- readonly synth: SkillSynth;
53
- }
54
-
55
- /** One ordered registration captured by the context. */
56
- export type Registration =
57
- | { readonly kind: "agent"; readonly input: AgentInput }
58
- | { readonly kind: "workflow"; readonly input: WorkflowInput }
59
- | { readonly kind: "mcpServer"; readonly input: McpServerInput }
60
- | { readonly kind: "skill"; readonly synth: SkillSynth };
61
-
62
- /** The resource-registration API passed to a `defineProject` builder. */
63
- export interface ProjectContext {
64
- /** Register an agent for synthesis. */
65
- agent(input: AgentInput): void;
66
- /** Register a workflow for synthesis. */
67
- workflow(input: WorkflowInput): void;
68
- /** Register an MCP server for synthesis. */
69
- mcpServer(input: McpServerInput): void;
70
- /** Register skills sourced from a local directory or a git repository. */
71
- readonly skill: {
72
- fromDir(path: string, opts?: SkillFromDirOptions): SkillHandle;
73
- fromGit(input: SkillFromGitInput): SkillHandle;
74
- };
75
- }
76
-
77
- /**
78
- * Concrete {@link ProjectContext} that accumulates registrations in order.
79
- * `defineProject` runs the user's builder against one of these, then hands the
80
- * collected registrations to the writer.
81
- */
82
- export class RegistrationContext implements ProjectContext {
83
- private readonly registrations: Registration[] = [];
84
- private readonly defaultOrg: string;
85
-
86
- constructor(defaultOrg: string = process.env.STIGMER_ORG_ID ?? "") {
87
- this.defaultOrg = defaultOrg;
88
- }
89
-
90
- agent(input: AgentInput): void {
91
- this.registrations.push({ kind: "agent", input: this.withOrg(input) });
92
- }
93
-
94
- workflow(input: WorkflowInput): void {
95
- this.registrations.push({ kind: "workflow", input: this.withOrg(input) });
96
- }
97
-
98
- mcpServer(input: McpServerInput): void {
99
- this.registrations.push({ kind: "mcpServer", input: this.withOrg(input) });
100
- }
101
-
102
- readonly skill = {
103
- fromDir: (path: string, opts?: SkillFromDirOptions): SkillHandle => {
104
- const synth = create(SkillSynthSchema, {
105
- source: { case: "local", value: create(LocalDirSchema, { path }) },
106
- tag: opts?.tag ?? "",
107
- });
108
- this.registrations.push({ kind: "skill", synth });
109
- return { kind: "skill", synth };
110
- },
111
- fromGit: (input: SkillFromGitInput): SkillHandle => {
112
- const synth = create(SkillSynthSchema, {
113
- source: {
114
- case: "git",
115
- value: create(GitSchema, {
116
- url: input.url,
117
- ref: input.ref ?? "",
118
- subdir: input.subdir ?? "",
119
- }),
120
- },
121
- tag: input.tag ?? "",
122
- });
123
- this.registrations.push({ kind: "skill", synth });
124
- return { kind: "skill", synth };
125
- },
126
- };
127
-
128
- /** Registrations captured so far, in builder-call order. */
129
- collect(): readonly Registration[] {
130
- return this.registrations;
131
- }
132
-
133
- // Fill org from STIGMER_ORG_ID only when the resource left it blank; an
134
- // explicit org always wins (the CLI later warns on org mismatch, not here).
135
- private withOrg<T extends { org: string }>(input: T): T {
136
- if (this.defaultOrg !== "" && (input.org === undefined || input.org === "")) {
137
- return { ...input, org: this.defaultOrg };
138
- }
139
- return input;
140
- }
141
- }
@@ -1,85 +0,0 @@
1
- // `@stigmer/sdk/synth` — the project-synthesis authoring API (the "producer").
2
- //
3
- // A user's entry point describes resources functionally and synthesizes them to
4
- // proto `.pb` files that `stigmer apply` consumes:
5
- //
6
- // import { defineProject } from "@stigmer/sdk/synth";
7
- //
8
- // const project = defineProject((ctx) => {
9
- // ctx.skill.fromDir("./skills/calculator");
10
- // ctx.agent({ name: "support-bot", org: "acme", instructions: "…" });
11
- // });
12
- //
13
- // await project.synth();
14
- //
15
- // `synth()` is EXPLICIT (no import-time / beforeExit magic): the builder runs
16
- // lazily inside it, honoring `@stigmer/sdk`'s `sideEffects: false` and staying
17
- // trivially testable via `synth({ outDir })` (DD-009 §1). Node-only — it writes
18
- // files — and exported from the dedicated `/synth` subpath (DD-009 §2).
19
-
20
- import { RegistrationContext } from "./context.js";
21
- import { countRegistrations, type SynthCounts, writeRegistrations } from "./writer.js";
22
- import type { ProjectContext } from "./context.js";
23
-
24
- export type {
25
- ProjectContext,
26
- Registration,
27
- SkillFromDirOptions,
28
- SkillFromGitInput,
29
- SkillHandle,
30
- } from "./context.js";
31
- export type { SynthCounts, SynthFile } from "./writer.js";
32
- export { serializeRegistrations } from "./writer.js";
33
-
34
- /** Options for {@link ProjectApp.synth}. */
35
- export interface SynthOptions {
36
- /** Output directory; defaults to `process.env.STIGMER_OUT_DIR`. */
37
- readonly outDir?: string;
38
- /** Default org for resources that omit one; defaults to `STIGMER_ORG_ID`. */
39
- readonly org?: string;
40
- }
41
-
42
- /** Outcome of a synthesis run. */
43
- export interface SynthResult {
44
- /** Directory the `.pb` files were written to. */
45
- readonly outDir: string;
46
- /** Names of the written `.pb` files, in registration order. */
47
- readonly files: readonly string[];
48
- /** Per-kind resource counts. */
49
- readonly counts: SynthCounts;
50
- }
51
-
52
- /** A builder that registers resources on the given context (sync or async). */
53
- export type ProjectBuilder = (ctx: ProjectContext) => void | Promise<void>;
54
-
55
- /** A synthesizable project produced by {@link defineProject}. */
56
- export interface ProjectApp {
57
- /** Run the builder and write the `.pb` artifacts; resolves to a summary. */
58
- synth(opts?: SynthOptions): Promise<SynthResult>;
59
- }
60
-
61
- /**
62
- * Define a synthesizable project. The `build` callback is NOT run here — it runs
63
- * lazily inside {@link ProjectApp.synth}, so importing the module has no side
64
- * effects and the same app can be synthesized to different out dirs in tests.
65
- */
66
- export function defineProject(build: ProjectBuilder): ProjectApp {
67
- return {
68
- async synth(opts?: SynthOptions): Promise<SynthResult> {
69
- const outDir = opts?.outDir ?? process.env.STIGMER_OUT_DIR;
70
- if (outDir === undefined || outDir === "") {
71
- throw new Error(
72
- "no synthesis output directory\n\n" +
73
- "Run this project via `stigmer apply` (which sets STIGMER_OUT_DIR), " +
74
- "or call project.synth({ outDir }) with an explicit directory.",
75
- );
76
- }
77
-
78
- const ctx = new RegistrationContext(opts?.org ?? process.env.STIGMER_ORG_ID ?? "");
79
- await build(ctx);
80
- const registrations = ctx.collect();
81
- const files = writeRegistrations(outDir, registrations);
82
- return { outDir, files, counts: countRegistrations(registrations) };
83
- },
84
- };
85
- }