@inneranimalmedia/agentsam-sdk 2.6.2 → 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/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/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 +3 -2
- 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/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/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 +117 -9
- 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/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/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 +118 -37
- package/src/commands/resume.js +9 -5
- package/src/commands/runtime-status.js +154 -0
- package/src/commands/shell.js +466 -55
- package/src/commands/status.js +82 -7
- package/src/commands/tunnel.js +228 -195
- package/src/commands/whoami.js +78 -6
- 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 -51
- 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 +8 -2
- package/src/lib/agent-instructions.js +3 -0
- package/src/lib/auth.js +7 -3
- 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 +37 -18
- package/src/lib/deploy/local-studio.js +6 -5
- 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 +73 -11
- 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 +9 -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 +24 -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 +11 -4
- package/src/ui/wireframes.js +166 -0
- package/test/account-session.test.mjs +28 -0
- package/test/apps-scaffold-contract.test.mjs +16 -1
- 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/shell.test.mjs +149 -4
- package/test/smoke.mjs +2 -2
- package/test/tools-search.test.mjs +33 -0
- package/test/unit/website-assets-bindings.test.mjs +60 -0
- package/test/whoami-resume.test.mjs +82 -3
- package/examples/gorilla-shell/README.md +0 -15
- package/src/lib/gorilla-template.js +0 -54
- 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/dockerize.js
CHANGED
|
@@ -98,6 +98,7 @@ function generateViteReact(opts) {
|
|
|
98
98
|
FROM node:20-alpine AS build
|
|
99
99
|
WORKDIR /app
|
|
100
100
|
COPY package*.json ./
|
|
101
|
+
RUN apk add --no-cache python3 make g++
|
|
101
102
|
RUN if [ -f package-lock.json ]; then npm ci; else npm install; fi
|
|
102
103
|
COPY . .
|
|
103
104
|
RUN ${buildCmd}
|
|
@@ -125,6 +126,7 @@ function generateNodeService(opts) {
|
|
|
125
126
|
FROM node:20-alpine
|
|
126
127
|
WORKDIR /app
|
|
127
128
|
COPY package*.json ./
|
|
129
|
+
RUN apk add --no-cache python3 make g++
|
|
128
130
|
RUN if [ -f package-lock.json ]; then npm ci --omit=dev; else npm install --omit=dev; fi
|
|
129
131
|
COPY . .
|
|
130
132
|
ENV PORT=${port}
|
|
@@ -152,6 +154,7 @@ function generateWranglerDev(opts) {
|
|
|
152
154
|
FROM node:20-alpine
|
|
153
155
|
WORKDIR /app
|
|
154
156
|
COPY package*.json ./
|
|
157
|
+
RUN apk add --no-cache python3 make g++
|
|
155
158
|
RUN if [ -f package-lock.json ]; then npm ci; else npm install; fi
|
|
156
159
|
COPY . .
|
|
157
160
|
EXPOSE ${port}
|
|
@@ -33,6 +33,7 @@ export function toolApprovalKey(capabilityId, input = {}) {
|
|
|
33
33
|
const id = clean(capabilityId);
|
|
34
34
|
const command = clean(input?.command);
|
|
35
35
|
if (id === 'cloudflare.wrangler.native' && /^[A-Za-z0-9._-]+$/.test(command)) return `${id}:${command}`;
|
|
36
|
+
if (id === 'terminal.exec' && /^[A-Za-z0-9._+-]+$/.test(command)) return `${id}:${command}`;
|
|
36
37
|
return id;
|
|
37
38
|
}
|
|
38
39
|
|
|
@@ -9,7 +9,7 @@ const MIGRATION_FILE = path.join(IDENTITY_PKG, 'src', 'migrations', '0001_identi
|
|
|
9
9
|
const BRANDING_SCRIPT = path.join(IDENTITY_PKG, 'src', 'frontend', 'auth-portal', 'shared', 'company-branding.js');
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
-
* @param {{ projectName: string, brandName?: string, logoUrl?: string, sdkVersion?: string }} config
|
|
12
|
+
* @param {{ projectName: string, brandName?: string, logoUrl?: string, sdkVersion?: string, provider?: string }} config
|
|
13
13
|
* @returns {Record<string, string>}
|
|
14
14
|
*/
|
|
15
15
|
export function buildIdentityAppScaffold(config) {
|
|
@@ -17,6 +17,7 @@ export function buildIdentityAppScaffold(config) {
|
|
|
17
17
|
const brandName = config.brandName || projectName;
|
|
18
18
|
const logoUrl = config.logoUrl || '/brand/logo.svg';
|
|
19
19
|
const sdkVersion = config.sdkVersion || 'alpha';
|
|
20
|
+
const provider = config.provider || 'inneranimalmedia';
|
|
20
21
|
|
|
21
22
|
const migrationSql = `${fs.readFileSync(MIGRATION_FILE, 'utf8')}\n${buildCompanySeedSql({ brandName, logoUrl })}\n`;
|
|
22
23
|
const loginHtml = injectBrandingScript(applyBrandTokens(fs.readFileSync(path.join(AUTH_PAGES_DIR, 'login.html'), 'utf8'), {
|
|
@@ -95,6 +96,8 @@ migrations_dir = "migrations"
|
|
|
95
96
|
|
|
96
97
|
Boring scaffold: **app/frontend** (auth UI) + **backend** (Worker API) + **migrations** (D1).
|
|
97
98
|
|
|
99
|
+
Provider template: \`${provider}\` (see \`agentsam identity plan --provider ${provider}\`).
|
|
100
|
+
|
|
98
101
|
## Quick start
|
|
99
102
|
|
|
100
103
|
\`\`\`bash
|
|
@@ -7,7 +7,13 @@ import { CONFIG_PATH, defaultConfig, readConfig } from '../knowledge/config.js';
|
|
|
7
7
|
|
|
8
8
|
const sdkRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');
|
|
9
9
|
const runtimeFiles = () => {
|
|
10
|
-
const files = [
|
|
10
|
+
const files = [
|
|
11
|
+
'services/knowledge/package.json',
|
|
12
|
+
'services/knowledge/package-lock.json',
|
|
13
|
+
'packages/agentsam-repository/src/merkle/hash.js',
|
|
14
|
+
'packages/agentsam-errors/package.json',
|
|
15
|
+
'src/errors/contract.js',
|
|
16
|
+
];
|
|
11
17
|
const walk = dir => { for (const entry of fs.readdirSync(path.join(sdkRoot, dir), { withFileTypes: true })) {
|
|
12
18
|
const file = `${dir}/${entry.name}`;
|
|
13
19
|
if (entry.isDirectory()) walk(file);
|
|
@@ -15,6 +21,7 @@ const runtimeFiles = () => {
|
|
|
15
21
|
} };
|
|
16
22
|
walk('src/knowledge');
|
|
17
23
|
walk('src/rpc/generated');
|
|
24
|
+
walk('packages/agentsam-errors/src');
|
|
18
25
|
return files.sort();
|
|
19
26
|
};
|
|
20
27
|
|
|
@@ -31,6 +38,7 @@ WORKDIR /app
|
|
|
31
38
|
COPY package.json package-lock.json ./
|
|
32
39
|
RUN npm ci --omit=dev --ignore-scripts --no-audit --no-fund
|
|
33
40
|
COPY src ./src
|
|
41
|
+
COPY packages ./packages
|
|
34
42
|
ENV NODE_ENV=production PORT=${port} GIT_OPTIONAL_LOCKS=0
|
|
35
43
|
EXPOSE ${port}
|
|
36
44
|
HEALTHCHECK --interval=15s --timeout=3s --start-period=10s --retries=3 CMD node -e "fetch('http://127.0.0.1:'+process.env.PORT+'/healthz').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"
|
|
@@ -2,6 +2,10 @@ import fs from 'node:fs';
|
|
|
2
2
|
import os from 'node:os';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { randomUUID } from 'node:crypto';
|
|
5
|
+
import { findCliProjectRoot } from './cli-preferences.js';
|
|
6
|
+
import { runtimeDatabasePath, SQLITE_RUNTIME_CAPABILITIES } from '../local/runtime-store.js';
|
|
7
|
+
import { createLocalSqliteDatabaseSync } from '../local/sqlite.js';
|
|
8
|
+
import { applyRuntimeMigrationsSync } from '../local/migrations.js';
|
|
5
9
|
|
|
6
10
|
export const LOCAL_SESSION_SCHEMA = 'agentsam-local-session-v1';
|
|
7
11
|
|
|
@@ -33,13 +37,51 @@ function filenameFor(sessionId, options = {}) {
|
|
|
33
37
|
return path.join(localSessionDirectory(options), `${validateSessionId(sessionId)}.json`);
|
|
34
38
|
}
|
|
35
39
|
|
|
36
|
-
function
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
40
|
+
function projectRoot(value = {}, options = {}) {
|
|
41
|
+
return findCliProjectRoot(options.projectRoot || value.project_root || value.cwd || options.cwd || process.cwd());
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function withSessionDb(root, fn) {
|
|
45
|
+
const db = createLocalSqliteDatabaseSync(runtimeDatabasePath(root));
|
|
46
|
+
try {
|
|
47
|
+
applyRuntimeMigrationsSync(db);
|
|
48
|
+
return fn(db);
|
|
49
|
+
} finally {
|
|
50
|
+
db.close();
|
|
41
51
|
}
|
|
42
|
-
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function safeProviderState(value) {
|
|
55
|
+
if (!value || typeof value !== 'object') return {};
|
|
56
|
+
// Opaque response IDs allow provider-side continuation. Message arrays and
|
|
57
|
+
// compaction input can carry prompts, tool output, or credential values.
|
|
58
|
+
return {
|
|
59
|
+
...(clean(value.provider) ? { provider: clean(value.provider) } : {}),
|
|
60
|
+
...(clean(value.previous_response_id) ? { previous_response_id: clean(value.previous_response_id) } : {}),
|
|
61
|
+
...(value.has_compacted_input === true ? { has_compacted_input: true } : {}),
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function safeLastError(value) {
|
|
66
|
+
if (!value || typeof value !== 'object') return null;
|
|
67
|
+
return {
|
|
68
|
+
code: clean(value.code) || null,
|
|
69
|
+
kind: clean(value.kind) || null,
|
|
70
|
+
source: clean(value.source) || null,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function safeUsageSnapshot(value) {
|
|
75
|
+
if (!value || typeof value !== 'object') return null;
|
|
76
|
+
const inputTokens = Number(value.current_context?.input_tokens);
|
|
77
|
+
const windowTokens = Number(value.current_context?.window_tokens);
|
|
78
|
+
return {
|
|
79
|
+
estimate_kind: value.estimate_kind === 'provider' ? 'provider' : 'local',
|
|
80
|
+
current_context: {
|
|
81
|
+
input_tokens: Number.isFinite(inputTokens) ? Math.max(0, inputTokens) : 0,
|
|
82
|
+
window_tokens: Number.isFinite(windowTokens) ? Math.max(0, windowTokens) : null,
|
|
83
|
+
},
|
|
84
|
+
};
|
|
43
85
|
}
|
|
44
86
|
|
|
45
87
|
function normalizeUsage(value = {}) {
|
|
@@ -72,13 +114,18 @@ export function normalizeLocalSession(value = {}) {
|
|
|
72
114
|
const createdAt = clean(value.created_at) || now();
|
|
73
115
|
const status = clean(value.status) || 'active';
|
|
74
116
|
const updatedAt = clean(value.updated_at) || createdAt;
|
|
117
|
+
const root = projectRoot(value);
|
|
118
|
+
const dbPath = runtimeDatabasePath(root);
|
|
119
|
+
const relativeDbPath = path.relative(root, dbPath);
|
|
75
120
|
return {
|
|
76
121
|
schema_version: LOCAL_SESSION_SCHEMA,
|
|
77
122
|
id: validateSessionId(value.id || createLocalSessionId()),
|
|
78
123
|
status,
|
|
124
|
+
project_root: root,
|
|
125
|
+
storage: { runtime: 'sqlite', path: relativeDbPath.startsWith('..') ? dbPath : relativeDbPath, remote: null, capabilities: SQLITE_RUNTIME_CAPABILITIES },
|
|
79
126
|
cwd: path.resolve(clean(value.cwd) || process.cwd()),
|
|
80
|
-
title: clean(value.title) ||
|
|
81
|
-
last_input:
|
|
127
|
+
title: clean(value.title) || 'Agent Sam session',
|
|
128
|
+
last_input: null,
|
|
82
129
|
created_at: createdAt,
|
|
83
130
|
updated_at: updatedAt,
|
|
84
131
|
active_elapsed_ms: Math.max(0, Number(value.active_elapsed_ms || 0)),
|
|
@@ -88,26 +135,49 @@ export function normalizeLocalSession(value = {}) {
|
|
|
88
135
|
reasoning_effort: clean(value.reasoning_effort) || null,
|
|
89
136
|
requested_service_tier: clean(value.requested_service_tier) || null,
|
|
90
137
|
actual_service_tier: clean(value.actual_service_tier) || null,
|
|
91
|
-
provider_state: value.provider_state
|
|
92
|
-
|
|
138
|
+
provider_state: safeProviderState(value.provider_state),
|
|
139
|
+
latest_compaction: value.latest_compaction ? {
|
|
140
|
+
compaction_id: clean(value.latest_compaction.compaction_id) || null,
|
|
141
|
+
provider: clean(value.latest_compaction.provider) || null,
|
|
142
|
+
model: clean(value.latest_compaction.model) || null,
|
|
143
|
+
created_at: clean(value.latest_compaction.created_at) || null,
|
|
144
|
+
usage: normalizeUsage(value.latest_compaction.usage),
|
|
145
|
+
cost_usd: Number(value.latest_compaction.cost_usd || 0),
|
|
146
|
+
} : null,
|
|
147
|
+
auto_compact: value.auto_compact !== false,
|
|
148
|
+
usage_snapshot: safeUsageSnapshot(value.usage_snapshot),
|
|
93
149
|
cumulative_usage: normalizeUsage(value.cumulative_usage || {}),
|
|
94
150
|
total_cost_usd: Number(value.total_cost_usd || 0),
|
|
95
151
|
cost_breakdown_usd: normalizeCostBreakdown(value.cost_breakdown_usd || {}),
|
|
96
152
|
approved_projected_call_cost_usd: Number(value.approved_projected_call_cost_usd || 0),
|
|
97
|
-
last_error:
|
|
153
|
+
last_error: safeLastError(value.last_error),
|
|
98
154
|
};
|
|
99
155
|
}
|
|
100
156
|
|
|
101
157
|
export function saveLocalSession(session, options = {}) {
|
|
102
|
-
const normalized = normalizeLocalSession({ ...session, updated_at: now() });
|
|
103
|
-
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
158
|
+
const normalized = normalizeLocalSession({ ...session, project_root: projectRoot(session, options), updated_at: now() });
|
|
159
|
+
const compactedInput = session.provider_state?.compacted_input;
|
|
160
|
+
const serialized = Array.isArray(compactedInput) ? JSON.stringify(compactedInput) : null;
|
|
161
|
+
if (serialized && Buffer.byteLength(serialized) > 10 * 1024 * 1024) throw new Error('provider_continuation_too_large');
|
|
162
|
+
if (serialized) normalized.provider_state.has_compacted_input = true;
|
|
163
|
+
withSessionDb(normalized.project_root, (db) => {
|
|
164
|
+
db.exec('BEGIN IMMEDIATE');
|
|
165
|
+
try {
|
|
166
|
+
db.prepare(`
|
|
167
|
+
INSERT INTO agentsam_project_sessions (id, project_root, cwd, status, title, state_json, created_at, updated_at)
|
|
168
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
169
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
170
|
+
cwd = excluded.cwd, status = excluded.status, title = excluded.title,
|
|
171
|
+
state_json = excluded.state_json, updated_at = excluded.updated_at
|
|
172
|
+
`).run(normalized.id, normalized.project_root, normalized.cwd, normalized.status,
|
|
173
|
+
normalized.title, JSON.stringify(normalized), normalized.created_at, normalized.updated_at);
|
|
174
|
+
if (serialized) db.prepare(`INSERT INTO agentsam_provider_continuations (session_id, provider, output_json, updated_at)
|
|
175
|
+
VALUES (?, ?, ?, ?) ON CONFLICT(session_id) DO UPDATE SET provider=excluded.provider, output_json=excluded.output_json, updated_at=excluded.updated_at`
|
|
176
|
+
).run(normalized.id, normalized.provider_state.provider || '', serialized, normalized.updated_at);
|
|
177
|
+
else if (!normalized.provider_state.has_compacted_input) db.prepare('DELETE FROM agentsam_provider_continuations WHERE session_id = ?').run(normalized.id);
|
|
178
|
+
db.exec('COMMIT');
|
|
179
|
+
} catch (error) { db.exec('ROLLBACK'); throw error; }
|
|
180
|
+
});
|
|
111
181
|
return normalized;
|
|
112
182
|
}
|
|
113
183
|
|
|
@@ -116,11 +186,23 @@ export function createLocalSession(value = {}, options = {}) {
|
|
|
116
186
|
}
|
|
117
187
|
|
|
118
188
|
export function loadLocalSession(sessionId, options = {}) {
|
|
189
|
+
const root = projectRoot({}, options);
|
|
190
|
+
const dbPath = runtimeDatabasePath(root);
|
|
191
|
+
if (fs.existsSync(dbPath)) {
|
|
192
|
+
const row = withSessionDb(root, (db) => db.prepare(
|
|
193
|
+
'SELECT state_json FROM agentsam_project_sessions WHERE id = ? AND project_root = ?'
|
|
194
|
+
).get(validateSessionId(sessionId), root));
|
|
195
|
+
if (row) return normalizeLocalSession(JSON.parse(row.state_json));
|
|
196
|
+
}
|
|
197
|
+
// Read-only compatibility with older ~/.agentsam/sessions/*.json state.
|
|
198
|
+
// Import only when the saved cwd belongs to the selected project; never
|
|
199
|
+
// create new home-level session files or resume a different project's row.
|
|
119
200
|
const filename = filenameFor(sessionId, options);
|
|
120
201
|
if (!fs.existsSync(filename)) return null;
|
|
121
202
|
const parsed = JSON.parse(fs.readFileSync(filename, 'utf8'));
|
|
122
203
|
if (parsed?.schema_version !== LOCAL_SESSION_SCHEMA) throw new Error(`unsupported_local_session_schema:${parsed?.schema_version || 'missing'}`);
|
|
123
|
-
|
|
204
|
+
if (projectRoot(parsed) !== root) return null;
|
|
205
|
+
return saveLocalSession(parsed, { projectRoot: root });
|
|
124
206
|
}
|
|
125
207
|
|
|
126
208
|
export function updateLocalSession(sessionId, patch = {}, options = {}) {
|
|
@@ -130,19 +212,27 @@ export function updateLocalSession(sessionId, patch = {}, options = {}) {
|
|
|
130
212
|
}
|
|
131
213
|
|
|
132
214
|
export function listLocalSessions(options = {}) {
|
|
215
|
+
const root = projectRoot({}, options);
|
|
133
216
|
const dir = localSessionDirectory(options);
|
|
134
|
-
if (
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
try {
|
|
141
|
-
const parsed = JSON.parse(fs.readFileSync(path.join(dir, entry.name), 'utf8'));
|
|
142
|
-
if (parsed?.schema_version !== LOCAL_SESSION_SCHEMA) continue;
|
|
143
|
-
const session = normalizeLocalSession(parsed);
|
|
144
|
-
if (!cwd || session.cwd === cwd) rows.push(session);
|
|
145
|
-
} catch { /* skip corrupt session file */ }
|
|
217
|
+
if (fs.existsSync(dir)) {
|
|
218
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
219
|
+
if (!entry.isFile() || !entry.name.startsWith('asess_') || !entry.name.endsWith('.json')) continue;
|
|
220
|
+
try { loadLocalSession(entry.name.slice(0, -5), { ...options, projectRoot: root }); }
|
|
221
|
+
catch { /* legacy corrupt files remain untouched */ }
|
|
222
|
+
}
|
|
146
223
|
}
|
|
147
|
-
|
|
224
|
+
if (!fs.existsSync(runtimeDatabasePath(root))) return [];
|
|
225
|
+
const limit = Number.isInteger(options.limit) && options.limit > 0 ? Math.min(options.limit, 100) : 20;
|
|
226
|
+
return withSessionDb(root, (db) => db.prepare(
|
|
227
|
+
'SELECT state_json FROM agentsam_project_sessions WHERE project_root = ? ORDER BY updated_at DESC LIMIT ?'
|
|
228
|
+
).all(root, limit).map((row) => normalizeLocalSession(JSON.parse(row.state_json))));
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export function loadSessionContinuation(session) {
|
|
232
|
+
if (!session?.provider_state?.has_compacted_input) return session?.provider_state || null;
|
|
233
|
+
return withSessionDb(projectRoot(session), db => {
|
|
234
|
+
const row = db.prepare('SELECT provider, output_json FROM agentsam_provider_continuations WHERE session_id = ?').get(validateSessionId(session.id));
|
|
235
|
+
if (!row || row.provider !== session.provider_state.provider) throw new Error('provider_continuation_missing');
|
|
236
|
+
return { ...session.provider_state, compacted_input: JSON.parse(row.output_json) };
|
|
237
|
+
});
|
|
148
238
|
}
|
package/src/lib/local-status.js
CHANGED
|
@@ -1,29 +1,37 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
1
|
import path from 'node:path';
|
|
3
2
|
import { tryResolveGitContext } from '../../packages/agentsam-repository/src/git-context.js';
|
|
4
3
|
import { inspectLocalSqlite } from '../local/sqlite.js';
|
|
5
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
getCreatedWithVersion,
|
|
6
|
+
getDefaultProfile,
|
|
7
|
+
getDeployTarget,
|
|
8
|
+
getLocalDatabasePath,
|
|
9
|
+
getProjectName,
|
|
10
|
+
getProjectPreset,
|
|
11
|
+
getRepositoryId,
|
|
12
|
+
tryReadProjectConfig,
|
|
13
|
+
} from './project-config.js';
|
|
14
|
+
import { findCliProjectRoot } from './cli-preferences.js';
|
|
6
15
|
|
|
7
16
|
export function findAgentSamProjectRoot(startDir = process.cwd()) {
|
|
8
|
-
|
|
9
|
-
for (let i = 0; i < 16; i += 1) {
|
|
10
|
-
if (fs.existsSync(path.join(dir, '.agentsam', 'config.json'))) return dir;
|
|
11
|
-
const parent = path.dirname(dir);
|
|
12
|
-
if (parent === dir) break;
|
|
13
|
-
dir = parent;
|
|
14
|
-
}
|
|
15
|
-
return path.resolve(startDir);
|
|
17
|
+
return findCliProjectRoot(startDir);
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
async function probe(url) {
|
|
19
21
|
try {
|
|
20
|
-
const response = await fetch(url, { signal: AbortSignal.timeout(
|
|
22
|
+
const response = await fetch(url, { signal: AbortSignal.timeout(1500) });
|
|
21
23
|
return { online: response.ok, status: response.status, url };
|
|
22
24
|
} catch {
|
|
23
25
|
return { online: false, status: null, url };
|
|
24
26
|
}
|
|
25
27
|
}
|
|
26
28
|
|
|
29
|
+
function resolveLiveHealthUrl(config) {
|
|
30
|
+
const fromDeploy = config?.deployment?.cloudflare?.health_url;
|
|
31
|
+
if (fromDeploy != null && String(fromDeploy).trim()) return String(fromDeploy).trim();
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
|
|
27
35
|
export async function collectLocalStatus(cwd = process.cwd()) {
|
|
28
36
|
const root = findAgentSamProjectRoot(cwd);
|
|
29
37
|
const config = tryReadProjectConfig(root);
|
|
@@ -36,10 +44,16 @@ export async function collectLocalStatus(cwd = process.cwd()) {
|
|
|
36
44
|
|
|
37
45
|
const devPort = config?.dev_port ?? 8787;
|
|
38
46
|
const ptyPort = config?.pty_port ?? 3099;
|
|
39
|
-
const
|
|
47
|
+
const liveUrl = resolveLiveHealthUrl(config);
|
|
48
|
+
const probes = [
|
|
40
49
|
probe(`http://127.0.0.1:${devPort}/api/health`),
|
|
41
50
|
probe(`http://127.0.0.1:${ptyPort}/health`),
|
|
42
|
-
]
|
|
51
|
+
];
|
|
52
|
+
if (liveUrl) probes.push(probe(liveUrl));
|
|
53
|
+
const results = await Promise.all(probes);
|
|
54
|
+
const api = results[0];
|
|
55
|
+
const pty = results[1];
|
|
56
|
+
const live = liveUrl ? results[2] : null;
|
|
43
57
|
|
|
44
58
|
return {
|
|
45
59
|
schemaVersion: 'agentsam-local-status-v1',
|
|
@@ -60,12 +74,19 @@ export async function collectLocalStatus(cwd = process.cwd()) {
|
|
|
60
74
|
}
|
|
61
75
|
: null,
|
|
62
76
|
db: {
|
|
63
|
-
ready: Boolean(
|
|
77
|
+
ready: Boolean(
|
|
78
|
+
db.exists &&
|
|
79
|
+
db.tables?.includes('agentsam_schema_migrations') &&
|
|
80
|
+
db.tables?.includes('agentsam_project_sessions'),
|
|
81
|
+
),
|
|
64
82
|
path: db.dbPath || path.join(root, '.agentsam/data/agentsam.sqlite'),
|
|
65
83
|
tables: db.tables || [],
|
|
66
84
|
sizeBytes: db.sizeBytes || 0,
|
|
67
85
|
},
|
|
68
86
|
api,
|
|
69
87
|
pty,
|
|
88
|
+
live: liveUrl
|
|
89
|
+
? live || { online: false, status: null, url: liveUrl }
|
|
90
|
+
: { online: false, status: null, url: null },
|
|
70
91
|
};
|
|
71
92
|
}
|
|
@@ -76,6 +76,9 @@ export function createProjectManifest({
|
|
|
76
76
|
knowledge: {
|
|
77
77
|
config: '.agentsam/knowledge.json',
|
|
78
78
|
},
|
|
79
|
+
// Project-owned plugin/resource declarations. Bindings, indexes, models,
|
|
80
|
+
// and dimensions belong here rather than in a global SDK default.
|
|
81
|
+
plugins: {},
|
|
79
82
|
local: {
|
|
80
83
|
database: '.agentsam/data/agentsam.sqlite',
|
|
81
84
|
schema: 'db/schema.sql',
|
|
@@ -151,6 +154,12 @@ export function getKnowledgeConfigPath(config) {
|
|
|
151
154
|
return clean(config?.knowledge?.config) || '.agentsam/knowledge.json';
|
|
152
155
|
}
|
|
153
156
|
|
|
157
|
+
export function getProjectPluginConfig(config, pluginKey) {
|
|
158
|
+
const key = clean(pluginKey).replace(/^@/, '');
|
|
159
|
+
const plugins = config?.plugins || config?.integrations || {};
|
|
160
|
+
return plugins[key] || plugins[`@${key}`] || null;
|
|
161
|
+
}
|
|
162
|
+
|
|
154
163
|
export function getLocalDatabasePath(config) {
|
|
155
164
|
return clean(config?.local?.database || config?.db_path) || '.agentsam/data/agentsam.sqlite';
|
|
156
165
|
}
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import os from 'node:os';
|
|
3
3
|
import path from 'node:path';
|
|
4
|
+
import {
|
|
5
|
+
getSecureProviderKey,
|
|
6
|
+
setSecureProviderKey,
|
|
7
|
+
deleteSecureProviderKey,
|
|
8
|
+
hydrateSecureCredentials,
|
|
9
|
+
} from '../security/local-vault.js';
|
|
10
|
+
|
|
11
|
+
export { hydrateSecureCredentials };
|
|
4
12
|
|
|
5
13
|
export const PROVIDER_CREDENTIALS = Object.freeze({
|
|
6
14
|
openai: Object.freeze({ label: 'OpenAI', env: 'OPENAI_API_KEY', files: ['openai.env'], modelProvider: 'openai' }),
|
|
@@ -13,7 +21,7 @@ export const PROVIDER_CREDENTIALS = Object.freeze({
|
|
|
13
21
|
env: 'CLOUDFLARE_API_TOKEN',
|
|
14
22
|
files: ['cloudflare.env'],
|
|
15
23
|
modelProvider: 'cloudflare',
|
|
16
|
-
accountEnv: ['
|
|
24
|
+
accountEnv: ['CLOUDFLARE_ACCOUNT_ID'],
|
|
17
25
|
}),
|
|
18
26
|
inneranimalmedia: Object.freeze({
|
|
19
27
|
label: 'InnerAnimalMedia',
|
|
@@ -141,10 +149,6 @@ for _agentsam_profile in "$@"; do
|
|
|
141
149
|
set -a
|
|
142
150
|
. "$_agentsam_file"
|
|
143
151
|
set +a
|
|
144
|
-
if [ "$_agentsam_profile" = cloudflare ]; then
|
|
145
|
-
if [ -z "\${ACCOUNT_ID:-}" ] && [ -n "\${CLOUDFLARE_ACCOUNT_ID:-}" ]; then export ACCOUNT_ID="$CLOUDFLARE_ACCOUNT_ID"; fi
|
|
146
|
-
if [ -z "\${CLOUDFLARE_ACCOUNT_ID:-}" ] && [ -n "\${ACCOUNT_ID:-}" ]; then export CLOUDFLARE_ACCOUNT_ID="$ACCOUNT_ID"; fi
|
|
147
|
-
fi
|
|
148
152
|
done
|
|
149
153
|
unset _agentsam_file _agentsam_profile
|
|
150
154
|
`;
|
|
@@ -157,8 +161,8 @@ function profileSource(provider, credential = '', options = {}) {
|
|
|
157
161
|
if (!spec) throw new Error(`unsupported_provider:${normalizeProviderId(provider)}`);
|
|
158
162
|
const lines = [`# AgentSam ${spec.label} provider profile`];
|
|
159
163
|
if (spec.provider === 'cloudflare') {
|
|
160
|
-
lines.push('#
|
|
161
|
-
lines.push(`export
|
|
164
|
+
lines.push('# CLOUDFLARE_ACCOUNT_ID is your Cloudflare account identifier; it is not a secret.');
|
|
165
|
+
lines.push(`export CLOUDFLARE_ACCOUNT_ID=${envLiteral(normalizeCloudflareAccountId(options.accountId))}`);
|
|
162
166
|
}
|
|
163
167
|
lines.push(`export ${spec.env}=${envLiteral(credential)}`);
|
|
164
168
|
return `${lines.join('\n')}\n`;
|
|
@@ -190,9 +194,9 @@ export function ensureProviderEnvProfile(provider, options = {}) {
|
|
|
190
194
|
const current = firstEnvValue(source, spec.accountEnv || []);
|
|
191
195
|
if (!current) {
|
|
192
196
|
const accountId = normalizeCloudflareAccountId(options.accountId);
|
|
193
|
-
const line = `export
|
|
194
|
-
const next = /^(?:export\s+)?
|
|
195
|
-
? source.replace(/^(?:export\s+)?
|
|
197
|
+
const line = `export CLOUDFLARE_ACCOUNT_ID=${envLiteral(accountId)}`;
|
|
198
|
+
const next = /^(?:export\s+)?CLOUDFLARE_ACCOUNT_ID=.*$/m.test(source)
|
|
199
|
+
? source.replace(/^(?:export\s+)?CLOUDFLARE_ACCOUNT_ID=.*$/m, line)
|
|
196
200
|
: `${line}\n${source}`;
|
|
197
201
|
atomicWrite(filename, next, 0o600);
|
|
198
202
|
}
|
|
@@ -212,8 +216,46 @@ export function setProviderCredential(provider, credential, options = {}) {
|
|
|
212
216
|
const spec = providerCredentialSpec(provider);
|
|
213
217
|
if (!spec) throw new Error(`unsupported_provider:${normalizeProviderId(provider)}`);
|
|
214
218
|
const value = validateCredentialValue(spec, credential);
|
|
219
|
+
setSecureProviderKey(spec.provider, { value, accountId: options.accountId }, options);
|
|
220
|
+
if (typeof process !== 'undefined' && process.env) {
|
|
221
|
+
process.env[spec.env] = value;
|
|
222
|
+
if (spec.provider === 'cloudflare' && options.accountId) {
|
|
223
|
+
process.env.CLOUDFLARE_ACCOUNT_ID = options.accountId;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
let file = null;
|
|
227
|
+
let loader = null;
|
|
228
|
+
let sourceCommand = null;
|
|
229
|
+
if (options.exportProfile === true || options.writeEnvProfile === true) {
|
|
230
|
+
const filename = path.join(agentEnvDirectory(options), spec.files[0]);
|
|
231
|
+
atomicWrite(filename, profileSource(spec.provider, value, options), 0o600);
|
|
232
|
+
loader = ensureAgentEnvLoader(options);
|
|
233
|
+
file = filename;
|
|
234
|
+
sourceCommand = `source ~/.agentsam/load-agent-env.sh ${spec.provider}`;
|
|
235
|
+
}
|
|
236
|
+
return Object.freeze({
|
|
237
|
+
provider: spec.provider,
|
|
238
|
+
file,
|
|
239
|
+
loader,
|
|
240
|
+
source_command: sourceCommand,
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Exports a configured provider credential from the secure vault to a plaintext .env file.
|
|
246
|
+
* This is an explicit opt-in action for operators who need to source credentials into external shells.
|
|
247
|
+
* The standard AgentSam setup flows (interactive picker, models --setup, providers add)
|
|
248
|
+
* intentionally do NOT invoke this, keeping the credential strictly inside the encrypted vault.
|
|
249
|
+
*/
|
|
250
|
+
export function exportProviderEnvProfile(provider, options = {}) {
|
|
251
|
+
const spec = providerCredentialSpec(provider);
|
|
252
|
+
if (!spec) throw new Error(`unsupported_provider:${normalizeProviderId(provider)}`);
|
|
253
|
+
const resolved = resolveProviderCredential(spec.provider, options);
|
|
254
|
+
if (!resolved.configured || !resolved.value) {
|
|
255
|
+
throw new Error(`provider_not_configured:${spec.provider}`);
|
|
256
|
+
}
|
|
215
257
|
const filename = path.join(agentEnvDirectory(options), spec.files[0]);
|
|
216
|
-
atomicWrite(filename, profileSource(spec.provider, value, options), 0o600);
|
|
258
|
+
atomicWrite(filename, profileSource(spec.provider, resolved.value, { ...options, accountId: resolved.account_id }), 0o600);
|
|
217
259
|
const loader = ensureAgentEnvLoader(options);
|
|
218
260
|
return Object.freeze({
|
|
219
261
|
provider: spec.provider,
|
|
@@ -226,6 +268,7 @@ export function setProviderCredential(provider, credential, options = {}) {
|
|
|
226
268
|
export function removeProviderCredential(provider, options = {}) {
|
|
227
269
|
const spec = providerCredentialSpec(provider);
|
|
228
270
|
if (!spec) throw new Error(`unsupported_provider:${normalizeProviderId(provider)}`);
|
|
271
|
+
deleteSecureProviderKey(spec.provider, options);
|
|
229
272
|
const dir = agentEnvDirectory(options);
|
|
230
273
|
let removed = false;
|
|
231
274
|
for (const basename of spec.files) {
|
|
@@ -236,6 +279,9 @@ export function removeProviderCredential(provider, options = {}) {
|
|
|
236
279
|
fs.rmSync(filename, { force: true });
|
|
237
280
|
removed = true;
|
|
238
281
|
}
|
|
282
|
+
if (typeof process !== 'undefined' && process.env) {
|
|
283
|
+
delete process.env[spec.env];
|
|
284
|
+
}
|
|
239
285
|
return Object.freeze({ provider: spec.provider, removed });
|
|
240
286
|
}
|
|
241
287
|
|
|
@@ -259,6 +305,22 @@ export function resolveProviderCredential(provider, options = {}) {
|
|
|
259
305
|
});
|
|
260
306
|
}
|
|
261
307
|
|
|
308
|
+
const secure = getSecureProviderKey(spec.provider, options);
|
|
309
|
+
if (secure && clean(secure.value)) {
|
|
310
|
+
const val = clean(secure.value);
|
|
311
|
+
const prefixError = spec.tokenPrefix && !val.startsWith(spec.tokenPrefix) ? `credential_prefix_required:${spec.tokenPrefix}` : null;
|
|
312
|
+
return Object.freeze({
|
|
313
|
+
provider: spec.provider,
|
|
314
|
+
configured: !prefixError,
|
|
315
|
+
source: secure.source || 'local_vault',
|
|
316
|
+
env: spec.env,
|
|
317
|
+
file: null,
|
|
318
|
+
error: prefixError,
|
|
319
|
+
value: prefixError ? '' : val,
|
|
320
|
+
account_id: accountIdFromEnv || secure.accountId || null,
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
|
|
262
324
|
const dir = agentEnvDirectory({ ...options, env });
|
|
263
325
|
for (const basename of spec.files) {
|
|
264
326
|
const filename = path.join(dir, basename);
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Cloudflare account resolution for scaffold wizards.
|
|
3
|
+
* Reuses the same detection the CLI's `agentsam env init cloudflare` flow
|
|
4
|
+
* already relies on — never ask the user to hand-paste an account ID that
|
|
5
|
+
* `wrangler whoami` (or an existing env override) can already answer.
|
|
6
|
+
*/
|
|
7
|
+
import { detectCloudflareAccounts } from '../../commands/env.js';
|
|
8
|
+
|
|
9
|
+
export async function resolveCloudflareAccountId({ text, select, isCancel, cancel, note, pc, detectAccounts = detectCloudflareAccounts }) {
|
|
10
|
+
const detected = detectAccounts();
|
|
11
|
+
|
|
12
|
+
if (detected.accounts.length === 1) {
|
|
13
|
+
const acct = detected.accounts[0];
|
|
14
|
+
note(`Detected Cloudflare account: ${pc.cyan(acct.name || acct.id)}`, 'Cloudflare account');
|
|
15
|
+
return acct.id;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (detected.accounts.length > 1) {
|
|
19
|
+
const choice = await select({
|
|
20
|
+
message: 'Which Cloudflare account?',
|
|
21
|
+
options: detected.accounts.map((a) => ({ value: a.id, label: a.name || a.id, hint: a.id })),
|
|
22
|
+
});
|
|
23
|
+
if (isCancel(choice)) { cancel('Cancelled.'); process.exit(0); }
|
|
24
|
+
return choice;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
note('Could not auto-detect a Cloudflare account (run `agentsam cloudflare` to check login status).', 'Cloudflare account');
|
|
28
|
+
const cfAccountId = await text({
|
|
29
|
+
message: 'Cloudflare account ID? (from dash.cloudflare.com → right sidebar)',
|
|
30
|
+
placeholder: 'abc123...',
|
|
31
|
+
validate(val) {
|
|
32
|
+
if (!val || val.trim().length === 0) return 'Required.';
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
if (isCancel(cfAccountId)) { cancel('Cancelled.'); process.exit(0); }
|
|
36
|
+
return cfAccountId.trim();
|
|
37
|
+
}
|
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
import pc from 'picocolors';
|
|
23
23
|
import { writeFileTree } from '../writer.js';
|
|
24
24
|
import { cmsTemplates } from '../templates/cms/index.js';
|
|
25
|
+
import { resolveCloudflareAccountId } from '../resolve-cloudflare-account.js';
|
|
25
26
|
|
|
26
27
|
export async function runCmsWizard() {
|
|
27
28
|
note('A Cloudflare Worker + D1 + R2 CMS site with reusable page templates.', 'CMS Site');
|
|
@@ -111,14 +112,7 @@ export async function runCmsWizard() {
|
|
|
111
112
|
}
|
|
112
113
|
|
|
113
114
|
// ── Step 7: Cloudflare account details ────────────────────────────────────
|
|
114
|
-
const cfAccountId = await
|
|
115
|
-
message: 'Cloudflare account ID? (from dash.cloudflare.com → right sidebar)',
|
|
116
|
-
placeholder: 'abc123...',
|
|
117
|
-
validate(val) {
|
|
118
|
-
if (!val || val.trim().length === 0) return 'Required for wrangler.toml.';
|
|
119
|
-
},
|
|
120
|
-
});
|
|
121
|
-
if (isCancel(cfAccountId)) { cancel('Cancelled.'); process.exit(0); }
|
|
115
|
+
const cfAccountId = await resolveCloudflareAccountId({ text, select, isCancel, cancel, note, pc });
|
|
122
116
|
|
|
123
117
|
// ── Step 8: Confirm before writing ───────────────────────────────────────
|
|
124
118
|
const summary = [
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
import pc from 'picocolors';
|
|
17
17
|
import { writeFileTree } from '../writer.js';
|
|
18
18
|
import { workerApiTemplates } from '../templates/worker-api/index.js';
|
|
19
|
+
import { resolveCloudflareAccountId } from '../resolve-cloudflare-account.js';
|
|
19
20
|
|
|
20
21
|
export async function runWorkerApiWizard() {
|
|
21
22
|
note('A typed Cloudflare Worker with route handlers, D1 binding, and CORS ready.', 'Worker API');
|
|
@@ -52,14 +53,7 @@ export async function runWorkerApiWizard() {
|
|
|
52
53
|
});
|
|
53
54
|
if (isCancel(dbKind)) { cancel('Cancelled.'); process.exit(0); }
|
|
54
55
|
|
|
55
|
-
const cfAccountId = await
|
|
56
|
-
message: 'Cloudflare account ID?',
|
|
57
|
-
placeholder: 'abc123...',
|
|
58
|
-
validate(val) {
|
|
59
|
-
if (!val || val.trim().length === 0) return 'Required.';
|
|
60
|
-
},
|
|
61
|
-
});
|
|
62
|
-
if (isCancel(cfAccountId)) { cancel('Cancelled.'); process.exit(0); }
|
|
56
|
+
const cfAccountId = await resolveCloudflareAccountId({ text, select, isCancel, cancel, note, pc });
|
|
63
57
|
|
|
64
58
|
const confirmed = await confirm({ message: `Write files to ./${projectName.trim()}/?` });
|
|
65
59
|
if (isCancel(confirmed) || !confirmed) { cancel('Cancelled.'); process.exit(0); }
|