@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/commands/shell.js
CHANGED
|
@@ -13,25 +13,33 @@ import { runModels } from './models.js';
|
|
|
13
13
|
import { runProviders } from './providers.js';
|
|
14
14
|
import { configureCliPreferences } from './preferences.js';
|
|
15
15
|
import { runCloudflare } from './cloudflare.js';
|
|
16
|
+
import { runConnections } from './connections.js';
|
|
17
|
+
import { runTunnel } from './tunnel.js';
|
|
16
18
|
import { probeOllamaModel, resolveOllamaConfig } from './ollama.js';
|
|
17
19
|
import { createInlineActivity } from '../ui/cli/activity.js';
|
|
18
20
|
import { createCliRuntimePresenter } from '../ui/cli/runtime-events.js';
|
|
19
|
-
import { renderCliFooter } from '../ui/cli/footer.js';
|
|
21
|
+
import { renderCliFooter, renderDiffPreview, renderUsagePanel } from '../ui/cli/footer.js';
|
|
20
22
|
import { diagnosticFromError, renderDiagnosticError } from '../errors/index.js';
|
|
21
|
-
import { getModelRecord } from '../models/index.js';
|
|
23
|
+
import { getModelRecord, mergeModelReference } from '../models/index.js';
|
|
22
24
|
import { discoverProviderModels } from '../models/discovery.js';
|
|
23
|
-
import { readCliPreferences, updateCliPreferences } from '../lib/cli-preferences.js';
|
|
25
|
+
import { detectCliProject, findCliProjectRoot, readCliPreferences, updateCliPreferences } from '../lib/cli-preferences.js';
|
|
24
26
|
import { buildContextEconomicsReport, renderContextEconomics } from './context-economics.js';
|
|
25
27
|
import { createProviderAdapter } from '../providers/index.js';
|
|
26
28
|
import { createCapabilityAdapter, runResponsesAgent } from '../agent/index.js';
|
|
27
29
|
import { resolveProviderCredential } from '../lib/provider-credentials.js';
|
|
28
|
-
import { createLocalSession, saveLocalSession,
|
|
30
|
+
import { createLocalSession, saveLocalSession, localSessionElapsedMs, loadSessionContinuation } from '../lib/local-sessions.js';
|
|
31
|
+
import { runtimeDatabasePath } from '../local/runtime-store.js';
|
|
29
32
|
import { grantExecutionApproval, isExecutionApproved, toolApprovalKey } from '../lib/execution-approvals.js';
|
|
30
33
|
import { runWhoami } from './whoami.js';
|
|
31
34
|
import { runLogin, runLogout } from './account-auth.js';
|
|
32
35
|
import { runHelp } from '../ui/cli/help.js';
|
|
36
|
+
import { hydrateSecureCredentials } from '../security/local-vault.js';
|
|
33
37
|
import { readAccountSession } from '../lib/account-session.js';
|
|
34
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';
|
|
35
43
|
|
|
36
44
|
function writeLine(write, value = '') { write(`${value}\n`); }
|
|
37
45
|
|
|
@@ -54,6 +62,134 @@ export function renderShellPrompt(cwd, env = process.env) {
|
|
|
54
62
|
return `${shellUsername(env)} ${compactCwd(cwd, env.HOME || env.USERPROFILE || '')} > `;
|
|
55
63
|
}
|
|
56
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
|
+
|
|
57
193
|
export function tokenizeShellLine(input = '') {
|
|
58
194
|
const source = String(input);
|
|
59
195
|
const tokens = [];
|
|
@@ -121,9 +257,12 @@ function spawnGit(cwd, args) {
|
|
|
121
257
|
function selectedModel(cwd) {
|
|
122
258
|
const preferences = readCliPreferences(cwd) || {};
|
|
123
259
|
const snapshot = preferences.modelSnapshot?.model_key === preferences.modelPreference
|
|
124
|
-
? preferences.modelSnapshot
|
|
260
|
+
? mergeModelReference(preferences.modelSnapshot)
|
|
125
261
|
: null;
|
|
126
|
-
|
|
262
|
+
let model = snapshot || getModelRecord(preferences.modelPreference);
|
|
263
|
+
if (!model && (preferences.modelPreference === 'auto' || !preferences.modelPreference)) {
|
|
264
|
+
model = mergeModelReference(preferences.modelSnapshot) || listModelCatalog()[0];
|
|
265
|
+
}
|
|
127
266
|
if (!model) throw new Error('Select an exact provider-verified model with /model first so Agent Sam can verify supported runtime controls.');
|
|
128
267
|
return { preferences, model };
|
|
129
268
|
}
|
|
@@ -169,24 +308,32 @@ async function resolveModelForTurn(cwd, state) {
|
|
|
169
308
|
|
|
170
309
|
async function chooseReasoning(cwd, args, state) {
|
|
171
310
|
const { preferences, model } = selectedModel(cwd);
|
|
311
|
+
const supported = ['auto', ...model.reasoning_efforts.filter((value) => value !== 'auto')];
|
|
172
312
|
let effort = String(args[0] || '').trim().toLowerCase();
|
|
173
313
|
if (!effort) {
|
|
174
314
|
if (!state.interactive) {
|
|
175
|
-
writeLine(state.write,
|
|
176
|
-
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'));
|
|
177
318
|
return;
|
|
178
319
|
}
|
|
179
320
|
const choice = await select({
|
|
180
|
-
message:
|
|
181
|
-
initialValue:
|
|
182
|
-
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
|
+
})),
|
|
183
330
|
});
|
|
184
331
|
if (isCancel(choice)) return;
|
|
185
332
|
effort = choice;
|
|
186
333
|
}
|
|
187
|
-
if (!
|
|
334
|
+
if (!supported.includes(effort)) throw new Error('unsupported reasoning level for ' + model.provider_model_id + ': ' + effort);
|
|
188
335
|
updateCliPreferences(cwd, { reasoningEffort: effort });
|
|
189
|
-
writeLine(state.write,
|
|
336
|
+
writeLine(state.write, ' reasoning → ' + effort);
|
|
190
337
|
}
|
|
191
338
|
|
|
192
339
|
function setServiceTier(cwd, tier, write) {
|
|
@@ -241,15 +388,15 @@ export async function runLocalAgent(goal, write, options = {}) {
|
|
|
241
388
|
}
|
|
242
389
|
|
|
243
390
|
async function showLocalLogs(cwd, write) {
|
|
244
|
-
const dbPath =
|
|
245
|
-
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; }
|
|
246
393
|
const { createLocalSqliteDatabase } = await import('../local/sqlite.js');
|
|
247
394
|
const db = await createLocalSqliteDatabase(dbPath);
|
|
248
395
|
try {
|
|
249
|
-
const
|
|
250
|
-
if (!
|
|
251
|
-
writeLine(write, '\n Recent Agent Sam
|
|
252
|
-
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}`);
|
|
253
400
|
writeLine(write, '');
|
|
254
401
|
} finally { db.close(); }
|
|
255
402
|
}
|
|
@@ -300,6 +447,7 @@ export function renderSessionReceipt(session) {
|
|
|
300
447
|
if (componentTotal > 0) {
|
|
301
448
|
lines.push(`Cost breakdown: input ${formatUsd(breakdown.input)} · cached ${formatUsd(breakdown.cached_input)} · cache write ${formatUsd(breakdown.cache_write)} · output ${formatUsd(breakdown.output)}`);
|
|
302
449
|
}
|
|
450
|
+
if (session.latest_compaction) lines.push(`Latest compaction: ${session.latest_compaction.compaction_id || 'completed'} · ${formatUsd(session.latest_compaction.cost_usd)}`);
|
|
303
451
|
if (active) lines.push(`Active context: ${formatCount(active)} tokens`);
|
|
304
452
|
lines.push('', 'To continue this session, run:', ` agentsam resume ${session.id}`, '', 'Or run:', ' agentsam resume', '', 'and select:', ` ${session.title || 'this session'}`, '');
|
|
305
453
|
return lines.join('\n');
|
|
@@ -307,7 +455,7 @@ export function renderSessionReceipt(session) {
|
|
|
307
455
|
|
|
308
456
|
function persistSession(state, patch = {}) {
|
|
309
457
|
if (!state.session) return null;
|
|
310
|
-
state.session = saveLocalSession({ ...state.session, ...patch }, { home: state.home });
|
|
458
|
+
state.session = saveLocalSession({ ...state.session, ...patch }, { home: state.home, projectRoot: state.projectRoot });
|
|
311
459
|
return state.session;
|
|
312
460
|
}
|
|
313
461
|
|
|
@@ -318,8 +466,6 @@ function recordSessionInput(state, input) {
|
|
|
318
466
|
if (housekeeping.has(value.toLowerCase())) return;
|
|
319
467
|
persistSession(state, {
|
|
320
468
|
status: 'active',
|
|
321
|
-
last_input: value,
|
|
322
|
-
title: sessionTitleFromInput(value),
|
|
323
469
|
});
|
|
324
470
|
}
|
|
325
471
|
|
|
@@ -392,6 +538,55 @@ async function approveToolExecution(request, state) {
|
|
|
392
538
|
return true;
|
|
393
539
|
}
|
|
394
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
|
+
|
|
395
590
|
async function runInteractiveModelTurn(prompt, state) {
|
|
396
591
|
const resolved = await resolveModelForTurn(state.cwd, state);
|
|
397
592
|
const { preferences, model, credential } = resolved;
|
|
@@ -403,17 +598,15 @@ async function runInteractiveModelTurn(prompt, state) {
|
|
|
403
598
|
});
|
|
404
599
|
const capabilityAdapter = createCapabilityAdapter();
|
|
405
600
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
&& state.session.requested_service_tier === preferences.serviceTier;
|
|
410
|
-
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;
|
|
411
604
|
const previousUsageSnapshot = samePolicy ? state.session?.usage_snapshot : null;
|
|
412
605
|
const accountId = readAccountSession({ home: state.home })?.account_id || null;
|
|
413
606
|
let runtimeRunId = null;
|
|
414
607
|
try {
|
|
415
608
|
runtimeRunId = await startRuntimeRun({
|
|
416
|
-
|
|
609
|
+
projectRoot: state.projectRoot,
|
|
417
610
|
account_id: accountId,
|
|
418
611
|
mode: 'agent',
|
|
419
612
|
model_key: model.model_key,
|
|
@@ -431,6 +624,8 @@ async function runInteractiveModelTurn(prompt, state) {
|
|
|
431
624
|
});
|
|
432
625
|
state.activity = activity;
|
|
433
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 };
|
|
434
629
|
const startedAt = Date.now();
|
|
435
630
|
activity.start(`Thinking · ${model.provider_model_id}`);
|
|
436
631
|
|
|
@@ -445,9 +640,17 @@ async function runInteractiveModelTurn(prompt, state) {
|
|
|
445
640
|
modelRecord: model,
|
|
446
641
|
reasoningEffort: preferences.reasoningEffort,
|
|
447
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',
|
|
448
649
|
previousProviderState,
|
|
449
650
|
previousUsageSnapshot,
|
|
450
651
|
cumulativeUsage: state.session?.cumulative_usage || null,
|
|
652
|
+
autoCompact: state.session?.auto_compact !== false,
|
|
653
|
+
onCompaction: result => { if (state.session) checkpointCompaction(state, model, result); },
|
|
451
654
|
promptCacheKey: state.session?.id || undefined,
|
|
452
655
|
runId: runtimeRunId || state.session?.id || undefined,
|
|
453
656
|
beforeRequest: (preflight) => approveModelRequest(preflight, state),
|
|
@@ -463,7 +666,7 @@ async function runInteractiveModelTurn(prompt, state) {
|
|
|
463
666
|
if (runtimeRunId) {
|
|
464
667
|
try {
|
|
465
668
|
await finishRuntimeRun({
|
|
466
|
-
|
|
669
|
+
projectRoot: state.projectRoot,
|
|
467
670
|
id: runtimeRunId,
|
|
468
671
|
status: 'failed',
|
|
469
672
|
error_code: error?.code || 'interactive_error',
|
|
@@ -488,10 +691,12 @@ async function runInteractiveModelTurn(prompt, state) {
|
|
|
488
691
|
}
|
|
489
692
|
|
|
490
693
|
state.usageSnapshot = result.usage_snapshot;
|
|
694
|
+
state.providerState = result.provider_state || null;
|
|
695
|
+
state.lastTurnElapsedMs = Date.now() - startedAt;
|
|
491
696
|
if (runtimeRunId) {
|
|
492
697
|
try {
|
|
493
698
|
await finishRuntimeRun({
|
|
494
|
-
|
|
699
|
+
projectRoot: state.projectRoot,
|
|
495
700
|
id: runtimeRunId,
|
|
496
701
|
status: 'completed',
|
|
497
702
|
actual_service_tier: result.actual_service_tier,
|
|
@@ -501,7 +706,7 @@ async function runInteractiveModelTurn(prompt, state) {
|
|
|
501
706
|
});
|
|
502
707
|
if (presenter.state.lastCompaction) {
|
|
503
708
|
await recordRuntimeCompaction({
|
|
504
|
-
|
|
709
|
+
projectRoot: state.projectRoot,
|
|
505
710
|
account_id: accountId,
|
|
506
711
|
agent_run_id: runtimeRunId,
|
|
507
712
|
session_id: state.session?.id,
|
|
@@ -527,30 +732,66 @@ async function runInteractiveModelTurn(prompt, state) {
|
|
|
527
732
|
provider_state: { provider: model.provider, ...(result.provider_state || {}) },
|
|
528
733
|
usage_snapshot: result.usage_snapshot,
|
|
529
734
|
cumulative_usage: result.cumulative_usage,
|
|
530
|
-
|
|
735
|
+
latest_compaction: result.compaction || state.session.latest_compaction,
|
|
736
|
+
total_cost_usd: startingCostUsd + Number(result.total_cost_usd || 0),
|
|
531
737
|
cost_breakdown_usd: Object.fromEntries(['input', 'cached_input', 'cache_write', 'output'].map((key) => [
|
|
532
|
-
key, Number(
|
|
738
|
+
key, Number(startingCostBreakdown[key] || 0) + Number(result.cost_breakdown_usd?.[key] || 0),
|
|
533
739
|
])),
|
|
534
740
|
last_error: null,
|
|
535
741
|
});
|
|
536
742
|
}
|
|
537
743
|
|
|
744
|
+
const identity = resolveShellIdentity(state);
|
|
538
745
|
writeLine(state.write, renderCliFooter({
|
|
746
|
+
projectName: identity.project,
|
|
747
|
+
branch: identity.branch,
|
|
748
|
+
cwd: compactCwd(state.cwd),
|
|
539
749
|
model: result.model || model.provider_model_id,
|
|
750
|
+
provider: model.provider,
|
|
751
|
+
effort: result.reasoning_effort,
|
|
540
752
|
usageSnapshot: result.usage_snapshot,
|
|
541
753
|
tier: result.actual_service_tier,
|
|
542
|
-
elapsedMs:
|
|
754
|
+
elapsedMs: state.lastTurnElapsedMs,
|
|
543
755
|
}));
|
|
544
756
|
writeLine(state.write, '');
|
|
757
|
+
state.wroteTurnFooter = true;
|
|
545
758
|
return result;
|
|
546
759
|
}
|
|
547
760
|
|
|
548
761
|
export async function dispatchShellLine(line, state = {}) {
|
|
549
|
-
|
|
762
|
+
let tokens = tokenizeShellLine(line);
|
|
550
763
|
const write = state.write || ((text) => process.stdout.write(text));
|
|
551
764
|
state.write = write;
|
|
552
765
|
state.cwd = path.resolve(state.cwd || process.cwd());
|
|
766
|
+
state.projectRoot ||= findCliProjectRoot(state.cwd);
|
|
553
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
|
+
|
|
554
795
|
const [command, ...args] = tokens;
|
|
555
796
|
try {
|
|
556
797
|
switch (command.toLowerCase()) {
|
|
@@ -565,8 +806,15 @@ export async function dispatchShellLine(line, state = {}) {
|
|
|
565
806
|
case '/quit':
|
|
566
807
|
return { handled: true, exit: true, cwd: state.cwd };
|
|
567
808
|
case '/model': {
|
|
568
|
-
|
|
569
|
-
|
|
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
|
+
}
|
|
570
818
|
break;
|
|
571
819
|
}
|
|
572
820
|
case '/reasoning':
|
|
@@ -581,21 +829,37 @@ export async function dispatchShellLine(line, state = {}) {
|
|
|
581
829
|
case '/standard':
|
|
582
830
|
setServiceTier(state.cwd, 'default', write);
|
|
583
831
|
break;
|
|
832
|
+
case '/compact':
|
|
833
|
+
await runInteractiveCompaction(args, state);
|
|
834
|
+
break;
|
|
584
835
|
case '/context':
|
|
585
836
|
if (args[0] === 'repo' || args[0] === 'git') await runContext(['--cwd', state.cwd, ...args.slice(1)]);
|
|
586
837
|
else write(renderContextEconomics(buildContextEconomicsReport(state.cwd, {
|
|
587
838
|
activeInputTokens: state.usageSnapshot?.current_context?.input_tokens,
|
|
588
839
|
estimateKind: state.usageSnapshot?.estimate_kind,
|
|
840
|
+
autoCompact: state.session?.auto_compact,
|
|
589
841
|
})));
|
|
590
842
|
break;
|
|
591
843
|
case '/status':
|
|
592
844
|
await runStatus(args, { cwd: state.cwd });
|
|
593
845
|
break;
|
|
594
846
|
case '/models':
|
|
595
|
-
|
|
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
|
+
}
|
|
596
854
|
break;
|
|
597
855
|
case '/providers':
|
|
598
|
-
|
|
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
|
+
}
|
|
599
863
|
break;
|
|
600
864
|
case '/login':
|
|
601
865
|
await runLogin(args, { write, home: state.home });
|
|
@@ -608,17 +872,43 @@ export async function dispatchShellLine(line, state = {}) {
|
|
|
608
872
|
await runWhoami(args, { write, home: state.home });
|
|
609
873
|
break;
|
|
610
874
|
case '/session':
|
|
611
|
-
case '/usage':
|
|
612
875
|
if (state.session) write(renderSessionReceipt(state.session));
|
|
613
876
|
else writeLine(write, ' No persistent session is active in this shell invocation.');
|
|
614
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;
|
|
615
891
|
case '/cf':
|
|
616
892
|
case '/cloudflare':
|
|
617
893
|
await runCloudflare(args.length ? args : ['commands'], { cwd: state.cwd, write });
|
|
618
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;
|
|
619
902
|
case '/settings': {
|
|
620
|
-
|
|
621
|
-
|
|
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
|
+
}
|
|
622
912
|
break;
|
|
623
913
|
}
|
|
624
914
|
case '/pwd':
|
|
@@ -628,22 +918,100 @@ export async function dispatchShellLine(line, state = {}) {
|
|
|
628
918
|
const destination = args.length ? args.join(' ') : process.env.HOME || process.env.USERPROFILE || state.cwd;
|
|
629
919
|
const next = path.resolve(state.cwd, destination);
|
|
630
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
|
+
}
|
|
631
931
|
state.cwd = next;
|
|
932
|
+
state.identity = null;
|
|
933
|
+
state.identityCwd = null;
|
|
632
934
|
writeLine(write, state.cwd);
|
|
633
935
|
break;
|
|
634
936
|
}
|
|
635
937
|
case '/git':
|
|
636
938
|
spawnGit(state.cwd, args.length ? args : ['status', '--short', '--branch']);
|
|
637
939
|
break;
|
|
638
|
-
case '/diff':
|
|
639
|
-
|
|
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 || ''));
|
|
640
947
|
break;
|
|
948
|
+
}
|
|
641
949
|
case '/db':
|
|
642
|
-
await runDb(args.length ? args : ['status'], { cwd: state.cwd });
|
|
950
|
+
await runDb(args.length ? args : ['status'], { cwd: state.projectRoot || state.cwd, write });
|
|
643
951
|
break;
|
|
644
952
|
case '/agent':
|
|
645
953
|
await runLocalAgent(args.join(' '), write, { interactive: state.interactive });
|
|
646
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
|
+
}
|
|
647
1015
|
case '/logs':
|
|
648
1016
|
await showLocalLogs(state.cwd, write);
|
|
649
1017
|
break;
|
|
@@ -667,9 +1035,15 @@ export async function dispatchShellLine(line, state = {}) {
|
|
|
667
1035
|
persistSession(state, { last_error: diagnosticFromError(error, { source: 'shell', kind: 'interactive_error' }) });
|
|
668
1036
|
}
|
|
669
1037
|
if (!error?.reported) {
|
|
670
|
-
for (const
|
|
1038
|
+
for (const errorLine of renderDiagnosticError(error).split('\n')) writeLine(write, ` ${errorLine}`);
|
|
671
1039
|
}
|
|
672
1040
|
}
|
|
1041
|
+
const skipFooter = state.wroteTurnFooter;
|
|
1042
|
+
state.wroteTurnFooter = false;
|
|
1043
|
+
if (state.persistFooter && !skipFooter) {
|
|
1044
|
+
writeLine(write, renderShellSessionFooter(state));
|
|
1045
|
+
writeLine(write, '');
|
|
1046
|
+
}
|
|
673
1047
|
return { handled: true, exit: false, cwd: state.cwd };
|
|
674
1048
|
}
|
|
675
1049
|
|
|
@@ -677,14 +1051,18 @@ export async function runShell(argv = [], options = {}) {
|
|
|
677
1051
|
const write = options.write || ((text) => process.stdout.write(text));
|
|
678
1052
|
const state = {
|
|
679
1053
|
cwd: path.resolve(options.cwd || process.cwd()),
|
|
1054
|
+
projectRoot: findCliProjectRoot(options.session?.project_root || options.cwd || process.cwd()),
|
|
680
1055
|
write,
|
|
681
1056
|
interactive: options.interactive ?? Boolean(process.stdin.isTTY && process.stdout.isTTY),
|
|
682
1057
|
usageSnapshot: options.usageSnapshot || options.session?.usage_snapshot || null,
|
|
1058
|
+
providerState: null,
|
|
683
1059
|
session: options.session || null,
|
|
684
1060
|
home: options.home,
|
|
685
1061
|
providerFetchImpl: options.providerFetchImpl,
|
|
1062
|
+
persistFooter: options.persistFooter === true,
|
|
686
1063
|
};
|
|
687
1064
|
const sub = argv[0] || '';
|
|
1065
|
+
hydrateSecureCredentials(process.env, { home: state.home });
|
|
688
1066
|
if (sub === 'list' || sub === 'status') { write(renderShellCatalog()); return; }
|
|
689
1067
|
if (sub === '--command' || sub === '--once') {
|
|
690
1068
|
const line = argv.slice(1).join(' ');
|
|
@@ -701,40 +1079,73 @@ export async function runShell(argv = [], options = {}) {
|
|
|
701
1079
|
status: 'active',
|
|
702
1080
|
cwd: state.cwd,
|
|
703
1081
|
active_started_at: new Date().toISOString(),
|
|
704
|
-
}, { home: state.home });
|
|
1082
|
+
}, { home: state.home, projectRoot: state.projectRoot });
|
|
705
1083
|
state.usageSnapshot = state.session.usage_snapshot || state.usageSnapshot;
|
|
706
1084
|
} else {
|
|
707
1085
|
const preferences = readCliPreferences(state.cwd) || {};
|
|
708
1086
|
state.session = createLocalSession({
|
|
709
1087
|
cwd: state.cwd,
|
|
1088
|
+
project_root: state.projectRoot,
|
|
710
1089
|
status: 'active',
|
|
711
1090
|
model_key: preferences.modelPreference !== 'auto' ? preferences.modelPreference : null,
|
|
712
1091
|
reasoning_effort: preferences.reasoningEffort !== 'auto' ? preferences.reasoningEffort : null,
|
|
713
1092
|
requested_service_tier: preferences.serviceTier || 'default',
|
|
714
|
-
}, { home: state.home });
|
|
1093
|
+
}, { home: state.home, projectRoot: state.projectRoot });
|
|
715
1094
|
}
|
|
716
1095
|
|
|
717
1096
|
if (options.intro !== 'quiet') {
|
|
718
1097
|
write(renderShellCatalog());
|
|
719
1098
|
writeLine(write, ' Interactive shell ready. Type / for the command picker; /exit to return to your host shell.\n');
|
|
720
1099
|
}
|
|
1100
|
+
state.persistFooter = options.persistFooter !== false;
|
|
1101
|
+
writeLine(write, renderShellSessionFooter(state));
|
|
1102
|
+
writeLine(write, '');
|
|
721
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 });
|
|
722
1107
|
let interrupted = false;
|
|
1108
|
+
let lastSigintAt = 0;
|
|
1109
|
+
const SIGINT_EXIT_WINDOW_MS = 2000;
|
|
723
1110
|
rl.on('SIGINT', () => {
|
|
724
|
-
|
|
725
|
-
|
|
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(); }
|
|
726
1128
|
});
|
|
727
1129
|
const promptText = () => {
|
|
728
1130
|
if (typeof options.prompt === 'function') return options.prompt(state);
|
|
729
1131
|
if (typeof options.prompt === 'string' && options.prompt) return options.prompt;
|
|
730
1132
|
return renderShellPrompt(state.cwd);
|
|
731
1133
|
};
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
recordSessionInput(state, line);
|
|
735
|
-
const result = await dispatchShellLine(line, state);
|
|
736
|
-
if (result.exit) { rl.close(); break; }
|
|
1134
|
+
promptTextRef = promptText;
|
|
1135
|
+
try {
|
|
737
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;
|
|
738
1149
|
}
|
|
739
1150
|
if (state.session) {
|
|
740
1151
|
const activeElapsedMs = localSessionElapsedMs(state.session);
|