@agent-native/core 0.136.4 → 0.137.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.
Files changed (170) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/clips/.agents/skills/recording/SKILL.md +53 -0
  3. package/corpus/templates/clips/actions/import-loom-recording.ts +7 -0
  4. package/corpus/templates/clips/actions/lib/loom-import-job.ts +24 -4
  5. package/corpus/templates/clips/app/components/import-menu.tsx +109 -0
  6. package/corpus/templates/clips/app/components/library/library-grid.tsx +8 -18
  7. package/corpus/templates/clips/app/components/library/library-layout.tsx +14 -50
  8. package/corpus/templates/clips/app/components/library/sort-menu.tsx +20 -6
  9. package/corpus/templates/clips/app/components/recorder/pre-record-panel.tsx +10 -34
  10. package/corpus/templates/clips/app/routes/_app.library._index.tsx +0 -2
  11. package/corpus/templates/clips/changelog/2026-08-03-restart-during-a-recording-now-immediately-starts-a-fresh-ta.md +6 -0
  12. package/corpus/templates/clips/changelog/2026-08-04-cleaner-library-controls-with-an-icon-only-sort-button.md +6 -0
  13. package/corpus/templates/clips/changelog/2026-08-04-upload-and-loom-imports-now-live-under-one-import-menu.md +6 -0
  14. package/corpus/templates/clips/desktop/src/app.tsx +81 -30
  15. package/corpus/templates/clips/desktop/src/lib/recorder.ts +436 -158
  16. package/corpus/templates/clips/server/lib/post-finalize-dispatch.ts +14 -1
  17. package/corpus/templates/clips/server/plugins/auth.ts +9 -0
  18. package/corpus/templates/clips/server/routes/api/_agent-native-background/post-finalize-worker.post.ts +13 -0
  19. package/corpus/templates/content/actions/_database-utils.ts +6 -0
  20. package/corpus/templates/content/actions/bind-content-database-source-field.ts +273 -97
  21. package/corpus/templates/content/actions/change-content-database-source-role.ts +65 -29
  22. package/corpus/templates/content/actions/configure-document-property.ts +113 -32
  23. package/corpus/templates/content/actions/delete-content-database.ts +5 -7
  24. package/corpus/templates/content/actions/delete-document-property.ts +109 -62
  25. package/corpus/templates/content/actions/delete-document.ts +178 -36
  26. package/corpus/templates/content/actions/duplicate-database-item.ts +27 -0
  27. package/corpus/templates/content/actions/duplicate-database-items.ts +31 -1
  28. package/corpus/templates/content/actions/permanently-delete-document.ts +4 -6
  29. package/corpus/templates/content/actions/remove-database-items.ts +13 -0
  30. package/corpus/templates/content/actions/set-document-property.ts +69 -1
  31. package/corpus/templates/content/actions/upsert-database-item-by-key.ts +814 -0
  32. package/corpus/templates/content/parity/matrix.md +1 -1
  33. package/corpus/templates/content/parity/matrix.ts +1 -0
  34. package/corpus/templates/content/server/db/schema.ts +27 -0
  35. package/corpus/templates/content/server/plugins/db.ts +24 -0
  36. package/corpus/templates/design/app/components/design/BreakpointBar.tsx +122 -114
  37. package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +2 -2
  38. package/corpus/templates/design/app/components/design/EditPanel.tsx +68 -34
  39. package/corpus/templates/design/app/components/design/KeyboardShortcutsPanel.tsx +78 -4
  40. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +8 -0
  41. package/corpus/templates/design/app/components/design/QuestionFlow.tsx +5 -2
  42. package/corpus/templates/design/app/components/design/edit-panel/panel-primitives.tsx +10 -9
  43. package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +31 -69
  44. package/corpus/templates/design/app/components/design/inspector/design-icons.tsx +80 -106
  45. package/corpus/templates/design/app/components/design/multi-screen/types.ts +4 -0
  46. package/corpus/templates/design/app/hooks/use-editor-preferences.ts +75 -0
  47. package/corpus/templates/design/app/i18n-data.ts +8 -0
  48. package/corpus/templates/design/app/i18n-keyboard-shortcuts.ts +61 -0
  49. package/corpus/templates/design/app/pages/design-editor/editor-preferences.ts +98 -0
  50. package/corpus/templates/design/app/pages/design-editor/nudge-intent.ts +491 -0
  51. package/corpus/templates/design/app/pages/design-editor/paste-placement.ts +133 -0
  52. package/corpus/templates/design/app/pages/design-editor/png-export-render.ts +8 -0
  53. package/corpus/templates/design/app/pages/design-editor/selection-state.ts +5 -12
  54. package/corpus/templates/design/changelog/2026-08-03-arrow-keys-now-reorder-a-layer-inside-an-auto-layout-frame.md +6 -0
  55. package/corpus/templates/design/changelog/2026-08-03-auto-layout-flow-icons-show-the-direction-at-a-glance-instea.md +6 -0
  56. package/corpus/templates/design/changelog/2026-08-03-auto-layout-icons-share-one-outlined-square-style-so-flow-ga.md +6 -0
  57. package/corpus/templates/design/changelog/2026-08-03-export-has-a-named-preview-section-you-can-expand-replacing-.md +6 -0
  58. package/corpus/templates/design/changelog/2026-08-03-export-preview-shows-the-selected-element-instead-of-the-who.md +6 -0
  59. package/corpus/templates/design/changelog/2026-08-03-inspector-sections-show-an-expand-indicator-so-it-is-clear-w.md +6 -0
  60. package/corpus/templates/design/changelog/2026-08-03-paste-lands-inside-a-selected-frame-instead-of-beside-it.md +6 -0
  61. package/corpus/templates/design/changelog/2026-08-03-the-add-breakpoint-button-sits-outside-the-breakpoint-select.md +6 -0
  62. package/corpus/templates/design/changelog/2026-08-03-the-agent-s-follow-up-questions-keep-space-below-the-continu.md +6 -0
  63. package/corpus/templates/design/changelog/2026-08-03-the-agent-s-follow-up-questions-share-the-chat-panel-s-backg.md +6 -0
  64. package/corpus/templates/design/changelog/2026-08-03-the-export-panel-no-longer-stacks-a-duplicate-export-block-o.md +6 -0
  65. package/corpus/templates/design/changelog/2026-08-03-the-text-tool-uses-a-t-icon-matching-the-letter-it-inserts.md +6 -0
  66. package/corpus/templates/factory/.env.example +17 -0
  67. package/corpus/templates/factory/AGENTS.md +27 -17
  68. package/corpus/templates/factory/README.md +19 -9
  69. package/corpus/templates/factory/actions/get-slack-feedback-context.ts +90 -0
  70. package/corpus/templates/factory/actions/get-triage-config.ts +14 -3
  71. package/corpus/templates/factory/actions/govern-agent-native-pull-request.ts +386 -0
  72. package/corpus/templates/factory/actions/list-factory-automations.ts +53 -0
  73. package/corpus/templates/factory/actions/list-triage-items.ts +7 -2
  74. package/corpus/templates/factory/actions/poll-github-sources.ts +203 -0
  75. package/corpus/templates/factory/actions/poll-sentry-errors.ts +161 -0
  76. package/corpus/templates/factory/actions/poll-slack-channel.ts +4 -2
  77. package/corpus/templates/factory/actions/run-factory-automation.ts +42 -0
  78. package/corpus/templates/factory/actions/save-factory-automation.ts +69 -0
  79. package/corpus/templates/factory/actions/save-triage-config.ts +28 -2
  80. package/corpus/templates/factory/actions/start-builder-for-item.ts +411 -0
  81. package/corpus/templates/factory/app/components/factory/FactoryCanvas.tsx +14 -3
  82. package/corpus/templates/factory/app/components/ui/checkbox.tsx +1 -0
  83. package/corpus/templates/factory/app/hooks/use-navigation-state.ts +7 -0
  84. package/corpus/templates/factory/app/i18n/en-US.ts +35 -1
  85. package/corpus/templates/factory/app/routes/factory.tsx +462 -9
  86. package/corpus/templates/factory/changelog/2026-08-04-added-organization-owned-factory-automations-for-slack-bug-t.md +6 -0
  87. package/corpus/templates/factory/changelog/2026-08-04-automation-editor-controls-and-model-picker.md +6 -0
  88. package/corpus/templates/factory/netlify.toml +2 -2
  89. package/corpus/templates/factory/server/connectors/credentials.ts +6 -5
  90. package/corpus/templates/factory/server/connectors/slack.ts +133 -5
  91. package/corpus/templates/factory/server/db/schema.ts +6 -0
  92. package/corpus/templates/factory/server/lib/require-factory-automation.ts +65 -0
  93. package/corpus/templates/factory/server/plugins/agent-chat.ts +29 -11
  94. package/corpus/templates/factory/server/plugins/auth.ts +1 -0
  95. package/corpus/templates/factory/server/plugins/factory-migrations.ts +12 -0
  96. package/corpus/templates/factory/server/plugins/factory-scheduler-job.ts +218 -67
  97. package/corpus/templates/factory/server/triage/builder-executor.ts +4 -0
  98. package/corpus/templates/factory/server/triage/contracts.ts +14 -1
  99. package/corpus/templates/factory/server/triage/github-client.ts +404 -0
  100. package/corpus/templates/factory/server/triage/metadata.ts +44 -0
  101. package/corpus/templates/factory/server/triage/pr-babysit.ts +5 -5
  102. package/corpus/templates/factory/server/triage/pr-policy.ts +144 -0
  103. package/corpus/templates/factory/server/triage/sentry-client.ts +180 -0
  104. package/corpus/templates/factory/server/triage/slack-client.ts +43 -0
  105. package/corpus/templates/factory/server/triage/slack-poller.ts +9 -2
  106. package/corpus/templates/plan/.agents/skills/visual-plan/SKILL.md +27 -0
  107. package/corpus/templates/plan/.agents/skills/visual-plan/references/canvas.md +14 -4
  108. package/corpus/templates/plan/.agents/skills/visual-plan/references/wireframe.md +7 -0
  109. package/corpus/templates/plan/.agents/skills/visual-recap/references/wireframe.md +7 -0
  110. package/corpus/templates/plan/actions/create-plan-design.ts +8 -6
  111. package/corpus/templates/plan/actions/create-prototype-plan.ts +8 -6
  112. package/corpus/templates/plan/actions/create-ui-plan.ts +7 -7
  113. package/corpus/templates/plan/actions/get-plan-blocks.ts +7 -1
  114. package/corpus/templates/plan/actions/validate-plan-input.ts +39 -0
  115. package/corpus/templates/plan/app/components/plan/CanvasArea.tsx +167 -11
  116. package/corpus/templates/plan/app/i18n/en-US.ts +1 -0
  117. package/corpus/templates/plan/changelog/2026-08-04-canvas-zoom-controls-now-explain-the-command-ctrl-plus-scrol.md +6 -0
  118. package/corpus/templates/plan/changelog/2026-08-04-pinch-to-zoom-is-now-supported-on-touchscreens-in-visual-pla.md +6 -0
  119. package/corpus/templates/plan/shared/plan-content.ts +17 -2
  120. package/dist/cli/skills-content/canvas.d.ts +3 -3
  121. package/dist/cli/skills-content/canvas.js +16 -5
  122. package/dist/cli/skills-content/visual-plan-skill.d.ts +1 -1
  123. package/dist/cli/skills-content/visual-plan-skill.js +27 -0
  124. package/dist/cli/skills-content/wireframe.d.ts +2 -2
  125. package/dist/cli/skills-content/wireframe.js +7 -0
  126. package/dist/client/AgentPanel.js +23 -8
  127. package/dist/client/api-path.d.ts +6 -0
  128. package/dist/client/api-path.js +55 -0
  129. package/dist/client/onboarding/FirstRunOnboarding.d.ts +3 -0
  130. package/dist/client/onboarding/FirstRunOnboarding.js +93 -0
  131. package/dist/client/onboarding/first-run-enabled.d.ts +2 -0
  132. package/dist/client/onboarding/first-run-enabled.js +9 -0
  133. package/dist/client/onboarding/index.d.ts +2 -1
  134. package/dist/client/onboarding/index.js +1 -0
  135. package/dist/client/onboarding/use-onboarding.d.ts +6 -1
  136. package/dist/client/onboarding/use-onboarding.js +32 -1
  137. package/dist/client/route-state.js +10 -0
  138. package/dist/client/settings/SecretsSection.js +32 -8
  139. package/dist/collab/struct-routes.d.ts +1 -1
  140. package/dist/connections/catalog.d.ts +4 -4
  141. package/dist/connections/catalog.js +3 -3
  142. package/dist/db/index.d.ts +1 -1
  143. package/dist/db/index.js +1 -1
  144. package/dist/localization/default-messages.d.ts +5 -0
  145. package/dist/localization/default-messages.js +5 -0
  146. package/dist/mcp/screen-memory-stdio.d.ts +7 -7
  147. package/dist/observability/routes.d.ts +3 -3
  148. package/dist/onboarding/app-profile.d.ts +4 -0
  149. package/dist/onboarding/app-profile.js +378 -0
  150. package/dist/onboarding/index.d.ts +2 -1
  151. package/dist/onboarding/index.js +1 -0
  152. package/dist/onboarding/plugin.d.ts +2 -0
  153. package/dist/onboarding/plugin.js +21 -1
  154. package/dist/onboarding/types.d.ts +19 -0
  155. package/dist/progress/routes.d.ts +1 -1
  156. package/dist/provider-api/actions/custom-provider-registration.d.ts +9 -9
  157. package/dist/provider-api/actions/provider-api.d.ts +12 -12
  158. package/dist/secrets/routes.d.ts +2 -2
  159. package/dist/secrets/routes.js +41 -17
  160. package/dist/server/auth.js +21 -1
  161. package/dist/server/better-auth-instance.d.ts +3 -2
  162. package/dist/server/better-auth-instance.js +9 -7
  163. package/dist/server/email-markdown.js +3 -8
  164. package/dist/server/transcribe-voice.d.ts +1 -1
  165. package/dist/shared/first-run-onboarding.d.ts +3 -0
  166. package/dist/shared/first-run-onboarding.js +3 -0
  167. package/dist/triggers/index.d.ts +3 -0
  168. package/dist/triggers/index.js +5 -0
  169. package/docs/content/cross-app-sso.mdx +26 -0
  170. package/package.json +1 -1
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-08-03
4
+ ---
5
+
6
+ Export preview shows the selected element instead of the whole screen, with its real pixel size.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-08-03
4
+ ---
5
+
6
+ Inspector sections show an expand indicator, so it is clear which ones open.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-08-03
4
+ ---
5
+
6
+ Pasting with a frame selected now places the copy inside that frame, joining its auto layout when it has one, while pasting with an object selected still places the copy beside it.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-08-03
4
+ ---
5
+
6
+ The add-breakpoint button sits outside the breakpoint selector, so it no longer looks like a breakpoint you can pick.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-08-03
4
+ ---
5
+
6
+ The agent's follow-up questions keep space below the Continue buttons instead of pinning them to the bottom edge.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-08-03
4
+ ---
5
+
6
+ The agent's follow-up questions share the chat panel's background, so they read as part of the conversation.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-08-03
4
+ ---
5
+
6
+ The export panel no longer stacks a duplicate Export block on every inspector update.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-08-03
4
+ ---
5
+
6
+ The text tool uses a T icon, matching the letter it inserts.
@@ -4,6 +4,15 @@ PING_MESSAGE=pong
4
4
  # Email stamped as the creator of the deployment-owned observation scheduler.
5
5
  WORKSPACE_OWNER_EMAIL=
6
6
 
7
+ # Optional explicit id of the Dispatch vault organization. Leave blank when
8
+ # the deployment owner is a member of the organization where Dispatch synced
9
+ # the shared keys. This is an org id, not a secret.
10
+ AGENT_VAULT_ORG_ID=
11
+
12
+ # Use the same stable workspace key as Dispatch and sibling apps so they can
13
+ # decrypt shared app_secrets rows. Do not rotate this independently per app.
14
+ WORKSPACE_SECRETS_ENCRYPTION_KEY=
15
+
7
16
  # Public URL used for signed Builder completion callbacks after an explicit
8
17
  # approval. Keep this aligned with the deployed Netlify URL until a custom
9
18
  # domain is explicitly approved and configured.
@@ -20,5 +29,13 @@ BUILDER_PROJECT_ID=
20
29
  BUILDER_PRIVATE_KEY=
21
30
  FACTORY_BUILDER_WEBHOOK_SECRET=
22
31
 
32
+ # Optional deployment fallbacks. Prefer Dispatch Vault and leave these blank
33
+ # when the shared workspace secret rows are available.
34
+ SLACK_BOT_TOKEN=
35
+ GITHUB_TOKEN=
36
+ SENTRY_SERVER_TOKEN=
37
+ SENTRY_AUTH_TOKEN=
38
+ SENTRY_ORG_SLUG=
39
+
23
40
  # Skip login/signup (local dev / preview only)
