@inneranimalmedia/agentsam-sdk 2.6.1 → 2.6.3
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/AGENTSAM.md +45 -1
- package/README.md +80 -0
- package/apps/README.md +34 -0
- package/apps/cad-creator/README.md +728 -0
- package/apps/cad-creator/shared/cad/package.json +19 -0
- package/apps/cad-creator/shared/cad/src/domain/operations.ts +7 -0
- package/apps/cad-creator/shared/cad/src/domain/project-contract.d.ts +3 -0
- package/apps/cad-creator/shared/cad/src/domain/project-contract.js +75 -0
- package/apps/cad-creator/shared/cad/src/domain/project-tools.d.ts +1 -0
- package/apps/cad-creator/shared/cad/src/domain/project-tools.js +24 -0
- package/apps/cad-creator/shared/cad/src/domain/validation.ts +191 -0
- package/apps/cad-creator/shared/cad/src/index.ts +4 -0
- package/apps/cad-creator/shared/cad/src/robotics/types.ts +232 -0
- package/apps/cad-creator/shared/cad/src/types.ts +507 -0
- package/apps/cad-creator/shared/cad/tsconfig.json +14 -0
- package/docs/AUTH_IDENTITY_CONTRACT.md +25 -27
- package/docs/AUTORAG.md +58 -0
- package/docs/BRAND_INTELLIGENCE.md +30 -0
- package/docs/CLI_SHELL.md +4 -2
- package/docs/CMS_CONTEXTUAL_COMPOSER.md +38 -0
- package/docs/MERKLE.md +4 -0
- package/docs/PROJECT_CONFIG.md +3 -0
- package/docs/REPOSITORY_KNOWLEDGE.md +2 -0
- package/docs/SDK_WORKER.md +4 -3
- package/docs/THEME_REFINERY.md +120 -0
- package/docs/architecture/PROVIDER-TOOLS-AND-COMPACTION.md +60 -0
- package/docs/architecture/STORAGE.md +87 -0
- package/docs/cad-project-tools.md +69 -0
- package/docs/cms-scaffolding-pattern-reference.md +73 -0
- package/docs/plans/AGENTSAM-INTERACTIVE-UI-REQUIREMENTS-codex-tui-20260919.md +113 -0
- package/docs/plans/AGENTSAM-INTERACTIVE-UI-REQUIREMENTS.md +85 -0
- package/docs/plans/AGENTSAM-MCP-CLIENT-2026-09-19.md +181 -0
- package/docs/plans/ASBD-PORTABLE-WORKGRAPH-UI-DEFERRED.md +34 -0
- package/docs/plans/ASTRA-BRIEF-2026-09-18.md +258 -0
- package/docs/plans/MULTI-AGENT-SPRINTS-2026-09-19.md +373 -0
- package/docs/plans/NEXT-AGENT-HANDOFF.md +167 -0
- package/docs/plans/RECONCILIATION-2026-09-19.md +178 -0
- package/docs/plugins.md +43 -0
- package/docs/tools/README.md +57 -0
- package/docs/tools/agent-and-orchestration.md +49 -0
- package/docs/tools/browser-and-research.md +46 -0
- package/docs/tools/cloudflare-platform.md +32 -0
- package/docs/tools/cms.md +25 -0
- package/docs/tools/communications.md +41 -0
- package/docs/tools/database-and-storage.md +62 -0
- package/docs/tools/design-and-media.md +64 -0
- package/docs/tools/filesystem-and-code.md +55 -0
- package/docs/tools/github.md +56 -0
- package/docs/tools/integrations-and-misc.md +16 -0
- package/docs/tools/memory.md +21 -0
- package/docs/tools/terminal-and-execution.md +29 -0
- package/docs/tools/tickets-and-platform.md +30 -0
- package/migrations/d1/0001_agentsam_plugin_runtime.sql +177 -0
- package/migrations/d1/0002_agentsam_ticket_ownership.sql +8 -0
- package/migrations/d1/0002_dynamic_model_policies.sql +23 -0
- package/migrations/d1/0003_expand_tool_handler_families.sql +18 -0
- package/migrations/d1/0004_project_aware_retrieval_lanes.sql +24 -0
- package/migrations/d1/0005_portable_knowledge_identity.sql +104 -0
- package/migrations/d1/0006_repair_ops_trail_account_scope.sql +14 -0
- package/migrations/d1/0007_repair_ops_trail_agent_run_account.sql +13 -0
- package/migrations/d1/0008_backfill_knowledge_run_legacy_tenant.sql +14 -0
- package/migrations/d1/0009_normalize_cloudflare_plugin_installations.sql +137 -0
- package/migrations/runtime/0001_cli_runtime.sql +67 -0
- package/migrations/runtime/0002_project_sessions.sql +15 -0
- package/migrations/runtime/0003_provider_continuations.sql +8 -0
- package/package.json +92 -12
- package/packages/agentsam-brand/README.md +21 -0
- package/packages/agentsam-brand/package.json +22 -0
- package/packages/agentsam-brand/src/contract.js +59 -0
- package/packages/agentsam-brand/src/extract.js +126 -0
- package/packages/agentsam-brand/src/goap-actions.js +73 -0
- package/packages/agentsam-brand/src/index.js +48 -0
- package/packages/agentsam-brand/src/plan.js +115 -0
- package/packages/agentsam-brand/src/resolve.js +139 -0
- package/packages/agentsam-brand/src/scan.js +250 -0
- package/packages/agentsam-brand/test/brand-scan.test.mjs +106 -0
- package/packages/agentsam-contracts/README.md +23 -0
- package/packages/agentsam-contracts/package.json +32 -0
- package/packages/agentsam-contracts/src/adapter.ts +25 -0
- package/packages/agentsam-contracts/src/agent.ts +35 -0
- package/packages/agentsam-contracts/src/artifacts.ts +33 -0
- package/packages/agentsam-contracts/src/authority.ts +29 -0
- package/packages/agentsam-contracts/src/context.ts +16 -0
- package/packages/agentsam-contracts/src/errors.ts +46 -0
- package/packages/agentsam-contracts/src/events.ts +47 -0
- package/packages/agentsam-contracts/src/execution.ts +50 -0
- package/packages/agentsam-contracts/src/hooks.ts +40 -0
- package/packages/agentsam-contracts/src/identity.ts +16 -0
- package/packages/agentsam-contracts/src/index.ts +14 -0
- package/packages/agentsam-contracts/src/models.ts +9 -0
- package/packages/agentsam-contracts/src/providers.ts +33 -0
- package/packages/agentsam-contracts/src/repository.ts +64 -0
- package/packages/agentsam-contracts/src/tools.ts +98 -0
- package/packages/agentsam-contracts/test/contracts.test.mjs +16 -0
- package/packages/agentsam-contracts/test/errors-catalog.test.mjs +25 -0
- package/packages/agentsam-contracts/test/repository.test.mjs +18 -0
- package/packages/agentsam-contracts/tsconfig.json +12 -0
- package/packages/agentsam-errors/package.json +17 -0
- package/packages/agentsam-errors/src/adapters/anthropic.js +15 -0
- package/packages/agentsam-errors/src/adapters/cad.js +109 -0
- package/packages/agentsam-errors/src/adapters/cloudflare.js +21 -0
- package/packages/agentsam-errors/src/adapters/cursor.js +4 -0
- package/packages/agentsam-errors/src/adapters/device.js +38 -0
- package/packages/agentsam-errors/src/adapters/docker.js +28 -0
- package/packages/agentsam-errors/src/adapters/gcp.js +14 -0
- package/packages/agentsam-errors/src/adapters/github.js +22 -0
- package/packages/agentsam-errors/src/adapters/google.js +17 -0
- package/packages/agentsam-errors/src/adapters/index.js +55 -0
- package/packages/agentsam-errors/src/adapters/internal.js +40 -0
- package/packages/agentsam-errors/src/adapters/oauth.js +24 -0
- package/packages/agentsam-errors/src/adapters/openai.js +17 -0
- package/packages/agentsam-errors/src/adapters/process.js +35 -0
- package/packages/agentsam-errors/src/adapters/provider.js +114 -0
- package/packages/agentsam-errors/src/envelope.js +186 -0
- package/packages/agentsam-errors/src/error.js +24 -0
- package/packages/agentsam-errors/src/fingerprint.js +35 -0
- package/packages/agentsam-errors/src/index.js +10 -0
- package/packages/agentsam-errors/src/normalize.js +30 -0
- package/packages/agentsam-errors/src/redaction.js +52 -0
- package/packages/agentsam-errors/src/render.js +16 -0
- package/packages/agentsam-errors/src/retry.js +10 -0
- package/packages/agentsam-errors/src/transport.js +52 -0
- package/packages/agentsam-errors/src/vocabulary.js +320 -0
- package/packages/agentsam-errors/test/envelope.test.mjs +70 -0
- package/packages/agentsam-errors/test/providers.test.mjs +99 -0
- package/packages/agentsam-errors/test/redaction.test.mjs +21 -0
- package/packages/agentsam-errors/test/runtime-cad-device.test.mjs +76 -0
- package/packages/agentsam-errors/test/transport.test.mjs +46 -0
- package/packages/agentsam-knowledge/package.json +15 -0
- package/packages/agentsam-knowledge/src/autorag/index.js +64 -0
- package/packages/agentsam-knowledge/src/backends/index.js +26 -0
- package/packages/agentsam-knowledge/src/index.js +3 -0
- package/packages/agentsam-knowledge/src/providers/index.js +95 -0
- package/packages/agentsam-knowledge/test/autorag.test.mjs +42 -0
- package/packages/agentsam-nav/README.md +40 -0
- package/packages/agentsam-nav/dist/Nav.d.ts +43 -0
- package/packages/agentsam-nav/dist/NavCollapsible.d.ts +10 -0
- package/packages/agentsam-nav/dist/NavContent.d.ts +2 -0
- package/packages/agentsam-nav/dist/NavFooter.d.ts +2 -0
- package/packages/agentsam-nav/dist/NavGroup.d.ts +3 -0
- package/packages/agentsam-nav/dist/NavHeader.d.ts +2 -0
- package/packages/agentsam-nav/dist/NavMenu.d.ts +22 -0
- package/packages/agentsam-nav/dist/NavProvider.d.ts +35 -0
- package/packages/agentsam-nav/dist/NavTrigger.d.ts +2 -0
- package/packages/agentsam-nav/dist/Surfaces.d.ts +41 -0
- package/packages/agentsam-nav/dist/browser.d.ts +11 -0
- package/packages/agentsam-nav/dist/browser.global.js +132 -0
- package/packages/agentsam-nav/dist/browser.js +613 -0
- package/packages/agentsam-nav/dist/contracts.d.ts +76 -0
- package/packages/agentsam-nav/dist/index.d.ts +11 -0
- package/packages/agentsam-nav/dist/index.js +614 -0
- package/packages/agentsam-nav/dist/legacy.css +83 -0
- package/packages/agentsam-nav/dist/shell.css +113 -0
- package/packages/agentsam-nav/dist/theme.css +113 -0
- package/packages/agentsam-nav/dist/utils.d.ts +1 -0
- package/packages/agentsam-nav/package.json +43 -0
- package/packages/agentsam-queue-control/README.md +107 -0
- package/packages/agentsam-queue-control/package.json +31 -0
- package/packages/agentsam-queue-control/schemas/job-envelope.schema.json +56 -0
- package/packages/agentsam-queue-control/src/adapters/cloudflare.js +152 -0
- package/packages/agentsam-queue-control/src/adapters/memory.js +38 -0
- package/packages/agentsam-queue-control/src/contracts.js +130 -0
- package/packages/agentsam-queue-control/src/control-plane.js +141 -0
- package/packages/agentsam-queue-control/src/dispatch.js +43 -0
- package/packages/agentsam-queue-control/src/index.js +7 -0
- package/packages/agentsam-queue-control/src/policy.js +88 -0
- package/packages/agentsam-queue-control/src/topology.js +66 -0
- package/packages/agentsam-queue-control/test/queue-control.test.mjs +100 -0
- package/packages/agentsam-repository/src/goap.js +718 -0
- package/packages/agentsam-repository/src/goap.js.bak-20260922011251 +670 -0
- package/packages/agentsam-repository/src/index.js +5 -0
- package/packages/agentsam-repository/src/merkle/cloudflare-persistence.js +2 -2
- package/packages/agentsam-repository/src/tickets.js +184 -0
- package/packages/agentsam-repository/src/work-tracking.js +199 -0
- package/packages/agentsam-repository/src/workspace-state.js +176 -0
- package/packages/agentsam-repository/test/goap-tickets-workspace-state.test.mjs +152 -0
- package/packages/connectors/cloudflare/src/index.js +297 -15
- package/packages/connectors/cloudflare/src/owner.js +43 -40
- package/packages/connectors/cloudflare/src/routes.js +167 -26
- package/packages/connectors/cloudflare/tests/connector.test.mjs +112 -2
- package/packages/heuristic-theme/README.md +11 -0
- package/packages/heuristic-theme/package.json +25 -0
- package/packages/heuristic-theme/src/index.js +2 -0
- package/packages/heuristic-theme/src/registry.js +36 -0
- package/packages/heuristic-theme/src/theme.js +41 -0
- package/packages/heuristic-theme/test/theme.test.mjs +26 -0
- package/packages/identity/.agentsam/features/oauth-login-portal/agentsam.feature.json +64 -0
- package/packages/identity/.agentsam/features/oauth-login-portal/providers.json +96 -0
- package/packages/identity/.agentsam/features/oauth-login-portal/resources.json +47 -0
- package/packages/identity/.agentsam/features/oauth-login-portal/routes.json +74 -0
- package/packages/identity/.agentsam/features/oauth-login-portal/ui.json +35 -0
- package/packages/identity/package.json +4 -3
- package/packages/identity/src/adapters/cloudflare-d1/ids.js +4 -0
- package/packages/identity/src/adapters/cloudflare-d1/index.js +39 -1
- package/packages/identity/src/contracts/auth-config.js +23 -40
- package/packages/identity/src/contracts/provider.js +3 -2
- package/packages/identity/src/frontend/auth-portal/pages/login.html +7 -0
- package/packages/identity/src/index.js +2 -0
- package/packages/identity/src/oauth/credentials.js +13 -0
- package/packages/identity/src/oauth/iam-platform.js +5 -5
- package/packages/identity/src/providers/cloudflare/index.js +19 -0
- package/packages/identity/src/providers/cloudflare/mapper.js +21 -0
- package/packages/identity/src/providers/cloudflare/oauth.js +48 -0
- package/packages/identity/src/providers/cloudflare/profile.js +28 -0
- package/packages/identity/src/providers/index.js +18 -2
- package/packages/identity/src/server/identity-service.js +13 -3
- package/packages/identity/src/server/worker-router.js +63 -8
- package/packages/identity/tests/auth-config.test.mjs +14 -23
- package/packages/identity/tests/identity-service.test.mjs +15 -0
- package/packages/providers/completeful/README.md +38 -0
- package/packages/providers/completeful/package.json +29 -0
- package/packages/providers/completeful/src/client.js +162 -0
- package/packages/providers/completeful/src/events.js +49 -0
- package/packages/providers/completeful/src/index.js +22 -0
- package/packages/providers/completeful/src/tools.js +579 -0
- package/packages/providers/completeful/src/webhooks.js +55 -0
- package/packages/providers/completeful/test/provider.test.mjs +196 -0
- package/packages/theme-church-site/README.md +10 -0
- package/packages/theme-church-site/package.json +30 -0
- package/packages/theme-church-site/src/harvest.json +14 -0
- package/packages/theme-church-site/src/index.js +84 -0
- package/packages/theme-church-site/test/theme.test.mjs +19 -0
- package/packages/theme-companions-site/README.md +10 -0
- package/packages/theme-companions-site/package.json +30 -0
- package/packages/theme-companions-site/src/harvest.json +12 -0
- package/packages/theme-companions-site/src/index.js +82 -0
- package/packages/theme-companions-site/test/theme.test.mjs +19 -0
- package/packages/theme-floors-site/README.md +10 -0
- package/packages/theme-floors-site/package.json +30 -0
- package/packages/theme-floors-site/src/harvest.json +14 -0
- package/packages/theme-floors-site/src/index.js +82 -0
- package/packages/theme-floors-site/test/theme.test.mjs +19 -0
- package/packages/theme-fuelnfree-site/README.md +10 -0
- package/packages/theme-fuelnfree-site/package.json +30 -0
- package/packages/theme-fuelnfree-site/src/harvest.json +13 -0
- package/packages/theme-fuelnfree-site/src/index.js +81 -0
- package/packages/theme-fuelnfree-site/test/theme.test.mjs +19 -0
- package/packages/theme-handyman-site/README.md +10 -0
- package/packages/theme-handyman-site/package.json +30 -0
- package/packages/theme-handyman-site/src/harvest.json +10 -0
- package/packages/theme-handyman-site/src/index.js +83 -0
- package/packages/theme-handyman-site/test/theme.test.mjs +19 -0
- package/packages/theme-insurance-site/README.md +10 -0
- package/packages/theme-insurance-site/package.json +30 -0
- package/packages/theme-insurance-site/src/harvest.json +10 -0
- package/packages/theme-insurance-site/src/index.js +83 -0
- package/packages/theme-insurance-site/test/theme.test.mjs +19 -0
- package/packages/theme-shinshu-site/README.md +10 -0
- package/packages/theme-shinshu-site/package.json +30 -0
- package/packages/theme-shinshu-site/src/harvest.json +12 -0
- package/packages/theme-shinshu-site/src/index.js +83 -0
- package/packages/theme-shinshu-site/test/theme.test.mjs +19 -0
- package/packages/work-graph/README.md +49 -0
- package/packages/work-graph/package.json +19 -0
- package/packages/work-graph/prototype/README.md +32 -0
- package/packages/work-graph/prototype/data/demo-workgraph.js +47 -0
- package/packages/work-graph/prototype/renderers/timeline-model.js +21 -0
- package/packages/work-graph/prototype/renderers/workgraph-runtime.js +38 -0
- package/packages/work-graph/prototype-gnantt.html +655 -0
- package/packages/work-graph/src/adapters/business/projects.js +23 -0
- package/packages/work-graph/src/adapters/engineering/git.js +22 -0
- package/packages/work-graph/src/adapters/engineering/mcp.js +22 -0
- package/packages/work-graph/src/index.js +76 -0
- package/packages/work-graph/src/renderers/gantt-model.js +11 -0
- package/packages/work-graph/src/renderers/timeline.js +16 -0
- package/packages/work-graph/test/work-graph.test.mjs +37 -0
- package/protocol/README.md +12 -0
- package/protocol/capabilities/cloudflare-cpu-audit-input.schema.json +30 -6
- package/protocol/capabilities/cloudflare-cpu-profile-input.schema.json +18 -4
- package/protocol/capabilities/cloudflare-wrangler-native-input.schema.json +59 -10
- package/protocol/capabilities/knowledge-search-input.schema.json +35 -0
- package/protocol/capabilities/manifest.json +163 -1
- package/protocol/capabilities/repository-audit-input.schema.json +39 -6
- package/protocol/capabilities/repository-snapshot-input.schema.json +15 -3
- package/protocol/capabilities/terminal-exec-input.schema.json +55 -0
- package/protocol/commerce/catalog.v1.json +50 -0
- package/protocol/errors/error-catalog.json +164 -0
- package/protocol/errors/error-envelope.schema.json +544 -0
- package/protocol/features/README.md +57 -0
- package/protocol/features/agentsam.feature.v1.schema.json +290 -0
- package/protocol/features/catalog.json +65 -0
- package/protocol/features/examples/provider-resend.feature.json +17 -0
- package/protocol/go/agentsam-go-runtime.v1.json +17 -0
- package/protocol/knowledge/LIFECYCLE.md +140 -0
- package/protocol/knowledge/README.md +4 -0
- package/protocol/presets/catalog.json +128 -19
- package/protocol/rpc/v1/errors.proto +24 -0
- package/protocol/theme-refinery/d1-reconciliation.md +48 -0
- package/protocol/theme-refinery/product-metadata.schema.json +27 -0
- package/protocol/theme-refinery/receipts/products-registry-batch-20260924.json +318 -0
- package/protocol/theme-refinery/receipts/theme-harvest-20260924.json +472 -0
- package/protocol/theme-refinery/reconciliation-receipt.schema.json +83 -0
- package/services/cad/server.py +249 -2
- package/src/agent/capability-adapter.js +15 -5
- package/src/agent/index.js +2 -1
- package/src/agent/model-turn.js +51 -0
- package/src/agent/responses-runner.js +304 -38
- package/src/capabilities/index.js +1 -0
- package/src/capabilities/terminal-exec.js +78 -0
- package/src/cli.js +129 -31
- package/src/cloudflare/index.js +6 -0
- package/src/cloudflare/runtime-status.js +393 -0
- package/src/cloudflare/wrangler.js +17 -1
- package/src/commands/account-auth.js +1 -1
- package/src/commands/app.js +106 -0
- package/src/commands/autorag.js +77 -0
- package/src/commands/brand.js +293 -0
- package/src/commands/cad.js +1 -0
- package/src/commands/connections.js +126 -29
- package/src/commands/context-economics.js +8 -0
- package/src/commands/db.js +7 -0
- package/src/commands/deploy.js +2 -2
- package/src/commands/env.js +5 -4
- package/src/commands/eval.js +209 -14
- package/src/commands/go.js +365 -0
- package/src/commands/goap.js +176 -0
- package/src/commands/identity-init.js +27 -3
- package/src/commands/identity-protocol.js +195 -0
- package/src/commands/knowledge.js +64 -5
- package/src/commands/mcp.js +341 -0
- package/src/commands/merkle-persist.js +3 -1
- package/src/commands/merkle.js +18 -3
- package/src/commands/models.js +109 -23
- package/src/commands/plugins.js +175 -0
- package/src/commands/preferences.js +28 -8
- package/src/commands/product.js +53 -10
- package/src/commands/providers.js +389 -0
- package/src/commands/resume.js +9 -5
- package/src/commands/runtime-status.js +154 -0
- package/src/commands/shell.js +469 -54
- package/src/commands/status.js +82 -7
- package/src/commands/tunnel.js +228 -195
- package/src/commands/whoami.js +115 -22
- package/src/context/budget.js +6 -0
- package/src/context/index.js +2 -1
- package/src/context/project-card.js +75 -0
- package/src/errors/contract.js +34 -211
- package/src/errors/diagnostic.js +95 -50
- package/src/errors/index.js +6 -13
- package/src/eval/index.js +6 -0
- package/src/eval/live.js +439 -0
- package/src/features/resolve.js +242 -0
- package/src/go/build.js +108 -0
- package/src/go/cloudflare.js +207 -0
- package/src/go/contract.js +139 -0
- package/src/go/discover.js +96 -0
- package/src/go/index.js +13 -0
- package/src/go/receipts.js +77 -0
- package/src/go/registry.js +223 -0
- package/src/go/verify.js +31 -0
- package/src/index.js +100 -1
- package/src/knowledge/config.js +13 -5
- package/src/knowledge/engine.js +23 -8
- package/src/knowledge/index.js +1 -0
- package/src/knowledge/lane-registry.js +46 -0
- package/src/knowledge/providers/gemini.js +48 -8
- package/src/knowledge/service/client.js +13 -1
- package/src/knowledge/service/grpc-codec.js +156 -53
- package/src/knowledge/service/job-engine.js +133 -11
- package/src/knowledge/service/job-worker.js +34 -5
- package/src/knowledge/service/server.js +10 -1
- package/src/knowledge/store-discovery.js +77 -0
- package/src/lib/account-session.js +100 -25
- package/src/lib/agent-instructions.js +3 -0
- package/src/lib/auth.js +318 -51
- package/src/lib/cad/blender.js +42 -3
- package/src/lib/cad/d1-project-store.js +43 -0
- package/src/lib/cad/discovery.js +616 -0
- package/src/lib/cad/docker-executor.js +352 -0
- package/src/lib/cad/freecad.js +253 -0
- package/src/lib/cad/index.js +40 -0
- package/src/lib/cad/openscad.js +198 -0
- package/src/lib/cad/project-cli.d.ts +2 -0
- package/src/lib/cad/project-cli.js +21 -0
- package/src/lib/cad/project-contract.d.ts +3 -0
- package/src/lib/cad/project-contract.js +1 -0
- package/src/lib/cad/project-recipe.js +30 -0
- package/src/lib/cad/project-runtime.d.ts +2 -0
- package/src/lib/cad/project-runtime.js +53 -0
- package/src/lib/cad/project-store.js +25 -0
- package/src/lib/cad/project-workflows.js +31 -0
- package/src/lib/cad-docker.js +21 -2
- package/src/lib/cli-preferences.js +17 -2
- package/src/lib/core-client.js +97 -33
- package/src/lib/deploy/local-studio.js +6 -5
- package/src/lib/detect-context.js +14 -16
- package/src/lib/dockerize.js +3 -0
- package/src/lib/execution-approvals.js +1 -0
- package/src/lib/identity-scaffold.js +4 -1
- package/src/lib/knowledge-docker.js +9 -1
- package/src/lib/local-sessions.js +124 -34
- package/src/lib/local-status.js +35 -14
- package/src/lib/project-config.js +9 -0
- package/src/lib/provider-credentials.js +233 -55
- package/src/lib/scaffold/resolve-cloudflare-account.js +37 -0
- package/src/lib/scaffold/wizards/cms.js +2 -8
- package/src/lib/scaffold/wizards/worker-api.js +2 -8
- package/src/lib/slash-commands.js +10 -2
- package/src/local/migrations.js +109 -1
- package/src/local/runtime-store.js +31 -5
- package/src/local/sqlite.js +36 -1
- package/src/mcp/authority.js +348 -0
- package/src/mcp/client-adapters.js +431 -0
- package/src/mcp/client.js +172 -0
- package/src/mcp/index.js +47 -0
- package/src/mcp/telemetry.js +103 -0
- package/src/models/catalog.js +329 -51
- package/src/models/discovery.js +59 -4
- package/src/models/index.js +2 -0
- package/src/models/inventory-core.js +182 -0
- package/src/models/policy.js +20 -0
- package/src/plugins/cloudflare.js +103 -0
- package/src/plugins/completeful.js +69 -0
- package/src/plugins/contracts.js +86 -0
- package/src/plugins/index.js +11 -0
- package/src/plugins/registry.js +207 -0
- package/src/plugins/resource-scope.js +45 -0
- package/src/plugins/runtime.js +118 -0
- package/src/plugins/vectorize.js +31 -0
- package/src/progression/engine.js +171 -0
- package/src/progression/index.js +1 -0
- package/src/providers/cloudflare-chat.js +1 -1
- package/src/providers/gemini-generate-content.js +2 -1
- package/src/providers/openai-responses.js +45 -16
- package/src/providers/tool-schema.js +85 -0
- package/src/repository/index.js +29 -0
- package/src/rpc/generated/errors_pb.js +961 -1
- package/src/security/local-vault.js +415 -0
- package/src/security/process.js +20 -4
- package/src/status/actions.js +192 -0
- package/src/tools/hydrate.js +5 -1
- package/src/tools/index.js +7 -0
- package/src/tools/redact.js +64 -0
- package/src/tools/registry.js +83 -0
- package/src/tools/runtime.js +257 -0
- package/src/tools/search.js +21 -8
- package/src/ui/ansi.js +117 -3
- package/src/ui/cli/activity.js +76 -7
- package/src/ui/cli/footer.js +110 -9
- package/src/ui/cli/help.js +14 -5
- package/src/ui/wireframes.js +166 -0
- package/test/account-session.test.mjs +76 -11
- package/test/apps-scaffold-contract.test.mjs +58 -0
- package/test/capabilities.test.mjs +1 -1
- package/test/cli/eval-live.test.mjs +219 -0
- package/test/cli/go.test.mjs +71 -0
- package/test/cli/local-vault-and-provider-setup.test.mjs +268 -0
- package/test/cli/mcp-client.test.mjs +245 -0
- package/test/cli/runtime-ui.test.mjs +69 -2
- package/test/cli/status-actions.test.mjs +88 -0
- package/test/cli/wireframes-go-registry.test.mjs +54 -0
- package/test/cloudflare-connector.test.mjs +3 -6
- package/test/cloudflare-runtime.test.mjs +8 -1
- package/test/context.test.mjs +15 -0
- package/test/error-diagnostics.test.mjs +9 -0
- package/test/fixtures/cad/courtyard-house.json +208 -0
- package/test/go/cloudflare-probe.test.mjs +53 -0
- package/test/integration/app-command.test.mjs +55 -0
- package/test/integration/cad-discovery.test.mjs +158 -0
- package/test/integration/cad-docker-executor.test.mjs +249 -0
- package/test/integration/cad-execution.test.mjs +184 -0
- package/test/integration/cad-project-app.test.mjs +31 -0
- package/test/integration/cad-project-d1.test.mjs +25 -0
- package/test/integration/cad-project-native.test.mjs +24 -0
- package/test/integration/cad-project-workflow.test.mjs +9 -0
- package/test/integration/cad-project.test.mjs +82 -0
- package/test/integration/cli-help.test.mjs +4 -0
- package/test/integration/cms-site-tenancy-contract.test.mjs +256 -0
- package/test/integration/core-client.integration.test.mjs +55 -0
- package/test/integration/error-runtime-rpc.test.mjs +71 -0
- package/test/integration/features-resolve.test.mjs +128 -0
- package/test/integration/install-script.test.mjs +107 -0
- package/test/integration/inventory-core.test.mjs +53 -0
- package/test/integration/plugins-cloudflare.integration.test.mjs +28 -0
- package/test/integration/provider-env-cli.test.mjs +1 -1
- package/test/integration/runtime-migrations.test.mjs +6 -1
- package/test/integration/runtime-status.integration.test.mjs +211 -0
- package/test/integration/scaffold-cloudflare.test.mjs +46 -0
- package/test/integration/storage-architecture.test.mjs +154 -0
- package/test/integration/store-discovery.test.mjs +44 -0
- package/test/integration/terminal-exec.integration.test.mjs +86 -0
- package/test/integration/tool-runtime.test.mjs +124 -0
- package/test/integration/tool-schema.test.mjs +59 -0
- package/test/knowledge-service.test.mjs +4 -0
- package/test/local-sessions.test.mjs +11 -2
- package/test/local-studio-deploy.test.mjs +1 -1
- package/test/model-catalog.test.mjs +28 -1
- package/test/models.test.mjs +159 -5
- package/test/openai-responses.test.mjs +60 -0
- package/test/provider-credentials.test.mjs +15 -5
- package/test/responses-runner.test.mjs +321 -6
- package/test/sdk-worker-contract.test.mjs +5 -1
- package/test/shell.test.mjs +149 -4
- package/test/smoke.mjs +4 -3
- package/test/tools-search.test.mjs +33 -0
- package/test/unit/website-assets-bindings.test.mjs +60 -0
- package/test/whoami-resume.test.mjs +87 -7
- package/examples/gorilla-shell/README.md +0 -15
- package/src/lib/gorilla-template.js +0 -54
- package/src/lib/prompt-byok.js +0 -57
- package/src/lib/save-sdk-token.js +0 -19
- package/templates/gorilla-shell/App.tsx +0 -639
- package/templates/gorilla-shell/README.md +0 -34
- package/templates/gorilla-shell/index.html +0 -15
- package/templates/gorilla-shell/main.jsx +0 -9
- package/templates/gorilla-shell/package.json +0 -19
- package/templates/gorilla-shell/vite.config.js +0 -21
package/src/lib/auth.js
CHANGED
|
@@ -1,71 +1,338 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* RFC 8252 native-app OAuth for AgentSam CLI.
|
|
3
|
+
*
|
|
4
|
+
* The CLI is a public client: authorization code + PKCE over a loopback
|
|
5
|
+
* redirect. Browser OAuth sessions are machine-local and remain separate from
|
|
6
|
+
* reusable AGENTSAM_API_KEY (aak_*) credentials.
|
|
3
7
|
*/
|
|
4
8
|
import http from 'node:http';
|
|
5
|
-
import { randomBytes } from 'node:crypto';
|
|
6
|
-
import {
|
|
9
|
+
import { createHash, randomBytes } from 'node:crypto';
|
|
10
|
+
import { resolveIamIssuer } from '../../packages/identity/src/contracts/auth-config.js';
|
|
7
11
|
import { promptToOpenUrl } from './open-url.js';
|
|
8
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
isBrowserSessionExpired,
|
|
14
|
+
readAccountSession,
|
|
15
|
+
resolveAccountApiKey,
|
|
16
|
+
saveAccountSession,
|
|
17
|
+
} from './account-session.js';
|
|
9
18
|
|
|
10
|
-
|
|
11
|
-
|
|
19
|
+
export const AGENTSAM_NATIVE_OAUTH_CLIENT_ID = 'iam_cli_agentsam';
|
|
20
|
+
export const AGENTSAM_NATIVE_OAUTH_SCOPE = 'openid profile email offline_access';
|
|
21
|
+
export const AGENTSAM_OAUTH_CALLBACK_PATH = '/callback';
|
|
22
|
+
|
|
23
|
+
function clean(value) { return value == null ? '' : String(value).trim(); }
|
|
24
|
+
function base64url(value) {
|
|
25
|
+
return Buffer.from(value).toString('base64')
|
|
26
|
+
.replace(/=/g, '')
|
|
27
|
+
.replace(/\+/g, '-')
|
|
28
|
+
.replace(/\//g, '_');
|
|
29
|
+
}
|
|
30
|
+
function randomUrlSafe(bytes = 32, randomBytesImpl = randomBytes) {
|
|
31
|
+
return base64url(randomBytesImpl(bytes));
|
|
32
|
+
}
|
|
33
|
+
function oauthErrorMessage(body, status) {
|
|
34
|
+
const code = clean(body?.error);
|
|
35
|
+
const description = clean(body?.error_description || body?.message);
|
|
36
|
+
if (code && description) return `${code}: ${description}`;
|
|
37
|
+
return code || description || `OAuth token HTTP ${status}`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function createPkcePair(options = {}) {
|
|
41
|
+
const verifier = randomUrlSafe(32, options.randomBytesImpl || randomBytes);
|
|
42
|
+
const challenge = base64url(createHash('sha256').update(verifier, 'ascii').digest());
|
|
43
|
+
return Object.freeze({ verifier, challenge, method: 'S256' });
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function buildNativeAuthorizationUrl(options = {}) {
|
|
47
|
+
const env = options.env || process.env;
|
|
48
|
+
const issuer = resolveIamIssuer(env, options.issuer || '');
|
|
49
|
+
const clientId = clean(options.clientId) || AGENTSAM_NATIVE_OAUTH_CLIENT_ID;
|
|
50
|
+
const redirectUri = clean(options.redirectUri);
|
|
51
|
+
const state = clean(options.state);
|
|
52
|
+
const codeChallenge = clean(options.codeChallenge);
|
|
53
|
+
const scope = clean(options.scope ?? AGENTSAM_NATIVE_OAUTH_SCOPE);
|
|
54
|
+
if (!redirectUri || !state || !codeChallenge) throw new Error('oauth_authorization_parameters_required');
|
|
55
|
+
|
|
56
|
+
const url = new URL('/api/oauth/authorize', `${issuer}/`);
|
|
57
|
+
url.searchParams.set('response_type', 'code');
|
|
58
|
+
url.searchParams.set('client_id', clientId);
|
|
59
|
+
url.searchParams.set('redirect_uri', redirectUri);
|
|
60
|
+
url.searchParams.set('code_challenge', codeChallenge);
|
|
61
|
+
url.searchParams.set('code_challenge_method', 'S256');
|
|
62
|
+
url.searchParams.set('state', state);
|
|
63
|
+
if (scope) url.searchParams.set('scope', scope);
|
|
64
|
+
return url.toString();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async function oauthTokenRequest(params, options = {}) {
|
|
68
|
+
const env = options.env || process.env;
|
|
69
|
+
const issuer = resolveIamIssuer(env, options.issuer || '');
|
|
70
|
+
const fetchImpl = options.fetchImpl || fetch;
|
|
71
|
+
const body = new URLSearchParams();
|
|
72
|
+
for (const [key, value] of Object.entries(params || {})) {
|
|
73
|
+
const normalized = clean(value);
|
|
74
|
+
if (normalized) body.set(key, normalized);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const response = await fetchImpl(new URL('/api/oauth/token', `${issuer}/`).toString(), {
|
|
78
|
+
method: 'POST',
|
|
79
|
+
headers: {
|
|
80
|
+
Accept: 'application/json',
|
|
81
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
82
|
+
},
|
|
83
|
+
body: body.toString(),
|
|
84
|
+
signal: options.signal || (typeof AbortSignal?.timeout === 'function' ? AbortSignal.timeout(15_000) : undefined),
|
|
85
|
+
});
|
|
86
|
+
const data = await response.json().catch(() => ({}));
|
|
87
|
+
if (!response.ok) {
|
|
88
|
+
const error = new Error(oauthErrorMessage(data, response.status));
|
|
89
|
+
error.status = response.status;
|
|
90
|
+
error.oauth_error = clean(data?.error) || null;
|
|
91
|
+
throw error;
|
|
92
|
+
}
|
|
93
|
+
if (!clean(data?.access_token)) throw new Error('oauth_token_response_missing_access_token');
|
|
94
|
+
return data;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export async function exchangeAuthorizationCode(options = {}) {
|
|
98
|
+
const code = clean(options.code);
|
|
99
|
+
const codeVerifier = clean(options.codeVerifier);
|
|
100
|
+
const redirectUri = clean(options.redirectUri);
|
|
101
|
+
if (!code || !codeVerifier || !redirectUri) throw new Error('oauth_authorization_code_exchange_parameters_required');
|
|
102
|
+
return oauthTokenRequest({
|
|
103
|
+
grant_type: 'authorization_code',
|
|
104
|
+
client_id: clean(options.clientId) || AGENTSAM_NATIVE_OAUTH_CLIENT_ID,
|
|
105
|
+
redirect_uri: redirectUri,
|
|
106
|
+
code,
|
|
107
|
+
code_verifier: codeVerifier,
|
|
108
|
+
}, options);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export async function refreshAccountSession(options = {}) {
|
|
112
|
+
const session = options.session || readAccountSession(options);
|
|
113
|
+
if (!session?.refresh_token) throw new Error('browser_oauth_refresh_unavailable');
|
|
114
|
+
const clientId = clean(session.client_id) || clean(options.clientId) || AGENTSAM_NATIVE_OAUTH_CLIENT_ID;
|
|
115
|
+
const refreshed = await oauthTokenRequest({
|
|
116
|
+
grant_type: 'refresh_token',
|
|
117
|
+
client_id: clientId,
|
|
118
|
+
refresh_token: session.refresh_token,
|
|
119
|
+
}, options);
|
|
120
|
+
|
|
121
|
+
return saveAccountSession({
|
|
122
|
+
...refreshed,
|
|
123
|
+
refresh_token: clean(refreshed.refresh_token) || session.refresh_token,
|
|
124
|
+
client_id: clientId,
|
|
125
|
+
user_id: session.user_id,
|
|
126
|
+
account_id: session.account_id,
|
|
127
|
+
email: session.email,
|
|
128
|
+
}, {
|
|
129
|
+
...options,
|
|
130
|
+
preserveRefreshToken: true,
|
|
131
|
+
});
|
|
12
132
|
}
|
|
13
133
|
|
|
14
134
|
/**
|
|
15
|
-
*
|
|
135
|
+
* Canonical SDK account authority resolution.
|
|
136
|
+
* explicit aak_* -> AGENTSAM_API_KEY -> stored browser OAuth -> OAuth refresh.
|
|
16
137
|
*/
|
|
17
|
-
export async function
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
138
|
+
export async function resolveAccountAuthority(options = {}) {
|
|
139
|
+
const apiKey = resolveAccountApiKey(options);
|
|
140
|
+
if (apiKey.value) return apiKey;
|
|
141
|
+
if (clean(options.explicit) && apiKey.error) return apiKey;
|
|
21
142
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
143
|
+
let session = readAccountSession(options);
|
|
144
|
+
if (!session?.access_token) {
|
|
145
|
+
return apiKey.error ? apiKey : { value: '', source: null, kind: null, session: null };
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (options.forceRefresh === true || isBrowserSessionExpired(session, options)) {
|
|
149
|
+
if (!session.refresh_token) {
|
|
150
|
+
return {
|
|
151
|
+
value: '',
|
|
152
|
+
source: 'agentsam_browser_oauth',
|
|
153
|
+
kind: 'browser_oauth',
|
|
154
|
+
session,
|
|
155
|
+
error: 'browser_oauth_session_expired',
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
try {
|
|
159
|
+
const refreshImpl = options.refreshImpl || refreshAccountSession;
|
|
160
|
+
session = await refreshImpl({ ...options, session });
|
|
161
|
+
} catch (error) {
|
|
162
|
+
return {
|
|
163
|
+
value: '',
|
|
164
|
+
source: 'agentsam_browser_oauth',
|
|
165
|
+
kind: 'browser_oauth',
|
|
166
|
+
session,
|
|
167
|
+
error: `browser_oauth_refresh_failed: ${error?.message || String(error)}`,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return {
|
|
173
|
+
value: session.access_token,
|
|
174
|
+
source: 'agentsam_browser_oauth',
|
|
175
|
+
kind: 'browser_oauth',
|
|
176
|
+
session,
|
|
177
|
+
fallback_error: apiKey.error || null,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export async function createLoopbackCallbackListener(options = {}) {
|
|
182
|
+
const host = clean(options.host) || '127.0.0.1';
|
|
183
|
+
const callbackPath = clean(options.callbackPath) || AGENTSAM_OAUTH_CALLBACK_PATH;
|
|
184
|
+
const expectedState = clean(options.state);
|
|
185
|
+
if (!expectedState) throw new Error('oauth_state_required');
|
|
186
|
+
const timeoutMs = Number.isFinite(Number(options.timeoutMs)) ? Number(options.timeoutMs) : 180_000;
|
|
187
|
+
const createServerImpl = options.createServerImpl || http.createServer;
|
|
188
|
+
|
|
189
|
+
let settle;
|
|
190
|
+
let settled = false;
|
|
191
|
+
let timer = null;
|
|
192
|
+
const callbackPromise = new Promise((resolve, reject) => {
|
|
193
|
+
settle = (error, result) => {
|
|
194
|
+
if (settled) return;
|
|
195
|
+
settled = true;
|
|
196
|
+
if (timer) clearTimeout(timer);
|
|
197
|
+
if (error) reject(error);
|
|
198
|
+
else resolve(result);
|
|
199
|
+
};
|
|
25
200
|
});
|
|
26
201
|
|
|
27
|
-
|
|
202
|
+
const server = createServerImpl((req, res) => {
|
|
203
|
+
try {
|
|
204
|
+
const requestUrl = new URL(req.url || '/', `http://${host}`);
|
|
205
|
+
if (requestUrl.pathname !== callbackPath) {
|
|
206
|
+
res.writeHead(404, { 'Content-Type': 'text/plain; charset=utf-8' });
|
|
207
|
+
res.end('Not found');
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
28
210
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const gotState = u.searchParams.get('state');
|
|
40
|
-
if (!code || gotState !== state) {
|
|
41
|
-
res.writeHead(400);
|
|
42
|
-
res.end('Invalid callback');
|
|
43
|
-
reject(new Error('auth callback invalid'));
|
|
44
|
-
server.close();
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
48
|
-
res.end('<html><body style="font-family:system-ui"><h1>Agent Sam</h1><p>Authentication complete. You can close this tab and return to your terminal.</p></body></html>');
|
|
49
|
-
resolve(code);
|
|
50
|
-
server.close();
|
|
51
|
-
} catch (e) {
|
|
52
|
-
reject(e);
|
|
53
|
-
server.close();
|
|
211
|
+
const returnedState = clean(requestUrl.searchParams.get('state'));
|
|
212
|
+
const oauthError = clean(requestUrl.searchParams.get('error'));
|
|
213
|
+
const oauthDescription = clean(requestUrl.searchParams.get('error_description'));
|
|
214
|
+
const code = clean(requestUrl.searchParams.get('code'));
|
|
215
|
+
|
|
216
|
+
if (!returnedState || returnedState !== expectedState) {
|
|
217
|
+
res.writeHead(400, { 'Content-Type': 'text/plain; charset=utf-8' });
|
|
218
|
+
res.end('Invalid OAuth state. Return to the terminal and retry.');
|
|
219
|
+
settle(new Error('oauth_state_mismatch'));
|
|
220
|
+
return;
|
|
54
221
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
222
|
+
if (oauthError) {
|
|
223
|
+
res.writeHead(400, { 'Content-Type': 'text/plain; charset=utf-8' });
|
|
224
|
+
res.end('Authorization was not completed. Return to the terminal.');
|
|
225
|
+
settle(new Error(oauthDescription ? `${oauthError}: ${oauthDescription}` : oauthError));
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
if (!code) {
|
|
229
|
+
res.writeHead(400, { 'Content-Type': 'text/plain; charset=utf-8' });
|
|
230
|
+
res.end('Authorization code missing. Return to the terminal and retry.');
|
|
231
|
+
settle(new Error('oauth_authorization_code_missing'));
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
236
|
+
res.end('<!doctype html><html><body style="font-family:system-ui"><h1>Agent Sam</h1><p>Authentication complete. You can close this tab and return to your terminal.</p></body></html>');
|
|
237
|
+
settle(null, { code, state: returnedState });
|
|
238
|
+
} catch (error) {
|
|
239
|
+
try {
|
|
240
|
+
res.writeHead(500, { 'Content-Type': 'text/plain; charset=utf-8' });
|
|
241
|
+
res.end('OAuth callback failed. Return to the terminal.');
|
|
242
|
+
} catch { /* response may already be closed */ }
|
|
243
|
+
settle(error);
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
await new Promise((resolve, reject) => {
|
|
248
|
+
const onError = (error) => {
|
|
249
|
+
server.off('listening', onListening);
|
|
250
|
+
reject(error);
|
|
251
|
+
};
|
|
252
|
+
const onListening = () => {
|
|
253
|
+
server.off('error', onError);
|
|
254
|
+
resolve();
|
|
255
|
+
};
|
|
256
|
+
server.once('error', onError);
|
|
257
|
+
server.once('listening', onListening);
|
|
258
|
+
server.listen({ host, port: Number(options.port) || 0, exclusive: true });
|
|
58
259
|
});
|
|
59
260
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
261
|
+
const address = server.address();
|
|
262
|
+
if (!address || typeof address === 'string') {
|
|
263
|
+
server.close();
|
|
264
|
+
throw new Error('oauth_loopback_listener_address_unavailable');
|
|
265
|
+
}
|
|
266
|
+
const redirectUri = `http://${host}:${address.port}${callbackPath}`;
|
|
267
|
+
timer = setTimeout(() => settle(new Error('oauth_callback_timeout')), Math.max(1, timeoutMs));
|
|
268
|
+
timer.unref?.();
|
|
269
|
+
|
|
270
|
+
return {
|
|
271
|
+
redirectUri,
|
|
272
|
+
waitForCallback: () => callbackPromise,
|
|
273
|
+
close: () => new Promise((resolve) => {
|
|
274
|
+
if (!server.listening) return resolve();
|
|
275
|
+
server.close(() => resolve());
|
|
276
|
+
}),
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
export async function authenticateViaBrowser(options = {}) {
|
|
281
|
+
const env = options.env || process.env;
|
|
282
|
+
const clientId = clean(options.clientId) || AGENTSAM_NATIVE_OAUTH_CLIENT_ID;
|
|
283
|
+
const state = randomUrlSafe(24, options.randomBytesImpl || randomBytes);
|
|
284
|
+
const pkce = createPkcePair({ randomBytesImpl: options.randomBytesImpl });
|
|
285
|
+
const listener = await createLoopbackCallbackListener({
|
|
286
|
+
state,
|
|
287
|
+
host: options.host,
|
|
288
|
+
port: options.port,
|
|
289
|
+
callbackPath: options.callbackPath,
|
|
290
|
+
timeoutMs: options.timeoutMs,
|
|
291
|
+
createServerImpl: options.createServerImpl,
|
|
63
292
|
});
|
|
64
293
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
294
|
+
try {
|
|
295
|
+
const authorizationUrl = buildNativeAuthorizationUrl({
|
|
296
|
+
env,
|
|
297
|
+
issuer: options.issuer,
|
|
298
|
+
clientId,
|
|
299
|
+
redirectUri: listener.redirectUri,
|
|
300
|
+
state,
|
|
301
|
+
codeChallenge: pkce.challenge,
|
|
302
|
+
scope: options.scope,
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
const promptImpl = options.promptToOpenUrlImpl || promptToOpenUrl;
|
|
306
|
+
await promptImpl(authorizationUrl, {
|
|
307
|
+
heading: 'Authenticate your InnerAnimalMedia account at:',
|
|
308
|
+
prompt: 'Press ENTER to open InnerAnimalMedia sign-in in your browser.',
|
|
309
|
+
input: options.input,
|
|
310
|
+
output: options.output,
|
|
311
|
+
openImpl: options.openImpl,
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
const callback = await listener.waitForCallback();
|
|
315
|
+
const tokenSet = await exchangeAuthorizationCode({
|
|
316
|
+
env,
|
|
317
|
+
issuer: options.issuer,
|
|
318
|
+
clientId,
|
|
319
|
+
redirectUri: listener.redirectUri,
|
|
320
|
+
code: callback.code,
|
|
321
|
+
codeVerifier: pkce.verifier,
|
|
322
|
+
fetchImpl: options.fetchImpl,
|
|
323
|
+
signal: options.signal,
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
return saveAccountSession({
|
|
327
|
+
...tokenSet,
|
|
328
|
+
client_id: clientId,
|
|
329
|
+
}, {
|
|
330
|
+
home: options.home,
|
|
331
|
+
env,
|
|
332
|
+
nowMs: options.nowMs,
|
|
333
|
+
preserveRefreshToken: false,
|
|
334
|
+
});
|
|
335
|
+
} finally {
|
|
336
|
+
await listener.close();
|
|
69
337
|
}
|
|
70
|
-
return session;
|
|
71
338
|
}
|
package/src/lib/cad/blender.js
CHANGED
|
@@ -4,9 +4,11 @@ import path from 'node:path';
|
|
|
4
4
|
import { createHash } from 'node:crypto';
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
6
6
|
import { runProcess } from '../../security/process.js';
|
|
7
|
+
import { probeDockerServiceHealth, executeBlenderDocker } from './docker-executor.js';
|
|
7
8
|
|
|
8
9
|
const sdkRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../..');
|
|
9
|
-
|
|
10
|
+
const packagedAdapter = path.join(path.dirname(fileURLToPath(import.meta.url)), 'cad/blender/adapter.py');
|
|
11
|
+
export const BLENDER_ADAPTER_PATH = fs.existsSync(packagedAdapter) ? packagedAdapter : path.join(sdkRoot, 'services/cad/blender/adapter.py');
|
|
10
12
|
export const BLENDER_RESULT_PREFIX = 'AGENTSAM_RESULT=';
|
|
11
13
|
export const BLENDER_EXPORT_FORMATS = Object.freeze(['glb', 'stl', 'obj']);
|
|
12
14
|
export const BLENDER_RECIPE_OPS = Object.freeze([
|
|
@@ -172,9 +174,46 @@ async function invokeBlender({
|
|
|
172
174
|
runProcessImpl = runProcess,
|
|
173
175
|
}) {
|
|
174
176
|
const binary = discoverBlender({ blenderBin });
|
|
175
|
-
if (!binary) throw new Error('Blender is not installed or could not be discovered; use --blender-bin or AGENTSAM_BLENDER_BIN');
|
|
176
|
-
if (!fs.existsSync(BLENDER_ADAPTER_PATH)) throw new Error(`Bundled Blender adapter is missing: ${BLENDER_ADAPTER_PATH}`);
|
|
177
177
|
const timeout = boundedInteger(timeoutSeconds, 120, 1, 600, 'timeout');
|
|
178
|
+
|
|
179
|
+
if (!binary || !fs.existsSync(BLENDER_ADAPTER_PATH)) {
|
|
180
|
+
try {
|
|
181
|
+
const dockerHealth = await probeDockerServiceHealth();
|
|
182
|
+
if (dockerHealth.available && dockerHealth.tools?.blender?.installed) {
|
|
183
|
+
// Forward the full operation request (recipe/scene/camera/width/height/
|
|
184
|
+
// format/objects/collection/apply_modifiers as applicable) — the
|
|
185
|
+
// docker service has no access to `request.output`'s local path, so
|
|
186
|
+
// strip it and let the container pick its own temp output path.
|
|
187
|
+
const { output: _localOutput, ...requestRest } = request || {};
|
|
188
|
+
const inputBase64 = input && fs.existsSync(input) ? fs.readFileSync(input).toString('base64') : null;
|
|
189
|
+
|
|
190
|
+
const dockerRes = await executeBlenderDocker({
|
|
191
|
+
operation,
|
|
192
|
+
request: requestRest,
|
|
193
|
+
inputBase64,
|
|
194
|
+
format: requestRest.format
|
|
195
|
+
|| (operation === 'build' ? 'blend' : operation === 'render_preview' ? 'png' : 'glb'),
|
|
196
|
+
filename: request.output ? path.basename(request.output) : undefined,
|
|
197
|
+
timeoutMs: timeout * 1000,
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
if (request.output && dockerRes.artifactBase64) {
|
|
201
|
+
const outputPath = path.resolve(cwd, request.output);
|
|
202
|
+
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
|
|
203
|
+
fs.writeFileSync(outputPath, Buffer.from(dockerRes.artifactBase64, 'base64'));
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return {
|
|
207
|
+
result: dockerRes.result || { ok: true, blender_version: dockerHealth.tools.blender.version },
|
|
208
|
+
binary: `docker://${dockerHealth.service || 'agentsam-cad'}/blender`,
|
|
209
|
+
duration_ms: dockerRes.durationMs,
|
|
210
|
+
execution_lane: 'docker_service',
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
} catch {}
|
|
214
|
+
|
|
215
|
+
throw new Error('Blender is not installed or could not be discovered; use --blender-bin, AGENTSAM_BLENDER_BIN, or launch AgentSam CAD Docker service');
|
|
216
|
+
}
|
|
178
217
|
const requestDir = fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-blender-'));
|
|
179
218
|
const requestPath = path.join(requestDir, 'request.json');
|
|
180
219
|
fs.writeFileSync(requestPath, JSON.stringify({ schema_version: 1, ...request }, null, 2), { mode: 0o600 });
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import {randomUUID} from 'node:crypto';
|
|
2
|
+
import {requireValidProject} from './project-contract.js';
|
|
3
|
+
import {projectHash} from './project-store.js';
|
|
4
|
+
// Reuses blueprint documents + immutable R2 scene snapshots. No new tables.
|
|
5
|
+
// scope is supplied by the authenticated host, never by tool arguments.
|
|
6
|
+
export class D1ProjectStore {
|
|
7
|
+
constructor({db,objects,bucket,scope}) {
|
|
8
|
+
if(!scope?.account_id||!scope?.workspace_id||!scope?.tenant_id||!bucket)throw new Error('authenticated_design_scope_required');
|
|
9
|
+
this.db=db;this.objects=objects;this.bucket=bucket;this.scope=scope;
|
|
10
|
+
}
|
|
11
|
+
async read(id,revision){
|
|
12
|
+
const s=this.scope;
|
|
13
|
+
const row=await this.db.prepare("SELECT * FROM designstudio_design_blueprints WHERE id=? AND tenant_id=? AND workspace_id=? AND json_extract(intent_json,'$.account_id')=?").bind(id,s.tenant_id,s.workspace_id,s.account_id).first();
|
|
14
|
+
if(!row)throw new Error('project_not_found');
|
|
15
|
+
const current=JSON.parse(row.generation_config_json||'{}').project_revision;
|
|
16
|
+
if(revision==null||revision===current){const p=JSON.parse(row.sketch_json);return {project:p,revision:current,content_hash:projectHash(p)};}
|
|
17
|
+
const snapshot=await this.db.prepare("SELECT r2_key FROM scene_snapshots WHERE project_id=? AND user_id=? AND workspace_id=? AND tenant_id=? AND version=? AND project_type='CAD_PROJECT'").bind(id,s.account_id,s.workspace_id,s.tenant_id,revision).first();
|
|
18
|
+
if(!snapshot)throw new Error('revision_not_found');
|
|
19
|
+
const object=await this.objects.get(snapshot.r2_key);if(!object)throw new Error('revision_object_missing');
|
|
20
|
+
const saved=JSON.parse(await object.text());requireValidProject(saved.project);if(saved.content_hash!==projectHash(saved.project))throw new Error('revision_digest_mismatch');return saved;
|
|
21
|
+
}
|
|
22
|
+
async save(project,expectedRevision,message='Saved project'){
|
|
23
|
+
requireValidProject(project);
|
|
24
|
+
if(!Number.isSafeInteger(expectedRevision)||expectedRevision<0)throw new Error('expected_revision_required');
|
|
25
|
+
const s=this.scope,revision=expectedRevision+1,now=Math.floor(Date.now()/1000),id='scene_'+randomUUID().replaceAll('-','');
|
|
26
|
+
const p={...structuredClone(project),version:revision,updatedAt:Date.now()};
|
|
27
|
+
const saved={project:p,revision,content_hash:projectHash(p),message,created_at:now};
|
|
28
|
+
const key='design-projects/'+encodeURIComponent(s.account_id)+'/'+encodeURIComponent(p.id)+'/'+revision+'/'+saved.content_hash+'.json';
|
|
29
|
+
await this.objects.put(key,JSON.stringify(saved),{httpMetadata:{contentType:'application/json'}});
|
|
30
|
+
const statements=[];
|
|
31
|
+
if(expectedRevision===0){
|
|
32
|
+
statements.push(this.db.prepare("INSERT INTO designstudio_design_blueprints (id,tenant_id,workspace_id,title,intent_json,sketch_json,generation_config_json,status) VALUES (?,?,?,?,?,?,?,'structured')").bind(p.id,s.tenant_id,s.workspace_id,p.name,JSON.stringify({account_id:s.account_id,contract:'cad.project.v1'}),JSON.stringify(p),JSON.stringify({project_revision:revision,content_hash:saved.content_hash})));
|
|
33
|
+
}else{
|
|
34
|
+
statements.push(this.db.prepare("UPDATE designstudio_design_blueprints SET title=?,sketch_json=?,generation_config_json=json_set(generation_config_json,'$.project_revision',?,'$.content_hash',?),updated_at=datetime('now') WHERE id=? AND tenant_id=? AND workspace_id=? AND json_extract(intent_json,'$.account_id')=? AND json_extract(generation_config_json,'$.project_revision')=?").bind(p.name,JSON.stringify(p),revision,saved.content_hash,p.id,s.tenant_id,s.workspace_id,s.account_id,expectedRevision));
|
|
35
|
+
}
|
|
36
|
+
// D1 batch is transactional; changes() guards the snapshot against a failed CAS.
|
|
37
|
+
statements.push(this.db.prepare("INSERT INTO scene_snapshots (id,workspace_id,user_id,tenant_id,name,project_type,entity_count,r2_key,r2_bucket,project_id,version,description,created_at,updated_at) SELECT ?,?,?,?,?,'CAD_PROJECT',?,?,?,?,?,?,?,? WHERE changes()=1").bind(id,s.workspace_id,s.account_id,s.tenant_id,p.name,p.walls.length+p.rooms.length+p.doors.length+p.windows.length,key,this.bucket,p.id,revision,message,now,now));
|
|
38
|
+
let results;try{results=await this.db.batch(statements);}catch(e){throw new Error('project_save_failed:'+e.message);}
|
|
39
|
+
if(results[0]?.meta?.changes!==1)throw new Error('revision_conflict');
|
|
40
|
+
return saved;
|
|
41
|
+
}
|
|
42
|
+
async restore(id,revision,expectedRevision){const row=await this.read(id,revision);return this.save(row.project,expectedRevision,'Restored revision '+revision);}
|
|
43
|
+
}
|