@1agh/maude 0.42.0 → 0.44.0
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/apps/studio/.ai/cache/_stats.json +7 -0
- package/apps/studio/acp/bootstrap-brief.ts +12 -2
- package/apps/studio/acp/bridge.ts +44 -10
- package/apps/studio/acp/env.ts +23 -0
- package/apps/studio/acp/login-state.ts +263 -0
- package/apps/studio/acp/plugin-bootstrap.ts +31 -25
- package/apps/studio/acp/probe.ts +152 -1
- package/apps/studio/annotations-layer.tsx +1451 -324
- package/apps/studio/annotations-model.ts +58 -0
- package/apps/studio/api.ts +568 -24
- package/apps/studio/bin/_audio-search.mjs +140 -0
- package/apps/studio/bin/_import-asset-pdf-worker.mjs +34 -0
- package/apps/studio/bin/_import-asset.mjs +815 -0
- package/apps/studio/bin/_import-brand.mjs +635 -0
- package/apps/studio/bin/_import-tokens-alias-resolver.mjs +95 -0
- package/apps/studio/bin/_import-tokens.mjs +1201 -0
- package/apps/studio/bin/_ingest-footage.mjs +386 -0
- package/apps/studio/bin/_probe-footage-playwright.mjs +269 -0
- package/apps/studio/bin/_transcribe.mjs +419 -0
- package/apps/studio/bin/_transcribe.test.mjs +80 -0
- package/apps/studio/bin/_video-playwright.mjs +141 -71
- package/apps/studio/bin/audio-search.sh +28 -0
- package/apps/studio/bin/generate.sh +154 -0
- package/apps/studio/bin/import-asset.sh +34 -0
- package/apps/studio/bin/import-brand.sh +29 -0
- package/apps/studio/bin/import-tokens.sh +33 -0
- package/apps/studio/bin/ingest-footage.sh +27 -0
- package/apps/studio/bin/photo-adjust.sh +163 -0
- package/apps/studio/bin/photo-bg-remove.sh +258 -0
- package/apps/studio/bin/probe-footage.sh +28 -0
- package/apps/studio/bin/read-annotations.mjs +125 -2
- package/apps/studio/bin/transcribe.sh +39 -0
- package/apps/studio/canvas-edit.ts +656 -12
- package/apps/studio/canvas-lib.tsx +637 -10
- package/apps/studio/canvas-pipeline.ts +65 -7
- package/apps/studio/canvas-shell.tsx +156 -16
- package/apps/studio/client/app.jsx +2385 -699
- package/apps/studio/client/export-center.jsx +35 -1
- package/apps/studio/client/generate-dialog.jsx +352 -0
- package/apps/studio/client/github.js +18 -0
- package/apps/studio/client/inspector-controls.jsx +781 -0
- package/apps/studio/client/panels/BrandUploadPanel.jsx +233 -0
- package/apps/studio/client/panels/ChatPanel.jsx +15 -33
- package/apps/studio/client/panels/GitPanel.jsx +8 -0
- package/apps/studio/client/panels/IntroVideoDialog.jsx +44 -0
- package/apps/studio/client/panels/OnboardingWizard.jsx +12 -0
- package/apps/studio/client/panels/ReadinessList.jsx +227 -7
- package/apps/studio/client/panels/RepoBranchSwitcher.jsx +133 -21
- package/apps/studio/client/panels/SettingsPanel.jsx +828 -0
- package/apps/studio/client/panels/SetupChecklist.jsx +223 -0
- package/apps/studio/client/panels/StickerPicker.jsx +160 -0
- package/apps/studio/client/panels/TimelinePanel.jsx +15 -2
- package/apps/studio/client/photo-knobs.jsx +432 -0
- package/apps/studio/client/styles/3-shell-maude.css +376 -28
- package/apps/studio/client/styles/4-components.css +223 -0
- package/apps/studio/client/styles/6-acp-chat.css +86 -0
- package/apps/studio/client/tour/quick-setup-tour.js +39 -0
- package/apps/studio/commands/annotation-strokes-command.ts +13 -3
- package/apps/studio/commands/edit-source-command.ts +31 -4
- package/apps/studio/config.schema.json +70 -0
- package/apps/studio/context-menu.tsx +42 -8
- package/apps/studio/context.ts +16 -0
- package/apps/studio/design-setup-readiness.ts +115 -0
- package/apps/studio/dist/client.bundle.js +5572 -21
- package/apps/studio/dist/comment-mount.js +2 -2
- package/apps/studio/dist/runtime/.min-sizes.json +1 -0
- package/apps/studio/dist/runtime/@imgly_background-removal.js +5543 -0
- package/apps/studio/dist/runtime/pixi-js.js +519 -519
- package/apps/studio/dist/styles.css +1 -1
- package/apps/studio/dom-selection.ts +25 -0
- package/apps/studio/draw/palette.ts +34 -0
- package/apps/studio/exporters/jobs.ts +47 -5
- package/apps/studio/exporters/video.ts +24 -4
- package/apps/studio/footage/schema.test.ts +287 -0
- package/apps/studio/footage/schema.ts +662 -0
- package/apps/studio/footage-store.ts +235 -0
- package/apps/studio/fs-watch.ts +10 -0
- package/apps/studio/generation/adapters/elevenlabs.ts +370 -0
- package/apps/studio/generation/adapters/gemini.ts +542 -0
- package/apps/studio/generation/adapters/groq.test.ts +80 -0
- package/apps/studio/generation/adapters/groq.ts +247 -0
- package/apps/studio/generation/audio-library.test.ts +95 -0
- package/apps/studio/generation/audio-library.ts +156 -0
- package/apps/studio/generation/captions.test.ts +78 -0
- package/apps/studio/generation/captions.ts +132 -0
- package/apps/studio/generation/download.ts +76 -0
- package/apps/studio/generation/elevenlabs.test.ts +223 -0
- package/apps/studio/generation/gemini.test.ts +350 -0
- package/apps/studio/generation/jobs.test.ts +128 -0
- package/apps/studio/generation/jobs.ts +243 -0
- package/apps/studio/generation/keys.test.ts +75 -0
- package/apps/studio/generation/keys.ts +162 -0
- package/apps/studio/generation/prefs.test.ts +95 -0
- package/apps/studio/generation/prefs.ts +82 -0
- package/apps/studio/generation/registry.ts +88 -0
- package/apps/studio/generation/types.test.ts +123 -0
- package/apps/studio/generation/types.ts +266 -0
- package/apps/studio/generation/whisper-models.test.ts +152 -0
- package/apps/studio/generation/whisper-models.ts +257 -0
- package/apps/studio/generation/whisper-spike-results.md +61 -0
- package/apps/studio/git/endpoints.ts +68 -7
- package/apps/studio/git/service.ts +199 -21
- package/apps/studio/github/service.ts +67 -0
- package/apps/studio/handoff.ts +3 -2
- package/apps/studio/http.ts +1039 -22
- package/apps/studio/input-router.tsx +10 -0
- package/apps/studio/inspect.ts +53 -1
- package/apps/studio/media/intro.mp4 +0 -0
- package/apps/studio/media-commit-chain.ts +119 -0
- package/apps/studio/paths.ts +20 -0
- package/apps/studio/photo/filters.ts +285 -0
- package/apps/studio/photo/pipeline.ts +607 -0
- package/apps/studio/photo/schema.ts +367 -0
- package/apps/studio/photo-store.ts +154 -0
- package/apps/studio/readiness.ts +108 -20
- package/apps/studio/runtime-bundle.ts +29 -6
- package/apps/studio/scaffold-design.ts +1145 -0
- package/apps/studio/server.ts +18 -2
- package/apps/studio/stickers/figjam-doodle/manifest.json +104 -0
- package/apps/studio/stickers/figjam-doodle/slice1.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice10.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice11.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice12.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice13.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice14.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice15.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice16.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice17.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice18.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice19.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice2.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice20.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice21.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice22.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice23.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice24.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice3.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice4.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice5.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice6.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice7.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice8.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice9.png +0 -0
- package/apps/studio/stickers/life-style/best.png +0 -0
- package/apps/studio/stickers/life-style/come-on.png +0 -0
- package/apps/studio/stickers/life-style/cut.png +0 -0
- package/apps/studio/stickers/life-style/detox.png +0 -0
- package/apps/studio/stickers/life-style/just.png +0 -0
- package/apps/studio/stickers/life-style/manifest.json +68 -0
- package/apps/studio/stickers/life-style/mirror.png +0 -0
- package/apps/studio/stickers/life-style/nice.png +0 -0
- package/apps/studio/stickers/life-style/objects.png +0 -0
- package/apps/studio/stickers/life-style/ok.png +0 -0
- package/apps/studio/stickers/life-style/queen.png +0 -0
- package/apps/studio/stickers/life-style/star.png +0 -0
- package/apps/studio/stickers/life-style/sun.png +0 -0
- package/apps/studio/stickers/life-style/water.png +0 -0
- package/apps/studio/stickers/life-style/yeah.png +0 -0
- package/apps/studio/stickers/life-style/you-can.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/check-the-deets.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/cut-it.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/dope.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/fresh.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/hot.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/idea.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/keep-exploring.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/killed-it.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/love-it.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/manifest.json +88 -0
- package/apps/studio/stickers/opposing-thoughts/not-sure.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/ok.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/pure-gold.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/save-for-later.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/steal-this.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/take-a-peek.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/this-or-that.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/thoughts.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/vibes.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/winner.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/wip.png +0 -0
- package/apps/studio/stickers/project-status/group-100.png +0 -0
- package/apps/studio/stickers/project-status/group-101.png +0 -0
- package/apps/studio/stickers/project-status/group-102.png +0 -0
- package/apps/studio/stickers/project-status/group-103.png +0 -0
- package/apps/studio/stickers/project-status/group-104.png +0 -0
- package/apps/studio/stickers/project-status/group-105.png +0 -0
- package/apps/studio/stickers/project-status/group-106.png +0 -0
- package/apps/studio/stickers/project-status/group-107.png +0 -0
- package/apps/studio/stickers/project-status/group-108.png +0 -0
- package/apps/studio/stickers/project-status/group-109.png +0 -0
- package/apps/studio/stickers/project-status/group-110.png +0 -0
- package/apps/studio/stickers/project-status/group-111.png +0 -0
- package/apps/studio/stickers/project-status/group-112.png +0 -0
- package/apps/studio/stickers/project-status/group-113.png +0 -0
- package/apps/studio/stickers/project-status/group-114.png +0 -0
- package/apps/studio/stickers/project-status/group-115.png +0 -0
- package/apps/studio/stickers/project-status/group-117.png +0 -0
- package/apps/studio/stickers/project-status/group-118.png +0 -0
- package/apps/studio/stickers/project-status/group-119.png +0 -0
- package/apps/studio/stickers/project-status/group-120.png +0 -0
- package/apps/studio/stickers/project-status/group-121.png +0 -0
- package/apps/studio/stickers/project-status/group-122.png +0 -0
- package/apps/studio/stickers/project-status/group-41.png +0 -0
- package/apps/studio/stickers/project-status/group-42.png +0 -0
- package/apps/studio/stickers/project-status/group-43.png +0 -0
- package/apps/studio/stickers/project-status/group-44.png +0 -0
- package/apps/studio/stickers/project-status/group-45.png +0 -0
- package/apps/studio/stickers/project-status/group-46.png +0 -0
- package/apps/studio/stickers/project-status/group-47.png +0 -0
- package/apps/studio/stickers/project-status/group-48.png +0 -0
- package/apps/studio/stickers/project-status/group-49.png +0 -0
- package/apps/studio/stickers/project-status/group-50.png +0 -0
- package/apps/studio/stickers/project-status/group-51.png +0 -0
- package/apps/studio/stickers/project-status/group-52.png +0 -0
- package/apps/studio/stickers/project-status/group-53.png +0 -0
- package/apps/studio/stickers/project-status/group-54.png +0 -0
- package/apps/studio/stickers/project-status/group-55.png +0 -0
- package/apps/studio/stickers/project-status/group-56.png +0 -0
- package/apps/studio/stickers/project-status/group-57.png +0 -0
- package/apps/studio/stickers/project-status/group-58.png +0 -0
- package/apps/studio/stickers/project-status/group-59.png +0 -0
- package/apps/studio/stickers/project-status/group-60.png +0 -0
- package/apps/studio/stickers/project-status/group-61.png +0 -0
- package/apps/studio/stickers/project-status/group-62.png +0 -0
- package/apps/studio/stickers/project-status/group-63.png +0 -0
- package/apps/studio/stickers/project-status/group-64.png +0 -0
- package/apps/studio/stickers/project-status/group-65.png +0 -0
- package/apps/studio/stickers/project-status/group-66.png +0 -0
- package/apps/studio/stickers/project-status/group-67.png +0 -0
- package/apps/studio/stickers/project-status/group-68.png +0 -0
- package/apps/studio/stickers/project-status/group-69.png +0 -0
- package/apps/studio/stickers/project-status/group-70.png +0 -0
- package/apps/studio/stickers/project-status/group-71.png +0 -0
- package/apps/studio/stickers/project-status/group-72.png +0 -0
- package/apps/studio/stickers/project-status/group-73.png +0 -0
- package/apps/studio/stickers/project-status/group-74.png +0 -0
- package/apps/studio/stickers/project-status/group-75.png +0 -0
- package/apps/studio/stickers/project-status/group-76.png +0 -0
- package/apps/studio/stickers/project-status/group-77.png +0 -0
- package/apps/studio/stickers/project-status/group-78.png +0 -0
- package/apps/studio/stickers/project-status/group-79.png +0 -0
- package/apps/studio/stickers/project-status/group-80.png +0 -0
- package/apps/studio/stickers/project-status/group-81.png +0 -0
- package/apps/studio/stickers/project-status/group-82.png +0 -0
- package/apps/studio/stickers/project-status/group-83.png +0 -0
- package/apps/studio/stickers/project-status/group-84.png +0 -0
- package/apps/studio/stickers/project-status/group-85.png +0 -0
- package/apps/studio/stickers/project-status/group-86.png +0 -0
- package/apps/studio/stickers/project-status/group-87.png +0 -0
- package/apps/studio/stickers/project-status/group-88.png +0 -0
- package/apps/studio/stickers/project-status/group-89.png +0 -0
- package/apps/studio/stickers/project-status/group-90.png +0 -0
- package/apps/studio/stickers/project-status/group-91.png +0 -0
- package/apps/studio/stickers/project-status/group-92.png +0 -0
- package/apps/studio/stickers/project-status/group-93.png +0 -0
- package/apps/studio/stickers/project-status/group-94.png +0 -0
- package/apps/studio/stickers/project-status/group-96.png +0 -0
- package/apps/studio/stickers/project-status/group-97.png +0 -0
- package/apps/studio/stickers/project-status/group-98.png +0 -0
- package/apps/studio/stickers/project-status/group-99.png +0 -0
- package/apps/studio/stickers/project-status/manifest.json +328 -0
- package/apps/studio/test/_helpers.ts +15 -2
- package/apps/studio/test/acp-bootstrap-brief.test.ts +11 -0
- package/apps/studio/test/acp-bridge.test.ts +34 -1
- package/apps/studio/test/acp-commands.test.ts +2 -1
- package/apps/studio/test/acp-env.test.ts +30 -0
- package/apps/studio/test/acp-plugin-bootstrap.test.ts +23 -57
- package/apps/studio/test/acp-session-plugins.test.ts +72 -1
- package/apps/studio/test/annotation-strokes-command.test.ts +17 -0
- package/apps/studio/test/annotations-layer.test.ts +174 -0
- package/apps/studio/test/asset-api.test.ts +3 -3
- package/apps/studio/test/canvas-edit.test.ts +17 -6
- package/apps/studio/test/canvas-origin-gate.test.ts +50 -0
- package/apps/studio/test/csp-canvas-shell.test.ts +11 -0
- package/apps/studio/test/csrf-write-guard.test.ts +23 -1
- package/apps/studio/test/design-setup-readiness.test.ts +155 -0
- package/apps/studio/test/dynamic-text-edit.test.ts +162 -0
- package/apps/studio/test/edit-source-command.test.ts +23 -0
- package/apps/studio/test/element-structural-edit.test.ts +154 -0
- package/apps/studio/test/fixtures/fake-claude-auth.mjs +13 -0
- package/apps/studio/test/footage-store.test.ts +100 -0
- package/apps/studio/test/generate-route.test.ts +106 -0
- package/apps/studio/test/git-branches.test.ts +97 -0
- package/apps/studio/test/github-api.test.ts +56 -1
- package/apps/studio/test/import-asset-browser.test.ts +64 -0
- package/apps/studio/test/import-asset-route.test.ts +71 -0
- package/apps/studio/test/import-asset.test.ts +399 -0
- package/apps/studio/test/import-brand-browser.test.ts +88 -0
- package/apps/studio/test/import-brand-route.test.ts +120 -0
- package/apps/studio/test/import-brand.test.ts +206 -0
- package/apps/studio/test/import-tokens.test.ts +722 -0
- package/apps/studio/test/input-router.test.ts +33 -0
- package/apps/studio/test/inspect-script-syntax.test.ts +53 -0
- package/apps/studio/test/media-commit-chain.test.ts +210 -0
- package/apps/studio/test/photo-bg-remove-validation.test.ts +71 -0
- package/apps/studio/test/photo-canvas-bundle.test.ts +61 -0
- package/apps/studio/test/photo-edit-api.test.ts +201 -0
- package/apps/studio/test/photo-filters.test.ts +149 -0
- package/apps/studio/test/photo-pipeline.test.ts +106 -0
- package/apps/studio/test/photo-taxonomy.test.ts +96 -0
- package/apps/studio/test/read-annotations.test.ts +164 -0
- package/apps/studio/test/readiness.test.ts +13 -11
- package/apps/studio/test/scaffold-design.test.ts +122 -0
- package/apps/studio/test/shell-importmap.test.ts +49 -0
- package/apps/studio/test/text-editability-stamp.test.ts +131 -0
- package/apps/studio/test/timeline-parse.test.ts +57 -0
- package/apps/studio/test/tool-palette-insert-anchor.test.ts +5 -3
- package/apps/studio/test/tour-overlay.test.tsx +16 -0
- package/apps/studio/test/undo-stack.test.ts +33 -0
- package/apps/studio/test/video-asset.test.ts +5 -5
- package/apps/studio/test/video-render-bridge.test.ts +23 -1
- package/apps/studio/text-caret.ts +239 -0
- package/apps/studio/tool-palette.tsx +49 -21
- package/apps/studio/ui-prefs.ts +130 -0
- package/apps/studio/undo-stack.ts +94 -2
- package/apps/studio/use-annotation-resize.tsx +4 -4
- package/apps/studio/use-canvas-media-drop.tsx +40 -1
- package/apps/studio/use-chrome-visibility.tsx +8 -2
- package/apps/studio/use-selection-set.tsx +21 -0
- package/apps/studio/video-comp.tsx +48 -7
- package/apps/studio/whats-new.json +149 -0
- package/apps/studio/ws.ts +5 -0
- package/cli/bin/maude.mjs +6 -6
- package/cli/commands/design.mjs +67 -3
- package/cli/lib/gitignore-block.mjs +2 -0
- package/cli/lib/pkg-root.mjs +107 -0
- package/cli/lib/pkg-root.test.mjs +79 -0
- package/cli/lib/reconstruct-toolset.test.mjs +194 -0
- package/cli/lib/update-check.mjs +8 -0
- package/package.json +13 -11
- package/plugins/design/dependencies.json +18 -0
- package/plugins/design/templates/_shell.html +1 -0
package/apps/studio/acp/probe.ts
CHANGED
|
@@ -6,10 +6,12 @@
|
|
|
6
6
|
// native shell ships the apps/studio source tree (with node_modules), so the
|
|
7
7
|
// adapter resolves on disk there.
|
|
8
8
|
|
|
9
|
+
import { createHash } from 'node:crypto';
|
|
9
10
|
import { existsSync, readFileSync, realpathSync } from 'node:fs';
|
|
10
11
|
import { dirname, join } from 'node:path';
|
|
11
12
|
|
|
12
13
|
import { DEV_SERVER_ROOT } from '../paths.ts';
|
|
14
|
+
import { scrubAgentEnv } from './env.ts';
|
|
13
15
|
|
|
14
16
|
/** Adapter npm package — the renamed continuation of `@zed-industries/claude-code-acp`. */
|
|
15
17
|
const ADAPTER_PKG = '@agentclientprotocol/claude-agent-acp';
|
|
@@ -64,13 +66,91 @@ export function resolveAdapterEntry(): string | null {
|
|
|
64
66
|
return null;
|
|
65
67
|
}
|
|
66
68
|
|
|
69
|
+
/**
|
|
70
|
+
* Content pin for a Maude-auto-provisioned `MAUDE_CLAUDE_BIN` override
|
|
71
|
+
* (DDR-166 T0c, `installClaudeCli()` in `login-state.ts` is the only writer).
|
|
72
|
+
*
|
|
73
|
+
* Second-round security-review finding against the first cut of this file:
|
|
74
|
+
* checking only `existsSync(override)` on every call meant that once a
|
|
75
|
+
* freshly-installed binary passed its one-time freshness check, the PATH
|
|
76
|
+
* override was trusted **forever** for the rest of this long-lived process —
|
|
77
|
+
* a same-UID attacker who swapped the file's *content* at any later point in
|
|
78
|
+
* the session (the install-flow one-time check does not repeat) got the
|
|
79
|
+
* exact "durable, silent MITM over every future chat spawn" blast radius the
|
|
80
|
+
* original cached-artifact design was rejected for, just reached through a
|
|
81
|
+
* different door. Path existence is not authenticity.
|
|
82
|
+
*
|
|
83
|
+
* The fix: pin the SHA-256 captured at verified-install time, and re-hash
|
|
84
|
+
* UNCONDITIONALLY on every resolution — no mtime-based caching shortcut.
|
|
85
|
+
*
|
|
86
|
+
* A third-round review finding against the first cut of this fix: an
|
|
87
|
+
* earlier draft cached the hash result keyed on mtime ("skip the re-hash if
|
|
88
|
+
* mtime is unchanged since the last verified read") as a performance
|
|
89
|
+
* optimization. That cache is trivially forgeable by the EXACT SAME attacker
|
|
90
|
+
* the fix exists to stop: swapping the file's content costs them nothing
|
|
91
|
+
* beyond a `touch -d <original-mtime>` immediately after, at zero additional
|
|
92
|
+
* privilege — same-UID write access to the file is already required for the
|
|
93
|
+
* swap itself, and mtime is neither secret nor tamper-evident (`utimensat`
|
|
94
|
+
* sets it with nanosecond precision, not a race against clock granularity).
|
|
95
|
+
* The cache silently reopened the exact "durable, silent MITM over every
|
|
96
|
+
* future chat spawn" blast radius the whole fix exists to close.
|
|
97
|
+
*
|
|
98
|
+
* The "don't re-hash on every 1.5s readiness-poll tick" concern that
|
|
99
|
+
* motivated the cache doesn't actually hold: readiness polling
|
|
100
|
+
* (`useReadiness` in `ReadinessList.jsx`) only runs while the panel is
|
|
101
|
+
* DISCONNECTED — i.e., only during the bounded, actively-supervised
|
|
102
|
+
* install/sign-in flow itself, not for the lifetime of a long session. Once
|
|
103
|
+
* connected, nothing polls `/_api/preflight` on an interval. A live-measured
|
|
104
|
+
* SHA-256 pass over the actual ~241 MB installed `claude` binary took
|
|
105
|
+
* ~116 ms — cheap enough to simply always pay, especially since the other
|
|
106
|
+
* caller that matters (a fresh chat-session spawn, once per session) has no
|
|
107
|
+
* latency budget concern at all.
|
|
108
|
+
*/
|
|
109
|
+
let trustedBin: { path: string; sha256: string } | null = null;
|
|
110
|
+
|
|
111
|
+
/** Called only by `installClaudeCli()` after its own freshness check passes. */
|
|
112
|
+
export function setTrustedClaudeBin(path: string, sha256: string): void {
|
|
113
|
+
trustedBin = { path, sha256 };
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function hashFile(path: string): string | null {
|
|
117
|
+
try {
|
|
118
|
+
return createHash('sha256').update(readFileSync(path)).digest('hex');
|
|
119
|
+
} catch {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** True iff `path` is either not a Maude-provisioned override (nothing to pin) or its content still matches the pinned hash — re-hashed every call, deliberately no caching shortcut (see doc comment above). */
|
|
125
|
+
function contentStillTrusted(path: string): boolean {
|
|
126
|
+
if (!trustedBin || trustedBin.path !== path) return true; // not our concern — e.g. a user-set override
|
|
127
|
+
return hashFile(path) === trustedBin.sha256;
|
|
128
|
+
}
|
|
129
|
+
|
|
67
130
|
/**
|
|
68
131
|
* Absolute path to the user's installed `claude` CLI, or null. Honors a
|
|
69
132
|
* `MAUDE_CLAUDE_BIN` override; otherwise looks it up on PATH.
|
|
70
133
|
*/
|
|
71
134
|
export function resolveClaudePath(): string | null {
|
|
135
|
+
// An explicit, content-pinned `MAUDE_CLAUDE_BIN` override is checked FIRST
|
|
136
|
+
// and always wins — including over the E2E force-missing stub below. This
|
|
137
|
+
// matters for the desktop-e2e `acp-cold-start` scenario (T0f): it starts
|
|
138
|
+
// with MAUDE_E2E_FORCE_CLAUDE_STATUS=missing to simulate a machine with no
|
|
139
|
+
// `claude` on PATH, then drives the real T0c install flow, which sets THIS
|
|
140
|
+
// override once its own freshness+hash verification passes
|
|
141
|
+
// (login-state.ts's setTrustedClaudeBin). A coarse "simulate absent" test
|
|
142
|
+
// stub must not out-rank a just-verified, explicitly-provisioned install —
|
|
143
|
+
// that would make the guided install flow untestable end-to-end.
|
|
72
144
|
const override = process.env.MAUDE_CLAUDE_BIN;
|
|
73
|
-
if (override)
|
|
145
|
+
if (override) {
|
|
146
|
+
if (!existsSync(override)) return null;
|
|
147
|
+
if (!contentStillTrusted(override)) return null;
|
|
148
|
+
return override;
|
|
149
|
+
}
|
|
150
|
+
// DDR-166 — deterministic E2E stub (mirrors MAUDE_E2E_FAKE_GITHUB_LOGIN in
|
|
151
|
+
// oauth.rs), simulating a machine where `claude` is absent from PATH.
|
|
152
|
+
// Never set in a normal launch.
|
|
153
|
+
if (process.env.MAUDE_E2E_FORCE_CLAUDE_STATUS === 'missing') return null;
|
|
74
154
|
return Bun.which('claude');
|
|
75
155
|
}
|
|
76
156
|
|
|
@@ -110,3 +190,74 @@ export function probeAcpAvailability(): AcpAvailability {
|
|
|
110
190
|
}
|
|
111
191
|
return { available: true, adapterEntry, claudePath };
|
|
112
192
|
}
|
|
193
|
+
|
|
194
|
+
export interface ClaudeAuthStatus {
|
|
195
|
+
loggedIn: boolean;
|
|
196
|
+
/** 'firstParty' = claude.ai subscription. Anything else may mean API billing. */
|
|
197
|
+
apiProvider?: string;
|
|
198
|
+
subscriptionType?: string;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Shells `claude auth status --json` and narrows the result to only the fields
|
|
203
|
+
* ever trusted/exposed here. `email`/`orgId`/`orgName` are deliberately dropped
|
|
204
|
+
* on read — never forwarded to a caller, never logged (security review finding:
|
|
205
|
+
* raw-stdout-to-log is a real habit elsewhere in this codebase; the fix is to
|
|
206
|
+
* never let the raw payload exist past this function).
|
|
207
|
+
*/
|
|
208
|
+
export async function getClaudeAuthStatus(): Promise<ClaudeAuthStatus | null> {
|
|
209
|
+
const bin = resolveClaudePath();
|
|
210
|
+
if (!bin) return null;
|
|
211
|
+
try {
|
|
212
|
+
const proc = Bun.spawn([bin, 'auth', 'status', '--json'], {
|
|
213
|
+
env: scrubAgentEnv(),
|
|
214
|
+
stdout: 'pipe',
|
|
215
|
+
stderr: 'ignore',
|
|
216
|
+
});
|
|
217
|
+
const timeout = setTimeout(() => proc.kill(), 5000);
|
|
218
|
+
const out = await new Response(proc.stdout).text();
|
|
219
|
+
await proc.exited;
|
|
220
|
+
clearTimeout(timeout);
|
|
221
|
+
const parsed: unknown = JSON.parse(out);
|
|
222
|
+
if (typeof parsed !== 'object' || parsed === null) return null;
|
|
223
|
+
const p = parsed as Record<string, unknown>;
|
|
224
|
+
return {
|
|
225
|
+
loggedIn: !!p.loggedIn,
|
|
226
|
+
apiProvider: typeof p.apiProvider === 'string' ? p.apiProvider : undefined,
|
|
227
|
+
subscriptionType: typeof p.subscriptionType === 'string' ? p.subscriptionType : undefined,
|
|
228
|
+
};
|
|
229
|
+
} catch {
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* The fuller availability check backing `GET /_api/acp/status` — the ONE
|
|
236
|
+
* signal the ChatPanel UI's connected/not-connected gate actually watches
|
|
237
|
+
* (`probeStatus()` in ChatPanel.jsx). Adds a real sign-in check on top of
|
|
238
|
+
* {@link probeAcpAvailability}'s cheap adapter+path probe.
|
|
239
|
+
*
|
|
240
|
+
* Security-review-grade bug found while building the T0f `acp-cold-start`
|
|
241
|
+
* desktop-e2e scenario: `probeAcpAvailability()` alone reports `available:
|
|
242
|
+
* true` the moment `claude` is INSTALLED, before the user has signed in —
|
|
243
|
+
* exactly the "logged-out-but-installed reads as available" failure mode
|
|
244
|
+
* T0d's own validation criteria calls out by name. Deliberately a SEPARATE
|
|
245
|
+
* function rather than changing `probeAcpAvailability()` itself: that one
|
|
246
|
+
* also backs the WS `onOpen` ready frame (cheap, no subprocess spawn on every
|
|
247
|
+
* socket open) and has an existing test contract (`acp-bridge.test.ts`)
|
|
248
|
+
* treating "a resolvable binary" as sufficient — this is the one call site
|
|
249
|
+
* that needs the fuller, auth-checked answer.
|
|
250
|
+
*/
|
|
251
|
+
export async function probeAcpAvailabilityAuthed(): Promise<AcpAvailability> {
|
|
252
|
+
const base = probeAcpAvailability();
|
|
253
|
+
if (!base.available) return base;
|
|
254
|
+
const authStatus = await getClaudeAuthStatus();
|
|
255
|
+
if (!authStatus?.loggedIn) {
|
|
256
|
+
return {
|
|
257
|
+
...base,
|
|
258
|
+
available: false,
|
|
259
|
+
reason: 'Claude Code is installed but not signed in — sign in to connect.',
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
return base;
|
|
263
|
+
}
|