24
41
  # AUTH_DISABLED=true
@@ -27,27 +27,30 @@ ladder.
27
27
  `packages/*` changes always require human review.
28
28
  - All work is deduped by Factory item and rule/run identity. Provider comment IDs
29
29
  are not the idempotency boundary.
30
- - Slack interaction uses the generic Agent-Native Slack adapter. Polling is for
31
- observation; mentions are for explanation, rule tuning, and explicit approval.
30
+ - Slack interaction uses the generic Agent-Native Slack adapter. Clear-bug Slack
31
+ automations add 👀 and tag `@builderio` in the source thread; GitHub and Sentry
32
+ clear bugs use the Builder run API. Clips, Design, and Content are always
33
+ owner-managed and never enter autonomous dispatch or PR governance.
34
+ - PR governance requires verified internal BuilderIO membership, a clear bug,
35
+ passing CI, and handled review feedback. Product or UX implications stay
36
+ manual. Auto-merge additionally requires a verified Factory Builder run.
32
37
  - Reuse the existing ai-services GitHub read and Builder execution APIs. Do not
33
38
  duplicate GitHub installation/webhook infrastructure in this template.
34
39
  - Do not add CRUD routes under `server/routes/api/`; actions are the domain
35
40
  surface. Provider callbacks are the only exception and must verify signatures.
