mirror of
https://github.com/profullstack/logicsrc.git
synced 2026-08-13 22:37:29 +00:00
Implement OpenSpec artifacts and SDK contracts
This commit is contained in:
parent
1aa67367b8
commit
17942eef57
16 changed files with 486 additions and 21 deletions
|
|
@ -15,8 +15,8 @@ apps/
|
|||
packages/
|
||||
cli logicsrc OpenSpec CLI, also exposed as commandboard/cb
|
||||
logicsrc-mcp @profullstack/logicsrc-mcp standards MCP server
|
||||
sdk SDK contract types and helpers
|
||||
tui terminal UI
|
||||
sdk planned Rust, Bun, Node, Python, and curl SDK surfaces
|
||||
schemas LogicSRC JSON schemas
|
||||
validators schema validation utilities
|
||||
plugin-core plugin manifest and loader runtime
|
||||
|
|
@ -36,6 +36,8 @@ scripts/
|
|||
npm install
|
||||
npm run check
|
||||
npm --workspace @logicsrc/cli run dev -- --openspec agentswarm --yolo --repo profullstack/logicsrc
|
||||
npm --workspace @logicsrc/cli run dev -- openspec import
|
||||
npm --workspace @logicsrc/cli run dev -- openspec export --out logicsrc-openspec-summary.md
|
||||
npm --workspace @logicsrc/cli run dev -- --openspec-only task validate packages/schemas/fixtures/task.yaml
|
||||
npm --workspace @logicsrc/cli run dev -- agentswarm --yolo --repo profullstack/logicsrc
|
||||
npm --workspace @logicsrc/cli run dev -- plugins
|
||||
|
|
|
|||
17
apps/logicsrc-web/public/blog/rss.xml
Normal file
17
apps/logicsrc-web/public/blog/rss.xml
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
|
||||
<channel>
|
||||
<title>LogicSRC Blog</title>
|
||||
<link>https://logicsrc.com/blog</link>
|
||||
<description>Project notes for LogicSRC OpenSpec standards, AgentSwarm, AgentByte, SDKs, MCP, and reference implementations.</description>
|
||||
<language>en-us</language>
|
||||
<atom:link href="https://logicsrc.com/blog/rss.xml" rel="self" type="application/rss+xml" />
|
||||
<item>
|
||||
<title>LogicSRC OpenSpec Compatibility</title>
|
||||
<link>https://logicsrc.com/openspec</link>
|
||||
<guid>https://logicsrc.com/openspec</guid>
|
||||
<description>LogicSRC adds an OpenSpec.dev comparison and compatibility mode for repo-local specs, proposals, tasks, and deltas.</description>
|
||||
<pubDate>Sat, 06 Jun 2026 00:00:00 GMT</pubDate>
|
||||
</item>
|
||||
</channel>
|
||||
</rss>
|
||||
48
apps/logicsrc-web/public/sitemap.xml
Normal file
48
apps/logicsrc-web/public/sitemap.xml
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
<url>
|
||||
<loc>https://logicsrc.com/</loc>
|
||||
<changefreq>weekly</changefreq>
|
||||
<priority>1.0</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://logicsrc.com/docs</loc>
|
||||
<changefreq>weekly</changefreq>
|
||||
<priority>0.9</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://logicsrc.com/openspec</loc>
|
||||
<changefreq>weekly</changefreq>
|
||||
<priority>0.8</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://logicsrc.com/agent-swarm</loc>
|
||||
<changefreq>weekly</changefreq>
|
||||
<priority>0.8</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://logicsrc.com/agentbyte</loc>
|
||||
<changefreq>weekly</changefreq>
|
||||
<priority>0.8</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://logicsrc.com/blog</loc>
|
||||
<changefreq>weekly</changefreq>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://logicsrc.com/about</loc>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.6</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://logicsrc.com/terms</loc>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.4</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://logicsrc.com/privacy</loc>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.4</priority>
|
||||
</url>
|
||||
</urlset>
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import { accessSync } from "node:fs";
|
||||
|
||||
for (const file of ["index.html", "public/manifest.webmanifest", "public/icon.svg", "public/service-worker.js", "src/main.ts", "src/styles.css"]) {
|
||||
for (const file of ["index.html", "public/manifest.webmanifest", "public/icon.svg", "public/service-worker.js", "public/sitemap.xml", "public/blog/rss.xml", "src/main.ts", "src/styles.css"]) {
|
||||
accessSync(new URL(`../${file}`, import.meta.url));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,8 @@ const mimeTypes = {
|
|||
".json": "application/json; charset=utf-8",
|
||||
".png": "image/png",
|
||||
".svg": "image/svg+xml",
|
||||
".webmanifest": "application/manifest+json; charset=utf-8"
|
||||
".webmanifest": "application/manifest+json; charset=utf-8",
|
||||
".xml": "application/xml; charset=utf-8"
|
||||
};
|
||||
|
||||
createServer((request, response) => {
|
||||
|
|
@ -76,7 +77,7 @@ function sendFile(file, headOnly, response) {
|
|||
|
||||
const extension = extname(file);
|
||||
response.writeHead(200, {
|
||||
"cache-control": extension === ".html" ? "no-store" : "public, max-age=31536000, immutable",
|
||||
"cache-control": extension === ".html" || extension === ".xml" ? "no-store" : "public, max-age=31536000, immutable",
|
||||
"content-type": mimeTypes[extension] ?? "application/octet-stream"
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ const schemas = [
|
|||
const implementations = [
|
||||
{ name: "CommandBoard.run", detail: "Hosted reference product implementing the LogicSRC primitives." },
|
||||
{ name: "CLI and TUI", detail: "`logicsrc` is the standards CLI; `commandboard` and `cb` remain compatible product aliases." },
|
||||
{ name: "SDKs", detail: "Planned Rust, Bun, Node, Python, and curl surfaces mirror the same OpenSpec resources." },
|
||||
{ name: "SDKs", detail: "`@logicsrc/sdk` defines contract types now; Rust, Bun, Node, Python, and curl surfaces mirror the same resources." },
|
||||
{ name: "sh1pt CLI", detail: "`sh1pt logicsrc ...` lets sh1pt users choose LogicSRC OpenSpec-only workflows." },
|
||||
{ name: "Reference API", detail: "Sample REST API available under `/api/*` for contract testing." },
|
||||
{ name: "Plugins", detail: "CoinPay, uGig, and sh1pt adapters prove the plugin manifest shape." }
|
||||
|
|
@ -56,7 +56,7 @@ const comparisonRows = [
|
|||
},
|
||||
{
|
||||
area: "Artifacts",
|
||||
logicsrc: "Schemas, plugin manifests, task/agent/run docs, event contracts, SDKs, MCP resources, CLI/TUI/PWA/API surfaces.",
|
||||
logicsrc: "Schemas, plugin manifests, task/agent/run docs, event contracts, `@logicsrc/sdk`, MCP resources, CLI/TUI/PWA/API surfaces.",
|
||||
openspec: "Repo-local specs, proposals, design docs, implementation tasks, and spec deltas."
|
||||
},
|
||||
{
|
||||
|
|
@ -243,7 +243,7 @@ sh1pt logicsrc --openspec-only \\
|
|||
|
||||
sh1pt logicsrc --openspec \\
|
||||
agentswarm --yolo</code></pre>
|
||||
<p><code>--openspec</code> enables OpenSpec.dev-compatible repo-local specs, proposals, tasks, and deltas where supported. <code>--openspec-only</code> restricts work to LogicSRC-published contracts.</p>
|
||||
<p><code>--openspec</code> enables OpenSpec.dev-compatible repo-local specs, proposals, tasks, and deltas where supported. <code>openspec import</code> and <code>openspec export</code> summarize those artifacts for LogicSRC workflows. <code>--openspec-only</code> restricts work to LogicSRC-published contracts.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
|
|
|||
11
docs/cli.md
11
docs/cli.md
|
|
@ -41,6 +41,7 @@ task
|
|||
wallet
|
||||
events
|
||||
agentswarm
|
||||
openspec
|
||||
plugins
|
||||
tui
|
||||
update / upgrade
|
||||
|
|
@ -57,6 +58,16 @@ sh1pt logicsrc --openspec-only agentswarm --yolo --repo profullstack/logicsrc
|
|||
|
||||
`agentswarm --yolo` opens the master agent flow. The master agent coordinates slave agents for scoped work such as reproduction, patching, review, documentation, and release evidence.
|
||||
|
||||
OpenSpec-compatible artifact commands:
|
||||
|
||||
```bash
|
||||
logicsrc openspec import
|
||||
logicsrc openspec export --out logicsrc-openspec-summary.md
|
||||
logicsrc openspec change --id add-agent-policy --capability agents
|
||||
```
|
||||
|
||||
When `--openspec` is enabled, AgentSwarm writes OpenSpec.dev-style files under `openspec/changes/<change-id>/`.
|
||||
|
||||
Machine-readable output should be available anywhere data is returned:
|
||||
|
||||
```bash
|
||||
|
|
|
|||
|
|
@ -21,9 +21,13 @@ The projects can be complementary. LogicSRC should support an `--openspec` compa
|
|||
|
||||
```bash
|
||||
logicsrc --openspec agentswarm --yolo --repo profullstack/logicsrc
|
||||
logicsrc openspec import
|
||||
logicsrc openspec export --out logicsrc-openspec-summary.md
|
||||
logicsrc --openspec-only task validate ./task.yaml
|
||||
sh1pt logicsrc --openspec agentswarm --yolo --repo profullstack/logicsrc
|
||||
```
|
||||
|
||||
- `--openspec` enables OpenSpec.dev-compatible repo-local planning conventions where supported.
|
||||
- `--openspec-only` restricts work to LogicSRC-published OpenSpec contracts.
|
||||
- `openspec import` summarizes repo-local OpenSpec.dev-style specs and changes.
|
||||
- `openspec export` writes a LogicSRC-readable markdown summary of those artifacts.
|
||||
|
|
|
|||
11
package-lock.json
generated
11
package-lock.json
generated
|
|
@ -1003,6 +1003,10 @@
|
|||
"resolved": "packages/schemas",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@logicsrc/sdk": {
|
||||
"resolved": "packages/sdk",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@logicsrc/tui": {
|
||||
"resolved": "packages/tui",
|
||||
"link": true
|
||||
|
|
@ -4692,6 +4696,13 @@
|
|||
"name": "@logicsrc/schemas",
|
||||
"version": "0.1.0"
|
||||
},
|
||||
"packages/sdk": {
|
||||
"name": "@logicsrc/sdk",
|
||||
"version": "0.1.0",
|
||||
"devDependencies": {
|
||||
"vitest": "^4.0.8"
|
||||
}
|
||||
},
|
||||
"packages/tui": {
|
||||
"name": "@logicsrc/tui",
|
||||
"version": "0.1.0",
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
"apps/*"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "npm --workspace @logicsrc/schemas run build && npm --workspace @logicsrc/validators run build && npm --workspace @logicsrc/plugin-core run build && npm --workspace @logicsrc/plugin-coinpay run build && npm --workspace @logicsrc/plugin-ugig run build && npm --workspace @logicsrc/plugin-sh1pt run build && npm --workspace @logicsrc/tui run build && npm --workspace @logicsrc/cli run build && npm --workspace @profullstack/logicsrc-mcp run build && npm --workspace @logicsrc/commandboard-api run build && npm --workspace @logicsrc/commandboard-web run build && npm --workspace @logicsrc/web run build",
|
||||
"build": "npm --workspace @logicsrc/schemas run build && npm --workspace @logicsrc/validators run build && npm --workspace @logicsrc/sdk run build && npm --workspace @logicsrc/plugin-core run build && npm --workspace @logicsrc/plugin-coinpay run build && npm --workspace @logicsrc/plugin-ugig run build && npm --workspace @logicsrc/plugin-sh1pt run build && npm --workspace @logicsrc/tui run build && npm --workspace @logicsrc/cli run build && npm --workspace @profullstack/logicsrc-mcp run build && npm --workspace @logicsrc/commandboard-api run build && npm --workspace @logicsrc/commandboard-web run build && npm --workspace @logicsrc/web run build",
|
||||
"start": "npm --workspace @logicsrc/web run start",
|
||||
"test": "npm run test --workspaces --if-present",
|
||||
"check": "npm run build && npm run test",
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { renderPluginStatus, renderTui } from "@logicsrc/tui";
|
|||
import { assertSchemaKind, parseDocument, validate } from "@logicsrc/validators";
|
||||
import { boards, tasks } from "./fixtures.js";
|
||||
import { print, type OutputFormat } from "./format.js";
|
||||
import { exportOpenSpecSummary, importOpenSpec, writeOpenSpecChange } from "./openspec.js";
|
||||
import { defaultPluginRegistry } from "./registry.js";
|
||||
|
||||
const program = new Command();
|
||||
|
|
@ -134,6 +135,8 @@ program
|
|||
.option("--yolo", "Start the master agent with autonomous execution enabled.")
|
||||
.option("--repo <repo>", "Target repository, for example profullstack/logicsrc")
|
||||
.option("--agents <agents>", "Comma-separated slave agent roles", "reproduce,patch,review")
|
||||
.option("--change <id>", "OpenSpec-compatible change id", "agentswarm-yolo")
|
||||
.option("--out <dir>", "OpenSpec-compatible output directory")
|
||||
.action((options) => {
|
||||
if (!options.yolo) {
|
||||
console.log("AgentSwarm is coming soon. Run `logicsrc agentswarm --yolo` to open the master agent flow.");
|
||||
|
|
@ -145,21 +148,69 @@ program
|
|||
.map((agent) => agent.trim())
|
||||
.filter(Boolean);
|
||||
|
||||
print(
|
||||
{
|
||||
const openspecCompatible = program.opts().openspec || process.env.LOGICSRC_OPENSPEC_COMPAT === "1";
|
||||
const openspecArtifacts = openspecCompatible
|
||||
? writeOpenSpecChange({
|
||||
id: options.change,
|
||||
title: "AgentSwarm YOLO Session",
|
||||
summary: "Open a LogicSRC AgentSwarm master agent session and coordinate scoped slave agents.",
|
||||
capability: "agentswarm",
|
||||
repo: options.repo,
|
||||
agents: slaveAgents,
|
||||
outDir: options.out
|
||||
})
|
||||
: null;
|
||||
|
||||
print({
|
||||
type: "logicsrc.agentswarm.session",
|
||||
status: "opening",
|
||||
mode: "yolo",
|
||||
master_agent: "agentswarm-master",
|
||||
slave_agents: slaveAgents,
|
||||
repo: options.repo ?? null,
|
||||
openspec_compatible: program.opts().openspec || process.env.LOGICSRC_OPENSPEC_COMPAT === "1",
|
||||
openspec_only: program.opts().openspecOnly || process.env.LOGICSRC_OPENSPEC_ONLY === "1"
|
||||
},
|
||||
"json"
|
||||
);
|
||||
openspec_compatible: openspecCompatible,
|
||||
openspec_only: program.opts().openspecOnly || process.env.LOGICSRC_OPENSPEC_ONLY === "1",
|
||||
openspec_artifacts: openspecArtifacts
|
||||
}, "json");
|
||||
});
|
||||
|
||||
const openspec = program.command("openspec").description("Import, export, and generate OpenSpec.dev-compatible repo-local planning artifacts.");
|
||||
|
||||
openspec
|
||||
.command("import")
|
||||
.argument("[root]", "OpenSpec root directory", "openspec")
|
||||
.option("--format <format>", "table, json, or markdown", "json")
|
||||
.description("Read OpenSpec.dev-style specs and changes from a repo.")
|
||||
.action((root, options) => print(importOpenSpec(root), options.format as OutputFormat));
|
||||
|
||||
openspec
|
||||
.command("export")
|
||||
.argument("[root]", "OpenSpec root directory", "openspec")
|
||||
.option("--out <file>", "Write a markdown summary", "logicsrc-openspec-summary.md")
|
||||
.description("Export OpenSpec.dev-style repo artifacts into a LogicSRC-readable summary.")
|
||||
.action((root, options) => {
|
||||
const outFile = exportOpenSpecSummary(importOpenSpec(root), options.out);
|
||||
console.log(`Wrote ${outFile}`);
|
||||
});
|
||||
|
||||
openspec
|
||||
.command("change")
|
||||
.option("--id <id>", "Change id", "logic-src-change")
|
||||
.option("--title <title>", "Change title", "LogicSRC OpenSpec Change")
|
||||
.option("--summary <summary>", "Change summary", "Describe a LogicSRC-compatible change.")
|
||||
.option("--capability <capability>", "Capability/spec id", "logicsrc")
|
||||
.option("--repo <repo>", "Target repository")
|
||||
.option("--out <dir>", "Output directory")
|
||||
.description("Create an OpenSpec.dev-style proposal/design/tasks/spec delta.")
|
||||
.action((options) => print(writeOpenSpecChange({
|
||||
id: options.id,
|
||||
title: options.title,
|
||||
summary: options.summary,
|
||||
capability: options.capability,
|
||||
repo: options.repo,
|
||||
outDir: options.out
|
||||
}), "json"));
|
||||
|
||||
program.command("plugins").option("--format <format>", "table, json, or markdown", "table").description("Show plugin status.").action((options) => {
|
||||
const snapshot = defaultPluginRegistry().snapshot();
|
||||
print(snapshot.plugins, options.format as OutputFormat);
|
||||
|
|
|
|||
176
packages/cli/src/openspec.ts
Normal file
176
packages/cli/src/openspec.ts
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
|
||||
import { basename, join } from "node:path";
|
||||
|
||||
export interface OpenSpecChangeInput {
|
||||
id: string;
|
||||
title: string;
|
||||
summary: string;
|
||||
capability: string;
|
||||
repo?: string;
|
||||
agents?: string[];
|
||||
outDir?: string;
|
||||
tasks?: string[];
|
||||
}
|
||||
|
||||
export interface OpenSpecImportSummary {
|
||||
root: string;
|
||||
specs: Array<{ id: string; path: string; title: string }>;
|
||||
changes: Array<{ id: string; path: string; files: string[] }>;
|
||||
}
|
||||
|
||||
export function writeOpenSpecChange(input: OpenSpecChangeInput) {
|
||||
const root = input.outDir ?? join("openspec", "changes", input.id);
|
||||
const specRoot = join(root, "specs", input.capability);
|
||||
mkdirSync(specRoot, { recursive: true });
|
||||
|
||||
const tasks = input.tasks?.length ? input.tasks : [
|
||||
"Review existing LogicSRC schemas and CLI conventions.",
|
||||
"Open the AgentSwarm master agent session.",
|
||||
"Assign slave agents to reproduction, patching, review, and evidence.",
|
||||
"Export audit artifacts back into LogicSRC run/event documents."
|
||||
];
|
||||
|
||||
const proposal = `# ${input.title}
|
||||
|
||||
## Summary
|
||||
|
||||
${input.summary}
|
||||
|
||||
## Repository
|
||||
|
||||
${input.repo ?? "not specified"}
|
||||
|
||||
## Compatibility
|
||||
|
||||
This change uses OpenSpec.dev-style repo-local planning artifacts while preserving LogicSRC task, agent, run, event, plugin, SDK, MCP, CLI, TUI, PWA, and API contract names.
|
||||
`;
|
||||
|
||||
const design = `# ${input.title} Design
|
||||
|
||||
## Architecture
|
||||
|
||||
- A master agent owns the session goal, policy, and final decision packet.
|
||||
- Slave agents execute scoped work such as reproduction, patching, review, documentation, and release evidence.
|
||||
- LogicSRC records agent runs, model/tool use, artifacts, audit events, and schema versions.
|
||||
|
||||
## OpenSpec Compatibility
|
||||
|
||||
OpenSpec-compatible files stay under \`openspec/changes/${input.id}\` and can be reviewed through normal git workflows.
|
||||
`;
|
||||
|
||||
const taskList = tasks.map((task, index) => `- [ ] ${index + 1}. ${task}`).join("\n");
|
||||
const spec = `# ${input.capability} Specification
|
||||
|
||||
## Purpose
|
||||
|
||||
${input.summary}
|
||||
|
||||
## Requirements
|
||||
|
||||
### Requirement: Master agent session
|
||||
|
||||
The system SHALL create a master agent session that can coordinate scoped slave agents.
|
||||
|
||||
#### Scenario: YOLO AgentSwarm session
|
||||
|
||||
- GIVEN a repository target${input.repo ? ` of \`${input.repo}\`` : ""}
|
||||
- WHEN \`logicsrc --openspec agentswarm --yolo\` runs
|
||||
- THEN create OpenSpec-compatible proposal, design, task, and spec-delta artifacts
|
||||
- AND keep LogicSRC audit and run contracts available for export
|
||||
|
||||
### Requirement: Slave agent coordination
|
||||
|
||||
The system SHALL record slave agent roles for reproducible review.
|
||||
|
||||
#### Scenario: Declared slave agents
|
||||
|
||||
- GIVEN slave agents ${input.agents?.length ? input.agents.map((agent) => `\`${agent}\``).join(", ") : "are declared"}
|
||||
- WHEN the session opens
|
||||
- THEN include those roles in the LogicSRC session output
|
||||
- AND include them in the repo-local OpenSpec artifacts
|
||||
`;
|
||||
|
||||
const files = [
|
||||
{ path: join(root, "proposal.md"), content: proposal },
|
||||
{ path: join(root, "design.md"), content: design },
|
||||
{ path: join(root, "tasks.md"), content: `# ${input.title} Tasks\n\n${taskList}\n` },
|
||||
{ path: join(specRoot, "spec.md"), content: spec }
|
||||
];
|
||||
|
||||
for (const file of files) {
|
||||
writeFileSync(file.path, file.content);
|
||||
}
|
||||
|
||||
return {
|
||||
id: input.id,
|
||||
root,
|
||||
files: files.map((file) => file.path)
|
||||
};
|
||||
}
|
||||
|
||||
export function importOpenSpec(root = "openspec"): OpenSpecImportSummary {
|
||||
const specsRoot = join(root, "specs");
|
||||
const changesRoot = join(root, "changes");
|
||||
const specs = existsSync(specsRoot)
|
||||
? listDirectories(specsRoot).map((directory) => {
|
||||
const specPath = join(specsRoot, directory, "spec.md");
|
||||
return {
|
||||
id: directory,
|
||||
path: specPath,
|
||||
title: readMarkdownTitle(specPath) ?? directory
|
||||
};
|
||||
})
|
||||
: [];
|
||||
|
||||
const changes = existsSync(changesRoot)
|
||||
? listDirectories(changesRoot).map((directory) => {
|
||||
const changePath = join(changesRoot, directory);
|
||||
return {
|
||||
id: directory,
|
||||
path: changePath,
|
||||
files: listFiles(changePath).map((file) => file.slice(changePath.length + 1))
|
||||
};
|
||||
})
|
||||
: [];
|
||||
|
||||
return { root, specs, changes };
|
||||
}
|
||||
|
||||
export function exportOpenSpecSummary(summary: OpenSpecImportSummary, outFile: string) {
|
||||
const markdown = `# OpenSpec Import Summary
|
||||
|
||||
Root: \`${summary.root}\`
|
||||
|
||||
## Specs
|
||||
|
||||
${summary.specs.length ? summary.specs.map((spec) => `- \`${spec.id}\` — ${spec.title} (${spec.path})`).join("\n") : "- none"}
|
||||
|
||||
## Changes
|
||||
|
||||
${summary.changes.length ? summary.changes.map((change) => `- \`${change.id}\` — ${change.files.length} file(s) (${change.path})`).join("\n") : "- none"}
|
||||
`;
|
||||
|
||||
writeFileSync(outFile, markdown);
|
||||
return outFile;
|
||||
}
|
||||
|
||||
function listDirectories(root: string) {
|
||||
return readdirSync(root).filter((entry) => statSync(join(root, entry)).isDirectory()).sort();
|
||||
}
|
||||
|
||||
function listFiles(root: string): string[] {
|
||||
const entries = readdirSync(root);
|
||||
return entries.flatMap((entry) => {
|
||||
const path = join(root, entry);
|
||||
return statSync(path).isDirectory() ? listFiles(path) : [path];
|
||||
}).sort();
|
||||
}
|
||||
|
||||
function readMarkdownTitle(path: string) {
|
||||
if (!existsSync(path)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const line = readFileSync(path, "utf8").split(/\r?\n/).find((entry) => entry.startsWith("# "));
|
||||
return line ? line.replace(/^#\s+/, "").trim() : basename(path);
|
||||
}
|
||||
15
packages/sdk/package.json
Normal file
15
packages/sdk/package.json
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"name": "@logicsrc/sdk",
|
||||
"version": "0.1.0",
|
||||
"description": "LogicSRC SDK contract types and client interface.",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"scripts": {
|
||||
"build": "tsc -p tsconfig.json",
|
||||
"test": "vitest run src"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vitest": "^4.0.8"
|
||||
}
|
||||
}
|
||||
31
packages/sdk/src/index.test.ts
Normal file
31
packages/sdk/src/index.test.ts
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
import { createAgentSwarmSession, createTask } from "./index.js";
|
||||
|
||||
describe("LogicSRC SDK contract helpers", () => {
|
||||
it("creates task documents with LogicSRC defaults", () => {
|
||||
expect(createTask({
|
||||
title: "Document SDK",
|
||||
description: "Add SDK contract helpers.",
|
||||
board: "/docs",
|
||||
creator_did: "did:example:alice"
|
||||
})).toMatchObject({
|
||||
type: "logicsrc.task",
|
||||
version: "0.1",
|
||||
status: "draft"
|
||||
});
|
||||
});
|
||||
|
||||
it("creates AgentSwarm session documents", () => {
|
||||
expect(createAgentSwarmSession({
|
||||
repo: "profullstack/logicsrc",
|
||||
agents: ["reproduce", "patch"],
|
||||
yolo: true,
|
||||
openspec: true
|
||||
})).toMatchObject({
|
||||
type: "logicsrc.agentswarm.session",
|
||||
mode: "yolo",
|
||||
openspec_compatible: true,
|
||||
slave_agents: ["reproduce", "patch"]
|
||||
});
|
||||
});
|
||||
});
|
||||
90
packages/sdk/src/index.ts
Normal file
90
packages/sdk/src/index.ts
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
export type LogicSrcId = string;
|
||||
|
||||
export interface LogicSrcTask {
|
||||
type: "logicsrc.task";
|
||||
version: string;
|
||||
title: string;
|
||||
description: string;
|
||||
board: string;
|
||||
creator_did: string;
|
||||
status: "draft" | "open" | "funded" | "claimed" | "submitted" | "approved" | "rejected" | "disputed" | "closed";
|
||||
budget?: {
|
||||
amount: number;
|
||||
currency: string;
|
||||
};
|
||||
assignee_did?: string;
|
||||
}
|
||||
|
||||
export interface LogicSrcAgent {
|
||||
type: "logicsrc.agent";
|
||||
id: LogicSrcId;
|
||||
name: string;
|
||||
capabilities: string[];
|
||||
logicsrc_compatibility_version?: string;
|
||||
}
|
||||
|
||||
export interface LogicSrcRun {
|
||||
type: "logicsrc.agent_run";
|
||||
id: LogicSrcId;
|
||||
agent_id: LogicSrcId;
|
||||
status: "queued" | "running" | "succeeded" | "failed" | "canceled";
|
||||
task_id?: LogicSrcId;
|
||||
}
|
||||
|
||||
export interface LogicSrcEvent {
|
||||
type: "logicsrc.event";
|
||||
event: string;
|
||||
resource_id: LogicSrcId;
|
||||
created_at?: string;
|
||||
}
|
||||
|
||||
export interface AgentSwarmSession {
|
||||
type: "logicsrc.agentswarm.session";
|
||||
status: "opening" | "active" | "paused" | "completed" | "failed";
|
||||
mode: "yolo" | "review";
|
||||
master_agent: string;
|
||||
slave_agents: string[];
|
||||
repo: string | null;
|
||||
openspec_compatible: boolean;
|
||||
openspec_only: boolean;
|
||||
}
|
||||
|
||||
export interface LogicSrcClient {
|
||||
createTask(input: Omit<LogicSrcTask, "type" | "version" | "status"> & Partial<Pick<LogicSrcTask, "version" | "status">>): Promise<LogicSrcTask>;
|
||||
validateTask(input: unknown): Promise<{ ok: boolean; errors: string[] }>;
|
||||
startAgentSwarm(input: {
|
||||
repo?: string;
|
||||
agents?: string[];
|
||||
yolo?: boolean;
|
||||
openspec?: boolean;
|
||||
openspecOnly?: boolean;
|
||||
}): Promise<AgentSwarmSession>;
|
||||
}
|
||||
|
||||
export function createTask(input: Omit<LogicSrcTask, "type" | "version" | "status"> & Partial<Pick<LogicSrcTask, "version" | "status">>): LogicSrcTask {
|
||||
return {
|
||||
type: "logicsrc.task",
|
||||
version: input.version ?? "0.1",
|
||||
status: input.status ?? "draft",
|
||||
...input
|
||||
};
|
||||
}
|
||||
|
||||
export function createAgentSwarmSession(input: {
|
||||
repo?: string;
|
||||
agents?: string[];
|
||||
yolo?: boolean;
|
||||
openspec?: boolean;
|
||||
openspecOnly?: boolean;
|
||||
}): AgentSwarmSession {
|
||||
return {
|
||||
type: "logicsrc.agentswarm.session",
|
||||
status: "opening",
|
||||
mode: input.yolo ? "yolo" : "review",
|
||||
master_agent: "agentswarm-master",
|
||||
slave_agents: input.agents ?? ["reproduce", "patch", "review"],
|
||||
repo: input.repo ?? null,
|
||||
openspec_compatible: input.openspec ?? false,
|
||||
openspec_only: input.openspecOnly ?? false
|
||||
};
|
||||
}
|
||||
8
packages/sdk/tsconfig.json
Normal file
8
packages/sdk/tsconfig.json
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "src",
|
||||
"outDir": "dist"
|
||||
},
|
||||
"include": ["src/**/*.ts"]
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue