@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/commands/shell.js
CHANGED
|
@@ -10,27 +10,36 @@ import { runDb } from './db.js';
|
|
|
10
10
|
import { runDeploy } from './deploy.js';
|
|
11
11
|
import { runStatus } from './status.js';
|
|
12
12
|
import { runModels } from './models.js';
|
|
13
|
+
import { runProviders } from './providers.js';
|
|
13
14
|
import { configureCliPreferences } from './preferences.js';
|
|
14
15
|
import { runCloudflare } from './cloudflare.js';
|
|
16
|
+
import { runConnections } from './connections.js';
|
|
17
|
+
import { runTunnel } from './tunnel.js';
|
|
15
18
|
import { probeOllamaModel, resolveOllamaConfig } from './ollama.js';
|
|
16
19
|
import { createInlineActivity } from '../ui/cli/activity.js';
|
|
17
20
|
import { createCliRuntimePresenter } from '../ui/cli/runtime-events.js';
|
|
18
|
-
import { renderCliFooter } from '../ui/cli/footer.js';
|
|
21
|
+
import { renderCliFooter, renderDiffPreview, renderUsagePanel } from '../ui/cli/footer.js';
|
|
19
22
|
import { diagnosticFromError, renderDiagnosticError } from '../errors/index.js';
|
|
20
|
-
import { getModelRecord } from '../models/index.js';
|
|
23
|
+
import { getModelRecord, mergeModelReference } from '../models/index.js';
|
|
21
24
|
import { discoverProviderModels } from '../models/discovery.js';
|
|
22
|
-
import { readCliPreferences, updateCliPreferences } from '../lib/cli-preferences.js';
|
|
25
|
+
import { detectCliProject, findCliProjectRoot, readCliPreferences, updateCliPreferences } from '../lib/cli-preferences.js';
|
|
23
26
|
import { buildContextEconomicsReport, renderContextEconomics } from './context-economics.js';
|
|
24
27
|
import { createProviderAdapter } from '../providers/index.js';
|
|
25
28
|
import { createCapabilityAdapter, runResponsesAgent } from '../agent/index.js';
|
|
26
29
|
import { resolveProviderCredential } from '../lib/provider-credentials.js';
|
|
27
|
-
import { createLocalSession, saveLocalSession,
|
|
30
|
+
import { createLocalSession, saveLocalSession, localSessionElapsedMs, loadSessionContinuation } from '../lib/local-sessions.js';
|
|
31
|
+
import { runtimeDatabasePath } from '../local/runtime-store.js';
|
|
28
32
|
import { grantExecutionApproval, isExecutionApproved, toolApprovalKey } from '../lib/execution-approvals.js';
|
|
29
33
|
import { runWhoami } from './whoami.js';
|
|
30
34
|
import { runLogin, runLogout } from './account-auth.js';
|
|
31
35
|
import { runHelp } from '../ui/cli/help.js';
|
|
36
|
+
import { hydrateSecureCredentials } from '../security/local-vault.js';
|
|
32
37
|
import { readAccountSession } from '../lib/account-session.js';
|
|
33
38
|
import { startRuntimeRun, finishRuntimeRun, recordRuntimeCompaction } from '../local/runtime-store.js';
|
|
39
|
+
import { tryResolveGitContext } from '../../packages/agentsam-repository/src/git-context.js';
|
|
40
|
+
import { syncWorkspaceStateToD1, readWorkspaceStateFromD1 } from '../../packages/agentsam-repository/src/workspace-state.js';
|
|
41
|
+
import { syncGitCommitsToD1 } from '../../packages/agentsam-repository/src/work-tracking.js';
|
|
42
|
+
import { readGoapState, listGoapTickets, createGoapGoal, switchGoapGoal, closeGoapGoal, renderGoapStatus, renderGoapList, renderGoapGoal, renderGoapWhy, renderGoapPlan } from '../../packages/agentsam-repository/src/goap.js';
|
|
34
43
|
|
|
35
44
|
function writeLine(write, value = '') { write(`${value}\n`); }
|
|
36
45
|
|
|
@@ -53,6 +62,134 @@ export function renderShellPrompt(cwd, env = process.env) {
|
|
|
53
62
|
return `${shellUsername(env)} ${compactCwd(cwd, env.HOME || env.USERPROFILE || '')} > `;
|
|
54
63
|
}
|
|
55
64
|
|
|
65
|
+
export const PASTE_COLLAPSE_LINE_THRESHOLD = 5;
|
|
66
|
+
export const PASTE_COLLAPSE_CHAR_THRESHOLD = 300;
|
|
67
|
+
const BRACKETED_PASTE_START = '\x1b[200~';
|
|
68
|
+
const BRACKETED_PASTE_END = '\x1b[201~';
|
|
69
|
+
const BRACKETED_PASTE_ENABLE = '\x1b[?2004h';
|
|
70
|
+
const BRACKETED_PASTE_DISABLE = '\x1b[?2004l';
|
|
71
|
+
|
|
72
|
+
export function countPasteLines(text) {
|
|
73
|
+
const source = String(text ?? '').replace(/\r\n/g, '\n').replace(/\r/g, '\n');
|
|
74
|
+
if (!source) return 0;
|
|
75
|
+
const parts = source.split('\n');
|
|
76
|
+
if (parts[parts.length - 1] === '') parts.pop();
|
|
77
|
+
return Math.max(parts.length, source ? 1 : 0);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function shouldCollapsePaste(text) {
|
|
81
|
+
const source = String(text ?? '');
|
|
82
|
+
return countPasteLines(source) > PASTE_COLLAPSE_LINE_THRESHOLD || source.length > PASTE_COLLAPSE_CHAR_THRESHOLD;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function renderCollapsedPaste(text) {
|
|
86
|
+
return `[Pasted ${countPasteLines(text)} lines — Enter to run, Backspace to clear]`;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function installPasteCollapse(rl, options = {}) {
|
|
90
|
+
if (!rl || rl.terminal === false || typeof rl._ttyWrite !== 'function') return () => {};
|
|
91
|
+
const original = rl._ttyWrite.bind(rl);
|
|
92
|
+
let collapsed = null;
|
|
93
|
+
let collecting = '';
|
|
94
|
+
let inPaste = false;
|
|
95
|
+
|
|
96
|
+
function refresh(line) {
|
|
97
|
+
rl.line = line;
|
|
98
|
+
rl.cursor = line.length;
|
|
99
|
+
if (typeof rl._refreshLine === 'function') rl._refreshLine();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function showCollapsed(text) {
|
|
103
|
+
collapsed = text;
|
|
104
|
+
refresh(renderCollapsedPaste(text));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function consumePaste(body) {
|
|
108
|
+
inPaste = false;
|
|
109
|
+
collecting = '';
|
|
110
|
+
if (shouldCollapsePaste(body)) {
|
|
111
|
+
showCollapsed(body);
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
original(body);
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
rl._ttyWrite = (s, key) => {
|
|
119
|
+
const str = s == null ? '' : String(s);
|
|
120
|
+
|
|
121
|
+
if (str.includes(BRACKETED_PASTE_START) || key?.name === 'paste-start') {
|
|
122
|
+
inPaste = true;
|
|
123
|
+
collecting = str.replace(BRACKETED_PASTE_START, '');
|
|
124
|
+
if (collecting.includes(BRACKETED_PASTE_END) || key?.name === 'paste-end') {
|
|
125
|
+
return consumePaste(collecting.replace(BRACKETED_PASTE_END, ''));
|
|
126
|
+
}
|
|
127
|
+
return undefined;
|
|
128
|
+
}
|
|
129
|
+
if (inPaste) {
|
|
130
|
+
collecting += str;
|
|
131
|
+
if (collecting.includes(BRACKETED_PASTE_END) || key?.name === 'paste-end') {
|
|
132
|
+
return consumePaste(collecting.replace(BRACKETED_PASTE_END, ''));
|
|
133
|
+
}
|
|
134
|
+
return undefined;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (collapsed) {
|
|
138
|
+
if (key?.name === 'backspace' || key?.name === 'delete') {
|
|
139
|
+
collapsed = null;
|
|
140
|
+
refresh('');
|
|
141
|
+
return undefined;
|
|
142
|
+
}
|
|
143
|
+
if (key?.name === 'return' || key?.name === 'enter') {
|
|
144
|
+
const text = collapsed;
|
|
145
|
+
collapsed = null;
|
|
146
|
+
rl.line = text;
|
|
147
|
+
rl.cursor = text.length;
|
|
148
|
+
return original('\n', { name: 'return' });
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (str && !key?.name && shouldCollapsePaste(str.replace(/\n$/, ''))) {
|
|
153
|
+
const payload = str.endsWith('\n') ? str.slice(0, -1) : str;
|
|
154
|
+
showCollapsed(payload);
|
|
155
|
+
return undefined;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return original(s, key);
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
try { options.output?.write?.(BRACKETED_PASTE_ENABLE); } catch { /* ignore */ }
|
|
162
|
+
return () => {
|
|
163
|
+
rl._ttyWrite = original;
|
|
164
|
+
try { options.output?.write?.(BRACKETED_PASTE_DISABLE); } catch { /* ignore */ }
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function resolveShellIdentity(state) {
|
|
169
|
+
if (state.identity && state.identityCwd === state.cwd) return state.identity;
|
|
170
|
+
try { state.identity = detectCliProject(state.cwd); }
|
|
171
|
+
catch { state.identity = { project: path.basename(state.cwd || ''), branch: '', root: state.cwd }; }
|
|
172
|
+
state.identityCwd = state.cwd;
|
|
173
|
+
return state.identity;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function renderShellSessionFooter(state) {
|
|
177
|
+
const identity = resolveShellIdentity(state);
|
|
178
|
+
const preferences = readCliPreferences(state.cwd) || {};
|
|
179
|
+
return renderCliFooter({
|
|
180
|
+
projectName: identity.project,
|
|
181
|
+
branch: identity.branch,
|
|
182
|
+
cwd: compactCwd(state.cwd),
|
|
183
|
+
model: state.session?.provider_model_id || state.session?.model_key || preferences.modelPreference,
|
|
184
|
+
provider: state.providerState?.provider || state.session?.provider_state?.provider,
|
|
185
|
+
effort: state.session?.reasoning_effort || preferences.reasoningEffort,
|
|
186
|
+
tier: state.session?.actual_service_tier || state.session?.requested_service_tier || preferences.serviceTier,
|
|
187
|
+
usageSnapshot: state.usageSnapshot || state.session?.usage_snapshot,
|
|
188
|
+
elapsedMs: state.lastTurnElapsedMs ?? (state.session ? localSessionElapsedMs(state.session) : undefined),
|
|
189
|
+
action: state.activity?.active ? 'working' : '',
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
|
|
56
193
|
export function tokenizeShellLine(input = '') {
|
|
57
194
|
const source = String(input);
|
|
58
195
|
const tokens = [];
|
|
@@ -120,9 +257,12 @@ function spawnGit(cwd, args) {
|
|
|
120
257
|
function selectedModel(cwd) {
|
|
121
258
|
const preferences = readCliPreferences(cwd) || {};
|
|
122
259
|
const snapshot = preferences.modelSnapshot?.model_key === preferences.modelPreference
|
|
123
|
-
? preferences.modelSnapshot
|
|
260
|
+
? mergeModelReference(preferences.modelSnapshot)
|
|
124
261
|
: null;
|
|
125
|
-
|
|
262
|
+
let model = snapshot || getModelRecord(preferences.modelPreference);
|
|
263
|
+
if (!model && (preferences.modelPreference === 'auto' || !preferences.modelPreference)) {
|
|
264
|
+
model = mergeModelReference(preferences.modelSnapshot) || listModelCatalog()[0];
|
|
265
|
+
}
|
|
126
266
|
if (!model) throw new Error('Select an exact provider-verified model with /model first so Agent Sam can verify supported runtime controls.');
|
|
127
267
|
return { preferences, model };
|
|
128
268
|
}
|
|
@@ -168,24 +308,32 @@ async function resolveModelForTurn(cwd, state) {
|
|
|
168
308
|
|
|
169
309
|
async function chooseReasoning(cwd, args, state) {
|
|
170
310
|
const { preferences, model } = selectedModel(cwd);
|
|
311
|
+
const supported = ['auto', ...model.reasoning_efforts.filter((value) => value !== 'auto')];
|
|
171
312
|
let effort = String(args[0] || '').trim().toLowerCase();
|
|
172
313
|
if (!effort) {
|
|
173
314
|
if (!state.interactive) {
|
|
174
|
-
writeLine(state.write,
|
|
175
|
-
writeLine(state.write,
|
|
315
|
+
writeLine(state.write, ' ' + model.provider_model_id + ' reasoning: ' + supported.join(' | '));
|
|
316
|
+
writeLine(state.write, ' provider default: ' + (model.default_reasoning_effort || 'unknown'));
|
|
317
|
+
writeLine(state.write, ' current: ' + (preferences.reasoningEffort || 'auto'));
|
|
176
318
|
return;
|
|
177
319
|
}
|
|
178
320
|
const choice = await select({
|
|
179
|
-
message:
|
|
180
|
-
initialValue:
|
|
181
|
-
options:
|
|
321
|
+
message: 'Reasoning level · ' + model.provider_model_id,
|
|
322
|
+
initialValue: supported.includes(preferences.reasoningEffort) ? preferences.reasoningEffort : 'auto',
|
|
323
|
+
options: supported.map((value) => ({
|
|
324
|
+
value,
|
|
325
|
+
label: value === 'auto' ? 'Automatic' : value === 'xhigh' ? 'Extra high' : value === 'max' ? 'Max' : value[0].toUpperCase() + value.slice(1),
|
|
326
|
+
hint: value === 'auto'
|
|
327
|
+
? 'omit reasoning.effort · provider default ' + (model.default_reasoning_effort || 'unknown')
|
|
328
|
+
: value === model.default_reasoning_effort ? 'provider default' : undefined,
|
|
329
|
+
})),
|
|
182
330
|
});
|
|
183
331
|
if (isCancel(choice)) return;
|
|
184
332
|
effort = choice;
|
|
185
333
|
}
|
|
186
|
-
if (!
|
|
334
|
+
if (!supported.includes(effort)) throw new Error('unsupported reasoning level for ' + model.provider_model_id + ': ' + effort);
|
|
187
335
|
updateCliPreferences(cwd, { reasoningEffort: effort });
|
|
188
|
-
writeLine(state.write,
|
|
336
|
+
writeLine(state.write, ' reasoning → ' + effort);
|
|
189
337
|
}
|
|
190
338
|
|
|
191
339
|
function setServiceTier(cwd, tier, write) {
|
|
@@ -240,15 +388,15 @@ export async function runLocalAgent(goal, write, options = {}) {
|
|
|
240
388
|
}
|
|
241
389
|
|
|
242
390
|
async function showLocalLogs(cwd, write) {
|
|
243
|
-
const dbPath =
|
|
244
|
-
if (!fs.existsSync(dbPath)) { writeLine(write, ' No local Agent Sam
|
|
391
|
+
const dbPath = runtimeDatabasePath(cwd);
|
|
392
|
+
if (!fs.existsSync(dbPath)) { writeLine(write, ' No local Agent Sam runs yet.'); return; }
|
|
245
393
|
const { createLocalSqliteDatabase } = await import('../local/sqlite.js');
|
|
246
394
|
const db = await createLocalSqliteDatabase(dbPath);
|
|
247
395
|
try {
|
|
248
|
-
const
|
|
249
|
-
if (!
|
|
250
|
-
writeLine(write, '\n Recent Agent Sam
|
|
251
|
-
for (const row of
|
|
396
|
+
const runs = await db.prepare('SELECT id, model_key, status, started_at_unix FROM agentsam_agent_run ORDER BY started_at_unix DESC LIMIT 20').all();
|
|
397
|
+
if (!runs.results.length) { writeLine(write, ' No local Agent Sam runs yet.'); return; }
|
|
398
|
+
writeLine(write, '\n Recent Agent Sam runs');
|
|
399
|
+
for (const row of runs.results) writeLine(write, ` ${new Date(Number(row.started_at_unix) * 1000).toISOString()} ${String(row.status || '').padEnd(10)} ${row.model_key || 'model unknown'} · ${row.id}`);
|
|
252
400
|
writeLine(write, '');
|
|
253
401
|
} finally { db.close(); }
|
|
254
402
|
}
|
|
@@ -299,6 +447,7 @@ export function renderSessionReceipt(session) {
|
|
|
299
447
|
if (componentTotal > 0) {
|
|
300
448
|
lines.push(`Cost breakdown: input ${formatUsd(breakdown.input)} · cached ${formatUsd(breakdown.cached_input)} · cache write ${formatUsd(breakdown.cache_write)} · output ${formatUsd(breakdown.output)}`);
|
|
301
449
|
}
|
|
450
|
+
if (session.latest_compaction) lines.push(`Latest compaction: ${session.latest_compaction.compaction_id || 'completed'} · ${formatUsd(session.latest_compaction.cost_usd)}`);
|
|
302
451
|
if (active) lines.push(`Active context: ${formatCount(active)} tokens`);
|
|
303
452
|
lines.push('', 'To continue this session, run:', ` agentsam resume ${session.id}`, '', 'Or run:', ' agentsam resume', '', 'and select:', ` ${session.title || 'this session'}`, '');
|
|
304
453
|
return lines.join('\n');
|
|
@@ -306,7 +455,7 @@ export function renderSessionReceipt(session) {
|
|
|
306
455
|
|
|
307
456
|
function persistSession(state, patch = {}) {
|
|
308
457
|
if (!state.session) return null;
|
|
309
|
-
state.session = saveLocalSession({ ...state.session, ...patch }, { home: state.home });
|
|
458
|
+
state.session = saveLocalSession({ ...state.session, ...patch }, { home: state.home, projectRoot: state.projectRoot });
|
|
310
459
|
return state.session;
|
|
311
460
|
}
|
|
312
461
|
|
|
@@ -317,8 +466,6 @@ function recordSessionInput(state, input) {
|
|
|
317
466
|
if (housekeeping.has(value.toLowerCase())) return;
|
|
318
467
|
persistSession(state, {
|
|
319
468
|
status: 'active',
|
|
320
|
-
last_input: value,
|
|
321
|
-
title: sessionTitleFromInput(value),
|
|
322
469
|
});
|
|
323
470
|
}
|
|
324
471
|
|
|
@@ -391,6 +538,55 @@ async function approveToolExecution(request, state) {
|
|
|
391
538
|
return true;
|
|
392
539
|
}
|
|
393
540
|
|
|
541
|
+
async function runInteractiveCompaction(args, state) {
|
|
542
|
+
if (args.length > 1 || (args.length && args[0] !== 'status')) throw new Error('Usage: /compact [status]');
|
|
543
|
+
const { model } = selectedModel(state.cwd);
|
|
544
|
+
const supported = ['openai', 'grok'].includes(model.provider) && model.capabilities?.compaction === true;
|
|
545
|
+
const report = buildContextEconomicsReport(state.cwd, { activeInputTokens: state.usageSnapshot?.current_context?.input_tokens ?? state.session?.usage_snapshot?.current_context?.input_tokens });
|
|
546
|
+
if (args[0] === 'status') {
|
|
547
|
+
writeLine(state.write, ` Compaction · ${model.provider}/${model.provider_model_id}`);
|
|
548
|
+
writeLine(state.write, ` support ${supported ? 'native' : 'unavailable'}`);
|
|
549
|
+
writeLine(state.write, ` active ${report.active_input_tokens ?? 'unknown'} tokens`);
|
|
550
|
+
writeLine(state.write, ` threshold ${report.compact_at_tokens ?? 'unknown'} tokens`);
|
|
551
|
+
writeLine(state.write, ` automatic ${supported && state.session?.auto_compact !== false ? 'enabled' : 'disabled'}`);
|
|
552
|
+
const receipt = state.session?.latest_compaction;
|
|
553
|
+
writeLine(state.write, ` latest ${receipt ? `${receipt.compaction_id} · ${receipt.created_at} · ${formatUsd(receipt.cost_usd)}` : 'none'}`);
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
if (!supported) throw new Error(`native_compaction_unavailable:${model.provider}`);
|
|
557
|
+
if (!state.session || state.session.model_key !== model.model_key) throw new Error('compaction_active_model_session_required');
|
|
558
|
+
const previous = state.providerState || loadSessionContinuation(state.session);
|
|
559
|
+
if (!previous?.previous_response_id && !previous?.compacted_input?.length && !previous?.compaction_input?.length) throw new Error('compaction_context_unavailable');
|
|
560
|
+
const credential = resolveProviderCredential(model.provider, { home: state.home });
|
|
561
|
+
const provider = createProviderAdapter({ modelRecord: model, credential, fetchImpl: state.providerFetchImpl });
|
|
562
|
+
if (typeof provider.compact !== 'function') throw new Error(`native_compaction_unavailable:${model.provider}`);
|
|
563
|
+
const result = await provider.compact({
|
|
564
|
+
model: model.provider_model_id, modelRecord: model, providerState: previous,
|
|
565
|
+
promptCacheKey: state.session.id,
|
|
566
|
+
tokensBefore: report.active_input_tokens, cumulativeUsage: state.session.cumulative_usage,
|
|
567
|
+
});
|
|
568
|
+
if (!Array.isArray(result.output) || !result.output.length) throw new Error('provider_compaction_output_missing');
|
|
569
|
+
const receipt = checkpointCompaction(state, model, result);
|
|
570
|
+
writeLine(state.write, ` Compacted · ${receipt.compaction_id} · ${formatUsd(receipt.cost_usd)} · continuation saved`);
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
function checkpointCompaction(state, model, result) {
|
|
574
|
+
const delta = result.usage_delta || result.usage || {};
|
|
575
|
+
const cumulative = Object.fromEntries(['input_tokens', 'output_tokens', 'cached_input_tokens', 'cache_write_tokens', 'reasoning_tokens'].map(key => [key, Number(state.session.cumulative_usage?.[key] || 0) + Number(delta[key] || 0)]));
|
|
576
|
+
const providerState = { provider: model.provider, ...(result.provider_state || {}), previous_response_id: null, compacted_input: result.output };
|
|
577
|
+
const usageSnapshot = { current_context: { input_tokens: Math.ceil(JSON.stringify(result.output).length / 4), window_tokens: model.context_window }, cumulative, estimate_kind: 'local' };
|
|
578
|
+
const receipt = { compaction_id: result.compaction_id, provider: model.provider, model: model.provider_model_id, created_at: new Date().toISOString(), usage: delta, cost_usd: result.cost?.total_usd || 0 };
|
|
579
|
+
persistSession(state, {
|
|
580
|
+
provider_state: providerState, usage_snapshot: usageSnapshot, cumulative_usage: cumulative,
|
|
581
|
+
latest_compaction: receipt,
|
|
582
|
+
total_cost_usd: Number(state.session.total_cost_usd || 0) + Number(result.cost?.total_usd || 0),
|
|
583
|
+
cost_breakdown_usd: Object.fromEntries(['input', 'cached_input', 'cache_write', 'output'].map(key => [key, Number(state.session.cost_breakdown_usd?.[key] || 0) + Number(result.cost?.components_usd?.[key] || 0)])),
|
|
584
|
+
});
|
|
585
|
+
state.providerState = providerState;
|
|
586
|
+
state.usageSnapshot = usageSnapshot;
|
|
587
|
+
return receipt;
|
|
588
|
+
}
|
|
589
|
+
|
|
394
590
|
async function runInteractiveModelTurn(prompt, state) {
|
|
395
591
|
const resolved = await resolveModelForTurn(state.cwd, state);
|
|
396
592
|
const { preferences, model, credential } = resolved;
|
|
@@ -402,17 +598,15 @@ async function runInteractiveModelTurn(prompt, state) {
|
|
|
402
598
|
});
|
|
403
599
|
const capabilityAdapter = createCapabilityAdapter();
|
|
404
600
|
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
&& state.session.requested_service_tier === preferences.serviceTier;
|
|
409
|
-
const previousProviderState = samePolicy ? state.session?.provider_state : null;
|
|
601
|
+
// Reasoning/tier changes do not change the provider conversation's owner.
|
|
602
|
+
const samePolicy = state.session && state.session.model_key === model.model_key;
|
|
603
|
+
const previousProviderState = samePolicy ? (state.providerState || loadSessionContinuation(state.session)) : null;
|
|
410
604
|
const previousUsageSnapshot = samePolicy ? state.session?.usage_snapshot : null;
|
|
411
605
|
const accountId = readAccountSession({ home: state.home })?.account_id || null;
|
|
412
606
|
let runtimeRunId = null;
|
|
413
607
|
try {
|
|
414
608
|
runtimeRunId = await startRuntimeRun({
|
|
415
|
-
|
|
609
|
+
projectRoot: state.projectRoot,
|
|
416
610
|
account_id: accountId,
|
|
417
611
|
mode: 'agent',
|
|
418
612
|
model_key: model.model_key,
|
|
@@ -430,6 +624,8 @@ async function runInteractiveModelTurn(prompt, state) {
|
|
|
430
624
|
});
|
|
431
625
|
state.activity = activity;
|
|
432
626
|
const presenter = createCliRuntimePresenter({ activity, write: state.write, state });
|
|
627
|
+
const startingCostUsd = Number(state.session?.total_cost_usd || 0);
|
|
628
|
+
const startingCostBreakdown = { ...state.session?.cost_breakdown_usd };
|
|
433
629
|
const startedAt = Date.now();
|
|
434
630
|
activity.start(`Thinking · ${model.provider_model_id}`);
|
|
435
631
|
|
|
@@ -444,9 +640,17 @@ async function runInteractiveModelTurn(prompt, state) {
|
|
|
444
640
|
modelRecord: model,
|
|
445
641
|
reasoningEffort: preferences.reasoningEffort,
|
|
446
642
|
serviceTier: preferences.serviceTier,
|
|
643
|
+
// The interactive CLI turn is the main agentic engineering loop, not a
|
|
644
|
+
// one-shot lookup -- the previous unconfigurable default (quick: 8
|
|
645
|
+
// rounds) killed genuine multi-step work for no reason tied to risk,
|
|
646
|
+
// cost, or progress. `agent` (128 rounds) is the right default here;
|
|
647
|
+
// preferences.runMode leaves room for a future explicit override.
|
|
648
|
+
runMode: preferences.runMode || 'agent',
|
|
447
649
|
previousProviderState,
|
|
448
650
|
previousUsageSnapshot,
|
|
449
651
|
cumulativeUsage: state.session?.cumulative_usage || null,
|
|
652
|
+
autoCompact: state.session?.auto_compact !== false,
|
|
653
|
+
onCompaction: result => { if (state.session) checkpointCompaction(state, model, result); },
|
|
450
654
|
promptCacheKey: state.session?.id || undefined,
|
|
451
655
|
runId: runtimeRunId || state.session?.id || undefined,
|
|
452
656
|
beforeRequest: (preflight) => approveModelRequest(preflight, state),
|
|
@@ -462,7 +666,7 @@ async function runInteractiveModelTurn(prompt, state) {
|
|
|
462
666
|
if (runtimeRunId) {
|
|
463
667
|
try {
|
|
464
668
|
await finishRuntimeRun({
|
|
465
|
-
|
|
669
|
+
projectRoot: state.projectRoot,
|
|
466
670
|
id: runtimeRunId,
|
|
467
671
|
status: 'failed',
|
|
468
672
|
error_code: error?.code || 'interactive_error',
|
|
@@ -487,10 +691,12 @@ async function runInteractiveModelTurn(prompt, state) {
|
|
|
487
691
|
}
|
|
488
692
|
|
|
489
693
|
state.usageSnapshot = result.usage_snapshot;
|
|
694
|
+
state.providerState = result.provider_state || null;
|
|
695
|
+
state.lastTurnElapsedMs = Date.now() - startedAt;
|
|
490
696
|
if (runtimeRunId) {
|
|
491
697
|
try {
|
|
492
698
|
await finishRuntimeRun({
|
|
493
|
-
|
|
699
|
+
projectRoot: state.projectRoot,
|
|
494
700
|
id: runtimeRunId,
|
|
495
701
|
status: 'completed',
|
|
496
702
|
actual_service_tier: result.actual_service_tier,
|
|
@@ -500,7 +706,7 @@ async function runInteractiveModelTurn(prompt, state) {
|
|
|
500
706
|
});
|
|
501
707
|
if (presenter.state.lastCompaction) {
|
|
502
708
|
await recordRuntimeCompaction({
|
|
503
|
-
|
|
709
|
+
projectRoot: state.projectRoot,
|
|
504
710
|
account_id: accountId,
|
|
505
711
|
agent_run_id: runtimeRunId,
|
|
506
712
|
session_id: state.session?.id,
|
|
@@ -526,30 +732,66 @@ async function runInteractiveModelTurn(prompt, state) {
|
|
|
526
732
|
provider_state: { provider: model.provider, ...(result.provider_state || {}) },
|
|
527
733
|
usage_snapshot: result.usage_snapshot,
|
|
528
734
|
cumulative_usage: result.cumulative_usage,
|
|
529
|
-
|
|
735
|
+
latest_compaction: result.compaction || state.session.latest_compaction,
|
|
736
|
+
total_cost_usd: startingCostUsd + Number(result.total_cost_usd || 0),
|
|
530
737
|
cost_breakdown_usd: Object.fromEntries(['input', 'cached_input', 'cache_write', 'output'].map((key) => [
|
|
531
|
-
key, Number(
|
|
738
|
+
key, Number(startingCostBreakdown[key] || 0) + Number(result.cost_breakdown_usd?.[key] || 0),
|
|
532
739
|
])),
|
|
533
740
|
last_error: null,
|
|
534
741
|
});
|
|
535
742
|
}
|
|
536
743
|
|
|
744
|
+
const identity = resolveShellIdentity(state);
|
|
537
745
|
writeLine(state.write, renderCliFooter({
|
|
746
|
+
projectName: identity.project,
|
|
747
|
+
branch: identity.branch,
|
|
748
|
+
cwd: compactCwd(state.cwd),
|
|
538
749
|
model: result.model || model.provider_model_id,
|
|
750
|
+
provider: model.provider,
|
|
751
|
+
effort: result.reasoning_effort,
|
|
539
752
|
usageSnapshot: result.usage_snapshot,
|
|
540
753
|
tier: result.actual_service_tier,
|
|
541
|
-
elapsedMs:
|
|
754
|
+
elapsedMs: state.lastTurnElapsedMs,
|
|
542
755
|
}));
|
|
543
756
|
writeLine(state.write, '');
|
|
757
|
+
state.wroteTurnFooter = true;
|
|
544
758
|
return result;
|
|
545
759
|
}
|
|
546
760
|
|
|
547
761
|
export async function dispatchShellLine(line, state = {}) {
|
|
548
|
-
|
|
762
|
+
let tokens = tokenizeShellLine(line);
|
|
549
763
|
const write = state.write || ((text) => process.stdout.write(text));
|
|
550
764
|
state.write = write;
|
|
551
765
|
state.cwd = path.resolve(state.cwd || process.cwd());
|
|
766
|
+
state.projectRoot ||= findCliProjectRoot(state.cwd);
|
|
552
767
|
if (!tokens.length) return { handled: true, exit: false, cwd: state.cwd };
|
|
768
|
+
|
|
769
|
+
// Strip a leading "agentsam" prefix if present -- it should never change
|
|
770
|
+
// whether the rest of the line resolves, only whether it was typed at all.
|
|
771
|
+
if (tokens[0].toLowerCase() === 'agentsam') {
|
|
772
|
+
tokens = tokens.slice(1);
|
|
773
|
+
if (!tokens.length) tokens = ['help'];
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
// Recognized short verbs (with or without a stripped "agentsam" prefix)
|
|
777
|
+
// become their slash command. Anything unrecognized -- typo, a host-CLI-only
|
|
778
|
+
// verb like "merkle" typed here, whatever -- is left as plain text and
|
|
779
|
+
// falls through to the natural-language model turn below. There is no
|
|
780
|
+
// path left that hard-errors on an unrecognized word; "unknown command"
|
|
781
|
+
// only fires for input that explicitly starts with "/".
|
|
782
|
+
if (!tokens[0].startsWith('/')) {
|
|
783
|
+
const bare = tokens[0].toLowerCase();
|
|
784
|
+
const commonVerbs = [
|
|
785
|
+
'help', 'exit', 'quit', 'clear', 'status', 'models', 'model',
|
|
786
|
+
'whoami', 'cf', 'cloudflare', 'db', 'tunnel', 'connections',
|
|
787
|
+
'connect', 'usage', 'session', 'providers', 'settings', 'logs',
|
|
788
|
+
'git', 'diff', 'pwd', 'cd', 'fast', 'flex', 'standard', 'reasoning',
|
|
789
|
+
];
|
|
790
|
+
if (commonVerbs.includes(bare)) {
|
|
791
|
+
tokens[0] = `/${bare}`;
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
|
|
553
795
|
const [command, ...args] = tokens;
|
|
554
796
|
try {
|
|
555
797
|
switch (command.toLowerCase()) {
|
|
@@ -564,8 +806,15 @@ export async function dispatchShellLine(line, state = {}) {
|
|
|
564
806
|
case '/quit':
|
|
565
807
|
return { handled: true, exit: true, cwd: state.cwd };
|
|
566
808
|
case '/model': {
|
|
567
|
-
|
|
568
|
-
|
|
809
|
+
state.rl?.pause?.();
|
|
810
|
+
try {
|
|
811
|
+
const configured = await configureCliPreferences({ cwd: state.cwd, firstRun: false, section: 'model', home: state.home });
|
|
812
|
+
state.cwd = configured.identity.root;
|
|
813
|
+
state.projectRoot = findCliProjectRoot(state.cwd);
|
|
814
|
+
} finally {
|
|
815
|
+
if (process.stdin.isPaused()) process.stdin.resume();
|
|
816
|
+
state.rl?.resume?.();
|
|
817
|
+
}
|
|
569
818
|
break;
|
|
570
819
|
}
|
|
571
820
|
case '/reasoning':
|
|
@@ -580,18 +829,37 @@ export async function dispatchShellLine(line, state = {}) {
|
|
|
580
829
|
case '/standard':
|
|
581
830
|
setServiceTier(state.cwd, 'default', write);
|
|
582
831
|
break;
|
|
832
|
+
case '/compact':
|
|
833
|
+
await runInteractiveCompaction(args, state);
|
|
834
|
+
break;
|
|
583
835
|
case '/context':
|
|
584
836
|
if (args[0] === 'repo' || args[0] === 'git') await runContext(['--cwd', state.cwd, ...args.slice(1)]);
|
|
585
837
|
else write(renderContextEconomics(buildContextEconomicsReport(state.cwd, {
|
|
586
838
|
activeInputTokens: state.usageSnapshot?.current_context?.input_tokens,
|
|
587
839
|
estimateKind: state.usageSnapshot?.estimate_kind,
|
|
840
|
+
autoCompact: state.session?.auto_compact,
|
|
588
841
|
})));
|
|
589
842
|
break;
|
|
590
843
|
case '/status':
|
|
591
844
|
await runStatus(args, { cwd: state.cwd });
|
|
592
845
|
break;
|
|
593
846
|
case '/models':
|
|
594
|
-
|
|
847
|
+
state.rl?.pause?.();
|
|
848
|
+
try {
|
|
849
|
+
await runModels(args, { cwd: state.cwd, write, home: state.home, interactive: state.interactive });
|
|
850
|
+
} finally {
|
|
851
|
+
if (process.stdin.isPaused()) process.stdin.resume();
|
|
852
|
+
state.rl?.resume?.();
|
|
853
|
+
}
|
|
854
|
+
break;
|
|
855
|
+
case '/providers':
|
|
856
|
+
state.rl?.pause?.();
|
|
857
|
+
try {
|
|
858
|
+
await runProviders(args, { write, home: state.home, interactive: state.interactive });
|
|
859
|
+
} finally {
|
|
860
|
+
if (process.stdin.isPaused()) process.stdin.resume();
|
|
861
|
+
state.rl?.resume?.();
|
|
862
|
+
}
|
|
595
863
|
break;
|
|
596
864
|
case '/login':
|
|
597
865
|
await runLogin(args, { write, home: state.home });
|
|
@@ -604,17 +872,43 @@ export async function dispatchShellLine(line, state = {}) {
|
|
|
604
872
|
await runWhoami(args, { write, home: state.home });
|
|
605
873
|
break;
|
|
606
874
|
case '/session':
|
|
607
|
-
case '/usage':
|
|
608
875
|
if (state.session) write(renderSessionReceipt(state.session));
|
|
609
876
|
else writeLine(write, ' No persistent session is active in this shell invocation.');
|
|
610
877
|
break;
|
|
878
|
+
case '/usage':
|
|
879
|
+
write(renderUsagePanel({
|
|
880
|
+
session: state.session,
|
|
881
|
+
usage: state.usageSnapshot || state.session?.usage_snapshot,
|
|
882
|
+
provider: state.providerState?.provider || state.session?.provider,
|
|
883
|
+
model: state.providerState?.model || state.session?.model,
|
|
884
|
+
effort: state.providerState?.reasoning_effort || state.session?.reasoning_effort,
|
|
885
|
+
tier: state.providerState?.service_tier || state.session?.service_tier,
|
|
886
|
+
estimateKind: state.usageSnapshot?.estimate_kind,
|
|
887
|
+
elapsedMs: state.session ? localSessionElapsedMs(state.session) : null,
|
|
888
|
+
cost: state.usageSnapshot?.cumulative?.cost_usd ?? state.session?.cumulative_usage?.cost_usd,
|
|
889
|
+
}));
|
|
890
|
+
break;
|
|
611
891
|
case '/cf':
|
|
612
892
|
case '/cloudflare':
|
|
613
893
|
await runCloudflare(args.length ? args : ['commands'], { cwd: state.cwd, write });
|
|
614
894
|
break;
|
|
895
|
+
case '/connections':
|
|
896
|
+
case '/connect':
|
|
897
|
+
await runConnections(args, { cwd: state.cwd, write, home: state.home });
|
|
898
|
+
break;
|
|
899
|
+
case '/tunnel':
|
|
900
|
+
await runTunnel(args, { cwd: state.cwd, write, home: state.home, interactive: state.interactive });
|
|
901
|
+
break;
|
|
615
902
|
case '/settings': {
|
|
616
|
-
|
|
617
|
-
|
|
903
|
+
state.rl?.pause?.();
|
|
904
|
+
try {
|
|
905
|
+
const configured = await configureCliPreferences({ cwd: state.cwd, firstRun: false, home: state.home });
|
|
906
|
+
state.cwd = configured.identity.root;
|
|
907
|
+
state.projectRoot = findCliProjectRoot(state.cwd);
|
|
908
|
+
} finally {
|
|
909
|
+
if (process.stdin.isPaused()) process.stdin.resume();
|
|
910
|
+
state.rl?.resume?.();
|
|
911
|
+
}
|
|
618
912
|
break;
|
|
619
913
|
}
|
|
620
914
|
case '/pwd':
|
|
@@ -624,22 +918,100 @@ export async function dispatchShellLine(line, state = {}) {
|
|
|
624
918
|
const destination = args.length ? args.join(' ') : process.env.HOME || process.env.USERPROFILE || state.cwd;
|
|
625
919
|
const next = path.resolve(state.cwd, destination);
|
|
626
920
|
if (!fs.existsSync(next) || !fs.statSync(next).isDirectory()) throw new Error(`directory not found: ${next}`);
|
|
921
|
+
const nextRoot = findCliProjectRoot(next);
|
|
922
|
+
if (nextRoot !== (state.projectRoot || findCliProjectRoot(state.cwd))) {
|
|
923
|
+
if (state.session) {
|
|
924
|
+
persistSession(state, { status: 'paused', active_elapsed_ms: localSessionElapsedMs(state.session), active_started_at: null });
|
|
925
|
+
state.session = createLocalSession({ cwd: next, project_root: nextRoot }, { projectRoot: nextRoot, home: state.home });
|
|
926
|
+
}
|
|
927
|
+
state.projectRoot = nextRoot;
|
|
928
|
+
state.usageSnapshot = null;
|
|
929
|
+
state.providerState = null;
|
|
930
|
+
}
|
|
627
931
|
state.cwd = next;
|
|
932
|
+
state.identity = null;
|
|
933
|
+
state.identityCwd = null;
|
|
628
934
|
writeLine(write, state.cwd);
|
|
629
935
|
break;
|
|
630
936
|
}
|
|
631
937
|
case '/git':
|
|
632
938
|
spawnGit(state.cwd, args.length ? args : ['status', '--short', '--branch']);
|
|
633
939
|
break;
|
|
634
|
-
case '/diff':
|
|
635
|
-
|
|
940
|
+
case '/diff': {
|
|
941
|
+
const result = spawnSync('git', ['diff', '--no-color', ...args], { cwd: state.cwd, encoding: 'utf8', shell: false });
|
|
942
|
+
if (result.error) throw result.error;
|
|
943
|
+
if (result.status !== 0 && !String(result.stdout || '').trim()) {
|
|
944
|
+
throw new Error(String(result.stderr || `git exited ${result.status}`).trim());
|
|
945
|
+
}
|
|
946
|
+
write(renderDiffPreview(result.stdout || ''));
|
|
636
947
|
break;
|
|
948
|
+
}
|
|
637
949
|
case '/db':
|
|
638
|
-
await runDb(args.length ? args : ['status'], { cwd: state.cwd });
|
|
950
|
+
await runDb(args.length ? args : ['status'], { cwd: state.projectRoot || state.cwd, write });
|
|
639
951
|
break;
|
|
640
952
|
case '/agent':
|
|
641
953
|
await runLocalAgent(args.join(' '), write, { interactive: state.interactive });
|
|
642
954
|
break;
|
|
955
|
+
case '/goap': {
|
|
956
|
+
const sub = (args[0] || 'status').toLowerCase();
|
|
957
|
+
if (sub === 'list' || sub === 'ls') {
|
|
958
|
+
const listState = await listGoapTickets({ cwd: state.cwd });
|
|
959
|
+
if (!listState.ok) {
|
|
960
|
+
writeLine(write, ` Failed to list GOAP tickets: ${listState.error || 'unknown error'}`);
|
|
961
|
+
} else {
|
|
962
|
+
writeLine(write, renderGoapList(listState));
|
|
963
|
+
}
|
|
964
|
+
break;
|
|
965
|
+
}
|
|
966
|
+
if (sub === 'new' || sub === 'create') {
|
|
967
|
+
const title = args.slice(1).join(' ').trim();
|
|
968
|
+
if (!title) {
|
|
969
|
+
writeLine(write, ' Usage: /goap new <title>');
|
|
970
|
+
break;
|
|
971
|
+
}
|
|
972
|
+
const res = await createGoapGoal({ cwd: state.cwd, title, accountId: readAccountSession({ home: state.home })?.account_id || null });
|
|
973
|
+
if (!res.ok) {
|
|
974
|
+
writeLine(write, ` Failed to create GOAP goal: ${res.error || 'unknown error'}`);
|
|
975
|
+
} else {
|
|
976
|
+
writeLine(write, ` Created and activated goal: ${res.ticketId} ("${res.title}")`);
|
|
977
|
+
}
|
|
978
|
+
break;
|
|
979
|
+
}
|
|
980
|
+
if (sub === 'switch' || sub === 'select') {
|
|
981
|
+
const tid = args[1]?.trim();
|
|
982
|
+
if (!tid) {
|
|
983
|
+
writeLine(write, ' Usage: /goap switch <ticket_id>');
|
|
984
|
+
break;
|
|
985
|
+
}
|
|
986
|
+
const res = await switchGoapGoal({ cwd: state.cwd, ticketId: tid, accountId: readAccountSession({ home: state.home })?.account_id || null });
|
|
987
|
+
if (!res.ok) {
|
|
988
|
+
writeLine(write, ` Failed to switch GOAP goal: ${res.error || 'unknown error'}`);
|
|
989
|
+
} else {
|
|
990
|
+
writeLine(write, ` Switched active GOAP goal to: ${res.ticketId}`);
|
|
991
|
+
}
|
|
992
|
+
break;
|
|
993
|
+
}
|
|
994
|
+
if (sub === 'close') {
|
|
995
|
+
const tid = args[1]?.trim() || null;
|
|
996
|
+
const res = await closeGoapGoal({ cwd: state.cwd, ticketId: tid, accountId: readAccountSession({ home: state.home })?.account_id || null });
|
|
997
|
+
if (!res.ok) {
|
|
998
|
+
writeLine(write, ` Failed to close GOAP goal: ${res.error || 'unknown error'}`);
|
|
999
|
+
} else {
|
|
1000
|
+
writeLine(write, ` Closed GOAP goal: ${res.ticketId} [${res.status}]`);
|
|
1001
|
+
}
|
|
1002
|
+
break;
|
|
1003
|
+
}
|
|
1004
|
+
const goapState = await readGoapState({ cwd: state.cwd, accountId: readAccountSession({ home: state.home })?.account_id || null });
|
|
1005
|
+
if (!goapState.ok) {
|
|
1006
|
+
writeLine(write, ` Failed to read GOAP state: ${goapState.error || 'unknown error'}`);
|
|
1007
|
+
break;
|
|
1008
|
+
}
|
|
1009
|
+
if (sub === 'goal') writeLine(write, renderGoapGoal(goapState));
|
|
1010
|
+
else if (sub === 'why') writeLine(write, renderGoapWhy(goapState));
|
|
1011
|
+
else if (sub === 'plan') writeLine(write, renderGoapPlan(goapState));
|
|
1012
|
+
else writeLine(write, renderGoapStatus(goapState));
|
|
1013
|
+
break;
|
|
1014
|
+
}
|
|
643
1015
|
case '/logs':
|
|
644
1016
|
await showLocalLogs(state.cwd, write);
|
|
645
1017
|
break;
|
|
@@ -663,9 +1035,15 @@ export async function dispatchShellLine(line, state = {}) {
|
|
|
663
1035
|
persistSession(state, { last_error: diagnosticFromError(error, { source: 'shell', kind: 'interactive_error' }) });
|
|
664
1036
|
}
|
|
665
1037
|
if (!error?.reported) {
|
|
666
|
-
for (const
|
|
1038
|
+
for (const errorLine of renderDiagnosticError(error).split('\n')) writeLine(write, ` ${errorLine}`);
|
|
667
1039
|
}
|
|
668
1040
|
}
|
|
1041
|
+
const skipFooter = state.wroteTurnFooter;
|
|
1042
|
+
state.wroteTurnFooter = false;
|
|
1043
|
+
if (state.persistFooter && !skipFooter) {
|
|
1044
|
+
writeLine(write, renderShellSessionFooter(state));
|
|
1045
|
+
writeLine(write, '');
|
|
1046
|
+
}
|
|
669
1047
|
return { handled: true, exit: false, cwd: state.cwd };
|
|
670
1048
|
}
|
|
671
1049
|
|
|
@@ -673,14 +1051,18 @@ export async function runShell(argv = [], options = {}) {
|
|
|
673
1051
|
const write = options.write || ((text) => process.stdout.write(text));
|
|
674
1052
|
const state = {
|
|
675
1053
|
cwd: path.resolve(options.cwd || process.cwd()),
|
|
1054
|
+
projectRoot: findCliProjectRoot(options.session?.project_root || options.cwd || process.cwd()),
|
|
676
1055
|
write,
|
|
677
1056
|
interactive: options.interactive ?? Boolean(process.stdin.isTTY && process.stdout.isTTY),
|
|
678
1057
|
usageSnapshot: options.usageSnapshot || options.session?.usage_snapshot || null,
|
|
1058
|
+
providerState: null,
|
|
679
1059
|
session: options.session || null,
|
|
680
1060
|
home: options.home,
|
|
681
1061
|
providerFetchImpl: options.providerFetchImpl,
|
|
1062
|
+
persistFooter: options.persistFooter === true,
|
|
682
1063
|
};
|
|
683
1064
|
const sub = argv[0] || '';
|
|
1065
|
+
hydrateSecureCredentials(process.env, { home: state.home });
|
|
684
1066
|
if (sub === 'list' || sub === 'status') { write(renderShellCatalog()); return; }
|
|
685
1067
|
if (sub === '--command' || sub === '--once') {
|
|
686
1068
|
const line = argv.slice(1).join(' ');
|
|
@@ -697,40 +1079,73 @@ export async function runShell(argv = [], options = {}) {
|
|
|
697
1079
|
status: 'active',
|
|
698
1080
|
cwd: state.cwd,
|
|
699
1081
|
active_started_at: new Date().toISOString(),
|
|
700
|
-
}, { home: state.home });
|
|
1082
|
+
}, { home: state.home, projectRoot: state.projectRoot });
|
|
701
1083
|
state.usageSnapshot = state.session.usage_snapshot || state.usageSnapshot;
|
|
702
1084
|
} else {
|
|
703
1085
|
const preferences = readCliPreferences(state.cwd) || {};
|
|
704
1086
|
state.session = createLocalSession({
|
|
705
1087
|
cwd: state.cwd,
|
|
1088
|
+
project_root: state.projectRoot,
|
|
706
1089
|
status: 'active',
|
|
707
1090
|
model_key: preferences.modelPreference !== 'auto' ? preferences.modelPreference : null,
|
|
708
1091
|
reasoning_effort: preferences.reasoningEffort !== 'auto' ? preferences.reasoningEffort : null,
|
|
709
1092
|
requested_service_tier: preferences.serviceTier || 'default',
|
|
710
|
-
}, { home: state.home });
|
|
1093
|
+
}, { home: state.home, projectRoot: state.projectRoot });
|
|
711
1094
|
}
|
|
712
1095
|
|
|
713
1096
|
if (options.intro !== 'quiet') {
|
|
714
1097
|
write(renderShellCatalog());
|
|
715
1098
|
writeLine(write, ' Interactive shell ready. Type / for the command picker; /exit to return to your host shell.\n');
|
|
716
1099
|
}
|
|
1100
|
+
state.persistFooter = options.persistFooter !== false;
|
|
1101
|
+
writeLine(write, renderShellSessionFooter(state));
|
|
1102
|
+
writeLine(write, '');
|
|
717
1103
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout, terminal: Boolean(process.stdin.isTTY && process.stdout.isTTY) });
|
|
1104
|
+
state.rl = rl;
|
|
1105
|
+
let promptTextRef = () => renderShellPrompt(state.cwd);
|
|
1106
|
+
const restorePaste = installPasteCollapse(rl, { output: process.stdout });
|
|
718
1107
|
let interrupted = false;
|
|
1108
|
+
let lastSigintAt = 0;
|
|
1109
|
+
const SIGINT_EXIT_WINDOW_MS = 2000;
|
|
719
1110
|
rl.on('SIGINT', () => {
|
|
720
|
-
|
|
721
|
-
|
|
1111
|
+
const now = Date.now();
|
|
1112
|
+
if (now - lastSigintAt < SIGINT_EXIT_WINDOW_MS) {
|
|
1113
|
+
// Second Ctrl+C within the window: actually exit, matching the
|
|
1114
|
+
// near-universal CLI convention (bash, node REPL, Claude Code, Codex).
|
|
1115
|
+
interrupted = true;
|
|
1116
|
+
rl.close();
|
|
1117
|
+
return;
|
|
1118
|
+
}
|
|
1119
|
+
// First Ctrl+C: cancel the current line/prompt only, matching what the
|
|
1120
|
+
// footer already tells the user ("ctrl-c to cancel"). A single press
|
|
1121
|
+
// used to close the whole session outright -- that's the discrepancy
|
|
1122
|
+
// being fixed here, not the intended behavior.
|
|
1123
|
+
lastSigintAt = now;
|
|
1124
|
+
write('\n (Ctrl+C again within 2s to exit)\n');
|
|
1125
|
+
rl.line = '';
|
|
1126
|
+
rl.cursor = 0;
|
|
1127
|
+
if (rl.terminal) { rl.setPrompt(promptTextRef()); rl.prompt(); }
|
|
722
1128
|
});
|
|
723
1129
|
const promptText = () => {
|
|
724
1130
|
if (typeof options.prompt === 'function') return options.prompt(state);
|
|
725
1131
|
if (typeof options.prompt === 'string' && options.prompt) return options.prompt;
|
|
726
1132
|
return renderShellPrompt(state.cwd);
|
|
727
1133
|
};
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
recordSessionInput(state, line);
|
|
731
|
-
const result = await dispatchShellLine(line, state);
|
|
732
|
-
if (result.exit) { rl.close(); break; }
|
|
1134
|
+
promptTextRef = promptText;
|
|
1135
|
+
try {
|
|
733
1136
|
if (rl.terminal) { rl.setPrompt(promptText()); rl.prompt(); }
|
|
1137
|
+
for await (const line of rl) {
|
|
1138
|
+
recordSessionInput(state, line);
|
|
1139
|
+
const result = await dispatchShellLine(line, state);
|
|
1140
|
+
if (result.exit) { rl.close(); break; }
|
|
1141
|
+
if (process.stdin.isPaused()) {
|
|
1142
|
+
process.stdin.resume();
|
|
1143
|
+
}
|
|
1144
|
+
if (rl.terminal) { rl.setPrompt(promptText()); rl.prompt(); }
|
|
1145
|
+
}
|
|
1146
|
+
} finally {
|
|
1147
|
+
restorePaste();
|
|
1148
|
+
state.rl = null;
|
|
734
1149
|
}
|
|
735
1150
|
if (state.session) {
|
|
736
1151
|
const activeElapsedMs = localSessionElapsedMs(state.session);
|