36
41
  - Factory graph edits create immutable blueprint versions. AI proposes a
37
42
  complete graph with `source=ai`; a person reviews and publishes it through
38
- the same action surface as manual edits. The current evaluator runs enabled
39
- rules in parallel, so graph edges describe intended handoffs until a runtime
40
- binding exists.
41
- - A selected graph node or edge is part of `navigation` context. Read
42
- `view-screen` before answering why a route exists or changing the selected
43
- Factory.
43
+ the same action surface as manual edits.
44
44
 
45
45
  ## Application state
46
46
 
47
47
  - `navigation.view`: `factory` when the visual workspace is open.
48
48
  - `navigation.factoryId`: selected Factory id when present.
49
- - `navigation.factoryTab`: `map` | `inbox` | `rules` | `settings`.
49
+ - `navigation.factoryTab`: `map` | `inbox` | `rules` | `automations` | `settings`.
50
50
  - `navigation.factoryNodeId` / `navigation.factoryEdgeId`: selected graph target.
51
+ - A selected graph node or edge is part of `navigation` context. Read
52
+ `view-screen` before answering why a route exists or changing the selected
53
+ Factory.
51
54
 
52
55
  ## Action contract
53
56
 
@@ -55,20 +58,26 @@ ladder.
55
58
  | --- | --- |
