kiokuko-dsh 0.2.1 → 0.2.3
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/PERMISSIONS.md +21 -28
- package/README.ja.md +8 -6
- package/README.md +12 -6
- package/THIRD_PARTY_NOTICES.md +8 -0
- package/dist/client.cjs +2248 -1383
- package/dist/client.d.ts +3 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/context/continuity-view.d.ts +1 -1
- package/dist/deep-thinker/configuration.d.ts.map +1 -1
- package/dist/deep-thinker/configuration.js +8 -5
- package/dist/deep-thinker/configuration.js.map +1 -1
- package/dist/deep-thinker/core/contracts.d.ts +107 -13
- package/dist/deep-thinker/core/contracts.d.ts.map +1 -1
- package/dist/deep-thinker/core/contracts.js +4 -2
- package/dist/deep-thinker/core/contracts.js.map +1 -1
- package/dist/deep-thinker/memory-finalizer.d.ts +10 -10
- package/dist/deep-thinker/memory-finalizer.js +2 -2
- package/dist/deep-thinker/memory-finalizer.js.map +1 -1
- package/dist/deep-thinker/report.d.ts +1 -1
- package/dist/deep-thinker/store.d.ts +10 -10
- package/dist/deep-thinker/store.d.ts.map +1 -1
- package/dist/deep-thinker/store.js +2 -2
- package/dist/deep-thinker/store.js.map +1 -1
- package/dist/dsh/coding-workflow/contracts.d.ts +120 -0
- package/dist/dsh/coding-workflow/contracts.d.ts.map +1 -0
- package/dist/dsh/coding-workflow/contracts.js +77 -0
- package/dist/dsh/coding-workflow/contracts.js.map +1 -0
- package/dist/dsh/coding-workflow/host.d.ts +41 -0
- package/dist/dsh/coding-workflow/host.d.ts.map +1 -0
- package/dist/dsh/coding-workflow/host.js +235 -0
- package/dist/dsh/coding-workflow/host.js.map +1 -0
- package/dist/dsh/coding-workflow/intent.d.ts +15 -0
- package/dist/dsh/coding-workflow/intent.d.ts.map +1 -0
- package/dist/dsh/coding-workflow/intent.js +86 -0
- package/dist/dsh/coding-workflow/intent.js.map +1 -0
- package/dist/dsh/coding-workflow/service.d.ts +155 -0
- package/dist/dsh/coding-workflow/service.d.ts.map +1 -0
- package/dist/dsh/coding-workflow/service.js +282 -0
- package/dist/dsh/coding-workflow/service.js.map +1 -0
- package/dist/dsh/coding-workflow/store.d.ts +17 -0
- package/dist/dsh/coding-workflow/store.d.ts.map +1 -0
- package/dist/dsh/coding-workflow/store.js +77 -0
- package/dist/dsh/coding-workflow/store.js.map +1 -0
- package/dist/dsh/completion-verifiers.d.ts +39 -0
- package/dist/dsh/completion-verifiers.d.ts.map +1 -0
- package/dist/dsh/completion-verifiers.js +9 -0
- package/dist/dsh/completion-verifiers.js.map +1 -0
- package/dist/dsh/config.d.ts +5 -1
- package/dist/dsh/config.d.ts.map +1 -1
- package/dist/dsh/core/host.d.ts +1 -1
- package/dist/dsh/core/host.d.ts.map +1 -1
- package/dist/dsh/core/host.js +97 -11
- package/dist/dsh/core/host.js.map +1 -1
- package/dist/dsh/core/index.d.ts +4 -4
- package/dist/dsh/core/index.js +2 -2
- package/dist/dsh/core/index.js.map +1 -1
- package/dist/dsh/core/tasks.d.ts +2 -0
- package/dist/dsh/core/tasks.d.ts.map +1 -1
- package/dist/dsh/core/tasks.js +43 -1
- package/dist/dsh/core/tasks.js.map +1 -1
- package/dist/dsh/core-runtime.d.ts +1 -0
- package/dist/dsh/core-runtime.d.ts.map +1 -1
- package/dist/dsh/core-runtime.js +4 -1
- package/dist/dsh/core-runtime.js.map +1 -1
- package/dist/dsh/decisions/config.d.ts +2 -2
- package/dist/dsh/enno-delegation.js +2 -2
- package/dist/dsh/enno-delegation.js.map +1 -1
- package/dist/dsh/execution-command.d.ts +4 -0
- package/dist/dsh/execution-command.d.ts.map +1 -0
- package/dist/dsh/execution-command.js +52 -0
- package/dist/dsh/execution-command.js.map +1 -0
- package/dist/dsh/execution-journal.d.ts +17 -0
- package/dist/dsh/execution-journal.d.ts.map +1 -0
- package/dist/dsh/execution-journal.js +69 -0
- package/dist/dsh/execution-journal.js.map +1 -0
- package/dist/dsh/execution-result.d.ts +20 -0
- package/dist/dsh/execution-result.d.ts.map +1 -0
- package/dist/dsh/execution-result.js +7 -0
- package/dist/dsh/execution-result.js.map +1 -0
- package/dist/dsh/execution-selection.d.ts +150 -23
- package/dist/dsh/execution-selection.d.ts.map +1 -1
- package/dist/dsh/execution-selection.js +18 -6
- package/dist/dsh/execution-selection.js.map +1 -1
- package/dist/dsh/host-adapter/admission.d.ts.map +1 -1
- package/dist/dsh/host-adapter/admission.js +33 -22
- package/dist/dsh/host-adapter/admission.js.map +1 -1
- package/dist/dsh/host-adapter/boundaries.d.ts.map +1 -1
- package/dist/dsh/host-adapter/boundaries.js +2 -0
- package/dist/dsh/host-adapter/boundaries.js.map +1 -1
- package/dist/dsh/host-adapter/context.d.ts.map +1 -1
- package/dist/dsh/host-adapter/context.js +18 -13
- package/dist/dsh/host-adapter/context.js.map +1 -1
- package/dist/dsh/host-adapter/lifecycle.d.ts.map +1 -1
- package/dist/dsh/host-adapter/lifecycle.js +12 -0
- package/dist/dsh/host-adapter/lifecycle.js.map +1 -1
- package/dist/dsh/host-adapter/routing.js +1 -1
- package/dist/dsh/host-adapter/routing.js.map +1 -1
- package/dist/dsh/host-adapter/turn-state.js +1 -1
- package/dist/dsh/host-adapter/turn-state.js.map +1 -1
- package/dist/dsh/host-adapter.d.ts.map +1 -1
- package/dist/dsh/host-adapter.js +61 -18
- package/dist/dsh/host-adapter.js.map +1 -1
- package/dist/dsh/index.d.ts +4 -2
- package/dist/dsh/index.d.ts.map +1 -1
- package/dist/dsh/index.js +7 -0
- package/dist/dsh/index.js.map +1 -1
- package/dist/dsh/intake-gate.d.ts +1 -0
- package/dist/dsh/intake-gate.d.ts.map +1 -1
- package/dist/dsh/intake-gate.js +9 -1
- package/dist/dsh/intake-gate.js.map +1 -1
- package/dist/dsh/lisp/approval.d.ts +2 -1
- package/dist/dsh/lisp/approval.d.ts.map +1 -1
- package/dist/dsh/lisp/approval.js +4 -3
- package/dist/dsh/lisp/approval.js.map +1 -1
- package/dist/dsh/lisp/candidate.d.ts +1 -1
- package/dist/dsh/lisp/code-intelligence-contracts.d.ts +78 -0
- package/dist/dsh/lisp/code-intelligence-contracts.d.ts.map +1 -0
- package/dist/dsh/lisp/code-intelligence-contracts.js +54 -0
- package/dist/dsh/lisp/code-intelligence-contracts.js.map +1 -0
- package/dist/dsh/lisp/code-intelligence-provider.d.ts +116 -0
- package/dist/dsh/lisp/code-intelligence.d.ts +13 -0
- package/dist/dsh/lisp/code-intelligence.d.ts.map +1 -0
- package/dist/dsh/lisp/code-intelligence.js +181 -0
- package/dist/dsh/lisp/code-intelligence.js.map +1 -0
- package/dist/dsh/lisp/coding-choice.d.ts +4 -1
- package/dist/dsh/lisp/coding-choice.d.ts.map +1 -1
- package/dist/dsh/lisp/coding-choice.js +26 -10
- package/dist/dsh/lisp/coding-choice.js.map +1 -1
- package/dist/dsh/lisp/compiled-cache.d.ts.map +1 -1
- package/dist/dsh/lisp/compiled-cache.js +3 -2
- package/dist/dsh/lisp/compiled-cache.js.map +1 -1
- package/dist/dsh/lisp/contracts.d.ts +4 -0
- package/dist/dsh/lisp/contracts.d.ts.map +1 -1
- package/dist/dsh/lisp/contracts.js +1 -0
- package/dist/dsh/lisp/contracts.js.map +1 -1
- package/dist/dsh/lisp/manager.d.ts +9 -1
- package/dist/dsh/lisp/manager.d.ts.map +1 -1
- package/dist/dsh/lisp/manager.js +91 -24
- package/dist/dsh/lisp/manager.js.map +1 -1
- package/dist/dsh/lisp/model-result.d.ts.map +1 -1
- package/dist/dsh/lisp/model-result.js +35 -1
- package/dist/dsh/lisp/model-result.js.map +1 -1
- package/dist/dsh/lisp/proposal-batch.d.ts +2 -0
- package/dist/dsh/lisp/proposal-batch.d.ts.map +1 -1
- package/dist/dsh/lisp/proposal-batch.js +32 -2
- package/dist/dsh/lisp/proposal-batch.js.map +1 -1
- package/dist/dsh/lisp/request-surface.d.ts +12 -2
- package/dist/dsh/lisp/request-surface.d.ts.map +1 -1
- package/dist/dsh/lisp/request-surface.js +1 -1
- package/dist/dsh/lisp/request-surface.js.map +1 -1
- package/dist/dsh/lisp/sandbox.d.ts +3 -0
- package/dist/dsh/lisp/sandbox.d.ts.map +1 -1
- package/dist/dsh/lisp/sandbox.js +13 -6
- package/dist/dsh/lisp/sandbox.js.map +1 -1
- package/dist/dsh/lisp/surface.d.ts +1 -1
- package/dist/dsh/lisp/surface.d.ts.map +1 -1
- package/dist/dsh/lisp/surface.js +118 -23
- package/dist/dsh/lisp/surface.js.map +1 -1
- package/dist/dsh/lisp/worker.d.ts +2 -0
- package/dist/dsh/lisp/worker.d.ts.map +1 -1
- package/dist/dsh/lisp/worker.js +7 -5
- package/dist/dsh/lisp/worker.js.map +1 -1
- package/dist/dsh/lisp-service-key.d.ts +9 -0
- package/dist/dsh/lisp-service-key.d.ts.map +1 -1
- package/dist/dsh/lisp-service-key.js +11 -0
- package/dist/dsh/lisp-service-key.js.map +1 -1
- package/dist/dsh/memory-application.d.ts +1 -1
- package/dist/dsh/memory-application.d.ts.map +1 -1
- package/dist/dsh/memory-application.js +4 -3
- package/dist/dsh/memory-application.js.map +1 -1
- package/dist/dsh/model-auto/candidates.d.ts.map +1 -1
- package/dist/dsh/model-auto/candidates.js +31 -22
- package/dist/dsh/model-auto/candidates.js.map +1 -1
- package/dist/dsh/model-configuration.d.ts +145 -2
- package/dist/dsh/model-configuration.d.ts.map +1 -1
- package/dist/dsh/model-configuration.js +10 -3
- package/dist/dsh/model-configuration.js.map +1 -1
- package/dist/dsh/model-selection-ui.d.ts.map +1 -1
- package/dist/dsh/model-selection-ui.js +7 -2
- package/dist/dsh/model-selection-ui.js.map +1 -1
- package/dist/dsh/models/config-store.d.ts +8 -0
- package/dist/dsh/models/config-store.d.ts.map +1 -0
- package/dist/dsh/models/config-store.js +49 -0
- package/dist/dsh/models/config-store.js.map +1 -0
- package/dist/dsh/models/contracts.d.ts +107 -0
- package/dist/dsh/models/contracts.d.ts.map +1 -0
- package/dist/dsh/models/contracts.js +104 -0
- package/dist/dsh/models/contracts.js.map +1 -0
- package/dist/dsh/models/metadata.d.ts +7 -0
- package/dist/dsh/models/metadata.d.ts.map +1 -0
- package/dist/dsh/models/metadata.js +13 -0
- package/dist/dsh/models/metadata.js.map +1 -0
- package/dist/dsh/models/profiles.d.ts +10 -0
- package/dist/dsh/models/profiles.d.ts.map +1 -0
- package/dist/dsh/models/profiles.js +176 -0
- package/dist/dsh/models/profiles.js.map +1 -0
- package/dist/dsh/models/service.d.ts +97 -0
- package/dist/dsh/models/service.d.ts.map +1 -0
- package/dist/dsh/models/service.js +518 -0
- package/dist/dsh/models/service.js.map +1 -0
- package/dist/dsh/models/surface.d.ts +8 -0
- package/dist/dsh/models/surface.d.ts.map +1 -0
- package/dist/dsh/models/surface.js +162 -0
- package/dist/dsh/models/surface.js.map +1 -0
- package/dist/dsh/models/vendor/THIRD_PARTY_NOTICES.txt +134 -0
- package/dist/dsh/models/vendor/abortable.d.ts +3 -0
- package/dist/dsh/models/vendor/abortable.d.ts.map +1 -0
- package/dist/dsh/models/vendor/abortable.js +10 -0
- package/dist/dsh/models/vendor/abortable.js.map +1 -0
- package/dist/dsh/models/vendor/auth-contract.d.ts +67 -0
- package/dist/dsh/models/vendor/auth-contract.d.ts.map +1 -0
- package/dist/dsh/models/vendor/auth-contract.js +2 -0
- package/dist/dsh/models/vendor/auth-contract.js.map +1 -0
- package/dist/dsh/models/vendor/credentials.d.ts +58 -0
- package/dist/dsh/models/vendor/credentials.d.ts.map +1 -0
- package/dist/dsh/models/vendor/credentials.js +205 -0
- package/dist/dsh/models/vendor/credentials.js.map +1 -0
- package/dist/dsh/models/vendor/nous-oauth.d.ts +6 -0
- package/dist/dsh/models/vendor/nous-oauth.d.ts.map +1 -0
- package/dist/dsh/models/vendor/nous-oauth.js +113 -0
- package/dist/dsh/models/vendor/nous-oauth.js.map +1 -0
- package/dist/dsh/models/vendor/opencode-adapter.d.ts +38 -0
- package/dist/dsh/models/vendor/opencode-adapter.d.ts.map +1 -0
- package/dist/dsh/models/vendor/opencode-adapter.js +207 -0
- package/dist/dsh/models/vendor/opencode-adapter.js.map +1 -0
- package/dist/dsh/models/vendor/opencode-catalog.d.ts +73 -0
- package/dist/dsh/models/vendor/opencode-catalog.d.ts.map +1 -0
- package/dist/dsh/models/vendor/opencode-catalog.js +253 -0
- package/dist/dsh/models/vendor/opencode-catalog.js.map +1 -0
- package/dist/dsh/models/vendor/opencode-codec.d.ts +7 -0
- package/dist/dsh/models/vendor/opencode-codec.d.ts.map +1 -0
- package/dist/dsh/models/vendor/opencode-codec.js +107 -0
- package/dist/dsh/models/vendor/opencode-codec.js.map +1 -0
- package/dist/dsh/models/vendor/opencode-owned.generated.d.ts +114 -0
- package/dist/dsh/models/vendor/opencode-owned.generated.d.ts.map +1 -0
- package/dist/dsh/models/vendor/opencode-owned.generated.js +2867 -0
- package/dist/dsh/models/vendor/opencode-owned.generated.js.map +1 -0
- package/dist/dsh/models/vendor/opencode-replay.d.ts +17 -0
- package/dist/dsh/models/vendor/opencode-replay.d.ts.map +1 -0
- package/dist/dsh/models/vendor/opencode-replay.js +147 -0
- package/dist/dsh/models/vendor/opencode-replay.js.map +1 -0
- package/dist/dsh/models/vendor/opencode-sdk.d.ts +6 -0
- package/dist/dsh/models/vendor/opencode-sdk.d.ts.map +1 -0
- package/dist/dsh/models/vendor/opencode-sdk.js +49915 -0
- package/dist/dsh/models/vendor/opencode-sdk.js.map +7 -0
- package/dist/dsh/models/vendor/opencode-transport.d.ts +6 -0
- package/dist/dsh/models/vendor/opencode-transport.d.ts.map +1 -0
- package/dist/dsh/models/vendor/opencode-transport.js +70 -0
- package/dist/dsh/models/vendor/opencode-transport.js.map +1 -0
- package/dist/dsh/models/vendor/pi-ai.d.ts +23 -0
- package/dist/dsh/models/vendor/pi-ai.d.ts.map +1 -0
- package/dist/dsh/models/vendor/pi-ai.js +27 -0
- package/dist/dsh/models/vendor/pi-ai.js.map +1 -0
- package/dist/dsh/modules/lisp.d.ts +1 -1
- package/dist/dsh/modules/lisp.d.ts.map +1 -1
- package/dist/dsh/modules/lisp.js +2 -13
- package/dist/dsh/modules/lisp.js.map +1 -1
- package/dist/dsh/modules/resources.d.ts +3 -1
- package/dist/dsh/modules/resources.d.ts.map +1 -1
- package/dist/dsh/modules/resources.js +4 -0
- package/dist/dsh/modules/resources.js.map +1 -1
- package/dist/dsh/native-model-catalog.d.ts.map +1 -1
- package/dist/dsh/native-model-catalog.js +4 -3
- package/dist/dsh/native-model-catalog.js.map +1 -1
- package/dist/dsh/node-tap-summary.d.ts +8 -1
- package/dist/dsh/node-tap-summary.d.ts.map +1 -1
- package/dist/dsh/node-tap-summary.js +33 -3
- package/dist/dsh/node-tap-summary.js.map +1 -1
- package/dist/dsh/on-demand-intake.d.ts +1 -1
- package/dist/dsh/on-demand-intake.d.ts.map +1 -1
- package/dist/dsh/on-demand-intake.js +35 -14
- package/dist/dsh/on-demand-intake.js.map +1 -1
- package/dist/dsh/owned-evidence.d.ts +49 -0
- package/dist/dsh/owned-evidence.d.ts.map +1 -0
- package/dist/dsh/owned-evidence.js +69 -0
- package/dist/dsh/owned-evidence.js.map +1 -0
- package/dist/dsh/owned-execution.d.ts +99 -0
- package/dist/dsh/owned-execution.d.ts.map +1 -0
- package/dist/dsh/owned-execution.js +558 -0
- package/dist/dsh/owned-execution.js.map +1 -0
- package/dist/dsh/plan-transition.d.ts +5 -0
- package/dist/dsh/plan-transition.d.ts.map +1 -0
- package/dist/dsh/plan-transition.js +34 -0
- package/dist/dsh/plan-transition.js.map +1 -0
- package/dist/dsh/session-memory-finalizer.d.ts.map +1 -1
- package/dist/dsh/session-memory-finalizer.js +46 -3
- package/dist/dsh/session-memory-finalizer.js.map +1 -1
- package/dist/dsh/setup.d.ts +1 -1
- package/dist/dsh/setup.d.ts.map +1 -1
- package/dist/dsh/setup.js +2 -0
- package/dist/dsh/setup.js.map +1 -1
- package/dist/dsh/skill-prompts.json +1 -1
- package/dist/dsh/task-completion-host.js +3 -3
- package/dist/dsh/task-completion-host.js.map +1 -1
- package/dist/dsh/task-completion.d.ts +17 -0
- package/dist/dsh/task-completion.d.ts.map +1 -1
- package/dist/dsh/task-completion.js +144 -38
- package/dist/dsh/task-completion.js.map +1 -1
- package/dist/dsh/task-intake.d.ts.map +1 -1
- package/dist/dsh/task-intake.js +7 -0
- package/dist/dsh/task-intake.js.map +1 -1
- package/dist/enno-oduno/coding-workflow.d.ts +39 -0
- package/dist/enno-oduno/coding-workflow.d.ts.map +1 -0
- package/dist/enno-oduno/coding-workflow.js +33 -0
- package/dist/enno-oduno/coding-workflow.js.map +1 -0
- package/dist/enno-oduno/schemas.d.ts +10 -10
- package/dist/enno-oduno/store.d.ts.map +1 -1
- package/dist/enno-oduno/store.js +56 -1
- package/dist/enno-oduno/store.js.map +1 -1
- package/dist/enno-oduno/types.d.ts +1 -0
- package/dist/enno-oduno/types.d.ts.map +1 -1
- package/dist/enno-oduno/verifier.d.ts.map +1 -1
- package/dist/enno-oduno/verifier.js +4 -1
- package/dist/enno-oduno/verifier.js.map +1 -1
- package/dist/locale/en.json +1 -1
- package/dist/locale/ja.json +1 -1
- package/dist/locale/ko.json +1 -1
- package/dist/locale/zh-CN.json +1 -1
- package/dist/memory/application.d.ts +2 -1
- package/dist/memory/application.d.ts.map +1 -1
- package/dist/memory/application.js +26 -12
- package/dist/memory/application.js.map +1 -1
- package/dist/memory/evidence.d.ts +2 -0
- package/dist/memory/evidence.d.ts.map +1 -1
- package/dist/memory/evidence.js +3 -1
- package/dist/memory/evidence.js.map +1 -1
- package/dist/model-tools/contracts.d.ts +4 -4
- package/dist/models-client.cjs +635 -0
- package/dist/models-client.d.ts +26 -0
- package/dist/models-client.d.ts.map +1 -0
- package/dist/models-client.js +642 -0
- package/dist/models-client.js.map +1 -0
- package/docs/code-intelligence.md +149 -0
- package/docs/coding-workflow.md +45 -0
- package/docs/dsh-auth-LICENSE.txt +22 -0
- package/docs/dsh-auth-provenance.md +25 -0
- package/docs/dsh-plugin.md +19 -0
- package/docs/execution-support.md +4 -0
- package/docs/kiokuko-models.md +66 -0
- package/docs/lisp-hot-tools.md +2 -2
- package/docs/lisp.md +112 -63
- package/docs/model-selection.ja.md +7 -9
- package/docs/model-selection.md +14 -12
- package/docs/owned-execution.md +99 -0
- package/lisp/supervisor.mjs +8 -2
- package/lisp/tools.lisp +31 -3
- package/migrations/035_owned_execution.sql +19 -0
- package/migrations/036_coding_workflow.sql +26 -0
- package/package.json +47 -12
- package/skills/coding-ideal-routine-skill/SKILL.md +6 -0
- package/skills/kiokuko-lisp/SKILL.md +53 -67
- package/skills/kiokuko-soul/SKILL.md +7 -28
- package/skills/one-shot-software-completion/SKILL.md +5 -6
package/dist/client.cjs
CHANGED
|
@@ -7,888 +7,1575 @@ window.__ModuleLoader__.load({
|
|
|
7
7
|
const { jsx, jsxs, Fragment } = require("react/jsx-runtime");
|
|
8
8
|
const { useState, useRef, useEffect } = require("react");
|
|
9
9
|
const { Modal, Button, IconDownloadOutline16, MarkdownText } = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
10
|
+
"use strict";
|
|
11
|
+
var __defProp = Object.defineProperty;
|
|
12
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
13
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
14
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
15
|
+
var __export = (target, all) => {
|
|
16
|
+
for (var name in all)
|
|
17
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
18
|
+
};
|
|
19
|
+
var __copyProps = (to, from, except, desc) => {
|
|
20
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
21
|
+
for (let key of __getOwnPropNames(from))
|
|
22
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
23
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
24
|
+
}
|
|
25
|
+
return to;
|
|
26
|
+
};
|
|
27
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
|
+
|
|
29
|
+
// dist/client.js
|
|
30
|
+
var client_exports = {};
|
|
31
|
+
__export(client_exports, {
|
|
32
|
+
apply: () => apply,
|
|
33
|
+
downloadDshSessionLog: () => downloadDshSessionLog,
|
|
34
|
+
inject: () => inject
|
|
35
|
+
});
|
|
36
|
+
module.exports = __toCommonJS(client_exports);
|
|
37
|
+
|
|
38
|
+
// dist/models-client.js
|
|
39
|
+
function messageOf(error) {
|
|
40
|
+
return error instanceof Error ? error.message : String(error);
|
|
41
|
+
}
|
|
42
|
+
var MODELS_NS = "kiokuko-models";
|
|
43
|
+
var MODEL_CONNECTION_DEFAULTS = {
|
|
44
|
+
openai: ["OpenAI API", "https://api.openai.com/v1", "responses"],
|
|
45
|
+
codex: ["Codex", "https://chatgpt.com/backend-api/codex", "responses"],
|
|
46
|
+
claude: ["Claude", "https://api.anthropic.com", "messages"],
|
|
47
|
+
xai: ["xAI", "https://api.x.ai/v1", "chat-completions"],
|
|
48
|
+
deepseek: ["DeepSeek", "https://api.deepseek.com/v1", "chat-completions"],
|
|
49
|
+
opencode: ["OpenCode Zen", "https://opencode.ai/zen/v1", "chat-completions"],
|
|
50
|
+
"opencode-go": [
|
|
51
|
+
"OpenCode Go",
|
|
52
|
+
"https://opencode.ai/zen/go/v1",
|
|
53
|
+
"chat-completions"
|
|
54
|
+
],
|
|
55
|
+
openrouter: [
|
|
56
|
+
"OpenRouter",
|
|
57
|
+
"https://openrouter.ai/api/v1",
|
|
58
|
+
"chat-completions"
|
|
59
|
+
],
|
|
60
|
+
nous: [
|
|
61
|
+
"Nous / Hermes",
|
|
62
|
+
"https://inference-api.nousresearch.com/v1",
|
|
63
|
+
"chat-completions"
|
|
64
|
+
],
|
|
65
|
+
infron: ["Infron", "https://llm.onerouter.pro/v1", "chat-completions"],
|
|
66
|
+
ollama: ["Ollama", "http://localhost:11434/v1", "chat-completions"],
|
|
67
|
+
custom: ["Custom connection", "http://localhost:8080/v1", "chat-completions"]
|
|
68
|
+
};
|
|
69
|
+
async function modelsApi(body, query = "") {
|
|
70
|
+
const response = await fetch("/api/kiokuko.models" + query, {
|
|
71
|
+
...body ? {
|
|
72
|
+
method: "POST",
|
|
73
|
+
headers: { "content-type": "application/json" },
|
|
74
|
+
body: JSON.stringify(body)
|
|
75
|
+
} : {},
|
|
76
|
+
cache: "no-store"
|
|
77
|
+
});
|
|
78
|
+
const value = await response.json();
|
|
79
|
+
if (!response.ok)
|
|
80
|
+
throw new Error(value.error ?? "Kiokuko Models request failed");
|
|
81
|
+
return value;
|
|
82
|
+
}
|
|
83
|
+
function KiokukoModelsPanel(props) {
|
|
84
|
+
const [state, setState] = useState({ revision: 0, connections: [] }), [connection, setConnection] = useState(null), [models, setModels] = useState([]), [filter, setFilter] = useState("");
|
|
85
|
+
const [busy, setBusy] = useState(false), [error, setError] = useState(""), [notice, setNotice] = useState(""), [key, setKey] = useState(""), [auth, setAuth] = useState(null), [answer, setAnswer] = useState("");
|
|
86
|
+
const [manual, setManual] = useState({
|
|
87
|
+
id: "",
|
|
88
|
+
contextWindow: 262144,
|
|
89
|
+
maxTokens: 32768,
|
|
90
|
+
reasoning: false,
|
|
91
|
+
image: false
|
|
92
|
+
});
|
|
93
|
+
const operation = useRef(void 0), mounted = useRef(true), working = useRef(false);
|
|
94
|
+
const sessionId = props.sessionId;
|
|
95
|
+
const load = async () => {
|
|
96
|
+
const value = await modelsApi();
|
|
97
|
+
if (mounted.current)
|
|
98
|
+
setState(value);
|
|
99
|
+
return value;
|
|
100
|
+
};
|
|
101
|
+
useEffect(() => {
|
|
102
|
+
mounted.current = true;
|
|
103
|
+
void load().catch((e) => setError(messageOf(e)));
|
|
104
|
+
return () => {
|
|
105
|
+
mounted.current = false;
|
|
106
|
+
if (operation.current)
|
|
107
|
+
void modelsApi({ op: "cancel", id: operation.current }).catch(() => void 0);
|
|
108
|
+
};
|
|
109
|
+
}, []);
|
|
110
|
+
const run = async (action) => {
|
|
111
|
+
if (working.current)
|
|
112
|
+
return;
|
|
113
|
+
working.current = true;
|
|
114
|
+
setBusy(true);
|
|
115
|
+
setError("");
|
|
116
|
+
setNotice("");
|
|
117
|
+
try {
|
|
118
|
+
await action();
|
|
119
|
+
} catch (e) {
|
|
120
|
+
if (mounted.current)
|
|
121
|
+
setError(messageOf(e));
|
|
122
|
+
} finally {
|
|
123
|
+
working.current = false;
|
|
124
|
+
if (mounted.current)
|
|
125
|
+
setBusy(false);
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
const choose = async (c) => {
|
|
129
|
+
setConnection({ ...c });
|
|
130
|
+
setKey("");
|
|
131
|
+
setError("");
|
|
132
|
+
setModels([]);
|
|
133
|
+
try {
|
|
134
|
+
setModels(await modelsApi(void 0, "?op=models&id=" + encodeURIComponent(c.id)));
|
|
135
|
+
} catch (e) {
|
|
136
|
+
setError(messageOf(e));
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
const save = async () => {
|
|
140
|
+
await modelsApi({
|
|
141
|
+
op: "save",
|
|
142
|
+
connection: {
|
|
143
|
+
id: connection.id,
|
|
144
|
+
kind: connection.kind,
|
|
145
|
+
name: connection.name,
|
|
146
|
+
baseURL: connection.baseURL,
|
|
147
|
+
protocol: connection.protocol,
|
|
148
|
+
serviceTier: connection.serviceTier,
|
|
149
|
+
models: connection.models
|
|
150
|
+
},
|
|
151
|
+
revision: state.revision
|
|
152
|
+
});
|
|
153
|
+
const next = await load();
|
|
154
|
+
await choose(next.connections.find((c) => c.id === connection.id));
|
|
155
|
+
setNotice("Connection saved");
|
|
156
|
+
};
|
|
157
|
+
const newConnection = (kind) => {
|
|
158
|
+
const spec = MODEL_CONNECTION_DEFAULTS[kind];
|
|
159
|
+
setConnection({
|
|
160
|
+
id: "kiokuko-" + kind + "-" + crypto.randomUUID().slice(0, 8),
|
|
161
|
+
kind,
|
|
162
|
+
name: spec[0],
|
|
163
|
+
baseURL: spec[1],
|
|
164
|
+
protocol: spec[2],
|
|
165
|
+
serviceTier: "standard",
|
|
166
|
+
models: []
|
|
167
|
+
});
|
|
168
|
+
setModels([]);
|
|
169
|
+
setKey("");
|
|
170
|
+
setError("");
|
|
171
|
+
};
|
|
172
|
+
const update = (field, value) => setConnection({ ...connection, [field]: value });
|
|
173
|
+
const startLogin = async () => {
|
|
174
|
+
await save();
|
|
175
|
+
const result = await modelsApi({ op: "login", id: connection.id });
|
|
176
|
+
operation.current = result.operationId;
|
|
177
|
+
setAuth({ id: result.operationId, status: "pending", events: [] });
|
|
178
|
+
};
|
|
179
|
+
useEffect(() => {
|
|
180
|
+
if (!auth || auth.status !== "pending")
|
|
181
|
+
return;
|
|
182
|
+
let stopped = false;
|
|
183
|
+
const timer = setInterval(() => {
|
|
184
|
+
void modelsApi(void 0, "?op=auth&id=" + encodeURIComponent(auth.id)).then((next) => {
|
|
185
|
+
if (stopped)
|
|
186
|
+
return;
|
|
187
|
+
setAuth(next);
|
|
188
|
+
if (next.status !== "pending") {
|
|
189
|
+
operation.current = void 0;
|
|
190
|
+
void load().then((value) => {
|
|
191
|
+
if (next.status === "success")
|
|
192
|
+
return choose(value.connections.find((c) => c.id === connection.id));
|
|
193
|
+
setError(next.error ?? "Authentication cancelled");
|
|
194
|
+
}).catch((e) => setError(messageOf(e)));
|
|
34
195
|
}
|
|
196
|
+
}, (e) => {
|
|
197
|
+
if (!stopped)
|
|
198
|
+
setError(messageOf(e));
|
|
199
|
+
});
|
|
200
|
+
}, 500);
|
|
201
|
+
return () => {
|
|
202
|
+
stopped = true;
|
|
203
|
+
clearInterval(timer);
|
|
204
|
+
};
|
|
205
|
+
}, [auth?.id, auth?.status]);
|
|
206
|
+
const input = (label, value, onChange, type = "text") => jsx("label", {
|
|
207
|
+
children: jsxs(Fragment, {
|
|
208
|
+
children: [
|
|
209
|
+
jsx("span", { children: label }),
|
|
210
|
+
jsx("input", {
|
|
211
|
+
type,
|
|
212
|
+
value,
|
|
213
|
+
"aria-label": label,
|
|
214
|
+
disabled: busy || label === "Base URL" && ["codex", "opencode", "opencode-go"].includes(connection?.kind),
|
|
215
|
+
onChange: (e) => onChange(e.target.value),
|
|
216
|
+
autoComplete: type === "password" ? "new-password" : "off"
|
|
217
|
+
})
|
|
218
|
+
]
|
|
219
|
+
})
|
|
220
|
+
});
|
|
221
|
+
const button = (label, action, disabled = false) => jsx("button", {
|
|
222
|
+
type: "button",
|
|
223
|
+
disabled: busy || disabled,
|
|
224
|
+
onClick: action,
|
|
225
|
+
children: label
|
|
226
|
+
});
|
|
227
|
+
return jsxs("section", {
|
|
228
|
+
className: "kiokuko-models-panel",
|
|
229
|
+
"aria-label": "Kiokuko Models",
|
|
230
|
+
"aria-busy": busy,
|
|
231
|
+
children: [
|
|
232
|
+
jsx("h2", { children: "Kiokuko Models" }),
|
|
233
|
+
jsx("p", {
|
|
234
|
+
children: "Connect directly for chat, Enno and Deep. Credentials are shared with dsh-cli. Signing out also signs dsh-cli out."
|
|
235
|
+
}),
|
|
236
|
+
...error ? [jsx("p", { role: "alert", children: error })] : [],
|
|
237
|
+
...notice ? [jsx("p", { role: "status", children: notice })] : [],
|
|
238
|
+
...busy ? [jsx("p", { role: "status", children: "Working\u2026" })] : [],
|
|
239
|
+
button("Reload", () => void run(load)),
|
|
240
|
+
jsx("label", {
|
|
241
|
+
children: jsxs(Fragment, {
|
|
242
|
+
children: [
|
|
243
|
+
"Add connection",
|
|
244
|
+
jsxs("select", {
|
|
245
|
+
"aria-label": "Add connection",
|
|
246
|
+
value: "",
|
|
247
|
+
disabled: busy,
|
|
248
|
+
onChange: (e) => newConnection(e.target.value),
|
|
249
|
+
children: [
|
|
250
|
+
jsx("option", { value: "", children: "Choose provider\u2026" }),
|
|
251
|
+
...Object.entries(MODEL_CONNECTION_DEFAULTS).map(([id, spec]) => jsx("option", { value: id, children: spec[0] }, id))
|
|
252
|
+
]
|
|
253
|
+
})
|
|
254
|
+
]
|
|
255
|
+
})
|
|
256
|
+
}),
|
|
257
|
+
jsx("ul", {
|
|
258
|
+
children: state.connections.map((c) => jsx("li", {
|
|
259
|
+
children: button(c.name + " \xB7 " + c.authState, () => void choose(c))
|
|
260
|
+
}, c.id))
|
|
261
|
+
}),
|
|
262
|
+
...connection ? [
|
|
263
|
+
jsxs("div", {
|
|
264
|
+
className: "kiokuko-models-editor",
|
|
265
|
+
children: [
|
|
266
|
+
input("Connection name", connection.name, (value) => update("name", value)),
|
|
267
|
+
input("Base URL", connection.baseURL, (value) => update("baseURL", value)),
|
|
268
|
+
jsx("label", {
|
|
269
|
+
children: jsxs(Fragment, {
|
|
270
|
+
children: [
|
|
271
|
+
"Protocol",
|
|
272
|
+
jsx("select", {
|
|
273
|
+
"aria-label": "Protocol",
|
|
274
|
+
value: connection.protocol,
|
|
275
|
+
disabled: busy || [
|
|
276
|
+
"codex",
|
|
277
|
+
"infron",
|
|
278
|
+
"opencode",
|
|
279
|
+
"opencode-go"
|
|
280
|
+
].includes(connection.kind),
|
|
281
|
+
onChange: (e) => update("protocol", e.target.value),
|
|
282
|
+
children: [
|
|
283
|
+
["chat-completions", "Chat Completions"],
|
|
284
|
+
["responses", "Responses"],
|
|
285
|
+
["messages", "Messages"]
|
|
286
|
+
].map(([id, name]) => jsx("option", { value: id, children: name }, id))
|
|
287
|
+
})
|
|
288
|
+
]
|
|
289
|
+
})
|
|
290
|
+
}),
|
|
291
|
+
...connection.kind === "infron" ? [
|
|
292
|
+
jsx("label", {
|
|
293
|
+
children: jsxs(Fragment, {
|
|
294
|
+
children: [
|
|
295
|
+
"Service tier",
|
|
296
|
+
jsx("select", {
|
|
297
|
+
"aria-label": "Service tier",
|
|
298
|
+
value: connection.serviceTier,
|
|
299
|
+
disabled: busy,
|
|
300
|
+
onChange: (e) => update("serviceTier", e.target.value),
|
|
301
|
+
children: [
|
|
302
|
+
jsx("option", {
|
|
303
|
+
value: "standard",
|
|
304
|
+
children: "Standard"
|
|
305
|
+
}),
|
|
306
|
+
jsx("option", {
|
|
307
|
+
value: "flex",
|
|
308
|
+
children: "Flex"
|
|
309
|
+
})
|
|
310
|
+
]
|
|
311
|
+
})
|
|
312
|
+
]
|
|
313
|
+
})
|
|
314
|
+
}),
|
|
315
|
+
jsx("p", {
|
|
316
|
+
children: "Requested tier: " + connection.serviceTier + ". Last request: " + (connection.lastRequestedTier ?? "none") + ". Actual served tier: " + (connection.actualTier ?? "unknown") + ". Infron may serve Standard for a Flex request."
|
|
317
|
+
})
|
|
318
|
+
] : [],
|
|
319
|
+
button("Save connection", () => void run(save)),
|
|
320
|
+
...connection.kind !== "codex" && connection.kind !== "ollama" ? [
|
|
321
|
+
input("API key / bearer token", key, setKey, "password"),
|
|
322
|
+
button("Save key", () => void run(async () => {
|
|
323
|
+
await save();
|
|
324
|
+
await modelsApi({
|
|
325
|
+
op: "key",
|
|
326
|
+
id: connection.id,
|
|
327
|
+
key
|
|
328
|
+
});
|
|
329
|
+
setKey("");
|
|
330
|
+
await load();
|
|
331
|
+
await choose(connection);
|
|
332
|
+
setNotice("Key saved");
|
|
333
|
+
}), !key)
|
|
334
|
+
] : [],
|
|
335
|
+
...[
|
|
336
|
+
"codex",
|
|
337
|
+
"claude",
|
|
338
|
+
"xai",
|
|
339
|
+
"openai",
|
|
340
|
+
"openrouter",
|
|
341
|
+
"nous"
|
|
342
|
+
].includes(connection.kind) ? [
|
|
343
|
+
button("Log in", () => void run(startLogin), auth?.status === "pending")
|
|
344
|
+
] : [],
|
|
345
|
+
button("Log out (also dsh-cli)", () => void run(async () => {
|
|
346
|
+
await modelsApi({ op: "logout", id: connection.id });
|
|
347
|
+
setKey("");
|
|
348
|
+
setModels([]);
|
|
349
|
+
await load();
|
|
350
|
+
setNotice("Signed out");
|
|
351
|
+
})),
|
|
352
|
+
button("Refresh models", () => void run(async () => {
|
|
353
|
+
await modelsApi({ op: "refresh", id: connection.id });
|
|
354
|
+
const next = await load();
|
|
355
|
+
await choose(next.connections.find((c) => c.id === connection.id));
|
|
356
|
+
setNotice("Models refreshed");
|
|
357
|
+
})),
|
|
358
|
+
...auth?.status === "pending" ? [
|
|
359
|
+
jsxs("div", {
|
|
360
|
+
"aria-label": "Authentication",
|
|
361
|
+
children: [
|
|
362
|
+
jsx("p", {
|
|
363
|
+
role: "status",
|
|
364
|
+
children: "Waiting for authentication"
|
|
365
|
+
}),
|
|
366
|
+
...auth.events.map((event, index) => jsx("div", {
|
|
367
|
+
children: event.type === "auth_url" ? jsxs(Fragment, {
|
|
368
|
+
children: [
|
|
369
|
+
jsx("a", {
|
|
370
|
+
href: event.url,
|
|
371
|
+
target: "_blank",
|
|
372
|
+
rel: "noopener noreferrer",
|
|
373
|
+
children: "Open authentication link"
|
|
374
|
+
}),
|
|
375
|
+
jsx("p", {
|
|
376
|
+
children: event.instructions
|
|
377
|
+
})
|
|
378
|
+
]
|
|
379
|
+
}) : event.type === "device_code" ? jsxs(Fragment, {
|
|
380
|
+
children: [
|
|
381
|
+
jsx("a", {
|
|
382
|
+
href: event.verificationUri,
|
|
383
|
+
target: "_blank",
|
|
384
|
+
rel: "noopener noreferrer",
|
|
385
|
+
children: "Open sign-in page"
|
|
386
|
+
}),
|
|
387
|
+
jsx("p", {
|
|
388
|
+
children: "Code: " + event.userCode
|
|
389
|
+
})
|
|
390
|
+
]
|
|
391
|
+
}) : jsxs(Fragment, {
|
|
392
|
+
children: [
|
|
393
|
+
jsx("p", {
|
|
394
|
+
children: event.message
|
|
395
|
+
}),
|
|
396
|
+
...(event.links ?? []).map((link) => jsx("a", {
|
|
397
|
+
href: link.url,
|
|
398
|
+
target: "_blank",
|
|
399
|
+
rel: "noopener noreferrer",
|
|
400
|
+
children: link.label ?? "Open link"
|
|
401
|
+
}, link.url))
|
|
402
|
+
]
|
|
403
|
+
})
|
|
404
|
+
}, index)),
|
|
405
|
+
...auth.prompt ? [
|
|
406
|
+
auth.prompt.type === "select" ? jsx("label", {
|
|
407
|
+
children: jsxs(Fragment, {
|
|
408
|
+
children: [
|
|
409
|
+
auth.prompt.message,
|
|
410
|
+
jsxs("select", {
|
|
411
|
+
"aria-label": auth.prompt.message,
|
|
412
|
+
value: answer,
|
|
413
|
+
onChange: (e) => setAnswer(e.target.value),
|
|
414
|
+
children: [
|
|
415
|
+
jsx("option", {
|
|
416
|
+
value: "",
|
|
417
|
+
children: "Choose\u2026"
|
|
418
|
+
}),
|
|
419
|
+
...auth.prompt.options.map((option) => jsx("option", {
|
|
420
|
+
value: option.id,
|
|
421
|
+
children: option.label
|
|
422
|
+
}, option.id))
|
|
423
|
+
]
|
|
424
|
+
})
|
|
425
|
+
]
|
|
426
|
+
})
|
|
427
|
+
}) : input(auth.prompt.message, answer, setAnswer, auth.prompt.type === "secret" ? "password" : "text"),
|
|
428
|
+
button("Submit authentication answer", () => void run(async () => {
|
|
429
|
+
await modelsApi({
|
|
430
|
+
op: "answer",
|
|
431
|
+
id: auth.id,
|
|
432
|
+
answer
|
|
433
|
+
});
|
|
434
|
+
setAnswer("");
|
|
435
|
+
}))
|
|
436
|
+
] : [],
|
|
437
|
+
button("Cancel authentication", () => void run(async () => {
|
|
438
|
+
await modelsApi({ op: "cancel", id: auth.id });
|
|
439
|
+
operation.current = void 0;
|
|
440
|
+
setAuth(null);
|
|
441
|
+
setNotice("Authentication cancelled");
|
|
442
|
+
}))
|
|
443
|
+
]
|
|
444
|
+
})
|
|
445
|
+
] : [],
|
|
446
|
+
...!["opencode", "opencode-go"].includes(connection.kind) ? [
|
|
447
|
+
jsx("details", {
|
|
448
|
+
children: jsxs(Fragment, {
|
|
449
|
+
children: [
|
|
450
|
+
jsx("summary", {
|
|
451
|
+
children: "Register model manually"
|
|
452
|
+
}),
|
|
453
|
+
input("Model ID", manual.id, (value) => setManual({ ...manual, id: value })),
|
|
454
|
+
input("Context window", manual.contextWindow, (value) => setManual({
|
|
455
|
+
...manual,
|
|
456
|
+
contextWindow: Number(value)
|
|
457
|
+
}), "number"),
|
|
458
|
+
input("Maximum output tokens", manual.maxTokens, (value) => setManual({
|
|
459
|
+
...manual,
|
|
460
|
+
maxTokens: Number(value)
|
|
461
|
+
}), "number"),
|
|
462
|
+
jsx("label", {
|
|
463
|
+
children: jsxs(Fragment, {
|
|
464
|
+
children: [
|
|
465
|
+
jsx("input", {
|
|
466
|
+
type: "checkbox",
|
|
467
|
+
checked: manual.reasoning,
|
|
468
|
+
onChange: (e) => setManual({
|
|
469
|
+
...manual,
|
|
470
|
+
reasoning: e.target.checked
|
|
471
|
+
})
|
|
472
|
+
}),
|
|
473
|
+
"Reasoning supported"
|
|
474
|
+
]
|
|
475
|
+
})
|
|
476
|
+
}),
|
|
477
|
+
jsx("label", {
|
|
478
|
+
children: jsxs(Fragment, {
|
|
479
|
+
children: [
|
|
480
|
+
jsx("input", {
|
|
481
|
+
type: "checkbox",
|
|
482
|
+
checked: manual.image,
|
|
483
|
+
onChange: (e) => setManual({
|
|
484
|
+
...manual,
|
|
485
|
+
image: e.target.checked
|
|
486
|
+
})
|
|
487
|
+
}),
|
|
488
|
+
"Image input supported"
|
|
489
|
+
]
|
|
490
|
+
})
|
|
491
|
+
}),
|
|
492
|
+
button("Add manual model", () => {
|
|
493
|
+
update("models", [
|
|
494
|
+
...connection.models.filter((m) => m.id !== manual.id),
|
|
495
|
+
{ ...manual, name: manual.id }
|
|
496
|
+
]);
|
|
497
|
+
setNotice("Model added to draft. Save connection to register it.");
|
|
498
|
+
}, !manual.id)
|
|
499
|
+
]
|
|
500
|
+
})
|
|
501
|
+
})
|
|
502
|
+
] : [],
|
|
503
|
+
input("Search models", filter, setFilter),
|
|
504
|
+
jsx("ul", {
|
|
505
|
+
children: models.filter((m) => (m.id + " " + m.name).toLowerCase().includes(filter.toLowerCase())).map((m) => jsx("li", {
|
|
506
|
+
children: jsxs(Fragment, {
|
|
507
|
+
children: [
|
|
508
|
+
jsx("span", { children: m.name + " \xB7 " + m.id }),
|
|
509
|
+
button("Use in current chat", () => void run(async () => {
|
|
510
|
+
await modelsApi({
|
|
511
|
+
op: "select",
|
|
512
|
+
id: connection.id,
|
|
513
|
+
model: m.id,
|
|
514
|
+
scope: "current",
|
|
515
|
+
sessionId
|
|
516
|
+
});
|
|
517
|
+
setNotice("Model selected for this chat");
|
|
518
|
+
}), !sessionId),
|
|
519
|
+
button("Default for new chats", () => void run(async () => {
|
|
520
|
+
await modelsApi({
|
|
521
|
+
op: "select",
|
|
522
|
+
id: connection.id,
|
|
523
|
+
model: m.id,
|
|
524
|
+
scope: "default"
|
|
525
|
+
});
|
|
526
|
+
setNotice("Default model saved for new chats");
|
|
527
|
+
}))
|
|
528
|
+
]
|
|
529
|
+
})
|
|
530
|
+
}, m.id))
|
|
531
|
+
})
|
|
532
|
+
]
|
|
533
|
+
})
|
|
534
|
+
] : []
|
|
535
|
+
]
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
function KiokukoModelsDialog(props) {
|
|
539
|
+
const useModels = props.useKiokukoModels;
|
|
540
|
+
const state = useModels((s) => s), close = props.closeModels;
|
|
541
|
+
return jsx(Modal, {
|
|
542
|
+
open: state.open,
|
|
543
|
+
className: "kiokuko-models-modal",
|
|
544
|
+
title: "Kiokuko Models",
|
|
545
|
+
closeLabel: "Close",
|
|
546
|
+
onClose: close,
|
|
547
|
+
children: state.open ? jsx(KiokukoModelsPanel, { sessionId: state.sessionId }) : null
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
function KiokukoModelsAnchor(props) {
|
|
551
|
+
const active = props.activeModelsSession;
|
|
552
|
+
useEffect(() => {
|
|
553
|
+
active.current = props.sessionId;
|
|
554
|
+
return () => {
|
|
555
|
+
if (active.current === props.sessionId)
|
|
556
|
+
active.current = void 0;
|
|
35
557
|
};
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
'Lisp approvals · Entire profile ',
|
|
39
|
-
jsxs('select', { 'aria-label': 'Lisp approvals', value: mode ?? 'ask', disabled: busy || !field || state.status !== 'ready' || !state.writable,
|
|
40
|
-
onChange: (event) => void update(event.target.value),
|
|
41
|
-
children: [jsx('option', { value: 'ask', children: 'Ask' }), jsx('option', { value: 'auto', children: 'Auto-approve all' })] }),
|
|
42
|
-
] }) }),
|
|
43
|
-
...(state.status === 'ready' && state.writable ? [] : [jsx('span', { children: ' Profile settings are unavailable or read-only.' })]),
|
|
44
|
-
...(error ? [jsx('span', { role: 'alert', children: error })] : []),
|
|
45
|
-
...(busy ? [jsx('span', { role: 'status', children: 'Saving…' })] : []),
|
|
46
|
-
] });
|
|
558
|
+
}, [props.sessionId]);
|
|
559
|
+
return null;
|
|
47
560
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
561
|
+
function mountModelsClient(ctx) {
|
|
562
|
+
const store = createSnapshotStore({
|
|
563
|
+
open: false
|
|
564
|
+
}), active = { current: void 0 };
|
|
565
|
+
let focusFrame;
|
|
566
|
+
const close = () => {
|
|
567
|
+
store.update((s) => {
|
|
568
|
+
s.open = false;
|
|
569
|
+
});
|
|
570
|
+
if (focusFrame !== void 0)
|
|
571
|
+
cancelAnimationFrame(focusFrame);
|
|
572
|
+
focusFrame = requestAnimationFrame(() => {
|
|
573
|
+
focusFrame = void 0;
|
|
574
|
+
const sessionId = active.current;
|
|
575
|
+
if (!sessionId)
|
|
576
|
+
return;
|
|
577
|
+
const sessions = ctx.get?.("sessions", false);
|
|
578
|
+
const scope = sessions?.scope(sessionId);
|
|
579
|
+
if (!scope)
|
|
580
|
+
return;
|
|
581
|
+
const conversation = scope.get("conversation", false);
|
|
582
|
+
conversation?.input.for(scope).focus();
|
|
583
|
+
});
|
|
584
|
+
};
|
|
585
|
+
ctx.effect(() => () => {
|
|
586
|
+
if (focusFrame !== void 0)
|
|
587
|
+
cancelAnimationFrame(focusFrame);
|
|
588
|
+
}, "kiokuko models focus lifecycle");
|
|
589
|
+
ctx.effect(() => {
|
|
590
|
+
const style = document.createElement("style");
|
|
591
|
+
style.textContent = ".kiokuko-models-modal{width:min(900px,calc(100vw - 32px))}.kiokuko-models-panel{box-sizing:border-box;width:100%;max-width:900px;padding:16px;overflow:auto;max-height:75vh}.kiokuko-models-panel label{display:flex;gap:10px;align-items:center;flex-wrap:wrap;margin:12px 0}.kiokuko-models-panel input,.kiokuko-models-panel select{max-width:100%;box-sizing:border-box;border:1px solid #888;border-radius:6px;padding:8px;color:inherit;background:transparent}.kiokuko-models-panel button{border:1px solid #888;border-radius:6px;padding:8px;margin:4px;color:inherit}.kiokuko-models-panel button:disabled{opacity:.5}.kiokuko-models-panel li{margin:8px 0}.kiokuko-models-panel :focus-visible{outline:2px solid #3286ff;outline-offset:3px}";
|
|
592
|
+
document.head.append(style);
|
|
593
|
+
return () => style.remove();
|
|
594
|
+
}, "kiokuko models style");
|
|
595
|
+
ctx.slots.inject("settings.section", () => ctx.slots.register({
|
|
596
|
+
name: "settings.section",
|
|
597
|
+
id: MODELS_NS,
|
|
598
|
+
order: 1e3,
|
|
599
|
+
label: "Kiokuko Models",
|
|
600
|
+
locale: MODELS_NS
|
|
601
|
+
}, () => jsx(KiokukoModelsPanel, { sessionId: active.current })));
|
|
602
|
+
ctx.slots.inject("conversation.input.left", () => ctx.slots.register({
|
|
603
|
+
name: "conversation.input.left",
|
|
604
|
+
id: "kiokuko-models-dialog",
|
|
605
|
+
locale: MODELS_NS,
|
|
606
|
+
inject: () => ({
|
|
607
|
+
hooks: { kiokukoModels: store },
|
|
608
|
+
closeModels: close,
|
|
609
|
+
activeModelsSession: active
|
|
610
|
+
})
|
|
611
|
+
}, KiokukoModelsAnchor));
|
|
612
|
+
ctx.slots.inject("shell.overlay", () => ctx.slots.register({
|
|
613
|
+
name: "shell.overlay",
|
|
614
|
+
id: "kiokuko-models-overlay",
|
|
615
|
+
locale: MODELS_NS,
|
|
616
|
+
inject: () => ({ hooks: { kiokukoModels: store }, closeModels: close })
|
|
617
|
+
}, KiokukoModelsDialog));
|
|
618
|
+
ctx.on("command/executed", (sessionId, name, result) => {
|
|
619
|
+
if (name === "kiokuko" && result.kind === "success")
|
|
620
|
+
store.update((s) => {
|
|
621
|
+
s.open = true;
|
|
622
|
+
s.sessionId = sessionId;
|
|
623
|
+
});
|
|
624
|
+
});
|
|
625
|
+
ctx.effect(() => ctx.locale.register(MODELS_NS, {
|
|
626
|
+
en: { "meta.title": "Kiokuko Models" },
|
|
627
|
+
ja: { "meta.title": "Kiokuko Models" }
|
|
628
|
+
}), "kiokuko models labels");
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
// dist/client.js
|
|
632
|
+
function LispApprovalControl(props) {
|
|
633
|
+
const scope = props.approvalScope;
|
|
634
|
+
const [state, setState] = useState(() => scope.getSnapshot());
|
|
635
|
+
const [busy, setBusy] = useState(false);
|
|
636
|
+
const [error, setError] = useState("");
|
|
637
|
+
useEffect(() => scope.subscribe(() => setState(scope.getSnapshot())), [scope]);
|
|
638
|
+
const modern = props.modern === true;
|
|
639
|
+
const field = modern ? "lisp" : Object.keys(state.base ?? {}).find((key) => key === "approvalMode" || key.startsWith("approvalMode-"));
|
|
640
|
+
const mode = modern ? state.value?.lisp?.approvalMode : field ? state.value?.[field] : void 0;
|
|
641
|
+
const update = async (mode2) => {
|
|
642
|
+
if (busy || !field)
|
|
643
|
+
return;
|
|
644
|
+
setBusy(true);
|
|
645
|
+
setError("");
|
|
646
|
+
try {
|
|
647
|
+
const saved = modern ? await scope.mutate([{ op: "set", path: ["lisp", "approvalMode"], value: mode2 }]) : await scope.set(field, mode2);
|
|
648
|
+
if (saved === false)
|
|
649
|
+
throw new Error("The host did not save the approval setting. Reload the current value and try again.");
|
|
650
|
+
} catch (error2) {
|
|
651
|
+
setError(messageOf2(error2));
|
|
652
|
+
} finally {
|
|
653
|
+
setBusy(false);
|
|
654
|
+
}
|
|
655
|
+
};
|
|
656
|
+
return jsxs("div", { children: [
|
|
657
|
+
jsx("label", { children: jsxs(Fragment, { children: [
|
|
658
|
+
"Lisp approvals \xB7 Entire profile ",
|
|
659
|
+
jsxs("select", {
|
|
660
|
+
"aria-label": "Lisp approvals",
|
|
661
|
+
value: mode ?? "ask",
|
|
662
|
+
disabled: busy || !field || state.status !== "ready" || !state.writable,
|
|
663
|
+
onChange: (event) => void update(event.target.value),
|
|
664
|
+
children: [jsx("option", { value: "ask", children: "Ask" }), jsx("option", { value: "auto", children: "Auto-approve all" })]
|
|
665
|
+
})
|
|
666
|
+
] }) }),
|
|
667
|
+
...state.status === "ready" && state.writable ? [] : [jsx("span", { children: " Profile settings are unavailable or read-only." })],
|
|
668
|
+
...error ? [jsx("span", { role: "alert", children: error })] : [],
|
|
669
|
+
...busy ? [jsx("span", { role: "status", children: "Saving\u2026" })] : []
|
|
670
|
+
] });
|
|
671
|
+
}
|
|
672
|
+
var SESSION_EXPORT_PATH = "/api/session.export";
|
|
673
|
+
var LOCALE_NAMESPACE = "kiokuko-session-log-download";
|
|
674
|
+
var INITIAL_DOWNLOAD_STATE = { bySession: {} };
|
|
675
|
+
var en = {
|
|
676
|
+
"header.action": "Session log",
|
|
677
|
+
"dialog.preparingTitle": "Exporting Session",
|
|
678
|
+
"dialog.preparingDescription": "Streaming this Session, its sub-Sessions, and attachments to a ZIP file.",
|
|
679
|
+
"dialog.successTitle": "Session export complete",
|
|
680
|
+
"dialog.successDescription": "The Session ZIP has been saved or handed to the browser download manager.",
|
|
681
|
+
"dialog.errorTitle": "Session export failed",
|
|
682
|
+
"dialog.close": "Close",
|
|
683
|
+
"dialog.commandFailed": "Could not export the Session log.",
|
|
684
|
+
"review.discuss": "Chat about it",
|
|
685
|
+
"review.copy": "Copy",
|
|
686
|
+
"review.copied": "Copied",
|
|
687
|
+
"review.footnotes": "Footnotes",
|
|
688
|
+
"review.title": "Diff review",
|
|
689
|
+
"review.description": "Review changes with repository facts and Kiokuko context."
|
|
66
690
|
};
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
691
|
+
var ja = {
|
|
692
|
+
"header.action": "Session log",
|
|
693
|
+
"dialog.preparingTitle": "Session\u3092\u30A8\u30AF\u30B9\u30DD\u30FC\u30C8\u4E2D",
|
|
694
|
+
"dialog.preparingDescription": "\u3053\u306ESession\u3001\u5B50Session\u3001\u6DFB\u4ED8\u30D5\u30A1\u30A4\u30EB\u3092ZIP\u3078\u30B9\u30C8\u30EA\u30FC\u30DF\u30F3\u30B0\u3057\u3066\u3044\u307E\u3059\u3002",
|
|
695
|
+
"dialog.successTitle": "Session\u306E\u30A8\u30AF\u30B9\u30DD\u30FC\u30C8\u5B8C\u4E86",
|
|
696
|
+
"dialog.successDescription": "Session ZIP\u3092\u4FDD\u5B58\u3001\u307E\u305F\u306F\u30D6\u30E9\u30A6\u30B6\u306E\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9\u51E6\u7406\u3078\u6E21\u3057\u307E\u3057\u305F\u3002",
|
|
697
|
+
"dialog.errorTitle": "Session\u306E\u30A8\u30AF\u30B9\u30DD\u30FC\u30C8\u306B\u5931\u6557",
|
|
698
|
+
"dialog.close": "\u9589\u3058\u308B",
|
|
699
|
+
"dialog.commandFailed": "Session log\u3092\u30A8\u30AF\u30B9\u30DD\u30FC\u30C8\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002",
|
|
700
|
+
"review.discuss": "\u76F8\u8AC7\u306B\u623B\u308B",
|
|
701
|
+
"review.copy": "\u30B3\u30D4\u30FC",
|
|
702
|
+
"review.copied": "\u30B3\u30D4\u30FC\u3057\u307E\u3057\u305F",
|
|
703
|
+
"review.footnotes": "\u811A\u6CE8",
|
|
704
|
+
"review.title": "Diff \u30EC\u30D3\u30E5\u30FC",
|
|
705
|
+
"review.description": "\u5DEE\u5206\u3092\u30EA\u30DD\u30B8\u30C8\u30EA\u306E\u4E8B\u5B9F\u3068 Kiokuko \u306E\u6587\u8108\u3067\u78BA\u8A8D\u3057\u307E\u3059\u3002"
|
|
82
706
|
};
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
707
|
+
var zh = {
|
|
708
|
+
"header.action": "Session \u65E5\u5FD7",
|
|
709
|
+
"dialog.preparingTitle": "\u6B63\u5728\u5BFC\u51FA Session",
|
|
710
|
+
"dialog.preparingDescription": "\u6B63\u5728\u5C06\u5F53\u524D Session\u3001\u5B50 Session \u548C\u9644\u4EF6\u6D41\u5F0F\u5199\u5165 ZIP \u6587\u4EF6\u3002",
|
|
711
|
+
"dialog.successTitle": "Session \u5BFC\u51FA\u5B8C\u6210",
|
|
712
|
+
"dialog.successDescription": "Session ZIP \u5DF2\u4FDD\u5B58\u6216\u4EA4\u7ED9\u6D4F\u89C8\u5668\u4E0B\u8F7D\u7BA1\u7406\u5668\u3002",
|
|
713
|
+
"dialog.errorTitle": "Session \u5BFC\u51FA\u5931\u8D25",
|
|
714
|
+
"dialog.close": "\u5173\u95ED",
|
|
715
|
+
"dialog.commandFailed": "\u65E0\u6CD5\u5BFC\u51FA Session \u65E5\u5FD7\u3002",
|
|
716
|
+
"review.discuss": "\u7EE7\u7EED\u8BA8\u8BBA",
|
|
717
|
+
"review.copy": "\u590D\u5236",
|
|
718
|
+
"review.copied": "\u5DF2\u590D\u5236",
|
|
719
|
+
"review.footnotes": "\u811A\u6CE8",
|
|
720
|
+
"review.title": "Diff \u5BA1\u67E5",
|
|
721
|
+
"review.description": "\u7ED3\u5408\u4ED3\u5E93\u4E8B\u5B9E\u548C Kiokuko \u4E0A\u4E0B\u6587\u67E5\u770B\u66F4\u6539\u3002"
|
|
98
722
|
};
|
|
99
723
|
function hostBase() {
|
|
100
|
-
|
|
101
|
-
|
|
724
|
+
const origin = globalThis.location?.origin;
|
|
725
|
+
return origin !== void 0 && origin !== "null" ? origin : "http://dsh.internal";
|
|
102
726
|
}
|
|
103
|
-
function
|
|
104
|
-
|
|
727
|
+
function messageOf2(error) {
|
|
728
|
+
return error instanceof Error ? error.message : String(error);
|
|
105
729
|
}
|
|
106
730
|
function isAbortError(error) {
|
|
107
|
-
|
|
731
|
+
return typeof DOMException !== "undefined" && error instanceof DOMException && error.name === "AbortError";
|
|
108
732
|
}
|
|
109
733
|
function sessionLogZipFilename(sessionId) {
|
|
110
|
-
|
|
734
|
+
return `dsh-session-${String(sessionId).replace(/[^A-Za-z0-9_-]/gu, "_")}.zip`;
|
|
111
735
|
}
|
|
112
736
|
async function responseFailure(response) {
|
|
113
|
-
|
|
114
|
-
|
|
737
|
+
const detail = await response.text().catch(() => "");
|
|
738
|
+
return new Error(`Session export failed: HTTP ${response.status}${detail === "" ? "" : ` ${detail}`}`);
|
|
115
739
|
}
|
|
116
|
-
/** Browser helper that never builds a whole-log Blob in application memory. */
|
|
117
740
|
async function downloadDshSessionLog(options) {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
741
|
+
const url = new URL(options.endpoint);
|
|
742
|
+
url.searchParams.set("sessionId", options.sessionId);
|
|
743
|
+
url.searchParams.set("includeDescendants", "true");
|
|
744
|
+
const browser = options.window ?? globalThis.window;
|
|
745
|
+
if (browser?.showSaveFilePicker === void 0) {
|
|
746
|
+
if (browser === void 0)
|
|
747
|
+
throw new Error("browser download surface is unavailable");
|
|
748
|
+
url.searchParams.set("download", "1");
|
|
749
|
+
browser.location.assign(url.toString());
|
|
750
|
+
return "navigated";
|
|
751
|
+
}
|
|
752
|
+
const handle = await browser.showSaveFilePicker({
|
|
753
|
+
suggestedName: sessionLogZipFilename(options.sessionId),
|
|
754
|
+
types: [{ description: "ZIP archive", accept: { "application/zip": [".zip"] } }]
|
|
755
|
+
});
|
|
756
|
+
const response = await (options.fetch ?? globalThis.fetch)(url, options.signal === void 0 ? {} : { signal: options.signal });
|
|
757
|
+
if (!response.ok)
|
|
758
|
+
throw await responseFailure(response);
|
|
759
|
+
if (response.body === null)
|
|
760
|
+
throw new Error("Session export returned no response stream");
|
|
761
|
+
const writable = await handle.createWritable();
|
|
762
|
+
await response.body.pipeTo(writable);
|
|
763
|
+
return "streamed";
|
|
141
764
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
});
|
|
180
|
-
if (!probe.ok)
|
|
181
|
-
throw await responseFailure(probe);
|
|
182
|
-
}
|
|
183
|
-
await downloadDshSessionLog({
|
|
184
|
-
endpoint,
|
|
185
|
-
sessionId,
|
|
186
|
-
signal,
|
|
187
|
-
...(browser === undefined ? {} : { window: browser }),
|
|
188
|
-
});
|
|
189
|
-
const open = this.store.getSnapshot().bySession[sessionId]?.open ?? true;
|
|
190
|
-
this.publish(sessionId, { open, status: 'success', error: null });
|
|
191
|
-
}
|
|
192
|
-
catch (error) {
|
|
193
|
-
if (signal.aborted || isAbortError(error))
|
|
194
|
-
return;
|
|
195
|
-
const open = this.store.getSnapshot().bySession[sessionId]?.open ?? true;
|
|
196
|
-
this.publish(sessionId, { open, status: 'error', error: messageOf(error) });
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
publish(sessionId, entry) {
|
|
200
|
-
this.store.update(state => {
|
|
201
|
-
state.bySession = { ...state.bySession, [sessionId]: entry };
|
|
765
|
+
var SessionLogDownloadController = class {
|
|
766
|
+
store = createSnapshotStore({ ...INITIAL_DOWNLOAD_STATE, bySession: {} });
|
|
767
|
+
active = /* @__PURE__ */ new Map();
|
|
768
|
+
disposed = false;
|
|
769
|
+
download(sessionId) {
|
|
770
|
+
const existing = this.active.get(sessionId);
|
|
771
|
+
if (existing !== void 0)
|
|
772
|
+
return existing.done;
|
|
773
|
+
if (this.disposed)
|
|
774
|
+
return Promise.resolve();
|
|
775
|
+
const abort = new AbortController();
|
|
776
|
+
const done = this.run(sessionId, abort.signal).finally(() => this.active.delete(sessionId));
|
|
777
|
+
this.active.set(sessionId, { abort, done });
|
|
778
|
+
return done;
|
|
779
|
+
}
|
|
780
|
+
dismiss(sessionId) {
|
|
781
|
+
const current = this.store.getSnapshot().bySession[sessionId];
|
|
782
|
+
if (current === void 0 || !current.open)
|
|
783
|
+
return;
|
|
784
|
+
this.publish(sessionId, { ...current, open: false });
|
|
785
|
+
}
|
|
786
|
+
async dispose() {
|
|
787
|
+
this.disposed = true;
|
|
788
|
+
const active = [...this.active.values()];
|
|
789
|
+
for (const operation of active)
|
|
790
|
+
operation.abort.abort();
|
|
791
|
+
await Promise.allSettled(active.map((operation) => operation.done));
|
|
792
|
+
}
|
|
793
|
+
async run(sessionId, signal) {
|
|
794
|
+
this.publish(sessionId, { open: true, status: "downloading", error: null });
|
|
795
|
+
try {
|
|
796
|
+
const endpoint = new URL(SESSION_EXPORT_PATH, hostBase()).toString();
|
|
797
|
+
const browser = globalThis.window;
|
|
798
|
+
if (browser?.showSaveFilePicker === void 0) {
|
|
799
|
+
const probe = await fetch(`${endpoint}?sessionId=${encodeURIComponent(sessionId)}&includeDescendants=true`, {
|
|
800
|
+
method: "HEAD",
|
|
801
|
+
signal
|
|
202
802
|
});
|
|
803
|
+
if (!probe.ok)
|
|
804
|
+
throw await responseFailure(probe);
|
|
805
|
+
}
|
|
806
|
+
await downloadDshSessionLog({
|
|
807
|
+
endpoint,
|
|
808
|
+
sessionId,
|
|
809
|
+
signal,
|
|
810
|
+
...browser === void 0 ? {} : { window: browser }
|
|
811
|
+
});
|
|
812
|
+
const open = this.store.getSnapshot().bySession[sessionId]?.open ?? true;
|
|
813
|
+
this.publish(sessionId, { open, status: "success", error: null });
|
|
814
|
+
} catch (error) {
|
|
815
|
+
if (signal.aborted || isAbortError(error))
|
|
816
|
+
return;
|
|
817
|
+
const open = this.store.getSnapshot().bySession[sessionId]?.open ?? true;
|
|
818
|
+
this.publish(sessionId, { open, status: "error", error: messageOf2(error) });
|
|
203
819
|
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
const dismiss = props.dismiss;
|
|
209
|
-
const t = props.t;
|
|
210
|
-
const entry = useSessionLogDownload(state => state.bySession[sessionId]);
|
|
211
|
-
const status = entry?.status;
|
|
212
|
-
const error = status === 'error' ? entry?.error || t('dialog.commandFailed') : null;
|
|
213
|
-
return jsx(Modal, {
|
|
214
|
-
open: entry?.open === true,
|
|
215
|
-
onClose: () => dismiss(sessionId),
|
|
216
|
-
title: status === 'downloading'
|
|
217
|
-
? t('dialog.preparingTitle')
|
|
218
|
-
: status === 'success' ? t('dialog.successTitle') : t('dialog.errorTitle'),
|
|
219
|
-
description: status === 'downloading'
|
|
220
|
-
? t('dialog.preparingDescription')
|
|
221
|
-
: status === 'success' ? t('dialog.successDescription') : error ?? t('dialog.commandFailed'),
|
|
222
|
-
closeLabel: t('dialog.close'),
|
|
223
|
-
footer: jsx(Button, { variant: 'primary', onClick: () => dismiss(sessionId), children: t('dialog.close') }),
|
|
820
|
+
}
|
|
821
|
+
publish(sessionId, entry) {
|
|
822
|
+
this.store.update((state) => {
|
|
823
|
+
state.bySession = { ...state.bySession, [sessionId]: entry };
|
|
224
824
|
});
|
|
825
|
+
}
|
|
826
|
+
};
|
|
827
|
+
function SessionLogDownloadDialog(props) {
|
|
828
|
+
const sessionId = String(props.sessionId);
|
|
829
|
+
const useSessionLogDownload = props.useSessionLogDownload;
|
|
830
|
+
const dismiss = props.dismiss;
|
|
831
|
+
const t = props.t;
|
|
832
|
+
const entry = useSessionLogDownload((state) => state.bySession[sessionId]);
|
|
833
|
+
const status = entry?.status;
|
|
834
|
+
const error = status === "error" ? entry?.error || t("dialog.commandFailed") : null;
|
|
835
|
+
return jsx(Modal, {
|
|
836
|
+
open: entry?.open === true,
|
|
837
|
+
onClose: () => dismiss(sessionId),
|
|
838
|
+
title: status === "downloading" ? t("dialog.preparingTitle") : status === "success" ? t("dialog.successTitle") : t("dialog.errorTitle"),
|
|
839
|
+
description: status === "downloading" ? t("dialog.preparingDescription") : status === "success" ? t("dialog.successDescription") : error ?? t("dialog.commandFailed"),
|
|
840
|
+
closeLabel: t("dialog.close"),
|
|
841
|
+
footer: jsx(Button, { variant: "primary", onClick: () => dismiss(sessionId), children: t("dialog.close") })
|
|
842
|
+
});
|
|
225
843
|
}
|
|
226
844
|
function SessionLogDownloadHeaderAction(props) {
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
845
|
+
const sessionId = String(props.sessionId);
|
|
846
|
+
const useSessionLogDownload = props.useSessionLogDownload;
|
|
847
|
+
const request = props.request;
|
|
848
|
+
const t = props.t;
|
|
849
|
+
const busy = useSessionLogDownload((state) => state.bySession[sessionId])?.status === "downloading";
|
|
850
|
+
return jsxs(Fragment, {
|
|
851
|
+
children: [
|
|
852
|
+
jsxs("button", {
|
|
853
|
+
type: "button",
|
|
854
|
+
className: "kiokuko-session-log-button",
|
|
855
|
+
disabled: busy,
|
|
856
|
+
"aria-busy": busy,
|
|
857
|
+
onClick: () => request(sessionId),
|
|
858
|
+
children: [jsx("span", { children: t("header.action") }), jsx(IconDownloadOutline16, { size: 12 })]
|
|
859
|
+
}),
|
|
860
|
+
jsx(SessionLogDownloadDialog, props)
|
|
861
|
+
]
|
|
862
|
+
});
|
|
245
863
|
}
|
|
246
864
|
function installStyle() {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
865
|
+
const styleId = "kiokuko-session-log-download-style";
|
|
866
|
+
const existing = document.querySelector(`style[data-plugin-css="${styleId}"]`);
|
|
867
|
+
if (existing !== null)
|
|
868
|
+
return () => void 0;
|
|
869
|
+
const style = document.createElement("style");
|
|
870
|
+
style.dataset.plugin = "kiokuko-dsh";
|
|
871
|
+
style.dataset.pluginCss = styleId;
|
|
872
|
+
style.textContent = ".kiokuko-session-log-button{border:.5px solid var(--dsw-alias-border-l4);min-width:111px;height:32px;color:var(--dsw-alias-label-primary);font-family:var(--dsw-font-family);cursor:pointer;background:transparent;border-radius:18px;justify-content:center;align-items:center;gap:4px;padding:6px 12px;font-size:13px;font-weight:400;line-height:20px;display:inline-flex}.kiokuko-session-log-button:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.kiokuko-session-log-button:disabled{color:var(--dsw-alias-label-dimmed);cursor:wait}.kiokuko-session-log-button span,.kiokuko-session-log-button svg{flex:none}.kiokuko-session-log-button span{white-space:nowrap}";
|
|
873
|
+
document.head.appendChild(style);
|
|
874
|
+
return () => style.remove();
|
|
257
875
|
}
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
876
|
+
var inject = ["slots", "locale", "uiConversation"];
|
|
877
|
+
var completionReportDefinition = {
|
|
878
|
+
kind: "kiokuko-completion-report",
|
|
879
|
+
target: "chat",
|
|
880
|
+
match: (event) => ["kiokuko/completion-report", "kiokuko/execution-status", "kiokuko/deep-report", "kiokuko/deep-status"].includes(event.type) && typeof event.data.reportId === "string" && typeof event.data.text === "string" ? { id: event.data.reportId, role: "start" } : null,
|
|
881
|
+
start: (_context, match) => ({ seq: match.event.seq, text: match.event.data.text, status: match.event.type.endsWith("status") }),
|
|
882
|
+
update: (context) => context.state,
|
|
883
|
+
buildViewNode: (context) => context.state === void 0 ? null : {
|
|
884
|
+
key: context.key,
|
|
885
|
+
id: context.id,
|
|
886
|
+
kind: "kiokuko-completion-report",
|
|
887
|
+
target: "chat",
|
|
888
|
+
anchorSeq: context.state.seq,
|
|
889
|
+
location: context.start?.location ?? { kind: "session" },
|
|
890
|
+
visibility: "visible",
|
|
891
|
+
data: { text: context.state.text, status: context.state.status }
|
|
892
|
+
}
|
|
271
893
|
};
|
|
272
894
|
function CompletionReport(props) {
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
895
|
+
const node = props.node;
|
|
896
|
+
return jsx("section", {
|
|
897
|
+
...node.data.status ? { role: "status", "aria-live": "polite", "aria-atomic": true } : { "aria-label": "\u4FDD\u5B58\u6E08\u307F\u306E\u56DE\u7B54", tabIndex: 0 },
|
|
898
|
+
style: { whiteSpace: "pre-wrap", overflowWrap: "anywhere", maxWidth: "100%", minWidth: 0, padding: "12px 0", lineHeight: 1.65 },
|
|
899
|
+
children: node.data.text
|
|
900
|
+
});
|
|
276
901
|
}
|
|
277
|
-
/** Recovery stays available even when the model loop is stopped. */
|
|
278
902
|
function LispSessionStatus(props) {
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
903
|
+
const sessionId = String(props.sessionId);
|
|
904
|
+
const [status, setStatus] = useState(null);
|
|
905
|
+
const [open, setOpen] = useState(false);
|
|
906
|
+
const [error, setError] = useState("");
|
|
907
|
+
const [busy, setBusy] = useState(false);
|
|
908
|
+
const [details, setDetails] = useState("");
|
|
909
|
+
const dialog = useRef(null);
|
|
910
|
+
const trigger = useRef(null);
|
|
911
|
+
const current = useRef(sessionId);
|
|
912
|
+
current.current = sessionId;
|
|
913
|
+
const request = async (action) => {
|
|
914
|
+
const url = new URL("/api/kiokuko.lisp", hostBase());
|
|
915
|
+
url.searchParams.set("sessionId", sessionId);
|
|
916
|
+
const response = await fetch(url, action ? { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ action }) } : {});
|
|
917
|
+
if (response.status === 404 && !action)
|
|
918
|
+
return null;
|
|
919
|
+
const value = await response.json();
|
|
920
|
+
if (!response.ok)
|
|
921
|
+
throw new Error(value.message ?? "Lisp \u306E\u72B6\u614B\u3092\u53D6\u5F97\u3067\u304D\u307E\u305B\u3093\u3002\u63A5\u7D9A\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002");
|
|
922
|
+
return value;
|
|
923
|
+
};
|
|
924
|
+
useEffect(() => {
|
|
925
|
+
if (open && dialog.current && !dialog.current.open)
|
|
926
|
+
dialog.current.showModal();
|
|
927
|
+
if (!open && dialog.current?.open) {
|
|
928
|
+
dialog.current.close();
|
|
929
|
+
trigger.current?.focus();
|
|
930
|
+
}
|
|
931
|
+
}, [open]);
|
|
932
|
+
useEffect(() => {
|
|
933
|
+
let disposed = false, timer, lastState = "";
|
|
934
|
+
setStatus(null);
|
|
935
|
+
setError("");
|
|
936
|
+
setOpen(false);
|
|
937
|
+
setDetails("");
|
|
938
|
+
setBusy(false);
|
|
939
|
+
const refresh = async () => {
|
|
940
|
+
try {
|
|
941
|
+
const value = await request();
|
|
942
|
+
if (disposed)
|
|
943
|
+
return;
|
|
944
|
+
if (value) {
|
|
945
|
+
setStatus(value);
|
|
946
|
+
setError("");
|
|
947
|
+
if (value.enabled && ["RECOVERY_REQUIRED", "STOP_UNCONFIRMED"].includes(value.state) && value.state !== lastState)
|
|
948
|
+
setOpen(true);
|
|
949
|
+
lastState = value.state;
|
|
950
|
+
} else if (lastState)
|
|
951
|
+
setError("Lisp \u306E\u63A5\u7D9A\u304C\u5931\u308F\u308C\u307E\u3057\u305F\u3002\u4FDD\u8B77\u306F\u89E3\u9664\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002\u30D7\u30E9\u30B0\u30A4\u30F3\u3092\u623B\u3057\u3066 /kioku-lisp status \u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002");
|
|
952
|
+
} catch (failure) {
|
|
953
|
+
if (!disposed && lastState)
|
|
954
|
+
setError(messageOf2(failure));
|
|
955
|
+
} finally {
|
|
956
|
+
if (!disposed)
|
|
957
|
+
timer = setTimeout(() => void refresh(), document.hidden ? 1e4 : 2e3);
|
|
958
|
+
}
|
|
299
959
|
};
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
dialog.current.close();
|
|
305
|
-
trigger.current?.focus();
|
|
306
|
-
}
|
|
307
|
-
}, [open]);
|
|
308
|
-
useEffect(() => {
|
|
309
|
-
let disposed = false, timer, lastState = '';
|
|
310
|
-
setStatus(null);
|
|
311
|
-
setError('');
|
|
312
|
-
setOpen(false);
|
|
313
|
-
setDetails('');
|
|
314
|
-
setBusy(false);
|
|
315
|
-
const refresh = async () => {
|
|
316
|
-
try {
|
|
317
|
-
const value = await request();
|
|
318
|
-
if (disposed)
|
|
319
|
-
return;
|
|
320
|
-
if (value) {
|
|
321
|
-
setStatus(value);
|
|
322
|
-
setError('');
|
|
323
|
-
if (value.enabled && ['RECOVERY_REQUIRED', 'STOP_UNCONFIRMED'].includes(value.state) && value.state !== lastState)
|
|
324
|
-
setOpen(true);
|
|
325
|
-
lastState = value.state;
|
|
326
|
-
}
|
|
327
|
-
else if (lastState)
|
|
328
|
-
setError('Lisp の接続が失われました。保護は解除されていません。プラグインを戻して /kioku-lisp status を確認してください。');
|
|
329
|
-
}
|
|
330
|
-
catch (failure) {
|
|
331
|
-
if (!disposed && lastState)
|
|
332
|
-
setError(messageOf(failure));
|
|
333
|
-
}
|
|
334
|
-
finally {
|
|
335
|
-
if (!disposed)
|
|
336
|
-
timer = setTimeout(() => void refresh(), document.hidden ? 10000 : 2000);
|
|
337
|
-
}
|
|
338
|
-
};
|
|
339
|
-
void refresh();
|
|
340
|
-
return () => { disposed = true; clearTimeout(timer); };
|
|
341
|
-
}, [sessionId]);
|
|
342
|
-
const act = async (action) => {
|
|
343
|
-
if (busy)
|
|
344
|
-
return;
|
|
345
|
-
setBusy(true);
|
|
346
|
-
setError('');
|
|
347
|
-
try {
|
|
348
|
-
const result = await request(action);
|
|
349
|
-
if (current.current !== sessionId)
|
|
350
|
-
return;
|
|
351
|
-
if (result?.code)
|
|
352
|
-
setDetails(JSON.stringify(result, null, 2));
|
|
353
|
-
else {
|
|
354
|
-
setDetails('');
|
|
355
|
-
if (result?.state)
|
|
356
|
-
setStatus({ ...status, ...result, enabled: result.enabled ?? status?.enabled ?? true });
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
catch (failure) {
|
|
360
|
-
if (current.current === sessionId)
|
|
361
|
-
setError(messageOf(failure));
|
|
362
|
-
}
|
|
363
|
-
finally {
|
|
364
|
-
if (current.current === sessionId)
|
|
365
|
-
setBusy(false);
|
|
366
|
-
}
|
|
960
|
+
void refresh();
|
|
961
|
+
return () => {
|
|
962
|
+
disposed = true;
|
|
963
|
+
clearTimeout(timer);
|
|
367
964
|
};
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
965
|
+
}, [sessionId]);
|
|
966
|
+
const act = async (action) => {
|
|
967
|
+
if (busy)
|
|
968
|
+
return;
|
|
969
|
+
setBusy(true);
|
|
970
|
+
setError("");
|
|
971
|
+
try {
|
|
972
|
+
const result = await request(action);
|
|
973
|
+
if (current.current !== sessionId)
|
|
974
|
+
return;
|
|
975
|
+
if (result?.code)
|
|
976
|
+
setDetails(JSON.stringify(result, null, 2));
|
|
977
|
+
else {
|
|
978
|
+
setDetails("");
|
|
979
|
+
if (result?.state)
|
|
980
|
+
setStatus({ ...status, ...result, enabled: result.enabled ?? status?.enabled ?? true });
|
|
981
|
+
}
|
|
982
|
+
} catch (failure) {
|
|
983
|
+
if (current.current === sessionId)
|
|
984
|
+
setError(messageOf2(failure));
|
|
985
|
+
} finally {
|
|
986
|
+
if (current.current === sessionId)
|
|
987
|
+
setBusy(false);
|
|
988
|
+
}
|
|
989
|
+
};
|
|
990
|
+
if (!status?.enabled && !error)
|
|
991
|
+
return null;
|
|
992
|
+
const label = { READY: "\u5B9F\u884C\u53EF\u80FD", SUSPENDED: "\u4F11\u6B62\u4E2D\uFF08\u6B21\u56DE\u81EA\u52D5\u8D77\u52D5\uFF09", EVALUATING: "\u51E6\u7406\u4E2D", PREFLIGHT: "\u8D77\u52D5\u4E2D", STOPPING: "\u505C\u6B62\u4E2D", RECOVERY_REQUIRED: "\u78BA\u8A8D\u304C\u5FC5\u8981", STOP_UNCONFIRMED: "\u505C\u6B62\u672A\u78BA\u8A8D" }[status?.state ?? ""] ?? "\u72B6\u614B\u4E0D\u660E";
|
|
993
|
+
return jsxs(Fragment, { children: [
|
|
994
|
+
jsx("button", { type: "button", ref: trigger, onClick: () => setOpen(true), children: `Lisp: ${label}` }),
|
|
995
|
+
jsx("dialog", {
|
|
996
|
+
ref: dialog,
|
|
997
|
+
onCancel: () => setOpen(false),
|
|
998
|
+
"aria-label": "Lisp \u306E\u72B6\u614B\u3068\u5FA9\u65E7",
|
|
999
|
+
style: { maxWidth: "min(720px, 90vw)", maxHeight: "85vh" },
|
|
1000
|
+
children: jsxs("section", { children: [
|
|
1001
|
+
jsx("h2", { children: `Lisp: ${label}` }),
|
|
1002
|
+
jsx("p", { role: "status", "aria-live": "polite", children: busy ? "\u51E6\u7406\u3057\u3066\u3044\u307E\u3059\u3002\u521D\u56DE\u306E\u8D77\u52D5\u306B\u306F\u6642\u9593\u304C\u304B\u304B\u308B\u5834\u5408\u304C\u3042\u308A\u307E\u3059\u3002" : status?.error?.message ?? "\u73FE\u5728\u306E\u30BB\u30C3\u30B7\u30E7\u30F3\u306E\u72B6\u614B\u3067\u3059\u3002" }),
|
|
1003
|
+
jsx("p", { children: status?.error?.recovery ?? status?.recovery ?? "" }),
|
|
1004
|
+
...error ? [jsx("p", { role: "alert", children: error })] : [],
|
|
1005
|
+
...details ? [jsx("pre", { style: { whiteSpace: "pre-wrap", overflowWrap: "anywhere" }, children: details })] : [],
|
|
1006
|
+
jsx("p", { children: "\u672A\u78BA\u5B9A\u306E\u5909\u66F4\u306F\u81EA\u52D5\u3067\u518D\u5B9F\u884C\u30FB\u5FA9\u5143\u3057\u307E\u305B\u3093\u3002\u8A73\u7D30\u306F /kioku-lisp diagnostics \u3067\u3082\u78BA\u8A8D\u3067\u304D\u307E\u3059\u3002" }),
|
|
1007
|
+
jsx(NumberedPicker, {
|
|
1008
|
+
label: "Lisp \u306E\u64CD\u4F5C",
|
|
1009
|
+
disabled: busy,
|
|
1010
|
+
options: [{ value: "cancel", label: "\u505C\u6B62\u3059\u308B" }, { value: "recover", label: "\u7167\u5408\u3057\u3066\u65B0\u3057\u3044 Lisp \u3092\u8D77\u52D5", disabled: ["STOP_UNCONFIRMED", "SUSPENDED"].includes(status?.state ?? "") }, { value: "close", label: "\u9589\u3058\u308B" }],
|
|
1011
|
+
onChoose: (value) => value === "close" ? setOpen(false) : void act(value)
|
|
1012
|
+
})
|
|
1013
|
+
] })
|
|
1014
|
+
})
|
|
1015
|
+
] });
|
|
383
1016
|
}
|
|
384
|
-
/** Read-only, Session-bound display with explicit delivery acknowledgement after render. */
|
|
385
1017
|
function DeepSessionReports(props) {
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
1018
|
+
const sessionId = String(props.sessionId);
|
|
1019
|
+
const notices = props.notices === true;
|
|
1020
|
+
const label = notices ? "Kiokuko" : "Deep";
|
|
1021
|
+
const endpoint = notices ? "/api/kiokuko.notices" : "/api/kiokuko.deep";
|
|
1022
|
+
const [items, setItems] = useState([]);
|
|
1023
|
+
const [open, setOpen] = useState(false);
|
|
1024
|
+
const [error, setError] = useState("");
|
|
1025
|
+
const seen = useRef(/* @__PURE__ */ new Set());
|
|
1026
|
+
const dialog = useRef(null);
|
|
1027
|
+
const trigger = useRef(null);
|
|
1028
|
+
useEffect(() => {
|
|
1029
|
+
if (open && dialog.current && !dialog.current.open)
|
|
1030
|
+
dialog.current.showModal();
|
|
1031
|
+
else if (!open && dialog.current?.open) {
|
|
1032
|
+
dialog.current.close();
|
|
1033
|
+
trigger.current?.focus();
|
|
1034
|
+
}
|
|
1035
|
+
}, [open]);
|
|
1036
|
+
useEffect(() => {
|
|
1037
|
+
const controller = new AbortController();
|
|
1038
|
+
let timer;
|
|
1039
|
+
let etag = "";
|
|
1040
|
+
setItems([]);
|
|
1041
|
+
setOpen(false);
|
|
1042
|
+
seen.current = /* @__PURE__ */ new Set();
|
|
1043
|
+
const refresh = async () => {
|
|
1044
|
+
try {
|
|
1045
|
+
const url = new URL(endpoint, hostBase());
|
|
1046
|
+
url.searchParams.set("sessionId", sessionId);
|
|
1047
|
+
const response = await fetch(url, { signal: controller.signal, headers: etag ? { "if-none-match": etag } : {} });
|
|
1048
|
+
if (response.status === 304) {
|
|
1049
|
+
setError("");
|
|
1050
|
+
return;
|
|
402
1051
|
}
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
1052
|
+
if (!response.ok)
|
|
1053
|
+
throw new Error(`${label}\u306E\u72B6\u614B\u3092\u518D\u78BA\u8A8D\u3067\u304D\u307E\u305B\u3093\u3002\u63A5\u7D9A\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002`);
|
|
1054
|
+
etag = response.headers.get("etag") ?? "";
|
|
1055
|
+
const data = await response.json();
|
|
1056
|
+
if (!Array.isArray(data.items) || data.items.some((item) => typeof item.id !== "string" || typeof item.text !== "string"))
|
|
1057
|
+
throw new Error(`${label}\u306E\u5FDC\u7B54\u3092\u8AAD\u307F\u53D6\u308C\u307E\u305B\u3093\u3002`);
|
|
1058
|
+
if (controller.signal.aborted)
|
|
1059
|
+
return;
|
|
1060
|
+
setItems(data.items);
|
|
1061
|
+
setError("");
|
|
1062
|
+
for (const item of data.items)
|
|
1063
|
+
if ((item.kind === "report" || notices && !item.id.startsWith("completion-wait:")) && !item.delivered && !seen.current.has(item.id)) {
|
|
1064
|
+
seen.current.add(item.id);
|
|
1065
|
+
setOpen(true);
|
|
1066
|
+
}
|
|
1067
|
+
} catch (failure) {
|
|
1068
|
+
if (!controller.signal.aborted)
|
|
1069
|
+
setError(messageOf2(failure));
|
|
1070
|
+
} finally {
|
|
1071
|
+
if (!controller.signal.aborted)
|
|
1072
|
+
timer = setTimeout(() => void refresh(), document.hidden ? 1e4 : 2e3);
|
|
1073
|
+
}
|
|
1074
|
+
};
|
|
1075
|
+
void refresh();
|
|
1076
|
+
return () => {
|
|
1077
|
+
controller.abort();
|
|
1078
|
+
clearTimeout(timer);
|
|
1079
|
+
};
|
|
1080
|
+
}, [sessionId, endpoint, label, notices]);
|
|
1081
|
+
useEffect(() => {
|
|
1082
|
+
const unread = items.filter((item) => !item.delivered && (open || !notices && item.kind === "status"));
|
|
1083
|
+
if (!unread.length)
|
|
1084
|
+
return;
|
|
1085
|
+
const controller = new AbortController();
|
|
1086
|
+
const url = new URL(endpoint, hostBase());
|
|
1087
|
+
url.searchParams.set("sessionId", sessionId);
|
|
1088
|
+
for (const item of unread)
|
|
1089
|
+
url.searchParams.append("id", item.id);
|
|
1090
|
+
let timer;
|
|
1091
|
+
const acknowledge = async () => {
|
|
1092
|
+
try {
|
|
1093
|
+
const response = await fetch(url, { method: "POST", signal: controller.signal });
|
|
1094
|
+
if (!response.ok)
|
|
1095
|
+
throw new Error(`${label}\u306E\u53D7\u9818\u78BA\u8A8D\u3092\u518D\u8A66\u884C\u3057\u3066\u3044\u307E\u3059\u3002\u56DE\u7B54\u306F\u4FDD\u6301\u3055\u308C\u3066\u3044\u307E\u3059\u3002`);
|
|
1096
|
+
} catch (failure) {
|
|
1097
|
+
if (!controller.signal.aborted) {
|
|
1098
|
+
setError(messageOf2(failure));
|
|
1099
|
+
timer = setTimeout(() => void acknowledge(), 5e3);
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
};
|
|
1103
|
+
void acknowledge();
|
|
1104
|
+
return () => {
|
|
1105
|
+
controller.abort();
|
|
1106
|
+
clearTimeout(timer);
|
|
1107
|
+
};
|
|
1108
|
+
}, [sessionId, items, open, endpoint, label, notices]);
|
|
1109
|
+
if (!items.length && !error)
|
|
1110
|
+
return null;
|
|
1111
|
+
const status = items.find((item) => item.kind === "status")?.text ?? `${label}\u306E\u4FDD\u5B58\u6E08\u307F\u56DE\u7B54`;
|
|
1112
|
+
return jsxs(Fragment, { children: [
|
|
1113
|
+
jsx("button", { ref: trigger, type: "button", className: "kiokuko-session-log-button", onClick: () => setOpen(true), "aria-label": `${label}: ${status}`, children: items.some((item) => item.kind === "report") ? `${label}\u306E\u56DE\u7B54` : `${label}\u306E\u72B6\u614B` }),
|
|
1114
|
+
jsx("span", { role: "status", "aria-live": "polite", style: { position: "absolute", width: 1, height: 1, overflow: "hidden", clipPath: "inset(50%)" }, children: error || status.slice(0, 200) }),
|
|
1115
|
+
jsxs("dialog", {
|
|
1116
|
+
ref: dialog,
|
|
1117
|
+
"aria-label": label,
|
|
1118
|
+
onCancel: () => setOpen(false),
|
|
1119
|
+
onClose: () => {
|
|
409
1120
|
setOpen(false);
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
if (!response.ok)
|
|
421
|
-
throw new Error(`${label}の状態を再確認できません。接続を確認してください。`);
|
|
422
|
-
etag = response.headers.get('etag') ?? '';
|
|
423
|
-
const data = await response.json();
|
|
424
|
-
if (!Array.isArray(data.items) || data.items.some(item => typeof item.id !== 'string' || typeof item.text !== 'string'))
|
|
425
|
-
throw new Error(`${label}の応答を読み取れません。`);
|
|
426
|
-
if (controller.signal.aborted)
|
|
427
|
-
return;
|
|
428
|
-
setItems(data.items);
|
|
429
|
-
setError('');
|
|
430
|
-
for (const item of data.items)
|
|
431
|
-
if ((item.kind === 'report' || notices) && !item.delivered && !seen.current.has(item.id)) {
|
|
432
|
-
seen.current.add(item.id);
|
|
433
|
-
setOpen(true);
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
catch (failure) {
|
|
437
|
-
if (!controller.signal.aborted)
|
|
438
|
-
setError(messageOf(failure));
|
|
439
|
-
}
|
|
440
|
-
finally {
|
|
441
|
-
if (!controller.signal.aborted)
|
|
442
|
-
timer = setTimeout(() => void refresh(), document.hidden ? 10_000 : 2_000);
|
|
443
|
-
}
|
|
444
|
-
};
|
|
445
|
-
void refresh();
|
|
446
|
-
return () => { controller.abort(); clearTimeout(timer); };
|
|
447
|
-
}, [sessionId, endpoint, label, notices]);
|
|
448
|
-
useEffect(() => {
|
|
449
|
-
const unread = items.filter(item => !item.delivered && (open || !notices && item.kind === 'status'));
|
|
450
|
-
if (!unread.length)
|
|
451
|
-
return;
|
|
452
|
-
const controller = new AbortController();
|
|
453
|
-
const url = new URL(endpoint, hostBase());
|
|
454
|
-
url.searchParams.set('sessionId', sessionId);
|
|
455
|
-
for (const item of unread)
|
|
456
|
-
url.searchParams.append('id', item.id);
|
|
457
|
-
let timer;
|
|
458
|
-
const acknowledge = async () => {
|
|
459
|
-
try {
|
|
460
|
-
const response = await fetch(url, { method: 'POST', signal: controller.signal });
|
|
461
|
-
if (!response.ok)
|
|
462
|
-
throw new Error(`${label}の受領確認を再試行しています。回答は保持されています。`);
|
|
463
|
-
}
|
|
464
|
-
catch (failure) {
|
|
465
|
-
if (!controller.signal.aborted) {
|
|
466
|
-
setError(messageOf(failure));
|
|
467
|
-
timer = setTimeout(() => void acknowledge(), 5_000);
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
};
|
|
471
|
-
void acknowledge();
|
|
472
|
-
return () => { controller.abort(); clearTimeout(timer); };
|
|
473
|
-
}, [sessionId, items, open, endpoint, label, notices]);
|
|
474
|
-
if (!items.length && !error)
|
|
475
|
-
return null;
|
|
476
|
-
const status = items.find(item => item.kind === 'status')?.text ?? `${label}の保存済み回答`;
|
|
477
|
-
return jsxs(Fragment, { children: [
|
|
478
|
-
jsx('button', { ref: trigger, type: 'button', className: 'kiokuko-session-log-button', onClick: () => setOpen(true), 'aria-label': `${label}: ${status}`, children: items.some(item => item.kind === 'report') ? `${label}の回答` : `${label}の状態` }),
|
|
479
|
-
jsx('span', { role: 'status', 'aria-live': 'polite', style: { position: 'absolute', width: 1, height: 1, overflow: 'hidden', clipPath: 'inset(50%)' }, children: error || status.slice(0, 200) }),
|
|
480
|
-
jsxs('dialog', { ref: dialog, 'aria-label': label, onCancel: () => setOpen(false), onClose: () => { setOpen(false); trigger.current?.focus(); },
|
|
481
|
-
style: { width: 'min(48rem, calc(100vw - 2rem))', maxHeight: 'calc(100dvh - 2rem)', boxSizing: 'border-box', margin: 'auto', padding: '20px', border: '1px solid var(--dsw-alias-border-l4, #ddd)', borderRadius: '16px', background: 'var(--dsw-alias-background-primary, Canvas)', color: 'var(--dsw-alias-label-primary, CanvasText)', overflow: 'auto' },
|
|
482
|
-
children: [jsxs('div', { style: { display: 'flex', justifyContent: 'space-between', gap: '16px', alignItems: 'center' }, children: [jsx('h2', { style: { fontSize: '20px', margin: 0 }, children: label }), jsx('button', { type: 'button', className: 'kiokuko-session-log-button', onClick: () => setOpen(false), children: '閉じる' })] }),
|
|
483
|
-
jsx('p', { style: { whiteSpace: 'pre-wrap', overflowWrap: 'anywhere' }, children: error || status }),
|
|
484
|
-
...items.filter(item => item.kind === 'report').map(item => jsx('section', { key: item.id, 'aria-label': '保存済みの回答', tabIndex: 0, style: { whiteSpace: 'pre-wrap', overflowWrap: 'anywhere', maxWidth: '100%', padding: '12px 0', lineHeight: 1.65 }, children: item.text }))] }),
|
|
485
|
-
] });
|
|
1121
|
+
trigger.current?.focus();
|
|
1122
|
+
},
|
|
1123
|
+
style: { width: "min(48rem, calc(100vw - 2rem))", maxHeight: "calc(100dvh - 2rem)", boxSizing: "border-box", margin: "auto", padding: "20px", border: "1px solid var(--dsw-alias-border-l4, #ddd)", borderRadius: "16px", background: "var(--dsw-alias-background-primary, Canvas)", color: "var(--dsw-alias-label-primary, CanvasText)", overflow: "auto" },
|
|
1124
|
+
children: [
|
|
1125
|
+
jsxs("div", { style: { display: "flex", justifyContent: "space-between", gap: "16px", alignItems: "center" }, children: [jsx("h2", { style: { fontSize: "20px", margin: 0 }, children: label }), jsx("button", { type: "button", className: "kiokuko-session-log-button", onClick: () => setOpen(false), children: "\u9589\u3058\u308B" })] }),
|
|
1126
|
+
jsx("p", { style: { whiteSpace: "pre-wrap", overflowWrap: "anywhere" }, children: error || status }),
|
|
1127
|
+
...items.filter((item) => item.kind === "report").map((item) => jsx("section", { key: item.id, "aria-label": "\u4FDD\u5B58\u6E08\u307F\u306E\u56DE\u7B54", tabIndex: 0, style: { whiteSpace: "pre-wrap", overflowWrap: "anywhere", maxWidth: "100%", padding: "12px 0", lineHeight: 1.65 }, children: item.text }))
|
|
1128
|
+
]
|
|
1129
|
+
})
|
|
1130
|
+
] });
|
|
486
1131
|
}
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
const namedIntakeDrafts = new Map();
|
|
491
|
-
const emptyDraft = () => ({ selected: null, checked: [], custom: '', ordinal: '' });
|
|
1132
|
+
var intakeDrafts = /* @__PURE__ */ new WeakMap();
|
|
1133
|
+
var namedIntakeDrafts = /* @__PURE__ */ new Map();
|
|
1134
|
+
var emptyDraft = () => ({ selected: null, checked: [], custom: "", ordinal: "" });
|
|
492
1135
|
function draftKey(pending) {
|
|
493
|
-
|
|
1136
|
+
return pending.sessionId && pending.dismissal === "hide" ? JSON.stringify([pending.sessionId, pending.key]) : void 0;
|
|
494
1137
|
}
|
|
495
1138
|
function readIntakeDraft(pending) {
|
|
496
|
-
|
|
1139
|
+
return intakeDrafts.get(pending) ?? namedIntakeDrafts.get(draftKey(pending) ?? "") ?? { page: 0, drafts: pending.questions.map(emptyDraft) };
|
|
497
1140
|
}
|
|
498
1141
|
function saveIntakeDraft(pending, batch) {
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
1142
|
+
const key = draftKey(pending);
|
|
1143
|
+
if (!batch) {
|
|
1144
|
+
intakeDrafts.delete(pending);
|
|
1145
|
+
if (key)
|
|
1146
|
+
namedIntakeDrafts.delete(key);
|
|
1147
|
+
return;
|
|
1148
|
+
}
|
|
1149
|
+
intakeDrafts.set(pending, batch);
|
|
1150
|
+
if (key) {
|
|
1151
|
+
namedIntakeDrafts.delete(key);
|
|
1152
|
+
namedIntakeDrafts.set(key, batch);
|
|
1153
|
+
if (namedIntakeDrafts.size > 100)
|
|
1154
|
+
namedIntakeDrafts.delete(namedIntakeDrafts.keys().next().value);
|
|
1155
|
+
}
|
|
513
1156
|
}
|
|
514
1157
|
function pendingState(pending) {
|
|
515
|
-
|
|
1158
|
+
return pending.snapshot?.() ?? { state: "open", channel: "waterfall", closed: false };
|
|
516
1159
|
}
|
|
517
1160
|
function dismissQuestion(pending) {
|
|
518
|
-
|
|
519
|
-
return pending.dismiss ? pending.dismiss() : pending.cancel();
|
|
1161
|
+
return pending.dismiss ? pending.dismiss() : pending.cancel();
|
|
520
1162
|
}
|
|
521
1163
|
function composingKey(event) {
|
|
522
|
-
|
|
1164
|
+
return !!(event.repeat || event.isComposing || event.keyCode === 229 || event.nativeEvent?.isComposing || event.nativeEvent?.keyCode === 229);
|
|
523
1165
|
}
|
|
524
1166
|
function editingKey(event) {
|
|
525
|
-
|
|
526
|
-
|
|
1167
|
+
const target = event.target;
|
|
1168
|
+
return !!(target?.isContentEditable || ["INPUT", "TEXTAREA", "SELECT"].includes(target?.tagName ?? ""));
|
|
527
1169
|
}
|
|
528
1170
|
function shortcutPlatform() {
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
1171
|
+
const mac = /Mac|iPhone|iPad|iPod/u.test(globalThis.navigator?.platform ?? "");
|
|
1172
|
+
const ua = globalThis.navigator?.userAgent ?? "";
|
|
1173
|
+
const control = !mac || /Safari\//u.test(ua) && !/(?:Chrome|Chromium|CriOS|Edg|OPR)\//u.test(ua);
|
|
1174
|
+
return { control, label: control ? "Ctrl" : "Cmd", aria: control ? "Control" : "Meta" };
|
|
533
1175
|
}
|
|
534
1176
|
function modifiedKey(event) {
|
|
535
|
-
|
|
1177
|
+
return !!(shortcutPlatform().control ? event.ctrlKey && !event.metaKey : event.metaKey && !event.ctrlKey);
|
|
536
1178
|
}
|
|
537
1179
|
function shortcutLabel(index, multi = false) {
|
|
538
|
-
|
|
1180
|
+
return index < 9 ? `${shortcutPlatform().label}+${index + 1}` : `${index + 1} \u2192 ${multi ? "Space" : "Enter"}`;
|
|
539
1181
|
}
|
|
540
1182
|
function shortcutAria(index, count) {
|
|
541
|
-
|
|
1183
|
+
return index < 9 ? { "aria-keyshortcuts": `${count <= 9 ? `${index + 1} ` : ""}${shortcutPlatform().aria}+${index + 1}` } : {};
|
|
542
1184
|
}
|
|
543
|
-
|
|
544
|
-
/** Only the focused group (or the most recently focused visible group) owns a key. */
|
|
1185
|
+
var shortcutOwners = /* @__PURE__ */ new WeakMap();
|
|
545
1186
|
function useShortcutGroup(ref, handler) {
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
1187
|
+
const latest = useRef(handler);
|
|
1188
|
+
latest.current = handler;
|
|
1189
|
+
useEffect(() => {
|
|
1190
|
+
const element = ref.current, doc = element?.ownerDocument;
|
|
1191
|
+
if (!element || !doc)
|
|
1192
|
+
return;
|
|
1193
|
+
const stack = shortcutOwners.get(doc) ?? [];
|
|
1194
|
+
shortcutOwners.set(doc, stack);
|
|
1195
|
+
stack.push(element);
|
|
1196
|
+
const claim = () => {
|
|
1197
|
+
const i = stack.indexOf(element);
|
|
1198
|
+
if (i >= 0)
|
|
1199
|
+
stack.splice(i, 1);
|
|
1200
|
+
stack.push(element);
|
|
1201
|
+
};
|
|
1202
|
+
const listener = (event) => {
|
|
1203
|
+
if (event.defaultPrevented || !element.isConnected || !element.getClientRects().length)
|
|
1204
|
+
return;
|
|
1205
|
+
const target = event.target;
|
|
1206
|
+
if (target?.nodeType && !element.contains(target))
|
|
1207
|
+
return;
|
|
1208
|
+
const group = target?.closest?.("[data-kiokuko-shortcuts]");
|
|
1209
|
+
if (group ? group !== element : stack.filter((item) => item.isConnected && item.getClientRects().length).at(-1) !== element)
|
|
1210
|
+
return;
|
|
1211
|
+
const dialog = target?.closest?.('dialog,[role="dialog"]');
|
|
1212
|
+
if (dialog && !dialog.contains(element))
|
|
1213
|
+
return;
|
|
1214
|
+
if (group === element)
|
|
1215
|
+
claim();
|
|
1216
|
+
latest.current(event);
|
|
1217
|
+
};
|
|
1218
|
+
element.addEventListener?.("focusin", claim);
|
|
1219
|
+
element.addEventListener?.("pointerdown", claim);
|
|
1220
|
+
doc.addEventListener("keydown", listener, true);
|
|
1221
|
+
return () => {
|
|
1222
|
+
element.removeEventListener?.("focusin", claim);
|
|
1223
|
+
element.removeEventListener?.("pointerdown", claim);
|
|
1224
|
+
doc.removeEventListener("keydown", listener, true);
|
|
1225
|
+
const i = stack.indexOf(element);
|
|
1226
|
+
if (i >= 0)
|
|
1227
|
+
stack.splice(i, 1);
|
|
1228
|
+
};
|
|
1229
|
+
}, [ref]);
|
|
585
1230
|
}
|
|
586
1231
|
function isEnnoSearchQuestion(question) {
|
|
587
|
-
|
|
1232
|
+
return question.header === "\u5B9F\u884C\u65B9\u5F0F\u3068\u30E2\u30C7\u30EB" && /^enno-(?:provider|model)-(?:ideal|zenki|goki|worker|check)$/u.test(question.id);
|
|
588
1233
|
}
|
|
589
1234
|
function questionInputKind(question) {
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
1235
|
+
if (isEnnoSearchQuestion(question) || question.header === "Deep planning" && question.id === "deep-role-model")
|
|
1236
|
+
return "search";
|
|
1237
|
+
if (question.header === "Deep planning" && question.id === "deep-budget-value")
|
|
1238
|
+
return "value";
|
|
1239
|
+
return "choice";
|
|
595
1240
|
}
|
|
596
1241
|
function isPlanReview(p) {
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
&& typeof q.detail === 'string' && (q.options?.length ?? 0) <= 3
|
|
600
|
-
&& q.options?.some(o => o.label === q.intent.approve) === true;
|
|
1242
|
+
const q = p.questions[0];
|
|
1243
|
+
return p.questions.length === 1 && !!q && !q.multiSelect && q.intent?.kind === "plan-review" && typeof q.detail === "string" && (q.options?.length ?? 0) <= 3 && q.options?.some((o) => o.label === q.intent.approve) === true;
|
|
601
1244
|
}
|
|
602
1245
|
function intakePending(props) {
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
const q = p.questions[0];
|
|
615
|
-
return p.kind === 'plan-review' && p.questions.length === 1 && !q.multiSelect && q.intent?.kind === 'plan-review'
|
|
616
|
-
&& typeof q.detail === 'string' && (q.options?.length ?? 0) <= 3 && q.options?.some((o) => o.label === q.intent.approve) ? p : null;
|
|
1246
|
+
const p = props.pendingInteraction;
|
|
1247
|
+
if (!p || !Array.isArray(p.questions) || !p.questions.length || typeof p.answer !== "function" || typeof p.dismiss !== "function" && typeof p.cancel !== "function")
|
|
1248
|
+
return null;
|
|
1249
|
+
if (p.sessionId && typeof props.sessionId === "string" && props.sessionId !== p.sessionId)
|
|
1250
|
+
return null;
|
|
1251
|
+
if (!p.questions.every((q2) => typeof q2.id === "string" && typeof q2.question === "string" && (q2.options === void 0 || Array.isArray(q2.options) && q2.options.every((o) => typeof o.label === "string"))))
|
|
1252
|
+
return null;
|
|
1253
|
+
if (p.kind === "question")
|
|
1254
|
+
return p;
|
|
1255
|
+
const q = p.questions[0];
|
|
1256
|
+
return p.kind === "plan-review" && p.questions.length === 1 && !q.multiSelect && q.intent?.kind === "plan-review" && typeof q.detail === "string" && (q.options?.length ?? 0) <= 3 && q.options?.some((o) => o.label === q.intent.approve) ? p : null;
|
|
617
1257
|
}
|
|
618
1258
|
function IntakeQuestion(props) {
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
1259
|
+
const pending = props.matched, t = props.t;
|
|
1260
|
+
return jsx(IntakeQuestionCard, {
|
|
1261
|
+
key: `${pending.sessionId ?? ""}:${pending.key}`,
|
|
1262
|
+
pending,
|
|
1263
|
+
...isPlanReview(pending) ? { reviewCopy: {
|
|
1264
|
+
discuss: t("review.discuss"),
|
|
1265
|
+
labels: { code: { copyLabel: t("review.copy"), copiedLabel: t("review.copied") }, footnotes: t("review.footnotes") }
|
|
1266
|
+
} } : {}
|
|
1267
|
+
});
|
|
624
1268
|
}
|
|
625
1269
|
function IntakeQuestionCard(props) {
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
1270
|
+
const pending = props.pending;
|
|
1271
|
+
const reviewCopy = props.reviewCopy;
|
|
1272
|
+
const reviewing = isPlanReview(pending);
|
|
1273
|
+
const [batch, setBatch] = useState(() => readIntakeDraft(pending));
|
|
1274
|
+
const [snapshot, setSnapshot] = useState(() => pendingState(pending));
|
|
1275
|
+
const [busy, setBusy] = useState(false), [error, setError] = useState("");
|
|
1276
|
+
const inFlight = useRef(false), mounted = useRef(false), sent = useRef(false);
|
|
1277
|
+
const generation = useRef(0);
|
|
1278
|
+
const sentChannel = useRef("none");
|
|
1279
|
+
const card = useRef(null), optionElements = useRef([]);
|
|
1280
|
+
const original = pending.questions[batch.page];
|
|
1281
|
+
const options = original.options ?? [];
|
|
1282
|
+
const alternatives = options.filter((option) => option.label !== original.intent?.approve);
|
|
1283
|
+
const question = { ...original, options: reviewing ? [
|
|
1284
|
+
{ label: reviewCopy.discuss },
|
|
1285
|
+
...alternatives.slice(0, 1),
|
|
1286
|
+
...options.filter((option) => option.label === original.intent?.approve),
|
|
1287
|
+
...alternatives.slice(1)
|
|
1288
|
+
] : options };
|
|
1289
|
+
const draft = batch.drafts[batch.page], multi = question.multiSelect === true, inputKind = questionInputKind(question);
|
|
1290
|
+
const editable = () => !pending.review && !pendingState(pending).closed && pendingState(pending).channel !== "none";
|
|
1291
|
+
useEffect(() => {
|
|
1292
|
+
generation.current++;
|
|
1293
|
+
mounted.current = true;
|
|
1294
|
+
inFlight.current = false;
|
|
1295
|
+
sent.current = false;
|
|
1296
|
+
setBusy(false);
|
|
1297
|
+
setError("");
|
|
1298
|
+
setBatch(readIntakeDraft(pending));
|
|
1299
|
+
const sync = () => {
|
|
1300
|
+
const next = pendingState(pending);
|
|
1301
|
+
setSnapshot(next);
|
|
1302
|
+
if (next.closed) {
|
|
1303
|
+
saveIntakeDraft(pending);
|
|
1304
|
+
return;
|
|
1305
|
+
}
|
|
1306
|
+
if (sent.current && sentChannel.current === "waterfall" && next.channel === "rpc") {
|
|
648
1307
|
sent.current = false;
|
|
1308
|
+
inFlight.current = false;
|
|
649
1309
|
setBusy(false);
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
sent.current = false;
|
|
661
|
-
inFlight.current = false;
|
|
662
|
-
setBusy(false);
|
|
663
|
-
}
|
|
664
|
-
};
|
|
665
|
-
const unsubscribe = pending.subscribe?.(sync);
|
|
666
|
-
sync();
|
|
667
|
-
card.current?.focus();
|
|
1310
|
+
}
|
|
1311
|
+
};
|
|
1312
|
+
const unsubscribe = pending.subscribe?.(sync);
|
|
1313
|
+
sync();
|
|
1314
|
+
card.current?.focus();
|
|
1315
|
+
pending.holdFocus?.();
|
|
1316
|
+
const win = card.current?.ownerDocument?.defaultView;
|
|
1317
|
+
const release = () => pending.releaseFocus?.();
|
|
1318
|
+
const hold = () => {
|
|
1319
|
+
if (card.current?.contains(card.current.ownerDocument.activeElement))
|
|
668
1320
|
pending.holdFocus?.();
|
|
669
|
-
const win = card.current?.ownerDocument?.defaultView;
|
|
670
|
-
const release = () => pending.releaseFocus?.();
|
|
671
|
-
const hold = () => { if (card.current?.contains(card.current.ownerDocument.activeElement))
|
|
672
|
-
pending.holdFocus?.(); };
|
|
673
|
-
win?.addEventListener('blur', release);
|
|
674
|
-
win?.addEventListener('focus', hold);
|
|
675
|
-
return () => { generation.current++; mounted.current = false; unsubscribe?.(); pending.releaseFocus?.(); win?.removeEventListener('blur', release); win?.removeEventListener('focus', hold); };
|
|
676
|
-
}, [pending]);
|
|
677
|
-
useEffect(() => { if (draft.selected !== null)
|
|
678
|
-
optionElements.current[draft.selected]?.scrollIntoView({ block: 'nearest' }); }, [draft.selected]);
|
|
679
|
-
const update = (value) => {
|
|
680
|
-
if (inFlight.current || !editable())
|
|
681
|
-
return;
|
|
682
|
-
const current = readIntakeDraft(pending), next = { ...current, drafts: current.drafts.map((d, i) => i === current.page ? value : d) };
|
|
683
|
-
saveIntakeDraft(pending, next);
|
|
684
|
-
setBatch(next);
|
|
685
|
-
setError('');
|
|
686
|
-
pending.engage?.();
|
|
687
1321
|
};
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
1322
|
+
win?.addEventListener("blur", release);
|
|
1323
|
+
win?.addEventListener("focus", hold);
|
|
1324
|
+
return () => {
|
|
1325
|
+
generation.current++;
|
|
1326
|
+
mounted.current = false;
|
|
1327
|
+
unsubscribe?.();
|
|
1328
|
+
pending.releaseFocus?.();
|
|
1329
|
+
win?.removeEventListener("blur", release);
|
|
1330
|
+
win?.removeEventListener("focus", hold);
|
|
691
1331
|
};
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
setError('');
|
|
731
|
-
const epoch = generation.current;
|
|
732
|
-
const currentCard = () => mounted.current && generation.current === epoch;
|
|
733
|
-
const dismissing = cancel || reviewing && d.selected === 0;
|
|
734
|
-
void Promise.resolve().then(() => {
|
|
735
|
-
if (!currentCard() || pendingState(pending).closed || !dismissing && !editable())
|
|
736
|
-
throw new Error('この質問には現在回答できません。');
|
|
737
|
-
sentChannel.current = pendingState(pending).channel;
|
|
738
|
-
return dismissing ? dismissQuestion(pending) : pending.answer({ answers });
|
|
739
|
-
}).then(() => {
|
|
740
|
-
if (!currentCard())
|
|
741
|
-
return;
|
|
742
|
-
if (!pending.snapshot || pendingState(pending).closed || dismissing && pending.dismissal !== 'hide')
|
|
743
|
-
saveIntakeDraft(pending);
|
|
744
|
-
if (pending.snapshot && !dismissing && !pendingState(pending).closed) {
|
|
745
|
-
sent.current = true;
|
|
746
|
-
if (sentChannel.current === 'waterfall' && pendingState(pending).channel === 'rpc') {
|
|
747
|
-
sent.current = false;
|
|
748
|
-
inFlight.current = false;
|
|
749
|
-
if (mounted.current)
|
|
750
|
-
setBusy(false);
|
|
751
|
-
}
|
|
752
|
-
}
|
|
753
|
-
}).catch(cause => { if (currentCard()) {
|
|
754
|
-
inFlight.current = false;
|
|
755
|
-
setBusy(false);
|
|
756
|
-
setError(cause instanceof Error ? cause.message : String(cause));
|
|
757
|
-
} });
|
|
758
|
-
};
|
|
759
|
-
const keyDown = (event) => {
|
|
760
|
-
if (event.defaultPrevented || inFlight.current || composingKey(event) || event.altKey || event.shiftKey)
|
|
761
|
-
return;
|
|
762
|
-
if (event.key === 'Escape') {
|
|
763
|
-
event.preventDefault();
|
|
764
|
-
event.stopPropagation();
|
|
765
|
-
void settle(true);
|
|
766
|
-
return;
|
|
767
|
-
}
|
|
768
|
-
if (pending.review && event.key === 'Enter' && !event.ctrlKey && !event.metaKey && event.target?.tagName !== 'BUTTON' && batch.page < pending.questions.length - 1) {
|
|
769
|
-
event.preventDefault();
|
|
770
|
-
event.stopPropagation();
|
|
771
|
-
page(batch.page + 1);
|
|
772
|
-
return;
|
|
773
|
-
}
|
|
774
|
-
if (!editable())
|
|
775
|
-
return;
|
|
776
|
-
if (event.key === 'Enter' && modifiedKey(event)) {
|
|
777
|
-
event.preventDefault();
|
|
778
|
-
event.stopPropagation();
|
|
779
|
-
settle(false, true);
|
|
780
|
-
return;
|
|
781
|
-
}
|
|
782
|
-
if (editingKey(event)) {
|
|
783
|
-
if (event.key === 'Enter' && !event.ctrlKey && !event.metaKey && !event.target?.isContentEditable) {
|
|
784
|
-
event.preventDefault();
|
|
785
|
-
event.stopPropagation();
|
|
786
|
-
if (!multi || batch.page < pending.questions.length - 1)
|
|
787
|
-
settle();
|
|
788
|
-
}
|
|
789
|
-
return;
|
|
1332
|
+
}, [pending]);
|
|
1333
|
+
useEffect(() => {
|
|
1334
|
+
if (draft.selected !== null)
|
|
1335
|
+
optionElements.current[draft.selected]?.scrollIntoView({ block: "nearest" });
|
|
1336
|
+
}, [draft.selected]);
|
|
1337
|
+
const update = (value) => {
|
|
1338
|
+
if (inFlight.current || !editable())
|
|
1339
|
+
return;
|
|
1340
|
+
const current = readIntakeDraft(pending), next = { ...current, drafts: current.drafts.map((d, i) => i === current.page ? value : d) };
|
|
1341
|
+
saveIntakeDraft(pending, next);
|
|
1342
|
+
setBatch(next);
|
|
1343
|
+
setError("");
|
|
1344
|
+
pending.engage?.();
|
|
1345
|
+
};
|
|
1346
|
+
const choose = (index) => {
|
|
1347
|
+
const d = readIntakeDraft(pending).drafts[batch.page];
|
|
1348
|
+
update({ selected: index, checked: multi ? d.checked.includes(index) ? d.checked.filter((n) => n !== index) : [...d.checked, index] : [], custom: "", ordinal: "" });
|
|
1349
|
+
};
|
|
1350
|
+
const page = (index) => {
|
|
1351
|
+
const next = { ...readIntakeDraft(pending), page: index };
|
|
1352
|
+
saveIntakeDraft(pending, next);
|
|
1353
|
+
setBatch(next);
|
|
1354
|
+
setError("");
|
|
1355
|
+
card.current?.focus();
|
|
1356
|
+
};
|
|
1357
|
+
const settle = (cancel = false, all = false) => {
|
|
1358
|
+
if (inFlight.current || !mounted.current || pendingState(pending).closed || !cancel && !editable())
|
|
1359
|
+
return;
|
|
1360
|
+
const current = readIntakeDraft(pending), d = current.drafts[current.page];
|
|
1361
|
+
const answers = [];
|
|
1362
|
+
if (!cancel) {
|
|
1363
|
+
for (let i = 0; i <= (all ? pending.questions.length - 1 : current.page); i++) {
|
|
1364
|
+
const q = pending.questions[i], value = current.drafts[i], opts = reviewing ? question.options : q.options ?? [];
|
|
1365
|
+
let selected = q.multiSelect ? value.checked : value.selected === null ? [] : [value.selected];
|
|
1366
|
+
let custom = value.custom.trim();
|
|
1367
|
+
if (value.ordinal && (Number(value.ordinal) < 1 || Number(value.ordinal) > opts.length || q.multiSelect)) {
|
|
1368
|
+
setError(q.multiSelect ? "\u5165\u529B\u3057\u305F\u756A\u53F7\u306FSpace\u3067\u30C1\u30A7\u30C3\u30AF\u3057\u3066\u304F\u3060\u3055\u3044\u3002" : `\u756A\u53F7\u306F1\u301C${opts.length}\u3067\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\u3002`);
|
|
1369
|
+
return;
|
|
790
1370
|
}
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
const d = readIntakeDraft(pending).drafts[batch.page];
|
|
796
|
-
if (modified && /^[1-9]$/u.test(digit) && Number(digit) <= question.options.length) {
|
|
797
|
-
event.preventDefault();
|
|
798
|
-
event.stopPropagation();
|
|
799
|
-
choose(Number(digit) - 1);
|
|
800
|
-
card.current?.focus();
|
|
801
|
-
return;
|
|
802
|
-
}
|
|
803
|
-
if (modified)
|
|
804
|
-
return;
|
|
805
|
-
if (question.options.length && (/^[0-9]$/u.test(digit) || event.key === 'Backspace' && d.ordinal)) {
|
|
806
|
-
if (question.options.length <= 9 && (!/^[1-9]$/u.test(digit) || Number(digit) > question.options.length))
|
|
807
|
-
return;
|
|
808
|
-
event.preventDefault();
|
|
809
|
-
event.stopPropagation();
|
|
810
|
-
if (question.options.length <= 9)
|
|
811
|
-
choose(Number(digit) - 1);
|
|
812
|
-
else {
|
|
813
|
-
const ordinal = event.key === 'Backspace' ? d.ordinal.slice(0, -1) : (d.ordinal + digit).slice(0, 9);
|
|
814
|
-
const n = Number(ordinal), valid = n >= 1 && n <= question.options.length;
|
|
815
|
-
update({ ...d, ordinal, custom: '', selected: !multi && valid ? n - 1 : multi ? d.selected : null });
|
|
816
|
-
if (ordinal && !valid)
|
|
817
|
-
setError(`番号「${ordinal}」は範囲外です。Backspaceで訂正してください。`);
|
|
818
|
-
}
|
|
819
|
-
card.current?.focus();
|
|
1371
|
+
if (!reviewing && questionInputKind(q) === "choice" && opts.length && /^[0-90-9]+$/u.test(custom)) {
|
|
1372
|
+
const n = Number(custom.normalize("NFKC"));
|
|
1373
|
+
if (n < 1 || n > opts.length) {
|
|
1374
|
+
setError(`\u756A\u53F7\u306F1\u301C${opts.length}\u3067\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\u3002`);
|
|
820
1375
|
return;
|
|
1376
|
+
}
|
|
1377
|
+
selected = q.multiSelect ? [.../* @__PURE__ */ new Set([...selected, n - 1])] : [n - 1];
|
|
1378
|
+
custom = "";
|
|
821
1379
|
}
|
|
822
|
-
if (
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
if (n >= 1 && n <= question.options.length)
|
|
827
|
-
choose(n - 1);
|
|
828
|
-
return;
|
|
1380
|
+
if (!selected.length && !custom) {
|
|
1381
|
+
page(i);
|
|
1382
|
+
setError("\u9078\u629E\u80A2\u3092\u9078\u3076\u304B\u3001\u81EA\u7531\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\u3002");
|
|
1383
|
+
return;
|
|
829
1384
|
}
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
1385
|
+
answers.push({ id: q.id, selected: selected.map((n) => opts[n].label), ...custom ? { custom } : {} });
|
|
1386
|
+
}
|
|
1387
|
+
if (!all && current.page < pending.questions.length - 1) {
|
|
1388
|
+
page(current.page + 1);
|
|
1389
|
+
return;
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
inFlight.current = true;
|
|
1393
|
+
setBusy(true);
|
|
1394
|
+
setError("");
|
|
1395
|
+
const epoch = generation.current;
|
|
1396
|
+
const currentCard = () => mounted.current && generation.current === epoch;
|
|
1397
|
+
const dismissing = cancel || reviewing && d.selected === 0;
|
|
1398
|
+
void Promise.resolve().then(() => {
|
|
1399
|
+
if (!currentCard() || pendingState(pending).closed || !dismissing && !editable())
|
|
1400
|
+
throw new Error("\u3053\u306E\u8CEA\u554F\u306B\u306F\u73FE\u5728\u56DE\u7B54\u3067\u304D\u307E\u305B\u3093\u3002");
|
|
1401
|
+
sentChannel.current = pendingState(pending).channel;
|
|
1402
|
+
return dismissing ? dismissQuestion(pending) : pending.answer({ answers });
|
|
1403
|
+
}).then(() => {
|
|
1404
|
+
if (!currentCard())
|
|
1405
|
+
return;
|
|
1406
|
+
if (!pending.snapshot || pendingState(pending).closed || dismissing && pending.dismissal !== "hide")
|
|
1407
|
+
saveIntakeDraft(pending);
|
|
1408
|
+
if (pending.snapshot && !dismissing && !pendingState(pending).closed) {
|
|
1409
|
+
sent.current = true;
|
|
1410
|
+
if (sentChannel.current === "waterfall" && pendingState(pending).channel === "rpc") {
|
|
1411
|
+
sent.current = false;
|
|
1412
|
+
inFlight.current = false;
|
|
1413
|
+
if (mounted.current)
|
|
1414
|
+
setBusy(false);
|
|
835
1415
|
}
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
onBlurCapture: (event) => { if (!card.current?.contains(event.relatedTarget))
|
|
844
|
-
pending.releaseFocus?.(); },
|
|
845
|
-
children: [
|
|
846
|
-
jsxs('header', { children: [jsx('h2', { id: titleId, children: question.question }),
|
|
847
|
-
jsx('button', { type: 'button', disabled: busy || snapshot.closed, onClick: () => settle(true), 'aria-label': '質問を閉じる', children: '閉じる(Esc)' })] }),
|
|
848
|
-
jsx('p', { id: `${titleId}-keys`, children: pending.review ? '回答済みの内容です。Enterで次の質問を表示、Escで閉じます。' : hint }),
|
|
849
|
-
jsxs('div', { className: 'kiokuko-intake-body', children: [
|
|
850
|
-
reviewing ? jsx(MarkdownText, { text: question.detail, labels: reviewCopy.labels }) : question.detail ? jsx('p', { children: question.detail }) : null,
|
|
851
|
-
!pending.review && !snapshot.closed && snapshot.state === 'continued' ? jsx('p', { children: '処理は継続中です。この質問には後から回答できます。' }) : null,
|
|
852
|
-
snapshot.countdown ? jsx('p', { children: `回答待ち: ${Math.ceil(snapshot.countdown.remainingMs / 1000)}秒${snapshot.countdown.running ? '' : '(操作中は停止)'}` }) : null,
|
|
853
|
-
pending.review ? jsx('p', { children: `回答済み: ${pending.review.find(a => a.id === question.id)?.selected.join('、') ?? ''} ${pending.review.find(a => a.id === question.id)?.custom ?? ''}` }) : null,
|
|
854
|
-
!pending.review && !editable() ? jsx('p', { role: 'status', children: snapshot.closed ? 'この質問は終了しました。' : '回答経路の接続を待っています。' }) : null,
|
|
855
|
-
jsx('div', { 'aria-label': '選択肢', 'aria-describedby': `${titleId}-keys`, children: question.options.map((option, index) => jsxs('button', {
|
|
856
|
-
type: 'button', className: 'kiokuko-intake-option', disabled,
|
|
857
|
-
ref: (el) => { optionElements.current[index] = el; },
|
|
858
|
-
...(multi ? { role: 'checkbox', 'aria-checked': draft.checked.includes(index) } : { 'aria-pressed': draft.selected === index }),
|
|
859
|
-
...(!pending.review ? shortcutAria(index, question.options.length) : {}),
|
|
860
|
-
onClick: () => choose(index),
|
|
861
|
-
onKeyDown: (event) => {
|
|
862
|
-
if (event.key === 'Enter' && !multi && !composingKey(event) && !event.ctrlKey && !event.metaKey && !event.shiftKey && !event.altKey
|
|
863
|
-
&& readIntakeDraft(pending).drafts[batch.page].selected === index) {
|
|
864
|
-
event.preventDefault();
|
|
865
|
-
event.stopPropagation();
|
|
866
|
-
settle();
|
|
867
|
-
}
|
|
868
|
-
},
|
|
869
|
-
children: [jsx('strong', { children: `${index + 1}. ${option.label}` }), option.description ? jsx('span', { children: option.description }) : null,
|
|
870
|
-
!pending.review ? jsx('kbd', { className: 'kiokuko-intake-shortcut', 'aria-hidden': true, children: shortcutLabel(index, multi) }) : null],
|
|
871
|
-
}, index)) }),
|
|
872
|
-
!reviewing ? jsx('label', { htmlFor: `${titleId}-custom`, children: inputKind === 'search' ? '検索(数字も検索語として入力できます)' : inputKind === 'value' ? '値を入力' : '自由入力(任意・Shift+Enterで改行)' }) : null,
|
|
873
|
-
!reviewing ? jsx('textarea', { id: `${titleId}-custom`, rows: 1, disabled, value: draft.custom,
|
|
874
|
-
onChange: (e) => update({ ...emptyDraft(), checked: draft.checked, custom: e.target.value }),
|
|
875
|
-
}) : null,
|
|
876
|
-
] }),
|
|
877
|
-
jsxs('footer', { children: [
|
|
878
|
-
batch.page > 0 ? jsx('button', { type: 'button', disabled: busy, onClick: () => page(batch.page - 1), children: '前の質問' }) : null,
|
|
879
|
-
pending.questions.length > 1 ? jsx('span', { children: `${batch.page + 1}/${pending.questions.length}` }) : null,
|
|
880
|
-
jsx('span', { role: 'status', 'aria-live': 'polite', children: error || (busy ? '送信中…' : draft.ordinal ? `入力番号: ${draft.ordinal}` : multi ? `${draft.checked.length}件を選択中` : draft.selected === null ? '' : `${draft.selected + 1}. ${question.options[draft.selected].label}を選択中`) }),
|
|
881
|
-
pending.review ? batch.page < pending.questions.length - 1 ? jsx('button', { type: 'button', onClick: () => page(batch.page + 1), children: '次の質問(Enter)' }) : null
|
|
882
|
-
: jsx('button', { type: 'button', disabled: disabled || (multi ? !draft.checked.length && !draft.custom.trim() : draft.selected === null && !draft.custom.trim()), onClick: () => settle(), children: batch.page < pending.questions.length - 1 ? '次の質問(Enter)' : `確定(${multi ? shortcutPlatform().label + '+' : ''}Enter)` }),
|
|
883
|
-
] }),
|
|
884
|
-
],
|
|
1416
|
+
}
|
|
1417
|
+
}).catch((cause) => {
|
|
1418
|
+
if (currentCard()) {
|
|
1419
|
+
inFlight.current = false;
|
|
1420
|
+
setBusy(false);
|
|
1421
|
+
setError(cause instanceof Error ? cause.message : String(cause));
|
|
1422
|
+
}
|
|
885
1423
|
});
|
|
1424
|
+
};
|
|
1425
|
+
const keyDown = (event) => {
|
|
1426
|
+
if (event.defaultPrevented || inFlight.current || composingKey(event) || event.altKey || event.shiftKey)
|
|
1427
|
+
return;
|
|
1428
|
+
if (event.key === "Escape") {
|
|
1429
|
+
event.preventDefault();
|
|
1430
|
+
event.stopPropagation();
|
|
1431
|
+
void settle(true);
|
|
1432
|
+
return;
|
|
1433
|
+
}
|
|
1434
|
+
if (pending.review && event.key === "Enter" && !event.ctrlKey && !event.metaKey && event.target?.tagName !== "BUTTON" && batch.page < pending.questions.length - 1) {
|
|
1435
|
+
event.preventDefault();
|
|
1436
|
+
event.stopPropagation();
|
|
1437
|
+
page(batch.page + 1);
|
|
1438
|
+
return;
|
|
1439
|
+
}
|
|
1440
|
+
if (!editable())
|
|
1441
|
+
return;
|
|
1442
|
+
if (event.key === "Enter" && modifiedKey(event)) {
|
|
1443
|
+
event.preventDefault();
|
|
1444
|
+
event.stopPropagation();
|
|
1445
|
+
settle(false, true);
|
|
1446
|
+
return;
|
|
1447
|
+
}
|
|
1448
|
+
if (editingKey(event)) {
|
|
1449
|
+
if (event.key === "Enter" && !event.ctrlKey && !event.metaKey && !event.target?.isContentEditable) {
|
|
1450
|
+
event.preventDefault();
|
|
1451
|
+
event.stopPropagation();
|
|
1452
|
+
if (!multi || batch.page < pending.questions.length - 1)
|
|
1453
|
+
settle();
|
|
1454
|
+
}
|
|
1455
|
+
return;
|
|
1456
|
+
}
|
|
1457
|
+
const modified = modifiedKey(event);
|
|
1458
|
+
if ((event.ctrlKey || event.metaKey) && !modified)
|
|
1459
|
+
return;
|
|
1460
|
+
const digit = /^(?:Digit|Numpad)([0-9])$/u.exec(event.code ?? "")?.[1] ?? event.key;
|
|
1461
|
+
const d = readIntakeDraft(pending).drafts[batch.page];
|
|
1462
|
+
if (modified && /^[1-9]$/u.test(digit) && Number(digit) <= question.options.length) {
|
|
1463
|
+
event.preventDefault();
|
|
1464
|
+
event.stopPropagation();
|
|
1465
|
+
choose(Number(digit) - 1);
|
|
1466
|
+
card.current?.focus();
|
|
1467
|
+
return;
|
|
1468
|
+
}
|
|
1469
|
+
if (modified)
|
|
1470
|
+
return;
|
|
1471
|
+
if (question.options.length && (/^[0-9]$/u.test(digit) || event.key === "Backspace" && d.ordinal)) {
|
|
1472
|
+
if (question.options.length <= 9 && (!/^[1-9]$/u.test(digit) || Number(digit) > question.options.length))
|
|
1473
|
+
return;
|
|
1474
|
+
event.preventDefault();
|
|
1475
|
+
event.stopPropagation();
|
|
1476
|
+
if (question.options.length <= 9)
|
|
1477
|
+
choose(Number(digit) - 1);
|
|
1478
|
+
else {
|
|
1479
|
+
const ordinal = event.key === "Backspace" ? d.ordinal.slice(0, -1) : (d.ordinal + digit).slice(0, 9);
|
|
1480
|
+
const n = Number(ordinal), valid = n >= 1 && n <= question.options.length;
|
|
1481
|
+
update({ ...d, ordinal, custom: "", selected: !multi && valid ? n - 1 : multi ? d.selected : null });
|
|
1482
|
+
if (ordinal && !valid)
|
|
1483
|
+
setError(`\u756A\u53F7\u300C${ordinal}\u300D\u306F\u7BC4\u56F2\u5916\u3067\u3059\u3002Backspace\u3067\u8A02\u6B63\u3057\u3066\u304F\u3060\u3055\u3044\u3002`);
|
|
1484
|
+
}
|
|
1485
|
+
card.current?.focus();
|
|
1486
|
+
return;
|
|
1487
|
+
}
|
|
1488
|
+
if (event.key === " " && multi && d.ordinal) {
|
|
1489
|
+
event.preventDefault();
|
|
1490
|
+
event.stopPropagation();
|
|
1491
|
+
const n = Number(d.ordinal);
|
|
1492
|
+
if (n >= 1 && n <= question.options.length)
|
|
1493
|
+
choose(n - 1);
|
|
1494
|
+
return;
|
|
1495
|
+
}
|
|
1496
|
+
if (event.key === "Enter" && event.target?.tagName !== "BUTTON") {
|
|
1497
|
+
event.preventDefault();
|
|
1498
|
+
event.stopPropagation();
|
|
1499
|
+
if (!multi || batch.page < pending.questions.length - 1)
|
|
1500
|
+
settle();
|
|
1501
|
+
}
|
|
1502
|
+
};
|
|
1503
|
+
useShortcutGroup(card, keyDown);
|
|
1504
|
+
const disabled = busy || !editable(), titleId = `kiokuko-intake-${pending.key}`;
|
|
1505
|
+
const hint = question.options.length ? `${shortcutPlatform().label}+1\u301C${Math.min(9, question.options.length)}\u3001\u307E\u305F\u306F\u6570\u5B57\u3067${multi ? "\u30C1\u30A7\u30C3\u30AF\u5207\u66FF" : "\u9078\u629E"}\u3002${question.options.length > 9 ? `10\u4EE5\u4E0A\u306F\u756A\u53F7\u3092\u7D9A\u3051\u3066\u5165\u529B\u3001Backspace\u3067\u8A02\u6B63${multi ? "\u3001Space\u3067\u30C1\u30A7\u30C3\u30AF" : ""}\u3002` : ""}${multi ? `${shortcutPlatform().label}+Enter\u3067\u5168\u56DE\u7B54\u3092\u9001\u4FE1\u3002` : "Enter\u3067\u78BA\u5B9A\u3002"}` : `\u81EA\u7531\u5165\u529B\u5F8C\u3001${multi ? shortcutPlatform().label + "+" : ""}Enter\u3067\u78BA\u5B9A\u3002Shift+Enter\u3067\u6539\u884C\u3002`;
|
|
1506
|
+
return jsxs("section", {
|
|
1507
|
+
className: "kiokuko-intake",
|
|
1508
|
+
tabIndex: 0,
|
|
1509
|
+
"data-kiokuko-shortcuts": "",
|
|
1510
|
+
ref: (el) => {
|
|
1511
|
+
card.current = el;
|
|
1512
|
+
},
|
|
1513
|
+
"aria-labelledby": titleId,
|
|
1514
|
+
"aria-busy": busy,
|
|
1515
|
+
onKeyDown: keyDown,
|
|
1516
|
+
onFocusCapture: () => pending.holdFocus?.(),
|
|
1517
|
+
onBlurCapture: (event) => {
|
|
1518
|
+
if (!card.current?.contains(event.relatedTarget))
|
|
1519
|
+
pending.releaseFocus?.();
|
|
1520
|
+
},
|
|
1521
|
+
children: [
|
|
1522
|
+
jsxs("header", { children: [
|
|
1523
|
+
jsx("h2", { id: titleId, children: question.question }),
|
|
1524
|
+
jsx("button", { type: "button", disabled: busy || snapshot.closed, onClick: () => settle(true), "aria-label": "\u8CEA\u554F\u3092\u9589\u3058\u308B", children: "\u9589\u3058\u308B\uFF08Esc\uFF09" })
|
|
1525
|
+
] }),
|
|
1526
|
+
jsx("p", { id: `${titleId}-keys`, children: pending.review ? "\u56DE\u7B54\u6E08\u307F\u306E\u5185\u5BB9\u3067\u3059\u3002Enter\u3067\u6B21\u306E\u8CEA\u554F\u3092\u8868\u793A\u3001Esc\u3067\u9589\u3058\u307E\u3059\u3002" : hint }),
|
|
1527
|
+
jsxs("div", { className: "kiokuko-intake-body", children: [
|
|
1528
|
+
reviewing ? jsx(MarkdownText, { text: question.detail, labels: reviewCopy.labels }) : question.detail ? jsx("p", { children: question.detail, ...question.id.startsWith("coding-lisp-") ? { "data-coding-goal": true, style: { whiteSpace: "pre-wrap", overflowWrap: "anywhere" } } : {} }) : null,
|
|
1529
|
+
!pending.review && !snapshot.closed && snapshot.state === "continued" ? jsx("p", { children: "\u51E6\u7406\u306F\u7D99\u7D9A\u4E2D\u3067\u3059\u3002\u3053\u306E\u8CEA\u554F\u306B\u306F\u5F8C\u304B\u3089\u56DE\u7B54\u3067\u304D\u307E\u3059\u3002" }) : null,
|
|
1530
|
+
snapshot.countdown ? jsx("p", { children: `\u56DE\u7B54\u5F85\u3061: ${Math.ceil(snapshot.countdown.remainingMs / 1e3)}\u79D2${snapshot.countdown.running ? "" : "\uFF08\u64CD\u4F5C\u4E2D\u306F\u505C\u6B62\uFF09"}` }) : null,
|
|
1531
|
+
pending.review ? jsx("p", { children: `\u56DE\u7B54\u6E08\u307F: ${pending.review.find((a) => a.id === question.id)?.selected.join("\u3001") ?? ""} ${pending.review.find((a) => a.id === question.id)?.custom ?? ""}` }) : null,
|
|
1532
|
+
!pending.review && !editable() ? jsx("p", { role: "status", children: snapshot.closed ? "\u3053\u306E\u8CEA\u554F\u306F\u7D42\u4E86\u3057\u307E\u3057\u305F\u3002" : "\u56DE\u7B54\u7D4C\u8DEF\u306E\u63A5\u7D9A\u3092\u5F85\u3063\u3066\u3044\u307E\u3059\u3002" }) : null,
|
|
1533
|
+
jsx("div", { "aria-label": "\u9078\u629E\u80A2", "aria-describedby": `${titleId}-keys`, children: question.options.map((option, index) => jsxs("button", {
|
|
1534
|
+
type: "button",
|
|
1535
|
+
className: "kiokuko-intake-option",
|
|
1536
|
+
disabled,
|
|
1537
|
+
ref: (el) => {
|
|
1538
|
+
optionElements.current[index] = el;
|
|
1539
|
+
},
|
|
1540
|
+
...multi ? { role: "checkbox", "aria-checked": draft.checked.includes(index) } : { "aria-pressed": draft.selected === index },
|
|
1541
|
+
...!pending.review ? shortcutAria(index, question.options.length) : {},
|
|
1542
|
+
onClick: () => choose(index),
|
|
1543
|
+
onKeyDown: (event) => {
|
|
1544
|
+
if (event.key === "Enter" && !multi && !composingKey(event) && !event.ctrlKey && !event.metaKey && !event.shiftKey && !event.altKey && readIntakeDraft(pending).drafts[batch.page].selected === index) {
|
|
1545
|
+
event.preventDefault();
|
|
1546
|
+
event.stopPropagation();
|
|
1547
|
+
settle();
|
|
1548
|
+
}
|
|
1549
|
+
},
|
|
1550
|
+
children: [
|
|
1551
|
+
jsx("strong", { children: `${index + 1}. ${option.label}` }),
|
|
1552
|
+
option.description ? jsx("span", { children: option.description }) : null,
|
|
1553
|
+
!pending.review ? jsx("kbd", { className: "kiokuko-intake-shortcut", "aria-hidden": true, children: shortcutLabel(index, multi) }) : null
|
|
1554
|
+
]
|
|
1555
|
+
}, index)) }),
|
|
1556
|
+
!reviewing ? jsx("label", { htmlFor: `${titleId}-custom`, children: inputKind === "search" ? "\u691C\u7D22\uFF08\u6570\u5B57\u3082\u691C\u7D22\u8A9E\u3068\u3057\u3066\u5165\u529B\u3067\u304D\u307E\u3059\uFF09" : inputKind === "value" ? "\u5024\u3092\u5165\u529B" : "\u81EA\u7531\u5165\u529B\uFF08\u4EFB\u610F\u30FBShift+Enter\u3067\u6539\u884C\uFF09" }) : null,
|
|
1557
|
+
!reviewing ? jsx("textarea", {
|
|
1558
|
+
id: `${titleId}-custom`,
|
|
1559
|
+
rows: 1,
|
|
1560
|
+
disabled,
|
|
1561
|
+
value: draft.custom,
|
|
1562
|
+
onChange: (e) => update({ ...emptyDraft(), checked: draft.checked, custom: e.target.value })
|
|
1563
|
+
}) : null
|
|
1564
|
+
] }),
|
|
1565
|
+
jsxs("footer", { children: [
|
|
1566
|
+
batch.page > 0 ? jsx("button", { type: "button", disabled: busy, onClick: () => page(batch.page - 1), children: "\u524D\u306E\u8CEA\u554F" }) : null,
|
|
1567
|
+
pending.questions.length > 1 ? jsx("span", { children: `${batch.page + 1}/${pending.questions.length}` }) : null,
|
|
1568
|
+
jsx("span", { role: "status", "aria-live": "polite", children: error || (busy ? "\u9001\u4FE1\u4E2D\u2026" : draft.ordinal ? `\u5165\u529B\u756A\u53F7: ${draft.ordinal}` : multi ? `${draft.checked.length}\u4EF6\u3092\u9078\u629E\u4E2D` : draft.selected === null ? "" : `${draft.selected + 1}. ${question.options[draft.selected].label}\u3092\u9078\u629E\u4E2D`) }),
|
|
1569
|
+
pending.review ? batch.page < pending.questions.length - 1 ? jsx("button", { type: "button", onClick: () => page(batch.page + 1), children: "\u6B21\u306E\u8CEA\u554F\uFF08Enter\uFF09" }) : null : jsx("button", { type: "button", disabled: disabled || (multi ? !draft.checked.length && !draft.custom.trim() : draft.selected === null && !draft.custom.trim()), onClick: () => settle(), children: batch.page < pending.questions.length - 1 ? "\u6B21\u306E\u8CEA\u554F\uFF08Enter\uFF09" : `\u78BA\u5B9A\uFF08${multi ? shortcutPlatform().label + "+" : ""}Enter\uFF09` })
|
|
1570
|
+
] })
|
|
1571
|
+
]
|
|
1572
|
+
});
|
|
886
1573
|
}
|
|
887
1574
|
function installIntakeStyle() {
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
1575
|
+
if (typeof document === "undefined")
|
|
1576
|
+
return void 0;
|
|
1577
|
+
const style = document.createElement("style");
|
|
1578
|
+
style.textContent = `
|
|
892
1579
|
.kiokuko-numbered-picker{min-width:0;position:relative}
|
|
893
1580
|
.kiokuko-numbered-options{border:1px solid var(--dsw-alias-border-l4,#bbb);padding:8px;border-radius:8px;max-height:50dvh;overflow:auto;min-width:0}
|
|
894
1581
|
.kiokuko-numbered-options[hidden]{display:none}
|
|
@@ -915,627 +1602,805 @@ window.__ModuleLoader__.load({
|
|
|
915
1602
|
.kiokuko-intake footer [role=status]{flex:1;min-width:0;font-size:12px;overflow-wrap:anywhere}
|
|
916
1603
|
@media(max-width:640px){.kiokuko-intake{position:fixed;inset:auto 8px 8px;width:auto;max-width:none;max-height:min(480px,75dvh);z-index:10}}
|
|
917
1604
|
`;
|
|
918
|
-
|
|
919
|
-
|
|
1605
|
+
document.head.appendChild(style);
|
|
1606
|
+
return () => style.remove();
|
|
920
1607
|
}
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
1608
|
+
var REVIEW_NS = "kiokuko-session-log-download";
|
|
1609
|
+
var REVIEW_KIND = "kiokuko-diff-review";
|
|
1610
|
+
var REVIEW_TAB_ID = "kiokuko-dsh/diff-review";
|
|
1611
|
+
var REVIEW_ERRORS = {
|
|
1612
|
+
repository_changed: "\u5DEE\u5206\u306E\u53D6\u5F97\u4E2D\u307E\u305F\u306F\u53D6\u5F97\u5F8C\u306B\u5909\u66F4\u304C\u3042\u308A\u307E\u3057\u305F\u3002\u53D6\u5F97\u3057\u76F4\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
|
|
1613
|
+
file_changed: "\u73FE\u5728\u306E\u30D5\u30A1\u30A4\u30EB\u306F\u53D6\u5F97\u6E08\u307F\u306E\u5DEE\u5206\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u5DEE\u5206\u5185\u306E\u5185\u5BB9\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
|
|
1614
|
+
file_link_unavailable: "\u3053\u306E\u5DEE\u5206\u304B\u3089\u73FE\u5728\u306E\u30D5\u30A1\u30A4\u30EB\u3078\u306F\u79FB\u52D5\u3067\u304D\u307E\u305B\u3093\u3002",
|
|
1615
|
+
turn_snapshot_unavailable: "\u3053\u306E\u30BF\u30FC\u30F3\u306E\u5DEE\u5206\u8A18\u9332\u306F\u5229\u7528\u3067\u304D\u307E\u305B\u3093\u3002\u73FE\u5728\u306E\u5DEE\u5206\u3092\u9078\u3093\u3067\u53D6\u5F97\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
|
|
1616
|
+
repo_unavailable: "\u3053\u306E\u30BB\u30C3\u30B7\u30E7\u30F3\u306E Git \u30EA\u30DD\u30B8\u30C8\u30EA\u3092\u78BA\u8A8D\u3067\u304D\u307E\u305B\u3093\u3002",
|
|
1617
|
+
session_unavailable: "\u9078\u629E\u4E2D\u306E\u30BB\u30C3\u30B7\u30E7\u30F3\u3092\u78BA\u8A8D\u3067\u304D\u307E\u305B\u3093\u3002\u958B\u304D\u76F4\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
|
|
1618
|
+
session_workspace_mismatch: "\u30BB\u30C3\u30B7\u30E7\u30F3\u3068\u4F5C\u696D\u5834\u6240\u304C\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002",
|
|
1619
|
+
diff_too_large: "\u5DEE\u5206\u304C\u4E0A\u9650\u3092\u8D85\u3048\u307E\u3057\u305F\u3002\u5BFE\u8C61\u3092\u7D5E\u3063\u3066\u53D6\u5F97\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
|
|
1620
|
+
git_timeout: "Git \u306E\u8AAD\u307F\u53D6\u308A\u304C\u6642\u9593\u5185\u306B\u7D42\u308F\u308A\u307E\u305B\u3093\u3067\u3057\u305F\u3002",
|
|
1621
|
+
git_unavailable: "Git \u306E\u8AAD\u307F\u53D6\u308A\u30B5\u30FC\u30D3\u30B9\u3092\u5229\u7528\u3067\u304D\u307E\u305B\u3093\u3002",
|
|
1622
|
+
model_unavailable: "\u9078\u629E\u3057\u305F\u30E2\u30C7\u30EB\u3092\u5229\u7528\u3067\u304D\u307E\u305B\u3093\u3002\u30E2\u30C7\u30EB\u306E\u8A2D\u5B9A\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
|
|
1623
|
+
analysis_in_progress: "\u3053\u306E\u30BB\u30C3\u30B7\u30E7\u30F3\u3067\u306F\u5206\u6790\u304C\u9032\u884C\u4E2D\u3067\u3059\u3002\u5B8C\u4E86\u307E\u305F\u306F\u505C\u6B62\u5F8C\u306B\u518D\u8A66\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
|
|
1624
|
+
capture_in_progress: "\u5DEE\u5206\u3092\u53D6\u5F97\u4E2D\u3067\u3059\u3002\u5B8C\u4E86\u5F8C\u306B\u518D\u8A66\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
|
|
1625
|
+
review_expired: "\u7D50\u679C\u306E\u4FDD\u5B58\u671F\u9593\u304C\u904E\u304E\u307E\u3057\u305F\u3002\u5DEE\u5206\u3092\u53D6\u5F97\u3057\u76F4\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
|
|
1626
|
+
unmerged_conflict: "\u7AF6\u5408\u4E2D\u306E\u30D5\u30A1\u30A4\u30EB\u304C\u3042\u308A\u307E\u3059\u3002\u89E3\u6C7A\u3057\u3066\u304B\u3089\u5206\u6790\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
|
|
1627
|
+
unsafe_review_input: "\u30EC\u30D3\u30E5\u30FC\u306E\u76EE\u7684\u306B\u79D8\u5BC6\u60C5\u5831\u3089\u3057\u3044\u5185\u5BB9\u304C\u3042\u308A\u307E\u3059\u3002\u524A\u9664\u3057\u3066\u518D\u8A66\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
|
|
1628
|
+
analysis_timeout: "\u5206\u6790\u304C\u6642\u9593\u5185\u306B\u7D42\u308F\u308A\u307E\u305B\u3093\u3067\u3057\u305F\u3002\u53D6\u5F97\u6E08\u307F\u306E\u5DEE\u5206\u306F\u8868\u793A\u3057\u3066\u3044\u307E\u3059\u3002",
|
|
1629
|
+
provider_failure: "\u30E2\u30C7\u30EB\u3078\u306E\u63A5\u7D9A\u306B\u5931\u6557\u3057\u307E\u3057\u305F\u3002\u53D6\u5F97\u6E08\u307F\u306E\u5DEE\u5206\u306F\u8868\u793A\u3057\u3066\u3044\u307E\u3059\u3002",
|
|
1630
|
+
invalid_model_json: "\u30E2\u30C7\u30EB\u306E\u51FA\u529B\u3092\u8AAD\u307F\u53D6\u308C\u307E\u305B\u3093\u3067\u3057\u305F\u3002\u53D6\u5F97\u6E08\u307F\u306E\u5DEE\u5206\u306F\u8868\u793A\u3057\u3066\u3044\u307E\u3059\u3002",
|
|
1631
|
+
invalid_model_schema: "\u30E2\u30C7\u30EB\u306E\u51FA\u529B\u5F62\u5F0F\u304C\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u53D6\u5F97\u6E08\u307F\u306E\u5DEE\u5206\u306F\u8868\u793A\u3057\u3066\u3044\u307E\u3059\u3002",
|
|
1632
|
+
model_incomplete: "\u30E2\u30C7\u30EB\u306E\u56DE\u7B54\u304C\u5B8C\u4E86\u3057\u307E\u305B\u3093\u3067\u3057\u305F\u3002\u53D6\u5F97\u6E08\u307F\u306E\u5DEE\u5206\u306F\u8868\u793A\u3057\u3066\u3044\u307E\u3059\u3002",
|
|
1633
|
+
invalid_evidence_reference: "\u5B58\u5728\u3057\u306A\u3044\u6839\u62E0\u3092\u53C2\u7167\u3059\u308B\u8AAC\u660E\u3092\u9664\u5916\u3057\u307E\u3057\u305F\u3002",
|
|
1634
|
+
context_limit: "\u6587\u8108\u304C\u5165\u529B\u4E0A\u9650\u3092\u8D85\u3048\u3001\u5206\u6790\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002",
|
|
1635
|
+
chunk_or_hunk_limit: "\u5165\u529B\u4E0A\u9650\u306B\u3088\u308A\u4E00\u90E8\u306E\u5909\u66F4\u3092\u5206\u6790\u3057\u3066\u3044\u307E\u305B\u3093\u3002",
|
|
1636
|
+
cancelled: "\u5206\u6790\u3092\u505C\u6B62\u3057\u307E\u3057\u305F\u3002\u53D6\u5F97\u6E08\u307F\u306E\u5DEE\u5206\u306F\u8868\u793A\u3057\u3066\u3044\u307E\u3059\u3002"
|
|
950
1637
|
};
|
|
951
|
-
function reviewErrorMessage(code) {
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
1638
|
+
function reviewErrorMessage(code) {
|
|
1639
|
+
return REVIEW_ERRORS[code] ?? `\u30EC\u30D3\u30E5\u30FC\u3092\u7D9A\u884C\u3067\u304D\u307E\u305B\u3093\uFF08${code}\uFF09\u3002`;
|
|
1640
|
+
}
|
|
1641
|
+
var REVIEW_STATES = { "facts-only": "\u5DEE\u5206\u306E\u307F", analyzing: "\u5206\u6790\u4E2D", analyzed: "\u5206\u6790\u5B8C\u4E86", partial: "\u4E00\u90E8\u672A\u5206\u6790", cancelled: "\u505C\u6B62", failed: "\u5206\u6790\u5931\u6557" };
|
|
1642
|
+
var REVIEW_CONTEXT_SOURCES = { "current-run": "\u5B9F\u884C\u4E2D\u306E\u30BF\u30B9\u30AF", "completed-run": "\u5B8C\u4E86\u6E08\u307F\u30BF\u30B9\u30AF", "review-input": "\u5229\u7528\u8005\u5165\u529B", unavailable: "\u53D6\u5F97\u4E0D\u53EF" };
|
|
1643
|
+
var REVIEW_MEMORY_STATES = { available: "\u53D6\u5F97\u6E08\u307F", empty: "\u8A72\u5F53\u306A\u3057", unavailable: "\u53D6\u5F97\u4E0D\u53EF", withheld: "\u4FDD\u7559", mismatch: "\u4E0D\u4E00\u81F4" };
|
|
1644
|
+
var REVIEW_FRESHNESS = { current: "\u73FE\u5728\u3068\u4E00\u81F4", stale: "\u53D6\u5F97\u5F8C\u306B\u5909\u66F4\u3042\u308A", unknown: "\u73FE\u5728\u3068\u306E\u4E00\u81F4\u306F\u672A\u78BA\u8A8D" };
|
|
956
1645
|
function initialReviewSession() {
|
|
957
|
-
|
|
958
|
-
|
|
1646
|
+
return {
|
|
1647
|
+
loading: false,
|
|
1648
|
+
busy: false,
|
|
1649
|
+
cancelling: false,
|
|
1650
|
+
error: "",
|
|
1651
|
+
availability: "unknown",
|
|
1652
|
+
modelAvailability: "unknown",
|
|
1653
|
+
models: [],
|
|
1654
|
+
untracked: [],
|
|
1655
|
+
turns: [],
|
|
1656
|
+
mode: "current",
|
|
1657
|
+
selected: [],
|
|
1658
|
+
selectedUntracked: [],
|
|
1659
|
+
modelKey: "",
|
|
1660
|
+
purpose: "",
|
|
1661
|
+
runId: "",
|
|
1662
|
+
activeFileId: "",
|
|
1663
|
+
fileListOpen: true
|
|
1664
|
+
};
|
|
959
1665
|
}
|
|
960
1666
|
function matchesReviewMode(review, mode, turnSeq) {
|
|
961
|
-
|
|
1667
|
+
return review?.snapshot.mode === mode && (mode !== "turn" || review.snapshot.turnSeq === turnSeq);
|
|
962
1668
|
}
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
1669
|
+
var DiffReviewClientController = class {
|
|
1670
|
+
store = createSnapshotStore({ bySession: {} });
|
|
1671
|
+
timers = /* @__PURE__ */ new Map();
|
|
1672
|
+
generations = /* @__PURE__ */ new Map();
|
|
1673
|
+
closed = false;
|
|
1674
|
+
nextGeneration(sessionId) {
|
|
1675
|
+
const next = (this.generations.get(sessionId) ?? 0) + 1;
|
|
1676
|
+
this.generations.set(sessionId, next);
|
|
1677
|
+
return next;
|
|
1678
|
+
}
|
|
1679
|
+
current(sessionId) {
|
|
1680
|
+
return this.store.getSnapshot().bySession[sessionId] ?? initialReviewSession();
|
|
1681
|
+
}
|
|
1682
|
+
publish(sessionId, next) {
|
|
1683
|
+
if (this.closed)
|
|
1684
|
+
return;
|
|
1685
|
+
this.store.update((state) => {
|
|
1686
|
+
state.bySession = { ...state.bySession, [sessionId]: next };
|
|
1687
|
+
});
|
|
1688
|
+
}
|
|
1689
|
+
change(sessionId, changes) {
|
|
1690
|
+
this.publish(sessionId, { ...this.current(sessionId), ...changes });
|
|
1691
|
+
}
|
|
1692
|
+
url(sessionId, reviewId) {
|
|
1693
|
+
const url = new URL("/api/kiokuko.diff-review", hostBase());
|
|
1694
|
+
url.searchParams.set("sessionId", sessionId);
|
|
1695
|
+
if (reviewId)
|
|
1696
|
+
url.searchParams.set("reviewId", reviewId);
|
|
1697
|
+
return url;
|
|
1698
|
+
}
|
|
1699
|
+
async json(url, body) {
|
|
1700
|
+
let response;
|
|
1701
|
+
try {
|
|
1702
|
+
response = await fetch(url, body ? { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(body) } : {});
|
|
1703
|
+
} catch {
|
|
1704
|
+
throw new Error("DSH \u306B\u63A5\u7D9A\u3067\u304D\u307E\u305B\u3093\u3002\u63A5\u7D9A\u3092\u78BA\u8A8D\u3057\u3066\u518D\u8A66\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002");
|
|
972
1705
|
}
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
1706
|
+
let value;
|
|
1707
|
+
try {
|
|
1708
|
+
value = await response.json();
|
|
1709
|
+
} catch {
|
|
1710
|
+
throw new Error("DSH \u306E\u5FDC\u7B54\u3092\u8AAD\u307F\u53D6\u308C\u307E\u305B\u3093\u3002\u518D\u8A66\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002");
|
|
978
1711
|
}
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
1712
|
+
if (!response.ok)
|
|
1713
|
+
throw new Error(typeof value.code === "string" ? reviewErrorMessage(value.code) : `HTTP ${response.status}`);
|
|
1714
|
+
return value;
|
|
1715
|
+
}
|
|
1716
|
+
async load(sessionId) {
|
|
1717
|
+
const generation = this.nextGeneration(sessionId);
|
|
1718
|
+
this.change(sessionId, { loading: true, error: "" });
|
|
1719
|
+
try {
|
|
1720
|
+
const response = await this.json(this.url(sessionId));
|
|
1721
|
+
if (this.generations.get(sessionId) !== generation)
|
|
1722
|
+
return;
|
|
1723
|
+
const review = response.review;
|
|
1724
|
+
const models = response.models ?? [];
|
|
1725
|
+
const modelKeys = models.map((item) => JSON.stringify([item.provider, item.model]));
|
|
1726
|
+
const current = this.current(sessionId);
|
|
1727
|
+
const untracked = response.untracked ?? [];
|
|
1728
|
+
this.change(sessionId, {
|
|
1729
|
+
loading: false,
|
|
1730
|
+
busy: review?.state === "analyzing",
|
|
1731
|
+
cancelling: false,
|
|
1732
|
+
availability: String(response.availability),
|
|
1733
|
+
modelAvailability: String(response.modelAvailability ?? "unknown"),
|
|
1734
|
+
models,
|
|
1735
|
+
review,
|
|
1736
|
+
untracked,
|
|
1737
|
+
selectedUntracked: current.selectedUntracked.filter((path) => untracked.includes(path)),
|
|
1738
|
+
turns: response.turns ?? [],
|
|
1739
|
+
...review ? {
|
|
1740
|
+
selected: current.review?.reviewId === review.reviewId ? current.selected.filter((id) => review.snapshot.files.some((file) => file.fileId === id && file.kind === "text")) : review.snapshot.files.filter((file) => file.kind === "text").map((file) => file.fileId),
|
|
1741
|
+
activeFileId: current.review?.reviewId === review.reviewId && review.snapshot.files.some((file) => file.fileId === current.activeFileId) ? current.activeFileId : review.snapshot.files[0]?.fileId || ""
|
|
1742
|
+
} : {},
|
|
1743
|
+
modelKey: modelKeys.includes(current.modelKey) ? current.modelKey : "",
|
|
1744
|
+
error: !review && current.review ? "\u4FDD\u5B58\u671F\u9593\u304C\u904E\u304E\u307E\u3057\u305F\u3002\u5DEE\u5206\u3092\u53D6\u5F97\u3057\u76F4\u3057\u3066\u304F\u3060\u3055\u3044\u3002" : ""
|
|
1745
|
+
});
|
|
1746
|
+
if (review?.state === "analyzing")
|
|
1747
|
+
this.poll(sessionId, review.reviewId);
|
|
1748
|
+
} catch (error) {
|
|
1749
|
+
if (this.generations.get(sessionId) === generation)
|
|
1750
|
+
this.change(sessionId, { loading: false, busy: false, error: messageOf2(error) });
|
|
986
1751
|
}
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
return
|
|
1752
|
+
}
|
|
1753
|
+
async capture(sessionId) {
|
|
1754
|
+
const current = this.current(sessionId);
|
|
1755
|
+
if (current.busy || current.loading || current.cancelling || current.review?.state === "analyzing")
|
|
1756
|
+
return;
|
|
1757
|
+
const generation = this.nextGeneration(sessionId);
|
|
1758
|
+
this.change(sessionId, { busy: true, error: "" });
|
|
1759
|
+
try {
|
|
1760
|
+
const review = await this.json(this.url(sessionId), {
|
|
1761
|
+
action: "capture",
|
|
1762
|
+
sessionId,
|
|
1763
|
+
mode: current.mode,
|
|
1764
|
+
...current.mode === "turn" ? { turnSeq: current.turnSeq } : {},
|
|
1765
|
+
untracked: current.selectedUntracked,
|
|
1766
|
+
requestId: crypto.randomUUID()
|
|
1767
|
+
});
|
|
1768
|
+
if (this.generations.get(sessionId) !== generation)
|
|
1769
|
+
return;
|
|
1770
|
+
this.change(sessionId, {
|
|
1771
|
+
loading: false,
|
|
1772
|
+
busy: false,
|
|
1773
|
+
review,
|
|
1774
|
+
selected: review.snapshot.files.filter((file) => file.kind === "text").map((file) => file.fileId),
|
|
1775
|
+
activeFileId: review.snapshot.files[0]?.fileId ?? "",
|
|
1776
|
+
fileListOpen: false
|
|
1777
|
+
});
|
|
1778
|
+
await this.load(sessionId);
|
|
1779
|
+
} catch (error) {
|
|
1780
|
+
if (this.generations.get(sessionId) === generation)
|
|
1781
|
+
this.change(sessionId, { loading: false, busy: false, error: messageOf2(error) });
|
|
1005
1782
|
}
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
const current = this.current(sessionId);
|
|
1017
|
-
const untracked = response.untracked ?? [];
|
|
1018
|
-
this.change(sessionId, { loading: false, busy: review?.state === 'analyzing', cancelling: false,
|
|
1019
|
-
availability: String(response.availability), modelAvailability: String(response.modelAvailability ?? 'unknown'), models, review,
|
|
1020
|
-
untracked, selectedUntracked: current.selectedUntracked.filter(path => untracked.includes(path)), turns: response.turns ?? [],
|
|
1021
|
-
...(review ? { selected: current.review?.reviewId === review.reviewId ? current.selected.filter(id => review.snapshot.files.some(file => file.fileId === id && file.kind === 'text')) : review.snapshot.files.filter(file => file.kind === 'text').map(file => file.fileId),
|
|
1022
|
-
activeFileId: current.review?.reviewId === review.reviewId && review.snapshot.files.some(file => file.fileId === current.activeFileId) ? current.activeFileId : review.snapshot.files[0]?.fileId || '' } : {}),
|
|
1023
|
-
modelKey: modelKeys.includes(current.modelKey) ? current.modelKey : '',
|
|
1024
|
-
error: !review && current.review ? '保存期間が過ぎました。差分を取得し直してください。' : '' });
|
|
1025
|
-
if (review?.state === 'analyzing')
|
|
1026
|
-
this.poll(sessionId, review.reviewId);
|
|
1027
|
-
}
|
|
1028
|
-
catch (error) {
|
|
1029
|
-
if (this.generations.get(sessionId) === generation)
|
|
1030
|
-
this.change(sessionId, { loading: false, busy: false, error: messageOf(error) });
|
|
1031
|
-
}
|
|
1783
|
+
}
|
|
1784
|
+
async analyze(sessionId) {
|
|
1785
|
+
const current = this.current(sessionId);
|
|
1786
|
+
if (current.busy || current.loading || current.cancelling || !current.review || !matchesReviewMode(current.review, current.mode, current.turnSeq) || current.review.state === "analyzing" || !current.selected.length || !current.modelKey)
|
|
1787
|
+
return;
|
|
1788
|
+
let provider, model;
|
|
1789
|
+
try {
|
|
1790
|
+
[provider, model] = JSON.parse(current.modelKey);
|
|
1791
|
+
} catch {
|
|
1792
|
+
return;
|
|
1032
1793
|
}
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
}
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1794
|
+
if (!provider || !model)
|
|
1795
|
+
return;
|
|
1796
|
+
const generation = this.nextGeneration(sessionId);
|
|
1797
|
+
this.change(sessionId, { busy: true, error: "" });
|
|
1798
|
+
try {
|
|
1799
|
+
const review = await this.json(this.url(sessionId), {
|
|
1800
|
+
action: "analyze",
|
|
1801
|
+
sessionId,
|
|
1802
|
+
reviewId: current.review.reviewId,
|
|
1803
|
+
requestId: crypto.randomUUID(),
|
|
1804
|
+
selectedFileIds: current.selected,
|
|
1805
|
+
provider,
|
|
1806
|
+
model,
|
|
1807
|
+
...current.purpose.trim() ? { purpose: current.purpose.trim() } : {},
|
|
1808
|
+
...current.runId ? { runId: current.runId } : {}
|
|
1809
|
+
});
|
|
1810
|
+
if (this.generations.get(sessionId) !== generation)
|
|
1811
|
+
return;
|
|
1812
|
+
this.change(sessionId, { loading: false, review });
|
|
1813
|
+
this.poll(sessionId, review.reviewId);
|
|
1814
|
+
} catch (error) {
|
|
1815
|
+
if (this.generations.get(sessionId) === generation)
|
|
1816
|
+
this.change(sessionId, { busy: false, error: messageOf2(error) });
|
|
1052
1817
|
}
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
try {
|
|
1069
|
-
const review = await this.json(this.url(sessionId), { action: 'analyze', sessionId, reviewId: current.review.reviewId,
|
|
1070
|
-
requestId: crypto.randomUUID(), selectedFileIds: current.selected, provider, model,
|
|
1071
|
-
...(current.purpose.trim() ? { purpose: current.purpose.trim() } : {}), ...(current.runId ? { runId: current.runId } : {}) });
|
|
1072
|
-
if (this.generations.get(sessionId) !== generation)
|
|
1073
|
-
return;
|
|
1074
|
-
this.change(sessionId, { loading: false, review });
|
|
1075
|
-
this.poll(sessionId, review.reviewId);
|
|
1076
|
-
}
|
|
1077
|
-
catch (error) {
|
|
1078
|
-
if (this.generations.get(sessionId) === generation)
|
|
1079
|
-
this.change(sessionId, { busy: false, error: messageOf(error) });
|
|
1818
|
+
}
|
|
1819
|
+
poll(sessionId, reviewId) {
|
|
1820
|
+
clearTimeout(this.timers.get(sessionId));
|
|
1821
|
+
const generation = this.generations.get(sessionId);
|
|
1822
|
+
const tick = async () => {
|
|
1823
|
+
try {
|
|
1824
|
+
const review = await this.json(this.url(sessionId, reviewId));
|
|
1825
|
+
if (this.generations.get(sessionId) !== generation || this.current(sessionId).review?.reviewId !== reviewId || this.current(sessionId).cancelling)
|
|
1826
|
+
return;
|
|
1827
|
+
this.change(sessionId, { review, busy: review.state === "analyzing", error: "" });
|
|
1828
|
+
if (review.state === "analyzing")
|
|
1829
|
+
this.timers.set(sessionId, setTimeout(() => void tick(), document.hidden ? 5e3 : 1e3));
|
|
1830
|
+
} catch (error) {
|
|
1831
|
+
if (this.generations.get(sessionId) === generation && this.current(sessionId).review?.reviewId === reviewId && !this.current(sessionId).cancelling) {
|
|
1832
|
+
this.change(sessionId, { busy: false, error: messageOf2(error) });
|
|
1080
1833
|
}
|
|
1834
|
+
}
|
|
1835
|
+
};
|
|
1836
|
+
this.timers.set(sessionId, setTimeout(() => void tick(), 500));
|
|
1837
|
+
}
|
|
1838
|
+
async refreshReview(sessionId, reviewId) {
|
|
1839
|
+
const generation = this.nextGeneration(sessionId);
|
|
1840
|
+
clearTimeout(this.timers.get(sessionId));
|
|
1841
|
+
this.change(sessionId, { loading: true, error: "" });
|
|
1842
|
+
try {
|
|
1843
|
+
const review = await this.json(this.url(sessionId, reviewId));
|
|
1844
|
+
if (this.generations.get(sessionId) === generation && this.current(sessionId).review?.reviewId === reviewId) {
|
|
1845
|
+
this.change(sessionId, { loading: false, busy: review.state === "analyzing", review, error: "" });
|
|
1846
|
+
if (review.state === "analyzing")
|
|
1847
|
+
this.poll(sessionId, reviewId);
|
|
1848
|
+
}
|
|
1849
|
+
} catch (error) {
|
|
1850
|
+
if (this.generations.get(sessionId) === generation && this.current(sessionId).review?.reviewId === reviewId)
|
|
1851
|
+
this.change(sessionId, { loading: false, busy: false, error: messageOf2(error) });
|
|
1081
1852
|
}
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
this.change(sessionId, { busy: false, error: messageOf(error) });
|
|
1097
|
-
}
|
|
1098
|
-
}
|
|
1099
|
-
};
|
|
1100
|
-
this.timers.set(sessionId, setTimeout(() => void tick(), 500));
|
|
1853
|
+
}
|
|
1854
|
+
async cancel(sessionId, reviewId) {
|
|
1855
|
+
if (this.current(sessionId).cancelling || this.current(sessionId).review?.reviewId !== reviewId)
|
|
1856
|
+
return;
|
|
1857
|
+
const generation = this.nextGeneration(sessionId);
|
|
1858
|
+
clearTimeout(this.timers.get(sessionId));
|
|
1859
|
+
this.change(sessionId, { loading: false, cancelling: true, error: "" });
|
|
1860
|
+
try {
|
|
1861
|
+
const review = await this.json(this.url(sessionId), { action: "cancel", sessionId, reviewId });
|
|
1862
|
+
if (this.generations.get(sessionId) === generation && this.current(sessionId).review?.reviewId === reviewId)
|
|
1863
|
+
this.change(sessionId, { review, busy: false, cancelling: false, error: "" });
|
|
1864
|
+
} catch (error) {
|
|
1865
|
+
if (this.generations.get(sessionId) === generation && this.current(sessionId).review?.reviewId === reviewId)
|
|
1866
|
+
this.change(sessionId, { busy: false, cancelling: false, error: messageOf2(error) });
|
|
1101
1867
|
}
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1868
|
+
}
|
|
1869
|
+
exportUrl(sessionId, reviewId, format) {
|
|
1870
|
+
const url = this.url(sessionId, reviewId);
|
|
1871
|
+
url.searchParams.set("format", format);
|
|
1872
|
+
return url.toString();
|
|
1873
|
+
}
|
|
1874
|
+
async openCurrentFile(sessionId, reviewId, fileId, openFile) {
|
|
1875
|
+
try {
|
|
1876
|
+
const url = this.url(sessionId, reviewId);
|
|
1877
|
+
url.searchParams.set("format", "file-link");
|
|
1878
|
+
url.searchParams.set("fileId", fileId);
|
|
1879
|
+
const response = await this.json(url);
|
|
1880
|
+
if (typeof response.address !== "string" || !response.address.startsWith("dsh-resource://file/session/") || !openFile(response.address)) {
|
|
1881
|
+
throw new Error("\u30D5\u30A1\u30A4\u30EB\u30BF\u30D6\u3092\u958B\u3051\u307E\u305B\u3093\u3002\u53D6\u5F97\u6E08\u307F\u306E\u5DEE\u5206\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002");
|
|
1882
|
+
}
|
|
1883
|
+
} catch (error) {
|
|
1884
|
+
this.change(sessionId, { error: messageOf2(error) });
|
|
1118
1885
|
}
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1886
|
+
}
|
|
1887
|
+
async dispose() {
|
|
1888
|
+
this.closed = true;
|
|
1889
|
+
for (const timer of this.timers.values())
|
|
1890
|
+
clearTimeout(timer);
|
|
1891
|
+
this.timers.clear();
|
|
1892
|
+
}
|
|
1893
|
+
};
|
|
1894
|
+
function SnapshotDiff(props) {
|
|
1895
|
+
return jsxs("div", { className: "kiokuko-review-diff", children: props.file.hunks.map((hunk) => {
|
|
1896
|
+
let oldLine = hunk.oldStart, newLine = hunk.newStart;
|
|
1897
|
+
return jsxs("section", { id: `kiokuko-review-${props.file.fileId}-${hunk.id}`, tabIndex: -1, children: [
|
|
1898
|
+
jsx("h4", { children: `@@ -${hunk.oldStart} +${hunk.newStart} @@` }),
|
|
1899
|
+
jsx("pre", { children: hunk.lines.map((line, index) => {
|
|
1900
|
+
const prefix = line[0];
|
|
1901
|
+
const old = prefix === "+" || prefix === "\\" ? "" : String(oldLine++);
|
|
1902
|
+
const next = prefix === "-" || prefix === "\\" ? "" : String(newLine++);
|
|
1903
|
+
return jsx("div", {
|
|
1904
|
+
className: prefix === "+" ? "added" : prefix === "-" ? "removed" : "",
|
|
1905
|
+
tabIndex: -1,
|
|
1906
|
+
"data-snapshot-id": props.snapshotId,
|
|
1907
|
+
"data-file-id": props.file.fileId,
|
|
1908
|
+
"data-hunk-id": hunk.id,
|
|
1909
|
+
...old ? { "data-old-line": old } : {},
|
|
1910
|
+
...next ? { "data-new-line": next } : {},
|
|
1911
|
+
children: `${old.padStart(5)} ${next.padStart(5)} ${line}`
|
|
1912
|
+
}, index);
|
|
1913
|
+
}) })
|
|
1914
|
+
] }, hunk.id);
|
|
1915
|
+
}) });
|
|
1916
|
+
}
|
|
1917
|
+
function NumberedPicker(props) {
|
|
1918
|
+
const [open, setOpen] = useState(false), [index, setIndex] = useState(-1), [ordinal, setOrdinal] = useState("");
|
|
1919
|
+
const buffer = useRef(""), selected = useRef(-1), group = useRef(null), trigger = useRef(null);
|
|
1920
|
+
const shown = props.inline || open;
|
|
1921
|
+
const close = () => {
|
|
1922
|
+
setOpen(false);
|
|
1923
|
+
buffer.current = "";
|
|
1924
|
+
setOrdinal("");
|
|
1925
|
+
trigger.current?.focus();
|
|
1926
|
+
};
|
|
1927
|
+
useEffect(() => {
|
|
1928
|
+
if (shown && !props.inline)
|
|
1929
|
+
group.current?.focus();
|
|
1930
|
+
}, [shown, props.inline]);
|
|
1931
|
+
const pick = (n, confirm) => {
|
|
1932
|
+
const option = props.options[n];
|
|
1933
|
+
if (!option || option.disabled && !props.onToggle)
|
|
1934
|
+
return;
|
|
1935
|
+
selected.current = n;
|
|
1936
|
+
setIndex(n);
|
|
1937
|
+
if (props.inline || confirm)
|
|
1938
|
+
props.onChoose(option.value);
|
|
1939
|
+
if (confirm && !props.inline)
|
|
1940
|
+
close();
|
|
1941
|
+
};
|
|
1942
|
+
const keys = (e) => {
|
|
1943
|
+
if (!shown || props.disabled || composingKey(e) || editingKey(e) || e.altKey || e.shiftKey || e.defaultPrevented)
|
|
1944
|
+
return;
|
|
1945
|
+
if (e.key === "Escape" && !props.inline) {
|
|
1946
|
+
e.preventDefault();
|
|
1947
|
+
e.stopPropagation();
|
|
1948
|
+
close();
|
|
1949
|
+
return;
|
|
1134
1950
|
}
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1951
|
+
const optionButton = e.target?.closest?.("button[data-kiokuko-option]");
|
|
1952
|
+
if (e.key === " " && props.onToggle && optionButton && !e.ctrlKey && !e.metaKey) {
|
|
1953
|
+
e.preventDefault();
|
|
1954
|
+
e.stopPropagation();
|
|
1955
|
+
const option = props.options[Number(optionButton.dataset.kiokukoOption)];
|
|
1956
|
+
if (option && !option.disabled)
|
|
1957
|
+
props.onToggle(option.value);
|
|
1958
|
+
return;
|
|
1139
1959
|
}
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1960
|
+
if ((e.key === "Enter" || e.key === " ") && e.target?.tagName === "BUTTON")
|
|
1961
|
+
return;
|
|
1962
|
+
const modified = modifiedKey(e);
|
|
1963
|
+
if ((e.ctrlKey || e.metaKey) && !modified)
|
|
1964
|
+
return;
|
|
1965
|
+
const digit = /^(?:Digit|Numpad)([0-9])$/u.exec(e.code ?? "")?.[1] ?? e.key;
|
|
1966
|
+
if (/^[0-9]$/u.test(digit) && (!modified || digit !== "0") || !modified && e.key === "Backspace" && buffer.current) {
|
|
1967
|
+
e.preventDefault();
|
|
1968
|
+
e.stopPropagation();
|
|
1969
|
+
buffer.current = modified || props.options.length <= 9 ? digit : e.key === "Backspace" ? buffer.current.slice(0, -1) : (buffer.current + digit).slice(0, 9);
|
|
1970
|
+
setOrdinal(buffer.current);
|
|
1971
|
+
pick(Number(buffer.current) - 1, false);
|
|
1972
|
+
return;
|
|
1153
1973
|
}
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1974
|
+
if (modified)
|
|
1975
|
+
return;
|
|
1976
|
+
if (e.key === "Enter" || e.key === " " && props.onToggle) {
|
|
1977
|
+
e.preventDefault();
|
|
1978
|
+
e.stopPropagation();
|
|
1979
|
+
const n = buffer.current ? Number(buffer.current) - 1 : selected.current;
|
|
1980
|
+
const item = props.options[n];
|
|
1981
|
+
if (!item)
|
|
1982
|
+
return;
|
|
1983
|
+
if (e.key === " ") {
|
|
1984
|
+
if (!item.disabled)
|
|
1985
|
+
props.onToggle?.(item.value);
|
|
1986
|
+
} else
|
|
1987
|
+
pick(n, true);
|
|
1988
|
+
buffer.current = "";
|
|
1989
|
+
setOrdinal("");
|
|
1159
1990
|
}
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
props.onToggle(option.value);
|
|
1213
|
-
return;
|
|
1214
|
-
}
|
|
1215
|
-
if ((e.key === 'Enter' || e.key === ' ') && e.target?.tagName === 'BUTTON')
|
|
1216
|
-
return;
|
|
1217
|
-
const modified = modifiedKey(e);
|
|
1218
|
-
if ((e.ctrlKey || e.metaKey) && !modified)
|
|
1219
|
-
return;
|
|
1220
|
-
const digit = /^(?:Digit|Numpad)([0-9])$/u.exec(e.code ?? '')?.[1] ?? e.key;
|
|
1221
|
-
if (/^[0-9]$/u.test(digit) && (!modified || digit !== '0') || !modified && e.key === 'Backspace' && buffer.current) {
|
|
1222
|
-
e.preventDefault();
|
|
1223
|
-
e.stopPropagation();
|
|
1224
|
-
buffer.current = modified || props.options.length <= 9 ? digit : e.key === 'Backspace' ? buffer.current.slice(0, -1) : (buffer.current + digit).slice(0, 9);
|
|
1225
|
-
setOrdinal(buffer.current);
|
|
1226
|
-
pick(Number(buffer.current) - 1, false);
|
|
1227
|
-
return;
|
|
1228
|
-
}
|
|
1229
|
-
if (modified)
|
|
1230
|
-
return;
|
|
1231
|
-
if (e.key === 'Enter' || e.key === ' ' && props.onToggle) {
|
|
1232
|
-
e.preventDefault();
|
|
1233
|
-
e.stopPropagation();
|
|
1234
|
-
const n = buffer.current ? Number(buffer.current) - 1 : selected.current;
|
|
1235
|
-
const item = props.options[n];
|
|
1236
|
-
if (!item)
|
|
1237
|
-
return;
|
|
1238
|
-
if (e.key === ' ') {
|
|
1239
|
-
if (!item.disabled)
|
|
1240
|
-
props.onToggle?.(item.value);
|
|
1241
|
-
}
|
|
1242
|
-
else
|
|
1243
|
-
pick(n, true);
|
|
1244
|
-
buffer.current = '';
|
|
1245
|
-
setOrdinal('');
|
|
1246
|
-
}
|
|
1247
|
-
};
|
|
1248
|
-
useShortcutGroup(group, keys);
|
|
1249
|
-
// Keep the group mounted so a popup opened after its parent mounts acquires
|
|
1250
|
-
// the same document listener and relinquishes ownership when hidden.
|
|
1251
|
-
return jsxs('div', { className: 'kiokuko-numbered-picker', children: [
|
|
1252
|
-
!props.inline ? jsx('button', { type: 'button', ref: trigger, disabled: props.disabled, 'aria-haspopup': 'dialog', 'aria-expanded': open,
|
|
1253
|
-
onClick: () => setOpen(!open), children: `${props.label}: ${props.options.find(o => o.value === props.value)?.label ?? '選択'}` }) : null,
|
|
1254
|
-
jsxs('section', { hidden: !shown, tabIndex: 0, ref: (el) => { group.current = el; },
|
|
1255
|
-
'data-kiokuko-shortcuts': '', role: props.inline ? 'group' : 'dialog', 'aria-label': props.label, className: 'kiokuko-numbered-options', onKeyDown: keys,
|
|
1256
|
-
children: [jsx('p', { children: `${props.label} — 数字 / ${shortcutPlatform().label}+1〜9で選択。${props.inline ? 'Spaceでチェック切替。' : 'Enterで確定、Escで閉じる。'}10以上は連続入力、Backspaceで訂正。` }),
|
|
1257
|
-
jsx('p', { role: 'status', children: ordinal ? `入力番号: ${ordinal}${Number(ordinal) < 1 || Number(ordinal) > props.options.length ? '(範囲外)' : ''}` : '' }),
|
|
1258
|
-
...props.options.map((o, n) => jsxs('div', { className: 'kiokuko-review-file-row', children: [
|
|
1259
|
-
props.onToggle ? jsx('input', { type: 'checkbox', checked: props.checked?.includes(o.value) ?? false, disabled: props.disabled || o.disabled,
|
|
1260
|
-
'aria-label': `${o.label} を選択対象にする`, onChange: () => props.onToggle?.(o.value) }) : null,
|
|
1261
|
-
jsxs('button', { type: 'button', 'data-kiokuko-option': n, disabled: props.disabled || !props.onToggle && o.disabled, 'aria-pressed': (index < 0 ? props.value === o.value : index === n), ...shortcutAria(n, props.options.length),
|
|
1262
|
-
onClick: () => { buffer.current = ''; setOrdinal(''); pick(n, !props.inline); },
|
|
1263
|
-
children: [jsx('span', { children: `${n + 1}. ${o.label}` }), jsx('kbd', { children: shortcutLabel(n, !!props.onToggle) })] }),
|
|
1264
|
-
] }, o.value)),
|
|
1265
|
-
!props.inline ? jsx('button', { type: 'button', onClick: close, children: '閉じる(Esc)' }) : null,
|
|
1266
|
-
] }),
|
|
1267
|
-
] });
|
|
1991
|
+
};
|
|
1992
|
+
useShortcutGroup(group, keys);
|
|
1993
|
+
return jsxs("div", { className: "kiokuko-numbered-picker", children: [
|
|
1994
|
+
!props.inline ? jsx("button", {
|
|
1995
|
+
type: "button",
|
|
1996
|
+
ref: trigger,
|
|
1997
|
+
disabled: props.disabled,
|
|
1998
|
+
"aria-haspopup": "dialog",
|
|
1999
|
+
"aria-expanded": open,
|
|
2000
|
+
onClick: () => setOpen(!open),
|
|
2001
|
+
children: `${props.label}: ${props.options.find((o) => o.value === props.value)?.label ?? "\u9078\u629E"}`
|
|
2002
|
+
}) : null,
|
|
2003
|
+
jsxs("section", {
|
|
2004
|
+
hidden: !shown,
|
|
2005
|
+
tabIndex: 0,
|
|
2006
|
+
ref: (el) => {
|
|
2007
|
+
group.current = el;
|
|
2008
|
+
},
|
|
2009
|
+
"data-kiokuko-shortcuts": "",
|
|
2010
|
+
role: props.inline ? "group" : "dialog",
|
|
2011
|
+
"aria-label": props.label,
|
|
2012
|
+
className: "kiokuko-numbered-options",
|
|
2013
|
+
onKeyDown: keys,
|
|
2014
|
+
children: [
|
|
2015
|
+
jsx("p", { children: `${props.label} \u2014 \u6570\u5B57 / ${shortcutPlatform().label}+1\u301C9\u3067\u9078\u629E\u3002${props.inline ? "Space\u3067\u30C1\u30A7\u30C3\u30AF\u5207\u66FF\u3002" : "Enter\u3067\u78BA\u5B9A\u3001Esc\u3067\u9589\u3058\u308B\u3002"}10\u4EE5\u4E0A\u306F\u9023\u7D9A\u5165\u529B\u3001Backspace\u3067\u8A02\u6B63\u3002` }),
|
|
2016
|
+
jsx("p", { role: "status", children: ordinal ? `\u5165\u529B\u756A\u53F7: ${ordinal}${Number(ordinal) < 1 || Number(ordinal) > props.options.length ? "\uFF08\u7BC4\u56F2\u5916\uFF09" : ""}` : "" }),
|
|
2017
|
+
...props.options.map((o, n) => jsxs("div", { className: "kiokuko-review-file-row", children: [
|
|
2018
|
+
props.onToggle ? jsx("input", {
|
|
2019
|
+
type: "checkbox",
|
|
2020
|
+
checked: props.checked?.includes(o.value) ?? false,
|
|
2021
|
+
disabled: props.disabled || o.disabled,
|
|
2022
|
+
"aria-label": `${o.label} \u3092\u9078\u629E\u5BFE\u8C61\u306B\u3059\u308B`,
|
|
2023
|
+
onChange: () => props.onToggle?.(o.value)
|
|
2024
|
+
}) : null,
|
|
2025
|
+
jsxs("button", {
|
|
2026
|
+
type: "button",
|
|
2027
|
+
"data-kiokuko-option": n,
|
|
2028
|
+
disabled: props.disabled || !props.onToggle && o.disabled,
|
|
2029
|
+
"aria-pressed": index < 0 ? props.value === o.value : index === n,
|
|
2030
|
+
...shortcutAria(n, props.options.length),
|
|
2031
|
+
onClick: () => {
|
|
2032
|
+
buffer.current = "";
|
|
2033
|
+
setOrdinal("");
|
|
2034
|
+
pick(n, !props.inline);
|
|
2035
|
+
},
|
|
2036
|
+
children: [jsx("span", { children: `${n + 1}. ${o.label}` }), jsx("kbd", { children: shortcutLabel(n, !!props.onToggle) })]
|
|
2037
|
+
})
|
|
2038
|
+
] }, o.value)),
|
|
2039
|
+
!props.inline ? jsx("button", { type: "button", onClick: close, children: "\u9589\u3058\u308B\uFF08Esc\uFF09" }) : null
|
|
2040
|
+
]
|
|
2041
|
+
})
|
|
2042
|
+
] });
|
|
1268
2043
|
}
|
|
1269
2044
|
function DiffReviewTab(props) {
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
const reviewMatchesSelection = matchesReviewMode(review, state.mode, state.turnSeq);
|
|
1292
|
-
const active = review?.snapshot.files.find(file => file.fileId === state.activeFileId) ?? review?.snapshot.files[0];
|
|
1293
|
-
const selectFile = (fileId) => controller.change(sessionId, { selected: state.selected.includes(fileId)
|
|
1294
|
-
? state.selected.filter(id => id !== fileId) : [...state.selected, fileId] });
|
|
1295
|
-
const visitEvidence = (id, anchor) => {
|
|
1296
|
-
const [fileId, hunkId] = id.split(':');
|
|
1297
|
-
if (!fileId || !review?.snapshot.files.some(file => file.fileId === fileId))
|
|
1298
|
-
return;
|
|
1299
|
-
controller.change(sessionId, { activeFileId: fileId, fileListOpen: false });
|
|
1300
|
-
requestAnimationFrame(() => {
|
|
1301
|
-
if (!hunkId) {
|
|
1302
|
-
document.getElementById(`kiokuko-review-${review.reviewId}-detail`)?.focus();
|
|
1303
|
-
return;
|
|
1304
|
-
}
|
|
1305
|
-
const section = document.getElementById(`kiokuko-review-${fileId}-${hunkId}`);
|
|
1306
|
-
const line = anchor?.fileId === fileId && anchor.hunkId === hunkId
|
|
1307
|
-
? [...(section?.querySelectorAll('[data-old-line],[data-new-line]') ?? [])].find(element => element.dataset[anchor.side === 'old' ? 'oldLine' : 'newLine'] === String(anchor.startLine)) : undefined;
|
|
1308
|
-
const target = line ?? section;
|
|
1309
|
-
target?.focus({ preventScroll: true });
|
|
1310
|
-
target?.scrollIntoView({ block: 'center' });
|
|
1311
|
-
});
|
|
2045
|
+
const sessionId = String(props.sessionId);
|
|
2046
|
+
const useReview = props.useDiffReview;
|
|
2047
|
+
const controller = props.reviewController;
|
|
2048
|
+
const openFile = props.openCurrentFile;
|
|
2049
|
+
const useTabInfo = props.useTabInfo;
|
|
2050
|
+
const { tab } = useTabInfo();
|
|
2051
|
+
const state = useReview((value) => value.bySession[sessionId]) ?? initialReviewSession();
|
|
2052
|
+
const wasVisible = useRef(tab.visible);
|
|
2053
|
+
useEffect(() => {
|
|
2054
|
+
void controller.load(sessionId);
|
|
2055
|
+
}, [sessionId]);
|
|
2056
|
+
useEffect(() => {
|
|
2057
|
+
if (tab.visible && !wasVisible.current && state.review)
|
|
2058
|
+
void controller.refreshReview(sessionId, state.review.reviewId);
|
|
2059
|
+
wasVisible.current = tab.visible;
|
|
2060
|
+
}, [sessionId, tab.visible, state.review?.reviewId]);
|
|
2061
|
+
useEffect(() => {
|
|
2062
|
+
const onClose = () => {
|
|
2063
|
+
const review2 = controller.store.getSnapshot().bySession[sessionId]?.review;
|
|
2064
|
+
if (review2?.state === "analyzing")
|
|
2065
|
+
void controller.cancel(sessionId, review2.reviewId);
|
|
1312
2066
|
};
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
2067
|
+
tab.signal.addEventListener("abort", onClose, { once: true });
|
|
2068
|
+
return () => tab.signal.removeEventListener("abort", onClose);
|
|
2069
|
+
}, [sessionId, tab.signal]);
|
|
2070
|
+
const review = state.review;
|
|
2071
|
+
const reviewMatchesSelection = matchesReviewMode(review, state.mode, state.turnSeq);
|
|
2072
|
+
const active = review?.snapshot.files.find((file) => file.fileId === state.activeFileId) ?? review?.snapshot.files[0];
|
|
2073
|
+
const selectFile = (fileId) => controller.change(sessionId, { selected: state.selected.includes(fileId) ? state.selected.filter((id) => id !== fileId) : [...state.selected, fileId] });
|
|
2074
|
+
const visitEvidence = (id, anchor) => {
|
|
2075
|
+
const [fileId, hunkId] = id.split(":");
|
|
2076
|
+
if (!fileId || !review?.snapshot.files.some((file) => file.fileId === fileId))
|
|
2077
|
+
return;
|
|
2078
|
+
controller.change(sessionId, { activeFileId: fileId, fileListOpen: false });
|
|
2079
|
+
requestAnimationFrame(() => {
|
|
2080
|
+
if (!hunkId) {
|
|
2081
|
+
document.getElementById(`kiokuko-review-${review.reviewId}-detail`)?.focus();
|
|
2082
|
+
return;
|
|
2083
|
+
}
|
|
2084
|
+
const section = document.getElementById(`kiokuko-review-${fileId}-${hunkId}`);
|
|
2085
|
+
const line = anchor?.fileId === fileId && anchor.hunkId === hunkId ? [...section?.querySelectorAll("[data-old-line],[data-new-line]") ?? []].find((element) => element.dataset[anchor.side === "old" ? "oldLine" : "newLine"] === String(anchor.startLine)) : void 0;
|
|
2086
|
+
const target = line ?? section;
|
|
2087
|
+
target?.focus({ preventScroll: true });
|
|
2088
|
+
target?.scrollIntoView({ block: "center" });
|
|
2089
|
+
});
|
|
2090
|
+
};
|
|
2091
|
+
const analysisGroups = review?.analysis ? [
|
|
2092
|
+
{ label: "\u5F71\u97FF", items: review.analysis.impact },
|
|
2093
|
+
{ label: "\u7834\u58CA\u7684\u5909\u66F4", items: review.analysis.breakingChanges },
|
|
2094
|
+
{ label: "\u30C6\u30B9\u30C8\u306E\u4E0D\u8DB3", items: review.analysis.testGaps },
|
|
2095
|
+
{ label: "\u904E\u53BB\u5224\u65AD\u3068\u306E\u4E0D\u4E00\u81F4", items: review.analysis.memoryConflicts },
|
|
2096
|
+
{ label: "\u4EEE\u5B9A", items: review.analysis.assumptions }
|
|
2097
|
+
] : [];
|
|
2098
|
+
return jsxs("section", { className: "kiokuko-review", "aria-label": "Diff \u30EC\u30D3\u30E5\u30FC", children: [
|
|
2099
|
+
jsx("h2", { children: "Diff \u30EC\u30D3\u30E5\u30FC" }),
|
|
2100
|
+
jsxs("div", { className: "kiokuko-review-controls", children: [
|
|
2101
|
+
jsx(NumberedPicker, {
|
|
2102
|
+
label: "\u6BD4\u8F03\u5BFE\u8C61",
|
|
2103
|
+
value: state.mode,
|
|
2104
|
+
options: [
|
|
2105
|
+
{ value: "current", label: "\u672A\u30B3\u30DF\u30C3\u30C8\u5168\u4F53" },
|
|
2106
|
+
{ value: "staged", label: "\u30B9\u30C6\u30FC\u30B8\u6E08\u307F" },
|
|
2107
|
+
{ value: "unstaged", label: "\u672A\u30B9\u30C6\u30FC\u30B8" },
|
|
2108
|
+
{ value: "turn", label: "\u3053\u306E\u30BF\u30FC\u30F3" }
|
|
2109
|
+
],
|
|
2110
|
+
onChoose: (value) => controller.change(sessionId, { mode: value })
|
|
2111
|
+
}),
|
|
2112
|
+
...state.mode === "turn" ? [jsx(NumberedPicker, {
|
|
2113
|
+
label: "\u30BF\u30FC\u30F3\u5DEE\u5206",
|
|
2114
|
+
value: String(state.turnSeq ?? ""),
|
|
2115
|
+
options: [{ value: "", label: "\u9078\u629E" }, ...state.turns.map((seq) => ({ value: String(seq), label: `seq ${seq}` }))],
|
|
2116
|
+
onChoose: (value) => controller.change(sessionId, { turnSeq: value === "" ? void 0 : Number(value) })
|
|
2117
|
+
}, "turn")] : [],
|
|
2118
|
+
jsx("button", { type: "button", disabled: state.busy || state.loading || state.cancelling || review?.state === "analyzing" || state.mode === "turn" && state.turnSeq === void 0, onClick: () => void controller.capture(sessionId), children: review ? "\u53D6\u5F97\u3057\u76F4\u3059" : "\u5DEE\u5206\u3092\u53D6\u5F97" }),
|
|
2119
|
+
review ? jsx("button", { type: "button", disabled: state.loading || state.cancelling || state.busy && review.state !== "analyzing", onClick: () => void controller.refreshReview(sessionId, review.reviewId), children: "\u72B6\u614B\u3092\u78BA\u8A8D" }) : null
|
|
2120
|
+
] }),
|
|
2121
|
+
state.untracked.length ? jsx(NumberedPicker, {
|
|
2122
|
+
label: "\u672A\u8FFD\u8DE1\u30D5\u30A1\u30A4\u30EB\uFF08\u660E\u793A\u9078\u629E\uFF09",
|
|
2123
|
+
inline: true,
|
|
2124
|
+
options: state.untracked.map((path) => ({ value: path, label: path })),
|
|
2125
|
+
checked: state.selectedUntracked,
|
|
2126
|
+
onChoose: () => {
|
|
2127
|
+
},
|
|
2128
|
+
onToggle: (path) => controller.change(sessionId, { selectedUntracked: state.selectedUntracked.includes(path) ? state.selectedUntracked.filter((item) => item !== path) : [...state.selectedUntracked, path] })
|
|
2129
|
+
}) : null,
|
|
2130
|
+
jsx("p", { role: "status", "aria-live": "polite", children: state.cancelling ? "\u5206\u6790\u3092\u505C\u6B62\u4E2D" : state.loading ? "\u78BA\u8A8D\u4E2D" : state.busy ? "\u51E6\u7406\u4E2D" : state.error || (state.availability === "repo_unavailable" ? "Git \u30EA\u30DD\u30B8\u30C8\u30EA\u3092\u78BA\u8A8D\u3067\u304D\u307E\u305B\u3093" : "") }),
|
|
2131
|
+
review ? jsxs(Fragment, { children: [
|
|
2132
|
+
jsx("p", { children: `${review.snapshot.capturedAt} / ${review.snapshot.mode} / ${REVIEW_STATES[review.state] ?? review.state} / \u9BAE\u5EA6: ${REVIEW_FRESHNESS[review.freshness] ?? review.freshness}` }),
|
|
2133
|
+
jsx("p", { children: `\u6587\u8108: ${REVIEW_CONTEXT_SOURCES[review.context.source] ?? review.context.source} / \u30E1\u30E2\u30EA: ${REVIEW_MEMORY_STATES[review.context.memory] ?? review.context.memory}${review.context.reason ? ` (${review.context.reason})` : ""}` }),
|
|
2134
|
+
review.context.task ? jsx("p", { children: `\u30BF\u30B9\u30AF: ${review.context.task}` }) : null,
|
|
2135
|
+
review.context.reviewInput ? jsx("p", { children: `\u3053\u306E\u30EC\u30D3\u30E5\u30FC\u306E\u76EE\u7684\uFF08\u5229\u7528\u8005\u5165\u529B\uFF09: ${review.context.reviewInput}` }) : null,
|
|
2136
|
+
...review.context.candidates?.length ? [jsx(NumberedPicker, {
|
|
2137
|
+
label: "\u30BF\u30B9\u30AF",
|
|
2138
|
+
value: state.runId,
|
|
2139
|
+
options: [{ value: "", label: "\u6307\u5B9A\u306A\u3057" }, ...review.context.candidates.map((item) => ({ value: item.runId, label: `${item.task} (${item.status})` }))],
|
|
2140
|
+
onChoose: (value) => controller.change(sessionId, { runId: value })
|
|
2141
|
+
}, "runs")] : [],
|
|
2142
|
+
jsx("p", { children: `\u5909\u66F4\u30D5\u30A1\u30A4\u30EB: ${review.snapshot.files.length} / ${review.snapshot.totalFiles}` }),
|
|
2143
|
+
review.snapshot.totalFiles > review.snapshot.files.length ? jsx("p", { role: "status", children: `${review.snapshot.totalFiles - review.snapshot.files.length} \u4EF6\u306F\u53D6\u5F97\u4E0A\u9650\u3067\u672A\u53CE\u96C6\u3067\u3059\u3002\u5168\u4F53\u30EA\u30B9\u30AF\u306F\u672A\u78BA\u5B9A\u3067\u3059\u3002` }) : null,
|
|
2144
|
+
jsx("p", { children: `\u9001\u4FE1\u5BFE\u8C61: ${state.selected.length} \u30D5\u30A1\u30A4\u30EB / ${review.snapshot.files.filter((file) => file.kind !== "text").length} \u30D5\u30A1\u30A4\u30EB\u306F\u30C6\u30AD\u30B9\u30C8\u5206\u6790\u5BFE\u8C61\u5916` }),
|
|
2145
|
+
!reviewMatchesSelection ? jsx("p", { role: "status", children: "\u6BD4\u8F03\u5BFE\u8C61\u3092\u5909\u66F4\u3057\u307E\u3057\u305F\u3002\u300C\u53D6\u5F97\u3057\u76F4\u3059\u300D\u3067\u65B0\u3057\u3044\u5DEE\u5206\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002" }) : null,
|
|
2146
|
+
!state.selected.length ? jsx("p", { role: "status", children: review.snapshot.files.some((file) => file.kind === "text") ? "\u5206\u6790\u3059\u308B\u30C6\u30AD\u30B9\u30C8\u30D5\u30A1\u30A4\u30EB\u3092\u5909\u66F4\u30D5\u30A1\u30A4\u30EB\u4E00\u89A7\u3067\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044\u3002" : "\u5206\u6790\u3067\u304D\u308B\u30C6\u30AD\u30B9\u30C8\u30D5\u30A1\u30A4\u30EB\u304C\u3042\u308A\u307E\u305B\u3093\u3002\u5DEE\u5206\u306F\u5F15\u304D\u7D9A\u304D\u78BA\u8A8D\u3067\u304D\u307E\u3059\u3002" }) : null,
|
|
2147
|
+
jsxs("div", { className: "kiokuko-review-analysis-controls", children: [
|
|
2148
|
+
jsx(NumberedPicker, {
|
|
2149
|
+
label: "\u30E2\u30C7\u30EB",
|
|
2150
|
+
value: state.modelKey,
|
|
2151
|
+
disabled: state.busy || state.loading || state.cancelling,
|
|
2152
|
+
options: [{ value: "", label: "\u9078\u629E" }, ...state.models.map((item) => ({ value: JSON.stringify([item.provider, item.model]), label: `${item.provider}/${item.model}` }))],
|
|
2153
|
+
onChoose: (value) => controller.change(sessionId, { modelKey: value })
|
|
2154
|
+
}),
|
|
2155
|
+
jsxs("label", { children: ["\u30EC\u30D3\u30E5\u30FC\u306E\u76EE\u7684\uFF08\u4EFB\u610F\uFF09", jsx("textarea", { value: state.purpose, disabled: state.busy || state.loading || state.cancelling, maxLength: 4e3, onChange: (event) => controller.change(sessionId, { purpose: event.target.value }) })] }),
|
|
2156
|
+
jsx("button", { type: "button", disabled: state.busy || state.loading || state.cancelling || review.state === "analyzing" || !reviewMatchesSelection || !state.selected.length || !state.modelKey, onClick: () => void controller.analyze(sessionId), children: "\u5206\u6790\u3059\u308B" }),
|
|
2157
|
+
review.state === "analyzing" ? jsx("button", { type: "button", disabled: state.cancelling, onClick: () => void controller.cancel(sessionId, review.reviewId), children: state.cancelling ? "\u505C\u6B62\u4E2D" : "\u505C\u6B62" }) : null
|
|
2158
|
+
] }),
|
|
2159
|
+
!state.models.length && !state.loading ? jsxs("p", { role: "status", children: [
|
|
2160
|
+
state.modelAvailability === "no_models" ? "\u767B\u9332\u6E08\u307F\u30E2\u30C7\u30EB\u304C\u3042\u308A\u307E\u305B\u3093\u3002DSH \u306E\u30E2\u30C7\u30EB\u8A2D\u5B9A\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002" : state.modelAvailability === "catalog_error" ? "\u30E2\u30C7\u30EB\u4E00\u89A7\u3092\u53D6\u5F97\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002" : state.modelAvailability === "service_unavailable" ? "\u30E2\u30C7\u30EB\u30B5\u30FC\u30D3\u30B9\u3092\u5229\u7528\u3067\u304D\u307E\u305B\u3093\u3002DSH \u306E\u63A5\u7D9A\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002" : "\u30E2\u30C7\u30EB\u4E00\u89A7\u3092\u78BA\u8A8D\u3067\u304D\u307E\u305B\u3093\u3002DSH \u306E\u63A5\u7D9A\u3068\u30E2\u30C7\u30EB\u8A2D\u5B9A\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
|
|
2161
|
+
" ",
|
|
2162
|
+
jsx("button", { type: "button", disabled: state.busy || state.cancelling, onClick: () => void controller.load(sessionId), children: "\u30E2\u30C7\u30EB\u3092\u518D\u53D6\u5F97" })
|
|
2163
|
+
] }) : null,
|
|
2164
|
+
jsx("button", {
|
|
2165
|
+
type: "button",
|
|
2166
|
+
className: "kiokuko-review-list-toggle",
|
|
2167
|
+
onClick: () => {
|
|
2168
|
+
controller.change(sessionId, { fileListOpen: !state.fileListOpen });
|
|
2169
|
+
requestAnimationFrame(() => {
|
|
2170
|
+
const pane = document.getElementById(`kiokuko-review-${review.reviewId}-${state.fileListOpen ? "detail" : "files"}`);
|
|
2171
|
+
(pane?.querySelector("[data-kiokuko-shortcuts]") ?? pane)?.focus();
|
|
2172
|
+
});
|
|
2173
|
+
},
|
|
2174
|
+
children: state.fileListOpen ? "\u5DEE\u5206\u306B\u623B\u308B" : "\u5909\u66F4\u30D5\u30A1\u30A4\u30EB\u4E00\u89A7"
|
|
2175
|
+
}),
|
|
2176
|
+
jsxs("div", { className: "kiokuko-review-main", "data-list-open": String(state.fileListOpen), children: [
|
|
2177
|
+
jsx("nav", { id: `kiokuko-review-${review.reviewId}-files`, tabIndex: -1, "aria-label": "\u5909\u66F4\u30D5\u30A1\u30A4\u30EB", children: jsx(NumberedPicker, {
|
|
2178
|
+
label: "\u5909\u66F4\u30D5\u30A1\u30A4\u30EB",
|
|
2179
|
+
inline: true,
|
|
2180
|
+
value: active?.fileId,
|
|
2181
|
+
checked: state.selected,
|
|
2182
|
+
options: review.snapshot.files.map((file) => ({ value: file.fileId, label: `${file.displayPath} (${file.layer}, ${file.kind})`, disabled: file.kind !== "text" })),
|
|
2183
|
+
onChoose: (fileId) => controller.change(sessionId, { activeFileId: fileId }),
|
|
2184
|
+
onToggle: selectFile
|
|
2185
|
+
}) }),
|
|
2186
|
+
active ? jsxs("article", { id: `kiokuko-review-${review.reviewId}-detail`, tabIndex: -1, children: [
|
|
2187
|
+
jsx("h3", { children: active.displayPath }),
|
|
2188
|
+
active.kind === "text" && active.newDigest && review.snapshot.mode !== "turn" ? jsx("button", {
|
|
2189
|
+
type: "button",
|
|
2190
|
+
onClick: () => void controller.openCurrentFile(sessionId, review.reviewId, active.fileId, openFile),
|
|
2191
|
+
children: "\u73FE\u5728\u306E\u30D5\u30A1\u30A4\u30EB\u3078"
|
|
2192
|
+
}) : null,
|
|
2193
|
+
active.reason ? jsx("p", { children: `\u9664\u5916\u30FB\u5236\u9650: ${active.reason}` }) : null,
|
|
2194
|
+
jsx(SnapshotDiff, { file: active, snapshotId: review.snapshot.snapshotId })
|
|
2195
|
+
] }) : jsx("p", { children: "\u5909\u66F4\u306F\u3042\u308A\u307E\u305B\u3093" })
|
|
2196
|
+
] }),
|
|
2197
|
+
review.context.execution?.length ? jsxs("section", { children: [jsx("h3", { children: "\u8A18\u9332\u3055\u308C\u305F\u5B9F\u884C\u8A3C\u62E0" }), ...review.context.execution.map((item, index) => jsx("p", { children: `${item.command}: ${item.status} / \u4ECA\u56DE\u306E\u5DEE\u5206\u3068\u306E\u4E00\u81F4: ${item.snapshotMatch}` }, index))] }) : null,
|
|
2198
|
+
jsxs("section", { children: [
|
|
2199
|
+
jsx("h3", { children: "AI \u306E\u89E3\u91C8" }),
|
|
2200
|
+
jsx("p", { children: review.summary || "\u5206\u6790\u306A\u3057" }),
|
|
2201
|
+
review.analysis ? jsx("p", { children: `\u5168\u4F53\u30EA\u30B9\u30AF: ${review.analysis.overallRisk}` }) : null,
|
|
2202
|
+
...analysisGroups.filter((group) => group.items.length).map((group) => jsxs("section", { children: [jsx("h4", { children: group.label }), jsx("ul", { children: group.items.map((item, index) => jsx("li", { children: item }, index)) })] }, group.label)),
|
|
2203
|
+
...review.claims.map((claim, index) => jsxs("p", { children: [
|
|
2204
|
+
claim.text,
|
|
2205
|
+
` (\u78BA\u4FE1\u5EA6: ${claim.confidence}) `,
|
|
2206
|
+
...claim.evidenceIds.map((id) => jsx("button", { type: "button", onClick: () => visitEvidence(id, claim.anchor), children: `\u6839\u62E0 ${id}` }, id)),
|
|
2207
|
+
...claim.unverifiedAssumptions.length ? [jsx("span", { children: ` \u672A\u691C\u8A3C\u306E\u4EEE\u5B9A: ${claim.unverifiedAssumptions.join("\u3001")}` })] : []
|
|
2208
|
+
] }, index))
|
|
2209
|
+
] }),
|
|
2210
|
+
review.unanalyzedFileIds?.length ? jsx("p", { children: `\u672A\u5206\u6790: ${review.unanalyzedFileIds.map((id) => review.snapshot.files.find((file) => file.fileId === id)?.displayPath ?? id).join("\u3001")}` }) : null,
|
|
2211
|
+
review.errors.length ? jsx("p", { role: "status", children: `\u672A\u691C\u8A3C: ${review.errors.map(reviewErrorMessage).join(" ")}` }) : null,
|
|
2212
|
+
jsxs("div", { className: "kiokuko-review-exports", children: [jsx("a", { href: controller.exportUrl(sessionId, review.reviewId, "markdown"), children: "Markdown \u3092\u4FDD\u5B58" }), jsx("a", { href: controller.exportUrl(sessionId, review.reviewId, "json"), children: "JSON \u3092\u4FDD\u5B58" })] })
|
|
2213
|
+
] }) : null
|
|
2214
|
+
] });
|
|
1398
2215
|
}
|
|
1399
2216
|
function DiffReviewHeaderAction(props) {
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
2217
|
+
const openPane = props.openDiffReview;
|
|
2218
|
+
const [open, setOpen] = useState(false);
|
|
2219
|
+
const dialog = useRef(null);
|
|
2220
|
+
const trigger = useRef(null);
|
|
2221
|
+
const fallbackAbort = useRef(new AbortController());
|
|
2222
|
+
useEffect(() => {
|
|
2223
|
+
if (open && dialog.current && !dialog.current.open)
|
|
2224
|
+
dialog.current.showModal();
|
|
2225
|
+
if (!open && dialog.current?.open) {
|
|
2226
|
+
dialog.current.close();
|
|
2227
|
+
trigger.current?.focus();
|
|
2228
|
+
}
|
|
2229
|
+
}, [open]);
|
|
2230
|
+
const close = () => {
|
|
2231
|
+
fallbackAbort.current.abort();
|
|
2232
|
+
setOpen(false);
|
|
2233
|
+
trigger.current?.focus();
|
|
2234
|
+
};
|
|
2235
|
+
const openReview = () => {
|
|
2236
|
+
if (openPane())
|
|
2237
|
+
return;
|
|
2238
|
+
fallbackAbort.current = new AbortController();
|
|
2239
|
+
setOpen(true);
|
|
2240
|
+
};
|
|
2241
|
+
return jsxs(Fragment, { children: [
|
|
2242
|
+
jsx("button", { ref: trigger, type: "button", className: "kiokuko-session-log-button", onClick: openReview, children: "Diff \u30EC\u30D3\u30E5\u30FC" }),
|
|
2243
|
+
open ? jsxs("dialog", {
|
|
2244
|
+
ref: dialog,
|
|
2245
|
+
onCancel: close,
|
|
2246
|
+
onClose: close,
|
|
2247
|
+
"aria-label": "Diff \u30EC\u30D3\u30E5\u30FC",
|
|
2248
|
+
className: "kiokuko-review-fallback",
|
|
2249
|
+
children: [
|
|
2250
|
+
jsx("button", { type: "button", onClick: close, children: "\u9589\u3058\u308B" }),
|
|
2251
|
+
jsx(DiffReviewTab, { ...props, useTabInfo: () => ({ tab: { signal: fallbackAbort.current.signal, visible: true } }) })
|
|
2252
|
+
]
|
|
2253
|
+
}) : null
|
|
2254
|
+
] });
|
|
1428
2255
|
}
|
|
1429
2256
|
function installReviewStyle() {
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
2257
|
+
const style = document.createElement("style");
|
|
2258
|
+
style.dataset.pluginCss = "kiokuko-diff-review";
|
|
2259
|
+
style.textContent = `.kiokuko-review-fallback{width:min(1000px,95vw);height:min(85vh,900px);padding:8px;box-sizing:border-box}.kiokuko-review{box-sizing:border-box;height:100%;overflow:auto;padding:12px;color:var(--dsw-alias-label-primary,CanvasText);background:var(--dsw-alias-background-primary,Canvas);font:13px/1.5 var(--dsw-font-family,system-ui)}.kiokuko-review h2{margin:0 0 12px;font-size:17px}.kiokuko-review h3{font-size:14px}.kiokuko-review button,.kiokuko-review select,.kiokuko-review textarea{font:inherit;color:inherit;background:transparent;border:1px solid var(--dsw-alias-border-l4,#888);border-radius:6px;padding:6px;min-height:36px}.kiokuko-review button{cursor:pointer}.kiokuko-review button:disabled{opacity:.55;cursor:default}.kiokuko-review :focus-visible{outline:2px solid Highlight;outline-offset:2px}.kiokuko-review-controls,.kiokuko-review-analysis-controls,.kiokuko-review-exports{display:flex;flex-wrap:wrap;gap:8px;align-items:end;margin:8px 0}.kiokuko-review label{display:flex;flex-direction:column;gap:3px}.kiokuko-review fieldset label{display:inline-flex;flex-direction:row;align-items:center;margin:4px 8px}.kiokuko-review-main{display:grid;grid-template-columns:minmax(130px,32%) minmax(0,1fr);gap:10px;min-width:0}.kiokuko-review-main nav{overflow:auto;min-width:0;max-height:55vh}.kiokuko-review-main article{overflow:auto;min-width:0}.kiokuko-review-file-row{display:flex;align-items:center;overflow-wrap:anywhere}.kiokuko-review-file-row button{text-align:left;border:0;overflow-wrap:anywhere}.kiokuko-review-file-row button[aria-current=true]{font-weight:700;text-decoration:underline}.kiokuko-review-diff pre{font:12px/1.4 ui-monospace,monospace;overflow:auto;white-space:pre}.kiokuko-review-diff .added{background:color-mix(in srgb,green 15%,transparent)}.kiokuko-review-diff .removed{background:color-mix(in srgb,red 15%,transparent)}.kiokuko-review-exports a{color:inherit;text-decoration:underline}@media(max-width:600px){.kiokuko-review-main{grid-template-columns:1fr}.kiokuko-review-main nav{max-height:180px}}`;
|
|
2260
|
+
style.textContent += `.kiokuko-review{container-type:inline-size}.kiokuko-review-list-toggle{display:none}
|
|
1434
2261
|
.kiokuko-review-analysis-controls{flex-direction:column;align-items:stretch}
|
|
1435
2262
|
.kiokuko-review-analysis-controls label{min-width:0}
|
|
1436
2263
|
.kiokuko-review-analysis-controls select,.kiokuko-review-analysis-controls textarea{box-sizing:border-box;width:100%;min-width:0;max-width:100%}
|
|
1437
2264
|
.kiokuko-review-analysis-controls button{align-self:flex-start}
|
|
1438
2265
|
.kiokuko-review-diff [tabindex="-1"]:focus{outline:2px solid Highlight;outline-offset:2px}
|
|
1439
2266
|
@container (max-width:800px){.kiokuko-review-main{grid-template-columns:minmax(0,1fr)}.kiokuko-review-list-toggle{display:block}.kiokuko-review-main[data-list-open=false] nav{display:none}.kiokuko-review-main[data-list-open=true] article{display:none}}`;
|
|
1440
|
-
|
|
1441
|
-
|
|
2267
|
+
document.head.appendChild(style);
|
|
2268
|
+
return () => style.remove();
|
|
1442
2269
|
}
|
|
1443
|
-
/** Register Kiokuko's streaming Session-export browser surface. */
|
|
1444
2270
|
function apply(ctx) {
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
},
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
2271
|
+
mountModelsClient(ctx);
|
|
2272
|
+
const installApprovals = (scope, approvalScope, modern) => {
|
|
2273
|
+
scope.slots.inject("settings.general.item", () => scope.slots.register({
|
|
2274
|
+
name: "settings.general.item",
|
|
2275
|
+
id: "kiokuko-lisp-approval",
|
|
2276
|
+
locale: LOCALE_NAMESPACE,
|
|
2277
|
+
inject: () => ({ approvalScope, modern })
|
|
2278
|
+
}, LispApprovalControl));
|
|
2279
|
+
};
|
|
2280
|
+
ctx.inject?.(["settingsScope"], (scope) => installApprovals(scope, scope.settingsScope.bind({ namespace: "kiokuko-lisp" }), false));
|
|
2281
|
+
ctx.inject?.(["configForms"], (scope) => installApprovals(scope, scope.configForms.get("kiokuko-dsh"), true));
|
|
2282
|
+
const reviewController = new DiffReviewClientController();
|
|
2283
|
+
let rightSidebar;
|
|
2284
|
+
ctx.effect(() => async () => reviewController.dispose(), "kiokuko-dsh: diff review browser lifecycle");
|
|
2285
|
+
ctx.effect(installReviewStyle, "kiokuko-dsh: diff review style");
|
|
2286
|
+
ctx.inject?.(["sidebarRightTabs", "sidebarRight"], (scope) => {
|
|
2287
|
+
const t = scope.locale.bind?.(REVIEW_NS) ?? ((key) => key);
|
|
2288
|
+
scope.effect(() => {
|
|
2289
|
+
rightSidebar = scope.sidebarRight;
|
|
2290
|
+
return () => {
|
|
2291
|
+
if (rightSidebar === scope.sidebarRight)
|
|
2292
|
+
rightSidebar = void 0;
|
|
2293
|
+
};
|
|
2294
|
+
}, "kiokuko-dsh: diff review pane availability");
|
|
2295
|
+
scope.effect(() => {
|
|
2296
|
+
const dispose = scope.sidebarRightTabs.register({
|
|
2297
|
+
id: REVIEW_TAB_ID,
|
|
2298
|
+
kind: REVIEW_KIND,
|
|
2299
|
+
priority: "extension",
|
|
2300
|
+
title: () => t("review.title"),
|
|
2301
|
+
guide: [{ id: "open", order: 30, title: () => t("review.title"), description: () => t("review.description") }]
|
|
2302
|
+
});
|
|
2303
|
+
return () => {
|
|
2304
|
+
void dispose();
|
|
2305
|
+
};
|
|
2306
|
+
}, "kiokuko-dsh: diff review page");
|
|
2307
|
+
scope.effect(() => scope.slots.inject("sidebar.right.pane.tab", () => scope.slots.register({
|
|
2308
|
+
name: "sidebar.right.pane.tab",
|
|
2309
|
+
key: REVIEW_TAB_ID,
|
|
2310
|
+
locale: REVIEW_NS,
|
|
2311
|
+
inject: () => ({
|
|
2312
|
+
hooks: { diffReview: reviewController.store },
|
|
2313
|
+
reviewController,
|
|
2314
|
+
openCurrentFile: (address) => {
|
|
2315
|
+
if (!rightSidebar?.openResource)
|
|
2316
|
+
return false;
|
|
2317
|
+
try {
|
|
2318
|
+
rightSidebar.openResource(address);
|
|
2319
|
+
return true;
|
|
2320
|
+
} catch {
|
|
2321
|
+
return false;
|
|
2322
|
+
}
|
|
2323
|
+
}
|
|
2324
|
+
})
|
|
2325
|
+
}, DiffReviewTab)), "kiokuko-dsh: diff review tab body");
|
|
2326
|
+
});
|
|
2327
|
+
ctx.slots.inject("conversation.session.header.utilities", () => ctx.slots.register({
|
|
2328
|
+
name: "conversation.session.header.utilities",
|
|
2329
|
+
id: "kiokuko-diff-review-open",
|
|
2330
|
+
locale: REVIEW_NS,
|
|
2331
|
+
inject: () => ({
|
|
2332
|
+
hooks: { diffReview: reviewController.store },
|
|
2333
|
+
reviewController,
|
|
2334
|
+
openDiffReview: () => {
|
|
2335
|
+
if (!rightSidebar)
|
|
2336
|
+
return false;
|
|
2337
|
+
try {
|
|
2338
|
+
rightSidebar.openTab(REVIEW_KIND);
|
|
2339
|
+
return true;
|
|
2340
|
+
} catch {
|
|
2341
|
+
return false;
|
|
2342
|
+
}
|
|
2343
|
+
},
|
|
2344
|
+
openCurrentFile: (address) => {
|
|
2345
|
+
if (!rightSidebar?.openResource)
|
|
2346
|
+
return false;
|
|
2347
|
+
try {
|
|
2348
|
+
rightSidebar.openResource(address);
|
|
2349
|
+
return true;
|
|
2350
|
+
} catch {
|
|
2351
|
+
return false;
|
|
2352
|
+
}
|
|
2353
|
+
}
|
|
2354
|
+
})
|
|
2355
|
+
}, DiffReviewHeaderAction));
|
|
2356
|
+
ctx.slots.inject("conversation.input.left", () => ctx.slots.register({
|
|
2357
|
+
name: "conversation.input.left",
|
|
2358
|
+
id: "kiokuko-lisp-status",
|
|
2359
|
+
locale: LOCALE_NAMESPACE
|
|
2360
|
+
}, LispSessionStatus));
|
|
2361
|
+
ctx.slots.inject("conversation.composer", () => ctx.slots.register({
|
|
2362
|
+
name: "conversation.composer",
|
|
2363
|
+
priority: -10,
|
|
2364
|
+
select: intakePending,
|
|
2365
|
+
locale: LOCALE_NAMESPACE
|
|
2366
|
+
}, IntakeQuestion));
|
|
2367
|
+
ctx.effect(installIntakeStyle, "kiokuko-dsh: intake style");
|
|
2368
|
+
ctx.slots.inject("conversation.session.header.utilities", () => ctx.slots.register({
|
|
2369
|
+
name: "conversation.session.header.utilities",
|
|
2370
|
+
id: "kiokuko-deep-reports",
|
|
2371
|
+
locale: LOCALE_NAMESPACE
|
|
2372
|
+
}, DeepSessionReports));
|
|
2373
|
+
ctx.slots.inject("conversation.session.header.utilities", () => ctx.slots.register({
|
|
2374
|
+
name: "conversation.session.header.utilities",
|
|
2375
|
+
id: "kiokuko-session-notices",
|
|
2376
|
+
locale: LOCALE_NAMESPACE
|
|
2377
|
+
}, (props) => jsx(DeepSessionReports, { ...props, notices: true })));
|
|
2378
|
+
ctx.uiConversation.events.register(completionReportDefinition);
|
|
2379
|
+
ctx.slots.inject("conversation.chat.node", () => ctx.slots.register({
|
|
2380
|
+
name: "conversation.chat.node",
|
|
2381
|
+
key: "kiokuko-completion-report",
|
|
2382
|
+
locale: LOCALE_NAMESPACE
|
|
2383
|
+
}, CompletionReport));
|
|
2384
|
+
const controller = new SessionLogDownloadController();
|
|
2385
|
+
ctx.effect(() => async () => controller.dispose(), "kiokuko-dsh: browser download lifecycle");
|
|
2386
|
+
ctx.effect(installStyle, "kiokuko-dsh: browser download style");
|
|
2387
|
+
ctx.effect(() => ctx.locale.register(LOCALE_NAMESPACE, { en, ja, zh }), "kiokuko-dsh: browser dictionaries");
|
|
2388
|
+
ctx.on("command/executed", (sessionId, commandName, result) => {
|
|
2389
|
+
if (commandName === "export" && result.kind === "success")
|
|
2390
|
+
void controller.download(sessionId);
|
|
2391
|
+
});
|
|
2392
|
+
ctx.slots.inject("conversation.session.header.utilities", () => ctx.slots.register({
|
|
2393
|
+
name: "conversation.session.header.utilities",
|
|
2394
|
+
id: "kiokuko-session-log-download",
|
|
2395
|
+
locale: LOCALE_NAMESPACE,
|
|
2396
|
+
inject: () => ({
|
|
2397
|
+
hooks: { sessionLogDownload: controller.store },
|
|
2398
|
+
request: (sessionId) => controller.download(sessionId),
|
|
2399
|
+
dismiss: (sessionId) => controller.dismiss(sessionId)
|
|
2400
|
+
})
|
|
2401
|
+
}, SessionLogDownloadHeaderAction));
|
|
1535
2402
|
}
|
|
1536
|
-
|
|
1537
|
-
exports.downloadDshSessionLog = downloadDshSessionLog;
|
|
1538
|
-
exports.inject = inject;
|
|
2403
|
+
|
|
1539
2404
|
return module.exports;
|
|
1540
2405
|
}
|
|
1541
2406
|
});
|