@antelopejs/dms-ai 0.9.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 +15 -4
- package/dist/pages/settings/sections.js.map +1 -1
- package/dist/routes/builder.d.ts +3 -3
- package/dist/routes/builder.js +7 -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/frontend-vue/app/chat/components/ChatView.vue +16 -49
- package/frontend-vue/app/chat/components/Composer.vue +23 -39
- package/frontend-vue/app/chat/components/NoticeCard.vue +9 -0
- package/frontend-vue/app/chat/components/ProviderNotice.vue +14 -3
- package/frontend-vue/app/chat/composables/conversation-events.ts +0 -3
- 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 +11 -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/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 +21 -11
- package/frontend-vue/i18n/locales/dms-ai-pages-fr-FR.json +21 -11
- package/frontend-vue/i18n/locales/dms-ai-panel-en-GB.json +11 -21
- package/frontend-vue/i18n/locales/dms-ai-panel-fr-FR.json +11 -21
- 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/chat/chat-scroll.test.ts +251 -0
- package/frontend-vue/tests/chat/conversation-events.test.ts +1 -3
- package/frontend-vue/tests/chat/provider-notice.test.ts +33 -0
- package/frontend-vue/tests/chat-panel.test.ts +2 -4
- 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 +14 -6
- 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 +4 -3
- 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 +5 -4
- package/sidecar/dist/agent/runner.d.ts +3 -2
- package/sidecar/dist/agent/runner.js +9 -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 +13 -1
- 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 +3 -0
- package/sidecar/dist/constants/builder.js +3 -0
- package/sidecar/dist/constants/builder.js.map +1 -1
- package/sidecar/dist/constants/claude.d.ts +6 -0
- package/sidecar/dist/constants/claude.js +6 -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/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 +1 -2
- package/sidecar/dist/constants/settings.js +2 -9
- package/sidecar/dist/constants/settings.js.map +1 -1
- package/sidecar/dist/constants/tool-kinds.d.ts +67 -2
- package/sidecar/dist/constants/tool-kinds.js +111 -34
- package/sidecar/dist/constants/tool-kinds.js.map +1 -1
- 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 +65 -3
- package/sidecar/dist/mcp/tools/builder-project.js.map +1 -1
- package/sidecar/dist/protocol/events.d.ts +97 -63
- package/sidecar/dist/protocol/events.js +14 -8
- package/sidecar/dist/protocol/events.js.map +1 -1
- package/sidecar/dist/protocol/messages.d.ts +54 -49
- package/sidecar/dist/protocol/messages.js +8 -13
- package/sidecar/dist/protocol/messages.js.map +1 -1
- package/sidecar/dist/providers/claude/config.d.ts +3 -3
- package/sidecar/dist/providers/claude/config.js +4 -2
- package/sidecar/dist/providers/claude/config.js.map +1 -1
- package/sidecar/dist/providers/claude/provider.js +20 -26
- package/sidecar/dist/providers/claude/provider.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 +4 -9
- package/sidecar/dist/providers/claude/session-stream.js +22 -0
- package/sidecar/dist/providers/claude/session-stream.js.map +1 -1
- 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/http-routes.js +1 -1
- package/sidecar/dist/server/http-routes.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 +0 -5
- 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 +9 -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/settings-store.d.ts +13 -5
- package/sidecar/dist/state/settings-store.js +33 -8
- package/sidecar/dist/state/settings-store.js.map +1 -1
- package/sidecar/dist/state/settings-types.d.ts +15 -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 +7 -6
- package/sidecar/dist/state/types.js.map +1 -1
- package/sidecar/package.json +1 -1
- package/skills/dms-ai/SKILL.md +2 -1
- package/skills/dms-external-database/SKILL.md +5 -2
- package/frontend-vue/app/chat/components/FullAutoBanner.vue +0 -76
- package/frontend-vue/app/chat/components/FullAutoDialog.vue +0 -103
|
@@ -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";
|
|
@@ -263,13 +263,15 @@
|
|
|
263
263
|
"approved": "Approved by you",
|
|
264
264
|
"rule": "Allowed by a rule",
|
|
265
265
|
"full_auto": "Full auto",
|
|
266
|
+
"auto_approved": "Allowed by Auto review",
|
|
267
|
+
"auto_denied": "Blocked by Auto review",
|
|
266
268
|
"blocked": "Blocked · safe mode",
|
|
267
269
|
"denied": "Denied by you",
|
|
268
270
|
"expired": "Expired"
|
|
269
271
|
},
|
|
270
272
|
"allowed_metric": {
|
|
271
273
|
"deletions_asked": "Deletions asked",
|
|
272
|
-
"deletions_note": "Deletions always ask,
|
|
274
|
+
"deletions_note": "Deletions always ask, in every mode"
|
|
273
275
|
},
|
|
274
276
|
"result": {
|
|
275
277
|
"done": "Done",
|
|
@@ -421,6 +423,7 @@
|
|
|
421
423
|
"label": "Coding agent",
|
|
422
424
|
"description": "Runs on this machine, in the project folder. Your code only goes to the provider you pick; a failing agent never falls back to the other.",
|
|
423
425
|
"unavailable": "Not set up on this machine",
|
|
426
|
+
"codex_not_signed_in": "Sign in with ChatGPT below to run Codex on your ChatGPT plan.",
|
|
424
427
|
"claude": {
|
|
425
428
|
"label": "Claude Code",
|
|
426
429
|
"description": "Anthropic · model chosen by Claude Code"
|
|
@@ -469,29 +472,36 @@
|
|
|
469
472
|
"label": "Claude model",
|
|
470
473
|
"description": "The model Claude Code runs on. Thinking sets its reasoning effort."
|
|
471
474
|
},
|
|
475
|
+
"default_mode_claude": {
|
|
476
|
+
"label": "Default mode on Claude Code",
|
|
477
|
+
"description": "What Claude Code may do without asking you first. Auto review is the recommended default."
|
|
478
|
+
},
|
|
479
|
+
"default_mode_codex": {
|
|
480
|
+
"label": "Default mode on Codex",
|
|
481
|
+
"description": "What Codex may do without asking you first. Codex has no Auto review."
|
|
482
|
+
},
|
|
472
483
|
"mode": {
|
|
473
|
-
"label": "Approval mode",
|
|
474
|
-
"description": "What the assistant may do without asking you first.",
|
|
475
484
|
"normal": {
|
|
476
485
|
"label": "Ask first",
|
|
477
|
-
"description": "Asks before any change outside the Builder."
|
|
486
|
+
"description": "Asks before any change outside the Builder and before every command, read-only ones included."
|
|
487
|
+
},
|
|
488
|
+
"auto": {
|
|
489
|
+
"label": "Auto review",
|
|
490
|
+
"description": "A safety check approves routine file edits and web access. Shell commands, dependency files, git hooks and deletions still ask. Asks first on models or plans without it."
|
|
478
491
|
},
|
|
479
492
|
"acceptEdits": {
|
|
480
493
|
"label": "Accept edits",
|
|
481
|
-
"description": "Applies file edits,
|
|
494
|
+
"description": "Applies file edits, except dependency and git hook files. Asks for the rest, every command included.",
|
|
495
|
+
"description_codex": "With Codex, works as Ask first: asks before every file edit, dependency and git hook files included, and before any command that writes."
|
|
482
496
|
},
|
|
483
497
|
"plan": {
|
|
484
498
|
"label": "Plan only",
|
|
485
499
|
"description": "Reads and proposes. Changes nothing."
|
|
486
|
-
},
|
|
487
|
-
"auto": {
|
|
488
|
-
"label": "Full auto",
|
|
489
|
-
"description": "Not available as a default. Turn it on per chat, for a limited time."
|
|
490
500
|
}
|
|
491
501
|
},
|
|
492
502
|
"always_ask": {
|
|
493
503
|
"label": "Always ask for",
|
|
494
|
-
"description": "These ask in every mode
|
|
504
|
+
"description": "These ask in every mode."
|
|
495
505
|
},
|
|
496
506
|
"always_ask_deletions": {
|
|
497
507
|
"label": "Deleting pages, tables, fields or queries",
|
|
@@ -617,7 +627,7 @@
|
|
|
617
627
|
"normal": "Ask first",
|
|
618
628
|
"acceptEdits": "Accept edits",
|
|
619
629
|
"plan": "Plan only",
|
|
620
|
-
"auto": "
|
|
630
|
+
"auto": "Auto review"
|
|
621
631
|
},
|
|
622
632
|
"facts": {
|
|
623
633
|
"state": "Status",
|
|
@@ -263,13 +263,15 @@
|
|
|
263
263
|
"approved": "Autorisée par vous",
|
|
264
264
|
"rule": "Autorisée par une règle",
|
|
265
265
|
"full_auto": "Automatique complet",
|
|
266
|
+
"auto_approved": "Autorisé par la revue automatique",
|
|
267
|
+
"auto_denied": "Bloqué par la revue automatique",
|
|
266
268
|
"blocked": "Bloquée · mode sûr",
|
|
267
269
|
"denied": "Refusée par vous",
|
|
268
270
|
"expired": "Expirée"
|
|
269
271
|
},
|
|
270
272
|
"allowed_metric": {
|
|
271
273
|
"deletions_asked": "Suppressions demandées",
|
|
272
|
-
"deletions_note": "Les suppressions demandent toujours,
|
|
274
|
+
"deletions_note": "Les suppressions demandent toujours, dans tous les modes"
|
|
273
275
|
},
|
|
274
276
|
"result": {
|
|
275
277
|
"done": "Terminée",
|
|
@@ -421,6 +423,7 @@
|
|
|
421
423
|
"label": "Agent de code",
|
|
422
424
|
"description": "Tourne sur cette machine, dans le dossier du projet. Votre code ne part que chez le fournisseur choisi ; un agent en panne ne bascule jamais sur l'autre.",
|
|
423
425
|
"unavailable": "Non configuré sur cette machine",
|
|
426
|
+
"codex_not_signed_in": "Connectez-vous avec ChatGPT ci-dessous pour utiliser Codex avec votre forfait ChatGPT.",
|
|
424
427
|
"claude": {
|
|
425
428
|
"label": "Claude Code",
|
|
426
429
|
"description": "Anthropic · modèle choisi par Claude Code"
|
|
@@ -469,29 +472,36 @@
|
|
|
469
472
|
"label": "Modèle Claude",
|
|
470
473
|
"description": "Le modèle sur lequel tourne Claude Code. La réflexion règle son niveau d'effort."
|
|
471
474
|
},
|
|
475
|
+
"default_mode_claude": {
|
|
476
|
+
"label": "Mode par défaut avec Claude Code",
|
|
477
|
+
"description": "Ce que Claude Code peut faire sans vous demander d'abord. La revue automatique est le choix recommandé."
|
|
478
|
+
},
|
|
479
|
+
"default_mode_codex": {
|
|
480
|
+
"label": "Mode par défaut avec Codex",
|
|
481
|
+
"description": "Ce que Codex peut faire sans vous demander d'abord. Codex n'a pas de revue automatique."
|
|
482
|
+
},
|
|
472
483
|
"mode": {
|
|
473
|
-
"label": "Mode de validation",
|
|
474
|
-
"description": "Ce que l'assistant peut faire sans vous demander d'abord.",
|
|
475
484
|
"normal": {
|
|
476
485
|
"label": "Demander d'abord",
|
|
477
|
-
"description": "Demande avant toute modification en dehors du Builder."
|
|
486
|
+
"description": "Demande avant toute modification en dehors du Builder et avant chaque commande, même en lecture seule."
|
|
487
|
+
},
|
|
488
|
+
"auto": {
|
|
489
|
+
"label": "Revue automatique",
|
|
490
|
+
"description": "Un contrôle de sécurité approuve les modifications de fichiers courantes et l'accès au web. Les commandes shell, les fichiers de dépendances, les hooks git et les suppressions demandent encore votre accord. Sur un modèle ou une offre qui ne la permet pas, l'assistant demande avant d'agir."
|
|
478
491
|
},
|
|
479
492
|
"acceptEdits": {
|
|
480
493
|
"label": "Accepter les modifications",
|
|
481
|
-
"description": "Applique les modifications de fichiers,
|
|
494
|
+
"description": "Applique les modifications de fichiers, sauf les fichiers de dépendances et les hooks git. Demande pour le reste, chaque commande comprise.",
|
|
495
|
+
"description_codex": "Avec Codex, fonctionne comme Demander d'abord : demande avant chaque modification de fichier, fichiers de dépendances et hooks git compris, et avant toute commande qui écrit."
|
|
482
496
|
},
|
|
483
497
|
"plan": {
|
|
484
498
|
"label": "Plan seulement",
|
|
485
499
|
"description": "Lit et propose. Ne modifie rien."
|
|
486
|
-
},
|
|
487
|
-
"auto": {
|
|
488
|
-
"label": "Automatique complet",
|
|
489
|
-
"description": "Indisponible par défaut. Activez-le par conversation, pour une durée limitée."
|
|
490
500
|
}
|
|
491
501
|
},
|
|
492
502
|
"always_ask": {
|
|
493
503
|
"label": "Toujours demander pour",
|
|
494
|
-
"description": "Ces opérations demandent dans tous les modes
|
|
504
|
+
"description": "Ces opérations demandent dans tous les modes."
|
|
495
505
|
},
|
|
496
506
|
"always_ask_deletions": {
|
|
497
507
|
"label": "Supprimer des pages, tables, champs ou requêtes",
|
|
@@ -617,7 +627,7 @@
|
|
|
617
627
|
"normal": "Demander d'abord",
|
|
618
628
|
"acceptEdits": "Accepter les modifications",
|
|
619
629
|
"plan": "Plan seulement",
|
|
620
|
-
"auto": "
|
|
630
|
+
"auto": "Revue automatique"
|
|
621
631
|
},
|
|
622
632
|
"facts": {
|
|
623
633
|
"state": "État",
|
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
},
|
|
8
8
|
"mode": {
|
|
9
9
|
"normal": "Ask first",
|
|
10
|
+
"auto": "Auto review",
|
|
10
11
|
"acceptEdits": "Accept edits",
|
|
11
|
-
"plan": "Plan only"
|
|
12
|
-
"auto": "Full auto"
|
|
12
|
+
"plan": "Plan only"
|
|
13
13
|
},
|
|
14
14
|
"scope": {
|
|
15
15
|
"safe": "Safe mode",
|
|
@@ -143,6 +143,8 @@
|
|
|
143
143
|
"expired_text": "“{summary}” was not answered in time, so it was denied at {time} and the assistant was told why.",
|
|
144
144
|
"question_skipped": "You let the assistant decide “{header}”.",
|
|
145
145
|
"full_auto_ended": "Full auto ended at {time}. The assistant asks first again.",
|
|
146
|
+
"auto_unavailable_title": "Auto review isn't available here.",
|
|
147
|
+
"auto_unavailable_text": "{model}, this plan or a setting doesn't allow it. This chat asks first instead.",
|
|
146
148
|
"model_fallback_title": "Switched to {model}.",
|
|
147
149
|
"model_fallback_text": "The requested model, {requested}, was refused (unknown, or no access on this plan). This answer comes from {model}, the default model."
|
|
148
150
|
},
|
|
@@ -156,6 +158,7 @@
|
|
|
156
158
|
"stop_not_delivered": "The assistant could not be reached to stop the run. Reconnect to see where it stands.",
|
|
157
159
|
"agent_cant_run": "{agent} can't run.",
|
|
158
160
|
"agent_no_fallback": "Your messages are not sent to any other agent.",
|
|
161
|
+
"codex_not_signed_in": "Sign in with ChatGPT in Assistant › Settings to run Codex on your ChatGPT plan.",
|
|
159
162
|
"open_settings": "Open settings"
|
|
160
163
|
},
|
|
161
164
|
"plan": {
|
|
@@ -234,7 +237,8 @@
|
|
|
234
237
|
"delete_table": "Delete the table {target}",
|
|
235
238
|
"remove_field": "Remove the field {target}",
|
|
236
239
|
"delete_category": "Delete the category {target}",
|
|
237
|
-
"remove_query": "Remove the query {target}"
|
|
240
|
+
"remove_query": "Remove the query {target}",
|
|
241
|
+
"map_resources": "Map the tables and remove the pages {target}"
|
|
238
242
|
},
|
|
239
243
|
"consequence_deletes_data": "Removes the code and its data",
|
|
240
244
|
"consequence_removes_code": "Removes the code · undoable"
|
|
@@ -290,12 +294,12 @@
|
|
|
290
294
|
},
|
|
291
295
|
"mode_menu": "Approval mode · this chat",
|
|
292
296
|
"mode_desc": {
|
|
293
|
-
"normal": "Asks before any edit,
|
|
294
|
-
"acceptEdits": "Applies file edits,
|
|
297
|
+
"normal": "Asks before any edit, web request or command, read-only commands included.",
|
|
298
|
+
"acceptEdits": "Applies file edits, except dependency and git hook files. Asks before every command and web request.",
|
|
299
|
+
"acceptEdits_codex": "With Codex, works as Ask first: asks before every file edit, dependency and git hook files included, and before any command that writes.",
|
|
295
300
|
"plan": "Reads and proposes a plan. Changes nothing.",
|
|
296
|
-
"auto": "
|
|
301
|
+
"auto": "A safety check approves routine file edits and web access. Shell commands, dependency files, git hooks and deletions still ask."
|
|
297
302
|
},
|
|
298
|
-
"full_auto_item": "Full auto…",
|
|
299
303
|
"default_mode": "Default for new chats",
|
|
300
304
|
"hint_send": "send",
|
|
301
305
|
"hint_queue": "queue",
|
|
@@ -306,20 +310,6 @@
|
|
|
306
310
|
"usage_new": "new chat",
|
|
307
311
|
"usage_offline": "offline"
|
|
308
312
|
},
|
|
309
|
-
"full_auto": {
|
|
310
|
-
"title": "Turn on Full auto?",
|
|
311
|
-
"description": "The assistant will edit files and run commands in this chat without asking. Deletions and dependency changes still ask. Every change stays in the change set and can be undone.",
|
|
312
|
-
"turn_off_after": "Turn off after",
|
|
313
|
-
"duration_turn": "This turn",
|
|
314
|
-
"duration_30m": "30 minutes",
|
|
315
|
-
"duration_chat": "Closing the chat",
|
|
316
|
-
"confirm": "Turn on Full auto",
|
|
317
|
-
"banner_turn": "this turn only",
|
|
318
|
-
"banner_30m": "for 30 minutes",
|
|
319
|
-
"banner_chat": "until the chat closes",
|
|
320
|
-
"banner_until": "ends in {time}",
|
|
321
|
-
"turn_off": "Turn off"
|
|
322
|
-
},
|
|
323
313
|
"drawer": {
|
|
324
314
|
"title": "Conversations",
|
|
325
315
|
"new": "New",
|
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
},
|
|
8
8
|
"mode": {
|
|
9
9
|
"normal": "Demander d'abord",
|
|
10
|
+
"auto": "Revue automatique",
|
|
10
11
|
"acceptEdits": "Accepter les modifications",
|
|
11
|
-
"plan": "Plan seulement"
|
|
12
|
-
"auto": "Automatique complet"
|
|
12
|
+
"plan": "Plan seulement"
|
|
13
13
|
},
|
|
14
14
|
"scope": {
|
|
15
15
|
"safe": "Mode sûr",
|
|
@@ -143,6 +143,8 @@
|
|
|
143
143
|
"expired_text": "« {summary} » est restée sans réponse : elle a été refusée à {time} et l'assistant en a été informé.",
|
|
144
144
|
"question_skipped": "Vous avez laissé l'assistant décider pour « {header} ».",
|
|
145
145
|
"full_auto_ended": "Le mode automatique complet a pris fin à {time}. L'assistant redemande avant d'agir.",
|
|
146
|
+
"auto_unavailable_title": "La revue automatique n'est pas disponible ici.",
|
|
147
|
+
"auto_unavailable_text": "{model}, votre offre ou un réglage ne la permet pas. Dans cette conversation, l'assistant demande avant d'agir.",
|
|
146
148
|
"model_fallback_title": "Passage à {model}.",
|
|
147
149
|
"model_fallback_text": "Le modèle demandé, {requested}, a été refusé (inconnu, ou sans accès avec cet abonnement). Cette réponse vient de {model}, le modèle par défaut."
|
|
148
150
|
},
|
|
@@ -156,6 +158,7 @@
|
|
|
156
158
|
"stop_not_delivered": "L'assistant n'a pas pu être joint pour arrêter le tour. Reconnectez-vous pour voir où il en est.",
|
|
157
159
|
"agent_cant_run": "{agent} ne peut pas démarrer.",
|
|
158
160
|
"agent_no_fallback": "Vos messages ne sont envoyés à aucun autre agent.",
|
|
161
|
+
"codex_not_signed_in": "Connectez-vous avec ChatGPT dans Assistant › Réglages pour utiliser Codex avec votre forfait ChatGPT.",
|
|
159
162
|
"open_settings": "Ouvrir les paramètres"
|
|
160
163
|
},
|
|
161
164
|
"plan": {
|
|
@@ -234,7 +237,8 @@
|
|
|
234
237
|
"delete_table": "Supprimer la table {target}",
|
|
235
238
|
"remove_field": "Retirer le champ {target}",
|
|
236
239
|
"delete_category": "Supprimer la catégorie {target}",
|
|
237
|
-
"remove_query": "Retirer la requête {target}"
|
|
240
|
+
"remove_query": "Retirer la requête {target}",
|
|
241
|
+
"map_resources": "Mapper les tables et retirer les pages {target}"
|
|
238
242
|
},
|
|
239
243
|
"consequence_deletes_data": "Retire le code et ses données",
|
|
240
244
|
"consequence_removes_code": "Retire le code · annulable"
|
|
@@ -290,12 +294,12 @@
|
|
|
290
294
|
},
|
|
291
295
|
"mode_menu": "Mode d'approbation · cette conversation",
|
|
292
296
|
"mode_desc": {
|
|
293
|
-
"normal": "Demande avant toute modification,
|
|
294
|
-
"acceptEdits": "Applique les modifications de fichiers,
|
|
297
|
+
"normal": "Demande avant toute modification, requête web ou commande, même en lecture seule.",
|
|
298
|
+
"acceptEdits": "Applique les modifications de fichiers, sauf les fichiers de dépendances et les hooks git. Demande avant chaque commande et requête web.",
|
|
299
|
+
"acceptEdits_codex": "Avec Codex, fonctionne comme Demander d'abord : demande avant chaque modification de fichier, fichiers de dépendances et hooks git compris, et avant toute commande qui écrit.",
|
|
295
300
|
"plan": "Lit et propose un plan. Ne modifie rien.",
|
|
296
|
-
"auto": "
|
|
301
|
+
"auto": "Un contrôle de sécurité approuve les modifications de fichiers courantes et l'accès au web. Les commandes shell, les fichiers de dépendances, les hooks git et les suppressions demandent encore votre accord."
|
|
297
302
|
},
|
|
298
|
-
"full_auto_item": "Automatique complet…",
|
|
299
303
|
"default_mode": "Par défaut pour les nouvelles conversations",
|
|
300
304
|
"hint_send": "envoyer",
|
|
301
305
|
"hint_queue": "mettre en file",
|
|
@@ -306,20 +310,6 @@
|
|
|
306
310
|
"usage_new": "nouvelle conversation",
|
|
307
311
|
"usage_offline": "hors ligne"
|
|
308
312
|
},
|
|
309
|
-
"full_auto": {
|
|
310
|
-
"title": "Activer le mode automatique complet ?",
|
|
311
|
-
"description": "L'assistant modifiera des fichiers et exécutera des commandes dans cette conversation sans demander. Les suppressions et les changements de dépendances demandent toujours. Chaque modification reste dans le lot de modifications et peut être annulée.",
|
|
312
|
-
"turn_off_after": "Désactiver après",
|
|
313
|
-
"duration_turn": "Ce tour",
|
|
314
|
-
"duration_30m": "30 minutes",
|
|
315
|
-
"duration_chat": "Fermeture de la conversation",
|
|
316
|
-
"confirm": "Activer le mode automatique complet",
|
|
317
|
-
"banner_turn": "ce tour seulement",
|
|
318
|
-
"banner_30m": "pendant 30 minutes",
|
|
319
|
-
"banner_chat": "jusqu'à la fermeture de la conversation",
|
|
320
|
-
"banner_until": "se termine dans {time}",
|
|
321
|
-
"turn_off": "Désactiver"
|
|
322
|
-
},
|
|
323
313
|
"drawer": {
|
|
324
314
|
"title": "Conversations",
|
|
325
315
|
"new": "Nouvelle",
|
|
@@ -49,6 +49,8 @@
|
|
|
49
49
|
"approved": "Approved by you",
|
|
50
50
|
"rule": "Allowed by a rule",
|
|
51
51
|
"full_auto": "Full auto",
|
|
52
|
+
"auto_approved": "Allowed by Auto review",
|
|
53
|
+
"auto_denied": "Blocked by Auto review",
|
|
52
54
|
"blocked": "Blocked · safe mode",
|
|
53
55
|
"denied": "Denied by you",
|
|
54
56
|
"expired": "Expired, not answered"
|
|
@@ -49,6 +49,8 @@
|
|
|
49
49
|
"approved": "Autorisé par vous",
|
|
50
50
|
"rule": "Autorisé par une règle",
|
|
51
51
|
"full_auto": "Automatique complet",
|
|
52
|
+
"auto_approved": "Autorisé par la revue automatique",
|
|
53
|
+
"auto_denied": "Bloqué par la revue automatique",
|
|
52
54
|
"blocked": "Bloqué · mode sûr",
|
|
53
55
|
"denied": "Refusé par vous",
|
|
54
56
|
"expired": "Expiré, sans réponse"
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
import { flushPromises, type VueWrapper } from "@vue/test-utils";
|
|
3
|
+
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
4
|
+
import { nextTick } from "vue";
|
|
5
|
+
import {
|
|
6
|
+
CONVERSATION_ID,
|
|
7
|
+
createHarness,
|
|
8
|
+
deliver,
|
|
9
|
+
type Harness,
|
|
10
|
+
openPanel,
|
|
11
|
+
sendMessage,
|
|
12
|
+
unmountPanel,
|
|
13
|
+
} from "../support/panel-harness";
|
|
14
|
+
import {
|
|
15
|
+
type FakeScroller,
|
|
16
|
+
fakeScroller,
|
|
17
|
+
settleLayout,
|
|
18
|
+
} from "../support/fake-layout";
|
|
19
|
+
|
|
20
|
+
const BOTTOM_TOLERANCE_PX = 4;
|
|
21
|
+
|
|
22
|
+
interface OpenChat {
|
|
23
|
+
harness: Harness;
|
|
24
|
+
panel: VueWrapper;
|
|
25
|
+
scroller: FakeScroller;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function transcript(rows: number) {
|
|
29
|
+
return Array.from({ length: rows }, (_, index) => ({
|
|
30
|
+
role: index % 2 === 0 ? "user" : "assistant",
|
|
31
|
+
content: `message ${index}`,
|
|
32
|
+
timestampMs: 1_700_000_000_000 + index,
|
|
33
|
+
}));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** One browser frame: Vue renders, then layout is reported. */
|
|
37
|
+
async function frame(): Promise<void> {
|
|
38
|
+
await nextTick();
|
|
39
|
+
await flushPromises();
|
|
40
|
+
settleLayout();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function openChat(rows = 30): Promise<OpenChat> {
|
|
44
|
+
const harness = createHarness();
|
|
45
|
+
const panel = await openPanel(harness);
|
|
46
|
+
const scroller = fakeScroller(
|
|
47
|
+
panel.find<HTMLElement>(".chat-view-body").element,
|
|
48
|
+
);
|
|
49
|
+
deliver(harness, {
|
|
50
|
+
type: "conversation_snapshot",
|
|
51
|
+
messages: transcript(rows),
|
|
52
|
+
});
|
|
53
|
+
await frame();
|
|
54
|
+
return { harness, panel, scroller };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function growTranscript(chat: OpenChat, rows: number): Promise<void> {
|
|
58
|
+
deliver(chat.harness, {
|
|
59
|
+
type: "conversation_snapshot",
|
|
60
|
+
messages: transcript(rows),
|
|
61
|
+
});
|
|
62
|
+
await frame();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
beforeEach(() => {
|
|
66
|
+
localStorage.setItem("dms-ai-conversation-id", CONVERSATION_ID);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
afterEach(() => {
|
|
70
|
+
unmountPanel();
|
|
71
|
+
localStorage.clear();
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
describe("the chat follows the conversation", () => {
|
|
75
|
+
it("shows the end of a chat opened from its snapshot", async () => {
|
|
76
|
+
const { scroller } = await openChat(60);
|
|
77
|
+
expect(scroller.distanceFromBottom()).toBeLessThanOrEqual(
|
|
78
|
+
BOTTOM_TOLERANCE_PX,
|
|
79
|
+
);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it("stays at the bottom when the view loses height without any message arriving", async () => {
|
|
83
|
+
const { scroller } = await openChat();
|
|
84
|
+
scroller.viewportPx -= 250;
|
|
85
|
+
await frame();
|
|
86
|
+
expect(scroller.distanceFromBottom()).toBeLessThanOrEqual(
|
|
87
|
+
BOTTOM_TOLERANCE_PX,
|
|
88
|
+
);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("stays at the bottom when content grows without any message arriving", async () => {
|
|
92
|
+
const { scroller } = await openChat();
|
|
93
|
+
scroller.extraContentPx += 600;
|
|
94
|
+
await frame();
|
|
95
|
+
expect(scroller.distanceFromBottom()).toBeLessThanOrEqual(
|
|
96
|
+
BOTTOM_TOLERANCE_PX,
|
|
97
|
+
);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it("stays at the bottom through one message taller than the old 80px margin", async () => {
|
|
101
|
+
const { scroller, harness } = await openChat();
|
|
102
|
+
deliver(harness, { type: "assistant_message_chunk", text: "answer" });
|
|
103
|
+
scroller.extraContentPx += 900;
|
|
104
|
+
await frame();
|
|
105
|
+
expect(scroller.distanceFromBottom()).toBeLessThanOrEqual(
|
|
106
|
+
BOTTOM_TOLERANCE_PX,
|
|
107
|
+
);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it("does not pull the person back down once they scroll up", async () => {
|
|
111
|
+
const chat = await openChat();
|
|
112
|
+
chat.scroller.scrollTo(500);
|
|
113
|
+
await growTranscript(chat, 40);
|
|
114
|
+
chat.scroller.extraContentPx += 300;
|
|
115
|
+
await frame();
|
|
116
|
+
expect(
|
|
117
|
+
chat.panel.find<HTMLElement>(".chat-view-body").element.scrollTop,
|
|
118
|
+
).toBe(500);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it("jumps to the bottom when a message is sent from far up", async () => {
|
|
122
|
+
const chat = await openChat();
|
|
123
|
+
chat.scroller.scrollTo(200);
|
|
124
|
+
await sendMessage(chat.panel, "and now this");
|
|
125
|
+
await frame();
|
|
126
|
+
expect(chat.scroller.distanceFromBottom()).toBeLessThanOrEqual(
|
|
127
|
+
BOTTOM_TOLERANCE_PX,
|
|
128
|
+
);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it("follows again once the person scrolls back to the bottom", async () => {
|
|
132
|
+
const chat = await openChat();
|
|
133
|
+
chat.scroller.scrollTo(500);
|
|
134
|
+
const bottom = chat.scroller.viewportPx;
|
|
135
|
+
chat.scroller.scrollTo(
|
|
136
|
+
chat.panel.find<HTMLElement>(".chat-view-body").element.scrollHeight -
|
|
137
|
+
bottom,
|
|
138
|
+
);
|
|
139
|
+
await growTranscript(chat, 40);
|
|
140
|
+
expect(chat.scroller.distanceFromBottom()).toBeLessThanOrEqual(
|
|
141
|
+
BOTTOM_TOLERANCE_PX,
|
|
142
|
+
);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it("stops following on an upward scroll that carries no input", async () => {
|
|
146
|
+
const chat = await openChat();
|
|
147
|
+
chat.scroller.scrollTo(500);
|
|
148
|
+
await growTranscript(chat, 40);
|
|
149
|
+
chat.scroller.extraContentPx += 300;
|
|
150
|
+
await frame();
|
|
151
|
+
expect(
|
|
152
|
+
chat.panel.find<HTMLElement>(".chat-view-body").element.scrollTop,
|
|
153
|
+
).toBe(500);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it("keeps following when content above the view collapses and scroll anchoring moves the view up", async () => {
|
|
157
|
+
const chat = await openChat();
|
|
158
|
+
chat.scroller.extraContentPx += 800;
|
|
159
|
+
await frame();
|
|
160
|
+
chat.scroller.collapseAbove(600);
|
|
161
|
+
await frame();
|
|
162
|
+
await frame();
|
|
163
|
+
expect(chat.scroller.distanceFromBottom()).toBeLessThanOrEqual(
|
|
164
|
+
BOTTOM_TOLERANCE_PX,
|
|
165
|
+
);
|
|
166
|
+
chat.scroller.extraContentPx += 400;
|
|
167
|
+
await frame();
|
|
168
|
+
expect(chat.scroller.distanceFromBottom()).toBeLessThanOrEqual(
|
|
169
|
+
BOTTOM_TOLERANCE_PX,
|
|
170
|
+
);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
it("keeps following when a collapse above the view comes with growth below it", async () => {
|
|
174
|
+
const chat = await openChat();
|
|
175
|
+
chat.scroller.extraContentPx += 800;
|
|
176
|
+
await frame();
|
|
177
|
+
chat.scroller.collapseAbove(600);
|
|
178
|
+
chat.scroller.extraContentPx += 700;
|
|
179
|
+
await frame();
|
|
180
|
+
await frame();
|
|
181
|
+
expect(chat.scroller.distanceFromBottom()).toBeLessThanOrEqual(
|
|
182
|
+
BOTTOM_TOLERANCE_PX,
|
|
183
|
+
);
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it("keeps following when the view gains height and the browser clamps the scroll", async () => {
|
|
187
|
+
const chat = await openChat();
|
|
188
|
+
chat.scroller.viewportPx += 250;
|
|
189
|
+
await frame();
|
|
190
|
+
await frame();
|
|
191
|
+
chat.scroller.extraContentPx += 500;
|
|
192
|
+
await frame();
|
|
193
|
+
expect(chat.scroller.distanceFromBottom()).toBeLessThanOrEqual(
|
|
194
|
+
BOTTOM_TOLERANCE_PX,
|
|
195
|
+
);
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
it("keeps following after the content shrinks under the view", async () => {
|
|
199
|
+
const chat = await openChat(60);
|
|
200
|
+
await growTranscript(chat, 20);
|
|
201
|
+
await growTranscript(chat, 30);
|
|
202
|
+
expect(chat.scroller.distanceFromBottom()).toBeLessThanOrEqual(
|
|
203
|
+
BOTTOM_TOLERANCE_PX,
|
|
204
|
+
);
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it("ends at the bottom for a chat started from outside that sends its prompt", async () => {
|
|
208
|
+
const chat = await openChat();
|
|
209
|
+
chat.scroller.scrollTo(200);
|
|
210
|
+
chat.harness.session.startConversation("build me a page", undefined, true);
|
|
211
|
+
await frame();
|
|
212
|
+
await frame();
|
|
213
|
+
expect(chat.scroller.distanceFromBottom()).toBeLessThanOrEqual(
|
|
214
|
+
BOTTOM_TOLERANCE_PX,
|
|
215
|
+
);
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
it("opens another chat at its bottom, even after scrolling up in this one", async () => {
|
|
219
|
+
const chat = await openChat();
|
|
220
|
+
chat.scroller.scrollTo(200);
|
|
221
|
+
chat.harness.session.openConversation("conv-other");
|
|
222
|
+
await frame();
|
|
223
|
+
deliver(chat.harness, {
|
|
224
|
+
conversationId: "conv-other",
|
|
225
|
+
type: "conversation_snapshot",
|
|
226
|
+
messages: transcript(50),
|
|
227
|
+
});
|
|
228
|
+
await frame();
|
|
229
|
+
expect(chat.scroller.distanceFromBottom()).toBeLessThanOrEqual(
|
|
230
|
+
BOTTOM_TOLERANCE_PX,
|
|
231
|
+
);
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
it("keeps following in a shorter chat opened from the bottom of a long one", async () => {
|
|
235
|
+
const chat = await openChat(60);
|
|
236
|
+
chat.harness.session.openConversation("conv-other");
|
|
237
|
+
await frame();
|
|
238
|
+
deliver(chat.harness, {
|
|
239
|
+
conversationId: "conv-other",
|
|
240
|
+
type: "conversation_snapshot",
|
|
241
|
+
messages: transcript(8),
|
|
242
|
+
});
|
|
243
|
+
await frame();
|
|
244
|
+
await frame();
|
|
245
|
+
chat.scroller.extraContentPx += 500;
|
|
246
|
+
await frame();
|
|
247
|
+
expect(chat.scroller.distanceFromBottom()).toBeLessThanOrEqual(
|
|
248
|
+
BOTTOM_TOLERANCE_PX,
|
|
249
|
+
);
|
|
250
|
+
});
|
|
251
|
+
});
|
|
@@ -134,7 +134,6 @@ describe("the conversation folds the redesign's events", () => {
|
|
|
134
134
|
type: "conversation_mode",
|
|
135
135
|
mode: "plan",
|
|
136
136
|
generationMode: "vibe",
|
|
137
|
-
fullAuto: { duration: "turn" },
|
|
138
137
|
});
|
|
139
138
|
expect(conversation.messages.value[0]).toMatchObject({
|
|
140
139
|
role: "notice",
|
|
@@ -144,7 +143,6 @@ describe("the conversation folds the redesign's events", () => {
|
|
|
144
143
|
expect(conversation.mode.value).toEqual({
|
|
145
144
|
mode: "plan",
|
|
146
145
|
generationMode: "vibe",
|
|
147
|
-
fullAuto: { duration: "turn" },
|
|
148
146
|
});
|
|
149
147
|
});
|
|
150
148
|
|
|
@@ -200,7 +198,7 @@ describe("the conversation folds the redesign's events", () => {
|
|
|
200
198
|
},
|
|
201
199
|
],
|
|
202
200
|
changeSets: [changeSet()],
|
|
203
|
-
mode: { mode: "acceptEdits", generationMode: "safe"
|
|
201
|
+
mode: { mode: "acceptEdits", generationMode: "safe" },
|
|
204
202
|
totalTokens: 1_200,
|
|
205
203
|
});
|
|
206
204
|
expect(conversation.messages.value.map((m) => m.role)).toEqual([
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
import { mount } from "@vue/test-utils";
|
|
3
|
+
import { describe, expect, it } from "vitest";
|
|
4
|
+
import ProviderNotice from "../../app/chat/components/ProviderNotice.vue";
|
|
5
|
+
import { CHAT_I18N_KEY } from "../../app/chat/composables/useChatI18n";
|
|
6
|
+
import fr from "../../i18n/locales/dms-ai-panel-fr-FR.json";
|
|
7
|
+
import { createTestI18n } from "../support/i18n";
|
|
8
|
+
import { PANEL_STUBS } from "../support/stubs";
|
|
9
|
+
|
|
10
|
+
const ENGLISH_REASON =
|
|
11
|
+
"Sign in with ChatGPT in Assistant › Settings to run Codex on your ChatGPT plan.";
|
|
12
|
+
|
|
13
|
+
function noticeText(code?: "codex_not_signed_in"): string {
|
|
14
|
+
return mount(ProviderNotice, {
|
|
15
|
+
props: { agentName: "Codex", reason: ENGLISH_REASON, code },
|
|
16
|
+
global: {
|
|
17
|
+
provide: { [CHAT_I18N_KEY as symbol]: createTestI18n(fr) },
|
|
18
|
+
stubs: PANEL_STUBS,
|
|
19
|
+
},
|
|
20
|
+
}).text();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
describe("the agent can't run notice", () => {
|
|
24
|
+
it("words the ChatGPT sign-in hint in the panel's language", () => {
|
|
25
|
+
const text = noticeText("codex_not_signed_in");
|
|
26
|
+
expect(text).toContain("Connectez-vous avec ChatGPT");
|
|
27
|
+
expect(text).not.toContain(ENGLISH_REASON);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("shows the sidecar's own reason when the panel has no wording for it", () => {
|
|
31
|
+
expect(noticeText()).toContain(ENGLISH_REASON);
|
|
32
|
+
});
|
|
33
|
+
});
|