56
59
  | `list-triage-items` / `get-triage-item` | Inspect the queue and evidence. |
57
60
  | `poll-slack-channel` | Observe Slack history; never writes to Slack. |
61
+ | `get-slack-feedback-context` | Read the bounded full Slack thread before classification. |
62
+ | `poll-github-sources` / `poll-sentry-errors` | Observe bounded GitHub and Sentry source queues. |
58
63
  | `ingest-github-observation` | Store read-only PR evidence. |
59
64
  | `list-triage-rules` / `save-triage-rule` | Tune prompt rules and guards. |
60
65
  | `evaluate-triage-item` | Append a structured decision. |
61
66
  | `record-triage-feedback` | Capture human correction for learning. |
62
67
  | `approve-factory-item` | Explicitly authorize one bounded run. |
68
+ | `start-builder-for-item` | Govern clear-bug dispatch; Slack tags Builder in-thread, other sources use Builder API. |
69
+ | `govern-agent-native-pull-request` | Apply CI, review, internal-author, product, and owner gates to PR approval/merge. |
70
+ | `list-factory-automations` / `save-factory-automation` / `run-factory-automation` | Inspect and edit organization-owned Factory prompts, models, schedules, and runs. |
63
71
  | `suggest-factory-rules` | Mine feedback and fast approvals into proposals. |
