@agent-native/core 0.98.1 → 0.98.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/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +18 -0
- package/corpus/core/docs/content/locales/ar-SA/pr-visual-recap.mdx +25 -1
- package/corpus/core/docs/content/locales/ar-SA/template-plan.mdx +1 -1
- package/corpus/core/docs/content/locales/de-DE/pr-visual-recap.mdx +25 -1
- package/corpus/core/docs/content/locales/de-DE/template-plan.mdx +1 -1
- package/corpus/core/docs/content/locales/es-ES/pr-visual-recap.mdx +25 -1
- package/corpus/core/docs/content/locales/es-ES/template-plan.mdx +1 -1
- package/corpus/core/docs/content/locales/fr-FR/pr-visual-recap.mdx +25 -1
- package/corpus/core/docs/content/locales/fr-FR/template-plan.mdx +1 -1
- package/corpus/core/docs/content/locales/hi-IN/pr-visual-recap.mdx +25 -1
- package/corpus/core/docs/content/locales/hi-IN/template-plan.mdx +1 -1
- package/corpus/core/docs/content/locales/ja-JP/pr-visual-recap.mdx +25 -1
- package/corpus/core/docs/content/locales/ja-JP/template-plan.mdx +1 -1
- package/corpus/core/docs/content/locales/ko-KR/pr-visual-recap.mdx +25 -1
- package/corpus/core/docs/content/locales/ko-KR/template-plan.mdx +1 -1
- package/corpus/core/docs/content/locales/pt-BR/pr-visual-recap.mdx +25 -1
- package/corpus/core/docs/content/locales/pt-BR/template-plan.mdx +1 -1
- package/corpus/core/docs/content/locales/zh-CN/pr-visual-recap.mdx +25 -1
- package/corpus/core/docs/content/locales/zh-CN/template-plan.mdx +1 -1
- package/corpus/core/docs/content/locales/zh-TW/pr-visual-recap.mdx +25 -1
- package/corpus/core/docs/content/locales/zh-TW/template-plan.mdx +1 -1
- package/corpus/core/docs/content/pr-visual-recap.mdx +50 -1
- package/corpus/core/docs/content/template-plan.mdx +1 -1
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/agent/production-agent.ts +2 -2
- package/corpus/core/src/cli/plan-local.ts +43 -11
- package/corpus/core/src/cli/pr-visual-recap-workflow.ts +2 -9
- package/corpus/core/src/cli/recap.ts +356 -4
- package/corpus/core/src/cli/skills-content/local-files.ts +17 -12
- package/corpus/core/src/client/analytics.ts +96 -14
- package/corpus/core/src/client/index.ts +7 -0
- package/corpus/core/src/client/session-replay.ts +10 -0
- package/corpus/core/src/client/settings/DemoModeSection.tsx +10 -34
- package/corpus/core/src/client/settings/SettingsPanel.tsx +31 -211
- package/corpus/core/src/client/settings/agent-settings-search.ts +219 -0
- package/corpus/core/src/client/settings/index.ts +4 -0
- package/corpus/core/src/client/url-scrub.ts +13 -0
- package/corpus/core/src/client/use-demo-mode-status.ts +44 -0
- package/corpus/core/src/demo/actions/toggle-demo-mode.ts +2 -2
- package/corpus/core/src/demo/config.ts +6 -6
- package/corpus/core/src/demo/redact.ts +18 -76
- package/corpus/templates/analytics/.agents/skills/session-replay/SKILL.md +21 -4
- package/corpus/templates/analytics/AGENTS.md +8 -0
- package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +18 -4
- package/corpus/templates/analytics/app/components/layout/CommandPalette.tsx +429 -244
- package/corpus/templates/analytics/app/components/layout/command-palette-search.ts +93 -0
- package/corpus/templates/analytics/app/hooks/use-replay-storage-status.ts +2 -1
- package/corpus/templates/analytics/app/lib/demo-chart-trend.ts +169 -0
- package/corpus/templates/analytics/app/pages/Settings.tsx +8 -45
- package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +205 -70
- package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +32 -16
- package/corpus/templates/analytics/app/pages/settings/settings-search.ts +126 -0
- package/corpus/templates/analytics/changelog/2026-07-12-command-menu-loading-placeholders-now-stay-below-available-r.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-12-command-menu-search-now-prioritizes-the-best-match.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-12-daily-dashboard-emails-reliably-include-the-complete-dashboa.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-12-demo-charts-preserve-source-movement.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-12-demo-mode-charts-trend-upward.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-12-replay-storage-settings-stay-readable-at-narrow-widths.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-12-session-replays-preserve-recorded-styling-and-keep-malformed.md +6 -0
- package/corpus/templates/analytics/server/jobs/dashboard-report.ts +2 -0
- package/corpus/templates/analytics/server/lib/dashboard-report.ts +17 -33
- package/corpus/templates/clips/app/components/player/video-player.tsx +5 -1
- package/corpus/templates/clips/changelog/2026-07-11-clips-no-longer-stay-stuck-on-preparing-clip-when-they-are-r.md +6 -0
- package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +2 -2
- package/corpus/templates/content/changelog/2026-07-12-the-left-sidebar-stays-fixed-horizontally-while-scrolling-on.md +6 -0
- package/corpus/templates/plan/.agents/skills/visual-plan/references/local-files.md +17 -12
- package/corpus/templates/plan/.agents/skills/visual-recap/references/local-files.md +17 -12
- package/corpus/templates/plan/actions/validate-local-plan-source.ts +4 -4
- package/corpus/templates/plan/app/components/layout/Sidebar.tsx +2 -1
- package/corpus/templates/plan/app/lib/plan-local-bridge.ts +41 -0
- package/corpus/templates/plan/app/lib/plan-tracking.ts +3 -0
- package/corpus/templates/plan/app/pages/PlansPage.tsx +9 -9
- package/corpus/templates/plan/app/root.tsx +13 -3
- package/corpus/templates/plan/changelog/2026-07-12-local-plan-source-now-stays-on-device.md +6 -0
- package/dist/agent/production-agent.js +2 -2
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/cli/plan-local.d.ts +6 -6
- package/dist/cli/plan-local.d.ts.map +1 -1
- package/dist/cli/plan-local.js +36 -7
- package/dist/cli/plan-local.js.map +1 -1
- package/dist/cli/pr-visual-recap-workflow.d.ts +2 -8
- package/dist/cli/pr-visual-recap-workflow.d.ts.map +1 -1
- package/dist/cli/pr-visual-recap-workflow.js +2 -8
- package/dist/cli/pr-visual-recap-workflow.js.map +1 -1
- package/dist/cli/recap.d.ts +22 -1
- package/dist/cli/recap.d.ts.map +1 -1
- package/dist/cli/recap.js +286 -2
- package/dist/cli/recap.js.map +1 -1
- package/dist/cli/skills-content/local-files.d.ts +1 -1
- package/dist/cli/skills-content/local-files.d.ts.map +1 -1
- package/dist/cli/skills-content/local-files.js +17 -12
- package/dist/cli/skills-content/local-files.js.map +1 -1
- package/dist/client/analytics.d.ts +8 -0
- package/dist/client/analytics.d.ts.map +1 -1
- package/dist/client/analytics.js +77 -13
- package/dist/client/analytics.js.map +1 -1
- package/dist/client/index.d.ts +3 -2
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +3 -2
- package/dist/client/index.js.map +1 -1
- package/dist/client/session-replay.d.ts +2 -0
- package/dist/client/session-replay.d.ts.map +1 -1
- package/dist/client/session-replay.js +7 -0
- package/dist/client/session-replay.js.map +1 -1
- package/dist/client/settings/DemoModeSection.d.ts +3 -3
- package/dist/client/settings/DemoModeSection.d.ts.map +1 -1
- package/dist/client/settings/DemoModeSection.js +8 -27
- package/dist/client/settings/DemoModeSection.js.map +1 -1
- package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
- package/dist/client/settings/SettingsPanel.js +41 -191
- package/dist/client/settings/SettingsPanel.js.map +1 -1
- package/dist/client/settings/agent-settings-search.d.ts +16 -0
- package/dist/client/settings/agent-settings-search.d.ts.map +1 -0
- package/dist/client/settings/agent-settings-search.js +178 -0
- package/dist/client/settings/agent-settings-search.js.map +1 -0
- package/dist/client/settings/index.d.ts +1 -0
- package/dist/client/settings/index.d.ts.map +1 -1
- package/dist/client/settings/index.js +1 -0
- package/dist/client/settings/index.js.map +1 -1
- package/dist/client/url-scrub.d.ts.map +1 -1
- package/dist/client/url-scrub.js +14 -0
- package/dist/client/url-scrub.js.map +1 -1
- package/dist/client/use-demo-mode-status.d.ts +12 -0
- package/dist/client/use-demo-mode-status.d.ts.map +1 -0
- package/dist/client/use-demo-mode-status.js +30 -0
- package/dist/client/use-demo-mode-status.js.map +1 -0
- package/dist/collab/routes.d.ts +2 -2
- package/dist/demo/actions/toggle-demo-mode.js +2 -2
- package/dist/demo/actions/toggle-demo-mode.js.map +1 -1
- package/dist/demo/config.js +6 -6
- package/dist/demo/config.js.map +1 -1
- package/dist/demo/redact.d.ts +7 -5
- package/dist/demo/redact.d.ts.map +1 -1
- package/dist/demo/redact.js +19 -54
- package/dist/demo/redact.js.map +1 -1
- package/dist/notifications/routes.d.ts +2 -2
- package/dist/observability/routes.d.ts +5 -5
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/docs/content/locales/ar-SA/pr-visual-recap.mdx +25 -1
- package/docs/content/locales/ar-SA/template-plan.mdx +1 -1
- package/docs/content/locales/de-DE/pr-visual-recap.mdx +25 -1
- package/docs/content/locales/de-DE/template-plan.mdx +1 -1
- package/docs/content/locales/es-ES/pr-visual-recap.mdx +25 -1
- package/docs/content/locales/es-ES/template-plan.mdx +1 -1
- package/docs/content/locales/fr-FR/pr-visual-recap.mdx +25 -1
- package/docs/content/locales/fr-FR/template-plan.mdx +1 -1
- package/docs/content/locales/hi-IN/pr-visual-recap.mdx +25 -1
- package/docs/content/locales/hi-IN/template-plan.mdx +1 -1
- package/docs/content/locales/ja-JP/pr-visual-recap.mdx +25 -1
- package/docs/content/locales/ja-JP/template-plan.mdx +1 -1
- package/docs/content/locales/ko-KR/pr-visual-recap.mdx +25 -1
- package/docs/content/locales/ko-KR/template-plan.mdx +1 -1
- package/docs/content/locales/pt-BR/pr-visual-recap.mdx +25 -1
- package/docs/content/locales/pt-BR/template-plan.mdx +1 -1
- package/docs/content/locales/zh-CN/pr-visual-recap.mdx +25 -1
- package/docs/content/locales/zh-CN/template-plan.mdx +1 -1
- package/docs/content/locales/zh-TW/pr-visual-recap.mdx +25 -1
- package/docs/content/locales/zh-TW/template-plan.mdx +1 -1
- package/docs/content/pr-visual-recap.mdx +50 -1
- package/docs/content/template-plan.mdx +1 -1
- package/package.json +2 -2
|
@@ -42,9 +42,8 @@ const DASHBOARD_REPORT_SCREENSHOT_PARAM = "reportScreenshot";
|
|
|
42
42
|
const DASHBOARD_REPORT_SETTINGS_PARAM = "reportSettings";
|
|
43
43
|
const DASHBOARD_REPORT_CID = "dashboard-report-snapshot";
|
|
44
44
|
const LOCAL_SCREENSHOT_TIMEOUT_MS = 90_000;
|
|
45
|
-
const SERVERLESS_SCREENSHOT_TIMEOUT_MS =
|
|
46
|
-
const SERVERLESS_SECOND_READY_TIMEOUT_MS =
|
|
47
|
-
const MAX_SCREENSHOT_VIEWPORT_HEIGHT = 30_000;
|
|
45
|
+
const SERVERLESS_SCREENSHOT_TIMEOUT_MS = 90_000;
|
|
46
|
+
const SERVERLESS_SECOND_READY_TIMEOUT_MS = 45_000;
|
|
48
47
|
const SCREENSHOT_VIEWPORT_PADDING = 64;
|
|
49
48
|
|
|
50
49
|
type DashboardScreenshotAttempt = {
|
|
@@ -328,42 +327,27 @@ async function scrollDashboardForLazyRendering(page: any): Promise<void> {
|
|
|
328
327
|
})()`);
|
|
329
328
|
}
|
|
330
329
|
|
|
331
|
-
async function
|
|
330
|
+
async function fitViewportWidthToDashboardCapture(
|
|
332
331
|
page: any,
|
|
333
332
|
capture: any,
|
|
334
|
-
|
|
333
|
+
viewport: { width: number; height: number },
|
|
335
334
|
): Promise<void> {
|
|
336
335
|
const box = await capture.boundingBox();
|
|
337
336
|
if (!box) return;
|
|
338
337
|
|
|
339
|
-
const
|
|
340
|
-
width
|
|
341
|
-
|
|
342
|
-
Math.min(1800, Math.ceil(box.width + SCREENSHOT_VIEWPORT_PADDING)),
|
|
343
|
-
),
|
|
344
|
-
height: Math.max(
|
|
345
|
-
minViewport.height,
|
|
346
|
-
Math.min(
|
|
347
|
-
MAX_SCREENSHOT_VIEWPORT_HEIGHT,
|
|
348
|
-
Math.ceil(box.height + SCREENSHOT_VIEWPORT_PADDING),
|
|
349
|
-
),
|
|
350
|
-
),
|
|
351
|
-
};
|
|
352
|
-
await page.setViewportSize(size);
|
|
353
|
-
await page.waitForTimeout(250);
|
|
354
|
-
|
|
355
|
-
const resizedBox = await capture.boundingBox();
|
|
356
|
-
if (!resizedBox) return;
|
|
357
|
-
const resizedHeight = Math.ceil(
|
|
358
|
-
resizedBox.height + SCREENSHOT_VIEWPORT_PADDING,
|
|
338
|
+
const width = Math.max(
|
|
339
|
+
viewport.width,
|
|
340
|
+
Math.min(1800, Math.ceil(box.width + SCREENSHOT_VIEWPORT_PADDING)),
|
|
359
341
|
);
|
|
360
|
-
if (
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
342
|
+
if (width === viewport.width) return;
|
|
343
|
+
|
|
344
|
+
// Keep the render surface bounded. Playwright's locator screenshot captures
|
|
345
|
+
// the full element beyond the viewport, while growing Chromium to the full
|
|
346
|
+
// dashboard height can exhaust memory and close the browser on serverless
|
|
347
|
+
// workers. Width-only fitting preserves the full dashboard without that
|
|
348
|
+
// oversized render surface.
|
|
349
|
+
await page.setViewportSize({ width, height: viewport.height });
|
|
350
|
+
await page.waitForTimeout(250);
|
|
367
351
|
}
|
|
368
352
|
|
|
369
353
|
async function captureDashboardPng(
|
|
@@ -412,7 +396,7 @@ async function captureDashboardPng(
|
|
|
412
396
|
await scrollDashboardForLazyRendering(page);
|
|
413
397
|
await waitForDashboardReportReady(page, secondReadyTimeoutMs());
|
|
414
398
|
|
|
415
|
-
await
|
|
399
|
+
await fitViewportWidthToDashboardCapture(page, capture, attempt.viewport);
|
|
416
400
|
await capture.scrollIntoViewIfNeeded();
|
|
417
401
|
const image = await capture.screenshot({
|
|
418
402
|
type: "png",
|
|
@@ -1083,13 +1083,17 @@ export const VideoPlayer = forwardRef<VideoPlayerHandle, VideoPlayerProps>(
|
|
|
1083
1083
|
const fullscreenMenuContainer = isFullscreen ? containerRef.current : null;
|
|
1084
1084
|
|
|
1085
1085
|
const showThroughoutCta = cta && cta.placement === "throughout";
|
|
1086
|
+
// Mobile Safari may defer loadeddata/canplay until playback starts. Keep
|
|
1087
|
+
// the paused state actionable even when those readiness events have not
|
|
1088
|
+
// fired yet; once the user asks to play, the pending/buffering states give
|
|
1089
|
+
// them accurate loading feedback.
|
|
1086
1090
|
const centerOverlayMode =
|
|
1087
1091
|
activeVideoSrc &&
|
|
1088
1092
|
!isLoomEmbed &&
|
|
1089
1093
|
!unsupportedFormat &&
|
|
1090
1094
|
!showEndCta &&
|
|
1091
1095
|
(!isPlaying || isPlayPending || isBuffering)
|
|
1092
|
-
?
|
|
1096
|
+
? isPlayPending || isBuffering
|
|
1093
1097
|
? "loading"
|
|
1094
1098
|
: "ready"
|
|
1095
1099
|
: null;
|
|
@@ -1188,8 +1188,8 @@ export function DocumentSidebar({
|
|
|
1188
1188
|
</div>
|
|
1189
1189
|
)}
|
|
1190
1190
|
|
|
1191
|
-
<ScrollArea className="min-h-0 flex-1">
|
|
1192
|
-
<div className="
|
|
1191
|
+
<ScrollArea className="min-h-0 flex-1 [&_[data-radix-scroll-area-viewport]]:!overflow-x-hidden">
|
|
1192
|
+
<div className="w-full min-w-0 py-2 pe-2">
|
|
1193
1193
|
{/* Search results */}
|
|
1194
1194
|
{filteredDocuments ? (
|
|
1195
1195
|
<>
|
|
@@ -36,9 +36,9 @@ The local-files contract:
|
|
|
36
36
|
— encode multiline code as JSON string attributes such as `code={"const x =\n y"}`
|
|
37
37
|
(a static template literal is accepted only when it has no `${...}`
|
|
38
38
|
interpolation). `plan local check` is a quick OFFLINE lint (a subset of the
|
|
39
|
-
renderer schema), so a green `check` does not guarantee the plan renders
|
|
40
|
-
`plan local verify`
|
|
41
|
-
|
|
39
|
+
renderer schema), so a green `check` does not guarantee the plan renders.
|
|
40
|
+
`plan local verify` also stays on-device: it uses the offline lint unless it
|
|
41
|
+
can reach a Plan renderer on an explicit loopback `--app-url`.
|
|
42
42
|
- **Write a local MDX folder.** Use `plans/<slug>/` to check the artifact into the
|
|
43
43
|
repo, or a repo-ignored/temporary folder such as `.agent-native/plans/<slug>/`
|
|
44
44
|
or `/tmp/agent-native-plans/<slug>/` when it should not be checked in. The
|
|
@@ -53,7 +53,10 @@ The local-files contract:
|
|
|
53
53
|
(use `--kind plan` for plans, `--kind recap` for recaps). Report the local
|
|
54
54
|
bridge URL from stdout or `<plan-dir>/.plan-url`; treat `.plan-url` as a local
|
|
55
55
|
token file and do not commit it. The URL opens the hosted Plan UI but reads from
|
|
56
|
-
the localhost bridge on this machine, so it is not shareable across machines.
|
|
56
|
+
the localhost bridge on this machine, so it is not shareable across machines.
|
|
57
|
+
The token is carried in the URL fragment (which is not sent to the hosted
|
|
58
|
+
origin), and the local-plan route disables DOM autocapture and session replay
|
|
59
|
+
while retaining sanitized pageviews and error monitoring. On
|
|
57
60
|
macOS `--open` prefers Chromium browsers; if Safari opens, switch to
|
|
58
61
|
Chrome/Chromium because Safari can block the hosted HTTPS page from fetching the
|
|
59
62
|
HTTP localhost bridge. If the Plan app itself is running locally with the same
|
|
@@ -63,14 +66,16 @@ The local-files contract:
|
|
|
63
66
|
running local Plan app.
|
|
64
67
|
- **Headless verify.** Run
|
|
65
68
|
`npx @agent-native/core@latest plan local verify --dir <plan-dir> --kind <plan|recap>`.
|
|
66
|
-
It starts the bridge
|
|
67
|
-
|
|
68
|
-
|
|
69
|
+
It starts the bridge and checks the private-network preflight and JSON payload
|
|
70
|
+
entirely on loopback. It never sends MDX or assets to a remote validation
|
|
71
|
+
action. When `--app-url` points to a loopback Plan app, verify also validates
|
|
72
|
+
against that local app's real renderer schema via `validate-local-plan-source`.
|
|
73
|
+
A non-`ok` result with
|
|
69
74
|
`validation.valid: false` lists the renderer's exact schema-path issues (e.g.
|
|
70
75
|
`blocks[1].data.tabs[0]...`); fix those before handing off. If `validation.ran`
|
|
71
|
-
is `false`,
|
|
72
|
-
|
|
73
|
-
|
|
76
|
+
is `false`, verify used the offline lint because the app URL was remote or the
|
|
77
|
+
local Plan app was unavailable. Run a local Plan app and pass
|
|
78
|
+
`--app-url http://localhost:8096` for the authoritative check. If the browser hangs on
|
|
74
79
|
"Loading plan", fetch the `bridgeUrl` from the verify/serve JSON to read the
|
|
75
80
|
concrete validation error.
|
|
76
81
|
- **Never call hosted tools for that plan/recap.** Do not call
|
|
@@ -86,8 +91,8 @@ The local-files contract:
|
|
|
86
91
|
attachment, and publish/export receipts are unavailable until the user
|
|
87
92
|
explicitly opts into publishing.
|
|
88
93
|
|
|
89
|
-
Local-files mode
|
|
90
|
-
Plan database. It does not by itself make the coding agent's language model local;
|
|
94
|
+
Local-files mode prevents plan/recap content from being uploaded to the
|
|
95
|
+
Agent-Native Plan server or database. It does not by itself make the coding agent's language model local;
|
|
91
96
|
for that stronger boundary the host agent/model must also be local or otherwise
|
|
92
97
|
approved by the user.
|
|
93
98
|
|
|
@@ -36,9 +36,9 @@ The local-files contract:
|
|
|
36
36
|
— encode multiline code as JSON string attributes such as `code={"const x =\n y"}`
|
|
37
37
|
(a static template literal is accepted only when it has no `${...}`
|
|
38
38
|
interpolation). `plan local check` is a quick OFFLINE lint (a subset of the
|
|
39
|
-
renderer schema), so a green `check` does not guarantee the plan renders
|
|
40
|
-
`plan local verify`
|
|
41
|
-
|
|
39
|
+
renderer schema), so a green `check` does not guarantee the plan renders.
|
|
40
|
+
`plan local verify` also stays on-device: it uses the offline lint unless it
|
|
41
|
+
can reach a Plan renderer on an explicit loopback `--app-url`.
|
|
42
42
|
- **Write a local MDX folder.** Use `plans/<slug>/` to check the artifact into the
|
|
43
43
|
repo, or a repo-ignored/temporary folder such as `.agent-native/plans/<slug>/`
|
|
44
44
|
or `/tmp/agent-native-plans/<slug>/` when it should not be checked in. The
|
|
@@ -53,7 +53,10 @@ The local-files contract:
|
|
|
53
53
|
(use `--kind plan` for plans, `--kind recap` for recaps). Report the local
|
|
54
54
|
bridge URL from stdout or `<plan-dir>/.plan-url`; treat `.plan-url` as a local
|
|
55
55
|
token file and do not commit it. The URL opens the hosted Plan UI but reads from
|
|
56
|
-
the localhost bridge on this machine, so it is not shareable across machines.
|
|
56
|
+
the localhost bridge on this machine, so it is not shareable across machines.
|
|
57
|
+
The token is carried in the URL fragment (which is not sent to the hosted
|
|
58
|
+
origin), and the local-plan route disables DOM autocapture and session replay
|
|
59
|
+
while retaining sanitized pageviews and error monitoring. On
|
|
57
60
|
macOS `--open` prefers Chromium browsers; if Safari opens, switch to
|
|
58
61
|
Chrome/Chromium because Safari can block the hosted HTTPS page from fetching the
|
|
59
62
|
HTTP localhost bridge. If the Plan app itself is running locally with the same
|
|
@@ -63,14 +66,16 @@ The local-files contract:
|
|
|
63
66
|
running local Plan app.
|
|
64
67
|
- **Headless verify.** Run
|
|
65
68
|
`npx @agent-native/core@latest plan local verify --dir <plan-dir> --kind <plan|recap>`.
|
|
66
|
-
It starts the bridge
|
|
67
|
-
|
|
68
|
-
|
|
69
|
+
It starts the bridge and checks the private-network preflight and JSON payload
|
|
70
|
+
entirely on loopback. It never sends MDX or assets to a remote validation
|
|
71
|
+
action. When `--app-url` points to a loopback Plan app, verify also validates
|
|
72
|
+
against that local app's real renderer schema via `validate-local-plan-source`.
|
|
73
|
+
A non-`ok` result with
|
|
69
74
|
`validation.valid: false` lists the renderer's exact schema-path issues (e.g.
|
|
70
75
|
`blocks[1].data.tabs[0]...`); fix those before handing off. If `validation.ran`
|
|
71
|
-
is `false`,
|
|
72
|
-
|
|
73
|
-
|
|
76
|
+
is `false`, verify used the offline lint because the app URL was remote or the
|
|
77
|
+
local Plan app was unavailable. Run a local Plan app and pass
|
|
78
|
+
`--app-url http://localhost:8096` for the authoritative check. If the browser hangs on
|
|
74
79
|
"Loading plan", fetch the `bridgeUrl` from the verify/serve JSON to read the
|
|
75
80
|
concrete validation error.
|
|
76
81
|
- **Never call hosted tools for that plan/recap.** Do not call
|
|
@@ -86,8 +91,8 @@ The local-files contract:
|
|
|
86
91
|
attachment, and publish/export receipts are unavailable until the user
|
|
87
92
|
explicitly opts into publishing.
|
|
88
93
|
|
|
89
|
-
Local-files mode
|
|
90
|
-
Plan database. It does not by itself make the coding agent's language model local;
|
|
94
|
+
Local-files mode prevents plan/recap content from being uploaded to the
|
|
95
|
+
Agent-Native Plan server or database. It does not by itself make the coding agent's language model local;
|
|
91
96
|
for that stronger boundary the host agent/model must also be local or otherwise
|
|
92
97
|
approved by the user.
|
|
93
98
|
|
|
@@ -13,8 +13,8 @@ import { parsePlanMdxFolder, planMdxFileSchema } from "../server/plan-mdx.js";
|
|
|
13
13
|
*
|
|
14
14
|
* It is intentionally a pure parse: it accepts the posted MDX folder, never
|
|
15
15
|
* reads `schema.plans`, never touches the filesystem, and never writes to the
|
|
16
|
-
* database.
|
|
17
|
-
*
|
|
16
|
+
* database. The local-files CLI calls it only on an explicit loopback Plan app;
|
|
17
|
+
* it never posts private source to this action on a hosted deployment.
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
20
|
// Covers the CLI's 10 MiB raw asset cap (~13.3 MiB base64) plus MDX text, so
|
|
@@ -63,7 +63,7 @@ function toValidationIssues(error: unknown): ValidationIssue[] {
|
|
|
63
63
|
|
|
64
64
|
export default defineAction({
|
|
65
65
|
description:
|
|
66
|
-
"Validate a
|
|
66
|
+
"Validate a plan MDX folder against this Plan app's renderer schema (parsePlanMdxFolder + planContentSchema). Returns { valid, issues } where issues carry the renderer's exact schema path (e.g. blocks[1].data.items[0].id). The local-files CLI calls this only on loopback Plan apps so private source stays on-device. Pure parse: no database, filesystem, or schema.plans access.",
|
|
67
67
|
schema: z.object({
|
|
68
68
|
mdx: planMdxFileSchema.describe(
|
|
69
69
|
"The plan MDX folder: plan.mdx plus optional canvas.mdx, prototype.mdx, .plan-state.json, and assets/.",
|
|
@@ -81,7 +81,7 @@ export default defineAction({
|
|
|
81
81
|
requiresAuth: false,
|
|
82
82
|
title: "Validate Local Plan Source",
|
|
83
83
|
description:
|
|
84
|
-
"Validate a
|
|
84
|
+
"Validate a plan MDX folder against this app's renderer schema without touching the database.",
|
|
85
85
|
},
|
|
86
86
|
run: async (args) => {
|
|
87
87
|
let totalBytes = 0;
|
|
@@ -62,6 +62,7 @@ import {
|
|
|
62
62
|
} from "@/components/ui/tooltip";
|
|
63
63
|
import { usePlans } from "@/hooks/use-plans";
|
|
64
64
|
import { APP_TITLE } from "@/lib/app-config";
|
|
65
|
+
import { planReturnPathFromLocation } from "@/lib/plan-local-bridge";
|
|
65
66
|
import { cn } from "@/lib/utils";
|
|
66
67
|
|
|
67
68
|
const PLAN_CHAT_STORAGE_KEY = "plans";
|
|
@@ -651,7 +652,7 @@ export function Sidebar({
|
|
|
651
652
|
const location = useLocation();
|
|
652
653
|
const { session, isLoading: sessionLoading } = useSession();
|
|
653
654
|
const t = useT();
|
|
654
|
-
const returnPath =
|
|
655
|
+
const returnPath = planReturnPathFromLocation(location);
|
|
655
656
|
const ToggleIcon = collapsed
|
|
656
657
|
? IconLayoutSidebarLeftExpand
|
|
657
658
|
: IconLayoutSidebarLeftCollapse;
|
|
@@ -67,6 +67,47 @@ export class LocalPlanBridgePermissionError extends Error {
|
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
+
type LocalPlanBridgeSessionStorage = Pick<Storage, "getItem" | "setItem">;
|
|
71
|
+
|
|
72
|
+
function browserSessionStorage(): LocalPlanBridgeSessionStorage | null {
|
|
73
|
+
if (typeof window === "undefined") return null;
|
|
74
|
+
try {
|
|
75
|
+
return window.sessionStorage;
|
|
76
|
+
} catch {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function localPlanBridgeUrlFromLocation(
|
|
82
|
+
hash: string,
|
|
83
|
+
slug: string,
|
|
84
|
+
storage: LocalPlanBridgeSessionStorage | null = browserSessionStorage(),
|
|
85
|
+
): string | null {
|
|
86
|
+
const hashParams = hash.startsWith("#bridge=")
|
|
87
|
+
? new URLSearchParams(hash.slice(1))
|
|
88
|
+
: null;
|
|
89
|
+
const bridgeUrl = hashParams?.get("bridge") ?? null;
|
|
90
|
+
const storageKey = `agent-native.local-plan-bridge.${slug}`;
|
|
91
|
+
try {
|
|
92
|
+
if (bridgeUrl) {
|
|
93
|
+
storage?.setItem(storageKey, bridgeUrl);
|
|
94
|
+
return bridgeUrl;
|
|
95
|
+
}
|
|
96
|
+
return storage?.getItem(storageKey) ?? null;
|
|
97
|
+
} catch {
|
|
98
|
+
return bridgeUrl;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function planReturnPathFromLocation(location: {
|
|
103
|
+
pathname: string;
|
|
104
|
+
search: string;
|
|
105
|
+
hash: string;
|
|
106
|
+
}): string {
|
|
107
|
+
const safeHash = location.hash.startsWith("#bridge=") ? "" : location.hash;
|
|
108
|
+
return `${location.pathname}${location.search}${safeHash}`;
|
|
109
|
+
}
|
|
110
|
+
|
|
70
111
|
export async function localNetworkAccessPermissionState(): Promise<
|
|
71
112
|
Exclude<LocalNetworkAccessPermissionState, "checking">
|
|
72
113
|
> {
|
|
@@ -273,11 +273,13 @@ import { planDocumentTitle } from "@/lib/plan-document-title";
|
|
|
273
273
|
import {
|
|
274
274
|
fetchLocalPlanBridgeBundle,
|
|
275
275
|
localNetworkAccessPermissionState,
|
|
276
|
+
localPlanBridgeUrlFromLocation,
|
|
276
277
|
localPlanBridgeQueryKey,
|
|
277
278
|
localPlanBridgeRetryDelay,
|
|
278
279
|
localPlanRoutePath,
|
|
279
280
|
localPlanRouteUrl,
|
|
280
281
|
mergeLocalBridgeComments,
|
|
282
|
+
planReturnPathFromLocation,
|
|
281
283
|
shouldRetryLocalPlanBridgeBundle,
|
|
282
284
|
shouldShowLocalPlanLoadError,
|
|
283
285
|
shouldShowPlanLoadError,
|
|
@@ -2024,9 +2026,10 @@ export function PlansPage({ localPlanSlug }: { localPlanSlug?: string } = {}) {
|
|
|
2024
2026
|
() => new URLSearchParams(location.search),
|
|
2025
2027
|
[location.search],
|
|
2026
2028
|
);
|
|
2027
|
-
const localPlanBridgeUrl =
|
|
2028
|
-
|
|
2029
|
-
|
|
2029
|
+
const localPlanBridgeUrl =
|
|
2030
|
+
localPlanMode && localPlanSlug
|
|
2031
|
+
? localPlanBridgeUrlFromLocation(location.hash, localPlanSlug)
|
|
2032
|
+
: null;
|
|
2030
2033
|
const localPlanRepoPath = localPlanMode
|
|
2031
2034
|
? routeSearchParams.get("path")
|
|
2032
2035
|
: null;
|
|
@@ -2137,8 +2140,7 @@ export function PlansPage({ localPlanSlug }: { localPlanSlug?: string } = {}) {
|
|
|
2137
2140
|
// Redirect to sign-in, returning to wherever the guest currently is.
|
|
2138
2141
|
const openSignIn = useCallback((returnOverride?: string) => {
|
|
2139
2142
|
const returnPath =
|
|
2140
|
-
returnOverride ??
|
|
2141
|
-
window.location.pathname + window.location.search + window.location.hash;
|
|
2143
|
+
returnOverride ?? planReturnPathFromLocation(window.location);
|
|
2142
2144
|
window.location.href = `${agentNativePath(
|
|
2143
2145
|
"/_agent-native/sign-in",
|
|
2144
2146
|
)}?return=${encodeURIComponent(returnPath)}`;
|
|
@@ -2292,8 +2294,7 @@ export function PlansPage({ localPlanSlug }: { localPlanSlug?: string } = {}) {
|
|
|
2292
2294
|
}
|
|
2293
2295
|
}, [accessRequestSentPlanId, selectedId]);
|
|
2294
2296
|
const startGoogleSignIn = useCallback(async () => {
|
|
2295
|
-
const returnPath =
|
|
2296
|
-
window.location.pathname + window.location.search + window.location.hash;
|
|
2297
|
+
const returnPath = planReturnPathFromLocation(window.location);
|
|
2297
2298
|
try {
|
|
2298
2299
|
const res = await fetch(
|
|
2299
2300
|
`${agentNativePath("/_agent-native/google/auth-url")}?return=${encodeURIComponent(returnPath)}`,
|
|
@@ -6826,8 +6827,7 @@ function PlanLoadError({
|
|
|
6826
6827
|
? t("plansPage.loadError.orgTitle", { orgName })
|
|
6827
6828
|
: null;
|
|
6828
6829
|
|
|
6829
|
-
const returnPath = () =>
|
|
6830
|
-
window.location.pathname + window.location.search + window.location.hash;
|
|
6830
|
+
const returnPath = () => planReturnPathFromLocation(window.location);
|
|
6831
6831
|
|
|
6832
6832
|
const readAuthError = async (res: Response, fallback: string) => {
|
|
6833
6833
|
const data = (await res.json().catch(() => null)) as {
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
} from "@tabler/icons-react";
|
|
21
21
|
import { useQueryClient } from "@tanstack/react-query";
|
|
22
22
|
import { useTheme } from "next-themes";
|
|
23
|
-
import { useCallback, useState } from "react";
|
|
23
|
+
import { useCallback, useEffect, useState } from "react";
|
|
24
24
|
import {
|
|
25
25
|
Links,
|
|
26
26
|
Meta,
|
|
@@ -44,13 +44,17 @@ import { useNavigationState } from "@/hooks/use-navigation-state";
|
|
|
44
44
|
// their diagram/wireframe/api-spec blocks inline in the agent chat.
|
|
45
45
|
import "@/lib/register-chat-renderers";
|
|
46
46
|
import { APP_TITLE } from "@/lib/app-config";
|
|
47
|
+
import { shouldCapturePlanContent } from "@/lib/plan-tracking";
|
|
47
48
|
import { TAB_ID } from "@/lib/tab-id";
|
|
48
49
|
|
|
49
50
|
import changelog from "../CHANGELOG.md?raw";
|
|
50
51
|
import { i18nCatalog } from "./i18n";
|
|
51
52
|
|
|
52
53
|
import stylesheet from "./global.css?url";
|
|
54
|
+
// Keep standard pageviews, explicit analytics, and Sentry on local-plan routes,
|
|
55
|
+
// but disable DOM/session capture so rendered plan contents stay on-device.
|
|
53
56
|
configureTracking({
|
|
57
|
+
contentCaptureForPath: shouldCapturePlanContent,
|
|
54
58
|
getDefaultProps: (_name, properties) => ({
|
|
55
59
|
...properties,
|
|
56
60
|
app: "plan",
|
|
@@ -221,6 +225,7 @@ export default function Root() {
|
|
|
221
225
|
location.pathname.startsWith("/recaps/") ||
|
|
222
226
|
location.pathname === "/local-plans" ||
|
|
223
227
|
location.pathname.startsWith("/local-plans/");
|
|
228
|
+
const localPlanPrivacyRoute = !shouldCapturePlanContent(location.pathname);
|
|
224
229
|
return (
|
|
225
230
|
// Pass the plan-specific styled Toaster via `toaster` so only one sonner
|
|
226
231
|
// instance renders (avoids the duplicate that would appear if AppProviders'
|
|
@@ -232,8 +237,13 @@ export default function Root() {
|
|
|
232
237
|
toaster={<Toaster richColors position="bottom-left" />}
|
|
233
238
|
i18n={{ catalog: i18nCatalog }}
|
|
234
239
|
>
|
|
235
|
-
<
|
|
236
|
-
|
|
240
|
+
<div
|
|
241
|
+
data-an-mask={localPlanPrivacyRoute ? "" : undefined}
|
|
242
|
+
style={{ display: "contents" }}
|
|
243
|
+
>
|
|
244
|
+
<DbSyncSetup />
|
|
245
|
+
<AppContent />
|
|
246
|
+
</div>
|
|
237
247
|
</AppProviders>
|
|
238
248
|
</AppToolkitProvider>
|
|
239
249
|
);
|
|
@@ -3247,8 +3247,8 @@ export async function runAgentLoop(opts) {
|
|
|
3247
3247
|
// content parts; first-party actions opt in via the well-known
|
|
3248
3248
|
// `_agentImages` result field (stripped from the JSON the model
|
|
3249
3249
|
// reads, even in demo mode). Demo mode drops the images themselves —
|
|
3250
|
-
// text redaction can't scrub pixels, and a screenshot
|
|
3251
|
-
//
|
|
3250
|
+
// text redaction can't scrub pixels, and a screenshot may expose
|
|
3251
|
+
// original visual data. The images array
|
|
3252
3252
|
// never touches the ledger — only the compact text notes appended
|
|
3253
3253
|
// below are persisted.
|
|
3254
3254
|
let imageNotes = [];
|