@stigmer/sdk 3.0.8-dev.20260613074252 → 3.0.8
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/execution/tool-view.d.ts +7 -0
- package/execution/tool-view.d.ts.map +1 -1
- package/execution/tool-view.js +14 -0
- package/execution/tool-view.js.map +1 -1
- package/gen/agent.d.ts +1 -0
- package/gen/agent.d.ts.map +1 -1
- package/gen/agent.js +1 -1
- package/gen/agent.js.map +1 -1
- package/gen/agentexecution.d.ts +1 -0
- package/gen/agentexecution.d.ts.map +1 -1
- package/gen/agentexecution.js +1 -1
- package/gen/agentexecution.js.map +1 -1
- package/gen/agentinstance.d.ts +1 -0
- package/gen/agentinstance.d.ts.map +1 -1
- package/gen/agentinstance.js +1 -1
- package/gen/agentinstance.js.map +1 -1
- package/gen/apikey.d.ts +1 -0
- package/gen/apikey.d.ts.map +1 -1
- package/gen/apikey.js +1 -1
- package/gen/apikey.js.map +1 -1
- package/gen/artifact.d.ts +1 -0
- package/gen/artifact.d.ts.map +1 -1
- package/gen/artifact.js +1 -1
- package/gen/artifact.js.map +1 -1
- package/gen/environment.d.ts +1 -0
- package/gen/environment.d.ts.map +1 -1
- package/gen/environment.js +1 -1
- package/gen/environment.js.map +1 -1
- package/gen/executioncontext.d.ts +1 -0
- package/gen/executioncontext.d.ts.map +1 -1
- package/gen/executioncontext.js +1 -1
- package/gen/executioncontext.js.map +1 -1
- package/gen/iampolicy.d.ts +1 -0
- package/gen/iampolicy.d.ts.map +1 -1
- package/gen/iampolicy.js +1 -1
- package/gen/iampolicy.js.map +1 -1
- package/gen/identityaccount.d.ts +1 -0
- package/gen/identityaccount.d.ts.map +1 -1
- package/gen/identityaccount.js +1 -1
- package/gen/identityaccount.js.map +1 -1
- package/gen/identityprovider.d.ts +1 -0
- package/gen/identityprovider.d.ts.map +1 -1
- package/gen/identityprovider.js +1 -1
- package/gen/identityprovider.js.map +1 -1
- package/gen/invitation.d.ts +1 -0
- package/gen/invitation.d.ts.map +1 -1
- package/gen/invitation.js +1 -1
- package/gen/invitation.js.map +1 -1
- package/gen/mcpserver.d.ts +1 -0
- package/gen/mcpserver.d.ts.map +1 -1
- package/gen/mcpserver.js +1 -1
- package/gen/mcpserver.js.map +1 -1
- package/gen/oauthapp.d.ts +1 -0
- package/gen/oauthapp.d.ts.map +1 -1
- package/gen/oauthapp.js +1 -1
- package/gen/oauthapp.js.map +1 -1
- package/gen/organization.d.ts +1 -0
- package/gen/organization.d.ts.map +1 -1
- package/gen/organization.js +1 -1
- package/gen/organization.js.map +1 -1
- package/gen/platformclient.d.ts +1 -0
- package/gen/platformclient.d.ts.map +1 -1
- package/gen/platformclient.js +1 -1
- package/gen/platformclient.js.map +1 -1
- package/gen/project.d.ts +1 -0
- package/gen/project.d.ts.map +1 -1
- package/gen/project.js +1 -1
- package/gen/project.js.map +1 -1
- package/gen/session.d.ts +1 -0
- package/gen/session.d.ts.map +1 -1
- package/gen/session.js +1 -1
- package/gen/session.js.map +1 -1
- package/gen/skill.d.ts +1 -0
- package/gen/skill.d.ts.map +1 -1
- package/gen/skill.js +1 -1
- package/gen/skill.js.map +1 -1
- package/gen/workflow.d.ts +1 -0
- package/gen/workflow.d.ts.map +1 -1
- package/gen/workflow.js +1 -1
- package/gen/workflow.js.map +1 -1
- package/gen/workflowexecution.d.ts +1 -0
- package/gen/workflowexecution.d.ts.map +1 -1
- package/gen/workflowexecution.js +1 -1
- package/gen/workflowexecution.js.map +1 -1
- package/gen/workflowinstance.d.ts +1 -0
- package/gen/workflowinstance.d.ts.map +1 -1
- package/gen/workflowinstance.js +1 -1
- package/gen/workflowinstance.js.map +1 -1
- package/package.json +6 -2
- package/src/execution/tool-view.ts +26 -0
- package/src/gen/agent.ts +1 -1
- package/src/gen/agentexecution.ts +1 -1
- package/src/gen/agentinstance.ts +1 -1
- package/src/gen/apikey.ts +1 -1
- package/src/gen/artifact.ts +1 -1
- package/src/gen/environment.ts +1 -1
- package/src/gen/executioncontext.ts +1 -1
- package/src/gen/iampolicy.ts +1 -1
- package/src/gen/identityaccount.ts +1 -1
- package/src/gen/identityprovider.ts +1 -1
- package/src/gen/invitation.ts +1 -1
- package/src/gen/mcpserver.ts +1 -1
- package/src/gen/oauthapp.ts +1 -1
- package/src/gen/organization.ts +1 -1
- package/src/gen/platformclient.ts +1 -1
- package/src/gen/project.ts +1 -1
- package/src/gen/session.ts +1 -1
- package/src/gen/skill.ts +1 -1
- package/src/gen/workflow.ts +1 -1
- package/src/gen/workflowexecution.ts +1 -1
- package/src/gen/workflowinstance.ts +1 -1
- package/src/synth/__tests__/synth.test.ts +171 -0
- package/src/synth/context.ts +141 -0
- package/src/synth/index.ts +85 -0
- package/src/synth/writer.ts +100 -0
- package/src/synth.ts +8 -0
- package/synth/__tests__/synth.test.d.ts +2 -0
- package/synth/__tests__/synth.test.d.ts.map +1 -0
- package/synth/__tests__/synth.test.js +143 -0
- package/synth/__tests__/synth.test.js.map +1 -0
- package/synth/context.d.ts +73 -0
- package/synth/context.d.ts.map +1 -0
- package/synth/context.js +76 -0
- package/synth/context.js.map +1 -0
- package/synth/index.d.ts +35 -0
- package/synth/index.d.ts.map +1 -0
- package/synth/index.js +44 -0
- package/synth/index.js.map +1 -0
- package/synth/writer.d.ts +28 -0
- package/synth/writer.d.ts.map +1 -0
- package/synth/writer.js +86 -0
- package/synth/writer.js.map +1 -0
- package/synth.d.ts +2 -0
- package/synth.d.ts.map +1 -0
- package/synth.js +8 -0
- package/synth.js.map +1 -0
|
@@ -0,0 +1,141 @@
|
|
|
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";
|
|
25
|
+
import type { McpServerInput } from "../gen/mcpserver";
|
|
26
|
+
import type { WorkflowInput } from "../gen/workflow";
|
|
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
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
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";
|
|
21
|
+
import { countRegistrations, type SynthCounts, writeRegistrations } from "./writer";
|
|
22
|
+
import type { ProjectContext } from "./context";
|
|
23
|
+
|
|
24
|
+
export type {
|
|
25
|
+
ProjectContext,
|
|
26
|
+
Registration,
|
|
27
|
+
SkillFromDirOptions,
|
|
28
|
+
SkillFromGitInput,
|
|
29
|
+
SkillHandle,
|
|
30
|
+
} from "./context";
|
|
31
|
+
export type { SynthCounts, SynthFile } from "./writer";
|
|
32
|
+
export { serializeRegistrations } from "./writer";
|
|
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
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
// Writer — turns ordered {@link Registration}s into the proto `.pb` files the
|
|
2
|
+
// CLI's synthesis reader consumes.
|
|
3
|
+
//
|
|
4
|
+
// Each kind gets its own zero-based counter, producing `agent-N.pb`,
|
|
5
|
+
// `workflow-N.pb`, `mcpserver-N.pb`, and `skill-N.pb`. These names and the
|
|
6
|
+
// binary encoding are the SDK↔CLI handoff contract: they must match the reader's
|
|
7
|
+
// glob/sort (`<kind>-*.pb`, lexically sorted) on both the Go and TS consumers
|
|
8
|
+
// (reader.go / reader.ts). Resources are serialized via protobuf-es `toBinary`
|
|
9
|
+
// (DD-009 §3); the full proto is built by reusing the generated, package-private
|
|
10
|
+
// `build<Kind>Proto` helpers (DD-009 §4) so synthesis and the imperative SDK
|
|
11
|
+
// share one field mapping. Skills are already `SkillSynth` messages and are
|
|
12
|
+
// encoded directly.
|
|
13
|
+
|
|
14
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
15
|
+
import { join } from "node:path";
|
|
16
|
+
import { toBinary } from "@bufbuild/protobuf";
|
|
17
|
+
import { AgentSchema } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/api_pb";
|
|
18
|
+
import { McpServerSchema } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/api_pb";
|
|
19
|
+
import { SkillSynthSchema } from "@stigmer/protos/ai/stigmer/agentic/skill/v1/synth_pb";
|
|
20
|
+
import { WorkflowSchema } from "@stigmer/protos/ai/stigmer/agentic/workflow/v1/api_pb";
|
|
21
|
+
import { buildAgentProto } from "../gen/agent";
|
|
22
|
+
import { buildMcpServerProto } from "../gen/mcpserver";
|
|
23
|
+
import { buildWorkflowProto } from "../gen/workflow";
|
|
24
|
+
import type { Registration } from "./context";
|
|
25
|
+
|
|
26
|
+
/** One serialized synthesis artifact: its file name and binary proto bytes. */
|
|
27
|
+
export interface SynthFile {
|
|
28
|
+
readonly name: string;
|
|
29
|
+
readonly bytes: Uint8Array;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** Per-kind counts of synthesized resources. */
|
|
33
|
+
export interface SynthCounts {
|
|
34
|
+
readonly agents: number;
|
|
35
|
+
readonly workflows: number;
|
|
36
|
+
readonly mcpServers: number;
|
|
37
|
+
readonly skills: number;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Serialize registrations into named `.pb` artifacts, in registration order,
|
|
42
|
+
* with a per-kind zero-based index. Pure (no filesystem) so it is trivially
|
|
43
|
+
* unit-testable and reusable by callers that want the bytes without writing.
|
|
44
|
+
*/
|
|
45
|
+
export function serializeRegistrations(registrations: readonly Registration[]): SynthFile[] {
|
|
46
|
+
const next = { agent: 0, workflow: 0, mcpServer: 0, skill: 0 };
|
|
47
|
+
const files: SynthFile[] = [];
|
|
48
|
+
for (const reg of registrations) {
|
|
49
|
+
switch (reg.kind) {
|
|
50
|
+
case "agent":
|
|
51
|
+
files.push({ name: `agent-${next.agent++}.pb`, bytes: toBinary(AgentSchema, buildAgentProto(reg.input)) });
|
|
52
|
+
break;
|
|
53
|
+
case "workflow":
|
|
54
|
+
files.push({
|
|
55
|
+
name: `workflow-${next.workflow++}.pb`,
|
|
56
|
+
bytes: toBinary(WorkflowSchema, buildWorkflowProto(reg.input)),
|
|
57
|
+
});
|
|
58
|
+
break;
|
|
59
|
+
case "mcpServer":
|
|
60
|
+
files.push({
|
|
61
|
+
name: `mcpserver-${next.mcpServer++}.pb`,
|
|
62
|
+
bytes: toBinary(McpServerSchema, buildMcpServerProto(reg.input)),
|
|
63
|
+
});
|
|
64
|
+
break;
|
|
65
|
+
case "skill":
|
|
66
|
+
files.push({ name: `skill-${next.skill++}.pb`, bytes: toBinary(SkillSynthSchema, reg.synth) });
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return files;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Tally registrations by kind (for the synth result summary). */
|
|
74
|
+
export function countRegistrations(registrations: readonly Registration[]): SynthCounts {
|
|
75
|
+
let agents = 0;
|
|
76
|
+
let workflows = 0;
|
|
77
|
+
let mcpServers = 0;
|
|
78
|
+
let skills = 0;
|
|
79
|
+
for (const reg of registrations) {
|
|
80
|
+
if (reg.kind === "agent") agents++;
|
|
81
|
+
else if (reg.kind === "workflow") workflows++;
|
|
82
|
+
else if (reg.kind === "mcpServer") mcpServers++;
|
|
83
|
+
else skills++;
|
|
84
|
+
}
|
|
85
|
+
return { agents, workflows, mcpServers, skills };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Serialize and write all registrations into `outDir`, returning the written
|
|
90
|
+
* file names. The directory is created if absent (idempotent) — synthesis owns
|
|
91
|
+
* its output target, like CDK's `app.synth()` creating `cdk.out`.
|
|
92
|
+
*/
|
|
93
|
+
export function writeRegistrations(outDir: string, registrations: readonly Registration[]): string[] {
|
|
94
|
+
const files = serializeRegistrations(registrations);
|
|
95
|
+
mkdirSync(outDir, { recursive: true });
|
|
96
|
+
for (const file of files) {
|
|
97
|
+
writeFileSync(join(outDir, file.name), file.bytes);
|
|
98
|
+
}
|
|
99
|
+
return files.map((file) => file.name);
|
|
100
|
+
}
|
package/src/synth.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// Node-only entry point for the project-synthesis authoring API.
|
|
2
|
+
//
|
|
3
|
+
// Re-exports `@stigmer/sdk/synth` (see ./synth/index.ts). Kept as a thin
|
|
4
|
+
// top-level module so the package `exports` map can expose `"./synth"` the same
|
|
5
|
+
// way `"./node"` maps to ./node.ts — a capability subpath, not a client noun
|
|
6
|
+
// (DD-009 §2).
|
|
7
|
+
|
|
8
|
+
export * from "./synth/index.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"synth.test.d.ts","sourceRoot":"","sources":["../../../src/synth/__tests__/synth.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,143 @@
|
|
|
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
|
+
import { mkdtempSync, readFileSync, rmSync } from "node:fs";
|
|
6
|
+
import { tmpdir } from "node:os";
|
|
7
|
+
import { join } from "node:path";
|
|
8
|
+
import { fromBinary } from "@bufbuild/protobuf";
|
|
9
|
+
import { AgentSchema } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/api_pb";
|
|
10
|
+
import { McpServerSchema } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/api_pb";
|
|
11
|
+
import { SkillSynthSchema } from "@stigmer/protos/ai/stigmer/agentic/skill/v1/synth_pb";
|
|
12
|
+
import { WorkflowSchema } from "@stigmer/protos/ai/stigmer/agentic/workflow/v1/api_pb";
|
|
13
|
+
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
14
|
+
import { defineProject } from "../index";
|
|
15
|
+
let outDir;
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
outDir = mkdtempSync(join(tmpdir(), "stigmer-synth-"));
|
|
18
|
+
});
|
|
19
|
+
afterEach(() => {
|
|
20
|
+
rmSync(outDir, { recursive: true, force: true });
|
|
21
|
+
});
|
|
22
|
+
function readProto(schema, name) {
|
|
23
|
+
return fromBinary(schema, readFileSync(join(outDir, name)));
|
|
24
|
+
}
|
|
25
|
+
describe("defineProject().synth()", () => {
|
|
26
|
+
it("writes per-kind, zero-indexed file names in registration order", async () => {
|
|
27
|
+
const project = defineProject((ctx) => {
|
|
28
|
+
ctx.skill.fromDir("./skills/calculator");
|
|
29
|
+
ctx.mcpServer({ name: "fs", org: "acme" });
|
|
30
|
+
ctx.agent({ name: "support-bot", org: "acme", instructions: "help" });
|
|
31
|
+
ctx.agent({ name: "sales-bot", org: "acme", instructions: "sell" });
|
|
32
|
+
ctx.workflow({
|
|
33
|
+
name: "onboard",
|
|
34
|
+
org: "acme",
|
|
35
|
+
document: { namespace: "acme", name: "onboard", version: "1.0.0" },
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
const result = await project.synth({ outDir });
|
|
39
|
+
expect(result.outDir).toBe(outDir);
|
|
40
|
+
expect(result.counts).toEqual({ agents: 2, workflows: 1, mcpServers: 1, skills: 1 });
|
|
41
|
+
expect(result.files).toEqual([
|
|
42
|
+
"skill-0.pb",
|
|
43
|
+
"mcpserver-0.pb",
|
|
44
|
+
"agent-0.pb",
|
|
45
|
+
"agent-1.pb",
|
|
46
|
+
"workflow-0.pb",
|
|
47
|
+
]);
|
|
48
|
+
});
|
|
49
|
+
it("round-trips each kind through fromBinary", async () => {
|
|
50
|
+
const project = defineProject((ctx) => {
|
|
51
|
+
ctx.agent({ name: "support-bot", org: "acme", instructions: "be helpful" });
|
|
52
|
+
ctx.workflow({
|
|
53
|
+
name: "onboard",
|
|
54
|
+
org: "acme",
|
|
55
|
+
document: { namespace: "acme", name: "onboard", version: "2.1.0" },
|
|
56
|
+
});
|
|
57
|
+
ctx.mcpServer({ name: "filesystem", org: "acme" });
|
|
58
|
+
});
|
|
59
|
+
await project.synth({ outDir });
|
|
60
|
+
const agent = readProto(AgentSchema, "agent-0.pb");
|
|
61
|
+
expect(agent.metadata?.name).toBe("support-bot");
|
|
62
|
+
expect(agent.metadata?.org).toBe("acme");
|
|
63
|
+
expect(agent.spec?.instructions).toBe("be helpful");
|
|
64
|
+
const workflow = readProto(WorkflowSchema, "workflow-0.pb");
|
|
65
|
+
expect(workflow.spec?.document?.name).toBe("onboard");
|
|
66
|
+
expect(workflow.spec?.document?.version).toBe("2.1.0");
|
|
67
|
+
const mcp = readProto(McpServerSchema, "mcpserver-0.pb");
|
|
68
|
+
expect(mcp.metadata?.name).toBe("filesystem");
|
|
69
|
+
});
|
|
70
|
+
it("serializes skills from a local directory", async () => {
|
|
71
|
+
const project = defineProject((ctx) => {
|
|
72
|
+
ctx.skill.fromDir("./skills/calculator", { tag: "stable" });
|
|
73
|
+
});
|
|
74
|
+
await project.synth({ outDir });
|
|
75
|
+
const synth = readProto(SkillSynthSchema, "skill-0.pb");
|
|
76
|
+
expect(synth.source.case).toBe("local");
|
|
77
|
+
expect(synth.source.value.path).toBe("./skills/calculator");
|
|
78
|
+
expect(synth.tag).toBe("stable");
|
|
79
|
+
});
|
|
80
|
+
it("serializes skills from a git repository", async () => {
|
|
81
|
+
const project = defineProject((ctx) => {
|
|
82
|
+
ctx.skill.fromGit({ url: "https://github.com/acme/skills.git", ref: "v1", subdir: "calc" });
|
|
83
|
+
});
|
|
84
|
+
await project.synth({ outDir });
|
|
85
|
+
const synth = readProto(SkillSynthSchema, "skill-0.pb");
|
|
86
|
+
expect(synth.source.case).toBe("git");
|
|
87
|
+
expect(synth.source.value.url).toBe("https://github.com/acme/skills.git");
|
|
88
|
+
expect(synth.source.value.ref).toBe("v1");
|
|
89
|
+
expect(synth.source.value.subdir).toBe("calc");
|
|
90
|
+
});
|
|
91
|
+
it("awaits an async builder", async () => {
|
|
92
|
+
const project = defineProject(async (ctx) => {
|
|
93
|
+
await Promise.resolve();
|
|
94
|
+
ctx.agent({ name: "async-bot", org: "acme", instructions: "later" });
|
|
95
|
+
});
|
|
96
|
+
const result = await project.synth({ outDir });
|
|
97
|
+
expect(result.counts.agents).toBe(1);
|
|
98
|
+
expect(readProto(AgentSchema, "agent-0.pb").metadata?.name).toBe("async-bot");
|
|
99
|
+
});
|
|
100
|
+
it("defaults org from the synth({ org }) option when a resource omits it", async () => {
|
|
101
|
+
const project = defineProject((ctx) => {
|
|
102
|
+
ctx.agent({ name: "no-org-bot", org: "", instructions: "x" });
|
|
103
|
+
});
|
|
104
|
+
await project.synth({ outDir, org: "from-option" });
|
|
105
|
+
expect(readProto(AgentSchema, "agent-0.pb").metadata?.org).toBe("from-option");
|
|
106
|
+
});
|
|
107
|
+
it("does not run the builder until synth() is called", async () => {
|
|
108
|
+
let ran = false;
|
|
109
|
+
defineProject(() => {
|
|
110
|
+
ran = true;
|
|
111
|
+
});
|
|
112
|
+
expect(ran).toBe(false);
|
|
113
|
+
});
|
|
114
|
+
it("throws actionable guidance when no out dir is resolvable", async () => {
|
|
115
|
+
const saved = process.env.STIGMER_OUT_DIR;
|
|
116
|
+
delete process.env.STIGMER_OUT_DIR;
|
|
117
|
+
try {
|
|
118
|
+
const project = defineProject((ctx) => ctx.agent({ name: "x", org: "acme", instructions: "x" }));
|
|
119
|
+
await expect(project.synth()).rejects.toThrow(/no synthesis output directory/);
|
|
120
|
+
await expect(project.synth()).rejects.toThrow(/stigmer apply/);
|
|
121
|
+
}
|
|
122
|
+
finally {
|
|
123
|
+
if (saved !== undefined)
|
|
124
|
+
process.env.STIGMER_OUT_DIR = saved;
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
it("resolves the out dir from STIGMER_OUT_DIR when no option is passed", async () => {
|
|
128
|
+
const saved = process.env.STIGMER_OUT_DIR;
|
|
129
|
+
process.env.STIGMER_OUT_DIR = outDir;
|
|
130
|
+
try {
|
|
131
|
+
const project = defineProject((ctx) => ctx.agent({ name: "env-bot", org: "acme", instructions: "x" }));
|
|
132
|
+
const result = await project.synth();
|
|
133
|
+
expect(result.outDir).toBe(outDir);
|
|
134
|
+
}
|
|
135
|
+
finally {
|
|
136
|
+
if (saved !== undefined)
|
|
137
|
+
process.env.STIGMER_OUT_DIR = saved;
|
|
138
|
+
else
|
|
139
|
+
delete process.env.STIGMER_OUT_DIR;
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
//# sourceMappingURL=synth.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"synth.test.js","sourceRoot":"","sources":["../../../src/synth/__tests__/synth.test.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,yEAAyE;AACzE,8EAA8E;AAC9E,+DAA+D;AAE/D,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAC5D,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,oDAAoD,CAAC;AACjF,OAAO,EAAE,eAAe,EAAE,MAAM,wDAAwD,CAAC;AACzF,OAAO,EAAE,gBAAgB,EAAE,MAAM,sDAAsD,CAAC;AACxF,OAAO,EAAE,cAAc,EAAE,MAAM,uDAAuD,CAAC;AACvF,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,IAAI,MAAc,CAAC;AAEnB,UAAU,CAAC,GAAG,EAAE;IACd,MAAM,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,gBAAgB,CAAC,CAAC,CAAC;AACzD,CAAC,CAAC,CAAC;AAEH,SAAS,CAAC,GAAG,EAAE;IACb,MAAM,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;AACnD,CAAC,CAAC,CAAC;AAEH,SAAS,SAAS,CAAI,MAAwC,EAAE,IAAY;IAC1E,OAAO,UAAU,CAAC,MAAM,EAAE,YAAY,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAM,CAAC;AACnE,CAAC;AAED,QAAQ,CAAC,yBAAyB,EAAE,GAAG,EAAE;IACvC,EAAE,CAAC,gEAAgE,EAAE,KAAK,IAAI,EAAE;QAC9E,MAAM,OAAO,GAAG,aAAa,CAAC,CAAC,GAAG,EAAE,EAAE;YACpC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAAC;YACzC,GAAG,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;YAC3C,GAAG,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC,CAAC;YACtE,GAAG,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC,CAAC;YACpE,GAAG,CAAC,QAAQ,CAAC;gBACX,IAAI,EAAE,SAAS;gBACf,GAAG,EAAE,MAAM;gBACX,QAAQ,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE;aACnE,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;QAE/C,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACnC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;QACrF,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC;YAC3B,YAAY;YACZ,gBAAgB;YAChB,YAAY;YACZ,YAAY;YACZ,eAAe;SAChB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0CAA0C,EAAE,KAAK,IAAI,EAAE;QACxD,MAAM,OAAO,GAAG,aAAa,CAAC,CAAC,GAAG,EAAE,EAAE;YACpC,GAAG,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,YAAY,EAAE,CAAC,CAAC;YAC5E,GAAG,CAAC,QAAQ,CAAC;gBACX,IAAI,EAAE,SAAS;gBACf,GAAG,EAAE,MAAM;gBACX,QAAQ,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE;aACnE,CAAC,CAAC;YACH,GAAG,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;QACrD,CAAC,CAAC,CAAC;QAEH,MAAM,OAAO,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;QAEhC,MAAM,KAAK,GAAG,SAAS,CACrB,WAAW,EACX,YAAY,CACb,CAAC;QACF,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QACjD,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACzC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAEpD,MAAM,QAAQ,GAAG,SAAS,CACxB,cAAc,EACd,eAAe,CAChB,CAAC;QACF,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACtD,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAEvD,MAAM,GAAG,GAAG,SAAS,CAAkC,eAAe,EAAE,gBAAgB,CAAC,CAAC;QAC1F,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0CAA0C,EAAE,KAAK,IAAI,EAAE;QACxD,MAAM,OAAO,GAAG,aAAa,CAAC,CAAC,GAAG,EAAE,EAAE;YACpC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,qBAAqB,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC9D,CAAC,CAAC,CAAC;QACH,MAAM,OAAO,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;QAEhC,MAAM,KAAK,GAAG,SAAS,CACrB,gBAAgB,EAChB,YAAY,CACb,CAAC;QACF,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACxC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;QAC5D,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yCAAyC,EAAE,KAAK,IAAI,EAAE;QACvD,MAAM,OAAO,GAAG,aAAa,CAAC,CAAC,GAAG,EAAE,EAAE;YACpC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,oCAAoC,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;QAC9F,CAAC,CAAC,CAAC;QACH,MAAM,OAAO,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;QAEhC,MAAM,KAAK,GAAG,SAAS,CACrB,gBAAgB,EAChB,YAAY,CACb,CAAC;QACF,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACtC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,oCAAoC,CAAC,CAAC;QAC1E,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1C,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yBAAyB,EAAE,KAAK,IAAI,EAAE;QACvC,MAAM,OAAO,GAAG,aAAa,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;YAC1C,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;YACxB,GAAG,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC,CAAC;QACvE,CAAC,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;QAC/C,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACrC,MAAM,CAAC,SAAS,CAAkC,WAAW,EAAE,YAAY,CAAC,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACjH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sEAAsE,EAAE,KAAK,IAAI,EAAE;QACpF,MAAM,OAAO,GAAG,aAAa,CAAC,CAAC,GAAG,EAAE,EAAE;YACpC,GAAG,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,EAAE,EAAE,EAAE,YAAY,EAAE,GAAG,EAAE,CAAC,CAAC;QAChE,CAAC,CAAC,CAAC;QACH,MAAM,OAAO,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,EAAE,CAAC,CAAC;QACpD,MAAM,CAAC,SAAS,CAAiC,WAAW,EAAE,YAAY,CAAC,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IACjH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;QAChE,IAAI,GAAG,GAAG,KAAK,CAAC;QAChB,aAAa,CAAC,GAAG,EAAE;YACjB,GAAG,GAAG,IAAI,CAAC;QACb,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0DAA0D,EAAE,KAAK,IAAI,EAAE;QACxE,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;QAC1C,OAAO,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;QACnC,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,aAAa,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;YACjG,MAAM,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,+BAA+B,CAAC,CAAC;YAC/E,MAAM,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;QACjE,CAAC;gBAAS,CAAC;YACT,IAAI,KAAK,KAAK,SAAS;gBAAE,OAAO,CAAC,GAAG,CAAC,eAAe,GAAG,KAAK,CAAC;QAC/D,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oEAAoE,EAAE,KAAK,IAAI,EAAE;QAClF,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;QAC1C,OAAO,CAAC,GAAG,CAAC,eAAe,GAAG,MAAM,CAAC;QACrC,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,aAAa,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;YACvG,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;YACrC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACrC,CAAC;gBAAS,CAAC;YACT,IAAI,KAAK,KAAK,SAAS;gBAAE,OAAO,CAAC,GAAG,CAAC,eAAe,GAAG,KAAK,CAAC;;gBACxD,OAAO,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;QAC1C,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { type SkillSynth } from "@stigmer/protos/ai/stigmer/agentic/skill/v1/synth_pb";
|
|
2
|
+
import type { AgentInput } from "../gen/agent";
|
|
3
|
+
import type { McpServerInput } from "../gen/mcpserver";
|
|
4
|
+
import type { WorkflowInput } from "../gen/workflow";
|
|
5
|
+
/** Options for registering a skill from a local directory. */
|
|
6
|
+
export interface SkillFromDirOptions {
|
|
7
|
+
/** Mutable version tag (the CLI defaults this to "latest" at push time). */
|
|
8
|
+
readonly tag?: string;
|
|
9
|
+
}
|
|
10
|
+
/** Input for registering a skill sourced from a remote git repository. */
|
|
11
|
+
export interface SkillFromGitInput {
|
|
12
|
+
/** Git repository URL (HTTPS or SSH). */
|
|
13
|
+
readonly url: string;
|
|
14
|
+
/** Tag, branch, or commit SHA; empty resolves to the default branch. */
|
|
15
|
+
readonly ref?: string;
|
|
16
|
+
/** Subdirectory within the repo that holds SKILL.md; empty = repo root. */
|
|
17
|
+
readonly subdir?: string;
|
|
18
|
+
/** Mutable version tag (the CLI defaults this to "latest" at push time). */
|
|
19
|
+
readonly tag?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface SkillHandle {
|
|
22
|
+
readonly kind: "skill";
|
|
23
|
+
readonly synth: SkillSynth;
|
|
24
|
+
}
|
|
25
|
+
/** One ordered registration captured by the context. */
|
|
26
|
+
export type Registration = {
|
|
27
|
+
readonly kind: "agent";
|
|
28
|
+
readonly input: AgentInput;
|
|
29
|
+
} | {
|
|
30
|
+
readonly kind: "workflow";
|
|
31
|
+
readonly input: WorkflowInput;
|
|
32
|
+
} | {
|
|
33
|
+
readonly kind: "mcpServer";
|
|
34
|
+
readonly input: McpServerInput;
|
|
35
|
+
} | {
|
|
36
|
+
readonly kind: "skill";
|
|
37
|
+
readonly synth: SkillSynth;
|
|
38
|
+
};
|
|
39
|
+
/** The resource-registration API passed to a `defineProject` builder. */
|
|
40
|
+
export interface ProjectContext {
|
|
41
|
+
/** Register an agent for synthesis. */
|
|
42
|
+
agent(input: AgentInput): void;
|
|
43
|
+
/** Register a workflow for synthesis. */
|
|
44
|
+
workflow(input: WorkflowInput): void;
|
|
45
|
+
/** Register an MCP server for synthesis. */
|
|
46
|
+
mcpServer(input: McpServerInput): void;
|
|
47
|
+
/** Register skills sourced from a local directory or a git repository. */
|
|
48
|
+
readonly skill: {
|
|
49
|
+
fromDir(path: string, opts?: SkillFromDirOptions): SkillHandle;
|
|
50
|
+
fromGit(input: SkillFromGitInput): SkillHandle;
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Concrete {@link ProjectContext} that accumulates registrations in order.
|
|
55
|
+
* `defineProject` runs the user's builder against one of these, then hands the
|
|
56
|
+
* collected registrations to the writer.
|
|
57
|
+
*/
|
|
58
|
+
export declare class RegistrationContext implements ProjectContext {
|
|
59
|
+
private readonly registrations;
|
|
60
|
+
private readonly defaultOrg;
|
|
61
|
+
constructor(defaultOrg?: string);
|
|
62
|
+
agent(input: AgentInput): void;
|
|
63
|
+
workflow(input: WorkflowInput): void;
|
|
64
|
+
mcpServer(input: McpServerInput): void;
|
|
65
|
+
readonly skill: {
|
|
66
|
+
fromDir: (path: string, opts?: SkillFromDirOptions) => SkillHandle;
|
|
67
|
+
fromGit: (input: SkillFromGitInput) => SkillHandle;
|
|
68
|
+
};
|
|
69
|
+
/** Registrations captured so far, in builder-call order. */
|
|
70
|
+
collect(): readonly Registration[];
|
|
71
|
+
private withOrg;
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/synth/context.ts"],"names":[],"mappings":"AAiBA,OAAO,EAGL,KAAK,UAAU,EAEhB,MAAM,sDAAsD,CAAC;AAC9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD,8DAA8D;AAC9D,MAAM,WAAW,mBAAmB;IAClC,4EAA4E;IAC5E,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,0EAA0E;AAC1E,MAAM,WAAW,iBAAiB;IAChC,yCAAyC;IACzC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,wEAAwE;IACxE,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,4EAA4E;IAC5E,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;CACvB;AAMD,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;CAC5B;AAED,wDAAwD;AACxD,MAAM,MAAM,YAAY,GACpB;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAA;CAAE,GACtD;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAA;CAAE,GAC5D;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAA;CAAE,GAC9D;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAA;CAAE,CAAC;AAE3D,yEAAyE;AACzE,MAAM,WAAW,cAAc;IAC7B,uCAAuC;IACvC,KAAK,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;IAC/B,yCAAyC;IACzC,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,CAAC;IACrC,4CAA4C;IAC5C,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI,CAAC;IACvC,0EAA0E;IAC1E,QAAQ,CAAC,KAAK,EAAE;QACd,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,mBAAmB,GAAG,WAAW,CAAC;QAC/D,OAAO,CAAC,KAAK,EAAE,iBAAiB,GAAG,WAAW,CAAC;KAChD,CAAC;CACH;AAED;;;;GAIG;AACH,qBAAa,mBAAoB,YAAW,cAAc;IACxD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAsB;IACpD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;gBAExB,UAAU,GAAE,MAAyC;IAIjE,KAAK,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAI9B,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI;IAIpC,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI;IAItC,QAAQ,CAAC,KAAK;wBACI,MAAM,SAAS,mBAAmB,KAAG,WAAW;yBAQ/C,iBAAiB,KAAG,WAAW;MAehD;IAEF,4DAA4D;IAC5D,OAAO,IAAI,SAAS,YAAY,EAAE;IAMlC,OAAO,CAAC,OAAO;CAMhB"}
|
package/synth/context.js
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
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
|
+
import { create } from "@bufbuild/protobuf";
|
|
17
|
+
import { GitSchema, LocalDirSchema, SkillSynthSchema, } from "@stigmer/protos/ai/stigmer/agentic/skill/v1/synth_pb";
|
|
18
|
+
/**
|
|
19
|
+
* Concrete {@link ProjectContext} that accumulates registrations in order.
|
|
20
|
+
* `defineProject` runs the user's builder against one of these, then hands the
|
|
21
|
+
* collected registrations to the writer.
|
|
22
|
+
*/
|
|
23
|
+
export class RegistrationContext {
|
|
24
|
+
registrations = [];
|
|
25
|
+
defaultOrg;
|
|
26
|
+
constructor(defaultOrg = process.env.STIGMER_ORG_ID ?? "") {
|
|
27
|
+
this.defaultOrg = defaultOrg;
|
|
28
|
+
}
|
|
29
|
+
agent(input) {
|
|
30
|
+
this.registrations.push({ kind: "agent", input: this.withOrg(input) });
|
|
31
|
+
}
|
|
32
|
+
workflow(input) {
|
|
33
|
+
this.registrations.push({ kind: "workflow", input: this.withOrg(input) });
|
|
34
|
+
}
|
|
35
|
+
mcpServer(input) {
|
|
36
|
+
this.registrations.push({ kind: "mcpServer", input: this.withOrg(input) });
|
|
37
|
+
}
|
|
38
|
+
skill = {
|
|
39
|
+
fromDir: (path, opts) => {
|
|
40
|
+
const synth = create(SkillSynthSchema, {
|
|
41
|
+
source: { case: "local", value: create(LocalDirSchema, { path }) },
|
|
42
|
+
tag: opts?.tag ?? "",
|
|
43
|
+
});
|
|
44
|
+
this.registrations.push({ kind: "skill", synth });
|
|
45
|
+
return { kind: "skill", synth };
|
|
46
|
+
},
|
|
47
|
+
fromGit: (input) => {
|
|
48
|
+
const synth = create(SkillSynthSchema, {
|
|
49
|
+
source: {
|
|
50
|
+
case: "git",
|
|
51
|
+
value: create(GitSchema, {
|
|
52
|
+
url: input.url,
|
|
53
|
+
ref: input.ref ?? "",
|
|
54
|
+
subdir: input.subdir ?? "",
|
|
55
|
+
}),
|
|
56
|
+
},
|
|
57
|
+
tag: input.tag ?? "",
|
|
58
|
+
});
|
|
59
|
+
this.registrations.push({ kind: "skill", synth });
|
|
60
|
+
return { kind: "skill", synth };
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
/** Registrations captured so far, in builder-call order. */
|
|
64
|
+
collect() {
|
|
65
|
+
return this.registrations;
|
|
66
|
+
}
|
|
67
|
+
// Fill org from STIGMER_ORG_ID only when the resource left it blank; an
|
|
68
|
+
// explicit org always wins (the CLI later warns on org mismatch, not here).
|
|
69
|
+
withOrg(input) {
|
|
70
|
+
if (this.defaultOrg !== "" && (input.org === undefined || input.org === "")) {
|
|
71
|
+
return { ...input, org: this.defaultOrg };
|
|
72
|
+
}
|
|
73
|
+
return input;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/synth/context.ts"],"names":[],"mappings":"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"}
|