64
72
  | `reconcile-triage-run` | Persist callback/provider reconciliation. |
65
73
  | `list-factories` / `get-factory-graph` | Inspect Factory definitions, graph versions, and live evidence metrics. |
66
74
  | `save-factory-graph` | Create or version a complete visual graph; never starts provider work. |
67
75
  | `list-factory-comments` / `add-factory-comment` | Read or attach comments to a canvas, node, or edge. |
68
76
 
69
- Rules start in shadow mode. Enabling a rule never bypasses hard guards or
70
- creates an implicit approval. Slack "do it now" and the UI approval control
71
- both call `approve-factory-item`, which records the approver before dispatch.
77
+ Rules start in shadow mode; hard guards always apply. Editable organization
78
+ automations execute stored prompts; every external mutation needs a durable run,
79
+ idempotency key, and provider confirmation. The legacy observer is disabled
80
+ when organization automations are seeded.
72
81
 
73
82
  Use the visual editor for direct blueprint changes. Use the agent chat for
74
83
  natural language design, explanations, and proposals; it must preserve a
@@ -78,13 +87,14 @@ actions, never through graph JSON.
78
87
 
79
88
  ## Scheduler identity
80
89
 
81
- `WORKSPACE_OWNER_EMAIL` is read only at startup to stamp the deployment-owned
82
- job's `createdBy`; it is never caller identity and must not enter request
83
- authorization or credential resolution.
90
+ `WORKSPACE_OWNER_EMAIL` is read only at startup to find the deployment
91
+ organization and stamp seeded automation `createdBy`; it is never caller
92
+ identity and must not enter request authorization or credential resolution.
84
93
 
85
94
  ## Hosting
86
95
 
87
96
  Production needs `DATABASE_URL`, `WORKSPACE_OWNER_EMAIL`, and
88
97
  `FACTORY_PUBLIC_URL`. Builder execution additionally needs the service URL and
89
- project ID plus workspace-resolved Builder credentials. Keep rules in shadow
90
- mode and require an explicit approval for every provider run.
98
+ project ID plus workspace-resolved Builder credentials. GitHub and Sentry
99
+ polling use workspace-resolved provider credentials. Provider callbacks and
100
+ external writes must remain auditable and fail closed when evidence is partial.
@@ -29,11 +29,19 @@ without a terminal record.
29
29
 
30
30
  ## Configure Slack
31
31
 
