diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7564c7d7e..7138da67f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -146,8 +146,8 @@ The codebase is organized into these areas. All are open to contributions: | AI/LLM layer | `packages/pi-ai` | Provider integrations, model handling | | Agent core | `packages/pi-agent-core` | Agent orchestration — RFC required for changes | | Coding agent | `packages/pi-coding-agent` | The main coding agent | -| MCP server | `packages/mcp-server` | Project state tools and MCP protocol | | SF extension | `src/resources/extensions/sf/` | SF workflow — RFC required for auto-mode | +| MCP client | `src/resources/extensions/mcp-client/` | External MCP tool-server integration only | | Other extensions | `src/resources/extensions/` | Browser, search, voice, MCP client, etc. | | Native engine | `rust-engine/` | Rust N-API modules (grep, git, AST, etc.) | | VS Code extension | `vscode-extension/` | Chat participant, sidebar, RPC integration | diff --git a/FEATURES.md b/FEATURES.md index 0666033cb..43917bcbd 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -1,6 +1,6 @@ # FEATURES -This file is the human-oriented capability map for Singularity Foundry. +This file is the human-oriented capability map for Singularity Forge. It is intentionally not the source of truth for schemas or tool parameters. Use it to answer: @@ -11,8 +11,8 @@ It is intentionally not the source of truth for schemas or tool parameters. Use For exact contracts, use: - `README.md` for product positioning and user docs -- `packages/mcp-server/src/workflow-tools.ts` for workflow tool schemas -- `src/resources/extensions/sf/` for planning/state-machine behavior +- `src/resources/extensions/sf/workflow-tools.js` for native workflow tool requirements +- `src/resources/extensions/sf/` for planning/state-machine behavior and tool schemas - `src/resources/extensions/*/extension-manifest.json` for extension inventory - `packages/pi-ai/src/` for provider and model registry behavior @@ -22,7 +22,7 @@ SF is a coding-agent application built around: - a milestone → slice → task planning hierarchy - a DB-backed workflow state machine -- MCP-accessible workflow mutations and readers +- native SF workflow mutations and readers - extension-based capability loading - multi-provider model routing - interactive and autonomous execution modes @@ -343,23 +343,32 @@ The section below is generated from source declarations so this overview can sta -### Workflow Tools +### SF Native Tools -Generated from `packages/mcp-server/src/workflow-tools.ts`. +Generated from `src/resources/extensions/sf/extension-manifest.json`. +- `sf_autonomous_checkpoint` - `sf_complete_milestone` - `sf_decision_save` +- `sf_exec` +- `sf_exec_search` +- `sf_graph` - `sf_journal_query` +- `sf_log_judgment` - `sf_milestone_generate_id` - `sf_milestone_status` - `sf_plan_milestone` - `sf_plan_slice` - `sf_plan_task` +- `sf_product_audit` - `sf_reassess_roadmap` - `sf_replan_slice` - `sf_requirement_save` - `sf_requirement_update` +- `sf_resume` - `sf_save_gate_result` +- `sf_self_feedback_resolve` +- `sf_self_report` - `sf_skip_slice` - `sf_slice_complete` - `sf_summary_save` diff --git a/scripts/generate-features-inventory.mjs b/scripts/generate-features-inventory.mjs index 39148b8ae..544ea9bf8 100644 --- a/scripts/generate-features-inventory.mjs +++ b/scripts/generate-features-inventory.mjs @@ -8,6 +8,7 @@ const repoRoot = resolve(__dirname, ".."); const featuresPath = join(repoRoot, "FEATURES.md"); const providersPath = join(repoRoot, "packages", "pi-ai", "src", "types.ts"); const extensionsRoot = join(repoRoot, "src", "resources", "extensions"); +const sfManifestPath = join(extensionsRoot, "sf", "extension-manifest.json"); const searchProviderPath = resolveExistingPath( join( repoRoot, @@ -75,6 +76,19 @@ export function parseBundledExtensions() { return uniqueSorted(entries); } +export function parseSfNativeTools() { + const manifest = JSON.parse(readFileSync(sfManifestPath, "utf8")); + const tools = manifest?.provides?.tools; + if (!Array.isArray(tools)) { + throw new Error( + "Could not find provides.tools in src/resources/extensions/sf/extension-manifest.json", + ); + } + return uniqueSorted( + tools.filter((tool) => typeof tool === "string" && tool.startsWith("sf_")), + ); +} + export function parseSearchProviders() { const src = readFileSync(searchProviderPath, "utf8"); const preferencesMatch = src.match( @@ -100,10 +114,17 @@ function formatBullets(values, formatter = (value) => `- \`${value}\``) { export function buildSection() { const extensions = parseBundledExtensions(); + const sfNativeTools = parseSfNativeTools(); const searchProviders = parseSearchProviders(); const knownProviders = parseKnownProviders(); return [ + "### SF Native Tools", + "", + "Generated from `src/resources/extensions/sf/extension-manifest.json`.", + "", + formatBullets(sfNativeTools), + "", "### Bundled Extensions", "", "Generated from `src/resources/extensions/*/extension-manifest.json`.", diff --git a/src/tests/features-inventory-generator.test.ts b/src/tests/features-inventory-generator.test.ts index 40fca8647..788bfc3f2 100644 --- a/src/tests/features-inventory-generator.test.ts +++ b/src/tests/features-inventory-generator.test.ts @@ -7,15 +7,22 @@ import { parseBundledExtensions, parseKnownProviders, parseSearchProviders, + parseSfNativeTools, START, updateFeaturesContent, } from "../../scripts/generate-features-inventory.mjs"; -test("features inventory generator surfaces expected workflow tool, extension, search, and provider inventories", () => { +test("features inventory generator surfaces expected SF native tool, extension, search, and provider inventories", () => { const extensions = parseBundledExtensions(); + const sfNativeTools = parseSfNativeTools(); const searchProviders = parseSearchProviders(); const knownProviders = parseKnownProviders(); + assert.ok(sfNativeTools.includes("sf_plan_milestone")); + assert.ok(sfNativeTools.includes("sf_task_complete")); + assert.ok(sfNativeTools.includes("sf_validate_milestone")); + assert.ok(!sfNativeTools.includes("capture_thought")); + assert.ok(extensions.includes("sf")); assert.ok(extensions.includes("search-the-web")); assert.ok(extensions.includes("subagent")); @@ -48,13 +55,15 @@ test("features inventory generator injects a rendered appendix between markers", assert.match( updated, new RegExp( - `${START.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\n\\n### Bundled Extensions`, + `${START.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\n\\n### SF Native Tools`, ), ); + assert.match(updated, /### SF Native Tools/); assert.match(updated, /### Bundled Extensions/); assert.match(updated, /### Search Providers/); assert.match(updated, /### Known Model Providers/); assert.match(updated, /- `search-the-web` — \[extension-manifest\.json]/); + assert.match(updated, /- `sf_task_complete`/); assert.match(updated, /- `brave`/); assert.match(updated, /- `xiaomi`/); assert.ok(updated.includes(generated)); diff --git a/vitest.config.ts b/vitest.config.ts index 8385c0970..9d582966d 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -150,10 +150,6 @@ export default defineConfig({ __dirname, "packages/native/src/index.ts", ), - "@singularity-forge/mcp-server": resolve( - __dirname, - "packages/mcp-server/src/index.ts", - ), "@singularity-forge/rpc-client": resolve( __dirname, "packages/rpc-client/src/index.ts", @@ -185,7 +181,6 @@ export default defineConfig({ "packages/pi-agent-core/src/**/*.test.ts", "packages/pi-tui/src/**/*.test.ts", "packages/daemon/src/**/*.test.ts", - "packages/mcp-server/src/**/*.test.ts", "packages/rpc-client/src/**/*.test.ts", "packages/native/src/**/*.test.mjs", "web/lib/**/*.test.ts",