squadfoundry 0.1.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/AGENTS.md +76 -0
- package/PROJECT.md +79 -0
- package/README.md +255 -0
- package/dist/orchestrator/adapters/context/IContextAdapter.d.ts +65 -0
- package/dist/orchestrator/adapters/context/IContextAdapter.d.ts.map +1 -0
- package/dist/orchestrator/adapters/context/IContextAdapter.js +12 -0
- package/dist/orchestrator/adapters/context/IContextAdapter.js.map +1 -0
- package/dist/orchestrator/adapters/context/filesystem.context-adapter.d.ts +33 -0
- package/dist/orchestrator/adapters/context/filesystem.context-adapter.d.ts.map +1 -0
- package/dist/orchestrator/adapters/context/filesystem.context-adapter.js +179 -0
- package/dist/orchestrator/adapters/context/filesystem.context-adapter.js.map +1 -0
- package/dist/orchestrator/adapters/deploy/IDeployAdapter.d.ts +78 -0
- package/dist/orchestrator/adapters/deploy/IDeployAdapter.d.ts.map +1 -0
- package/dist/orchestrator/adapters/deploy/IDeployAdapter.js +14 -0
- package/dist/orchestrator/adapters/deploy/IDeployAdapter.js.map +1 -0
- package/dist/orchestrator/adapters/deploy/vercel.adapter.d.ts +31 -0
- package/dist/orchestrator/adapters/deploy/vercel.adapter.d.ts.map +1 -0
- package/dist/orchestrator/adapters/deploy/vercel.adapter.js +83 -0
- package/dist/orchestrator/adapters/deploy/vercel.adapter.js.map +1 -0
- package/dist/orchestrator/adapters/host/IHostAdapter.d.ts +89 -0
- package/dist/orchestrator/adapters/host/IHostAdapter.d.ts.map +1 -0
- package/dist/orchestrator/adapters/host/IHostAdapter.js +10 -0
- package/dist/orchestrator/adapters/host/IHostAdapter.js.map +1 -0
- package/dist/orchestrator/adapters/host/anthropic.adapter.d.ts +27 -0
- package/dist/orchestrator/adapters/host/anthropic.adapter.d.ts.map +1 -0
- package/dist/orchestrator/adapters/host/anthropic.adapter.js +118 -0
- package/dist/orchestrator/adapters/host/anthropic.adapter.js.map +1 -0
- package/dist/orchestrator/adapters/host/antigravity.adapter.d.ts +53 -0
- package/dist/orchestrator/adapters/host/antigravity.adapter.d.ts.map +1 -0
- package/dist/orchestrator/adapters/host/antigravity.adapter.js +148 -0
- package/dist/orchestrator/adapters/host/antigravity.adapter.js.map +1 -0
- package/dist/orchestrator/adapters/host/claude-code.adapter.d.ts +13 -0
- package/dist/orchestrator/adapters/host/claude-code.adapter.d.ts.map +1 -0
- package/dist/orchestrator/adapters/host/claude-code.adapter.js +27 -0
- package/dist/orchestrator/adapters/host/claude-code.adapter.js.map +1 -0
- package/dist/orchestrator/adapters/host/command-model-invoker.d.ts +8 -0
- package/dist/orchestrator/adapters/host/command-model-invoker.d.ts.map +1 -0
- package/dist/orchestrator/adapters/host/command-model-invoker.js +46 -0
- package/dist/orchestrator/adapters/host/command-model-invoker.js.map +1 -0
- package/dist/orchestrator/adapters/host/ide.adapter.d.ts +61 -0
- package/dist/orchestrator/adapters/host/ide.adapter.d.ts.map +1 -0
- package/dist/orchestrator/adapters/host/ide.adapter.js +173 -0
- package/dist/orchestrator/adapters/host/ide.adapter.js.map +1 -0
- package/dist/orchestrator/adapters/host/local.adapter.d.ts +26 -0
- package/dist/orchestrator/adapters/host/local.adapter.d.ts.map +1 -0
- package/dist/orchestrator/adapters/host/local.adapter.js +82 -0
- package/dist/orchestrator/adapters/host/local.adapter.js.map +1 -0
- package/dist/orchestrator/adapters/host/openai.adapter.d.ts +26 -0
- package/dist/orchestrator/adapters/host/openai.adapter.d.ts.map +1 -0
- package/dist/orchestrator/adapters/host/openai.adapter.js +77 -0
- package/dist/orchestrator/adapters/host/openai.adapter.js.map +1 -0
- package/dist/orchestrator/adapters/host/opencode.adapter.d.ts +13 -0
- package/dist/orchestrator/adapters/host/opencode.adapter.d.ts.map +1 -0
- package/dist/orchestrator/adapters/host/opencode.adapter.js +27 -0
- package/dist/orchestrator/adapters/host/opencode.adapter.js.map +1 -0
- package/dist/orchestrator/adapters/model/IModelAdapter.d.ts +68 -0
- package/dist/orchestrator/adapters/model/IModelAdapter.d.ts.map +1 -0
- package/dist/orchestrator/adapters/model/IModelAdapter.js +11 -0
- package/dist/orchestrator/adapters/model/IModelAdapter.js.map +1 -0
- package/dist/orchestrator/adapters/publishing/ISocialMediaAdapter.d.ts +93 -0
- package/dist/orchestrator/adapters/publishing/ISocialMediaAdapter.d.ts.map +1 -0
- package/dist/orchestrator/adapters/publishing/ISocialMediaAdapter.js +10 -0
- package/dist/orchestrator/adapters/publishing/ISocialMediaAdapter.js.map +1 -0
- package/dist/orchestrator/adapters/publishing/instagram.adapter.d.ts +34 -0
- package/dist/orchestrator/adapters/publishing/instagram.adapter.d.ts.map +1 -0
- package/dist/orchestrator/adapters/publishing/instagram.adapter.js +105 -0
- package/dist/orchestrator/adapters/publishing/instagram.adapter.js.map +1 -0
- package/dist/orchestrator/adapters/tools/IToolAdapter.d.ts +52 -0
- package/dist/orchestrator/adapters/tools/IToolAdapter.d.ts.map +1 -0
- package/dist/orchestrator/adapters/tools/IToolAdapter.js +10 -0
- package/dist/orchestrator/adapters/tools/IToolAdapter.js.map +1 -0
- package/dist/orchestrator/adapters/vcs/IVCSAdapter.d.ts +89 -0
- package/dist/orchestrator/adapters/vcs/IVCSAdapter.d.ts.map +1 -0
- package/dist/orchestrator/adapters/vcs/IVCSAdapter.js +11 -0
- package/dist/orchestrator/adapters/vcs/IVCSAdapter.js.map +1 -0
- package/dist/orchestrator/adapters/vcs/github.adapter.d.ts +36 -0
- package/dist/orchestrator/adapters/vcs/github.adapter.d.ts.map +1 -0
- package/dist/orchestrator/adapters/vcs/github.adapter.js +110 -0
- package/dist/orchestrator/adapters/vcs/github.adapter.js.map +1 -0
- package/dist/orchestrator/artifacts/artifact-store.d.ts +47 -0
- package/dist/orchestrator/artifacts/artifact-store.d.ts.map +1 -0
- package/dist/orchestrator/artifacts/artifact-store.js +135 -0
- package/dist/orchestrator/artifacts/artifact-store.js.map +1 -0
- package/dist/orchestrator/builder/domain-classifier.d.ts +24 -0
- package/dist/orchestrator/builder/domain-classifier.d.ts.map +1 -0
- package/dist/orchestrator/builder/domain-classifier.js +156 -0
- package/dist/orchestrator/builder/domain-classifier.js.map +1 -0
- package/dist/orchestrator/builder/interview-questions.d.ts +13 -0
- package/dist/orchestrator/builder/interview-questions.d.ts.map +1 -0
- package/dist/orchestrator/builder/interview-questions.js +127 -0
- package/dist/orchestrator/builder/interview-questions.js.map +1 -0
- package/dist/orchestrator/builder/squad-builder.d.ts +53 -0
- package/dist/orchestrator/builder/squad-builder.d.ts.map +1 -0
- package/dist/orchestrator/builder/squad-builder.js +107 -0
- package/dist/orchestrator/builder/squad-builder.js.map +1 -0
- package/dist/orchestrator/builder/squad-generator.d.ts +33 -0
- package/dist/orchestrator/builder/squad-generator.d.ts.map +1 -0
- package/dist/orchestrator/builder/squad-generator.js +360 -0
- package/dist/orchestrator/builder/squad-generator.js.map +1 -0
- package/dist/orchestrator/cli/index.d.ts +3 -0
- package/dist/orchestrator/cli/index.d.ts.map +1 -0
- package/dist/orchestrator/cli/index.js +8 -0
- package/dist/orchestrator/cli/index.js.map +1 -0
- package/dist/orchestrator/context/context-index.d.ts +48 -0
- package/dist/orchestrator/context/context-index.d.ts.map +1 -0
- package/dist/orchestrator/context/context-index.js +116 -0
- package/dist/orchestrator/context/context-index.js.map +1 -0
- package/dist/orchestrator/context/context-loader.d.ts +49 -0
- package/dist/orchestrator/context/context-loader.d.ts.map +1 -0
- package/dist/orchestrator/context/context-loader.js +111 -0
- package/dist/orchestrator/context/context-loader.js.map +1 -0
- package/dist/orchestrator/core/guardrails.d.ts +33 -0
- package/dist/orchestrator/core/guardrails.d.ts.map +1 -0
- package/dist/orchestrator/core/guardrails.js +272 -0
- package/dist/orchestrator/core/guardrails.js.map +1 -0
- package/dist/orchestrator/core/state-machine.d.ts +65 -0
- package/dist/orchestrator/core/state-machine.d.ts.map +1 -0
- package/dist/orchestrator/core/state-machine.js +227 -0
- package/dist/orchestrator/core/state-machine.js.map +1 -0
- package/dist/orchestrator/core/types.d.ts +364 -0
- package/dist/orchestrator/core/types.d.ts.map +1 -0
- package/dist/orchestrator/core/types.js +10 -0
- package/dist/orchestrator/core/types.js.map +1 -0
- package/dist/orchestrator/index.d.ts +75 -0
- package/dist/orchestrator/index.d.ts.map +1 -0
- package/dist/orchestrator/index.js +64 -0
- package/dist/orchestrator/index.js.map +1 -0
- package/dist/orchestrator/mcp/server.d.ts +35 -0
- package/dist/orchestrator/mcp/server.d.ts.map +1 -0
- package/dist/orchestrator/mcp/server.js +378 -0
- package/dist/orchestrator/mcp/server.js.map +1 -0
- package/dist/orchestrator/runtime/agent-dispatcher.d.ts +25 -0
- package/dist/orchestrator/runtime/agent-dispatcher.d.ts.map +1 -0
- package/dist/orchestrator/runtime/agent-dispatcher.js +82 -0
- package/dist/orchestrator/runtime/agent-dispatcher.js.map +1 -0
- package/dist/orchestrator/runtime/approval-gate.d.ts +55 -0
- package/dist/orchestrator/runtime/approval-gate.d.ts.map +1 -0
- package/dist/orchestrator/runtime/approval-gate.js +104 -0
- package/dist/orchestrator/runtime/approval-gate.js.map +1 -0
- package/dist/orchestrator/runtime/handoff-manager.d.ts +29 -0
- package/dist/orchestrator/runtime/handoff-manager.d.ts.map +1 -0
- package/dist/orchestrator/runtime/handoff-manager.js +80 -0
- package/dist/orchestrator/runtime/handoff-manager.js.map +1 -0
- package/dist/orchestrator/runtime/job-manager.d.ts +39 -0
- package/dist/orchestrator/runtime/job-manager.d.ts.map +1 -0
- package/dist/orchestrator/runtime/job-manager.js +132 -0
- package/dist/orchestrator/runtime/job-manager.js.map +1 -0
- package/dist/orchestrator/runtime/squad-runtime.d.ts +70 -0
- package/dist/orchestrator/runtime/squad-runtime.d.ts.map +1 -0
- package/dist/orchestrator/runtime/squad-runtime.js +249 -0
- package/dist/orchestrator/runtime/squad-runtime.js.map +1 -0
- package/dist/orchestrator/shell/cli.d.ts +4 -0
- package/dist/orchestrator/shell/cli.d.ts.map +1 -0
- package/dist/orchestrator/shell/cli.js +27 -0
- package/dist/orchestrator/shell/cli.js.map +1 -0
- package/dist/orchestrator/shell/commands/create.command.d.ts +3 -0
- package/dist/orchestrator/shell/commands/create.command.d.ts.map +1 -0
- package/dist/orchestrator/shell/commands/create.command.js +41 -0
- package/dist/orchestrator/shell/commands/create.command.js.map +1 -0
- package/dist/orchestrator/shell/commands/edit.command.d.ts +3 -0
- package/dist/orchestrator/shell/commands/edit.command.d.ts.map +1 -0
- package/dist/orchestrator/shell/commands/edit.command.js +49 -0
- package/dist/orchestrator/shell/commands/edit.command.js.map +1 -0
- package/dist/orchestrator/shell/commands/hosts.command.d.ts +3 -0
- package/dist/orchestrator/shell/commands/hosts.command.d.ts.map +1 -0
- package/dist/orchestrator/shell/commands/hosts.command.js +27 -0
- package/dist/orchestrator/shell/commands/hosts.command.js.map +1 -0
- package/dist/orchestrator/shell/commands/init.command.d.ts +3 -0
- package/dist/orchestrator/shell/commands/init.command.d.ts.map +1 -0
- package/dist/orchestrator/shell/commands/init.command.js +13 -0
- package/dist/orchestrator/shell/commands/init.command.js.map +1 -0
- package/dist/orchestrator/shell/commands/list.command.d.ts +3 -0
- package/dist/orchestrator/shell/commands/list.command.d.ts.map +1 -0
- package/dist/orchestrator/shell/commands/list.command.js +18 -0
- package/dist/orchestrator/shell/commands/list.command.js.map +1 -0
- package/dist/orchestrator/shell/commands/run.command.d.ts +3 -0
- package/dist/orchestrator/shell/commands/run.command.d.ts.map +1 -0
- package/dist/orchestrator/shell/commands/run.command.js +71 -0
- package/dist/orchestrator/shell/commands/run.command.js.map +1 -0
- package/dist/orchestrator/shell/commands/status.command.d.ts +3 -0
- package/dist/orchestrator/shell/commands/status.command.d.ts.map +1 -0
- package/dist/orchestrator/shell/commands/status.command.js +29 -0
- package/dist/orchestrator/shell/commands/status.command.js.map +1 -0
- package/dist/orchestrator/shell/services/active-host-detector.service.d.ts +25 -0
- package/dist/orchestrator/shell/services/active-host-detector.service.d.ts.map +1 -0
- package/dist/orchestrator/shell/services/active-host-detector.service.js +128 -0
- package/dist/orchestrator/shell/services/active-host-detector.service.js.map +1 -0
- package/dist/orchestrator/shell/services/host-resolution.service.d.ts +42 -0
- package/dist/orchestrator/shell/services/host-resolution.service.d.ts.map +1 -0
- package/dist/orchestrator/shell/services/host-resolution.service.js +108 -0
- package/dist/orchestrator/shell/services/host-resolution.service.js.map +1 -0
- package/dist/orchestrator/shell/services/host-runtime.service.d.ts +23 -0
- package/dist/orchestrator/shell/services/host-runtime.service.d.ts.map +1 -0
- package/dist/orchestrator/shell/services/host-runtime.service.js +167 -0
- package/dist/orchestrator/shell/services/host-runtime.service.js.map +1 -0
- package/dist/orchestrator/shell/services/interview-host-bridge.service.d.ts +14 -0
- package/dist/orchestrator/shell/services/interview-host-bridge.service.d.ts.map +1 -0
- package/dist/orchestrator/shell/services/interview-host-bridge.service.js +16 -0
- package/dist/orchestrator/shell/services/interview-host-bridge.service.js.map +1 -0
- package/dist/orchestrator/shell/services/job-execution.service.d.ts +22 -0
- package/dist/orchestrator/shell/services/job-execution.service.d.ts.map +1 -0
- package/dist/orchestrator/shell/services/job-execution.service.js +39 -0
- package/dist/orchestrator/shell/services/job-execution.service.js.map +1 -0
- package/dist/orchestrator/shell/services/project-bootstrap.service.d.ts +6 -0
- package/dist/orchestrator/shell/services/project-bootstrap.service.d.ts.map +1 -0
- package/dist/orchestrator/shell/services/project-bootstrap.service.js +111 -0
- package/dist/orchestrator/shell/services/project-bootstrap.service.js.map +1 -0
- package/dist/orchestrator/shell/services/squad-scaffold.service.d.ts +3 -0
- package/dist/orchestrator/shell/services/squad-scaffold.service.d.ts.map +1 -0
- package/dist/orchestrator/shell/services/squad-scaffold.service.js +30 -0
- package/dist/orchestrator/shell/services/squad-scaffold.service.js.map +1 -0
- package/dist/tests/integration/instagram-squad.test.d.ts +8 -0
- package/dist/tests/integration/instagram-squad.test.d.ts.map +1 -0
- package/dist/tests/integration/instagram-squad.test.js +187 -0
- package/dist/tests/integration/instagram-squad.test.js.map +1 -0
- package/dist/tests/integration/shell/cli-run-host-native.test.d.ts +2 -0
- package/dist/tests/integration/shell/cli-run-host-native.test.d.ts.map +1 -0
- package/dist/tests/integration/shell/cli-run-host-native.test.js +42 -0
- package/dist/tests/integration/shell/cli-run-host-native.test.js.map +1 -0
- package/dist/tests/integration/software-squad.test.d.ts +8 -0
- package/dist/tests/integration/software-squad.test.d.ts.map +1 -0
- package/dist/tests/integration/software-squad.test.js +207 -0
- package/dist/tests/integration/software-squad.test.js.map +1 -0
- package/dist/tests/unit/artifact-store.test.d.ts +2 -0
- package/dist/tests/unit/artifact-store.test.d.ts.map +1 -0
- package/dist/tests/unit/artifact-store.test.js +137 -0
- package/dist/tests/unit/artifact-store.test.js.map +1 -0
- package/dist/tests/unit/context-loader.test.d.ts +2 -0
- package/dist/tests/unit/context-loader.test.d.ts.map +1 -0
- package/dist/tests/unit/context-loader.test.js +109 -0
- package/dist/tests/unit/context-loader.test.js.map +1 -0
- package/dist/tests/unit/docs/host-native-docs.test.d.ts +2 -0
- package/dist/tests/unit/docs/host-native-docs.test.d.ts.map +1 -0
- package/dist/tests/unit/docs/host-native-docs.test.js +18 -0
- package/dist/tests/unit/docs/host-native-docs.test.js.map +1 -0
- package/dist/tests/unit/guardrails.test.d.ts +2 -0
- package/dist/tests/unit/guardrails.test.d.ts.map +1 -0
- package/dist/tests/unit/guardrails.test.js +202 -0
- package/dist/tests/unit/guardrails.test.js.map +1 -0
- package/dist/tests/unit/host/host-adapter-contract.test.d.ts +2 -0
- package/dist/tests/unit/host/host-adapter-contract.test.d.ts.map +1 -0
- package/dist/tests/unit/host/host-adapter-contract.test.js +53 -0
- package/dist/tests/unit/host/host-adapter-contract.test.js.map +1 -0
- package/dist/tests/unit/host/ide.adapter.test.d.ts +2 -0
- package/dist/tests/unit/host/ide.adapter.test.d.ts.map +1 -0
- package/dist/tests/unit/host/ide.adapter.test.js +17 -0
- package/dist/tests/unit/host/ide.adapter.test.js.map +1 -0
- package/dist/tests/unit/host/native-ide-adapters.test.d.ts +2 -0
- package/dist/tests/unit/host/native-ide-adapters.test.d.ts.map +1 -0
- package/dist/tests/unit/host/native-ide-adapters.test.js +26 -0
- package/dist/tests/unit/host/native-ide-adapters.test.js.map +1 -0
- package/dist/tests/unit/runtime/squad-runtime-host-metadata.test.d.ts +2 -0
- package/dist/tests/unit/runtime/squad-runtime-host-metadata.test.d.ts.map +1 -0
- package/dist/tests/unit/runtime/squad-runtime-host-metadata.test.js +128 -0
- package/dist/tests/unit/runtime/squad-runtime-host-metadata.test.js.map +1 -0
- package/dist/tests/unit/shell/active-host-detector.test.d.ts +2 -0
- package/dist/tests/unit/shell/active-host-detector.test.d.ts.map +1 -0
- package/dist/tests/unit/shell/active-host-detector.test.js +85 -0
- package/dist/tests/unit/shell/active-host-detector.test.js.map +1 -0
- package/dist/tests/unit/shell/host-resolution.service.test.d.ts +2 -0
- package/dist/tests/unit/shell/host-resolution.service.test.d.ts.map +1 -0
- package/dist/tests/unit/shell/host-resolution.service.test.js +252 -0
- package/dist/tests/unit/shell/host-resolution.service.test.js.map +1 -0
- package/dist/tests/unit/shell/interview-host-bridge.test.d.ts +2 -0
- package/dist/tests/unit/shell/interview-host-bridge.test.d.ts.map +1 -0
- package/dist/tests/unit/shell/interview-host-bridge.test.js +58 -0
- package/dist/tests/unit/shell/interview-host-bridge.test.js.map +1 -0
- package/dist/tests/unit/shell/project-bootstrap.service.test.d.ts +2 -0
- package/dist/tests/unit/shell/project-bootstrap.service.test.d.ts.map +1 -0
- package/dist/tests/unit/shell/project-bootstrap.service.test.js +58 -0
- package/dist/tests/unit/shell/project-bootstrap.service.test.js.map +1 -0
- package/dist/tests/unit/shell/squad-scaffold.service.test.d.ts +2 -0
- package/dist/tests/unit/shell/squad-scaffold.service.test.d.ts.map +1 -0
- package/dist/tests/unit/shell/squad-scaffold.service.test.js +40 -0
- package/dist/tests/unit/shell/squad-scaffold.service.test.js.map +1 -0
- package/dist/tests/unit/squad-builder.test.d.ts +2 -0
- package/dist/tests/unit/squad-builder.test.d.ts.map +1 -0
- package/dist/tests/unit/squad-builder.test.js +126 -0
- package/dist/tests/unit/squad-builder.test.js.map +1 -0
- package/dist/tests/unit/state-machine.test.d.ts +2 -0
- package/dist/tests/unit/state-machine.test.d.ts.map +1 -0
- package/dist/tests/unit/state-machine.test.js +133 -0
- package/dist/tests/unit/state-machine.test.js.map +1 -0
- package/docs/architecture/overview.md +115 -0
- package/docs/development/adding-agents.md +75 -0
- package/docs/development/adding-hosts.md +104 -0
- package/docs/development/adding-integrations.md +83 -0
- package/docs/development/host-detection-and-resolution.md +59 -0
- package/docs/squads/how-to-create.md +85 -0
- package/docs/squads/how-to-execute.md +139 -0
- package/docs/superpowers/plans/2026-04-01-host-native-cli-shell-implementation.md +617 -0
- package/docs/superpowers/specs/2026-04-01-host-native-cli-shell-design.md +253 -0
- package/package.json +103 -0
- package/squads/examples/instagram-content/AGENTS.md +63 -0
- package/squads/examples/instagram-content/POLICIES.md +45 -0
- package/squads/examples/instagram-content/SQUAD.md +63 -0
- package/squads/examples/instagram-content/WORKFLOW.md +58 -0
- package/squads/examples/instagram-content/config/squad.json +474 -0
- package/squads/examples/software-development/AGENTS.md +88 -0
- package/squads/examples/software-development/POLICIES.md +44 -0
- package/squads/examples/software-development/SQUAD.md +65 -0
- package/squads/examples/software-development/WORKFLOW.md +78 -0
- package/squads/examples/software-development/config/squad.json +442 -0
- package/templates/AGENTS.md +46 -0
- package/templates/POLICIES.md +24 -0
- package/templates/PROJECT.md +52 -0
- package/templates/SQUAD.md +52 -0
- package/templates/TASKS.md +31 -0
- package/templates/WORKFLOW.md +35 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
+
import { createStateMachine } from '../../orchestrator/core/state-machine.js';
|
|
3
|
+
function makeJob(status) {
|
|
4
|
+
return {
|
|
5
|
+
id: 'test-job',
|
|
6
|
+
squadId: 'test-squad',
|
|
7
|
+
status,
|
|
8
|
+
objective: 'test',
|
|
9
|
+
initialInput: 'test input',
|
|
10
|
+
loadedContext: {
|
|
11
|
+
docs: [],
|
|
12
|
+
specs: [],
|
|
13
|
+
playbooks: [],
|
|
14
|
+
policies: [],
|
|
15
|
+
templates: [],
|
|
16
|
+
custom: [],
|
|
17
|
+
},
|
|
18
|
+
artifacts: [],
|
|
19
|
+
approvals: [],
|
|
20
|
+
currentStepId: null,
|
|
21
|
+
currentAgentId: null,
|
|
22
|
+
history: [],
|
|
23
|
+
startedAt: new Date().toISOString(),
|
|
24
|
+
updatedAt: new Date().toISOString(),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
describe('StateMachine', () => {
|
|
28
|
+
let sm;
|
|
29
|
+
beforeEach(() => {
|
|
30
|
+
sm = createStateMachine();
|
|
31
|
+
});
|
|
32
|
+
it('transitions from INTAKE_PENDING to CONTEXT_LOADING', () => {
|
|
33
|
+
const job = makeJob('INTAKE_PENDING');
|
|
34
|
+
const result = sm.transition(job, 'START_CONTEXT_LOADING');
|
|
35
|
+
expect(result.success).toBe(true);
|
|
36
|
+
expect(result.newStatus).toBe('CONTEXT_LOADING');
|
|
37
|
+
});
|
|
38
|
+
it('transitions from CONTEXT_LOADING to JOB_CREATED', () => {
|
|
39
|
+
const job = makeJob('CONTEXT_LOADING');
|
|
40
|
+
const result = sm.transition(job, 'CREATE_JOB');
|
|
41
|
+
expect(result.success).toBe(true);
|
|
42
|
+
expect(result.newStatus).toBe('JOB_CREATED');
|
|
43
|
+
});
|
|
44
|
+
it('transitions from JOB_CREATED to READY_FOR_EXECUTION', () => {
|
|
45
|
+
const job = makeJob('JOB_CREATED');
|
|
46
|
+
const result = sm.transition(job, 'MARK_READY');
|
|
47
|
+
expect(result.success).toBe(true);
|
|
48
|
+
expect(result.newStatus).toBe('READY_FOR_EXECUTION');
|
|
49
|
+
});
|
|
50
|
+
it('transitions from READY_FOR_EXECUTION to RUNNING_STEP', () => {
|
|
51
|
+
const job = makeJob('READY_FOR_EXECUTION');
|
|
52
|
+
const result = sm.transition(job, 'START_STEP');
|
|
53
|
+
expect(result.success).toBe(true);
|
|
54
|
+
expect(result.newStatus).toBe('RUNNING_STEP');
|
|
55
|
+
});
|
|
56
|
+
it('transitions from RUNNING_STEP to WAITING_APPROVAL', () => {
|
|
57
|
+
const job = makeJob('RUNNING_STEP');
|
|
58
|
+
const result = sm.transition(job, 'STEP_NEEDS_APPROVAL');
|
|
59
|
+
expect(result.success).toBe(true);
|
|
60
|
+
expect(result.newStatus).toBe('WAITING_APPROVAL');
|
|
61
|
+
});
|
|
62
|
+
it('transitions from WAITING_APPROVAL to READY_FOR_EXECUTION on grant', () => {
|
|
63
|
+
const job = makeJob('WAITING_APPROVAL');
|
|
64
|
+
const result = sm.transition(job, 'APPROVAL_GRANTED');
|
|
65
|
+
expect(result.success).toBe(true);
|
|
66
|
+
expect(result.newStatus).toBe('READY_FOR_EXECUTION');
|
|
67
|
+
});
|
|
68
|
+
it('transitions from WAITING_APPROVAL to BLOCKED on rejection', () => {
|
|
69
|
+
const job = makeJob('WAITING_APPROVAL');
|
|
70
|
+
const result = sm.transition(job, 'APPROVAL_REJECTED');
|
|
71
|
+
expect(result.success).toBe(true);
|
|
72
|
+
expect(result.newStatus).toBe('BLOCKED');
|
|
73
|
+
});
|
|
74
|
+
it('rejects invalid transitions', () => {
|
|
75
|
+
const job = makeJob('COMPLETED');
|
|
76
|
+
const result = sm.transition(job, 'START_STEP');
|
|
77
|
+
expect(result.success).toBe(false);
|
|
78
|
+
expect(result.reason).toBeDefined();
|
|
79
|
+
});
|
|
80
|
+
it('blocks via guard function', () => {
|
|
81
|
+
sm.registerTransition({
|
|
82
|
+
from: 'READY_FOR_EXECUTION',
|
|
83
|
+
event: 'CUSTOM_GUARDED_START',
|
|
84
|
+
to: 'RUNNING_STEP',
|
|
85
|
+
guard: () => ({ allowed: false, reason: 'Guard blocked' }),
|
|
86
|
+
description: 'Guarded start',
|
|
87
|
+
});
|
|
88
|
+
const job = makeJob('READY_FOR_EXECUTION');
|
|
89
|
+
const result = sm.transition(job, 'CUSTOM_GUARDED_START');
|
|
90
|
+
expect(result.success).toBe(false);
|
|
91
|
+
expect(result.reason).toBe('Guard blocked');
|
|
92
|
+
});
|
|
93
|
+
it('identifies terminal states correctly', () => {
|
|
94
|
+
expect(sm.isTerminal('COMPLETED')).toBe(true);
|
|
95
|
+
expect(sm.isTerminal('FAILED')).toBe(true);
|
|
96
|
+
expect(sm.isTerminal('RUNNING_STEP')).toBe(false);
|
|
97
|
+
expect(sm.isTerminal('WAITING_APPROVAL')).toBe(false);
|
|
98
|
+
});
|
|
99
|
+
it('lists valid events from a given status', () => {
|
|
100
|
+
const events = sm.validEventsFrom('READY_FOR_EXECUTION');
|
|
101
|
+
expect(events).toContain('START_STEP');
|
|
102
|
+
expect(events).toContain('COMPLETE');
|
|
103
|
+
});
|
|
104
|
+
it('allows registering and using custom transitions', () => {
|
|
105
|
+
sm.registerTransition({
|
|
106
|
+
from: 'RUNNING_STEP',
|
|
107
|
+
event: 'CUSTOM_EVENT',
|
|
108
|
+
to: 'BLOCKED',
|
|
109
|
+
description: 'Custom squad-specific transition',
|
|
110
|
+
});
|
|
111
|
+
const job = makeJob('RUNNING_STEP');
|
|
112
|
+
const result = sm.transition(job, 'CUSTOM_EVENT');
|
|
113
|
+
expect(result.success).toBe(true);
|
|
114
|
+
expect(result.newStatus).toBe('BLOCKED');
|
|
115
|
+
});
|
|
116
|
+
it('transitions through a full happy path', () => {
|
|
117
|
+
const states = [
|
|
118
|
+
['INTAKE_PENDING', 'START_CONTEXT_LOADING', 'CONTEXT_LOADING'],
|
|
119
|
+
['CONTEXT_LOADING', 'CREATE_JOB', 'JOB_CREATED'],
|
|
120
|
+
['JOB_CREATED', 'MARK_READY', 'READY_FOR_EXECUTION'],
|
|
121
|
+
['READY_FOR_EXECUTION', 'START_STEP', 'RUNNING_STEP'],
|
|
122
|
+
['RUNNING_STEP', 'STEP_COMPLETE', 'READY_FOR_EXECUTION'],
|
|
123
|
+
['READY_FOR_EXECUTION', 'COMPLETE', 'COMPLETED'],
|
|
124
|
+
];
|
|
125
|
+
for (const [from, event, expectedTo] of states) {
|
|
126
|
+
const job = makeJob(from);
|
|
127
|
+
const result = sm.transition(job, event);
|
|
128
|
+
expect(result.success, `Expected ${from} + ${event} → ${expectedTo}`).toBe(true);
|
|
129
|
+
expect(result.newStatus).toBe(expectedTo);
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
//# sourceMappingURL=state-machine.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state-machine.test.js","sourceRoot":"","sources":["../../../tests/unit/state-machine.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# Architecture Overview
|
|
2
|
+
|
|
3
|
+
Squad Foundry is built around five core principles:
|
|
4
|
+
|
|
5
|
+
1. **Core never imports adapters** — dependency inversion always
|
|
6
|
+
2. **State machine is explicit** — every transition is declared, no implicit changes
|
|
7
|
+
3. **All artifacts are human-readable** — JSON + Markdown, inspectable without tooling
|
|
8
|
+
4. **Squad = portable config** — reusable across hosts, models, and environments
|
|
9
|
+
5. **Guardrails are first-class** — enforced programmatically, not just in prompts
|
|
10
|
+
|
|
11
|
+
## Layers
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
┌─────────────────────────────────────────────┐
|
|
15
|
+
│ CLI / Host Interface │
|
|
16
|
+
├─────────────────────────────────────────────┤
|
|
17
|
+
│ Squad Builder | Squad Runtime │
|
|
18
|
+
├────────────────────────┬────────────────────┤
|
|
19
|
+
│ Context Layer │ Artifact Store │
|
|
20
|
+
├────────────────────────┴────────────────────┤
|
|
21
|
+
│ Core Layer │
|
|
22
|
+
│ (types, state machine, guardrails) │
|
|
23
|
+
├─────────────────────────────────────────────┤
|
|
24
|
+
│ Adapter Layer │
|
|
25
|
+
│ host | model | tools | vcs | publishing │
|
|
26
|
+
│ deploy | context │
|
|
27
|
+
└─────────────────────────────────────────────┘
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Core Layer (`orchestrator/core/`)
|
|
31
|
+
|
|
32
|
+
Pure TypeScript, zero external runtime dependencies. Contains:
|
|
33
|
+
- **`types.ts`** — All portable interfaces and type definitions
|
|
34
|
+
- **`state-machine.ts`** — Explicit state machine with guard functions
|
|
35
|
+
- **`guardrails.ts`** — Policy constraint evaluator
|
|
36
|
+
|
|
37
|
+
The core never imports from adapters. All coupling flows upward.
|
|
38
|
+
|
|
39
|
+
## Adapter Layer (`orchestrator/adapters/`)
|
|
40
|
+
|
|
41
|
+
Pluggable implementations for every external system:
|
|
42
|
+
|
|
43
|
+
| Interface | Purpose |
|
|
44
|
+
|-----------|---------|
|
|
45
|
+
| `IHostAdapter` | LLM execution runtime (Anthropic, OpenAI, local) |
|
|
46
|
+
| `IModelAdapter` | AI model provider selection |
|
|
47
|
+
| `IToolAdapter` | Tool/integration invocation |
|
|
48
|
+
| `IVCSAdapter` | Git operations and PRs |
|
|
49
|
+
| `ISocialMediaAdapter` | Social media publishing |
|
|
50
|
+
| `IDeployAdapter` | Deployment operations |
|
|
51
|
+
| `IContextAdapter` | Context file discovery and loading |
|
|
52
|
+
|
|
53
|
+
All adapters implement a clear interface. Swap implementations without touching core logic.
|
|
54
|
+
|
|
55
|
+
## Context Layer (`orchestrator/context/`)
|
|
56
|
+
|
|
57
|
+
Discovers and loads project documentation:
|
|
58
|
+
- `context-loader.ts` — Orchestrates discovery + loading via `IContextAdapter`
|
|
59
|
+
- `context-index.ts` — In-memory search index over loaded files
|
|
60
|
+
|
|
61
|
+
Priority order: PROJECT.md > TASKS.md > AGENTS.md > README.md > docs/** > specs/** > ...
|
|
62
|
+
|
|
63
|
+
## Artifact Store (`orchestrator/artifacts/`)
|
|
64
|
+
|
|
65
|
+
Filesystem-based persistence for all job data:
|
|
66
|
+
```
|
|
67
|
+
artifacts/<squad_id>/<job_id>/
|
|
68
|
+
state.json — full job state
|
|
69
|
+
handoffs.json — agent handoff records
|
|
70
|
+
events.json — history entries
|
|
71
|
+
approvals.json — approval records
|
|
72
|
+
outputs/ — agent-produced artifacts
|
|
73
|
+
reports/ — human-readable reports
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Squad Builder (`orchestrator/builder/`)
|
|
77
|
+
|
|
78
|
+
Interview-driven squad generation:
|
|
79
|
+
1. `interview-questions.ts` — Question bank organized by topic
|
|
80
|
+
2. `domain-classifier.ts` — Maps answers to SquadDomain
|
|
81
|
+
3. `squad-generator.ts` — Generates SquadDefinition + files
|
|
82
|
+
4. `squad-builder.ts` — Orchestrates the interview process
|
|
83
|
+
|
|
84
|
+
## Squad Runtime (`orchestrator/runtime/`)
|
|
85
|
+
|
|
86
|
+
Execution engine:
|
|
87
|
+
1. `job-manager.ts` — Job creation, state updates, history
|
|
88
|
+
2. `agent-dispatcher.ts` — Step → agent resolution + prompt building
|
|
89
|
+
3. `handoff-manager.ts` — Records and validates handoffs
|
|
90
|
+
4. `approval-gate.ts` — Human-in-the-loop pause/resume
|
|
91
|
+
5. `squad-runtime.ts` — Main coordinator
|
|
92
|
+
|
|
93
|
+
## Data Flow
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
User input
|
|
97
|
+
↓ SquadBuilder (interview)
|
|
98
|
+
↓ DomainClassifier
|
|
99
|
+
↓ SquadGenerator → squad.json files written to disk
|
|
100
|
+
↓
|
|
101
|
+
SquadRuntime.startJob()
|
|
102
|
+
↓ ContextLoader.load() → LoadedContext
|
|
103
|
+
↓ JobManager.create() → JobDefinition (persisted)
|
|
104
|
+
↓ StateMachine.transition('MARK_READY')
|
|
105
|
+
↓
|
|
106
|
+
Loop: SquadRuntime.executeStep()
|
|
107
|
+
↓ GuardrailEngine.evaluateAll() → block or pass
|
|
108
|
+
↓ ApprovalGate.isPending() → wait or continue
|
|
109
|
+
↓ AgentDispatcher.plan() → prompt
|
|
110
|
+
↓ IHostAdapter.sendPrompt() → AgentResponse
|
|
111
|
+
↓ ArtifactStore.persistArtifact() → ArtifactRef
|
|
112
|
+
↓ HandoffManager.record() → HandoffEvent
|
|
113
|
+
↓ StateMachine.transition('STEP_COMPLETE')
|
|
114
|
+
↓ next step or COMPLETE
|
|
115
|
+
```
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Adding New Agents
|
|
2
|
+
|
|
3
|
+
Agents are defined in `config/squad.json` — no code changes required.
|
|
4
|
+
|
|
5
|
+
## Step 1: Define the Agent
|
|
6
|
+
|
|
7
|
+
Add to `agents[]` in `squads/<squad_id>/config/squad.json`:
|
|
8
|
+
|
|
9
|
+
```json
|
|
10
|
+
{
|
|
11
|
+
"id": "my-new-agent",
|
|
12
|
+
"name": "My New Agent",
|
|
13
|
+
"role": "Specific Role",
|
|
14
|
+
"domain": "software-development",
|
|
15
|
+
"objective": "What this agent achieves",
|
|
16
|
+
"instructions": "You are the My New Agent. [Full instructions here...]",
|
|
17
|
+
"inputs": [
|
|
18
|
+
{ "name": "input_name", "description": "What comes in", "required": true }
|
|
19
|
+
],
|
|
20
|
+
"outputs": [
|
|
21
|
+
{ "name": "output_name", "description": "What goes out", "required": true, "format": "markdown" }
|
|
22
|
+
],
|
|
23
|
+
"allowedTools": ["filesystem", "git"],
|
|
24
|
+
"constraints": ["Do not do X", "Always do Y"],
|
|
25
|
+
"successCriteria": ["Output produced"],
|
|
26
|
+
"failureCriteria": ["Cannot produce output"],
|
|
27
|
+
"allowedStates": ["READY_FOR_EXECUTION", "RUNNING_STEP"],
|
|
28
|
+
"blockingConditions": [],
|
|
29
|
+
"handoffRules": [
|
|
30
|
+
{
|
|
31
|
+
"condition": "step_completed",
|
|
32
|
+
"targetAgentId": "next-agent-id",
|
|
33
|
+
"description": "Pass to next agent",
|
|
34
|
+
"requiresApproval": false
|
|
35
|
+
}
|
|
36
|
+
],
|
|
37
|
+
"responseFormat": "markdown"
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Step 2: Add a Workflow Step
|
|
42
|
+
|
|
43
|
+
Add to `workflow.steps[]`:
|
|
44
|
+
|
|
45
|
+
```json
|
|
46
|
+
{
|
|
47
|
+
"id": "step-my-new-agent",
|
|
48
|
+
"name": "My New Step",
|
|
49
|
+
"agentId": "my-new-agent",
|
|
50
|
+
"description": "What this step does",
|
|
51
|
+
"dependsOn": ["step-previous"],
|
|
52
|
+
"guardrails": [],
|
|
53
|
+
"requiresApprovalBefore": false,
|
|
54
|
+
"requiresApprovalAfter": false,
|
|
55
|
+
"requiredArtifacts": ["previous-output"],
|
|
56
|
+
"producedArtifacts": ["my-output"],
|
|
57
|
+
"nextStepId": "step-next"
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Step 3: Update the Previous Step
|
|
62
|
+
|
|
63
|
+
Point its `nextStepId` to your new step.
|
|
64
|
+
|
|
65
|
+
## Step 4: Document
|
|
66
|
+
|
|
67
|
+
Update `squads/<squad_id>/AGENTS.md` and `WORKFLOW.md`.
|
|
68
|
+
|
|
69
|
+
## Agent Instructions Best Practices
|
|
70
|
+
|
|
71
|
+
1. **Start with identity**: "You are the [Role]. [What you do]."
|
|
72
|
+
2. **Be explicit about inputs**: "Given [X] and [Y], ..."
|
|
73
|
+
3. **Specify outputs precisely**: "Produce [Z] as [format]."
|
|
74
|
+
4. **List constraints**: "Do NOT [X]. ALWAYS [Y]."
|
|
75
|
+
5. **Define handoff signal**: "When complete, signal: [condition]."
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# Adding a New Host Runtime Adapter
|
|
2
|
+
|
|
3
|
+
A "host" is the execution environment that runs the LLM.
|
|
4
|
+
|
|
5
|
+
## Step 1: Implement `IHostAdapter`
|
|
6
|
+
|
|
7
|
+
Create `orchestrator/adapters/host/myhost.adapter.ts`:
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
import type {
|
|
11
|
+
IHostAdapter,
|
|
12
|
+
PromptOptions,
|
|
13
|
+
HostCapabilities,
|
|
14
|
+
HostDetectionContext,
|
|
15
|
+
HostDetectionResult,
|
|
16
|
+
InterviewTurnInput,
|
|
17
|
+
InterviewTurnState,
|
|
18
|
+
InterviewTurnResult,
|
|
19
|
+
} from './IHostAdapter.js'
|
|
20
|
+
import type { AgentDefinition, AgentResponse, JobDefinition, WorkflowStep } from '../../core/types.js'
|
|
21
|
+
|
|
22
|
+
export class MyHostAdapter implements IHostAdapter {
|
|
23
|
+
readonly id = 'myhost'
|
|
24
|
+
readonly name = 'My Host'
|
|
25
|
+
|
|
26
|
+
detect(_context: HostDetectionContext): HostDetectionResult {
|
|
27
|
+
return { isDetected: false, confidence: 'low', reasons: [] }
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async initialize(): Promise<void> {
|
|
31
|
+
// Connect, validate credentials, etc.
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async runInterviewTurn(input: InterviewTurnInput, _state: InterviewTurnState): Promise<InterviewTurnResult> {
|
|
35
|
+
return { content: input.prompt, status: 'continue' }
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async getActiveModel(): Promise<string | null> {
|
|
39
|
+
return 'my-model'
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async sendPrompt(
|
|
43
|
+
prompt: string,
|
|
44
|
+
agent: AgentDefinition,
|
|
45
|
+
job: JobDefinition,
|
|
46
|
+
step: WorkflowStep,
|
|
47
|
+
options?: PromptOptions,
|
|
48
|
+
): Promise<AgentResponse> {
|
|
49
|
+
// Call your LLM/host here
|
|
50
|
+
const content = await callMyLLM(prompt, options)
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
agentId: agent.id,
|
|
54
|
+
stepId: step.id,
|
|
55
|
+
jobId: job.id,
|
|
56
|
+
content,
|
|
57
|
+
artifacts: [], // parse from content if needed
|
|
58
|
+
status: 'success',
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
getCapabilities(): HostCapabilities {
|
|
63
|
+
return {
|
|
64
|
+
supportsStreaming: false,
|
|
65
|
+
supportsToolUse: false,
|
|
66
|
+
supportsVision: false,
|
|
67
|
+
maxContextTokens: 32000,
|
|
68
|
+
supportedModels: ['my-model'],
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async healthCheck(): Promise<boolean> {
|
|
73
|
+
// Verify connectivity
|
|
74
|
+
return true
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Step 2: Parse Agent Response
|
|
80
|
+
|
|
81
|
+
The key contract is the `AgentResponse` type. Your adapter must parse the LLM output and return:
|
|
82
|
+
- `content` — the text response
|
|
83
|
+
- `artifacts` — any `PendingArtifact[]` the agent wants to persist
|
|
84
|
+
- `handoffSignal` — optional, if the agent signals handoff explicitly
|
|
85
|
+
- `status` — `'success' | 'failure' | 'needs_input' | 'loop_back'`
|
|
86
|
+
|
|
87
|
+
## Step 3: Use the Adapter
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
import { MyHostAdapter } from './orchestrator/adapters/host/myhost.adapter.js'
|
|
91
|
+
import { createSquadRuntime } from './orchestrator/runtime/squad-runtime.js'
|
|
92
|
+
|
|
93
|
+
const runtime = createSquadRuntime({
|
|
94
|
+
hostAdapter: new MyHostAdapter(),
|
|
95
|
+
artifactsDir: 'artifacts',
|
|
96
|
+
})
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Notes
|
|
100
|
+
|
|
101
|
+
- The `SquadRuntime` never imports a specific host adapter — it only uses `IHostAdapter`
|
|
102
|
+
- You can have different agents use different host adapters by extending `SquadRuntime`
|
|
103
|
+
- For IDE-native agents (Claude Code, Cursor, etc.), the host adapter can simply relay to the IDE's built-in agent API
|
|
104
|
+
- `sendPrompt` receives `options.metadata.allowedAgentIds` from runtime; use this to validate explicit handoff targets when parsing response text.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Adding New Integrations
|
|
2
|
+
|
|
3
|
+
All integrations implement one of the existing adapter interfaces. Each integration is isolated — the core and runtime never import integrations directly.
|
|
4
|
+
|
|
5
|
+
## Adapter Interfaces by Integration Type
|
|
6
|
+
|
|
7
|
+
| Integration type | Interface | Example |
|
|
8
|
+
|-----------------|-----------|---------|
|
|
9
|
+
| Git + PR platform | `IVCSAdapter` | GitHub, GitLab, Bitbucket |
|
|
10
|
+
| Social media publishing | `ISocialMediaAdapter` | Instagram, LinkedIn, Twitter/X |
|
|
11
|
+
| Deployment | `IDeployAdapter` | Vercel, AWS, Railway, Fly.io |
|
|
12
|
+
| Context/docs | `IContextAdapter` | Notion, Confluence, GitHub Wiki |
|
|
13
|
+
| Tools/APIs | `IToolAdapter` | Web search, database, custom APIs |
|
|
14
|
+
|
|
15
|
+
## Example: Adding a GitLab Adapter
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
// orchestrator/adapters/vcs/gitlab.adapter.ts
|
|
19
|
+
import type { IVCSAdapter, ... } from './IVCSAdapter.js'
|
|
20
|
+
|
|
21
|
+
export class GitLabVCSAdapter implements IVCSAdapter {
|
|
22
|
+
readonly id = 'gitlab'
|
|
23
|
+
readonly name = 'GitLab'
|
|
24
|
+
|
|
25
|
+
// Implement all IVCSAdapter methods
|
|
26
|
+
// ...
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Example: Adding a LinkedIn Publisher
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
// orchestrator/adapters/publishing/linkedin.adapter.ts
|
|
34
|
+
import type { ISocialMediaAdapter, ... } from './ISocialMediaAdapter.js'
|
|
35
|
+
|
|
36
|
+
export class LinkedInAdapter implements ISocialMediaAdapter {
|
|
37
|
+
readonly id = 'linkedin'
|
|
38
|
+
readonly platform = 'LinkedIn'
|
|
39
|
+
|
|
40
|
+
// Implement all ISocialMediaAdapter methods
|
|
41
|
+
// ...
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Registering Integrations in a Squad
|
|
46
|
+
|
|
47
|
+
In `config/squad.json`:
|
|
48
|
+
|
|
49
|
+
```json
|
|
50
|
+
{
|
|
51
|
+
"allowedIntegrations": [
|
|
52
|
+
{
|
|
53
|
+
"id": "gitlab",
|
|
54
|
+
"type": "vcs",
|
|
55
|
+
"name": "GitLab",
|
|
56
|
+
"required": true,
|
|
57
|
+
"status": "real"
|
|
58
|
+
}
|
|
59
|
+
]
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Making Stubs Real
|
|
64
|
+
|
|
65
|
+
All stubs follow this pattern:
|
|
66
|
+
1. They log `[STUB]` messages
|
|
67
|
+
2. They return mock data
|
|
68
|
+
3. They have `TODO:` comments marking where real API calls go
|
|
69
|
+
|
|
70
|
+
To activate a stub:
|
|
71
|
+
1. Set the required environment variables
|
|
72
|
+
2. Install the SDK (`npm install @anthropic-ai/sdk`, etc.)
|
|
73
|
+
3. Replace the stub implementation with real API calls
|
|
74
|
+
4. Update the adapter's `status` field from `'stub'` to `'real'`
|
|
75
|
+
|
|
76
|
+
## Safety
|
|
77
|
+
|
|
78
|
+
Always ensure:
|
|
79
|
+
- Publishing adapters check for human approval before acting
|
|
80
|
+
- Deploy adapters check for human confirmation before any deploy
|
|
81
|
+
- VCS adapters never force-push to protected branches
|
|
82
|
+
|
|
83
|
+
These checks belong in the runtime guardrail layer — the adapter implements the API call only.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Host Detection and Resolution
|
|
2
|
+
|
|
3
|
+
This document explains how Squad Foundry resolves host adapters in CLI-first mode.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Resolution happens in three stages:
|
|
8
|
+
|
|
9
|
+
1. `ActiveHostDetector` collects host signals from argv, files, env, and process hints.
|
|
10
|
+
2. `HostResolutionService` applies confidence + validity rules.
|
|
11
|
+
3. `HostRuntimeService` materializes the adapter and persists preference metadata.
|
|
12
|
+
|
|
13
|
+
## Confidence and Resolution Rules
|
|
14
|
+
|
|
15
|
+
- `high`: use detected host only if adapter initializes and supports command.
|
|
16
|
+
- `medium`: reuse persisted host only if:
|
|
17
|
+
- adapter initializes,
|
|
18
|
+
- command is supported,
|
|
19
|
+
- at least one medium/strong signal still matches prior validation.
|
|
20
|
+
- `low`: use assisted selection (interactive CLI) or fail with explicit message in non-interactive mode.
|
|
21
|
+
|
|
22
|
+
## Persisted Preference Format
|
|
23
|
+
|
|
24
|
+
File: `squad-foundry.hosts.json`
|
|
25
|
+
|
|
26
|
+
Example:
|
|
27
|
+
|
|
28
|
+
```json
|
|
29
|
+
{
|
|
30
|
+
"preferredHost": "local",
|
|
31
|
+
"validation": {
|
|
32
|
+
"timestamp": "2026-04-02T12:00:00.000Z",
|
|
33
|
+
"matchedSignals": ["file:CLAUDE.md"]
|
|
34
|
+
},
|
|
35
|
+
"lastValidated": "2026-04-02T12:00:00.000Z",
|
|
36
|
+
"hosts": ["antigravity", "anthropic", "local", "openai"]
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Runtime Provenance
|
|
41
|
+
|
|
42
|
+
Each `run` writes:
|
|
43
|
+
|
|
44
|
+
- `artifacts/<squad>/<job>/reports/runtime-metadata.json`
|
|
45
|
+
|
|
46
|
+
Fields:
|
|
47
|
+
|
|
48
|
+
- `resolvedHost`
|
|
49
|
+
- `confidence`
|
|
50
|
+
- `reasons`
|
|
51
|
+
- `activeModel`
|
|
52
|
+
- `fallbackPath`
|
|
53
|
+
|
|
54
|
+
`status` prints these fields for quick diagnosis.
|
|
55
|
+
|
|
56
|
+
## MCP Mode
|
|
57
|
+
|
|
58
|
+
MCP uses the same resolution pipeline but does not run interactive selection.
|
|
59
|
+
If no valid detected/persisted host is available, MCP returns an explicit error asking for `SQUAD_FOUNDRY_ADAPTER`.
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# How to Create a Squad
|
|
2
|
+
|
|
3
|
+
Squads are created via the **Squad Builder** — an interview-driven system that generates all necessary files.
|
|
4
|
+
|
|
5
|
+
## Method 1: CLI Interview
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
node dist/cli/index.js build
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
The CLI will ask you a series of questions and generate the squad files.
|
|
12
|
+
|
|
13
|
+
## Method 2: Programmatic API
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { createSquadBuilder } from './orchestrator/builder/squad-builder.js'
|
|
17
|
+
import type { InterviewAnswer } from './orchestrator/core/types.js'
|
|
18
|
+
|
|
19
|
+
const builder = createSquadBuilder({
|
|
20
|
+
contextRootPath: process.cwd(),
|
|
21
|
+
outputDir: process.cwd(),
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
const answers: InterviewAnswer[] = [
|
|
25
|
+
{ questionId: 'q_objective', answer: 'Create and publish Instagram content' },
|
|
26
|
+
{ questionId: 'q_domain', answer: '3' }, // social-media
|
|
27
|
+
{ questionId: 'q_description', answer: 'End-to-end Instagram content pipeline' },
|
|
28
|
+
{ questionId: 'q_inputs', answer: 'Campaign brief or topic' },
|
|
29
|
+
{ questionId: 'q_outputs', answer: 'Published Instagram post with analytics' },
|
|
30
|
+
{ questionId: 'q_steps', answer: '1. Strategy, 2. Write, 3. Review, 4. Approve, 5. Publish' },
|
|
31
|
+
{ questionId: 'q_approvals', answer: 'Publishing requires human approval' },
|
|
32
|
+
{ questionId: 'q_human_in_loop', answer: 'Never auto-publish' },
|
|
33
|
+
{ questionId: 'q_squad_name', answer: 'instagram-content' },
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
const result = await builder.build(answers)
|
|
37
|
+
console.log('Generated files:', result.generatedFiles.map(f => f.path))
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Method 3: Manual Creation
|
|
41
|
+
|
|
42
|
+
Copy the template from `templates/SQUAD.md` and create:
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
squads/my-squad/
|
|
46
|
+
SQUAD.md
|
|
47
|
+
WORKFLOW.md
|
|
48
|
+
AGENTS.md
|
|
49
|
+
POLICIES.md
|
|
50
|
+
config/
|
|
51
|
+
squad.json
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
The `config/squad.json` is the source of truth. See `squads/examples/software-development/config/squad.json` for a complete example.
|
|
55
|
+
|
|
56
|
+
## Generated Files
|
|
57
|
+
|
|
58
|
+
| File | Purpose |
|
|
59
|
+
|------|---------|
|
|
60
|
+
| `SQUAD.md` | Human-readable squad overview |
|
|
61
|
+
| `WORKFLOW.md` | Step-by-step workflow documentation |
|
|
62
|
+
| `AGENTS.md` | Agent descriptions and responsibilities |
|
|
63
|
+
| `POLICIES.md` | Guardrails and prohibited actions |
|
|
64
|
+
| `config/squad.json` | Machine-readable squad definition (source of truth) |
|
|
65
|
+
|
|
66
|
+
## Interview Questions
|
|
67
|
+
|
|
68
|
+
The builder asks about:
|
|
69
|
+
- **Objective** — What does the squad achieve?
|
|
70
|
+
- **Domain** — What type of work (software, social media, docs, etc.)?
|
|
71
|
+
- **I/O** — What goes in? What comes out?
|
|
72
|
+
- **Steps** — What are the workflow steps?
|
|
73
|
+
- **Approvals** — What requires human sign-off?
|
|
74
|
+
- **Tools** — What integrations are needed?
|
|
75
|
+
- **Policies** — What is prohibited?
|
|
76
|
+
- **Risks** — What could go wrong?
|
|
77
|
+
|
|
78
|
+
## Customizing After Generation
|
|
79
|
+
|
|
80
|
+
Edit `config/squad.json` to:
|
|
81
|
+
- Add/remove agents
|
|
82
|
+
- Add/remove workflow steps
|
|
83
|
+
- Change guardrail severity
|
|
84
|
+
- Add approval requirements
|
|
85
|
+
- Update agent instructions
|