32
- Set `WORKSPACE_OWNER_EMAIL` to an existing workspace member for the deployment-
33
- owned scheduler job. Connect Slack in Settings -> Messaging; Factory resolves
34
- the workspace credential through the vault resolver and only uses
35
- `SLACK_BOT_TOKEN` as the resolver's deployment fallback. Do not add a second
36
- env-only read.
32
+ Set `WORKSPACE_OWNER_EMAIL` to an existing member of the Builder.io organization
33
+ that Dispatch uses. Factory does not need a separate organization: startup
34
+ finds that existing organization and seeds its organization-owned automations.
35
+ If Dispatch synced the vault into a different organization, set
36
+ `AGENT_VAULT_ORG_ID` to that existing org id instead of creating a new org.
37
+
38
+ Connect Slack in Dispatch or in Settings -> Connections. Factory resolves
39
+ Slack, GitHub, Sentry, and Builder credentials from the shared workspace vault
40
+ and only uses matching deployment env vars as a last-resort fallback. All apps
41
+ that read shared `app_secrets` rows must use the same
42
+ `WORKSPACE_SECRETS_ENCRYPTION_KEY` (or the workspace's existing shared
43
+ encryption fallback). Never copy raw tokens between apps or add a second
44
+ env-only read in a provider client.
37
45
 
38
46
  In Factory, set the Slack workspace, channel ID, channel name, repository, and
39
47
  polling switch. The default scheduler polls once per minute, evaluates a
@@ -47,11 +55,13 @@ inspectable Factory link when a human decision is required.
47
55
  ## Hosting
48
56
 
49
57
  Production expects a direct PostgreSQL `DATABASE_URL`,
50
- `WORKSPACE_OWNER_EMAIL`, and `FACTORY_PUBLIC_URL`. The Builder executor also
58
+ `WORKSPACE_OWNER_EMAIL`, and `FACTORY_PUBLIC_URL`. `AGENT_VAULT_ORG_ID` is
59
+ optional and is only needed when the deployment owner cannot reach the existing
60
+ Dispatch vault organization through membership. The Builder executor also
51
61
  needs `BUILDER_AI_SERVICES_URL` and `BUILDER_PROJECT_ID`; its private key and
52
- signed callback secret belong in workspace credentials and are resolved at
53
- runtime. The app remains observe-only until a human explicitly approves a
54
- Factory item.
62
+ signed callback secret belong in Dispatch workspace credentials and are
63
+ resolved at runtime. The app remains observe-only until a human explicitly
64
+ approves a Factory item.
55
65
 
56
66
  ## Development
57
67
 
