@inneranimalmedia/agentsam-sdk 2.6.5 → 2.6.8
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 +29 -0
- package/README.md +37 -0
- package/apps/README.md +5 -0
- package/apps/cad-creator/README.md +4 -4
- package/apps/cad-creator/shared/cad/package.json +1 -1
- package/apps/client-cms-editor/AGENTS.md +12 -7
- package/apps/client-cms-editor/README.md +76 -48
- package/apps/client-cms-editor/agentsam.app.json +26 -9
- package/apps/client-cms-editor/backend/package.json +20 -3
- package/apps/client-cms-editor/backend/src/api/client.ts +134 -101
- package/apps/client-cms-editor/backend/src/index.ts +1 -1
- package/apps/client-cms-editor/backend/src/model.ts +11 -115
- package/apps/client-cms-editor/backend/src/preview/bridge.ts +1 -1
- package/apps/client-cms-editor/backend/tsconfig.json +6 -1
- package/apps/client-cms-editor/bin/agentsam-cms.js +262 -0
- package/apps/client-cms-editor/bin/agentsam-cms.mjs +2 -228
- package/apps/client-cms-editor/frontend/package.json +16 -7
- package/apps/client-cms-editor/frontend/src/AgentSamDrawer.tsx +9 -41
- package/apps/client-cms-editor/frontend/src/CmsAgentSurface.tsx +19 -174
- package/apps/client-cms-editor/frontend/src/adapters/heuristic.ts +29 -0
- package/apps/client-cms-editor/frontend/src/adapters/http.ts +628 -0
- package/apps/client-cms-editor/frontend/src/adapters/memory.ts +510 -0
- package/apps/client-cms-editor/frontend/src/editor/CmsEditor.tsx +213 -0
- package/apps/client-cms-editor/frontend/src/editor/CmsEditorProvider.tsx +20 -0
- package/apps/client-cms-editor/frontend/src/editor/canvas/PreviewCanvas.tsx +53 -0
- package/apps/client-cms-editor/frontend/src/{CmsEditor.tsx → editor/legacy/CmsEditorPrototype.tsx} +52 -23
- package/apps/client-cms-editor/frontend/src/editor/useCmsEditorController.ts +218 -0
- package/apps/client-cms-editor/frontend/src/index.ts +19 -5
- package/apps/client-cms-editor/frontend/src/lib/agent-host.ts +24 -0
- package/apps/client-cms-editor/frontend/src/main.tsx +82 -8
- package/apps/client-cms-editor/frontend/src/mount.tsx +92 -30
- package/apps/client-cms-editor/frontend/src/styles/agentsam-drawer.css +1 -1
- package/apps/client-cms-editor/frontend/src/styles/cmsShell.css +8 -8
- package/apps/client-cms-editor/frontend/src/styles/studio.css +55 -3
- package/apps/client-cms-editor/frontend/tsconfig.json +12 -1
- package/apps/client-cms-editor/frontend/vite.config.ts +12 -0
- package/apps/client-cms-editor/package-lock.json +973 -134
- package/apps/client-cms-editor/package.json +118 -6
- package/apps/client-cms-editor/reference/harvest/HARVEST_RECEIPT.json +201 -0
- package/apps/client-cms-editor/reference/harvest/PROVENANCE_HISTORY.txt +10 -0
- package/apps/client-cms-editor/reference/harvest/README.md +8 -0
- package/apps/client-cms-editor/reference/harvest/plans/ARCHIVE-INTAKE.md +135 -0
- package/apps/client-cms-editor/reference/harvest/plans/CHATGPT-IDENTITY-HARVEST.md +83 -0
- package/apps/client-cms-editor/reference/harvest/plans/CMS-EDITOR-HARVEST.md +166 -0
- package/apps/client-cms-editor/reference/harvest/plans/HARVEST-INDEX.md +196 -0
- package/apps/client-cms-editor/reference/harvest/plans/INNERANIMALS-CONTENT-001.md +137 -0
- package/apps/client-cms-editor/reference/harvest/plans/NO-IMPLICIT-SIDE-EFFECTS.md +87 -0
- package/apps/client-cms-editor/reference/harvest/plans/STOREFRONT-SURFACE-MAP.md +140 -0
- package/apps/client-cms-editor/reference/harvest/plans/THEME-INNERANIMALS-HARVEST.md +137 -0
- package/apps/client-cms-editor/reference/harvest/plans/TOOLING-LAB.md +63 -0
- package/apps/client-cms-editor/reference/harvest/plans/harvest-manifest.json +97 -0
- package/apps/client-cms-editor/reference/harvest/plans/local-cms-harvest-schema.sql +328 -0
- package/apps/client-cms-editor/shared/cms/package.json +17 -7
- package/apps/client-cms-editor/shared/cms/src/adapter.ts +204 -0
- package/apps/client-cms-editor/shared/cms/src/agent-context.ts +7 -5
- package/apps/client-cms-editor/shared/cms/src/editor-types.ts +32 -0
- package/apps/client-cms-editor/shared/cms/src/host.ts +82 -0
- package/apps/client-cms-editor/shared/cms/src/index.ts +4 -0
- package/apps/client-cms-editor/shared/cms/src/map.ts +115 -0
- package/apps/client-cms-editor/shared/cms/src/starter-pack.ts +158 -0
- package/contracts/source-types.v1.json +353 -0
- package/docs/CMS_CONTEXTUAL_COMPOSER.md +1 -1
- package/docs/PRODUCT_LIFECYCLE.md +566 -0
- package/docs/REPO_FILE_MAP.txt +132 -0
- package/docs/THEME_REFINERY.md +2 -2
- package/docs/architecture/AGENTSAM_RUNTIME_PROTOCOL.md +40 -20
- package/docs/content-studio/REVISION_GATE_2026-09-27.md +1 -1
- package/docs/plans/LOCAL_STUDIO_DESKTOP_RELEASE_2026-09-29.md +150 -0
- package/migrations/d1/0017_identity_native_oauth.sql +21 -0
- package/migrations/d1/0018_goap_control_plane_remaster.sql +40 -0
- package/migrations/d1/0019_agentsam_agent_run_plan_todo.sql +14 -0
- package/migrations/d1/README_PORTABLE_CONTROL_PLANE.md +20 -9
- package/migrations/runtime/0002_goap_blackboard_v1.sql +15 -0
- package/migrations/runtime/0004_agent_run_plan_linkage.sql +8 -0
- package/native/agentsam-machine/Cargo.lock +426 -0
- package/native/agentsam-machine/Cargo.toml +9 -0
- package/native/agentsam-machine/cli/Cargo.toml +21 -0
- package/native/agentsam-machine/cli/README.md +21 -0
- package/native/agentsam-machine/cli/src/main.rs +77 -0
- package/native/agentsam-machine/core/Cargo.toml +22 -0
- package/native/agentsam-machine/core/README.md +14 -0
- package/native/agentsam-machine/core/build.rs +33 -0
- package/native/agentsam-machine/core/contracts/source-types.v1.json +353 -0
- package/native/agentsam-machine/core/src/assets.rs +790 -0
- package/native/agentsam-machine/core/src/bound.rs +298 -0
- package/native/agentsam-machine/core/src/enrich.rs +706 -0
- package/native/agentsam-machine/core/src/frontend.rs +442 -0
- package/native/agentsam-machine/core/src/lib.rs +1092 -0
- package/native/agentsam-machine/core/src/liquid.rs +528 -0
- package/native/agentsam-machine/core/src/source_types.rs +78 -0
- package/package.json +64 -24
- package/packages/agentsam-brand/README.md +1 -1
- package/packages/agentsam-brand/package.json +4 -4
- package/packages/agentsam-brand/src/index.js +1 -1
- package/packages/agentsam-contracts/package.json +13 -3
- package/packages/agentsam-contracts/src/tools.ts +22 -0
- package/packages/agentsam-errors/package.json +13 -3
- package/packages/agentsam-errors/src/index.js +1 -0
- package/packages/agentsam-errors/src/tool.js +56 -0
- package/packages/agentsam-errors/test/tool.test.mjs +58 -0
- package/packages/agentsam-goap/README.md +52 -0
- package/packages/agentsam-goap/package.json +37 -0
- package/packages/agentsam-goap/src/adapters/d1-sqlite.js +570 -0
- package/packages/agentsam-goap/src/adapters/memory.js +199 -0
- package/packages/agentsam-goap/src/contracts.js +226 -0
- package/packages/agentsam-goap/src/control-plane.js +112 -0
- package/packages/agentsam-goap/src/errors.js +157 -0
- package/packages/agentsam-goap/src/index.js +5 -0
- package/packages/agentsam-goap/src/world.js +202 -0
- package/packages/agentsam-goap/test/goap-control-plane.test.mjs +245 -0
- package/packages/agentsam-goap/test/world.test.mjs +79 -0
- package/packages/agentsam-knowledge/package.json +18 -4
- package/packages/agentsam-knowledge/src/autorag/index.js +10 -3
- package/packages/agentsam-knowledge/src/backends/index.js +33 -1
- package/packages/agentsam-knowledge/test/autorag.test.mjs +60 -1
- package/packages/agentsam-nav/dist/browser.global.js +21 -18
- package/packages/agentsam-nav/dist/browser.js +6807 -130
- package/packages/agentsam-nav/dist/index.js +6799 -122
- package/packages/agentsam-nav/package.json +24 -6
- package/packages/agentsam-queue-control/README.md +1 -1
- package/packages/agentsam-queue-control/package.json +7 -2
- package/packages/agentsam-rapid-rust/src/main.rs +1 -1
- package/packages/agentsam-repository/package.json +13 -3
- package/packages/agentsam-repository/src/goap.js +13 -14
- package/packages/agentsam-repository/src/source-types.js +8 -0
- package/packages/agentsam-repository/src/tickets.js +15 -22
- package/packages/agentsam-repository/test/goap-tickets-workspace-state.test.mjs +19 -8
- package/packages/agentsam-vault/package.json +14 -4
- package/packages/agentsam-workbench/package.json +15 -4
- package/packages/agentsam-workbench/src/agent/ToolPermissionRequest.tsx +94 -0
- package/packages/agentsam-workbench/src/agent/index.ts +2 -0
- package/packages/agentsam-workbench/src/agent/tool-permission.css +134 -0
- package/packages/connectors/cloudflare/package.json +15 -3
- package/packages/connectors/cloudflare/src/api-client.js +3 -2
- package/packages/connectors/cloudflare/src/families/vectorize.js +127 -0
- package/packages/connectors/cloudflare/src/index.js +1 -0
- package/packages/heuristic-theme/README.md +2 -2
- package/packages/heuristic-theme/package.json +8 -3
- package/packages/heuristic-theme/src/registry.js +2 -2
- package/packages/heuristic-theme/src/theme.js +1 -1
- package/packages/heuristic-theme/test/theme.test.mjs +1 -1
- package/packages/identity/.agentsam/features/oauth-login-portal/agentsam.feature.json +1 -1
- package/packages/identity/.agentsam/features/oauth-login-portal/providers.json +27 -7
- package/packages/identity/README.md +2 -2
- package/packages/identity/migrations/D1_SCHEMA_MAPPING.md +18 -15
- package/packages/identity/migrations/apply-portable.js +109 -0
- package/packages/identity/migrations/sqlite/004_identity_oauth_consent_catalog.sql +1 -1
- package/packages/identity/migrations/sqlite/005_identity_company_native.sql +52 -0
- package/packages/identity/package.json +27 -6
- package/packages/identity/schema/agentsam.identity/manifest.json +101 -0
- package/packages/identity/scripts/local-identity-bridge.mjs +13 -7
- package/packages/identity/scripts/preview-auth-portal.mjs +6 -6
- package/packages/identity/src/adapters/cloudflare-d1/index.js +8 -401
- package/packages/identity/src/adapters/iam-compat/index.js +540 -0
- package/packages/identity/src/adapters/portable-d1/index.js +18 -0
- package/packages/identity/src/adapters/portable-store.js +479 -0
- package/packages/identity/src/adapters/sqlite/index.js +13 -312
- package/packages/identity/src/contracts/auth-config.js +0 -1
- package/packages/identity/src/contracts/identity-store.js +56 -5
- package/packages/identity/src/contracts/provider.js +1 -0
- package/packages/identity/src/contracts/sign-in-options.js +104 -0
- package/packages/identity/src/core/constants.js +1 -1
- package/packages/identity/src/core/session-policy.js +31 -0
- package/packages/identity/src/frontend/auth-portal/pages/login.html +6 -6
- package/packages/identity/src/frontend/auth-portal/pages/reset.html +5 -5
- package/packages/identity/src/frontend/auth-portal/pages/signup.html +5 -5
- package/packages/identity/src/frontend/auth-portal/shared/company-branding.js +1 -1
- package/packages/identity/src/frontend/auth-portal/shared/desktop-identity-bridge.js +6 -37
- package/packages/identity/src/index.js +28 -1
- package/packages/identity/src/migrations/README.md +23 -23
- package/packages/identity/src/oauth/README.md +1 -1
- package/packages/identity/src/oauth/credentials.js +10 -11
- package/packages/identity/src/oauth/google-desktop-exchange.js +195 -27
- package/packages/identity/src/oauth/iam-platform.js +21 -9
- package/packages/identity/src/oauth/native-handoff.js +136 -0
- package/packages/identity/src/providers/chatgpt/headers.js +65 -0
- package/packages/identity/src/providers/chatgpt/index.js +86 -0
- package/packages/identity/src/providers/chatgpt/mapper.js +43 -0
- package/packages/identity/src/providers/chatgpt/paths.js +45 -0
- package/packages/identity/src/providers/github/oauth.js +1 -2
- package/packages/identity/src/providers/github/profile.js +16 -2
- package/packages/identity/src/providers/index.js +11 -3
- package/packages/identity/src/server/identity-service.js +2 -1
- package/packages/identity/src/server/worker-router.js +71 -18
- package/packages/identity/tests/chatgpt-provider.test.mjs +75 -0
- package/packages/identity/tests/google-desktop-identity-login.test.mjs +210 -0
- package/packages/identity/tests/identity-init-scaffold.test.mjs +15 -4
- package/packages/identity/tests/lane1-identity-store-parity.test.mjs +527 -0
- package/packages/identity/tests/lane1-packed-consumer.test.mjs +175 -0
- package/packages/identity/tests/native-oauth-handoff.test.mjs +292 -0
- package/packages/identity/tests/oauth-credentials.test.mjs +4 -4
- package/packages/identity/tests/preview-auth-portal.test.mjs +4 -2
- package/packages/identity/tests/session-routes-policy.test.mjs +13 -1
- package/packages/identity/tests/worker-runtime-boundary.test.mjs +11 -0
- package/packages/providers/completeful/package.json +7 -2
- package/packages/theme-church-site/package.json +17 -6
- package/packages/theme-church-site/src/harvest.json +4 -2
- package/packages/theme-church-site/src/index.js +7 -3
- package/packages/theme-church-site/test/theme.test.mjs +4 -2
- package/packages/theme-companions-site/package.json +17 -6
- package/packages/theme-companions-site/src/harvest.json +4 -2
- package/packages/theme-companions-site/src/index.js +7 -3
- package/packages/theme-companions-site/test/theme.test.mjs +4 -2
- package/packages/theme-floors-site/package.json +17 -6
- package/packages/theme-floors-site/src/harvest.json +4 -2
- package/packages/theme-floors-site/src/index.js +7 -3
- package/packages/theme-floors-site/test/theme.test.mjs +4 -2
- package/packages/theme-fuelnfree-site/package.json +17 -6
- package/packages/theme-fuelnfree-site/src/harvest.json +4 -2
- package/packages/theme-fuelnfree-site/src/index.js +7 -3
- package/packages/theme-fuelnfree-site/test/theme.test.mjs +4 -2
- package/packages/theme-handyman-site/package.json +17 -6
- package/packages/theme-handyman-site/src/harvest.json +4 -2
- package/packages/theme-handyman-site/src/index.js +7 -3
- package/packages/theme-handyman-site/test/theme.test.mjs +4 -2
- package/packages/theme-insurance-site/package.json +17 -6
- package/packages/theme-insurance-site/src/harvest.json +4 -2
- package/packages/theme-insurance-site/src/index.js +7 -3
- package/packages/theme-insurance-site/test/theme.test.mjs +4 -2
- package/packages/theme-scenes/README.md +1 -1
- package/packages/theme-scenes/package.json +4 -3
- package/packages/theme-scenes/src/registry.js +187 -0
- package/packages/theme-shinshu-site/package.json +17 -6
- package/packages/theme-shinshu-site/src/harvest.json +4 -2
- package/packages/theme-shinshu-site/src/index.js +7 -3
- package/packages/theme-shinshu-site/test/theme.test.mjs +4 -2
- package/packages/work-graph/package.json +14 -4
- package/protocol/FILEMETA_V1.md +2 -2
- package/protocol/capabilities/manifest.json +1 -1
- package/protocol/database/agentsam.schema-pack.v1.schema.json +72 -0
- package/protocol/presets/catalog.json +2 -2
- package/protocol/theme-refinery/lineage-registry.json +105 -0
- package/protocol/theme-refinery/product-metadata.schema.json +21 -1
- package/python/agentsam_sdk/repository/intelligence/discovery.py +27 -2
- package/python/agentsam_sdk/repository/intelligence/git.py +4 -0
- package/python/tests/test_repository_intelligence.py +30 -0
- package/src/cli/command-catalog.js +48 -5
- package/src/cli/dispatch.js +1 -0
- package/src/cli.js +20 -1
- package/src/cloudflare/runtime-status.js +2 -1
- package/src/commands/autorag.js +67 -13
- package/src/commands/cheat-sheet.js +29 -4
- package/src/commands/codebaseindex.js +45 -2
- package/src/commands/goap-world.js +134 -0
- package/src/commands/goap.js +11 -4
- package/src/commands/knowledge.js +59 -2
- package/src/commands/machine-binary.js +109 -0
- package/src/commands/machine-runtime.js +266 -0
- package/src/commands/machine.js +208 -0
- package/src/commands/package.js +530 -0
- package/src/commands/plan-ledger.js +370 -0
- package/src/commands/plan.js +183 -0
- package/src/commands/security.js +67 -4
- package/src/commands/setup.js +33 -16
- package/src/commands/skill.js +78 -17
- package/src/commands/status.js +8 -1
- package/src/features/resolve.js +1 -0
- package/src/knowledge/engine.js +21 -2
- package/src/knowledge/runtime-discovery.js +127 -0
- package/src/knowledge/source.js +1 -1
- package/src/lib/identity-scaffold.js +53 -13
- package/src/lib/setup/recipes.js +1 -1
- package/src/lib/slash-commands.js +1 -1
- package/src/local/runtime-store.js +24 -2
- package/src/local/sqlite.js +17 -0
- package/src/models/discovery.js +40 -22
- package/src/models/inventory-core.d.ts +105 -0
- package/src/models/inventory-core.js +54 -6
- package/src/sam/operations/package-audit.js +41 -0
- package/src/sam/seed.js +2 -0
- package/src/security/logs.js +3 -0
- package/src/ui/cli/help.js +41 -0
- package/apps/client-cms-editor/backend/src/demo-bootstrap.ts +0 -145
- package/test/account-session.test.mjs +0 -101
- package/test/agent-capabilities.test.mjs +0 -67
- package/test/app-authority-context.test.mjs +0 -32
- package/test/app-building-skills.test.mjs +0 -61
- package/test/apps-scaffold-contract.test.mjs +0 -114
- package/test/blender-cad.test.mjs +0 -146
- package/test/cad-docker.test.mjs +0 -96
- package/test/capabilities.test.mjs +0 -133
- package/test/cli/api-key-env-whoami.test.mjs +0 -129
- package/test/cli/codebaseindex-plan-ux.test.mjs +0 -37
- package/test/cli/eval-live.test.mjs +0 -219
- package/test/cli/go.test.mjs +0 -128
- package/test/cli/local-vault-and-provider-setup.test.mjs +0 -268
- package/test/cli/mcp-client.test.mjs +0 -256
- package/test/cli/preferences-runtime.test.mjs +0 -11
- package/test/cli/runtime-persist.test.mjs +0 -56
- package/test/cli/runtime-ui.test.mjs +0 -141
- package/test/cli/rust-command.test.mjs +0 -21
- package/test/cli/skill-npm-and-env.test.mjs +0 -52
- package/test/cli/status-actions.test.mjs +0 -88
- package/test/cli/wireframes-go-registry.test.mjs +0 -139
- package/test/cli-preferences.test.mjs +0 -46
- package/test/cloudflare-connector.test.mjs +0 -93
- package/test/cloudflare-runtime.test.mjs +0 -82
- package/test/context.test.mjs +0 -159
- package/test/credentials-audit.test.mjs +0 -113
- package/test/deploy-health-scan.test.mjs +0 -95
- package/test/deploy-receipt.test.mjs +0 -91
- package/test/dockerize.test.mjs +0 -93
- package/test/error-diagnostics.test.mjs +0 -124
- package/test/eval-context.test.mjs +0 -37
- package/test/execution-approvals.test.mjs +0 -27
- package/test/fixtures/cad/courtyard-house.json +0 -208
- package/test/fixtures/knowledge-rpc-worker.mjs +0 -16
- package/test/gcloud-auth.test.mjs +0 -111
- package/test/go/build-source-identity.test.mjs +0 -31
- package/test/go/cloudflare-probe.test.mjs +0 -317
- package/test/go/distribution.test.mjs +0 -28
- package/test/google-cloud-connection.test.mjs +0 -83
- package/test/google-cloud-inventory.test.mjs +0 -64
- package/test/indexing-provider.test.mjs +0 -29
- package/test/init-options.test.mjs +0 -35
- package/test/integration/ai-access-onboarding.test.mjs +0 -47
- package/test/integration/app-command.test.mjs +0 -85
- package/test/integration/cad-discovery.test.mjs +0 -158
- package/test/integration/cad-docker-executor.test.mjs +0 -249
- package/test/integration/cad-execution.test.mjs +0 -184
- package/test/integration/cad-project-app.test.mjs +0 -31
- package/test/integration/cad-project-d1.test.mjs +0 -25
- package/test/integration/cad-project-native.test.mjs +0 -24
- package/test/integration/cad-project-workflow.test.mjs +0 -9
- package/test/integration/cad-project.test.mjs +0 -85
- package/test/integration/cli-help.test.mjs +0 -41
- package/test/integration/cms-app-scaffold.test.mjs +0 -71
- package/test/integration/cms-site-tenancy-contract.test.mjs +0 -257
- package/test/integration/codebaseindex-ingest.test.mjs +0 -214
- package/test/integration/core-client.integration.test.mjs +0 -55
- package/test/integration/error-runtime-rpc.test.mjs +0 -71
- package/test/integration/features-resolve.test.mjs +0 -147
- package/test/integration/icon-registry.test.mjs +0 -67
- package/test/integration/ingest-discover-models.test.mjs +0 -30
- package/test/integration/inspect-path-cli.test.mjs +0 -46
- package/test/integration/install-script.test.mjs +0 -110
- package/test/integration/inventory-core.test.mjs +0 -53
- package/test/integration/inventory-evidence.test.mjs +0 -125
- package/test/integration/knowledge-rpc.test.mjs +0 -112
- package/test/integration/local-fs.test.mjs +0 -113
- package/test/integration/merkle-cli.test.mjs +0 -61
- package/test/integration/merkle-persistence-identity.test.mjs +0 -48
- package/test/integration/plugins-cloudflare.integration.test.mjs +0 -28
- package/test/integration/provider-env-cli.test.mjs +0 -50
- package/test/integration/provider-factory.test.mjs +0 -197
- package/test/integration/repository-company-graph.test.mjs +0 -90
- package/test/integration/runtime-migrations.test.mjs +0 -87
- package/test/integration/runtime-status.integration.test.mjs +0 -212
- package/test/integration/sam-activity-recovery.test.mjs +0 -147
- package/test/integration/sam-decision.test.mjs +0 -584
- package/test/integration/sam-kernel.test.mjs +0 -99
- package/test/integration/sam-planning-astar.test.mjs +0 -279
- package/test/integration/scaffold-cloudflare.test.mjs +0 -46
- package/test/integration/skill-runtime.test.mjs +0 -240
- package/test/integration/storage-architecture.test.mjs +0 -154
- package/test/integration/store-discovery.test.mjs +0 -44
- package/test/integration/studio-fs-pty-e2e.test.mjs +0 -294
- package/test/integration/terminal-exec.integration.test.mjs +0 -86
- package/test/integration/tool-runtime.test.mjs +0 -124
- package/test/integration/tool-schema.test.mjs +0 -59
- package/test/jr-dev-skill.test.mjs +0 -26
- package/test/knowledge-context-pack.test.mjs +0 -19
- package/test/knowledge-postgres.test.mjs +0 -40
- package/test/knowledge-service.test.mjs +0 -110
- package/test/knowledge.test.mjs +0 -206
- package/test/live/terminal-transport.live.test.mjs +0 -24
- package/test/local-sessions.test.mjs +0 -57
- package/test/local-studio-deploy.test.mjs +0 -83
- package/test/loopback-oauth.test.mjs +0 -53
- package/test/merkle-render.test.mjs +0 -31
- package/test/mini.test.mjs +0 -140
- package/test/model-catalog.test.mjs +0 -70
- package/test/models.test.mjs +0 -309
- package/test/npm10-lock.test.mjs +0 -29
- package/test/ollama.test.mjs +0 -137
- package/test/open-url.test.mjs +0 -64
- package/test/openai-responses.test.mjs +0 -155
- package/test/portable-context.test.mjs +0 -94
- package/test/project-config.test.mjs +0 -81
- package/test/project-rules.test.mjs +0 -44
- package/test/provider-credentials.test.mjs +0 -106
- package/test/rehydrate.test.mjs +0 -25
- package/test/release-hygiene.test.mjs +0 -42
- package/test/repository-snapshot-view.test.mjs +0 -112
- package/test/responses-runner.test.mjs +0 -465
- package/test/runtime-activity.test.mjs +0 -98
- package/test/sdk-worker-contract.test.mjs +0 -72
- package/test/security.test.mjs +0 -252
- package/test/setup-planner.test.mjs +0 -74
- package/test/setup-runtime.test.mjs +0 -51
- package/test/shell.test.mjs +0 -281
- package/test/skills.test.mjs +0 -22
- package/test/smoke.mjs +0 -122
- package/test/telemetry.test.mjs +0 -79
- package/test/terminal/local-pty.mock.test.mjs +0 -153
- package/test/terminal-machine-identity.test.mjs +0 -88
- package/test/theme-portability.test.mjs +0 -14
- package/test/tools-search.test.mjs +0 -73
- package/test/unit/website-assets-bindings.test.mjs +0 -60
- package/test/whoami-resume.test.mjs +0 -157
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
import { test } from 'node:test';
|
|
4
|
+
import { DatabaseSync } from 'node:sqlite';
|
|
5
|
+
import { handleIdentityWorkerRequest } from '../src/server/worker-router.js';
|
|
6
|
+
import {
|
|
7
|
+
isAllowedNativeRedirect,
|
|
8
|
+
parseNativeStart,
|
|
9
|
+
} from '../src/oauth/native-handoff.js';
|
|
10
|
+
import { pkceChallenge, pkceVerifier } from '../src/oauth/pkce.js';
|
|
11
|
+
import { IDENTITY_ROUTE_IDS } from '../src/contracts/route-ids.js';
|
|
12
|
+
import { createRouteRegistry, defineRouteProjection } from '../src/contracts/route-projection.js';
|
|
13
|
+
|
|
14
|
+
const REDIRECT = 'agentsamstudio://auth/callback';
|
|
15
|
+
|
|
16
|
+
/** D1-shaped shim over node:sqlite so the real adapter + router run unmodified. */
|
|
17
|
+
function createTestD1() {
|
|
18
|
+
const sqlite = new DatabaseSync(':memory:');
|
|
19
|
+
const root = new URL('../../../migrations/d1/', import.meta.url);
|
|
20
|
+
for (const f of ['0013_identity_oauth_states.sql', '0014_auth_event_log.sql', '0015_identity_oauth_state_app_id.sql', '0017_identity_native_oauth.sql']) {
|
|
21
|
+
sqlite.exec(readFileSync(new URL(f, root), 'utf8'));
|
|
22
|
+
}
|
|
23
|
+
// Live-shaped subset of the account/session tables the adapter touches.
|
|
24
|
+
sqlite.exec(`
|
|
25
|
+
CREATE TABLE accounts (id TEXT PRIMARY KEY, email TEXT, display_name TEXT, status TEXT, created_at INTEGER, updated_at INTEGER);
|
|
26
|
+
CREATE TABLE auth_users (id TEXT PRIMARY KEY, email TEXT UNIQUE, display_name TEXT, password_hash TEXT, salt TEXT, status TEXT, created_at INTEGER, updated_at INTEGER);
|
|
27
|
+
CREATE TABLE account_identities (id TEXT PRIMARY KEY, account_id TEXT, provider TEXT, provider_subject TEXT, email TEXT, created_at INTEGER, updated_at INTEGER, UNIQUE(provider, provider_subject));
|
|
28
|
+
CREATE TABLE auth_sessions (id TEXT PRIMARY KEY, user_id TEXT, email TEXT, provider TEXT, provider_subject TEXT, display_name TEXT,
|
|
29
|
+
expires_at TEXT, created_at TEXT, last_active_at INTEGER, revoked_at TEXT, type TEXT NOT NULL DEFAULT 'browser');
|
|
30
|
+
`);
|
|
31
|
+
const log = [];
|
|
32
|
+
return {
|
|
33
|
+
sqlite,
|
|
34
|
+
log,
|
|
35
|
+
prepare(sql) {
|
|
36
|
+
log.push(sql);
|
|
37
|
+
return {
|
|
38
|
+
bind: (...args) => ({
|
|
39
|
+
first: async () => sqlite.prepare(sql).get(...args) ?? null,
|
|
40
|
+
run: async () => { sqlite.prepare(sql).run(...args); return { success: true }; },
|
|
41
|
+
all: async () => ({ results: sqlite.prepare(sql).all(...args) }),
|
|
42
|
+
}),
|
|
43
|
+
};
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const app = { id: 'local-studio' };
|
|
49
|
+
const routeRegistry = createRouteRegistry([
|
|
50
|
+
defineRouteProjection({
|
|
51
|
+
appId: app.id,
|
|
52
|
+
routes: {
|
|
53
|
+
[IDENTITY_ROUTE_IDS.LOGIN]: '/auth/login',
|
|
54
|
+
[IDENTITY_ROUTE_IDS.RECOVERY]: '/auth/reset',
|
|
55
|
+
[IDENTITY_ROUTE_IDS.APP_AUTHENTICATED]: '/agentsam',
|
|
56
|
+
[IDENTITY_ROUTE_IDS.OAUTH_CALLBACK]: '/api/oauth/:provider/callback',
|
|
57
|
+
},
|
|
58
|
+
}),
|
|
59
|
+
]);
|
|
60
|
+
const options = { app, routeRegistry };
|
|
61
|
+
const cfEnv = (DB) => ({ DB, CLOUDFLARE_OAUTH_CLIENT_ID: 'cf-client', CLOUDFLARE_OAUTH_CLIENT_SECRET: 'cf-secret' });
|
|
62
|
+
|
|
63
|
+
/** Stub Cloudflare token + userinfo + /v4/user so the real callback runs offline. */
|
|
64
|
+
async function withCloudflareStub(fn) {
|
|
65
|
+
const realFetch = globalThis.fetch;
|
|
66
|
+
globalThis.fetch = async (input) => {
|
|
67
|
+
const u = String(input?.url || input);
|
|
68
|
+
if (u.includes('/oauth2/token')) return Response.json({ access_token: 'cf_access', refresh_token: 'cf_refresh' });
|
|
69
|
+
if (u.includes('/oauth2/userinfo')) return Response.json({ sub: 'cf-user-1' });
|
|
70
|
+
if (u.includes('/client/v4/user')) return Response.json({ result: { email: 'sam@example.test', first_name: 'Sam' } });
|
|
71
|
+
throw new Error(`unexpected_fetch:${u}`);
|
|
72
|
+
};
|
|
73
|
+
try { return await fn(); } finally { globalThis.fetch = realFetch; }
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async function nativeStart(env, { challenge, redirect = REDIRECT }) {
|
|
77
|
+
const url = new URL('https://studio.test/api/oauth/cloudflare/start');
|
|
78
|
+
url.searchParams.set('client', 'native');
|
|
79
|
+
if (challenge) url.searchParams.set('native_challenge', challenge);
|
|
80
|
+
url.searchParams.set('native_redirect', redirect);
|
|
81
|
+
return handleIdentityWorkerRequest(new Request(url), env, options);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
test('native redirect allowlist: deep link + loopback only', () => {
|
|
85
|
+
assert.equal(isAllowedNativeRedirect('agentsamstudio://auth/callback'), true);
|
|
86
|
+
assert.equal(isAllowedNativeRedirect('http://127.0.0.1:53682/cb'), true);
|
|
87
|
+
assert.equal(isAllowedNativeRedirect('http://localhost:1/cb'), true);
|
|
88
|
+
assert.equal(isAllowedNativeRedirect('https://evil.example/cb'), false);
|
|
89
|
+
assert.equal(isAllowedNativeRedirect('http://evil.example/cb'), false);
|
|
90
|
+
assert.equal(isAllowedNativeRedirect('javascript:alert(1)'), false);
|
|
91
|
+
assert.equal(isAllowedNativeRedirect('otherscheme://x'), false);
|
|
92
|
+
assert.equal(isAllowedNativeRedirect('otherscheme://x', { IDENTITY_NATIVE_REDIRECT_SCHEMES: 'otherscheme' }), true);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test('parseNativeStart: browser requests are untouched; bad native params are rejected', async () => {
|
|
96
|
+
const good = await pkceChallenge(pkceVerifier());
|
|
97
|
+
assert.deepEqual(parseNativeStart(new URL('https://x.test/start')), { native: false });
|
|
98
|
+
assert.equal(parseNativeStart(new URL(`https://x.test/start?client=native&native_challenge=short&native_redirect=${REDIRECT}`)).error, 'native_challenge_invalid');
|
|
99
|
+
assert.equal(parseNativeStart(new URL(`https://x.test/start?client=native&native_challenge=${good}&native_redirect=https://evil.example`)).error, 'native_redirect_not_allowed');
|
|
100
|
+
assert.equal(parseNativeStart(new URL(`https://x.test/start?client=native&native_challenge=${good}&native_redirect=${REDIRECT}`)).clientType, 'desktop');
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test('native start rejects a bad redirect before any transaction is stored', async () => {
|
|
104
|
+
const db = createTestD1();
|
|
105
|
+
const res = await nativeStart(cfEnv(db), { challenge: await pkceChallenge(pkceVerifier()), redirect: 'https://evil.example/cb' });
|
|
106
|
+
assert.equal(res.status, 400);
|
|
107
|
+
assert.equal(db.sqlite.prepare('SELECT COUNT(*) c FROM identity_oauth_states').get().c, 0);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test('full native Cloudflare login: desktop session, deep-link handoff, single-use PKCE exchange', async () => {
|
|
111
|
+
const db = createTestD1();
|
|
112
|
+
const env = cfEnv(db);
|
|
113
|
+
const verifier = pkceVerifier();
|
|
114
|
+
|
|
115
|
+
const start = await nativeStart(env, { challenge: await pkceChallenge(verifier) });
|
|
116
|
+
assert.equal(start.status, 302);
|
|
117
|
+
const state = new URL(start.headers.get('location')).searchParams.get('state');
|
|
118
|
+
const txn = db.sqlite.prepare('SELECT * FROM identity_oauth_states WHERE state = ?').get(state);
|
|
119
|
+
assert.equal(txn.client_type, 'desktop');
|
|
120
|
+
assert.equal(txn.native_redirect, REDIRECT);
|
|
121
|
+
|
|
122
|
+
const cb = await withCloudflareStub(() => handleIdentityWorkerRequest(
|
|
123
|
+
new Request(`https://studio.test/api/oauth/cloudflare/callback?code=abc&state=${state}`), env, options,
|
|
124
|
+
));
|
|
125
|
+
assert.equal(cb.status, 302);
|
|
126
|
+
assert.equal(cb.headers.get('set-cookie'), null, 'native login must not set a browser cookie');
|
|
127
|
+
const location = new URL(cb.headers.get('location'));
|
|
128
|
+
assert.equal(`${location.protocol}//${location.host}${location.pathname}`, REDIRECT);
|
|
129
|
+
const handoff = location.searchParams.get('handoff');
|
|
130
|
+
assert.ok(handoff);
|
|
131
|
+
|
|
132
|
+
const session = db.sqlite.prepare('SELECT * FROM auth_sessions').get();
|
|
133
|
+
assert.equal(session.type, 'desktop');
|
|
134
|
+
assert.equal(session.provider, 'cloudflare');
|
|
135
|
+
assert.ok(!location.toString().includes(session.id), 'session id must never appear in the deep link');
|
|
136
|
+
// Identity only: a Cloudflare *login* must not create resource-grant rows.
|
|
137
|
+
assert.equal(db.log.some((s) => /user_oauth_tokens/i.test(s)), false);
|
|
138
|
+
|
|
139
|
+
const exchange = (body) => handleIdentityWorkerRequest(new Request('https://studio.test/api/oauth/native/exchange', {
|
|
140
|
+
method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(body),
|
|
141
|
+
}), env, options);
|
|
142
|
+
|
|
143
|
+
const ok = await exchange({ handoff, code_verifier: verifier });
|
|
144
|
+
assert.equal(ok.status, 200);
|
|
145
|
+
const payload = await ok.json();
|
|
146
|
+
assert.equal(payload.session_id, session.id);
|
|
147
|
+
assert.equal(payload.user.email, 'sam@example.test');
|
|
148
|
+
|
|
149
|
+
const replay = await exchange({ handoff, code_verifier: verifier });
|
|
150
|
+
assert.equal(replay.status, 400, 'handoff is single-use');
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
test('wrong PKCE verifier burns the handoff and revokes the desktop session', async () => {
|
|
154
|
+
const db = createTestD1();
|
|
155
|
+
const env = cfEnv(db);
|
|
156
|
+
const verifier = pkceVerifier();
|
|
157
|
+
const start = await nativeStart(env, { challenge: await pkceChallenge(verifier) });
|
|
158
|
+
const state = new URL(start.headers.get('location')).searchParams.get('state');
|
|
159
|
+
const cb = await withCloudflareStub(() => handleIdentityWorkerRequest(
|
|
160
|
+
new Request(`https://studio.test/api/oauth/cloudflare/callback?code=abc&state=${state}`), env, options,
|
|
161
|
+
));
|
|
162
|
+
const handoff = new URL(cb.headers.get('location')).searchParams.get('handoff');
|
|
163
|
+
|
|
164
|
+
const exchange = (v) => handleIdentityWorkerRequest(new Request('https://studio.test/api/oauth/native/exchange', {
|
|
165
|
+
method: 'POST', body: JSON.stringify({ handoff, code_verifier: v }),
|
|
166
|
+
}), env, options);
|
|
167
|
+
assert.equal((await exchange(pkceVerifier())).status, 400);
|
|
168
|
+
assert.equal((await exchange(verifier)).status, 400, 'code already burned even for the right verifier');
|
|
169
|
+
assert.ok(db.sqlite.prepare('SELECT revoked_at FROM auth_sessions').get().revoked_at, 'session revoked');
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
test('browser Cloudflare login is unchanged: browser session, cookie, globe redirect, no native columns written', async () => {
|
|
173
|
+
const db = createTestD1();
|
|
174
|
+
const env = cfEnv(db);
|
|
175
|
+
const start = await handleIdentityWorkerRequest(new Request('https://studio.test/api/oauth/cloudflare/start'), env, options);
|
|
176
|
+
const state = new URL(start.headers.get('location')).searchParams.get('state');
|
|
177
|
+
assert.equal(db.log.filter((s) => /INSERT INTO identity_oauth_states/.test(s)).every((s) => !/client_type/.test(s)), true);
|
|
178
|
+
|
|
179
|
+
const cb = await withCloudflareStub(() => handleIdentityWorkerRequest(
|
|
180
|
+
new Request(`https://studio.test/api/oauth/cloudflare/callback?code=abc&state=${state}`), env, options,
|
|
181
|
+
));
|
|
182
|
+
assert.equal(cb.status, 302);
|
|
183
|
+
assert.match(cb.headers.get('set-cookie') || '', /HttpOnly/);
|
|
184
|
+
assert.match(cb.headers.get('location'), /globe_exit=1/);
|
|
185
|
+
assert.equal(db.sqlite.prepare('SELECT type FROM auth_sessions').get().type, 'browser');
|
|
186
|
+
assert.equal(db.log.filter((s) => /INSERT INTO auth_sessions/.test(s)).every((s) => !/\btype\b/.test(s)), true);
|
|
187
|
+
assert.equal(db.sqlite.prepare('SELECT COUNT(*) c FROM identity_native_handoffs').get().c, 0);
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
// ── Provider-agnostic proof ────────────────────────────────────────────────
|
|
191
|
+
// The native handoff is transport only. Every lane Local Studio can expose must
|
|
192
|
+
// complete identically: desktop session, deep-link handoff, PKCE exchange, and
|
|
193
|
+
// no provider-grant (user_oauth_tokens) writes. IAM is one optional lane, never required.
|
|
194
|
+
const EMAIL = 'sam@example.test';
|
|
195
|
+
const LANES = [
|
|
196
|
+
{
|
|
197
|
+
name: 'cloudflare (identity sign-in)',
|
|
198
|
+
start: '/api/oauth/cloudflare/start', callback: '/api/oauth/cloudflare/callback', sessionProvider: 'cloudflare',
|
|
199
|
+
env: { CLOUDFLARE_OAUTH_CLIENT_ID: 'cf-client', CLOUDFLARE_OAUTH_CLIENT_SECRET: 'cf-secret' },
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
name: 'google (BYOK)',
|
|
203
|
+
start: '/api/oauth/google/start', callback: '/api/oauth/google/callback', sessionProvider: 'google',
|
|
204
|
+
env: { GOOGLE_CLIENT_ID: 'g-client', GOOGLE_CLIENT_SECRET: 'g-secret' },
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
name: 'github (BYOK)',
|
|
208
|
+
start: '/api/oauth/github/start', callback: '/api/oauth/github/callback', sessionProvider: 'github',
|
|
209
|
+
env: { GITHUB_CLIENT_ID: 'gh-client', GITHUB_CLIENT_SECRET: 'gh-secret' },
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
name: 'inneranimalmedia (optional IAM platform lane)',
|
|
213
|
+
start: '/api/oauth/inneranimalmedia/start', callback: '/api/oauth/inneranimalmedia/callback', sessionProvider: 'iam',
|
|
214
|
+
env: { IAM_CLIENT_ID: 'iam-client', IAM_CLIENT_SECRET: 'iam-secret', IAM_OAUTH_ISSUER: 'https://iam.test' },
|
|
215
|
+
},
|
|
216
|
+
];
|
|
217
|
+
|
|
218
|
+
async function withAllProviderStubs(fn) {
|
|
219
|
+
const realFetch = globalThis.fetch;
|
|
220
|
+
globalThis.fetch = async (input) => {
|
|
221
|
+
const u = String(input?.url || input);
|
|
222
|
+
if (u.includes('/oauth2/token')) return Response.json({ access_token: 'cf_access' });
|
|
223
|
+
if (u.includes('/oauth2/userinfo')) return Response.json({ sub: 'cf-user-1' });
|
|
224
|
+
if (u.includes('/client/v4/user')) return Response.json({ result: { email: EMAIL, first_name: 'Sam' } });
|
|
225
|
+
if (u.includes('oauth2.googleapis.com')) return Response.json({ access_token: 'g_access' });
|
|
226
|
+
if (u.includes('openidconnect.googleapis.com')) return Response.json({ sub: 'g-1', email: EMAIL, name: 'Sam' });
|
|
227
|
+
if (u.includes('github.com/login/oauth')) return Response.json({ access_token: 'gh_access' });
|
|
228
|
+
if (u.includes('api.github.com/user/emails')) return Response.json([{ email: EMAIL, primary: true, verified: true }]);
|
|
229
|
+
if (u.includes('api.github.com/user')) return Response.json({ id: 42, login: 'sam', name: 'Sam' });
|
|
230
|
+
if (u.startsWith('https://iam.test') && /token/.test(u)) return Response.json({ ok: true, access_token: 'iam_access' });
|
|
231
|
+
if (u.startsWith('https://iam.test')) return Response.json({ sub: 'iam-1', email: EMAIL, email_verified: true, name: 'Sam' });
|
|
232
|
+
throw new Error(`unexpected_fetch:${u}`);
|
|
233
|
+
};
|
|
234
|
+
try { return await fn(); } finally { globalThis.fetch = realFetch; }
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
for (const lane of LANES) {
|
|
238
|
+
test(`[${lane.name}] native login: desktop session → handoff → PKCE exchange, no grant writes`, async () => {
|
|
239
|
+
const db = createTestD1();
|
|
240
|
+
const env = { DB: db, ...lane.env };
|
|
241
|
+
const verifier = pkceVerifier();
|
|
242
|
+
|
|
243
|
+
const startUrl = new URL(`https://studio.test${lane.start}`);
|
|
244
|
+
startUrl.searchParams.set('client', 'native');
|
|
245
|
+
startUrl.searchParams.set('native_challenge', await pkceChallenge(verifier));
|
|
246
|
+
startUrl.searchParams.set('native_redirect', REDIRECT);
|
|
247
|
+
const start = await handleIdentityWorkerRequest(new Request(startUrl), env, options);
|
|
248
|
+
assert.equal(start.status, 302);
|
|
249
|
+
const state = new URL(start.headers.get('location')).searchParams.get('state');
|
|
250
|
+
assert.equal(db.sqlite.prepare('SELECT client_type FROM identity_oauth_states WHERE state = ?').get(state).client_type, 'desktop');
|
|
251
|
+
|
|
252
|
+
const cb = await withAllProviderStubs(() => handleIdentityWorkerRequest(
|
|
253
|
+
new Request(`https://studio.test${lane.callback}?code=abc&state=${state}`), env, options,
|
|
254
|
+
));
|
|
255
|
+
assert.equal(cb.status, 302);
|
|
256
|
+
assert.equal(cb.headers.get('set-cookie'), null, 'no browser cookie on native login');
|
|
257
|
+
const location = new URL(cb.headers.get('location'));
|
|
258
|
+
assert.equal(`${location.protocol}//${location.host}${location.pathname}`, REDIRECT);
|
|
259
|
+
const handoff = location.searchParams.get('handoff');
|
|
260
|
+
assert.ok(handoff);
|
|
261
|
+
|
|
262
|
+
const session = db.sqlite.prepare('SELECT * FROM auth_sessions').get();
|
|
263
|
+
assert.equal(session.type, 'desktop');
|
|
264
|
+
assert.equal(session.provider, lane.sessionProvider);
|
|
265
|
+
assert.ok(!location.toString().includes(session.id));
|
|
266
|
+
assert.equal(db.log.some((s) => /user_oauth_tokens/i.test(s)), false, 'sign-in never writes provider grants');
|
|
267
|
+
|
|
268
|
+
const exchange = () => handleIdentityWorkerRequest(new Request('https://studio.test/api/oauth/native/exchange', {
|
|
269
|
+
method: 'POST', body: JSON.stringify({ handoff, code_verifier: verifier }),
|
|
270
|
+
}), env, options);
|
|
271
|
+
const ok = await exchange();
|
|
272
|
+
assert.equal(ok.status, 200);
|
|
273
|
+
const payload = await ok.json();
|
|
274
|
+
assert.equal(payload.session_id, session.id);
|
|
275
|
+
assert.equal(payload.user.email, EMAIL);
|
|
276
|
+
assert.ok(payload.expires_at > 0);
|
|
277
|
+
assert.equal((await exchange()).status, 400, 'single-use');
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
test('IAM is optional: Cloudflare native sign-in works with no IAM config, and the IAM lane reports not-configured', async () => {
|
|
282
|
+
const db = createTestD1();
|
|
283
|
+
const env = { DB: db, ...LANES[0].env }; // no IAM_* at all
|
|
284
|
+
const iamStart = await handleIdentityWorkerRequest(
|
|
285
|
+
new Request('https://studio.test/api/oauth/inneranimalmedia/start'), env, options,
|
|
286
|
+
);
|
|
287
|
+
assert.equal(iamStart.status, 503);
|
|
288
|
+
assert.equal((await iamStart.json()).error, 'inneranimalmedia_oauth_not_configured');
|
|
289
|
+
|
|
290
|
+
const cfStart = await nativeStart(env, { challenge: await pkceChallenge(pkceVerifier()) });
|
|
291
|
+
assert.equal(cfStart.status, 302);
|
|
292
|
+
});
|
|
@@ -33,15 +33,15 @@ describe('oauth credentials', () => {
|
|
|
33
33
|
);
|
|
34
34
|
});
|
|
35
35
|
|
|
36
|
-
it('
|
|
36
|
+
it('never silently maps Google/GitHub buttons onto IAM', () => {
|
|
37
37
|
const env = {
|
|
38
38
|
IAM_CLIENT_ID: 'iam_dcr_legendary',
|
|
39
39
|
IAM_CLIENT_SECRET: 'secret',
|
|
40
40
|
IAM_OAUTH_ISSUER: 'https://iam.example.test',
|
|
41
41
|
};
|
|
42
|
-
|
|
43
|
-
assert.equal(
|
|
44
|
-
assert.equal(lane
|
|
42
|
+
assert.equal(resolveOAuthCredentialLane(env, 'google'), null);
|
|
43
|
+
assert.equal(resolveOAuthCredentialLane(env, 'github'), null);
|
|
44
|
+
assert.equal(resolveOAuthCredentialLane(env, 'inneranimalmedia')?.lane, 'iam_platform');
|
|
45
45
|
});
|
|
46
46
|
|
|
47
47
|
it('developer BYOK Google takes the Google button when set', () => {
|
|
@@ -21,7 +21,8 @@ describe('auth portal preview server', () => {
|
|
|
21
21
|
const loginRes = await fetch(`${baseUrl}/auth/login`);
|
|
22
22
|
assert.equal(loginRes.status, 200);
|
|
23
23
|
const loginHtml = await loginRes.text();
|
|
24
|
-
assert.match(loginHtml,
|
|
24
|
+
assert.match(loginHtml, /<title>Sign in<\/title>/);
|
|
25
|
+
assert.match(loginHtml, /data-company-name>App</);
|
|
25
26
|
|
|
26
27
|
const signupRes = await fetch(`${baseUrl}/auth/signup`);
|
|
27
28
|
assert.equal(signupRes.status, 200);
|
|
@@ -34,7 +35,8 @@ describe('auth portal preview server', () => {
|
|
|
34
35
|
const companyRes = await fetch(`${baseUrl}/api/company`);
|
|
35
36
|
const companyJson = await companyRes.json();
|
|
36
37
|
assert.equal(companyJson.ok, true);
|
|
37
|
-
assert.equal(companyJson.company.supportEmail, 'support@
|
|
38
|
+
assert.equal(companyJson.company.supportEmail, 'support@example.com');
|
|
39
|
+
assert.equal(companyJson.company.name, 'Preview App');
|
|
38
40
|
|
|
39
41
|
const apiRes = await fetch(`${baseUrl}/api/auth/login`, {
|
|
40
42
|
method: 'POST',
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import assert from 'node:assert/strict';
|
|
2
2
|
import { describe, it } from 'node:test';
|
|
3
|
-
import { SESSION_POLICY, clampAgentSessionTtl } from '../src/core/session-policy.js';
|
|
3
|
+
import { SESSION_POLICY, clampAgentSessionTtl, shouldRenewDesktopSession } from '../src/core/session-policy.js';
|
|
4
4
|
import { IDENTITY_ROUTE_IDS } from '../src/contracts/route-ids.js';
|
|
5
5
|
|
|
6
6
|
describe('SESSION_POLICY', () => {
|
|
7
7
|
it('keeps browser and agent TTLs distinct', () => {
|
|
8
8
|
assert.equal(SESSION_POLICY.browser.ttlSeconds, 30 * 24 * 60 * 60);
|
|
9
|
+
assert.equal(SESSION_POLICY.desktop.ttlSeconds, 30 * 24 * 60 * 60);
|
|
10
|
+
assert.equal(SESSION_POLICY.desktop.renewWindowSeconds, 7 * 24 * 60 * 60);
|
|
9
11
|
assert.equal(SESSION_POLICY.agent.defaultTtlSeconds, 15 * 60);
|
|
10
12
|
assert.equal(clampAgentSessionTtl(30), 60);
|
|
11
13
|
assert.equal(clampAgentSessionTtl(900), 900);
|
|
@@ -19,3 +21,13 @@ describe('IDENTITY_ROUTE_IDS', () => {
|
|
|
19
21
|
assert.ok(!String(IDENTITY_ROUTE_IDS.LOGIN).startsWith('/'));
|
|
20
22
|
});
|
|
21
23
|
});
|
|
24
|
+
|
|
25
|
+
describe('desktop session renewal', () => {
|
|
26
|
+
it('only renews in the final seven days', () => {
|
|
27
|
+
const now = 2_000_000;
|
|
28
|
+
assert.equal(shouldRenewDesktopSession({ type: 'desktop', expires_at: now + 6 * 24 * 60 * 60 }, now), true);
|
|
29
|
+
assert.equal(shouldRenewDesktopSession({ type: 'desktop', expires_at: now + 8 * 24 * 60 * 60 }, now), false);
|
|
30
|
+
assert.equal(shouldRenewDesktopSession({ type: 'browser', expires_at: now + 60 }, now), false);
|
|
31
|
+
assert.equal(shouldRenewDesktopSession({ type: 'desktop', expires_at: now - 1 }, now), false);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
import test from 'node:test';
|
|
4
|
+
|
|
5
|
+
const runtimeEntry = new URL('../src/adapters/portable-d1/index.js', import.meta.url);
|
|
6
|
+
|
|
7
|
+
test('portable D1 runtime entry does not pull Node-only migration loaders into Workers', () => {
|
|
8
|
+
const source = readFileSync(runtimeEntry, 'utf8');
|
|
9
|
+
assert.doesNotMatch(source, /migrations\/apply-portable/);
|
|
10
|
+
assert.doesNotMatch(source, /node:(?:fs|path|url)/);
|
|
11
|
+
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inneranimalmedia/agentsam-provider-completeful",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.6.7",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Portable Completeful provider adapter and AgentSam tool definitions.",
|
|
6
6
|
"type": "module",
|
|
@@ -25,5 +25,10 @@
|
|
|
25
25
|
"publishConfig": {
|
|
26
26
|
"access": "public"
|
|
27
27
|
},
|
|
28
|
-
"license": "MIT"
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "git+https://github.com/SamPrimeaux/agentsam-sdk.git",
|
|
32
|
+
"directory": "packages/providers/completeful"
|
|
33
|
+
}
|
|
29
34
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name": "@inneranimalmedia/theme-
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Real New Iberia Church of Christ public pages
|
|
2
|
+
"name": "@inneranimalmedia/theme-cypress",
|
|
3
|
+
"version": "2.6.7",
|
|
4
|
+
"description": "Real New Iberia Church of Christ public pages — visit, groups, mission, and giving.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.js",
|
|
7
7
|
"exports": {
|
|
@@ -25,7 +25,18 @@
|
|
|
25
25
|
"kind": "theme",
|
|
26
26
|
"slug": "church-site",
|
|
27
27
|
"galleryPath": "apps/theme-gallery-preview/themes/church-site",
|
|
28
|
-
"installable":
|
|
29
|
-
"icon": "theme"
|
|
30
|
-
|
|
28
|
+
"installable": false,
|
|
29
|
+
"icon": "theme",
|
|
30
|
+
"lineage": "nic",
|
|
31
|
+
"family": "community-faith",
|
|
32
|
+
"normalization": "canonical_id_assigned",
|
|
33
|
+
"canonicalId": "cypress",
|
|
34
|
+
"legacyPackageName": "@inneranimalmedia/theme-church-site"
|
|
35
|
+
},
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "git+https://github.com/SamPrimeaux/agentsam-sdk.git",
|
|
39
|
+
"directory": "packages/theme-church-site"
|
|
40
|
+
},
|
|
41
|
+
"private": true
|
|
31
42
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"harvest_batch": "theme-harvest-20260924",
|
|
3
3
|
"app_path": "apps/church-site",
|
|
4
4
|
"harvest_path": "work/theme-harvest/church-site",
|
|
5
|
-
"status": "
|
|
5
|
+
"status": "needs_normalization",
|
|
6
6
|
"source_hash": "0a8ae5de768f874ccdebe92a5e438ad8e4d51b4c5fdae9679c7e09268328fee6",
|
|
7
7
|
"capabilities": [
|
|
8
8
|
"cms.media",
|
|
@@ -10,5 +10,7 @@
|
|
|
10
10
|
"deploy.receipt",
|
|
11
11
|
"forms.leads",
|
|
12
12
|
"theme.storefront.shell"
|
|
13
|
-
]
|
|
13
|
+
],
|
|
14
|
+
"lineage": "nic",
|
|
15
|
+
"family": "community-faith"
|
|
14
16
|
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/** Harvested donor-derived theme wrapper — not installable until remaster gates pass. */
|
|
2
2
|
const THEME = {
|
|
3
3
|
"id": "theme.church-site",
|
|
4
4
|
"slug": "church-site",
|
|
5
|
+
"lineage": "nic",
|
|
6
|
+
"family": "community-faith",
|
|
5
7
|
"displayName": "New Iberia Church of Christ",
|
|
6
8
|
"version": "0.1.0",
|
|
7
9
|
"kind": "gallery-theme",
|
|
@@ -41,7 +43,7 @@ const THEME = {
|
|
|
41
43
|
"mobile": "/themes/church-site/demo/",
|
|
42
44
|
"demoUrl": "/themes/church-site/demo/"
|
|
43
45
|
},
|
|
44
|
-
"installable":
|
|
46
|
+
"installable": false,
|
|
45
47
|
"galleryPath": "apps/theme-gallery-preview/themes/church-site",
|
|
46
48
|
"capabilityHints": [
|
|
47
49
|
"theme.storefront.shell"
|
|
@@ -70,7 +72,9 @@ export function createProductRow({ accountId = null, repositoryId = null, status
|
|
|
70
72
|
package_name: theme.package,
|
|
71
73
|
metadata: {
|
|
72
74
|
origin: "gallery_mount",
|
|
73
|
-
normalization_state: status === "production" ? "promoted" : "
|
|
75
|
+
normalization_state: status === "production" ? "promoted" : "needs_normalization",
|
|
76
|
+
lineage: theme.lineage,
|
|
77
|
+
family: theme.family,
|
|
74
78
|
package: theme.package,
|
|
75
79
|
gallery_path: theme.galleryPath,
|
|
76
80
|
preview_kind: theme.preview?.kind || "static",
|
|
@@ -2,10 +2,12 @@ import assert from 'node:assert/strict';
|
|
|
2
2
|
import test from 'node:test';
|
|
3
3
|
import { createTheme, createProductRow } from '../src/index.js';
|
|
4
4
|
|
|
5
|
-
test('church-site theme package exports installable contract', () => {
|
|
5
|
+
test('church-site theme package exports harvested (not installable) contract', () => {
|
|
6
6
|
const theme = createTheme();
|
|
7
7
|
assert.equal(theme.slug, "church-site");
|
|
8
|
-
assert.equal(theme.installable,
|
|
8
|
+
assert.equal(theme.installable, false);
|
|
9
|
+
assert.equal(theme.lineage, "nic");
|
|
10
|
+
assert.equal(theme.family, "community-faith");
|
|
9
11
|
assert.equal(theme.package, "@inneranimalmedia/theme-church-site");
|
|
10
12
|
assert.ok(Array.isArray(theme.pages));
|
|
11
13
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name": "@inneranimalmedia/theme-
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Real Companions of Caddo public static surface
|
|
2
|
+
"name": "@inneranimalmedia/theme-violet",
|
|
3
|
+
"version": "2.6.7",
|
|
4
|
+
"description": "Real Companions of Caddo public static surface — mission, campaigns, and involvement paths.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.js",
|
|
7
7
|
"exports": {
|
|
@@ -25,7 +25,18 @@
|
|
|
25
25
|
"kind": "theme",
|
|
26
26
|
"slug": "companions-site",
|
|
27
27
|
"galleryPath": "apps/theme-gallery-preview/themes/companions-site",
|
|
28
|
-
"installable":
|
|
29
|
-
"icon": "theme"
|
|
30
|
-
|
|
28
|
+
"installable": false,
|
|
29
|
+
"icon": "theme",
|
|
30
|
+
"lineage": "coc",
|
|
31
|
+
"family": "nonprofit-campaign",
|
|
32
|
+
"normalization": "canonical_id_assigned",
|
|
33
|
+
"canonicalId": "violet",
|
|
34
|
+
"legacyPackageName": "@inneranimalmedia/theme-companions-site"
|
|
35
|
+
},
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "git+https://github.com/SamPrimeaux/agentsam-sdk.git",
|
|
39
|
+
"directory": "packages/theme-companions-site"
|
|
40
|
+
},
|
|
41
|
+
"private": true
|
|
31
42
|
}
|
|
@@ -2,11 +2,13 @@
|
|
|
2
2
|
"harvest_batch": "theme-harvest-20260924",
|
|
3
3
|
"app_path": "apps/companions-site",
|
|
4
4
|
"harvest_path": "work/theme-harvest/companions-site",
|
|
5
|
-
"status": "
|
|
5
|
+
"status": "needs_normalization",
|
|
6
6
|
"source_hash": "cdad95d1a674b05456a6166f9fc70d86dce106d4215395601164ec40ac161f7b",
|
|
7
7
|
"capabilities": [
|
|
8
8
|
"cms.media",
|
|
9
9
|
"cms.pages",
|
|
10
10
|
"theme.storefront.shell"
|
|
11
|
-
]
|
|
11
|
+
],
|
|
12
|
+
"lineage": "coc",
|
|
13
|
+
"family": "nonprofit-campaign"
|
|
12
14
|
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/** Harvested donor-derived theme wrapper — not installable until remaster gates pass. */
|
|
2
2
|
const THEME = {
|
|
3
3
|
"id": "theme.companions-site",
|
|
4
4
|
"slug": "companions-site",
|
|
5
|
+
"lineage": "coc",
|
|
6
|
+
"family": "nonprofit-campaign",
|
|
5
7
|
"displayName": "Companions of Caddo",
|
|
6
8
|
"version": "0.1.0",
|
|
7
9
|
"kind": "gallery-theme",
|
|
@@ -39,7 +41,7 @@ const THEME = {
|
|
|
39
41
|
"mobile": "/themes/companions-site/demo/",
|
|
40
42
|
"demoUrl": "/themes/companions-site/demo/"
|
|
41
43
|
},
|
|
42
|
-
"installable":
|
|
44
|
+
"installable": false,
|
|
43
45
|
"galleryPath": "apps/theme-gallery-preview/themes/companions-site",
|
|
44
46
|
"capabilityHints": [
|
|
45
47
|
"theme.storefront.shell"
|
|
@@ -68,7 +70,9 @@ export function createProductRow({ accountId = null, repositoryId = null, status
|
|
|
68
70
|
package_name: theme.package,
|
|
69
71
|
metadata: {
|
|
70
72
|
origin: "gallery_mount",
|
|
71
|
-
normalization_state: status === "production" ? "promoted" : "
|
|
73
|
+
normalization_state: status === "production" ? "promoted" : "needs_normalization",
|
|
74
|
+
lineage: theme.lineage,
|
|
75
|
+
family: theme.family,
|
|
72
76
|
package: theme.package,
|
|
73
77
|
gallery_path: theme.galleryPath,
|
|
74
78
|
preview_kind: theme.preview?.kind || "static",
|
|
@@ -2,10 +2,12 @@ import assert from 'node:assert/strict';
|
|
|
2
2
|
import test from 'node:test';
|
|
3
3
|
import { createTheme, createProductRow } from '../src/index.js';
|
|
4
4
|
|
|
5
|
-
test('companions-site theme package exports installable contract', () => {
|
|
5
|
+
test('companions-site theme package exports harvested (not installable) contract', () => {
|
|
6
6
|
const theme = createTheme();
|
|
7
7
|
assert.equal(theme.slug, "companions-site");
|
|
8
|
-
assert.equal(theme.installable,
|
|
8
|
+
assert.equal(theme.installable, false);
|
|
9
|
+
assert.equal(theme.lineage, "coc");
|
|
10
|
+
assert.equal(theme.family, "nonprofit-campaign");
|
|
9
11
|
assert.equal(theme.package, "@inneranimalmedia/theme-companions-site");
|
|
10
12
|
assert.ok(Array.isArray(theme.pages));
|
|
11
13
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name": "@inneranimalmedia/theme-
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Real Anything Floors & More public site
|
|
2
|
+
"name": "@inneranimalmedia/theme-grove",
|
|
3
|
+
"version": "2.6.7",
|
|
4
|
+
"description": "Real Anything Floors & More public site — services, gallery, process, and contact.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.js",
|
|
7
7
|
"exports": {
|
|
@@ -25,7 +25,18 @@
|
|
|
25
25
|
"kind": "theme",
|
|
26
26
|
"slug": "floors-site",
|
|
27
27
|
"galleryPath": "apps/theme-gallery-preview/themes/floors-site",
|
|
28
|
-
"installable":
|
|
29
|
-
"icon": "theme"
|
|
30
|
-
|
|
28
|
+
"installable": false,
|
|
29
|
+
"icon": "theme",
|
|
30
|
+
"lineage": "afm",
|
|
31
|
+
"family": "service-gallery",
|
|
32
|
+
"normalization": "canonical_id_assigned",
|
|
33
|
+
"canonicalId": "grove",
|
|
34
|
+
"legacyPackageName": "@inneranimalmedia/theme-floors-site"
|
|
35
|
+
},
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "git+https://github.com/SamPrimeaux/agentsam-sdk.git",
|
|
39
|
+
"directory": "packages/theme-floors-site"
|
|
40
|
+
},
|
|
41
|
+
"private": true
|
|
31
42
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"harvest_batch": "theme-harvest-20260924",
|
|
3
3
|
"app_path": "apps/floors-site",
|
|
4
4
|
"harvest_path": "work/theme-harvest/floors-site",
|
|
5
|
-
"status": "
|
|
5
|
+
"status": "needs_normalization",
|
|
6
6
|
"source_hash": "2244de43568a0bb08d7d3779971c1fc0c6c832c226a65c7bb4313e8ac039add8",
|
|
7
7
|
"capabilities": [
|
|
8
8
|
"cms.media",
|
|
@@ -10,5 +10,7 @@
|
|
|
10
10
|
"deploy.receipt",
|
|
11
11
|
"forms.leads",
|
|
12
12
|
"theme.storefront.shell"
|
|
13
|
-
]
|
|
13
|
+
],
|
|
14
|
+
"lineage": "afm",
|
|
15
|
+
"family": "service-gallery"
|
|
14
16
|
}
|