@agent-native/core 0.131.7 → 0.132.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/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +123 -0
- package/corpus/core/docs/content/durable-background-runs.mdx +15 -6
- package/corpus/core/docs/design/durable-agent-runs.md +15 -11
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/a2a/activity.ts +127 -10
- package/corpus/core/src/a2a/index.ts +3 -0
- package/corpus/core/src/agent/durable-background.ts +38 -28
- package/corpus/core/src/agent/harness/background.ts +12 -2
- package/corpus/core/src/agent/production-agent.ts +18 -15
- package/corpus/core/src/agent/run-store.ts +45 -3
- package/corpus/core/src/application-state/handlers.ts +45 -0
- package/corpus/core/src/application-state/index.ts +3 -0
- package/corpus/core/src/application-state/store.ts +38 -34
- package/corpus/core/src/audit/redact.ts +104 -18
- package/corpus/core/src/cli/create.ts +115 -16
- package/corpus/core/src/client/AgentPanel.tsx +2 -7
- package/corpus/core/src/client/AssistantChat.tsx +10 -2
- package/corpus/core/src/client/MultiTabAssistantChat.tsx +3 -0
- package/corpus/core/src/client/RunStuckBanner.tsx +29 -6
- package/corpus/core/src/client/agent-chat.ts +4 -9
- package/corpus/core/src/client/application-state.ts +115 -12
- package/corpus/core/src/client/dynamic-suggestions.ts +4 -12
- package/corpus/core/src/client/frame-protocol.ts +5 -1
- package/corpus/core/src/client/guided-questions.tsx +12 -23
- package/corpus/core/src/db/client.ts +148 -28
- package/corpus/core/src/db/create-get-db.ts +39 -6
- package/corpus/core/src/db/runtime-diagnostics.ts +41 -6
- package/corpus/core/src/deploy/build.ts +26 -33
- package/corpus/core/src/feature-flags/store.ts +10 -5
- package/corpus/core/src/integrations/a2a-continuations-store.ts +11 -0
- package/corpus/core/src/integrations/config-store.ts +13 -0
- package/corpus/core/src/integrations/google-docs-poller.ts +26 -2
- package/corpus/core/src/mcp-client/routes.ts +33 -2
- package/corpus/core/src/onboarding/plugin.ts +31 -25
- package/corpus/core/src/org/accept-pending.ts +2 -0
- package/corpus/core/src/org/auto-join-domain.ts +2 -0
- package/corpus/core/src/org/context.ts +35 -10
- package/corpus/core/src/org/handlers.ts +6 -0
- package/corpus/core/src/org/request-org-cache.ts +71 -0
- package/corpus/core/src/resources/store.ts +10 -9
- package/corpus/core/src/scripts/runner.ts +6 -3
- package/corpus/core/src/secrets/storage.ts +97 -5
- package/corpus/core/src/server/action-change.ts +33 -0
- package/corpus/core/src/server/action-routes.ts +11 -9
- package/corpus/core/src/server/agent-teams.ts +10 -2
- package/corpus/core/src/server/better-auth-instance.ts +39 -12
- package/corpus/core/src/server/core-routes-plugin.ts +19 -2
- package/corpus/core/src/server/credential-provider.ts +57 -14
- package/corpus/core/src/server/http-response-telemetry.ts +1 -0
- package/corpus/core/src/server/poll.ts +95 -57
- package/corpus/core/src/server/voice-providers-status.ts +19 -4
- package/corpus/core/src/workspace-files/tool.ts +18 -11
- package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +38 -0
- package/corpus/templates/analytics/actions/dashboard-mutation-api.ts +1 -1
- package/corpus/templates/analytics/actions/ensure-native-v2-dashboards.ts +299 -0
- package/corpus/templates/analytics/actions/list-native-v2-dashboard-templates.ts +34 -0
- package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +82 -0
- package/corpus/templates/analytics/app/components/layout/NewDashboardDialog.tsx +2 -2
- package/corpus/templates/analytics/app/hooks/use-dashboard-chat-context.ts +40 -34
- package/corpus/templates/analytics/app/hooks/use-user-pref.ts +3 -3
- package/corpus/templates/analytics/app/i18n-data.ts +40 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/PanelEditorDialog.tsx +18 -10
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +14 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/types.ts +1 -0
- package/corpus/templates/analytics/app/routes/chart.tsx +3 -0
- package/corpus/templates/analytics/changelog/2026-07-30-analytics-dashboards-now-expose-native-funnel-heatmap-callou.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-30-analytics-now-ships-reusable-native-v2-dashboard-manifests-w.md +6 -0
- package/corpus/templates/analytics/server/lib/dashboard-report-render.ts +81 -1
- package/corpus/templates/analytics/server/lib/native-v2-dashboards.ts +457 -0
- package/corpus/templates/analytics/server/lib/report-chart-svg.ts +73 -2
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +1 -1
- package/corpus/templates/analytics/shared/dashboard-funnel.ts +83 -0
- package/corpus/templates/clips/actions/generate-workflow.ts +6 -4
- package/corpus/templates/clips/actions/reconcile-workflow-generation.ts +257 -0
- package/corpus/templates/clips/app/hooks/use-auto-title.ts +166 -4
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +1 -1
- package/corpus/templates/clips/changelog/2026-07-27-stopped-agent-runs-no-longer-leave-generated-workflow-cards-.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-30-workflow-generation-now-stops-retrying-after-repeated-failur.md +6 -0
- package/corpus/templates/clips/shared/workflow.ts +5 -0
- package/corpus/templates/content/changelog/2026-07-30-long-running-delegated-requests-now-continue-reliably.md +6 -0
- package/corpus/templates/content/netlify.toml +3 -0
- package/corpus/templates/content/server/plugins/agent-chat.ts +1 -0
- package/corpus/templates/slides/.agents/skills/create-deck/SKILL.md +2 -1
- package/corpus/templates/slides/actions/patch-deck.ts +25 -1
- package/corpus/templates/slides/app/components/deck/DeckCard.tsx +17 -4
- package/corpus/templates/slides/app/components/deck/SlideRenderer.tsx +9 -1
- package/corpus/templates/slides/app/components/layout/Layout.tsx +1 -1
- package/corpus/templates/slides/app/context/DeckContext.tsx +11 -3
- package/corpus/templates/slides/app/lib/sanitize-slide-html.ts +39 -11
- package/corpus/templates/slides/app/pages/Index.tsx +2 -2
- package/corpus/templates/slides/changelog/2026-07-30-slide-previews-keep-their-aspect-ratio-isolate-embedded-styl.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-30-slides-no-longer-lose-decks-while-organization-access-is-loa.md +6 -0
- package/corpus/toolkit/CHANGELOG.md +8 -0
- package/corpus/toolkit/package.json +1 -1
- package/corpus/toolkit/src/composer/runtime-adapters.tsx +16 -11
- package/dist/a2a/activity.d.ts +22 -4
- package/dist/a2a/activity.d.ts.map +1 -1
- package/dist/a2a/activity.js +97 -11
- package/dist/a2a/activity.js.map +1 -1
- package/dist/a2a/index.d.ts +1 -1
- package/dist/a2a/index.d.ts.map +1 -1
- package/dist/a2a/index.js +1 -1
- package/dist/a2a/index.js.map +1 -1
- package/dist/agent/durable-background.d.ts +13 -8
- package/dist/agent/durable-background.d.ts.map +1 -1
- package/dist/agent/durable-background.js +36 -28
- package/dist/agent/durable-background.js.map +1 -1
- package/dist/agent/harness/background.d.ts.map +1 -1
- package/dist/agent/harness/background.js +12 -2
- package/dist/agent/harness/background.js.map +1 -1
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +18 -15
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-store.d.ts +2 -0
- package/dist/agent/run-store.d.ts.map +1 -1
- package/dist/agent/run-store.js +44 -3
- package/dist/agent/run-store.js.map +1 -1
- package/dist/application-state/handlers.d.ts +15 -0
- package/dist/application-state/handlers.d.ts.map +1 -1
- package/dist/application-state/handlers.js +42 -2
- package/dist/application-state/handlers.js.map +1 -1
- package/dist/application-state/index.d.ts +2 -2
- package/dist/application-state/index.d.ts.map +1 -1
- package/dist/application-state/index.js +2 -2
- package/dist/application-state/index.js.map +1 -1
- package/dist/application-state/store.d.ts +11 -0
- package/dist/application-state/store.d.ts.map +1 -1
- package/dist/application-state/store.js +37 -40
- package/dist/application-state/store.js.map +1 -1
- package/dist/audit/redact.d.ts +25 -2
- package/dist/audit/redact.d.ts.map +1 -1
- package/dist/audit/redact.js +85 -21
- package/dist/audit/redact.js.map +1 -1
- package/dist/cli/create.d.ts +8 -1
- package/dist/cli/create.d.ts.map +1 -1
- package/dist/cli/create.js +98 -16
- package/dist/cli/create.js.map +1 -1
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +2 -7
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +10 -2
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
- package/dist/client/MultiTabAssistantChat.js +1 -1
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/RunStuckBanner.d.ts +11 -1
- package/dist/client/RunStuckBanner.d.ts.map +1 -1
- package/dist/client/RunStuckBanner.js +20 -7
- package/dist/client/RunStuckBanner.js.map +1 -1
- package/dist/client/agent-chat.d.ts.map +1 -1
- package/dist/client/agent-chat.js +4 -6
- package/dist/client/agent-chat.js.map +1 -1
- package/dist/client/application-state.d.ts +11 -0
- package/dist/client/application-state.d.ts.map +1 -1
- package/dist/client/application-state.js +87 -9
- package/dist/client/application-state.js.map +1 -1
- package/dist/client/dynamic-suggestions.d.ts.map +1 -1
- package/dist/client/dynamic-suggestions.js +4 -13
- package/dist/client/dynamic-suggestions.js.map +1 -1
- package/dist/client/frame-protocol.d.ts +1 -0
- package/dist/client/frame-protocol.d.ts.map +1 -1
- package/dist/client/frame-protocol.js.map +1 -1
- package/dist/client/guided-questions.d.ts.map +1 -1
- package/dist/client/guided-questions.js +6 -22
- package/dist/client/guided-questions.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/db/client.d.ts +57 -10
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +122 -31
- package/dist/db/client.js.map +1 -1
- package/dist/db/create-get-db.d.ts.map +1 -1
- package/dist/db/create-get-db.js +31 -7
- package/dist/db/create-get-db.js.map +1 -1
- package/dist/db/runtime-diagnostics.d.ts +1 -0
- package/dist/db/runtime-diagnostics.d.ts.map +1 -1
- package/dist/db/runtime-diagnostics.js +31 -6
- package/dist/db/runtime-diagnostics.js.map +1 -1
- package/dist/deploy/build.d.ts +5 -20
- package/dist/deploy/build.d.ts.map +1 -1
- package/dist/deploy/build.js +18 -30
- package/dist/deploy/build.js.map +1 -1
- package/dist/feature-flags/store.d.ts.map +1 -1
- package/dist/feature-flags/store.js +10 -5
- package/dist/feature-flags/store.js.map +1 -1
- package/dist/integrations/a2a-continuations-store.d.ts.map +1 -1
- package/dist/integrations/a2a-continuations-store.js +12 -0
- package/dist/integrations/a2a-continuations-store.js.map +1 -1
- package/dist/integrations/config-store.d.ts +1 -0
- package/dist/integrations/config-store.d.ts.map +1 -1
- package/dist/integrations/config-store.js +11 -0
- package/dist/integrations/config-store.js.map +1 -1
- package/dist/integrations/google-docs-poller.d.ts.map +1 -1
- package/dist/integrations/google-docs-poller.js +19 -2
- package/dist/integrations/google-docs-poller.js.map +1 -1
- package/dist/mcp/screen-memory-stdio.d.ts +7 -7
- package/dist/mcp/screen-memory-stdio.d.ts.map +1 -1
- package/dist/mcp-client/routes.d.ts.map +1 -1
- package/dist/mcp-client/routes.js +30 -2
- package/dist/mcp-client/routes.js.map +1 -1
- package/dist/notifications/routes.d.ts +6 -6
- package/dist/onboarding/plugin.d.ts.map +1 -1
- package/dist/onboarding/plugin.js +12 -8
- package/dist/onboarding/plugin.js.map +1 -1
- package/dist/org/accept-pending.d.ts.map +1 -1
- package/dist/org/accept-pending.js +2 -0
- package/dist/org/accept-pending.js.map +1 -1
- package/dist/org/auto-join-domain.d.ts.map +1 -1
- package/dist/org/auto-join-domain.js +2 -0
- package/dist/org/auto-join-domain.js.map +1 -1
- package/dist/org/context.d.ts.map +1 -1
- package/dist/org/context.js +29 -9
- package/dist/org/context.js.map +1 -1
- package/dist/org/handlers.d.ts.map +1 -1
- package/dist/org/handlers.js +5 -0
- package/dist/org/handlers.js.map +1 -1
- package/dist/org/request-org-cache.d.ts +16 -0
- package/dist/org/request-org-cache.d.ts.map +1 -0
- package/dist/org/request-org-cache.js +62 -0
- package/dist/org/request-org-cache.js.map +1 -0
- package/dist/progress/routes.d.ts +1 -1
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/resources/store.d.ts.map +1 -1
- package/dist/resources/store.js +11 -9
- package/dist/resources/store.js.map +1 -1
- package/dist/scripts/runner.d.ts.map +1 -1
- package/dist/scripts/runner.js +3 -3
- package/dist/scripts/runner.js.map +1 -1
- package/dist/secrets/storage.d.ts.map +1 -1
- package/dist/secrets/storage.js +82 -5
- package/dist/secrets/storage.js.map +1 -1
- package/dist/server/action-change.d.ts +20 -0
- package/dist/server/action-change.d.ts.map +1 -1
- package/dist/server/action-change.js +29 -0
- package/dist/server/action-change.js.map +1 -1
- package/dist/server/action-routes.d.ts.map +1 -1
- package/dist/server/action-routes.js +7 -8
- package/dist/server/action-routes.js.map +1 -1
- package/dist/server/agent-teams.d.ts.map +1 -1
- package/dist/server/agent-teams.js +10 -2
- package/dist/server/agent-teams.js.map +1 -1
- package/dist/server/better-auth-instance.d.ts.map +1 -1
- package/dist/server/better-auth-instance.js +31 -14
- package/dist/server/better-auth-instance.js.map +1 -1
- package/dist/server/core-routes-plugin.d.ts +1 -0
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +18 -4
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/credential-provider.d.ts +16 -0
- package/dist/server/credential-provider.d.ts.map +1 -1
- package/dist/server/credential-provider.js +49 -13
- package/dist/server/credential-provider.js.map +1 -1
- package/dist/server/http-response-telemetry.d.ts.map +1 -1
- package/dist/server/http-response-telemetry.js +1 -0
- package/dist/server/http-response-telemetry.js.map +1 -1
- package/dist/server/poll.d.ts +6 -0
- package/dist/server/poll.d.ts.map +1 -1
- package/dist/server/poll.js +84 -47
- package/dist/server/poll.js.map +1 -1
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/voice-providers-status.d.ts.map +1 -1
- package/dist/server/voice-providers-status.js +12 -3
- package/dist/server/voice-providers-status.js.map +1 -1
- package/dist/workspace-files/tool.d.ts.map +1 -1
- package/dist/workspace-files/tool.js +18 -11
- package/dist/workspace-files/tool.js.map +1 -1
- package/docs/content/durable-background-runs.mdx +15 -6
- package/docs/design/durable-agent-runs.md +15 -11
- package/package.json +3 -3
- package/src/a2a/activity.ts +127 -10
- package/src/a2a/index.ts +3 -0
- package/src/agent/durable-background.ts +38 -28
- package/src/agent/harness/background.ts +12 -2
- package/src/agent/production-agent.ts +18 -15
- package/src/agent/run-store.ts +45 -3
- package/src/application-state/handlers.ts +45 -0
- package/src/application-state/index.ts +3 -0
- package/src/application-state/store.ts +38 -34
- package/src/audit/redact.ts +104 -18
- package/src/cli/create.ts +115 -16
- package/src/client/AgentPanel.tsx +2 -7
- package/src/client/AssistantChat.tsx +10 -2
- package/src/client/MultiTabAssistantChat.tsx +3 -0
- package/src/client/RunStuckBanner.tsx +29 -6
- package/src/client/agent-chat.ts +4 -9
- package/src/client/application-state.ts +115 -12
- package/src/client/dynamic-suggestions.ts +4 -12
- package/src/client/frame-protocol.ts +5 -1
- package/src/client/guided-questions.tsx +12 -23
- package/src/db/client.ts +148 -28
- package/src/db/create-get-db.ts +39 -6
- package/src/db/runtime-diagnostics.ts +41 -6
- package/src/deploy/build.ts +26 -33
- package/src/feature-flags/store.ts +10 -5
- package/src/integrations/a2a-continuations-store.ts +11 -0
- package/src/integrations/config-store.ts +13 -0
- package/src/integrations/google-docs-poller.ts +26 -2
- package/src/mcp-client/routes.ts +33 -2
- package/src/onboarding/plugin.ts +31 -25
- package/src/org/accept-pending.ts +2 -0
- package/src/org/auto-join-domain.ts +2 -0
- package/src/org/context.ts +35 -10
- package/src/org/handlers.ts +6 -0
- package/src/org/request-org-cache.ts +71 -0
- package/src/resources/store.ts +10 -9
- package/src/scripts/runner.ts +6 -3
- package/src/secrets/storage.ts +97 -5
- package/src/server/action-change.ts +33 -0
- package/src/server/action-routes.ts +11 -9
- package/src/server/agent-teams.ts +10 -2
- package/src/server/better-auth-instance.ts +39 -12
- package/src/server/core-routes-plugin.ts +19 -2
- package/src/server/credential-provider.ts +57 -14
- package/src/server/http-response-telemetry.ts +1 -0
- package/src/server/poll.ts +95 -57
- package/src/server/voice-providers-status.ts +19 -4
- package/src/workspace-files/tool.ts +18 -11
package/dist/audit/redact.js
CHANGED
|
@@ -10,13 +10,18 @@
|
|
|
10
10
|
* This mirrors the framework's standing rule that credential-looking literals
|
|
11
11
|
* never land in source, logs, or fixtures.
|
|
12
12
|
*/
|
|
13
|
-
const SENSITIVE_KEY = /(pass(word|phrase)?|secret|token|api[_-]?key|apikey|authorization|bearer|credential|cookie|session[_-]?(id|token)|private[_-]?key|client[_-]?secret|signing[_-]?secret|access[_-]?key|refresh[_-]?token|webhook[_-]?(url|secret))/i;
|
|
13
|
+
const SENSITIVE_KEY = /(?:pass(?:word|phrase)?|secret|token|api[_-]?key|apikey|authorization|bearer|credential|cookie|session[_-]?(?:id|token)|private[_-]?key|client[_-]?secret|signing[_-]?secret|access[_-]?key|refresh[_-]?token|webhook[_-]?(?:url|secret))/i;
|
|
14
14
|
const REDACTED = "[redacted]";
|
|
15
15
|
const MAX_STRING = 2000;
|
|
16
16
|
const MAX_DEPTH = 6;
|
|
17
17
|
const MAX_KEYS = 100;
|
|
18
18
|
const MAX_ARRAY = 100;
|
|
19
19
|
const MAX_JSON = 8000;
|
|
20
|
+
/**
|
|
21
|
+
* Head room reserved for the `…(N more chars)` marker so a truncated summary
|
|
22
|
+
* still fits its caller's cap. Callers below this cannot carry a marker at all.
|
|
23
|
+
*/
|
|
24
|
+
const MARKER_SLACK = 32;
|
|
20
25
|
/** Heuristic: does a bare string value look like a secret? */
|
|
21
26
|
function looksSecret(value) {
|
|
22
27
|
if (/^bearer\s+\S/i.test(value))
|
|
@@ -35,25 +40,32 @@ function looksSecret(value) {
|
|
|
35
40
|
}
|
|
36
41
|
return false;
|
|
37
42
|
}
|
|
38
|
-
function redactString(value) {
|
|
43
|
+
function redactString(value, maxString) {
|
|
39
44
|
if (looksSecret(value))
|
|
40
45
|
return REDACTED;
|
|
41
|
-
if (value.length >
|
|
42
|
-
return `${value.slice(0,
|
|
46
|
+
if (value.length > maxString) {
|
|
47
|
+
return `${value.slice(0, maxString)}…(${value.length - maxString} more chars)`;
|
|
43
48
|
}
|
|
44
49
|
return value;
|
|
45
50
|
}
|
|
46
|
-
function
|
|
51
|
+
function redactEmbeddedSecrets(value) {
|
|
52
|
+
const bearer = value.replace(/\b(bearer\s+)([^\s"',}]+)/gi, `$1${REDACTED}`);
|
|
53
|
+
const credentialField = new RegExp(`(["']?\\b${SENSITIVE_KEY.source}\\b["']?\\s*[:=]\\s*)(["']?)(?!bearer\\b)([^"'\\s,}]+)\\2`, "gi");
|
|
54
|
+
return bearer.replace(credentialField, `$1$2${REDACTED}$2`);
|
|
55
|
+
}
|
|
56
|
+
function redact(value, depth, maxString) {
|
|
47
57
|
if (value == null)
|
|
48
58
|
return value;
|
|
49
59
|
if (typeof value === "string")
|
|
50
|
-
return redactString(value);
|
|
60
|
+
return redactString(value, maxString);
|
|
51
61
|
if (typeof value === "number" || typeof value === "boolean")
|
|
52
62
|
return value;
|
|
53
63
|
if (depth >= MAX_DEPTH)
|
|
54
64
|
return "[…]";
|
|
55
65
|
if (Array.isArray(value)) {
|
|
56
|
-
const out = value
|
|
66
|
+
const out = value
|
|
67
|
+
.slice(0, MAX_ARRAY)
|
|
68
|
+
.map((v) => redact(v, depth + 1, maxString));
|
|
57
69
|
if (value.length > MAX_ARRAY)
|
|
58
70
|
out.push(`…(${value.length - MAX_ARRAY} more)`);
|
|
59
71
|
return out;
|
|
@@ -67,7 +79,9 @@ function redact(value, depth) {
|
|
|
67
79
|
break;
|
|
68
80
|
}
|
|
69
81
|
n += 1;
|
|
70
|
-
out[k] = SENSITIVE_KEY.test(k)
|
|
82
|
+
out[k] = SENSITIVE_KEY.test(k)
|
|
83
|
+
? REDACTED
|
|
84
|
+
: redact(v, depth + 1, maxString);
|
|
71
85
|
}
|
|
72
86
|
return out;
|
|
73
87
|
}
|
|
@@ -78,32 +92,82 @@ function redact(value, depth) {
|
|
|
78
92
|
* Redact and serialize call arguments to a capped JSON string, or `null` when
|
|
79
93
|
* there is nothing to record. Never throws.
|
|
80
94
|
*/
|
|
81
|
-
export function redactArgsToJson(args) {
|
|
95
|
+
export function redactArgsToJson(args, limits) {
|
|
96
|
+
const maxJson = Math.max(MARKER_SLACK * 4, limits?.maxJson ?? MAX_JSON);
|
|
97
|
+
const maxString = limits?.maxString ?? MAX_STRING;
|
|
82
98
|
try {
|
|
83
99
|
if (args == null)
|
|
84
100
|
return null;
|
|
85
|
-
const redacted = redact(args, 0);
|
|
101
|
+
const redacted = redact(args, 0, maxString);
|
|
86
102
|
if (redacted === undefined)
|
|
87
103
|
return null;
|
|
88
104
|
const json = JSON.stringify(redacted);
|
|
89
105
|
if (json == null)
|
|
90
106
|
return null;
|
|
91
|
-
if (json.length
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
107
|
+
if (json.length <= maxJson)
|
|
108
|
+
return json;
|
|
109
|
+
// Slicing the serialized JSON would yield an unparseable string. Wrap a
|
|
110
|
+
// preview in a valid envelope so `get-audit-event` can always JSON.parse
|
|
111
|
+
// the stored `input`. JSON escaping makes the envelope overhead
|
|
112
|
+
// content-dependent, so shrink the preview until the whole thing measures
|
|
113
|
+
// under the cap rather than guessing at the overhead.
|
|
114
|
+
const envelope = (preview) => JSON.stringify({
|
|
115
|
+
_auditTruncated: true,
|
|
116
|
+
originalBytes: json.length,
|
|
117
|
+
preview,
|
|
118
|
+
});
|
|
119
|
+
let take = maxJson;
|
|
120
|
+
let out = envelope(json.slice(0, take));
|
|
121
|
+
while (out.length > maxJson && take > 0) {
|
|
122
|
+
take = Math.max(0, take - Math.max(1, out.length - maxJson));
|
|
123
|
+
out = envelope(json.slice(0, take));
|
|
100
124
|
}
|
|
101
|
-
return
|
|
125
|
+
return out;
|
|
102
126
|
}
|
|
103
127
|
catch {
|
|
104
128
|
return null;
|
|
105
129
|
}
|
|
106
130
|
}
|
|
131
|
+
/**
|
|
132
|
+
* Same bounds as `redactArgsToJson`, returned as a structural value for
|
|
133
|
+
* surfaces whose consumers expect an object (transcript `metadata.input`).
|
|
134
|
+
*/
|
|
135
|
+
export function redactArgsToValue(args, limits) {
|
|
136
|
+
const json = redactArgsToJson(args, limits);
|
|
137
|
+
if (json == null)
|
|
138
|
+
return null;
|
|
139
|
+
try {
|
|
140
|
+
return JSON.parse(json);
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Bounded, redacted plain-text summary of a tool result. Oversized text keeps
|
|
148
|
+
* its head and gains an explicit `…(N more chars)` marker, so a reader can
|
|
149
|
+
* always tell a short result from a clipped one.
|
|
150
|
+
*/
|
|
151
|
+
export function redactTextToSummary(text, maxChars = MAX_STRING) {
|
|
152
|
+
if (!text)
|
|
153
|
+
return null;
|
|
154
|
+
// Only ever walk a bounded head: a multi-megabyte tool result must not be
|
|
155
|
+
// scanned in full just to produce a preview of it.
|
|
156
|
+
const head = text.slice(0, maxChars + MARKER_SLACK);
|
|
157
|
+
const redactedHead = redactEmbeddedSecrets(head);
|
|
158
|
+
if (looksSecret(redactedHead.trim()))
|
|
159
|
+
return REDACTED;
|
|
160
|
+
if (text.length <= maxChars && redactedHead.length <= maxChars) {
|
|
161
|
+
return redactedHead;
|
|
162
|
+
}
|
|
163
|
+
const keep = Math.max(0, maxChars - MARKER_SLACK);
|
|
164
|
+
return `${redactedHead.slice(0, keep)}…(${text.length - keep} more chars)`;
|
|
165
|
+
}
|
|
107
166
|
/** Exposed for tests. */
|
|
108
|
-
export const __test = {
|
|
167
|
+
export const __test = {
|
|
168
|
+
looksSecret,
|
|
169
|
+
redact,
|
|
170
|
+
redactEmbeddedSecrets,
|
|
171
|
+
SENSITIVE_KEY,
|
|
172
|
+
};
|
|
109
173
|
//# sourceMappingURL=redact.js.map
|
package/dist/audit/redact.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redact.js","sourceRoot":"","sources":["../../src/audit/redact.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Redaction for audit-captured arguments.\n *\n * The audit log must never become a secondary store of secrets. Before any\n * call arguments are persisted we:\n * - drop values under credential-looking keys (token, secret, password, …),\n * - redact string values that look like bearer tokens / long opaque keys,\n * - truncate oversized strings and cap the serialized payload size.\n *\n * This mirrors the framework's standing rule that credential-looking literals\n * never land in source, logs, or fixtures.\n */\n\nconst SENSITIVE_KEY =\n /(pass(word|phrase)?|secret|token|api[_-]?key|apikey|authorization|bearer|credential|cookie|session[_-]?(id|token)|private[_-]?key|client[_-]?secret|signing[_-]?secret|access[_-]?key|refresh[_-]?token|webhook[_-]?(url|secret))/i;\n\nconst REDACTED = \"[redacted]\";\nconst MAX_STRING = 2000;\nconst MAX_DEPTH = 6;\nconst MAX_KEYS = 100;\nconst MAX_ARRAY = 100;\nconst MAX_JSON = 8000;\n\n/** Heuristic: does a bare string value look like a secret? */\nfunction looksSecret(value: string): boolean {\n if (/^bearer\\s+\\S/i.test(value)) return true;\n // Long, unbroken, high-entropy-ish opaque token (hex/base64url, no spaces).\n if (value.length >= 32 && /^[A-Za-z0-9_\\-+/=.]+$/.test(value)) return true;\n // Common secret prefixes (Stripe, GitHub, OpenAI, Slack, AWS, …).\n if (/^(sk|pk|rk|ghp|gho|xox[baprs]|AKIA|AIza|ya29)[-_]/i.test(value)) {\n return true;\n }\n // Webhook URLs carry their secret in the path — redact regardless of the key\n // they arrive under (e.g. a generic `value` field holding a Slack webhook).\n if (\n /^https?:\\/\\/(hooks\\.slack\\.com\\/|[^/]*\\.webhook\\.office\\.com\\/|(canary\\.|ptb\\.)?discord(app)?\\.com\\/api\\/webhooks\\/|hooks\\.zapier\\.com\\/|maker\\.ifttt\\.com\\/|discord\\.com\\/api\\/webhooks\\/)/i.test(\n value,\n )\n ) {\n return true;\n }\n return false;\n}\n\nfunction redactString(value: string): string {\n if (looksSecret(value)) return REDACTED;\n if (value.length > MAX_STRING) {\n return `${value.slice(0, MAX_STRING)}…(${value.length - MAX_STRING} more chars)`;\n }\n return value;\n}\n\nfunction redact(value: unknown, depth: number): unknown {\n if (value == null) return value;\n if (typeof value === \"string\") return redactString(value);\n if (typeof value === \"number\" || typeof value === \"boolean\") return value;\n if (depth >= MAX_DEPTH) return \"[…]\";\n if (Array.isArray(value)) {\n const out = value.slice(0, MAX_ARRAY).map((v) => redact(v, depth + 1));\n if (value.length > MAX_ARRAY)\n out.push(`…(${value.length - MAX_ARRAY} more)`);\n return out;\n }\n if (typeof value === \"object\") {\n const out: Record<string, unknown> = {};\n let n = 0;\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n if (n >= MAX_KEYS) {\n out[\"…\"] = \"(truncated)\";\n break;\n }\n n += 1;\n out[k] = SENSITIVE_KEY.test(k) ? REDACTED : redact(v, depth + 1);\n }\n return out;\n }\n // Functions, symbols, bigint, etc. — not serializable / not interesting.\n return undefined;\n}\n\n/**\n * Redact and serialize call arguments to a capped JSON string, or `null` when\n * there is nothing to record. Never throws.\n */\nexport function redactArgsToJson(args: unknown): string | null {\n try {\n if (args == null) return null;\n const redacted = redact(args, 0);\n if (redacted === undefined) return null;\n const json = JSON.stringify(redacted);\n if (json == null) return null;\n if (json.length > MAX_JSON) {\n // Slicing the serialized JSON would yield an unparseable string. Wrap a\n // preview in a valid envelope so `get-audit-event` can always JSON.parse\n // the stored `input`.\n return JSON.stringify({\n _auditTruncated: true,\n originalBytes: json.length,\n preview: json.slice(0, MAX_JSON),\n });\n }\n return json;\n } catch {\n return null;\n }\n}\n\n/** Exposed for tests. */\nexport const __test = { looksSecret, redact, SENSITIVE_KEY };\n"]}
|
|
1
|
+
{"version":3,"file":"redact.js","sourceRoot":"","sources":["../../src/audit/redact.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Redaction for audit-captured arguments.\n *\n * The audit log must never become a secondary store of secrets. Before any\n * call arguments are persisted we:\n * - drop values under credential-looking keys (token, secret, password, …),\n * - redact string values that look like bearer tokens / long opaque keys,\n * - truncate oversized strings and cap the serialized payload size.\n *\n * This mirrors the framework's standing rule that credential-looking literals\n * never land in source, logs, or fixtures.\n */\n\nconst SENSITIVE_KEY =\n /(?:pass(?:word|phrase)?|secret|token|api[_-]?key|apikey|authorization|bearer|credential|cookie|session[_-]?(?:id|token)|private[_-]?key|client[_-]?secret|signing[_-]?secret|access[_-]?key|refresh[_-]?token|webhook[_-]?(?:url|secret))/i;\n\nconst REDACTED = \"[redacted]\";\nconst MAX_STRING = 2000;\nconst MAX_DEPTH = 6;\nconst MAX_KEYS = 100;\nconst MAX_ARRAY = 100;\nconst MAX_JSON = 8000;\n/**\n * Head room reserved for the `…(N more chars)` marker so a truncated summary\n * still fits its caller's cap. Callers below this cannot carry a marker at all.\n */\nconst MARKER_SLACK = 32;\n\n/** Heuristic: does a bare string value look like a secret? */\nfunction looksSecret(value: string): boolean {\n if (/^bearer\\s+\\S/i.test(value)) return true;\n // Long, unbroken, high-entropy-ish opaque token (hex/base64url, no spaces).\n if (value.length >= 32 && /^[A-Za-z0-9_\\-+/=.]+$/.test(value)) return true;\n // Common secret prefixes (Stripe, GitHub, OpenAI, Slack, AWS, …).\n if (/^(sk|pk|rk|ghp|gho|xox[baprs]|AKIA|AIza|ya29)[-_]/i.test(value)) {\n return true;\n }\n // Webhook URLs carry their secret in the path — redact regardless of the key\n // they arrive under (e.g. a generic `value` field holding a Slack webhook).\n if (\n /^https?:\\/\\/(hooks\\.slack\\.com\\/|[^/]*\\.webhook\\.office\\.com\\/|(canary\\.|ptb\\.)?discord(app)?\\.com\\/api\\/webhooks\\/|hooks\\.zapier\\.com\\/|maker\\.ifttt\\.com\\/|discord\\.com\\/api\\/webhooks\\/)/i.test(\n value,\n )\n ) {\n return true;\n }\n return false;\n}\n\nfunction redactString(value: string, maxString: number): string {\n if (looksSecret(value)) return REDACTED;\n if (value.length > maxString) {\n return `${value.slice(0, maxString)}…(${value.length - maxString} more chars)`;\n }\n return value;\n}\n\nfunction redactEmbeddedSecrets(value: string): string {\n const bearer = value.replace(/\\b(bearer\\s+)([^\\s\"',}]+)/gi, `$1${REDACTED}`);\n const credentialField = new RegExp(\n `([\"']?\\\\b${SENSITIVE_KEY.source}\\\\b[\"']?\\\\s*[:=]\\\\s*)([\"']?)(?!bearer\\\\b)([^\"'\\\\s,}]+)\\\\2`,\n \"gi\",\n );\n return bearer.replace(credentialField, `$1$2${REDACTED}$2`);\n}\n\nfunction redact(value: unknown, depth: number, maxString: number): unknown {\n if (value == null) return value;\n if (typeof value === \"string\") return redactString(value, maxString);\n if (typeof value === \"number\" || typeof value === \"boolean\") return value;\n if (depth >= MAX_DEPTH) return \"[…]\";\n if (Array.isArray(value)) {\n const out = value\n .slice(0, MAX_ARRAY)\n .map((v) => redact(v, depth + 1, maxString));\n if (value.length > MAX_ARRAY)\n out.push(`…(${value.length - MAX_ARRAY} more)`);\n return out;\n }\n if (typeof value === \"object\") {\n const out: Record<string, unknown> = {};\n let n = 0;\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n if (n >= MAX_KEYS) {\n out[\"…\"] = \"(truncated)\";\n break;\n }\n n += 1;\n out[k] = SENSITIVE_KEY.test(k)\n ? REDACTED\n : redact(v, depth + 1, maxString);\n }\n return out;\n }\n // Functions, symbols, bigint, etc. — not serializable / not interesting.\n return undefined;\n}\n\nexport interface RedactLimits {\n /**\n * Hard cap on the serialized output, INCLUDING the truncation envelope.\n * Surfaces with their own wire budget (the A2A activity snapshot) pass a\n * tighter cap than the audit-log default.\n */\n maxJson?: number;\n /** Cap on any single string value before it gets a truncation marker. */\n maxString?: number;\n}\n\n/**\n * Redact and serialize call arguments to a capped JSON string, or `null` when\n * there is nothing to record. Never throws.\n */\nexport function redactArgsToJson(\n args: unknown,\n limits?: RedactLimits,\n): string | null {\n const maxJson = Math.max(MARKER_SLACK * 4, limits?.maxJson ?? MAX_JSON);\n const maxString = limits?.maxString ?? MAX_STRING;\n try {\n if (args == null) return null;\n const redacted = redact(args, 0, maxString);\n if (redacted === undefined) return null;\n const json = JSON.stringify(redacted);\n if (json == null) return null;\n if (json.length <= maxJson) return json;\n // Slicing the serialized JSON would yield an unparseable string. Wrap a\n // preview in a valid envelope so `get-audit-event` can always JSON.parse\n // the stored `input`. JSON escaping makes the envelope overhead\n // content-dependent, so shrink the preview until the whole thing measures\n // under the cap rather than guessing at the overhead.\n const envelope = (preview: string) =>\n JSON.stringify({\n _auditTruncated: true,\n originalBytes: json.length,\n preview,\n });\n let take = maxJson;\n let out = envelope(json.slice(0, take));\n while (out.length > maxJson && take > 0) {\n take = Math.max(0, take - Math.max(1, out.length - maxJson));\n out = envelope(json.slice(0, take));\n }\n return out;\n } catch {\n return null;\n }\n}\n\n/**\n * Same bounds as `redactArgsToJson`, returned as a structural value for\n * surfaces whose consumers expect an object (transcript `metadata.input`).\n */\nexport function redactArgsToValue(\n args: unknown,\n limits?: RedactLimits,\n): unknown {\n const json = redactArgsToJson(args, limits);\n if (json == null) return null;\n try {\n return JSON.parse(json);\n } catch {\n return null;\n }\n}\n\n/**\n * Bounded, redacted plain-text summary of a tool result. Oversized text keeps\n * its head and gains an explicit `…(N more chars)` marker, so a reader can\n * always tell a short result from a clipped one.\n */\nexport function redactTextToSummary(\n text: string,\n maxChars = MAX_STRING,\n): string | null {\n if (!text) return null;\n // Only ever walk a bounded head: a multi-megabyte tool result must not be\n // scanned in full just to produce a preview of it.\n const head = text.slice(0, maxChars + MARKER_SLACK);\n const redactedHead = redactEmbeddedSecrets(head);\n if (looksSecret(redactedHead.trim())) return REDACTED;\n if (text.length <= maxChars && redactedHead.length <= maxChars) {\n return redactedHead;\n }\n const keep = Math.max(0, maxChars - MARKER_SLACK);\n return `${redactedHead.slice(0, keep)}…(${text.length - keep} more chars)`;\n}\n\n/** Exposed for tests. */\nexport const __test = {\n looksSecret,\n redact,\n redactEmbeddedSecrets,\n SENSITIVE_KEY,\n};\n"]}
|
package/dist/cli/create.d.ts
CHANGED
|
@@ -23,6 +23,11 @@ export interface CreateAppOptions {
|
|
|
23
23
|
* unconditional workspace scaffold.
|
|
24
24
|
*/
|
|
25
25
|
forceWorkspace?: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Internal: scaffold into the current directory instead of a new subfolder.
|
|
28
|
+
* Set when the name argument is `.`/`./` (see `createApp`).
|
|
29
|
+
*/
|
|
30
|
+
inPlace?: boolean;
|
|
26
31
|
}
|
|
27
32
|
/**
|
|
28
33
|
* Main entry for `agent-native create [name]`.
|
|
@@ -211,6 +216,8 @@ declare function rewriteAgentChatAppId(appDir: string, appName: string, template
|
|
|
211
216
|
declare function rewriteTrackingAppId(appDir: string, appName: string, templateName?: string, sourceIdentity?: ScaffoldSourceIdentity): void;
|
|
212
217
|
declare function renameGitignore(dir: string): void;
|
|
213
218
|
declare function replacePlaceholders(dir: string, appName: string, appTitle: string, workspaceName?: string): void;
|
|
214
|
-
declare function copyDir(src: string, dest: string, root?: string
|
|
219
|
+
declare function copyDir(src: string, dest: string, root?: string, opts?: {
|
|
220
|
+
skipExisting?: boolean;
|
|
221
|
+
}): void;
|
|
215
222
|
declare function shouldSkipScaffoldEntry(name: string, srcPath?: string): boolean;
|
|
216
223
|
//# sourceMappingURL=create.d.ts.map
|
package/dist/cli/create.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../src/cli/create.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAkB,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAKvE,QAAA,MAAM,IAAI,2BAA2B,CAAC;AACtC,QAAA,MAAM,aAAa,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../src/cli/create.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/create.js
CHANGED
|
@@ -39,6 +39,18 @@ const FIRST_PARTY_TARBALL_SYMLINK_EXCLUDES = [
|
|
|
39
39
|
"*/.claude/skills",
|
|
40
40
|
];
|
|
41
41
|
const localPackageTarballs = new Map();
|
|
42
|
+
/** VCS/editor files that don't count as "not empty" for an in-place scaffold. */
|
|
43
|
+
const IN_PLACE_ALLOWLIST = new Set([
|
|
44
|
+
".git",
|
|
45
|
+
".gitignore",
|
|
46
|
+
".gitattributes",
|
|
47
|
+
".DS_Store",
|
|
48
|
+
".idea",
|
|
49
|
+
".vscode",
|
|
50
|
+
"LICENSE",
|
|
51
|
+
"README.md",
|
|
52
|
+
"Thumbs.db",
|
|
53
|
+
]);
|
|
42
54
|
/**
|
|
43
55
|
* Tagged error for input that fails CLI-level validation (repo names, app
|
|
44
56
|
* names, etc.). The Sentry `beforeSend` hook in cli/index.ts drops events
|
|
@@ -89,6 +101,12 @@ const COMMUNITY_OPTION = {
|
|
|
89
101
|
*/
|
|
90
102
|
export async function createApp(name, opts) {
|
|
91
103
|
const clack = await import("@clack/prompts");
|
|
104
|
+
// `create .` (or `./`) means "scaffold into the current folder" — derive the
|
|
105
|
+
// project name from the folder's basename, like create-react-app / npm init.
|
|
106
|
+
if (name === "." || name === "./") {
|
|
107
|
+
name = path.basename(process.cwd());
|
|
108
|
+
opts = { ...opts, inPlace: true };
|
|
109
|
+
}
|
|
92
110
|
// Reject an invalid provided name before any interactive prompt so bad input
|
|
93
111
|
// fails fast instead of blocking on the start-shape picker below.
|
|
94
112
|
if (name !== undefined) {
|
|
@@ -260,6 +278,38 @@ function assertValidProjectName(name, clack) {
|
|
|
260
278
|
process.exit(1);
|
|
261
279
|
}
|
|
262
280
|
}
|
|
281
|
+
/**
|
|
282
|
+
* Resolve where a scaffold writes and guard the target. A named project writes
|
|
283
|
+
* to a new sibling subfolder that must not already exist; `create .` writes
|
|
284
|
+
* into the current directory, which must be empty apart from benign VCS/editor
|
|
285
|
+
* files (a pre-existing repo is allowed).
|
|
286
|
+
*
|
|
287
|
+
* For an in-place scaffold we do NOT return the current directory: we build
|
|
288
|
+
* into a private staging directory and `finalizeScaffold` copies the result
|
|
289
|
+
* in afterward. Staging keeps the whole scaffold atomic — a mid-scaffold
|
|
290
|
+
* failure's cleanup can only ever delete the staging dir, never the user's
|
|
291
|
+
* current directory (including its `.git`).
|
|
292
|
+
*/
|
|
293
|
+
function resolveScaffoldTarget(name, inPlace, clack) {
|
|
294
|
+
if (inPlace) {
|
|
295
|
+
const conflicting = fs
|
|
296
|
+
.readdirSync(process.cwd())
|
|
297
|
+
.filter((entry) => !IN_PLACE_ALLOWLIST.has(entry));
|
|
298
|
+
if (conflicting.length > 0) {
|
|
299
|
+
const shown = conflicting.slice(0, 3).join(", ");
|
|
300
|
+
const more = conflicting.length > 3 ? ", …" : "";
|
|
301
|
+
clack.cancel(`Current directory is not empty (${shown}${more}). Scaffold into an empty folder, or run \`create <name>\` to make a new one.`);
|
|
302
|
+
process.exit(1);
|
|
303
|
+
}
|
|
304
|
+
return fs.mkdtempSync(path.join(os.tmpdir(), "agent-native-create-"));
|
|
305
|
+
}
|
|
306
|
+
const targetDir = path.resolve(process.cwd(), name);
|
|
307
|
+
if (fs.existsSync(targetDir)) {
|
|
308
|
+
clack.cancel(`Directory "${name}" already exists.`);
|
|
309
|
+
process.exit(1);
|
|
310
|
+
}
|
|
311
|
+
return targetDir;
|
|
312
|
+
}
|
|
263
313
|
/* ─────────────────────────────────────────────────────────────────────────
|
|
264
314
|
* Workspace creation (new default)
|
|
265
315
|
* ───────────────────────────────────────────────────────────────────────── */
|
|
@@ -289,11 +339,7 @@ async function createWorkspaceInteractive(name, opts, clack) {
|
|
|
289
339
|
excludeNames: ["dispatch"],
|
|
290
340
|
});
|
|
291
341
|
const templates = ["dispatch", ...optionalPicks];
|
|
292
|
-
const targetDir =
|
|
293
|
-
if (fs.existsSync(targetDir)) {
|
|
294
|
-
clack.cancel(`Directory "${name}" already exists.`);
|
|
295
|
-
process.exit(1);
|
|
296
|
-
}
|
|
342
|
+
const targetDir = resolveScaffoldTarget(name, opts?.inPlace, clack);
|
|
297
343
|
const s = clack.spinner();
|
|
298
344
|
for (const template of templates) {
|
|
299
345
|
showCommunityTemplateTrustNote(template, clack);
|
|
@@ -362,12 +408,14 @@ async function createWorkspaceInteractive(name, opts, clack) {
|
|
|
362
408
|
catch (err) {
|
|
363
409
|
s.stop("Failed to scaffold workspace.");
|
|
364
410
|
// Remove the partially-scaffolded workspace so a retry of `agent-native
|
|
365
|
-
// create <name>` doesn't trip the "Directory already exists" guard.
|
|
411
|
+
// create <name>` doesn't trip the "Directory already exists" guard. For an
|
|
412
|
+
// in-place scaffold `targetDir` is the private staging dir, so this never
|
|
413
|
+
// touches the user's current directory.
|
|
366
414
|
cleanupOnFailure(targetDir);
|
|
367
415
|
clack.cancel(err?.message ?? String(err));
|
|
368
416
|
process.exit(1);
|
|
369
417
|
}
|
|
370
|
-
|
|
418
|
+
finalizeScaffold(targetDir, opts?.inPlace);
|
|
371
419
|
// Show the user the tree we just built so the workspace/app distinction is
|
|
372
420
|
// visible, not just described. First-time users routinely expect their
|
|
373
421
|
// workspace name to be the app — seeing apps/<template>/ subdirectories
|
|
@@ -630,11 +678,7 @@ async function scaffoldOneAppIntoWorkspace(workspace, appName, templateName, cla
|
|
|
630
678
|
async function createStandaloneApp(name, opts, clack) {
|
|
631
679
|
clack.intro("Create a new standalone agent-native app");
|
|
632
680
|
name = await promptNameIfMissing(name, clack, "app", "my-app");
|
|
633
|
-
const targetDir =
|
|
634
|
-
if (fs.existsSync(targetDir)) {
|
|
635
|
-
clack.cancel(`Directory "${name}" already exists.`);
|
|
636
|
-
process.exit(1);
|
|
637
|
-
}
|
|
681
|
+
const targetDir = resolveScaffoldTarget(name, opts?.inPlace, clack);
|
|
638
682
|
// Standalone is single-select — pick one template.
|
|
639
683
|
let template = opts?.template && !opts.template.includes(",") ? opts.template : undefined;
|
|
640
684
|
if (!template) {
|
|
@@ -666,11 +710,13 @@ async function createStandaloneApp(name, opts, clack) {
|
|
|
666
710
|
}
|
|
667
711
|
catch (err) {
|
|
668
712
|
s.stop("Failed to create app.");
|
|
713
|
+
// `targetDir` is the private staging dir for an in-place scaffold, so this
|
|
714
|
+
// only ever removes the staging copy, never the user's current directory.
|
|
669
715
|
cleanupOnFailure(targetDir);
|
|
670
716
|
clack.cancel(err?.message ?? String(err));
|
|
671
717
|
process.exit(1);
|
|
672
718
|
}
|
|
673
|
-
|
|
719
|
+
finalizeScaffold(targetDir, opts?.inPlace);
|
|
674
720
|
if (template === "headless") {
|
|
675
721
|
clack.outro([
|
|
676
722
|
"Done! Next steps:",
|
|
@@ -724,6 +770,35 @@ function cleanupOnFailure(targetDir) {
|
|
|
724
770
|
// Ignore — original error is more useful than a cleanup failure.
|
|
725
771
|
}
|
|
726
772
|
}
|
|
773
|
+
/**
|
|
774
|
+
* Land a finished scaffold in its final home and initialize git. A named
|
|
775
|
+
* scaffold is already in place, so this only inits git. An in-place scaffold
|
|
776
|
+
* (`create .`) was built in `scaffoldDir` (a staging dir); copy only the files
|
|
777
|
+
* that don't already exist into the current directory so pre-existing files
|
|
778
|
+
* (`.git`, `README.md`, `.gitignore`, editor configs) are preserved, then drop
|
|
779
|
+
* the staging dir. Git init/commit is skipped when the current directory is
|
|
780
|
+
* already a repo so we never write an unexpected commit into the user's
|
|
781
|
+
* history.
|
|
782
|
+
*/
|
|
783
|
+
function finalizeScaffold(scaffoldDir, inPlace) {
|
|
784
|
+
if (!inPlace) {
|
|
785
|
+
tryGitInitUnlessRepo(scaffoldDir);
|
|
786
|
+
return;
|
|
787
|
+
}
|
|
788
|
+
const dest = process.cwd();
|
|
789
|
+
try {
|
|
790
|
+
copyDir(scaffoldDir, dest, undefined, { skipExisting: true });
|
|
791
|
+
}
|
|
792
|
+
finally {
|
|
793
|
+
cleanupOnFailure(scaffoldDir);
|
|
794
|
+
}
|
|
795
|
+
tryGitInitUnlessRepo(dest);
|
|
796
|
+
}
|
|
797
|
+
function tryGitInitUnlessRepo(dir) {
|
|
798
|
+
if (fs.existsSync(path.join(dir, ".git")))
|
|
799
|
+
return;
|
|
800
|
+
tryGitInit(dir);
|
|
801
|
+
}
|
|
727
802
|
/**
|
|
728
803
|
* Scaffold a single app template into `targetDir`. Resolves:
|
|
729
804
|
* - "headless" / legacy "blank" → bundled action-first template
|
|
@@ -2538,14 +2613,21 @@ function replacePlaceholders(dir, appName, appTitle, workspaceName) {
|
|
|
2538
2613
|
fs.writeFileSync(p, next);
|
|
2539
2614
|
}
|
|
2540
2615
|
}
|
|
2541
|
-
function copyDir(src, dest, root) {
|
|
2616
|
+
function copyDir(src, dest, root, opts) {
|
|
2542
2617
|
const resolvedRoot = root ?? path.resolve(src);
|
|
2618
|
+
const skipExisting = opts?.skipExisting ?? false;
|
|
2543
2619
|
fs.mkdirSync(dest, { recursive: true });
|
|
2544
2620
|
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
2545
2621
|
const srcPath = path.join(src, entry.name);
|
|
2546
2622
|
if (shouldSkipScaffoldEntry(entry.name, srcPath))
|
|
2547
2623
|
continue;
|
|
2548
2624
|
const destPath = path.join(dest, entry.name);
|
|
2625
|
+
// Preserve anything already at the destination (in-place scaffold merges
|
|
2626
|
+
// into a directory the user may already own). Directories still recurse so
|
|
2627
|
+
// new files land inside a pre-existing folder.
|
|
2628
|
+
if (skipExisting && !entry.isDirectory() && fs.existsSync(destPath)) {
|
|
2629
|
+
continue;
|
|
2630
|
+
}
|
|
2549
2631
|
if (entry.isSymbolicLink()) {
|
|
2550
2632
|
const target = fs.readlinkSync(srcPath);
|
|
2551
2633
|
const resolvedTarget = path.resolve(path.dirname(srcPath), target);
|
|
@@ -2556,7 +2638,7 @@ function copyDir(src, dest, root) {
|
|
|
2556
2638
|
try {
|
|
2557
2639
|
const stat = fs.statSync(srcPath);
|
|
2558
2640
|
if (stat.isDirectory()) {
|
|
2559
|
-
copyDir(srcPath, destPath, resolvedRoot);
|
|
2641
|
+
copyDir(srcPath, destPath, resolvedRoot, opts);
|
|
2560
2642
|
}
|
|
2561
2643
|
else {
|
|
2562
2644
|
fs.copyFileSync(srcPath, destPath);
|
|
@@ -2568,7 +2650,7 @@ function copyDir(src, dest, root) {
|
|
|
2568
2650
|
}
|
|
2569
2651
|
}
|
|
2570
2652
|
else if (entry.isDirectory()) {
|
|
2571
|
-
copyDir(srcPath, destPath, resolvedRoot);
|
|
2653
|
+
copyDir(srcPath, destPath, resolvedRoot, opts);
|
|
2572
2654
|
}
|
|
2573
2655
|
else {
|
|
2574
2656
|
fs.copyFileSync(srcPath, destPath);
|