@antelopejs/dms-ai 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/dist/constants/frontend-module.d.ts +2 -0
- package/dist/constants/frontend-module.js +6 -1
- package/dist/constants/frontend-module.js.map +1 -1
- package/dist/constants/pages.d.ts +4 -4
- package/dist/constants/pages.js +4 -4
- package/dist/constants/pages.js.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/pages/skills/page.js +0 -2
- package/dist/pages/skills/page.js.map +1 -1
- package/frontend-vue/app/components/ActivityDetail.vue +11 -13
- package/frontend-vue/app/components/ChangesView.vue +56 -49
- package/frontend-vue/app/plugins/ai.client.ts +16 -6
- package/frontend-vue/app/runtime/assistant-activity.ts +38 -21
- package/frontend-vue/app/runtime/sidecar-status.ts +78 -56
- package/frontend-vue/app/views/ChangeSetPanel.vue +13 -18
- package/frontend-vue/app/views/UnavailableState.vue +1 -1
- package/frontend-vue/app/views/composables/useAiData.ts +116 -0
- package/frontend-vue/app/views/composables/useAssistant.ts +8 -2
- package/frontend-vue/app/views/composables/useChangeSetActions.ts +7 -6
- package/frontend-vue/app/views/constants.ts +1 -1
- package/frontend-vue/app/views/utils/change-sets.ts +0 -7
- package/frontend-vue/package.json +1 -1
- package/frontend-vue/tests/assistant-activity.test.ts +69 -0
- package/frontend-vue/tests/chat/markdown.test.ts +1 -0
- package/frontend-vue/tests/chat-panel.test.ts +1 -0
- package/frontend-vue/tests/host-commands.test.ts +1 -0
- package/frontend-vue/tests/navigation.test.ts +1 -0
- package/frontend-vue/tests/palette-assistant.test.ts +1 -0
- package/frontend-vue/tests/panel-states.test.ts +6 -1
- package/frontend-vue/tests/sidecar-guest.test.ts +1 -1
- package/frontend-vue/tests/sidecar-status.test.ts +93 -15
- package/frontend-vue/tests/support/dms-frontend-module.ts +9 -0
- package/frontend-vue/tests/views/api-data-reads.test.ts +445 -0
- package/frontend-vue/tests/views/diff-view.test.ts +1 -0
- package/frontend-vue/tests/views/use-assistant.test.ts +53 -0
- package/frontend-vue/vitest.config.ts +14 -1
- package/package.json +3 -3
- package/sidecar/package.json +2 -1
- package/frontend-vue/app/views/composables/useAiRequest.ts +0 -89
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@ Codex is selectable once its CLI is installed.
|
|
|
17
17
|
|
|
18
18
|
## Installation
|
|
19
19
|
|
|
20
|
-
Add the module to a project that already uses `@antelopejs/dms
|
|
20
|
+
Add the module to a project that already uses `@antelopejs/dms` 0.9 (with `@antelopejs/interface-dms` 0.7 and `@antelopejs/dms-frontend` 0.6: the views read their data with its `useApiData`, and the module's routes under `/ai/**` reach the backend through the frontend server, which the module declares as a backend prefix with the session):
|
|
21
21
|
|
|
22
22
|
```bash
|
|
23
23
|
ajs project modules add @antelopejs/dms-ai
|
|
@@ -234,6 +234,8 @@ pnpm --dir frontend-vue build
|
|
|
234
234
|
pnpm --dir frontend-vue typecheck
|
|
235
235
|
```
|
|
236
236
|
|
|
237
|
+
`pnpm test:node` runs every backend suite below in one go, after a single build (`DMS_PREBUILT=1` skips the build when `dist/` is already fresh, as in CI). The sidecar's opt-in Codex acceptance suite runs on its own with `CODEX_ACCEPTANCE=1 pnpm --dir sidecar test:acceptance`.
|
|
238
|
+
|
|
237
239
|
`pnpm test:frontend-registration` checks backend registration and sidecar inputs with the sidecar launcher mocked, and that every page, block and child of the Assistant module is titled with `$dms_ai` keys present in both locales.
|
|
238
240
|
`pnpm test:routes` drives the `/ai/*` routes against a stand-in sidecar: query translation, `503` while it is down, settings conversions, Undo stamping and the CSV export.
|
|
239
241
|
`pnpm test:sidecar-lifecycle` starts a stand-in sidecar to check that a hot reload keeps it, a restart replaces it, a sidecar left by an earlier run is stopped, and Ctrl+C on the backend stops it.
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { FrontendBackendProxy } from "@antelopejs/interface-dms/page";
|
|
1
2
|
export declare const FRONTEND_MODULE_NAME = "@antelopejs/dms-ai-frontend-vue";
|
|
2
3
|
export declare const FRONTEND_MODULE_DIR = "../frontend-vue";
|
|
3
4
|
export declare const FRONTEND_MODULE_PRIORITY = 100;
|
|
5
|
+
export declare const FRONTEND_BACKEND_PROXY: FrontendBackendProxy;
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.FRONTEND_MODULE_PRIORITY = exports.FRONTEND_MODULE_DIR = exports.FRONTEND_MODULE_NAME = void 0;
|
|
3
|
+
exports.FRONTEND_BACKEND_PROXY = exports.FRONTEND_MODULE_PRIORITY = exports.FRONTEND_MODULE_DIR = exports.FRONTEND_MODULE_NAME = void 0;
|
|
4
|
+
const module_1 = require("./module");
|
|
4
5
|
exports.FRONTEND_MODULE_NAME = "@antelopejs/dms-ai-frontend-vue";
|
|
5
6
|
exports.FRONTEND_MODULE_DIR = "../frontend-vue";
|
|
6
7
|
exports.FRONTEND_MODULE_PRIORITY = 100;
|
|
8
|
+
exports.FRONTEND_BACKEND_PROXY = {
|
|
9
|
+
path: `${module_1.ROUTE_PREFIX}/**`,
|
|
10
|
+
auth: "session",
|
|
11
|
+
};
|
|
7
12
|
//# sourceMappingURL=frontend-module.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"frontend-module.js","sourceRoot":"","sources":["../../src/constants/frontend-module.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"frontend-module.js","sourceRoot":"","sources":["../../src/constants/frontend-module.ts"],"names":[],"mappings":";;;AACA,qCAAwC;AAE3B,QAAA,oBAAoB,GAAG,iCAAiC,CAAC;AACzD,QAAA,mBAAmB,GAAG,iBAAiB,CAAC;AACxC,QAAA,wBAAwB,GAAG,GAAG,CAAC;AAO/B,QAAA,sBAAsB,GAAyB;IAC1D,IAAI,EAAE,GAAG,qBAAY,KAAK;IAC1B,IAAI,EAAE,SAAS;CAChB,CAAC"}
|
|
@@ -32,9 +32,9 @@ export declare const PAGE_ROUTES: {
|
|
|
32
32
|
readonly USAGE_SUMMARY: "/ai/metrics/usage/summary?days=14";
|
|
33
33
|
readonly CHANGES: "/ai/changes";
|
|
34
34
|
readonly RECENT_CHANGES: "/ai/recent-changes";
|
|
35
|
-
readonly CHANGE_UNDO: "/ai/changes/{_id}/undo";
|
|
36
|
-
readonly CHANGE_UNDO_CONFIRM: "/ai/changes/{
|
|
37
|
-
readonly CHANGE_REDO: "/ai/changes/{_id}/redo";
|
|
35
|
+
readonly CHANGE_UNDO: "/ai/changes/{{row._id}}/undo";
|
|
36
|
+
readonly CHANGE_UNDO_CONFIRM: "/ai/changes/{{row._id}}/undo-confirm";
|
|
37
|
+
readonly CHANGE_REDO: "/ai/changes/{{row._id}}/redo";
|
|
38
38
|
readonly ACTIVITY: "/ai/activity";
|
|
39
39
|
readonly ACTIVITY_EXPORT: "/ai/activity/export.csv";
|
|
40
40
|
readonly SKILLS_CATALOG: "/ai/skills/catalog";
|
|
@@ -43,7 +43,7 @@ export declare const PAGE_ROUTES: {
|
|
|
43
43
|
};
|
|
44
44
|
export declare const PAGE_LINKS: {
|
|
45
45
|
readonly CHANGES: "/modules/ai/changes";
|
|
46
|
-
readonly CHANGE_SET: "/modules/ai/changes?set={_id}";
|
|
46
|
+
readonly CHANGE_SET: "/modules/ai/changes?set={{row._id}}";
|
|
47
47
|
readonly ACTIVITY: "/modules/ai/activity";
|
|
48
48
|
readonly SETTINGS: "/modules/ai/settings";
|
|
49
49
|
readonly SKILL_SETTINGS: "/modules/ai/settings#dms-form-settings-section-skills";
|
package/dist/constants/pages.js
CHANGED
|
@@ -39,9 +39,9 @@ exports.PAGE_ROUTES = {
|
|
|
39
39
|
USAGE_SUMMARY: `${module_1.ROUTE_PREFIX}/metrics/usage/summary?days=${USAGE_DAYS}`,
|
|
40
40
|
CHANGES: `${module_1.ROUTE_PREFIX}/changes`,
|
|
41
41
|
RECENT_CHANGES: `${module_1.ROUTE_PREFIX}/recent-changes`,
|
|
42
|
-
CHANGE_UNDO: `${module_1.ROUTE_PREFIX}/changes/{_id}/undo`,
|
|
43
|
-
CHANGE_UNDO_CONFIRM: `${module_1.ROUTE_PREFIX}/changes/{
|
|
44
|
-
CHANGE_REDO: `${module_1.ROUTE_PREFIX}/changes/{_id}/redo`,
|
|
42
|
+
CHANGE_UNDO: `${module_1.ROUTE_PREFIX}/changes/{{row._id}}/undo`,
|
|
43
|
+
CHANGE_UNDO_CONFIRM: `${module_1.ROUTE_PREFIX}/changes/{{row._id}}/undo-confirm`,
|
|
44
|
+
CHANGE_REDO: `${module_1.ROUTE_PREFIX}/changes/{{row._id}}/redo`,
|
|
45
45
|
ACTIVITY: `${module_1.ROUTE_PREFIX}/activity`,
|
|
46
46
|
ACTIVITY_EXPORT: `${module_1.ROUTE_PREFIX}/activity/export.csv`,
|
|
47
47
|
SKILLS_CATALOG: `${module_1.ROUTE_PREFIX}/skills/catalog`,
|
|
@@ -50,7 +50,7 @@ exports.PAGE_ROUTES = {
|
|
|
50
50
|
};
|
|
51
51
|
exports.PAGE_LINKS = {
|
|
52
52
|
CHANGES: `${MODULE_PAGES_PATH}/${exports.PAGE_IDS.CHANGES}`,
|
|
53
|
-
CHANGE_SET: `${MODULE_PAGES_PATH}/${exports.PAGE_IDS.CHANGES}?set={_id}`,
|
|
53
|
+
CHANGE_SET: `${MODULE_PAGES_PATH}/${exports.PAGE_IDS.CHANGES}?set={{row._id}}`,
|
|
54
54
|
ACTIVITY: `${MODULE_PAGES_PATH}/${exports.PAGE_IDS.ACTIVITY}`,
|
|
55
55
|
SETTINGS: `${MODULE_PAGES_PATH}/${exports.PAGE_IDS.SETTINGS}`,
|
|
56
56
|
SKILL_SETTINGS: `${MODULE_PAGES_PATH}/${exports.PAGE_IDS.SETTINGS}#dms-form-${SETTINGS_FORM_KEY}-section-${exports.SETTINGS_SKILLS_SECTION}`,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pages.js","sourceRoot":"","sources":["../../src/constants/pages.ts"],"names":[],"mappings":";;;AAAA,qCAAwC;AAE3B,QAAA,cAAc,GAAG,cAAc,CAAC;AAChC,QAAA,sBAAsB,GAAG,UAAU,CAAC;AAGjD,MAAM,iBAAiB,GAAG,aAAa,CAAC;AAE3B,QAAA,QAAQ,GAAG;IACtB,QAAQ,EAAE,UAAU;IACpB,OAAO,EAAE,SAAS;IAClB,QAAQ,EAAE,UAAU;IACpB,MAAM,EAAE,QAAQ;IAChB,QAAQ,EAAE,UAAU;CACZ,CAAC;AAEE,QAAA,UAAU,GAAG;IACxB,QAAQ,EAAE,CAAC;IACX,OAAO,EAAE,CAAC;IACV,QAAQ,EAAE,CAAC;IACX,MAAM,EAAE,CAAC;IACT,QAAQ,EAAE,CAAC;CACH,CAAC;AAGE,QAAA,qBAAqB,GAAG,aAAa,CAAC;AAGtC,QAAA,kBAAkB,GAAG,CAAC,CAAC;AAEvB,QAAA,eAAe,GAAG,CAAC,CAAC;AAEpB,QAAA,kBAAkB,GAAG,EAAE,CAAC;AAErC,MAAM,UAAU,GAAG,EAAE,CAAC;AAGtB,MAAM,iBAAiB,GAAG,UAAU,CAAC;AACxB,QAAA,uBAAuB,GAAG,QAAQ,CAAC;AAGnC,QAAA,WAAW,GAAG;IACzB,MAAM,EAAE,GAAG,qBAAY,SAAS;IAChC,YAAY,EAAE,GAAG,qBAAY,eAAe;IAC5C,aAAa,EAAE,GAAG,qBAAY,gBAAgB;IAC9C,eAAe,EAAE,GAAG,qBAAY,kBAAkB;IAClD,GAAG,EAAE,GAAG,qBAAY,cAAc;IAClC,MAAM,EAAE,GAAG,qBAAY,iBAAiB;IACxC,OAAO,EAAE,GAAG,qBAAY,kBAAkB;IAC1C,SAAS,EAAE,GAAG,qBAAY,4BAA4B,uBAAe,EAAE;IACvE,KAAK,EAAE,GAAG,qBAAY,uBAAuB,UAAU,EAAE;IACzD,aAAa,EAAE,GAAG,qBAAY,+BAA+B,UAAU,EAAE;IACzE,OAAO,EAAE,GAAG,qBAAY,UAAU;IAClC,cAAc,EAAE,GAAG,qBAAY,iBAAiB;IAChD,WAAW,EAAE,GAAG,qBAAY,
|
|
1
|
+
{"version":3,"file":"pages.js","sourceRoot":"","sources":["../../src/constants/pages.ts"],"names":[],"mappings":";;;AAAA,qCAAwC;AAE3B,QAAA,cAAc,GAAG,cAAc,CAAC;AAChC,QAAA,sBAAsB,GAAG,UAAU,CAAC;AAGjD,MAAM,iBAAiB,GAAG,aAAa,CAAC;AAE3B,QAAA,QAAQ,GAAG;IACtB,QAAQ,EAAE,UAAU;IACpB,OAAO,EAAE,SAAS;IAClB,QAAQ,EAAE,UAAU;IACpB,MAAM,EAAE,QAAQ;IAChB,QAAQ,EAAE,UAAU;CACZ,CAAC;AAEE,QAAA,UAAU,GAAG;IACxB,QAAQ,EAAE,CAAC;IACX,OAAO,EAAE,CAAC;IACV,QAAQ,EAAE,CAAC;IACX,MAAM,EAAE,CAAC;IACT,QAAQ,EAAE,CAAC;CACH,CAAC;AAGE,QAAA,qBAAqB,GAAG,aAAa,CAAC;AAGtC,QAAA,kBAAkB,GAAG,CAAC,CAAC;AAEvB,QAAA,eAAe,GAAG,CAAC,CAAC;AAEpB,QAAA,kBAAkB,GAAG,EAAE,CAAC;AAErC,MAAM,UAAU,GAAG,EAAE,CAAC;AAGtB,MAAM,iBAAiB,GAAG,UAAU,CAAC;AACxB,QAAA,uBAAuB,GAAG,QAAQ,CAAC;AAGnC,QAAA,WAAW,GAAG;IACzB,MAAM,EAAE,GAAG,qBAAY,SAAS;IAChC,YAAY,EAAE,GAAG,qBAAY,eAAe;IAC5C,aAAa,EAAE,GAAG,qBAAY,gBAAgB;IAC9C,eAAe,EAAE,GAAG,qBAAY,kBAAkB;IAClD,GAAG,EAAE,GAAG,qBAAY,cAAc;IAClC,MAAM,EAAE,GAAG,qBAAY,iBAAiB;IACxC,OAAO,EAAE,GAAG,qBAAY,kBAAkB;IAC1C,SAAS,EAAE,GAAG,qBAAY,4BAA4B,uBAAe,EAAE;IACvE,KAAK,EAAE,GAAG,qBAAY,uBAAuB,UAAU,EAAE;IACzD,aAAa,EAAE,GAAG,qBAAY,+BAA+B,UAAU,EAAE;IACzE,OAAO,EAAE,GAAG,qBAAY,UAAU;IAClC,cAAc,EAAE,GAAG,qBAAY,iBAAiB;IAChD,WAAW,EAAE,GAAG,qBAAY,2BAA2B;IACvD,mBAAmB,EAAE,GAAG,qBAAY,mCAAmC;IACvE,WAAW,EAAE,GAAG,qBAAY,2BAA2B;IACvD,QAAQ,EAAE,GAAG,qBAAY,WAAW;IACpC,eAAe,EAAE,GAAG,qBAAY,sBAAsB;IACtD,cAAc,EAAE,GAAG,qBAAY,iBAAiB;IAChD,eAAe,EAAE,GAAG,qBAAY,mBAAmB;IACnD,QAAQ,EAAE,GAAG,qBAAY,WAAW;CAC5B,CAAC;AAGE,QAAA,UAAU,GAAG;IACxB,OAAO,EAAE,GAAG,iBAAiB,IAAI,gBAAQ,CAAC,OAAO,EAAE;IACnD,UAAU,EAAE,GAAG,iBAAiB,IAAI,gBAAQ,CAAC,OAAO,kBAAkB;IACtE,QAAQ,EAAE,GAAG,iBAAiB,IAAI,gBAAQ,CAAC,QAAQ,EAAE;IACrD,QAAQ,EAAE,GAAG,iBAAiB,IAAI,gBAAQ,CAAC,QAAQ,EAAE;IACrD,cAAc,EAAE,GAAG,iBAAiB,IAAI,gBAAQ,CAAC,QAAQ,aAAa,iBAAiB,YAAY,+BAAuB,EAAE;CACpH,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -30,6 +30,7 @@ async function start() {
|
|
|
30
30
|
sourcePath: node_path_1.default.join(__dirname, frontend_module_1.FRONTEND_MODULE_DIR),
|
|
31
31
|
renderer: { name: "vue", version: "3" },
|
|
32
32
|
priority: frontend_module_1.FRONTEND_MODULE_PRIORITY,
|
|
33
|
+
backendProxies: [frontend_module_1.FRONTEND_BACKEND_PROXY],
|
|
33
34
|
});
|
|
34
35
|
const [moduleRoots, skillDirs, builderEnabled] = await Promise.all([
|
|
35
36
|
(0, module_roots_1.collectModuleRoots)(),
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;AAoBA,8BAEC;AAED,sBA0BC;AAOD,0BAEC;AA3DD,0DAA6B;AAC7B,gEAA6D;AAC7D,yDAAmE;AACnE,iDAAwD;AACxD,kDAAsD;AACtD,qCAA6D;AAC7D,iEAKqC;AACrC,iDAAyD;AACzD,2DAA8D;AAC9D,6DAAgE;AAChE,6DAAyD;AACzD,qDAAuD;AACvD,mBAAiB;AACjB,oBAAkB;AAElB,SAAgB,SAAS,CAAC,MAAe;IACvC,IAAA,kBAAS,EAAC,IAAA,oBAAW,EAAC,MAAM,CAAC,CAAC,CAAC;AACjC,CAAC;AAEM,KAAK,UAAU,KAAK;IACzB,IAAA,4BAAe,GAAE,CAAC;IAClB,MAAM,IAAA,wBAAiB,EAAC;QACtB,IAAI,EAAE,sCAAoB;QAC1B,UAAU,EAAE,mBAAI,CAAC,IAAI,CAAC,SAAS,EAAE,qCAAmB,CAAC;QACrD,QAAQ,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE;QACvC,QAAQ,EAAE,0CAAwB;QAClC,cAAc,EAAE,CAAC,wCAAsB,CAAC;KACzC,CAAC,CAAC;IAIH,MAAM,CAAC,WAAW,EAAE,SAAS,EAAE,cAAc,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACjE,IAAA,iCAAkB,GAAE;QACpB,IAAA,mCAAmB,GAAE;QACrB,IAAA,6BAAkB,GAAE;KACrB,CAAC,CAAC;IACH,KAAK,IAAA,4BAAY,EAAC;QAChB,eAAe,EAAE,OAAO,CAAC,GAAG,EAAE;QAC9B,GAAG,IAAA,kBAAS,GAAE;QACd,WAAW;QACX,SAAS;QACT,cAAc;KACf,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;QACf,iBAAO,CAAC,KAAK,CAAC,GAAG,4BAAkB,gBAAgB,EAAE,GAAG,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;AACL,CAAC;AAOD,SAAgB,OAAO;IACrB,IAAA,0BAAe,GAAE,CAAC;AACpB,CAAC"}
|
|
@@ -82,8 +82,6 @@ let AISkillsPage = class AISkillsPage extends (0, page_1.PageController)(pages_1
|
|
|
82
82
|
labelKey: "name",
|
|
83
83
|
searchPlaceholder: text("search"),
|
|
84
84
|
displays: [{ id: CARDS_DISPLAY }],
|
|
85
|
-
tableDisplay: false,
|
|
86
|
-
defaultDisplay: CARDS_DISPLAY,
|
|
87
85
|
pageSize: CARDS_PAGE_SIZE,
|
|
88
86
|
defaultSort: { field: "uses30d", desc: true },
|
|
89
87
|
card: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"page.js","sourceRoot":"","sources":["../../../src/pages/skills/page.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"page.js","sourceRoot":"","sources":["../../../src/pages/skills/page.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { computed, ref
|
|
2
|
+
import { computed, ref } from "vue";
|
|
3
3
|
import DecisionLabel from "../views/DecisionLabel.vue";
|
|
4
4
|
import DiffView from "../views/DiffView.vue";
|
|
5
5
|
import RowStepper from "../views/RowStepper.vue";
|
|
6
6
|
import ResultPill from "../views/ResultPill.vue";
|
|
7
7
|
import UnavailableState from "../views/UnavailableState.vue";
|
|
8
|
-
import {
|
|
8
|
+
import { useAiData } from "../views/composables/useAiData";
|
|
9
9
|
import { useAssistant } from "../views/composables/useAssistant";
|
|
10
10
|
import { useViewFormat } from "../views/composables/useViewFormat";
|
|
11
11
|
import { AI_PAGES, AI_ROUTES, CHANGE_SET_QUERY_KEY } from "../views/constants";
|
|
@@ -30,29 +30,27 @@ interface Props {
|
|
|
30
30
|
const props = defineProps<Props>();
|
|
31
31
|
|
|
32
32
|
const { t } = useI18n();
|
|
33
|
-
const { $authFetch } = useAuthFetch();
|
|
34
33
|
const { moment, toolLabel, clock } = useViewFormat();
|
|
35
34
|
const assistant = useAssistant();
|
|
36
|
-
const detail = useAiRequest<ActivityDetailPayload>();
|
|
37
35
|
const isRawShown = ref(false);
|
|
38
36
|
|
|
39
37
|
const OUTPUT_MAX_LINES = 14;
|
|
40
38
|
const RAW_MAX_LINES = 20;
|
|
41
39
|
|
|
42
40
|
const rowId = computed(() => props.rowData?.id ?? props.rowData?._id);
|
|
41
|
+
// Read with the page: a deep link (`?record=<id>`) renders the entry on the
|
|
42
|
+
// server and hands it over. The drawer opened again shows the entry read
|
|
43
|
+
// before and reads it again, as a pending call may have ended since.
|
|
44
|
+
const detail = useAiData<ActivityDetailPayload>(() =>
|
|
45
|
+
rowId.value
|
|
46
|
+
? `${AI_ROUTES.activity}/${encodeURIComponent(rowId.value)}`
|
|
47
|
+
: null,
|
|
48
|
+
);
|
|
43
49
|
|
|
44
50
|
function load(): void {
|
|
45
|
-
|
|
46
|
-
if (!id) return;
|
|
47
|
-
void detail.run(() =>
|
|
48
|
-
$authFetch<ActivityDetailPayload>(
|
|
49
|
-
`${AI_ROUTES.activity}/${encodeURIComponent(id)}`,
|
|
50
|
-
),
|
|
51
|
-
);
|
|
51
|
+
void detail.refresh();
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
watch(rowId, load, { immediate: true });
|
|
55
|
-
|
|
56
54
|
const row = computed(() => props.rowData);
|
|
57
55
|
const eyebrow = computed(() => {
|
|
58
56
|
const current = row.value;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { computed,
|
|
2
|
+
import { computed, ref, watch } from "vue";
|
|
3
3
|
import { useDmsRoute } from "#dms/frontend-module";
|
|
4
4
|
import ChangeSetPanel from "../views/ChangeSetPanel.vue";
|
|
5
5
|
import UnavailableState from "../views/UnavailableState.vue";
|
|
6
|
-
import {
|
|
6
|
+
import { useAiData, useAiPagedData } from "../views/composables/useAiData";
|
|
7
7
|
import { useAssistant } from "../views/composables/useAssistant";
|
|
8
8
|
import { useViewFormat } from "../views/composables/useViewFormat";
|
|
9
9
|
import {
|
|
@@ -20,34 +20,18 @@ import type {
|
|
|
20
20
|
import {
|
|
21
21
|
changeSetIcon,
|
|
22
22
|
matchesSearch,
|
|
23
|
-
readSelectedSet,
|
|
24
23
|
writeSelectedSet,
|
|
25
24
|
} from "../views/utils/change-sets";
|
|
26
25
|
|
|
27
26
|
type ScopeFilter = ScopeId | "all";
|
|
28
27
|
|
|
29
28
|
const { t } = useI18n();
|
|
30
|
-
const { $authFetch } = useAuthFetch();
|
|
31
29
|
const { moment } = useViewFormat();
|
|
32
30
|
const assistant = useAssistant();
|
|
33
31
|
const route = useDmsRoute();
|
|
34
32
|
|
|
35
|
-
const list = useAiRequest<ListPayload<ChangeSetSummary>>();
|
|
36
|
-
const status = useAiRequest<AssistantStatus>();
|
|
37
|
-
const changeSets = ref<ChangeSetSummary[]>([]);
|
|
38
|
-
const total = ref(0);
|
|
39
33
|
const scope = ref<ScopeFilter>("all");
|
|
40
34
|
const search = ref("");
|
|
41
|
-
const selectedId = ref<string | undefined>(readSelectedSet());
|
|
42
|
-
// The list loads on the client only: until its first answer the server and
|
|
43
|
-
// the hydrating client both draw the skeleton, never a premature empty state.
|
|
44
|
-
const hasLoaded = ref(false);
|
|
45
|
-
|
|
46
|
-
const SCOPE_ITEMS = computed(() => [
|
|
47
|
-
{ value: "all", label: t("dms_ai.views.changes.filter_all") },
|
|
48
|
-
{ value: "safe", label: t("dms_ai.views.changes.filter_safe") },
|
|
49
|
-
{ value: "vibe", label: t("dms_ai.views.changes.filter_code") },
|
|
50
|
-
]);
|
|
51
35
|
|
|
52
36
|
function listQuery(offset: number): Record<string, string | number> {
|
|
53
37
|
const query: Record<string, string | number> = {
|
|
@@ -58,46 +42,69 @@ function listQuery(offset: number): Record<string, string | number> {
|
|
|
58
42
|
return { ...query, scope: scope.value, filter_scope: `is:${scope.value}` };
|
|
59
43
|
}
|
|
60
44
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
45
|
+
type ChangesPage = ListPayload<ChangeSetSummary>;
|
|
46
|
+
|
|
47
|
+
/** The sets the pages hold, in order. */
|
|
48
|
+
function loadedCount(pages: ChangesPage[]): number {
|
|
49
|
+
return pages.reduce((count, page) => count + page.results.length, 0);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// The status and the list's first page are read with the page: a server
|
|
53
|
+
// render shows them, and the selected set's panel, at once. "Load more"
|
|
54
|
+
// appends a page under the scope's key; the page's refreshes read every
|
|
55
|
+
// page loaded again.
|
|
56
|
+
const status = useAiData<AssistantStatus>(AI_ROUTES.status);
|
|
57
|
+
const list = useAiPagedData<ChangesPage, number>(
|
|
58
|
+
() => `dms-ai:changes:${scope.value}`,
|
|
59
|
+
({ $authFetch, cursor, signal }) =>
|
|
60
|
+
$authFetch<ChangesPage>(AI_ROUTES.changes, {
|
|
61
|
+
query: listQuery(cursor ?? 0),
|
|
62
|
+
signal,
|
|
65
63
|
}),
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
64
|
+
{
|
|
65
|
+
nextCursor: (page, pages) => {
|
|
66
|
+
const loaded = loadedCount(pages);
|
|
67
|
+
return page.results.length > 0 && loaded < page.total ? loaded : null;
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
);
|
|
71
|
+
const changeSets = computed(() =>
|
|
72
|
+
list.pages.value.flatMap((page) => page.results),
|
|
73
|
+
);
|
|
74
|
+
const total = computed(() => list.pages.value.at(-1)?.total ?? 0);
|
|
75
|
+
|
|
76
|
+
function selectedFromRoute(): string | undefined {
|
|
77
|
+
const id = route.query[CHANGE_SET_QUERY_KEY];
|
|
78
|
+
return typeof id === "string" && id ? id : undefined;
|
|
73
79
|
}
|
|
74
80
|
|
|
81
|
+
/** The set picked here or named by the URL (`?set=`); the first one until then. */
|
|
82
|
+
const pickedId = ref<string | undefined>(selectedFromRoute());
|
|
83
|
+
const selectedId = computed(() => pickedId.value ?? changeSets.value[0]?.id);
|
|
84
|
+
|
|
85
|
+
const SCOPE_ITEMS = computed(() => [
|
|
86
|
+
{ value: "all", label: t("dms_ai.views.changes.filter_all") },
|
|
87
|
+
{ value: "safe", label: t("dms_ai.views.changes.filter_safe") },
|
|
88
|
+
{ value: "vibe", label: t("dms_ai.views.changes.filter_code") },
|
|
89
|
+
]);
|
|
90
|
+
|
|
75
91
|
function reload(): Promise<void> {
|
|
76
|
-
return
|
|
92
|
+
return list.refresh();
|
|
77
93
|
}
|
|
78
94
|
|
|
95
|
+
/** Appends the next page; a failure keeps the sets listed and the button. */
|
|
79
96
|
function loadMore(): Promise<void> {
|
|
80
|
-
return
|
|
97
|
+
return list.loadMore();
|
|
81
98
|
}
|
|
82
99
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
void reload();
|
|
100
|
+
watch(selectedFromRoute, (id) => {
|
|
101
|
+
if (id) pickedId.value = id;
|
|
86
102
|
});
|
|
87
103
|
|
|
88
|
-
watch(scope, reload);
|
|
89
|
-
|
|
90
|
-
watch(
|
|
91
|
-
() => route.query[CHANGE_SET_QUERY_KEY],
|
|
92
|
-
(id) => {
|
|
93
|
-
if (id) selectedId.value = id;
|
|
94
|
-
},
|
|
95
|
-
);
|
|
96
|
-
|
|
97
104
|
function select(id: string | number | undefined): void {
|
|
98
105
|
if (id === undefined) return;
|
|
99
|
-
|
|
100
|
-
writeSelectedSet(
|
|
106
|
+
pickedId.value = String(id);
|
|
107
|
+
writeSelectedSet(pickedId.value);
|
|
101
108
|
}
|
|
102
109
|
|
|
103
110
|
function sublabel(set: ChangeSetSummary): string {
|
|
@@ -134,9 +141,10 @@ const isCheckpointOff = computed(
|
|
|
134
141
|
);
|
|
135
142
|
const isFirstLoad = computed(
|
|
136
143
|
() =>
|
|
137
|
-
|
|
144
|
+
changeSets.value.length === 0 &&
|
|
145
|
+
(list.pending.value || list.status.value === "idle"),
|
|
138
146
|
);
|
|
139
|
-
const hasMore = computed(() =>
|
|
147
|
+
const hasMore = computed(() => list.hasMore.value);
|
|
140
148
|
const listLabel = computed(() =>
|
|
141
149
|
t("dms_ai.views.changes.list_label", { count: total.value }),
|
|
142
150
|
);
|
|
@@ -230,7 +238,6 @@ const emptyActions = computed(() =>
|
|
|
230
238
|
v-if="selectedId"
|
|
231
239
|
:key="selectedId"
|
|
232
240
|
:change-set-id="selectedId"
|
|
233
|
-
@changed="reload"
|
|
234
241
|
/>
|
|
235
242
|
</DmsMasterDetail>
|
|
236
243
|
<div v-if="hasMore" class="flex lg:w-[380px] lg:justify-center">
|
|
@@ -239,7 +246,7 @@ const emptyActions = computed(() =>
|
|
|
239
246
|
variant="outline"
|
|
240
247
|
size="sm"
|
|
241
248
|
icon="i-ph-caret-down"
|
|
242
|
-
:loading="list.
|
|
249
|
+
:loading="list.loadingMore.value"
|
|
243
250
|
:label="t('dms_ai.views.common.load_more')"
|
|
244
251
|
@click="loadMore"
|
|
245
252
|
/>
|
|
@@ -70,6 +70,7 @@ import { runWhenLoggedIn } from "../runtime/session-gate";
|
|
|
70
70
|
import { installToggleShortcut } from "../runtime/shortcuts";
|
|
71
71
|
import {
|
|
72
72
|
createSidecarStatusController,
|
|
73
|
+
type SidecarInfoPayload,
|
|
73
74
|
type SidecarStatus,
|
|
74
75
|
type SidecarStatusController,
|
|
75
76
|
} from "../runtime/sidecar-status";
|
|
@@ -395,8 +396,13 @@ function createRuntime(
|
|
|
395
396
|
const holds = createStreamHolds();
|
|
396
397
|
const sidecarStatus = followSidecarStatus(controller, client);
|
|
397
398
|
const activity = createAssistantActivity({
|
|
398
|
-
|
|
399
|
-
|
|
399
|
+
// The application's read: polled for as long as the app runs, while
|
|
400
|
+
// the interval says so.
|
|
401
|
+
readStatus: (interval) =>
|
|
402
|
+
useApiData<AssistantStatusPayload>(STATUS_PATH, {
|
|
403
|
+
refreshInterval: interval,
|
|
404
|
+
refreshOnPageRefresh: false,
|
|
405
|
+
}),
|
|
400
406
|
chat: chat.transport,
|
|
401
407
|
shouldPoll: () =>
|
|
402
408
|
!panel.isOpen.value ||
|
|
@@ -413,7 +419,6 @@ function createRuntime(
|
|
|
413
419
|
activity,
|
|
414
420
|
currentPage,
|
|
415
421
|
});
|
|
416
|
-
void activity.refresh();
|
|
417
422
|
const stops = [
|
|
418
423
|
installToggleShortcut({ onToggle: panel.toggle }),
|
|
419
424
|
followPanel({ panel, activity, holds }, client),
|
|
@@ -462,8 +467,13 @@ async function startAssistant(
|
|
|
462
467
|
devReload: useDevReload(),
|
|
463
468
|
router: useDmsRouter(),
|
|
464
469
|
};
|
|
465
|
-
|
|
466
|
-
|
|
470
|
+
// Read once the gate opens, then polled while the sidecar comes back.
|
|
471
|
+
const controller = createSidecarStatusController((interval) =>
|
|
472
|
+
useApiData<SidecarInfoPayload>(SIDECAR_INFO_PATH, {
|
|
473
|
+
immediate: false,
|
|
474
|
+
refreshInterval: interval,
|
|
475
|
+
refreshOnPageRefresh: false,
|
|
476
|
+
}),
|
|
467
477
|
);
|
|
468
478
|
if (!(await controller.init())) {
|
|
469
479
|
context.runWithContext(() => unregisterSidePanel(SIDE_PANEL_ID));
|
|
@@ -496,7 +506,7 @@ export default defineDmsPlugin((context) => {
|
|
|
496
506
|
const appMounted = new Promise<void>((resolve) =>
|
|
497
507
|
context.hook("app:mounted", resolve),
|
|
498
508
|
);
|
|
499
|
-
const { loggedIn } =
|
|
509
|
+
const { loggedIn } = useDmsUserSession();
|
|
500
510
|
const stopGate = runWhenLoggedIn(
|
|
501
511
|
() => loggedIn.value,
|
|
502
512
|
() =>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { computed, type ComputedRef, type Ref, ref } from "vue";
|
|
1
|
+
import { computed, type ComputedRef, type Ref, ref, watch } from "vue";
|
|
2
2
|
import type { ChatTransport } from "./chat-transport";
|
|
3
3
|
import { STATUS_POLL_MS } from "./constants";
|
|
4
4
|
import { isTypedMessage } from "./typed-message";
|
|
@@ -35,10 +35,24 @@ export interface AssistantActivity {
|
|
|
35
35
|
stop: () => void;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
/** The read of the backend's status: `useApiData`, polled every `interval`. */
|
|
39
|
+
export interface AssistantStatusRead {
|
|
40
|
+
data: Readonly<Ref<AssistantStatusPayload | null>>;
|
|
41
|
+
refresh: () => Promise<void>;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Opens the status read, polled every `interval` ms while it is above 0 and
|
|
46
|
+
* not polled while it is 0.
|
|
47
|
+
*/
|
|
48
|
+
export type OpenAssistantStatusRead = (
|
|
49
|
+
interval: () => number,
|
|
50
|
+
) => AssistantStatusRead;
|
|
51
|
+
|
|
38
52
|
export interface AssistantActivityOptions {
|
|
39
|
-
|
|
53
|
+
readStatus: OpenAssistantStatusRead;
|
|
40
54
|
chat: ChatTransport;
|
|
41
|
-
/** Whether polling is useful now: the
|
|
55
|
+
/** Whether polling is useful now: the panel is closed, or its stream is down. */
|
|
42
56
|
shouldPoll: () => boolean;
|
|
43
57
|
}
|
|
44
58
|
|
|
@@ -55,8 +69,9 @@ function sum(
|
|
|
55
69
|
|
|
56
70
|
/**
|
|
57
71
|
* What the tab knows of the assistant's work across chats, from the backend's
|
|
58
|
-
* status (polled while the panel is closed
|
|
59
|
-
*
|
|
72
|
+
* status (polled while the panel is closed or its stream down: the polling
|
|
73
|
+
* follows `shouldPoll`) and from the conversation lists the sidecar
|
|
74
|
+
* broadcasts while the stream is open.
|
|
60
75
|
*/
|
|
61
76
|
export function createAssistantActivity(
|
|
62
77
|
options: AssistantActivityOptions,
|
|
@@ -65,16 +80,21 @@ export function createAssistantActivity(
|
|
|
65
80
|
const workingConversations = ref(0);
|
|
66
81
|
const lastError = ref<string | null>(null);
|
|
67
82
|
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
83
|
+
const isStopped = ref(false);
|
|
84
|
+
const status = options.readStatus(() =>
|
|
85
|
+
!isStopped.value && options.shouldPoll() ? STATUS_POLL_MS : 0,
|
|
86
|
+
);
|
|
87
|
+
// A failed read keeps the last answer: the counts stay as they were.
|
|
88
|
+
const stopFollowing = watch(
|
|
89
|
+
status.data,
|
|
90
|
+
(payload) => {
|
|
91
|
+
if (!payload) return;
|
|
92
|
+
pendingApprovals.value = payload.pendingApprovals ?? 0;
|
|
93
|
+
workingConversations.value = payload.workingConversations ?? 0;
|
|
94
|
+
lastError.value = payload.lastError ?? null;
|
|
95
|
+
},
|
|
96
|
+
{ immediate: true },
|
|
97
|
+
);
|
|
78
98
|
|
|
79
99
|
const stopListening = options.chat.onMessage((msg) => {
|
|
80
100
|
if (!isListFrame(msg)) return;
|
|
@@ -85,10 +105,6 @@ export function createAssistantActivity(
|
|
|
85
105
|
);
|
|
86
106
|
});
|
|
87
107
|
|
|
88
|
-
const timer = setInterval(() => {
|
|
89
|
-
if (options.shouldPoll()) void refresh();
|
|
90
|
-
}, STATUS_POLL_MS);
|
|
91
|
-
|
|
92
108
|
return {
|
|
93
109
|
pendingApprovals,
|
|
94
110
|
workingConversations,
|
|
@@ -96,9 +112,10 @@ export function createAssistantActivity(
|
|
|
96
112
|
() => pendingApprovals.value > 0 || workingConversations.value > 0,
|
|
97
113
|
),
|
|
98
114
|
lastError,
|
|
99
|
-
refresh,
|
|
115
|
+
refresh: () => status.refresh(),
|
|
100
116
|
stop: () => {
|
|
101
|
-
|
|
117
|
+
isStopped.value = true;
|
|
118
|
+
stopFollowing();
|
|
102
119
|
stopListening();
|
|
103
120
|
},
|
|
104
121
|
};
|