@@ -0,0 +1,90 @@
1
+ import { defineAction } from "@agent-native/core/action";
2
+ import { and, eq } from "drizzle-orm";
3
+ import { z } from "zod";
4
+
5
+ import type { SlackMessage } from "../server/connectors/slack.js";
6
+ import { getDb } from "../server/db/index.js";
7
+ import { triageConfig, triageItems } from "../server/db/schema.js";
8
+ import {
9
+ requireWorkspaceMember,
10
+ workspaceMemberIdentityFromContext,
11
+ } from "../server/lib/require-workspace-member.js";
12
+ import { createSlackReader } from "../server/triage/slack-client.js";
13
+
14
+ const MAX_THREAD_PAGES = 5;
15
+
16
+ export default defineAction({
17
+ description:
18
+ "Read the bounded full Slack thread for one Factory feedback item. Use this before deciding whether a report is a clear bug; unreadable or truncated context is not a green light.",
19
+ schema: z.object({ itemId: z.string().min(1) }),
20
+ http: { method: "GET" },
21
+ readOnly: true,
22
+ run: async ({ itemId }, context) => {
23
+ const { userEmail, orgId } = await requireWorkspaceMember(
24
+ workspaceMemberIdentityFromContext(context),
25
+ );
26
+ const item = (
27
+ await getDb()
28
+ .select()
29
+ .from(triageItems)
30
+ .where(and(eq(triageItems.id, itemId), eq(triageItems.orgId, orgId)))
31
+ .limit(1)
32
+ )[0];
33
+ if (!item) throw new Error("Factory item not found.");
34
+ if (item.source !== "slack" || !item.channelId || !item.threadTs) {
35
+ throw new Error("Factory item is not a readable Slack feedback item.");
36
+ }
37
+
38
+ const config = (
39
+ await getDb()
40
+ .select({ slackWorkspace: triageConfig.slackWorkspace })
41
+ .from(triageConfig)
42
+ .where(and(eq(triageConfig.id, orgId), eq(triageConfig.orgId, orgId)))
43
+ .limit(1)
44
+ )[0];
45
+ const workspace =
46
+ config?.slackWorkspace === "secondary" ? "secondary" : "primary";
47
+ const slack = createSlackReader({ ownerEmail: userEmail, orgId });
48
+ const messages: SlackMessage[] = [];
49
+ let cursor: string | undefined;
50
+ let hasMore = false;
51
+ for (let page = 0; page < MAX_THREAD_PAGES; page += 1) {
52
+ const result = await slack.getThread(
53
+ workspace,
54
+ item.channelId,
55
+ item.threadTs,
56
+ 100,
57
+ cursor,
58
+ );
59
+ messages.push(...result.messages);
60
+ if (result.has_more && !result.next_cursor) {
61
+ throw new Error(
62
+ "Slack thread pagination is incomplete because the provider omitted its next cursor.",
63
+ );
64
+ }
65
+ if (!result.has_more) {
66
+ hasMore = false;
67
+ break;
68
+ }
69
+ hasMore = page === MAX_THREAD_PAGES - 1;
70
+ if (hasMore) break;
71
+ cursor = result.next_cursor;
72
+ }
73
+
74
+ return {
75
+ ok: true,
76
+ itemId,
77
+ sourceUrl: item.sourceUrl,
78
+ channelId: item.channelId,
79
+ threadTs: item.threadTs,
80
+ coverage: hasMore ? "partial" : "complete",
81
+ messages: messages.map((message) => ({
82
+ user: message.user ?? message.username ?? message.bot_id ?? null,
83
+ text: message.text,
84
+ ts: message.ts,
85
+ threadTs: message.thread_ts ?? item.threadTs,
86
+ replyCount: message.reply_count ?? 0,
87
+ })),
88
+ };
89
+ },
90
+ });
@@ -1,5 +1,5 @@
1
1
  import { defineAction } from "@agent-native/core/action";
2
- import { eq } from "drizzle-orm";
2
+ import { and, eq } from "drizzle-orm";
3
3
  import { z } from "zod";
4
4
 
5
5
  import { getDb } from "../server/db/index.js";
@@ -23,7 +23,7 @@ export default defineAction({
23
23
  await getDb()
24
24
  .select()
25
25
  .from(triageConfig)
26
- .where(eq(triageConfig.id, orgId))
26
+ .where(and(eq(triageConfig.id, orgId), eq(triageConfig.orgId, orgId)))
27
27
  .limit(1)
28
28
  )[0];
29
29
  if (!row) {
@@ -35,8 +35,19 @@ export default defineAction({
35
35
  lastSlackTs: null,
36
36
  slackHistoryCursor: null,
37
37
  repository: null,
38
+ githubPollingEnabled: false,
39
+ sentryPollingEnabled: false,
40
+ sentryOrgSlug: null,
41
+ sentryProjectSlug: null,
42
+ sentryEnvironment: null,
43
+ lastSentrySeenAt: null,
38
44
  };
39
45
  }
40
- return { ...row, pollingEnabled: row.pollingEnabled === 1 };
46
+ return {
47
+ ...row,
48
+ pollingEnabled: row.pollingEnabled === 1,
49
+ githubPollingEnabled: row.githubPollingEnabled === 1,
50
+ sentryPollingEnabled: row.sentryPollingEnabled === 1,
51
+ };
41
52
  },
42
53
  });