@stigmer/sdk 3.19.0 → 3.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -1
- package/__tests__/update-input-roundtrip.test.js +0 -20
- package/__tests__/update-input-roundtrip.test.js.map +1 -1
- package/gen/authorization-config.d.ts.map +1 -1
- package/gen/authorization-config.js +0 -1
- package/gen/authorization-config.js.map +1 -1
- package/gen/client.d.ts +0 -4
- package/gen/client.d.ts.map +1 -1
- package/gen/client.js +0 -4
- package/gen/client.js.map +1 -1
- package/gen/resource-availability.d.ts.map +1 -1
- package/gen/resource-availability.js +0 -1
- package/gen/resource-availability.js.map +1 -1
- package/index.d.ts +0 -1
- package/index.d.ts.map +1 -1
- package/index.js +0 -1
- package/index.js.map +1 -1
- package/package.json +2 -6
- package/src/__tests__/update-input-roundtrip.test.ts +0 -28
- package/src/gen/authorization-config.ts +0 -1
- package/src/gen/client.ts +0 -5
- package/src/gen/resource-availability.ts +0 -1
- package/src/index.ts +0 -5
- package/gen/project.d.ts +0 -50
- package/gen/project.d.ts.map +0 -1
- package/gen/project.js +0 -121
- package/gen/project.js.map +0 -1
- package/src/gen/project.ts +0 -135
- package/src/synth/__tests__/synth.test.ts +0 -171
- package/src/synth/context.ts +0 -141
- package/src/synth/index.ts +0 -85
- package/src/synth/writer.ts +0 -100
- package/src/synth.ts +0 -8
- package/synth/__tests__/synth.test.d.ts +0 -2
- package/synth/__tests__/synth.test.d.ts.map +0 -1
- package/synth/__tests__/synth.test.js +0 -143
- package/synth/__tests__/synth.test.js.map +0 -1
- package/synth/context.d.ts +0 -73
- package/synth/context.d.ts.map +0 -1
- package/synth/context.js +0 -76
- package/synth/context.js.map +0 -1
- package/synth/index.d.ts +0 -35
- package/synth/index.d.ts.map +0 -1
- package/synth/index.js +0 -44
- package/synth/index.js.map +0 -1
- package/synth/writer.d.ts +0 -28
- package/synth/writer.d.ts.map +0 -1
- package/synth/writer.js +0 -86
- package/synth/writer.js.map +0 -1
- package/synth.d.ts +0 -2
- package/synth.d.ts.map +0 -1
- package/synth.js +0 -8
- 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
|
package/gen/project.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"project.js","sourceRoot":"","sources":["../../src/gen/project.ts"],"names":[],"mappings":"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"}
|
package/src/gen/project.ts
DELETED
|
@@ -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
|
-
});
|
package/src/synth/context.ts
DELETED
|
@@ -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
|
-
}
|
package/src/synth/index.ts
DELETED
|
@@ -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
|
-
}
|