@antelopejs/dms-ai 0.8.0 → 0.9.1
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/README.md +2 -1
- package/dist/lifecycle/skill-sources.js +19 -146
- package/dist/lifecycle/skill-sources.js.map +1 -1
- package/dist/pages/settings/availability.js +8 -1
- package/dist/pages/settings/availability.js.map +1 -1
- package/dist/pages/settings/options.d.ts +2 -1
- package/dist/pages/settings/options.js +29 -8
- package/dist/pages/settings/options.js.map +1 -1
- package/dist/pages/settings/sections.js +25 -4
- package/dist/pages/settings/sections.js.map +1 -1
- package/dist/routes/builder.d.ts +3 -3
- package/dist/routes/builder.js +10 -2
- package/dist/routes/builder.js.map +1 -1
- package/dist/routes/settings.js +1 -1
- package/dist/routes/settings.js.map +1 -1
- package/dist/sidecar/settings-values.d.ts +3 -0
- package/dist/sidecar/settings-values.js +33 -1
- package/dist/sidecar/settings-values.js.map +1 -1
- package/dist/vocabulary/enumerations.js +2 -0
- package/dist/vocabulary/enumerations.js.map +1 -1
- package/dist/vocabulary/tools.js +3 -0
- package/dist/vocabulary/tools.js.map +1 -1
- package/frontend-vue/app/chat/components/ChatView.vue +53 -85
- package/frontend-vue/app/chat/components/Composer.vue +23 -39
- package/frontend-vue/app/chat/components/NoticeCard.vue +25 -0
- package/frontend-vue/app/chat/components/PanelHeader.vue +2 -6
- package/frontend-vue/app/chat/components/ProviderNotice.vue +14 -3
- package/frontend-vue/app/chat/composables/conversation-events.ts +4 -3
- package/frontend-vue/app/chat/composables/useConversation.ts +6 -0
- package/frontend-vue/app/chat/composables/useConversationMode.ts +8 -11
- package/frontend-vue/app/chat/composables/useFollowScroll.ts +77 -0
- package/frontend-vue/app/chat/constants/modes.ts +15 -0
- package/frontend-vue/app/chat/constants/protocol.ts +0 -1
- package/frontend-vue/app/chat/constants/settings.ts +1 -1
- package/frontend-vue/app/chat/types/protocol.ts +19 -9
- package/frontend-vue/app/chat/types/settings.ts +7 -2
- package/frontend-vue/app/chat/utils/permission-view.ts +1 -0
- package/frontend-vue/app/chat/utils/status-label.ts +50 -0
- package/frontend-vue/app/chat/utils/tool-lexicon.ts +16 -0
- package/frontend-vue/app/plugins/ai.client.ts +2 -2
- package/frontend-vue/app/runtime/assistant-actions.ts +4 -2
- package/frontend-vue/app/runtime/assistant-session.ts +5 -1
- package/frontend-vue/app/runtime/block-health.ts +135 -0
- package/frontend-vue/app/runtime/constants.ts +1 -0
- package/frontend-vue/app/runtime/navigation-complete.ts +47 -6
- package/frontend-vue/app/runtime/panel-intents.ts +6 -2
- package/frontend-vue/app/views/constants.ts +2 -0
- package/frontend-vue/app/views/types.ts +3 -1
- package/frontend-vue/i18n/locales/dms-ai-pages-en-GB.json +28 -11
- package/frontend-vue/i18n/locales/dms-ai-pages-fr-FR.json +28 -11
- package/frontend-vue/i18n/locales/dms-ai-panel-en-GB.json +17 -22
- package/frontend-vue/i18n/locales/dms-ai-panel-fr-FR.json +17 -22
- package/frontend-vue/i18n/locales/dms-ai-views-en-GB.json +2 -0
- package/frontend-vue/i18n/locales/dms-ai-views-fr-FR.json +2 -0
- package/frontend-vue/tests/assistant-actions.test.ts +37 -0
- package/frontend-vue/tests/block-health.test.ts +142 -0
- package/frontend-vue/tests/chat/chat-scroll.test.ts +251 -0
- package/frontend-vue/tests/chat/conversation-events.test.ts +35 -3
- package/frontend-vue/tests/chat/provider-notice.test.ts +33 -0
- package/frontend-vue/tests/chat/tool-lexicon.test.ts +1 -0
- package/frontend-vue/tests/chat-panel.test.ts +2 -4
- package/frontend-vue/tests/navigation.test.ts +67 -2
- package/frontend-vue/tests/panel-modes.test.ts +146 -0
- package/frontend-vue/tests/panel-questions.test.ts +1 -19
- package/frontend-vue/tests/panel-states.test.ts +3 -15
- package/frontend-vue/tests/support/fake-layout.ts +119 -0
- package/frontend-vue/tests/support/panel-harness.ts +16 -8
- package/frontend-vue/tests/support/setup-layout.ts +3 -0
- package/frontend-vue/tests/support/stubs.ts +2 -0
- package/frontend-vue/vitest.config.ts +1 -0
- package/package.json +6 -5
- package/sidecar/dist/agent/always-ask-files.d.ts +2 -0
- package/sidecar/dist/agent/always-ask-files.js +34 -0
- package/sidecar/dist/agent/always-ask-files.js.map +1 -0
- package/sidecar/dist/agent/conversation-modes.d.ts +3 -12
- package/sidecar/dist/agent/conversation-modes.js +16 -69
- package/sidecar/dist/agent/conversation-modes.js.map +1 -1
- package/sidecar/dist/agent/effective-mode.d.ts +2 -5
- package/sidecar/dist/agent/effective-mode.js +1 -15
- package/sidecar/dist/agent/effective-mode.js.map +1 -1
- package/sidecar/dist/agent/permission-bus.d.ts +1 -2
- package/sidecar/dist/agent/permission-bus.js +1 -3
- package/sidecar/dist/agent/permission-bus.js.map +1 -1
- package/sidecar/dist/agent/permission-preview.d.ts +6 -0
- package/sidecar/dist/agent/permission-preview.js +35 -10
- package/sidecar/dist/agent/permission-preview.js.map +1 -1
- package/sidecar/dist/agent/permission-rules.js +2 -2
- package/sidecar/dist/agent/permission-rules.js.map +1 -1
- package/sidecar/dist/agent/project-secrets.d.ts +7 -0
- package/sidecar/dist/agent/project-secrets.js +61 -0
- package/sidecar/dist/agent/project-secrets.js.map +1 -0
- package/sidecar/dist/agent/provider.d.ts +10 -4
- package/sidecar/dist/agent/runner.d.ts +8 -2
- package/sidecar/dist/agent/runner.js +11 -3
- package/sidecar/dist/agent/runner.js.map +1 -1
- package/sidecar/dist/agent/session.d.ts +3 -3
- package/sidecar/dist/agent/session.js.map +1 -1
- package/sidecar/dist/agent/tool-kinds.d.ts +7 -1
- package/sidecar/dist/agent/tool-kinds.js +24 -5
- package/sidecar/dist/agent/tool-kinds.js.map +1 -1
- package/sidecar/dist/audit/activity-query.js +2 -0
- package/sidecar/dist/audit/activity-query.js.map +1 -1
- package/sidecar/dist/audit/activity.js +1 -0
- package/sidecar/dist/audit/activity.js.map +1 -1
- package/sidecar/dist/builder/builder-client.js +14 -2
- package/sidecar/dist/builder/builder-client.js.map +1 -1
- package/sidecar/dist/constants/audit.d.ts +1 -3
- package/sidecar/dist/constants/audit.js +2 -1
- package/sidecar/dist/constants/audit.js.map +1 -1
- package/sidecar/dist/constants/builder.d.ts +5 -1
- package/sidecar/dist/constants/builder.js +15 -0
- package/sidecar/dist/constants/builder.js.map +1 -1
- package/sidecar/dist/constants/claude.d.ts +8 -0
- package/sidecar/dist/constants/claude.js +8 -0
- package/sidecar/dist/constants/claude.js.map +1 -1
- package/sidecar/dist/constants/codex.d.ts +4 -0
- package/sidecar/dist/constants/codex.js +4 -0
- package/sidecar/dist/constants/codex.js.map +1 -1
- package/sidecar/dist/constants/mcp.d.ts +1 -1
- package/sidecar/dist/constants/mcp.js +1 -1
- package/sidecar/dist/constants/mcp.js.map +1 -1
- package/sidecar/dist/constants/native-binary.d.ts +5 -2
- package/sidecar/dist/constants/native-binary.js +5 -2
- package/sidecar/dist/constants/native-binary.js.map +1 -1
- package/sidecar/dist/constants/permissions.d.ts +2 -0
- package/sidecar/dist/constants/permissions.js +23 -0
- package/sidecar/dist/constants/permissions.js.map +1 -1
- package/sidecar/dist/constants/project-secrets.d.ts +5 -0
- package/sidecar/dist/constants/project-secrets.js +20 -0
- package/sidecar/dist/constants/project-secrets.js.map +1 -0
- package/sidecar/dist/constants/providers.d.ts +2 -0
- package/sidecar/dist/constants/providers.js +1 -0
- package/sidecar/dist/constants/providers.js.map +1 -1
- package/sidecar/dist/constants/settings.d.ts +2 -2
- package/sidecar/dist/constants/settings.js +4 -9
- package/sidecar/dist/constants/settings.js.map +1 -1
- package/sidecar/dist/constants/timing.d.ts +1 -0
- package/sidecar/dist/constants/timing.js +1 -0
- package/sidecar/dist/constants/timing.js.map +1 -1
- package/sidecar/dist/constants/tool-kinds.d.ts +67 -2
- package/sidecar/dist/constants/tool-kinds.js +111 -33
- package/sidecar/dist/constants/tool-kinds.js.map +1 -1
- package/sidecar/dist/mcp/tools/builder-compose.d.ts +51 -0
- package/sidecar/dist/mcp/tools/builder-compose.js +96 -0
- package/sidecar/dist/mcp/tools/builder-compose.js.map +1 -0
- package/sidecar/dist/mcp/tools/builder-gate.js +3 -1
- package/sidecar/dist/mcp/tools/builder-gate.js.map +1 -1
- package/sidecar/dist/mcp/tools/builder-project.js +119 -4
- package/sidecar/dist/mcp/tools/builder-project.js.map +1 -1
- package/sidecar/dist/mcp/tools/builder-queries.d.ts +31 -0
- package/sidecar/dist/mcp/tools/builder-queries.js +30 -13
- package/sidecar/dist/mcp/tools/builder-queries.js.map +1 -1
- package/sidecar/dist/mcp/tools/builder-table-view-schema.d.ts +99 -0
- package/sidecar/dist/mcp/tools/builder-table-view-schema.js +118 -0
- package/sidecar/dist/mcp/tools/builder-table-view-schema.js.map +1 -0
- package/sidecar/dist/mcp/tools/builder-table-view.d.ts +102 -0
- package/sidecar/dist/mcp/tools/builder-table-view.js +24 -0
- package/sidecar/dist/mcp/tools/builder-table-view.js.map +1 -0
- package/sidecar/dist/mcp/tools/builder.d.ts +135 -1
- package/sidecar/dist/mcp/tools/builder.js +17 -4
- package/sidecar/dist/mcp/tools/builder.js.map +1 -1
- package/sidecar/dist/mcp/tools/navigate-to-page.js +12 -4
- package/sidecar/dist/mcp/tools/navigate-to-page.js.map +1 -1
- package/sidecar/dist/pages/block-health.d.ts +14 -0
- package/sidecar/dist/pages/block-health.js +60 -0
- package/sidecar/dist/pages/block-health.js.map +1 -0
- package/sidecar/dist/prompts/agent.d.ts +1 -1
- package/sidecar/dist/prompts/agent.js +4 -3
- package/sidecar/dist/prompts/agent.js.map +1 -1
- package/sidecar/dist/protocol/events.d.ts +140 -63
- package/sidecar/dist/protocol/events.js +24 -8
- package/sidecar/dist/protocol/events.js.map +1 -1
- package/sidecar/dist/protocol/messages.d.ts +111 -49
- package/sidecar/dist/protocol/messages.js +30 -13
- package/sidecar/dist/protocol/messages.js.map +1 -1
- package/sidecar/dist/providers/claude/config.d.ts +19 -5
- package/sidecar/dist/providers/claude/config.js +21 -7
- package/sidecar/dist/providers/claude/config.js.map +1 -1
- package/sidecar/dist/providers/claude/model-fallback.d.ts +9 -0
- package/sidecar/dist/providers/claude/model-fallback.js +37 -0
- package/sidecar/dist/providers/claude/model-fallback.js.map +1 -0
- package/sidecar/dist/providers/claude/provider.js +35 -40
- package/sidecar/dist/providers/claude/provider.js.map +1 -1
- package/sidecar/dist/providers/claude/resolve-binary.js +18 -13
- package/sidecar/dist/providers/claude/resolve-binary.js.map +1 -1
- package/sidecar/dist/providers/claude/safe-mode.d.ts +5 -5
- package/sidecar/dist/providers/claude/safe-mode.js +49 -30
- package/sidecar/dist/providers/claude/safe-mode.js.map +1 -1
- package/sidecar/dist/providers/claude/secret-files.d.ts +2 -0
- package/sidecar/dist/providers/claude/secret-files.js +50 -0
- package/sidecar/dist/providers/claude/secret-files.js.map +1 -0
- package/sidecar/dist/providers/claude/session-stream.d.ts +18 -0
- package/sidecar/dist/providers/claude/session-stream.js +80 -0
- package/sidecar/dist/providers/claude/session-stream.js.map +1 -0
- package/sidecar/dist/providers/claude/tool-guard.d.ts +14 -0
- package/sidecar/dist/providers/claude/tool-guard.js +112 -0
- package/sidecar/dist/providers/claude/tool-guard.js.map +1 -0
- package/sidecar/dist/providers/codex/adapter.d.ts +10 -0
- package/sidecar/dist/providers/codex/adapter.js +20 -5
- package/sidecar/dist/providers/codex/adapter.js.map +1 -1
- package/sidecar/dist/providers/codex/config.d.ts +6 -17
- package/sidecar/dist/providers/codex/config.js +9 -56
- package/sidecar/dist/providers/codex/config.js.map +1 -1
- package/sidecar/dist/providers/codex/mcp-elicitation.d.ts +21 -0
- package/sidecar/dist/providers/codex/mcp-elicitation.js +66 -0
- package/sidecar/dist/providers/codex/mcp-elicitation.js.map +1 -0
- package/sidecar/dist/providers/codex/module.js +1 -1
- package/sidecar/dist/providers/codex/module.js.map +1 -1
- package/sidecar/dist/providers/codex/patch-directories.d.ts +6 -0
- package/sidecar/dist/providers/codex/patch-directories.js +53 -0
- package/sidecar/dist/providers/codex/patch-directories.js.map +1 -0
- package/sidecar/dist/providers/codex/permission-profiles.d.ts +11 -0
- package/sidecar/dist/providers/codex/permission-profiles.js +37 -0
- package/sidecar/dist/providers/codex/permission-profiles.js.map +1 -0
- package/sidecar/dist/providers/codex/permissions.d.ts +13 -4
- package/sidecar/dist/providers/codex/permissions.js +28 -2
- package/sidecar/dist/providers/codex/permissions.js.map +1 -1
- package/sidecar/dist/providers/codex/process.d.ts +1 -0
- package/sidecar/dist/providers/codex/process.js +3 -1
- package/sidecar/dist/providers/codex/process.js.map +1 -1
- package/sidecar/dist/providers/codex/protocol/common.d.ts +16 -4
- package/sidecar/dist/providers/codex/protocol/index.d.ts +2 -2
- package/sidecar/dist/providers/codex/protocol/index.js +1 -1
- package/sidecar/dist/providers/codex/protocol/index.js.map +1 -1
- package/sidecar/dist/providers/codex/protocol/v2.d.ts +23 -32
- package/sidecar/dist/providers/codex/provider.js +13 -12
- package/sidecar/dist/providers/codex/provider.js.map +1 -1
- package/sidecar/dist/providers/codex/secret-file-globs.d.ts +2 -0
- package/sidecar/dist/providers/codex/secret-file-globs.js +45 -0
- package/sidecar/dist/providers/codex/secret-file-globs.js.map +1 -0
- package/sidecar/dist/providers/types.d.ts +3 -1
- package/sidecar/dist/providers/types.js +2 -2
- package/sidecar/dist/providers/types.js.map +1 -1
- package/sidecar/dist/server/chat-events.js +1 -0
- package/sidecar/dist/server/chat-events.js.map +1 -1
- package/sidecar/dist/server/http-routes.js +1 -1
- package/sidecar/dist/server/http-routes.js.map +1 -1
- package/sidecar/dist/server/navigation-completer.d.ts +15 -2
- package/sidecar/dist/server/navigation-completer.js +42 -41
- package/sidecar/dist/server/navigation-completer.js.map +1 -1
- package/sidecar/dist/server/permission-events.d.ts +1 -1
- package/sidecar/dist/server/permission-events.js +5 -8
- package/sidecar/dist/server/permission-events.js.map +1 -1
- package/sidecar/dist/server/routing.js +11 -6
- package/sidecar/dist/server/routing.js.map +1 -1
- package/sidecar/dist/server/tool-calls.d.ts +0 -2
- package/sidecar/dist/server/tool-calls.js +7 -8
- package/sidecar/dist/server/tool-calls.js.map +1 -1
- package/sidecar/dist/server/turns.js +17 -1
- package/sidecar/dist/server/turns.js.map +1 -1
- package/sidecar/dist/server/ws.js +4 -15
- package/sidecar/dist/server/ws.js.map +1 -1
- package/sidecar/dist/skills/skill-usage.js +2 -2
- package/sidecar/dist/skills/skill-usage.js.map +1 -1
- package/sidecar/dist/state/conversations.d.ts +1 -0
- package/sidecar/dist/state/conversations.js +8 -0
- package/sidecar/dist/state/conversations.js.map +1 -1
- package/sidecar/dist/state/settings-store.d.ts +14 -5
- package/sidecar/dist/state/settings-store.js +34 -8
- package/sidecar/dist/state/settings-store.js.map +1 -1
- package/sidecar/dist/state/settings-types.d.ts +16 -2
- package/sidecar/dist/state/settings-types.js +14 -1
- package/sidecar/dist/state/settings-types.js.map +1 -1
- package/sidecar/dist/state/types.d.ts +14 -6
- package/sidecar/dist/state/types.js.map +1 -1
- package/sidecar/package.json +3 -3
- package/skills/dms-ai/SKILL.md +2 -1
- package/skills/dms-builder-safe/REFERENCE.md +5 -6
- package/skills/dms-builder-safe/SKILL.md +12 -10
- package/skills/dms-external-database/REFERENCE.md +20 -8
- package/skills/dms-external-database/SKILL.md +69 -20
- package/skills/dms-page-design/SKILL.md +192 -0
- package/skills/dms-page-design/cases.json +57 -0
- package/frontend-vue/app/chat/components/FullAutoBanner.vue +0 -76
- package/frontend-vue/app/chat/components/FullAutoDialog.vue +0 -103
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { computed, type ComputedRef, type Ref } from "vue";
|
|
2
|
+
import { modeFor } from "../constants/modes";
|
|
2
3
|
import { CLIENT_MESSAGE_TYPES } from "../constants/protocol";
|
|
3
4
|
import type {
|
|
4
5
|
ApprovalMode,
|
|
5
6
|
ConversationModeState,
|
|
6
|
-
FullAutoDuration,
|
|
7
7
|
Scope,
|
|
8
8
|
} from "../types/protocol";
|
|
9
9
|
import type { AppSettings } from "../types/settings";
|
|
@@ -17,12 +17,10 @@ export interface UseConversationModeOptions {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export interface UseConversationModeResult {
|
|
20
|
-
/** The chat's mode
|
|
20
|
+
/** The chat's mode and its scope, defaults until the sidecar says. */
|
|
21
21
|
current: ComputedRef<ConversationModeState>;
|
|
22
22
|
setMode: (mode: ApprovalMode) => void;
|
|
23
23
|
setScope: (scope: Scope) => void;
|
|
24
|
-
startFullAuto: (duration: FullAutoDuration) => void;
|
|
25
|
-
stopFullAuto: () => void;
|
|
26
24
|
}
|
|
27
25
|
|
|
28
26
|
function effectiveScope(scope: Scope, builderAvailable: boolean): Scope {
|
|
@@ -30,9 +28,10 @@ function effectiveScope(scope: Scope, builderAvailable: boolean): Scope {
|
|
|
30
28
|
}
|
|
31
29
|
|
|
32
30
|
/**
|
|
33
|
-
* The active chat's approval mode
|
|
34
|
-
* or the
|
|
35
|
-
*
|
|
31
|
+
* The active chat's approval mode and scope: what the sidecar says,
|
|
32
|
+
* or the current provider's default from the settings until it has. A mode the
|
|
33
|
+
* provider does not have reads as Ask first. Changes apply at once here and
|
|
34
|
+
* are sent for the sidecar to confirm.
|
|
36
35
|
*/
|
|
37
36
|
export function useConversationMode(
|
|
38
37
|
options: UseConversationModeOptions,
|
|
@@ -40,12 +39,12 @@ export function useConversationMode(
|
|
|
40
39
|
const current = computed<ConversationModeState>(() => {
|
|
41
40
|
const { settings, mode } = options;
|
|
42
41
|
const base: ConversationModeState = mode.value ?? {
|
|
43
|
-
mode: settings.value.
|
|
42
|
+
mode: settings.value.defaultModes[settings.value.provider],
|
|
44
43
|
generationMode: settings.value.generationMode,
|
|
45
|
-
fullAuto: null,
|
|
46
44
|
};
|
|
47
45
|
return {
|
|
48
46
|
...base,
|
|
47
|
+
mode: modeFor(settings.value.provider, base.mode),
|
|
49
48
|
generationMode: effectiveScope(
|
|
50
49
|
base.generationMode,
|
|
51
50
|
settings.value.builderAvailable,
|
|
@@ -67,7 +66,5 @@ export function useConversationMode(
|
|
|
67
66
|
current,
|
|
68
67
|
setMode: (mode) => change({ mode }),
|
|
69
68
|
setScope: (generationMode) => change({ generationMode }),
|
|
70
|
-
startFullAuto: (duration) => change({ fullAuto: { duration } }),
|
|
71
|
-
stopFullAuto: () => change({ fullAuto: null }),
|
|
72
69
|
};
|
|
73
70
|
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { type Ref, watch } from "vue";
|
|
2
|
+
|
|
3
|
+
const BOTTOM_EPSILON_PX = 4;
|
|
4
|
+
|
|
5
|
+
function distanceFromBottom(el: HTMLElement): number {
|
|
6
|
+
return el.scrollHeight - el.scrollTop - el.clientHeight;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function scrollToBottom(el: HTMLElement): void {
|
|
10
|
+
el.scrollTop = el.scrollHeight;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Keeps a scrolling container on its newest content while it follows. The
|
|
15
|
+
* view follows from the start. An upward scroll that leaves it more than a few
|
|
16
|
+
* pixels from the bottom stops the following, whatever caused it (wheel, keys,
|
|
17
|
+
* scrollbar, find in page, text selection). A scroll that reaches the bottom,
|
|
18
|
+
* or a call to `follow`, starts it again. This holds because the scrolls made
|
|
19
|
+
* here only go down, and a scroll the browser makes when content shrinks
|
|
20
|
+
* still ends at the bottom. A resize of the container or of anything inside
|
|
21
|
+
* it re-pins the bottom, so growth that changes no reactive data (docks,
|
|
22
|
+
* images, wrapping, cards that open) is followed too.
|
|
23
|
+
*/
|
|
24
|
+
export function useFollowScroll(scrollEl: Ref<HTMLElement | null>): {
|
|
25
|
+
/** Jumps to the bottom and follows from there. */
|
|
26
|
+
follow: () => void;
|
|
27
|
+
} {
|
|
28
|
+
let following = true;
|
|
29
|
+
|
|
30
|
+
function follow(): void {
|
|
31
|
+
following = true;
|
|
32
|
+
if (scrollEl.value !== null) scrollToBottom(scrollEl.value);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function attach(el: HTMLElement): () => void {
|
|
36
|
+
let lastTop = el.scrollTop;
|
|
37
|
+
|
|
38
|
+
const onScroll = (): void => {
|
|
39
|
+
const top = el.scrollTop;
|
|
40
|
+
const movedUp = top < lastTop;
|
|
41
|
+
lastTop = top;
|
|
42
|
+
if (distanceFromBottom(el) <= BOTTOM_EPSILON_PX) following = true;
|
|
43
|
+
else if (movedUp) following = false;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const resizes = new ResizeObserver(() => {
|
|
47
|
+
if (following) scrollToBottom(el);
|
|
48
|
+
});
|
|
49
|
+
const observeContent = (): void => {
|
|
50
|
+
resizes.disconnect();
|
|
51
|
+
resizes.observe(el);
|
|
52
|
+
for (const child of el.children) resizes.observe(child);
|
|
53
|
+
};
|
|
54
|
+
const children = new MutationObserver(observeContent);
|
|
55
|
+
observeContent();
|
|
56
|
+
children.observe(el, { childList: true });
|
|
57
|
+
|
|
58
|
+
el.addEventListener("scroll", onScroll, { passive: true });
|
|
59
|
+
|
|
60
|
+
return () => {
|
|
61
|
+
resizes.disconnect();
|
|
62
|
+
children.disconnect();
|
|
63
|
+
el.removeEventListener("scroll", onScroll);
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
watch(
|
|
68
|
+
scrollEl,
|
|
69
|
+
(el, _previous, onCleanup) => {
|
|
70
|
+
if (el === null) return;
|
|
71
|
+
onCleanup(attach(el));
|
|
72
|
+
},
|
|
73
|
+
{ immediate: true, flush: "post" },
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
return { follow };
|
|
77
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ApprovalMode, ProviderName } from "../types/protocol";
|
|
2
|
+
|
|
3
|
+
export const MODES_BY_PROVIDER: Record<ProviderName, readonly ApprovalMode[]> =
|
|
4
|
+
{
|
|
5
|
+
claude: ["normal", "auto", "acceptEdits", "plan"],
|
|
6
|
+
codex: ["normal", "acceptEdits", "plan"],
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
/** The mode as the provider has it: one it lacks reads as Ask first. */
|
|
10
|
+
export function modeFor(
|
|
11
|
+
provider: ProviderName,
|
|
12
|
+
mode: ApprovalMode,
|
|
13
|
+
): ApprovalMode {
|
|
14
|
+
return MODES_BY_PROVIDER[provider].includes(mode) ? mode : "normal";
|
|
15
|
+
}
|
|
@@ -14,7 +14,6 @@ export const CLIENT_MESSAGE_TYPES = {
|
|
|
14
14
|
QUEUE_CLEAR: "queue_clear",
|
|
15
15
|
REVOKE_RULE: "revoke_rule",
|
|
16
16
|
SET_CONVERSATION_MODE: "set_conversation_mode",
|
|
17
|
-
LEAVE_CONVERSATION: "leave_conversation",
|
|
18
17
|
STOP_AUTOFIX: "stop_autofix",
|
|
19
18
|
RETRY_TURN: "retry_turn",
|
|
20
19
|
CHANGE_SET_ACTION: "change_set_action",
|
|
@@ -5,9 +5,8 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
export type ProviderName = "claude" | "codex";
|
|
8
|
-
export type ApprovalMode = "normal" | "acceptEdits" | "plan";
|
|
8
|
+
export type ApprovalMode = "normal" | "auto" | "acceptEdits" | "plan";
|
|
9
9
|
export type Scope = "safe" | "vibe";
|
|
10
|
-
export type FullAutoDuration = "turn" | "30m" | "chat";
|
|
11
10
|
|
|
12
11
|
export type ToolOutcome = "done" | "failed" | "denied" | "blocked" | "stopped";
|
|
13
12
|
|
|
@@ -17,6 +16,8 @@ export type AllowedBy =
|
|
|
17
16
|
| "approved"
|
|
18
17
|
| "rule"
|
|
19
18
|
| "full_auto"
|
|
19
|
+
| "auto_approved"
|
|
20
|
+
| "auto_denied"
|
|
20
21
|
| "blocked"
|
|
21
22
|
| "denied"
|
|
22
23
|
| "expired";
|
|
@@ -165,21 +166,30 @@ export interface FullAutoEndedNotice {
|
|
|
165
166
|
timestampMs: number;
|
|
166
167
|
}
|
|
167
168
|
|
|
169
|
+
export interface ModelFallbackNotice {
|
|
170
|
+
kind: "model_fallback";
|
|
171
|
+
requestedModel: string;
|
|
172
|
+
usedModel: string;
|
|
173
|
+
timestampMs: number;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export interface AutoUnavailableNotice {
|
|
177
|
+
kind: "auto_unavailable";
|
|
178
|
+
model: string;
|
|
179
|
+
timestampMs: number;
|
|
180
|
+
}
|
|
181
|
+
|
|
168
182
|
export type Notice =
|
|
169
183
|
| AutoFixNotice
|
|
170
184
|
| PermissionExpiredNotice
|
|
171
185
|
| QuestionSkippedNotice
|
|
172
|
-
| FullAutoEndedNotice
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
duration: FullAutoDuration;
|
|
176
|
-
untilMs?: number;
|
|
177
|
-
}
|
|
186
|
+
| FullAutoEndedNotice
|
|
187
|
+
| ModelFallbackNotice
|
|
188
|
+
| AutoUnavailableNotice;
|
|
178
189
|
|
|
179
190
|
export interface ConversationModeState {
|
|
180
191
|
mode: ApprovalMode;
|
|
181
192
|
generationMode: Scope;
|
|
182
|
-
fullAuto: FullAutoState | null;
|
|
183
193
|
}
|
|
184
194
|
|
|
185
195
|
export interface QuestionAnswerRecord {
|
|
@@ -3,16 +3,21 @@ import type { ApprovalMode, ProviderName, Scope } from "./protocol";
|
|
|
3
3
|
export type ThinkingLevel = "off" | "low" | "medium" | "high";
|
|
4
4
|
export type { ProviderName };
|
|
5
5
|
|
|
6
|
+
/** The unavailability reasons the panel words itself (sidecar `PROVIDER_UNAVAILABLE_CODES`). */
|
|
7
|
+
export type ProviderUnavailableCode = "codex_not_signed_in";
|
|
8
|
+
|
|
6
9
|
export interface ProviderAvailability {
|
|
7
10
|
available: boolean;
|
|
8
|
-
/** Why the provider cannot be picked; absent when it is available. */
|
|
11
|
+
/** Why the provider cannot be picked, in English; absent when it is available. */
|
|
9
12
|
reason?: string;
|
|
13
|
+
/** Names the reason when the panel has its own wording for it. */
|
|
14
|
+
code?: ProviderUnavailableCode;
|
|
10
15
|
}
|
|
11
16
|
|
|
12
17
|
export interface AppSettings {
|
|
13
18
|
provider: ProviderName;
|
|
14
19
|
/** The default approval mode of new chats. */
|
|
15
|
-
|
|
20
|
+
defaultModes: Record<ProviderName, ApprovalMode>;
|
|
16
21
|
thinking: ThinkingLevel;
|
|
17
22
|
/** The default scope of new chats. */
|
|
18
23
|
generationMode: Scope;
|
|
@@ -90,6 +90,7 @@ const DESTRUCTIVE_TITLE_KEYS: Record<string, string> = {
|
|
|
90
90
|
BuilderRemoveField: "dms_ai.panel.approvals.destructive.remove_field",
|
|
91
91
|
BuilderDeleteCategory: "dms_ai.panel.approvals.destructive.delete_category",
|
|
92
92
|
BuilderRemoveQuery: "dms_ai.panel.approvals.destructive.remove_query",
|
|
93
|
+
BuilderMapResources: "dms_ai.panel.approvals.destructive.map_resources",
|
|
93
94
|
};
|
|
94
95
|
|
|
95
96
|
function destructiveTitle(
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { Translate } from "../composables/useChatI18n";
|
|
2
|
+
import { formatClock } from "./format";
|
|
3
|
+
|
|
4
|
+
export type StatusKind =
|
|
5
|
+
| "ready"
|
|
6
|
+
| "working"
|
|
7
|
+
| "waiting"
|
|
8
|
+
| "connecting"
|
|
9
|
+
| "offline";
|
|
10
|
+
|
|
11
|
+
export interface StatusFacts {
|
|
12
|
+
kind: StatusKind;
|
|
13
|
+
elapsedMs: number;
|
|
14
|
+
pendingCount: number;
|
|
15
|
+
agentName: string;
|
|
16
|
+
/** The model that answered last; null until a reply names it. */
|
|
17
|
+
model: string | null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const PART_SEPARATOR = " · ";
|
|
21
|
+
|
|
22
|
+
function stateLabel(facts: StatusFacts, t: Translate): string {
|
|
23
|
+
const labels: Record<StatusKind, () => string> = {
|
|
24
|
+
ready: () => t("dms_ai.panel.status.ready"),
|
|
25
|
+
working: () =>
|
|
26
|
+
t("dms_ai.panel.status.working", { time: formatClock(facts.elapsedMs) }),
|
|
27
|
+
waiting: () =>
|
|
28
|
+
t(
|
|
29
|
+
"dms_ai.panel.status.waiting",
|
|
30
|
+
{ count: facts.pendingCount },
|
|
31
|
+
facts.pendingCount,
|
|
32
|
+
),
|
|
33
|
+
connecting: () => t("dms_ai.panel.status.connecting"),
|
|
34
|
+
offline: () => t("dms_ai.panel.status.offline"),
|
|
35
|
+
};
|
|
36
|
+
return labels[facts.kind]();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* The panel's status line: the state, then the agent, then the model that
|
|
41
|
+
* answered last ("Ready · Claude Code · claude-opus-5-5"). Offline has no
|
|
42
|
+
* agent to name.
|
|
43
|
+
*/
|
|
44
|
+
export function describeStatus(facts: StatusFacts, t: Translate): string {
|
|
45
|
+
const label = stateLabel(facts, t);
|
|
46
|
+
if (facts.kind === "offline") return label;
|
|
47
|
+
const parts = [label, facts.agentName];
|
|
48
|
+
if (facts.model !== null) parts.push(facts.model);
|
|
49
|
+
return parts.join(PART_SEPARATOR);
|
|
50
|
+
}
|
|
@@ -374,6 +374,16 @@ const BUILDER_TOOLS: Record<string, ToolLexiconEntry> = {
|
|
|
374
374
|
icon: ICONS.BLOCK,
|
|
375
375
|
target: firstOf("path"),
|
|
376
376
|
},
|
|
377
|
+
BuilderComposePage: {
|
|
378
|
+
verb: "compose_page",
|
|
379
|
+
icon: ICONS.BLOCK,
|
|
380
|
+
target: firstOf("pageRef"),
|
|
381
|
+
},
|
|
382
|
+
BuilderConfigureTableView: {
|
|
383
|
+
verb: "configure_table_view",
|
|
384
|
+
icon: ICONS.BLOCK,
|
|
385
|
+
target: firstOf("pageRef"),
|
|
386
|
+
},
|
|
377
387
|
BuilderMoveBlock: {
|
|
378
388
|
verb: "move_block",
|
|
379
389
|
icon: ICONS.BLOCK,
|
|
@@ -475,6 +485,12 @@ const BUILDER_TOOLS: Record<string, ToolLexiconEntry> = {
|
|
|
475
485
|
icon: ICONS.DATA,
|
|
476
486
|
target: firstOf("name"),
|
|
477
487
|
},
|
|
488
|
+
BuilderPreviewQuery: {
|
|
489
|
+
verb: "preview_query",
|
|
490
|
+
icon: ICONS.DATA,
|
|
491
|
+
target: firstOf("name"),
|
|
492
|
+
isReadOnly: true,
|
|
493
|
+
},
|
|
478
494
|
BuilderConfigureQuery: {
|
|
479
495
|
verb: "configure_query",
|
|
480
496
|
icon: ICONS.DATA,
|
|
@@ -268,8 +268,8 @@ function createSession(parts: SessionParts): AssistantSession {
|
|
|
268
268
|
intents.push({ kind: "open", conversationId });
|
|
269
269
|
panel.open();
|
|
270
270
|
},
|
|
271
|
-
startConversation: (prompt, mode) => {
|
|
272
|
-
intents.push({ kind: "start", prompt, mode });
|
|
271
|
+
startConversation: (prompt, mode, send) => {
|
|
272
|
+
intents.push({ kind: "start", prompt, mode, send });
|
|
273
273
|
panel.open();
|
|
274
274
|
},
|
|
275
275
|
holdStream: parts.holds.hold,
|
|
@@ -14,10 +14,12 @@ export interface PublicAssistantActions {
|
|
|
14
14
|
/**
|
|
15
15
|
* Opens the assistant panel on a new conversation with `prompt` in the composer, unsent. With
|
|
16
16
|
* `mode`, the conversation is set to it first: `plan` makes the agent end with a plan to approve.
|
|
17
|
+
* With `send`, the prompt is sent as the first message once the stream is up, and the composer
|
|
18
|
+
* stays empty.
|
|
17
19
|
*/
|
|
18
20
|
startConversation: (
|
|
19
21
|
prompt: string,
|
|
20
|
-
options?: { mode?: ConversationStartMode },
|
|
22
|
+
options?: { mode?: ConversationStartMode; send?: boolean },
|
|
21
23
|
) => void;
|
|
22
24
|
}
|
|
23
25
|
|
|
@@ -36,6 +38,6 @@ export function publicAssistantActions(
|
|
|
36
38
|
return session.value !== null;
|
|
37
39
|
},
|
|
38
40
|
startConversation: (prompt, options) =>
|
|
39
|
-
session.value?.startConversation(prompt, options?.mode),
|
|
41
|
+
session.value?.startConversation(prompt, options?.mode, options?.send),
|
|
40
42
|
};
|
|
41
43
|
}
|
|
@@ -38,7 +38,11 @@ export interface AssistantSession {
|
|
|
38
38
|
* Opens the panel on a new conversation, the composer optionally prefilled, and the
|
|
39
39
|
* conversation set to `mode` first when one is given.
|
|
40
40
|
*/
|
|
41
|
-
startConversation: (
|
|
41
|
+
startConversation: (
|
|
42
|
+
prompt?: string,
|
|
43
|
+
mode?: ConversationStartMode,
|
|
44
|
+
send?: boolean,
|
|
45
|
+
) => void;
|
|
42
46
|
/**
|
|
43
47
|
* Keeps the tab's stream open while the panel is closed, until the returned
|
|
44
48
|
* function releases it: the command palette's answer streams through it.
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the DMS data blocks (charts, KPIs, lists, tables) say about themselves.
|
|
3
|
+
* Each states its kind, its layout path and what its reader sees on its root
|
|
4
|
+
* element; a test harness reads the same attributes. A host that predates
|
|
5
|
+
* them states nothing, and the page reads as having no data block.
|
|
6
|
+
*/
|
|
7
|
+
const BLOCK_SELECTOR = "[data-dms-block-state]";
|
|
8
|
+
const STATE_ATTRIBUTE = "data-dms-block-state";
|
|
9
|
+
const TYPE_ATTRIBUTE = "data-dms-block-type";
|
|
10
|
+
const PATH_ATTRIBUTE = "data-dms-block";
|
|
11
|
+
const UNKNOWN_TYPE = "Block";
|
|
12
|
+
|
|
13
|
+
/** How long the host waits for a page's blocks to stop loading. */
|
|
14
|
+
export const BLOCK_SETTLE_BUDGET_MS = 15_000;
|
|
15
|
+
/** How long the blocks of a page must stay unchanged before it counts as settled. */
|
|
16
|
+
export const BLOCK_QUIET_MS = 700;
|
|
17
|
+
|
|
18
|
+
const BLOCK_STATES = ["loading", "ok", "empty", "error"] as const;
|
|
19
|
+
type BlockState = (typeof BLOCK_STATES)[number];
|
|
20
|
+
type ReportedState = Exclude<BlockState, "ok">;
|
|
21
|
+
|
|
22
|
+
export interface BlockFact {
|
|
23
|
+
path?: string;
|
|
24
|
+
type: string;
|
|
25
|
+
state: BlockState;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface ReportedBlock extends BlockFact {
|
|
29
|
+
state: ReportedState;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface PageBlocks {
|
|
33
|
+
status: "settled" | "timeout" | "superseded";
|
|
34
|
+
checked: number;
|
|
35
|
+
/** The blocks showing no data: empty, failed, or still loading. */
|
|
36
|
+
blocks: ReportedBlock[];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function isBlockState(value: string | null): value is BlockState {
|
|
40
|
+
return BLOCK_STATES.some((state) => state === value);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function isReported(block: BlockFact): block is ReportedBlock {
|
|
44
|
+
return block.state !== "ok";
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function readBlock(element: Element): BlockFact | null {
|
|
48
|
+
const state = element.getAttribute(STATE_ATTRIBUTE);
|
|
49
|
+
if (!isBlockState(state)) return null;
|
|
50
|
+
const path = element.getAttribute(PATH_ATTRIBUTE);
|
|
51
|
+
return {
|
|
52
|
+
...(path === null ? {} : { path }),
|
|
53
|
+
type: element.getAttribute(TYPE_ATTRIBUTE) ?? UNKNOWN_TYPE,
|
|
54
|
+
state,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** The data blocks under `root`, in document order. */
|
|
59
|
+
export function readBlocks(root: ParentNode): BlockFact[] {
|
|
60
|
+
return [...root.querySelectorAll(BLOCK_SELECTOR)].flatMap((element) => {
|
|
61
|
+
const block = readBlock(element);
|
|
62
|
+
return block === null ? [] : [block];
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function holdsBlock(node: Node): boolean {
|
|
67
|
+
return (
|
|
68
|
+
node instanceof Element &&
|
|
69
|
+
(node.matches(BLOCK_SELECTOR) ||
|
|
70
|
+
node.querySelector(BLOCK_SELECTOR) !== null)
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function changesBlocks(record: MutationRecord): boolean {
|
|
75
|
+
if (record.type === "attributes") return true;
|
|
76
|
+
return [...record.addedNodes, ...record.removedNodes].some(holdsBlock);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export interface AwaitSettledBlocksOptions {
|
|
80
|
+
root: Document;
|
|
81
|
+
/** Aborted when another navigation starts: the wait ends as `superseded`. */
|
|
82
|
+
signal: AbortSignal;
|
|
83
|
+
budgetMs?: number;
|
|
84
|
+
quietMs?: number;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Resolves when the blocks of the page have stopped changing for `quietMs`
|
|
89
|
+
* and none is loading, or at `budgetMs` with the blocks still loading named,
|
|
90
|
+
* or at once when `signal` aborts.
|
|
91
|
+
*/
|
|
92
|
+
export function awaitSettledBlocks(
|
|
93
|
+
options: AwaitSettledBlocksOptions,
|
|
94
|
+
): Promise<PageBlocks> {
|
|
95
|
+
const { root, signal } = options;
|
|
96
|
+
const budgetMs = options.budgetMs ?? BLOCK_SETTLE_BUDGET_MS;
|
|
97
|
+
const quietMs = options.quietMs ?? BLOCK_QUIET_MS;
|
|
98
|
+
return new Promise((resolve) => {
|
|
99
|
+
let quietTimer: ReturnType<typeof setTimeout> | undefined;
|
|
100
|
+
const finish = (status: PageBlocks["status"]): void => {
|
|
101
|
+
clearTimeout(quietTimer);
|
|
102
|
+
clearTimeout(budgetTimer);
|
|
103
|
+
observer.disconnect();
|
|
104
|
+
signal.removeEventListener("abort", onAbort);
|
|
105
|
+
const facts = readBlocks(root);
|
|
106
|
+
resolve({
|
|
107
|
+
status,
|
|
108
|
+
checked: facts.length,
|
|
109
|
+
blocks: facts.filter(isReported),
|
|
110
|
+
});
|
|
111
|
+
};
|
|
112
|
+
const onQuiet = (): void => {
|
|
113
|
+
if (readBlocks(root).every((block) => block.state !== "loading"))
|
|
114
|
+
finish("settled");
|
|
115
|
+
};
|
|
116
|
+
const restartQuiet = (): void => {
|
|
117
|
+
clearTimeout(quietTimer);
|
|
118
|
+
quietTimer = setTimeout(onQuiet, quietMs);
|
|
119
|
+
};
|
|
120
|
+
const onAbort = (): void => finish("superseded");
|
|
121
|
+
const observer = new MutationObserver((records) => {
|
|
122
|
+
if (records.some(changesBlocks)) restartQuiet();
|
|
123
|
+
});
|
|
124
|
+
const budgetTimer = setTimeout(() => finish("timeout"), budgetMs);
|
|
125
|
+
if (signal.aborted) return finish("superseded");
|
|
126
|
+
signal.addEventListener("abort", onAbort);
|
|
127
|
+
observer.observe(root, {
|
|
128
|
+
subtree: true,
|
|
129
|
+
childList: true,
|
|
130
|
+
attributes: true,
|
|
131
|
+
attributeFilter: [STATE_ATTRIBUTE],
|
|
132
|
+
});
|
|
133
|
+
restartQuiet();
|
|
134
|
+
});
|
|
135
|
+
}
|
|
@@ -40,6 +40,7 @@ export const HELLO_MESSAGE_TYPE = "hello";
|
|
|
40
40
|
export const LOG_PREFIX = "[dms-ai]";
|
|
41
41
|
export const HOST_STATE_UPDATE_TYPE = "host_state_update";
|
|
42
42
|
export const HOST_NAVIGATION_COMPLETE_TYPE = "host_navigation_complete";
|
|
43
|
+
export const HOST_PAGE_BLOCKS_TYPE = "host_page_blocks";
|
|
43
44
|
export const HOST_COMMAND_NAVIGATE_TYPE = "host_command_navigate";
|
|
44
45
|
/** Frames of the tab's stream meant for the dashboard; every other one is the chat's. */
|
|
45
46
|
export const HOST_COMMAND_TYPES: ReadonlySet<string> = new Set([
|
|
@@ -1,22 +1,63 @@
|
|
|
1
1
|
import { router } from "@inertiajs/vue3";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
awaitSettledBlocks,
|
|
4
|
+
BLOCK_SETTLE_BUDGET_MS,
|
|
5
|
+
type PageBlocks,
|
|
6
|
+
} from "./block-health";
|
|
7
|
+
import {
|
|
8
|
+
HOST_NAVIGATION_COMPLETE_TYPE,
|
|
9
|
+
HOST_PAGE_BLOCKS_TYPE,
|
|
10
|
+
} from "./constants";
|
|
3
11
|
|
|
4
12
|
interface HostNavigationCompleteMessage {
|
|
5
13
|
type: typeof HOST_NAVIGATION_COMPLETE_TYPE;
|
|
6
14
|
path: string;
|
|
15
|
+
/** A `host_page_blocks` message for this path follows within this long. */
|
|
16
|
+
blocksWithinMs: number;
|
|
7
17
|
}
|
|
8
18
|
|
|
19
|
+
interface HostPageBlocksMessage extends PageBlocks {
|
|
20
|
+
type: typeof HOST_PAGE_BLOCKS_TYPE;
|
|
21
|
+
path: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
type NavigationMessage = HostNavigationCompleteMessage | HostPageBlocksMessage;
|
|
25
|
+
|
|
9
26
|
interface InstallNavigationCompleteEmitterOptions {
|
|
10
|
-
send: (msg:
|
|
27
|
+
send: (msg: NavigationMessage) => void;
|
|
11
28
|
}
|
|
12
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Reports each completed visit at once, then what the page's data blocks
|
|
32
|
+
* showed once they settled, so the assistant learns of empty charts without
|
|
33
|
+
* a screenshot.
|
|
34
|
+
*/
|
|
13
35
|
export function installNavigationCompleteEmitter(
|
|
14
36
|
options: InstallNavigationCompleteEmitterOptions,
|
|
15
37
|
): () => void {
|
|
16
|
-
|
|
38
|
+
let settling = new AbortController();
|
|
39
|
+
let stopped = false;
|
|
40
|
+
const stopNavigation = router.on("navigate", (event) => {
|
|
41
|
+
const path = new URL(event.detail.page.url, window.location.origin)
|
|
42
|
+
.pathname;
|
|
43
|
+
settling.abort();
|
|
44
|
+
settling = new AbortController();
|
|
17
45
|
options.send({
|
|
18
46
|
type: HOST_NAVIGATION_COMPLETE_TYPE,
|
|
19
|
-
path
|
|
20
|
-
|
|
21
|
-
|
|
47
|
+
path,
|
|
48
|
+
blocksWithinMs: BLOCK_SETTLE_BUDGET_MS,
|
|
49
|
+
});
|
|
50
|
+
void awaitSettledBlocks({
|
|
51
|
+
root: document,
|
|
52
|
+
signal: settling.signal,
|
|
53
|
+
}).then((blocks) => {
|
|
54
|
+
if (!stopped)
|
|
55
|
+
options.send({ type: HOST_PAGE_BLOCKS_TYPE, path, ...blocks });
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
return () => {
|
|
59
|
+
stopped = true;
|
|
60
|
+
settling.abort();
|
|
61
|
+
stopNavigation();
|
|
62
|
+
};
|
|
22
63
|
}
|
|
@@ -7,11 +7,15 @@ interface OpenConversationIntent {
|
|
|
7
7
|
conversationId: string;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
/**
|
|
11
|
-
|
|
10
|
+
/**
|
|
11
|
+
* Opens the panel on a new conversation, in `mode` when given. The prompt is put in the composer,
|
|
12
|
+
* or sent as the first message when `send` is set.
|
|
13
|
+
*/
|
|
14
|
+
export interface StartConversationIntent {
|
|
12
15
|
kind: "start";
|
|
13
16
|
prompt?: string;
|
|
14
17
|
mode?: ConversationStartMode;
|
|
18
|
+
send?: boolean;
|
|
15
19
|
}
|
|
16
20
|
|
|
17
21
|
/** Puts the caret in the composer of the current conversation. */
|
|
@@ -27,6 +27,8 @@ export const DECISION_STYLES: Record<AllowedBy, DecisionStyle> = {
|
|
|
27
27
|
approved: { icon: "i-ph-check-circle", iconClass: "text-success" },
|
|
28
28
|
rule: { icon: "i-ph-key", iconClass: "text-secondary" },
|
|
29
29
|
full_auto: { icon: "i-ph-lightning", iconClass: "text-secondary" },
|
|
30
|
+
auto_approved: { icon: "i-ph-seal-check", iconClass: "text-success" },
|
|
31
|
+
auto_denied: { icon: "i-ph-prohibit", iconClass: "text-warning" },
|
|
30
32
|
blocked: { icon: "i-ph-shield-warning", iconClass: "text-warning" },
|
|
31
33
|
denied: { icon: "i-ph-prohibit", iconClass: "text-error" },
|
|
32
34
|
expired: { icon: "i-ph-hourglass-simple", iconClass: "text-warning" },
|
|
@@ -2,7 +2,7 @@ import type { Tone } from "#dms-core/app/types/tone";
|
|
|
2
2
|
|
|
3
3
|
type AgentId = "claude" | "codex";
|
|
4
4
|
export type ScopeId = "safe" | "vibe";
|
|
5
|
-
export type ApprovalMode = "normal" | "acceptEdits" | "plan";
|
|
5
|
+
export type ApprovalMode = "normal" | "auto" | "acceptEdits" | "plan";
|
|
6
6
|
type AssistantState = "ready" | "working" | "waiting";
|
|
7
7
|
export type TypecheckOutcome = "passed" | "failed" | "skipped";
|
|
8
8
|
export type ChangeSetState = "applied" | "undone";
|
|
@@ -16,6 +16,8 @@ export type AllowedBy =
|
|
|
16
16
|
| "approved"
|
|
17
17
|
| "rule"
|
|
18
18
|
| "full_auto"
|
|
19
|
+
| "auto_approved"
|
|
20
|
+
| "auto_denied"
|
|
19
21
|
| "blocked"
|
|
20
22
|
| "denied"
|
|
21
23
|
| "expired";
|