@prettier-ai/dsh-client-ui-goal 0.1.2-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.i18n.yaml +6 -0
- package/README.md +90 -0
- package/README.zh.md +90 -0
- package/lib/client.js +448 -0
- package/lib/index.js +11 -0
- package/lib/invariant.js +25 -0
- package/lib/types/client/GoalBar.d.ts +22 -0
- package/lib/types/client/GoalCommandInputView.d.ts +6 -0
- package/lib/types/client/goal-command-input.d.ts +28 -0
- package/lib/types/client/index.d.ts +29 -0
- package/lib/types/client/locales.d.ts +32 -0
- package/lib/types/client/slots.d.ts +30 -0
- package/lib/types/index.d.ts +9 -0
- package/lib/types/invariant.d.ts +16 -0
- package/package.json +94 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 DeepSeek
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.i18n.yaml
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
|
2
|
+
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
|
3
|
+
# after editing either side, bring the other along and re-record with:
|
|
4
|
+
# pnpm run verify-translation-pairing --write packages/client/ui-goal/README.md
|
|
5
|
+
README.md: 05c44fee27f0500c6a5d53496fde3d447edbf424
|
|
6
|
+
README.zh.md: f280356eb37b364f49851ca24d73370eb62e6795
|
package/README.md
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Goal surface for the Web GUI: the composer-context strip that shows the current goal and edits, pauses, resumes, or clears it; for users and maintainers of the goal experience."
|
|
3
|
+
kind: "package-reference"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# @deepseek-ai/dsh-client-ui-goal
|
|
7
|
+
|
|
8
|
+
English | [中文](README.zh.md)
|
|
9
|
+
|
|
10
|
+
## Summary
|
|
11
|
+
|
|
12
|
+
This package renders the goal surface in the Web GUI: a strip in the composer-context stack that shows the current goal of the session and offers edit, pause, resume, and clear actions. It reads the live goal from the host-computed projection and routes every mutation through the goal service, surfacing rejections inline. It also projects each durable `/goal` command run as a `Command input` bubble in the chat, so a goal command entered by the user or the model appears in the transcript. Goal creation is outside this plugin. The shipped Web presets other than `minimal` mount `/goal` in their agent scope.
|
|
13
|
+
|
|
14
|
+
## Table of Contents
|
|
15
|
+
|
|
16
|
+
- [Use this package](#use-this-package)
|
|
17
|
+
- [Understand the implementation](#understand-the-implementation)
|
|
18
|
+
- [Further Exploration](#further-exploration)
|
|
19
|
+
- [Model Experience](#model-experience)
|
|
20
|
+
- [Known Limitations and Deferred Work](#known-limitations-and-deferred-work)
|
|
21
|
+
- [Dev Note](#dev-note)
|
|
22
|
+
|
|
23
|
+
-----
|
|
24
|
+
|
|
25
|
+
<a id="use-this-package"></a>
|
|
26
|
+
## Use this package
|
|
27
|
+
|
|
28
|
+
Mount this plugin alongside `ui-conversation` and the goal domain package; the strip then appears as the second card in the composer-context stack (after Todo, before Queue) whenever the session has a goal. An active goal offers pause; a paused one offers resume; edit rewrites the objective; clear removes the goal and suppresses the strip until the projection catches up.
|
|
29
|
+
|
|
30
|
+
### The command-input bubble
|
|
31
|
+
|
|
32
|
+
Each durable `/goal` run projects as a right-aligned monospace user-style bubble labeled `Command input` (or `指令输入`), rendered before the generic command result row. It carries no timestamp, copy, or branch actions, and reloading reconstructs it from the run.
|
|
33
|
+
|
|
34
|
+
### Failures
|
|
35
|
+
|
|
36
|
+
A rejected mutation surfaces the Remote error inline on the strip; loading, absent, completed, and successfully cleared goals render nothing.
|
|
37
|
+
|
|
38
|
+
-----
|
|
39
|
+
|
|
40
|
+
<a id="understand-the-implementation"></a>
|
|
41
|
+
## Understand the implementation
|
|
42
|
+
|
|
43
|
+
<details>
|
|
44
|
+
<summary>Implementation internals — click to expand</summary>
|
|
45
|
+
|
|
46
|
+
The strip is projection-mode: the live goal arrives through `useProjection('goal')` (seeded by the history tail page and updated by `session/projection` frames), so the plugin owns no domain store, refresh chain, or event listener. The inject face carries only the four mutation verbs through `ctx.remote.goals`; each reads the CAS ref from the session's current projected value at call time, and the RPC's compare-and-set is the staleness guard. The strip single-flights mutations synchronously because a pending render cannot fence same-frame clicks. The command-input projection is a separate Conversation Definition that builds a `command-input` Chat Node before the generic command result Node; it never creates `user/message` or a model turn.
|
|
47
|
+
|
|
48
|
+
</details>
|
|
49
|
+
|
|
50
|
+
-----
|
|
51
|
+
|
|
52
|
+
<a id="further-exploration"></a>
|
|
53
|
+
## Further Exploration
|
|
54
|
+
|
|
55
|
+
Read these pages when the goal surface is not enough. They move from the browser strip to the goal domain and the slots it fills.
|
|
56
|
+
|
|
57
|
+
- [dsh-goal](../../goal/goal/README.md) — the goal domain, projection, and `/goal` command this surface reads and mutates.
|
|
58
|
+
- [ui-conversation](../ui-conversation/README.md) — declares the `conversation.input.dock` slot and owns the composer.
|
|
59
|
+
- [Client package map](../README.md) — adjacent browser UI packages.
|
|
60
|
+
|
|
61
|
+
-----
|
|
62
|
+
|
|
63
|
+
<a id="model-experience"></a>
|
|
64
|
+
## Model Experience
|
|
65
|
+
|
|
66
|
+
Indirectly, through the `goals/edit`, `goals/pause`, `goals/resume`, and `goals/clear` mutations the strip routes; the host GoalService owns the model-visible goal context message those mutations queue.
|
|
67
|
+
|
|
68
|
+
#### KV Cache effect
|
|
69
|
+
|
|
70
|
+
None unless the queued goal context is admitted. An admitted context extends the history tail like any other message; an insertion discarded before admission does not affect the cache.
|
|
71
|
+
|
|
72
|
+
## Known Limitations and Deferred Work
|
|
73
|
+
|
|
74
|
+
<a id="known-limitations-and-deferred-work"></a>
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
These limits define the current goal surface. They are current package constraints, not a goal-domain comparison or a task backlog.
|
|
78
|
+
|
|
79
|
+
- **Durable phase only** — the projection omits process-local activation, so the strip cannot distinguish an active-but-disarmed goal from an armed one; resume re-arms through the RPC side. There is no host-live activation channel.
|
|
80
|
+
- **Preset-independent host state** — switching an active session to `minimal` leaves its host-owned goal intact. `/goal` and goal tools disappear, while this strip can still edit, pause, resume, or clear the goal.
|
|
81
|
+
|
|
82
|
+
<a id="dev-note"></a>
|
|
83
|
+
### Dev Note
|
|
84
|
+
|
|
85
|
+
<details>
|
|
86
|
+
<summary>Working context for maintainers — click to expand</summary>
|
|
87
|
+
|
|
88
|
+
None.
|
|
89
|
+
|
|
90
|
+
</details>
|
package/README.zh.md
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Web GUI 的 goal 表面:显示当前目标并支持编辑、暂停、恢复或清除的 composer 上下文条带;供 goal 体验的用户与维护者阅读。"
|
|
3
|
+
kind: "package-reference"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# @deepseek-ai/dsh-client-ui-goal
|
|
7
|
+
|
|
8
|
+
[English](README.md) | 中文
|
|
9
|
+
|
|
10
|
+
## 概述
|
|
11
|
+
|
|
12
|
+
本包在 Web GUI 中渲染 goal 表面:composer 上下文堆栈里的一条条带,显示会话的当前目标,并提供编辑、暂停、恢复与清除动作。它从宿主计算的投影读取活目标,把每次变更都经 goal 服务路由,并把拒绝内联呈现。它还把每条持久的 `/goal` 命令运行投影为聊天中的 `Command input` 气泡,让用户或模型输入的 goal 命令出现在文本记录中。goal 创建不归本插件。除 `minimal` 外,随附的 Web preset 都会在其 agent scope 中挂载 `/goal`。
|
|
13
|
+
|
|
14
|
+
## 目录
|
|
15
|
+
|
|
16
|
+
- [使用本包](#use-this-package)
|
|
17
|
+
- [理解实现](#understand-the-implementation)
|
|
18
|
+
- [进一步探索](#further-exploration)
|
|
19
|
+
- [模型体验](#model-experience)
|
|
20
|
+
- [已知限制与延期工作](#known-limitations-and-deferred-work)
|
|
21
|
+
- [开发备注](#dev-note)
|
|
22
|
+
|
|
23
|
+
-----
|
|
24
|
+
|
|
25
|
+
<a id="use-this-package"></a>
|
|
26
|
+
## 使用本包
|
|
27
|
+
|
|
28
|
+
与 `ui-conversation` 及 goal 领域包一起挂载本插件;只要会话存在目标,条带就会作为 composer 上下文堆栈的第二张卡片出现(位于 Todo 之后、Queue 之前)。active 的 goal 提供暂停动作;paused 的提供恢复;编辑重写目标文本;清除移除目标,并在投影追上之前抑制条带。
|
|
29
|
+
|
|
30
|
+
### 指令输入气泡
|
|
31
|
+
|
|
32
|
+
每条持久的 `/goal` 运行都投影为一个右对齐的等宽用户样式气泡,标签为 `Command input`(或 `指令输入`),渲染在通用命令结果行之前。它不含时间戳、复制或分支操作,重新加载时会依据运行记录重建。
|
|
33
|
+
|
|
34
|
+
### 失败
|
|
35
|
+
|
|
36
|
+
被拒绝的变更会把 Remote 错误内联呈现到条带上;加载中、无目标、已完成与成功清除的目标一律不渲染。
|
|
37
|
+
|
|
38
|
+
-----
|
|
39
|
+
|
|
40
|
+
<a id="understand-the-implementation"></a>
|
|
41
|
+
## 理解实现
|
|
42
|
+
|
|
43
|
+
<details>
|
|
44
|
+
<summary>实现细节——点击展开</summary>
|
|
45
|
+
|
|
46
|
+
条带是投影模式:活目标经 `useProjection('goal')` 到达(由历史尾页播种、`session/projection` 帧更新),因此插件不持有领域 store、不设刷新链、不挂事件监听。注入面只携带四个变更动词,经 `ctx.remote.goals` 调用;每个动词在调用时从会话当前投影值读取 CAS ref,比较并交换(RPC 的 CAS)就是陈旧性护栏。由于 React 的 pending 渲染无法拦住同一帧内的点击,条带会同步为变更建立 single-flight 防护。指令输入投影是独立的 Conversation Definition,在通用命令结果 Node 之前构建 `command-input` Chat Node;它绝不创建 `user/message` 或模型轮次。
|
|
47
|
+
|
|
48
|
+
</details>
|
|
49
|
+
|
|
50
|
+
-----
|
|
51
|
+
|
|
52
|
+
<a id="further-exploration"></a>
|
|
53
|
+
## 进一步探索
|
|
54
|
+
|
|
55
|
+
当 goal 表面不够用时阅读以下页面。它们从浏览器条带进入 goal 领域与它所填充的槽位。
|
|
56
|
+
|
|
57
|
+
- [dsh-goal](../../goal/goal/README.zh.md)——本表面读取并变更的 goal 领域、投影与 `/goal` 命令。
|
|
58
|
+
- [ui-conversation](../ui-conversation/README.zh.md)——声明 `conversation.input.dock` 槽位并拥有 composer。
|
|
59
|
+
- [客户端包映射](../README.zh.md)——相邻的浏览器 UI 包。
|
|
60
|
+
|
|
61
|
+
-----
|
|
62
|
+
|
|
63
|
+
<a id="model-experience"></a>
|
|
64
|
+
## 模型体验
|
|
65
|
+
|
|
66
|
+
间接影响:条带路由 `goals/edit`、`goals/pause`、`goals/resume` 与 `goals/clear` 变更;宿主 GoalService 拥有这些变更排队的模型可见 goal 上下文消息。
|
|
67
|
+
|
|
68
|
+
#### KV Cache 影响
|
|
69
|
+
|
|
70
|
+
除非已排队的 goal 上下文获准,否则没有影响。获准的上下文会像其他消息一样扩展历史尾部;准入前被丢弃的插入项不会影响缓存。
|
|
71
|
+
|
|
72
|
+
## 已知限制与延期工作
|
|
73
|
+
|
|
74
|
+
<a id="known-limitations-and-deferred-work"></a>
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
这些限制界定了当前 goal 表面。它们是当前包约束,不是 goal 领域对比或任务积压。
|
|
78
|
+
|
|
79
|
+
- **只反映持久阶段**——投影省略进程本地的激活状态,因此条带无法区分已激活但未武装的 goal 与已武装的 goal;恢复经 RPC 侧重新武装。不存在宿主实时激活通道。
|
|
80
|
+
- **Host 状态与 preset 无关**——把活跃会话切换到 `minimal` 后,Host 拥有的 goal 仍会保留。`/goal` 与 goal 工具会消失,但该条带仍可编辑、暂停、恢复或清除 goal。
|
|
81
|
+
|
|
82
|
+
<a id="dev-note"></a>
|
|
83
|
+
### 开发备注
|
|
84
|
+
|
|
85
|
+
<details>
|
|
86
|
+
<summary>维护者的工作上下文——点击展开</summary>
|
|
87
|
+
|
|
88
|
+
无。
|
|
89
|
+
|
|
90
|
+
</details>
|
package/lib/client.js
ADDED
|
@@ -0,0 +1,448 @@
|
|
|
1
|
+
window.__ModuleLoader__.load({
|
|
2
|
+
id: "@prettier-ai/dsh-client-ui-goal",
|
|
3
|
+
factory: (require) => {
|
|
4
|
+
var module = { exports: {} };
|
|
5
|
+
var exports = module.exports;
|
|
6
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
7
|
+
let react_jsx_runtime = require("react/jsx-runtime");
|
|
8
|
+
let react = require("react");
|
|
9
|
+
let _prettier_ai_dsh_client_ui_primitives = require("@prettier-ai/dsh-client-ui-primitives");
|
|
10
|
+
//#region \0dsh-css:/home/runner/work/dsh-publisher/dsh-publisher/upstream/packages/client/ui-goal/src/client/GoalBar.module.css.mjs
|
|
11
|
+
const css$1 = ".pLGJta_dock{box-sizing:border-box;width:calc(100% - var(--dsh-composer-side-clearance) - var(--dsh-composer-side-clearance) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset));margin:0 auto}.pLGJta_bar{box-sizing:border-box;width:100%;max-width:calc(var(--dsh-composer-card-max-width) - 4 * var(--dsh-composer-dock-inset));border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-specific-tip);border-radius:12px;align-items:center;gap:10px;height:36px;margin:0 auto;padding:4px 5px 4px 12px;display:flex}.pLGJta_goalGlyph{color:var(--dsw-alias-label-tertiary);flex:none;display:inline-flex}.pLGJta_label{color:var(--dsw-alias-label-primary);flex:none;font-size:13px;font-weight:500;line-height:24px}.pLGJta_objective{min-width:0;color:var(--dsw-alias-label-primary-dimmed);text-overflow:ellipsis;white-space:nowrap;flex:1;font-size:13px;line-height:20px;overflow:hidden}.pLGJta_error{min-width:0;color:var(--dsw-alias-state-error-primary);text-overflow:ellipsis;white-space:nowrap;flex:1;font-size:12px;line-height:20px;overflow:hidden}.pLGJta_objectiveInput{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);min-width:0;height:26px;color:var(--dsw-alias-label-primary);border-radius:6px;outline:none;flex:1;padding:0 8px;font-size:13px;line-height:20px}.pLGJta_objectiveInput:focus{border-color:var(--dsw-alias-state-business-primary)}.pLGJta_objectiveInput::placeholder{color:var(--dsw-alias-label-caption)}.pLGJta_actions{flex:none;align-items:center;gap:10px;display:flex}.pLGJta_iconBtn{width:28px;height:28px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:999px;justify-content:center;align-items:center;padding:0;display:inline-flex}.pLGJta_iconBtn:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}.pLGJta_iconBtn:disabled{opacity:.4;cursor:default}";
|
|
12
|
+
const tagId$1 = "@prettier-ai/dsh-client-ui-goal/GoalBar.module.css";
|
|
13
|
+
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
|
|
14
|
+
const tag = document.createElement("style");
|
|
15
|
+
tag.dataset.plugin = "@prettier-ai/dsh-client-ui-goal";
|
|
16
|
+
tag.dataset.pluginCss = tagId$1;
|
|
17
|
+
tag.textContent = css$1;
|
|
18
|
+
document.head.appendChild(tag);
|
|
19
|
+
}
|
|
20
|
+
var GoalBar_module_css_default = {
|
|
21
|
+
"actions": "pLGJta_actions",
|
|
22
|
+
"bar": "pLGJta_bar",
|
|
23
|
+
"dock": "pLGJta_dock",
|
|
24
|
+
"error": "pLGJta_error",
|
|
25
|
+
"goalGlyph": "pLGJta_goalGlyph",
|
|
26
|
+
"iconBtn": "pLGJta_iconBtn",
|
|
27
|
+
"label": "pLGJta_label",
|
|
28
|
+
"objective": "pLGJta_objective",
|
|
29
|
+
"objectiveInput": "pLGJta_objectiveInput"
|
|
30
|
+
};
|
|
31
|
+
//#endregion
|
|
32
|
+
//#region lib/types/client/GoalBar.js
|
|
33
|
+
/**
|
|
34
|
+
* GoalBar: the goal indicator docked above the message composer (input dock
|
|
35
|
+
* strip). A present goal shows a goal glyph, a phase label, the truncated
|
|
36
|
+
* objective, and icon actions — resume when paused, edit (inline form in the
|
|
37
|
+
* same strip), and clear. Goal creation lives on the `/goal` command, not
|
|
38
|
+
* here: loading (undefined), no goal (null), and complete goals render
|
|
39
|
+
* nothing. Live state arrives as the projected whole snapshot; the verbs are
|
|
40
|
+
* the injected face.
|
|
41
|
+
*/
|
|
42
|
+
/** Strip label keys per visible phase; complete goals render nothing. */
|
|
43
|
+
const PHASE_LABELS = {
|
|
44
|
+
active: "phase.active",
|
|
45
|
+
paused: "phase.paused",
|
|
46
|
+
blocked: "phase.blocked"
|
|
47
|
+
};
|
|
48
|
+
function GoalBar({ goal, onEdit, onPause, onResume, onClear, t }) {
|
|
49
|
+
const [editing, setEditing] = (0, react.useState)(false);
|
|
50
|
+
const [draft, setDraft] = (0, react.useState)("");
|
|
51
|
+
const [pending, setPending] = (0, react.useState)(false);
|
|
52
|
+
const [actionError, setActionError] = (0, react.useState)(null);
|
|
53
|
+
const [clearedGoalId, setClearedGoalId] = (0, react.useState)(null);
|
|
54
|
+
const pendingRef = (0, react.useRef)(false);
|
|
55
|
+
const goalId = goal?.id;
|
|
56
|
+
(0, react.useEffect)(() => {
|
|
57
|
+
setEditing(false);
|
|
58
|
+
setActionError(null);
|
|
59
|
+
setClearedGoalId(null);
|
|
60
|
+
}, [goalId]);
|
|
61
|
+
const runAction = (0, react.useCallback)(async (action) => {
|
|
62
|
+
if (pendingRef.current) return void 0;
|
|
63
|
+
pendingRef.current = true;
|
|
64
|
+
setPending(true);
|
|
65
|
+
setActionError(null);
|
|
66
|
+
const result = await action();
|
|
67
|
+
pendingRef.current = false;
|
|
68
|
+
setPending(false);
|
|
69
|
+
if (!result.ok) setActionError(`${result.error.message} (${result.error.code})`);
|
|
70
|
+
return result;
|
|
71
|
+
}, []);
|
|
72
|
+
const handleEdit = (0, react.useCallback)(async () => {
|
|
73
|
+
const trimmed = draft.trim();
|
|
74
|
+
if (trimmed === "") return;
|
|
75
|
+
if ((await runAction(() => onEdit(trimmed)))?.ok) setEditing(false);
|
|
76
|
+
}, [
|
|
77
|
+
draft,
|
|
78
|
+
onEdit,
|
|
79
|
+
runAction
|
|
80
|
+
]);
|
|
81
|
+
const handleClear = (0, react.useCallback)(async (clearedId) => {
|
|
82
|
+
if ((await runAction(onClear))?.ok) setClearedGoalId(clearedId);
|
|
83
|
+
}, [onClear, runAction]);
|
|
84
|
+
if (goal === void 0 || goal === null || goal.phase === "complete" || goal.id === clearedGoalId) return null;
|
|
85
|
+
if (editing) return (0, react_jsx_runtime.jsx)("div", {
|
|
86
|
+
className: GoalBar_module_css_default.dock,
|
|
87
|
+
"data-goal-bar": true,
|
|
88
|
+
children: (0, react_jsx_runtime.jsxs)("div", {
|
|
89
|
+
className: GoalBar_module_css_default.bar,
|
|
90
|
+
children: [
|
|
91
|
+
(0, react_jsx_runtime.jsx)("input", {
|
|
92
|
+
className: GoalBar_module_css_default.objectiveInput,
|
|
93
|
+
type: "text",
|
|
94
|
+
"aria-label": t("objective.aria"),
|
|
95
|
+
value: draft,
|
|
96
|
+
onChange: (e) => {
|
|
97
|
+
setDraft(e.target.value);
|
|
98
|
+
},
|
|
99
|
+
onKeyDown: (e) => {
|
|
100
|
+
if (e.key === "Enter") handleEdit();
|
|
101
|
+
if (e.key === "Escape") setEditing(false);
|
|
102
|
+
},
|
|
103
|
+
autoFocus: true
|
|
104
|
+
}),
|
|
105
|
+
actionError !== null && (0, react_jsx_runtime.jsx)("span", {
|
|
106
|
+
className: GoalBar_module_css_default.error,
|
|
107
|
+
role: "alert",
|
|
108
|
+
children: actionError
|
|
109
|
+
}),
|
|
110
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
111
|
+
className: GoalBar_module_css_default.actions,
|
|
112
|
+
children: [(0, react_jsx_runtime.jsx)(_prettier_ai_dsh_client_ui_primitives.Tooltip, {
|
|
113
|
+
label: t("action.save"),
|
|
114
|
+
side: "bottom",
|
|
115
|
+
delayMs: 500,
|
|
116
|
+
children: (0, react_jsx_runtime.jsx)("button", {
|
|
117
|
+
type: "button",
|
|
118
|
+
className: GoalBar_module_css_default.iconBtn,
|
|
119
|
+
onClick: () => {
|
|
120
|
+
handleEdit();
|
|
121
|
+
},
|
|
122
|
+
disabled: pending || draft.trim() === "",
|
|
123
|
+
"aria-label": t("action.save"),
|
|
124
|
+
children: (0, react_jsx_runtime.jsx)(_prettier_ai_dsh_client_ui_primitives.IconCheckOutline16, { size: 14 })
|
|
125
|
+
})
|
|
126
|
+
}), (0, react_jsx_runtime.jsx)(_prettier_ai_dsh_client_ui_primitives.Tooltip, {
|
|
127
|
+
label: t("action.cancel"),
|
|
128
|
+
side: "bottom",
|
|
129
|
+
delayMs: 500,
|
|
130
|
+
children: (0, react_jsx_runtime.jsx)("button", {
|
|
131
|
+
type: "button",
|
|
132
|
+
className: GoalBar_module_css_default.iconBtn,
|
|
133
|
+
onClick: () => {
|
|
134
|
+
setEditing(false);
|
|
135
|
+
},
|
|
136
|
+
disabled: pending,
|
|
137
|
+
"aria-label": t("action.cancel"),
|
|
138
|
+
children: (0, react_jsx_runtime.jsx)(_prettier_ai_dsh_client_ui_primitives.IconCloseOutline16, { size: 14 })
|
|
139
|
+
})
|
|
140
|
+
})]
|
|
141
|
+
})
|
|
142
|
+
]
|
|
143
|
+
})
|
|
144
|
+
});
|
|
145
|
+
const title = goal.phase === "blocked" ? goal.blockedReason?.message : void 0;
|
|
146
|
+
return (0, react_jsx_runtime.jsx)("div", {
|
|
147
|
+
className: GoalBar_module_css_default.dock,
|
|
148
|
+
"data-goal-bar": true,
|
|
149
|
+
children: (0, react_jsx_runtime.jsxs)("div", {
|
|
150
|
+
className: GoalBar_module_css_default.bar,
|
|
151
|
+
title,
|
|
152
|
+
children: [
|
|
153
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
154
|
+
className: GoalBar_module_css_default.goalGlyph,
|
|
155
|
+
children: (0, react_jsx_runtime.jsx)(_prettier_ai_dsh_client_ui_primitives.IconGoalOutline16, { size: 14 })
|
|
156
|
+
}),
|
|
157
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
158
|
+
className: GoalBar_module_css_default.label,
|
|
159
|
+
children: t(PHASE_LABELS[goal.phase])
|
|
160
|
+
}),
|
|
161
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
162
|
+
className: GoalBar_module_css_default.objective,
|
|
163
|
+
children: goal.objective
|
|
164
|
+
}),
|
|
165
|
+
actionError !== null && (0, react_jsx_runtime.jsx)("span", {
|
|
166
|
+
className: GoalBar_module_css_default.error,
|
|
167
|
+
role: "alert",
|
|
168
|
+
children: actionError
|
|
169
|
+
}),
|
|
170
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
171
|
+
className: GoalBar_module_css_default.actions,
|
|
172
|
+
children: [
|
|
173
|
+
goal.phase === "active" && (0, react_jsx_runtime.jsx)(_prettier_ai_dsh_client_ui_primitives.Tooltip, {
|
|
174
|
+
label: t("action.pause"),
|
|
175
|
+
side: "bottom",
|
|
176
|
+
delayMs: 500,
|
|
177
|
+
children: (0, react_jsx_runtime.jsx)("button", {
|
|
178
|
+
type: "button",
|
|
179
|
+
className: GoalBar_module_css_default.iconBtn,
|
|
180
|
+
disabled: pending,
|
|
181
|
+
onClick: () => {
|
|
182
|
+
runAction(onPause);
|
|
183
|
+
},
|
|
184
|
+
"aria-label": t("action.pause"),
|
|
185
|
+
children: (0, react_jsx_runtime.jsx)(_prettier_ai_dsh_client_ui_primitives.IconPauseOutline16, { size: 14 })
|
|
186
|
+
})
|
|
187
|
+
}),
|
|
188
|
+
goal.phase === "paused" && (0, react_jsx_runtime.jsx)(_prettier_ai_dsh_client_ui_primitives.Tooltip, {
|
|
189
|
+
label: t("action.resume"),
|
|
190
|
+
side: "bottom",
|
|
191
|
+
delayMs: 500,
|
|
192
|
+
children: (0, react_jsx_runtime.jsx)("button", {
|
|
193
|
+
type: "button",
|
|
194
|
+
className: GoalBar_module_css_default.iconBtn,
|
|
195
|
+
disabled: pending,
|
|
196
|
+
onClick: () => {
|
|
197
|
+
runAction(onResume);
|
|
198
|
+
},
|
|
199
|
+
"aria-label": t("action.resume"),
|
|
200
|
+
children: (0, react_jsx_runtime.jsx)(_prettier_ai_dsh_client_ui_primitives.IconPlayOutline16, { size: 14 })
|
|
201
|
+
})
|
|
202
|
+
}),
|
|
203
|
+
(0, react_jsx_runtime.jsx)(_prettier_ai_dsh_client_ui_primitives.Tooltip, {
|
|
204
|
+
label: t("action.edit"),
|
|
205
|
+
side: "bottom",
|
|
206
|
+
delayMs: 500,
|
|
207
|
+
children: (0, react_jsx_runtime.jsx)("button", {
|
|
208
|
+
type: "button",
|
|
209
|
+
className: GoalBar_module_css_default.iconBtn,
|
|
210
|
+
disabled: pending,
|
|
211
|
+
onClick: () => {
|
|
212
|
+
setDraft(goal.objective);
|
|
213
|
+
setEditing(true);
|
|
214
|
+
},
|
|
215
|
+
"aria-label": t("action.edit"),
|
|
216
|
+
children: (0, react_jsx_runtime.jsx)(_prettier_ai_dsh_client_ui_primitives.IconEditOutline16, { size: 14 })
|
|
217
|
+
})
|
|
218
|
+
}),
|
|
219
|
+
(0, react_jsx_runtime.jsx)(_prettier_ai_dsh_client_ui_primitives.Tooltip, {
|
|
220
|
+
label: t("action.clear"),
|
|
221
|
+
side: "bottom",
|
|
222
|
+
delayMs: 500,
|
|
223
|
+
children: (0, react_jsx_runtime.jsx)("button", {
|
|
224
|
+
type: "button",
|
|
225
|
+
className: GoalBar_module_css_default.iconBtn,
|
|
226
|
+
disabled: pending,
|
|
227
|
+
onClick: () => {
|
|
228
|
+
handleClear(goal.id);
|
|
229
|
+
},
|
|
230
|
+
"aria-label": t("action.clear"),
|
|
231
|
+
children: (0, react_jsx_runtime.jsx)(_prettier_ai_dsh_client_ui_primitives.IconTrashOutline16, { size: 14 })
|
|
232
|
+
})
|
|
233
|
+
})
|
|
234
|
+
]
|
|
235
|
+
})
|
|
236
|
+
]
|
|
237
|
+
})
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
/** Dock adapter: reads the host-computed 'goal' projection (whole value; absent or null renders nothing). */
|
|
241
|
+
function GoalDock({ useProjection, onEdit, onPause, onResume, onClear, t }) {
|
|
242
|
+
const projection = useProjection("goal");
|
|
243
|
+
return (0, react_jsx_runtime.jsx)(GoalBar, {
|
|
244
|
+
goal: projection === void 0 ? void 0 : projection === null ? null : projection.goal,
|
|
245
|
+
onEdit,
|
|
246
|
+
onPause,
|
|
247
|
+
onResume,
|
|
248
|
+
onClear,
|
|
249
|
+
t
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
//#endregion
|
|
253
|
+
//#region \0dsh-css:/home/runner/work/dsh-publisher/dsh-publisher/upstream/packages/client/ui-goal/src/client/GoalCommandInputView.module.css.mjs
|
|
254
|
+
const css = ".D3Tq-q_row{flex-direction:column;align-items:flex-end;gap:6px;display:flex}.D3Tq-q_stack{min-width:0;max-width:min(calc(var(--dsh-chat-content-width,748px) * .702), 82%);flex-direction:column;align-items:flex-end;display:flex}.D3Tq-q_bubble{overflow-wrap:anywhere;background:var(--dsw-specific-bubble);max-width:100%;color:var(--dsw-alias-label-primary);font:var(--dsw-font-markdown-code);font-size:var(--dsh-content-font-size,14px);line-height:calc(22px + var(--dsh-content-font-delta,0px));white-space:pre-wrap;border-radius:22px;padding:10px 16px}";
|
|
255
|
+
const tagId = "@prettier-ai/dsh-client-ui-goal/GoalCommandInputView.module.css";
|
|
256
|
+
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
257
|
+
const tag = document.createElement("style");
|
|
258
|
+
tag.dataset.plugin = "@prettier-ai/dsh-client-ui-goal";
|
|
259
|
+
tag.dataset.pluginCss = tagId;
|
|
260
|
+
tag.textContent = css;
|
|
261
|
+
document.head.appendChild(tag);
|
|
262
|
+
}
|
|
263
|
+
var GoalCommandInputView_module_css_default = {
|
|
264
|
+
"bubble": "D3Tq-q_bubble",
|
|
265
|
+
"row": "D3Tq-q_row",
|
|
266
|
+
"stack": "D3Tq-q_stack"
|
|
267
|
+
};
|
|
268
|
+
//#endregion
|
|
269
|
+
//#region lib/types/client/GoalCommandInputView.js
|
|
270
|
+
/** Right-aligned `/goal` input bubble without ordinary message actions. */
|
|
271
|
+
const GoalCommandInputView = (0, react.memo)(function GoalCommandInputView({ node, t }) {
|
|
272
|
+
const data = node.data;
|
|
273
|
+
return (0, react_jsx_runtime.jsx)("div", {
|
|
274
|
+
className: GoalCommandInputView_module_css_default.row,
|
|
275
|
+
"data-command-input": "",
|
|
276
|
+
role: "group",
|
|
277
|
+
"aria-label": t("commandInput.aria"),
|
|
278
|
+
children: (0, react_jsx_runtime.jsx)("div", {
|
|
279
|
+
className: GoalCommandInputView_module_css_default.stack,
|
|
280
|
+
children: (0, react_jsx_runtime.jsx)("div", {
|
|
281
|
+
className: GoalCommandInputView_module_css_default.bubble,
|
|
282
|
+
children: (0, react_jsx_runtime.jsx)(_prettier_ai_dsh_client_ui_primitives.MessageText, { text: data.text })
|
|
283
|
+
})
|
|
284
|
+
})
|
|
285
|
+
});
|
|
286
|
+
});
|
|
287
|
+
//#endregion
|
|
288
|
+
//#region lib/types/client/goal-command-input.js
|
|
289
|
+
/**
|
|
290
|
+
* Derive the visible command line from its structured durable run.
|
|
291
|
+
* @param event - `/goal` command run.
|
|
292
|
+
* @returns command text with trailing parser whitespace removed.
|
|
293
|
+
*/
|
|
294
|
+
function goalCommandText(event) {
|
|
295
|
+
return `/${event.data.name}${(event.data.args ?? "").trimEnd()}`;
|
|
296
|
+
}
|
|
297
|
+
/** Goal-owned command input projection; the generic command Definition retains the result row. */
|
|
298
|
+
const goalCommandInputDefinition = {
|
|
299
|
+
kind: "goal-command-input",
|
|
300
|
+
target: "chat",
|
|
301
|
+
match: (event) => event.type === "command/run" && event.data.name === "goal" ? {
|
|
302
|
+
id: String(event.data.commandId),
|
|
303
|
+
role: "start"
|
|
304
|
+
} : null,
|
|
305
|
+
start: (_context, match) => {
|
|
306
|
+
if (match.event.type !== "command/run") throw new Error("goal-command-input start requires command/run");
|
|
307
|
+
return {
|
|
308
|
+
commandId: match.event.data.commandId,
|
|
309
|
+
seq: match.event.seq,
|
|
310
|
+
time: match.event.time,
|
|
311
|
+
text: goalCommandText(match.event)
|
|
312
|
+
};
|
|
313
|
+
},
|
|
314
|
+
update: (context) => context.state,
|
|
315
|
+
buildViewNode: (context) => {
|
|
316
|
+
if (context.state === void 0) return null;
|
|
317
|
+
return {
|
|
318
|
+
key: context.key,
|
|
319
|
+
kind: "command-input",
|
|
320
|
+
id: context.id,
|
|
321
|
+
target: "chat",
|
|
322
|
+
anchorSeq: context.state.seq - .1,
|
|
323
|
+
location: context.start?.location ?? { kind: "unresolved" },
|
|
324
|
+
visibility: "visible",
|
|
325
|
+
data: {
|
|
326
|
+
commandId: context.state.commandId,
|
|
327
|
+
text: context.state.text,
|
|
328
|
+
time: context.state.time
|
|
329
|
+
}
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
};
|
|
333
|
+
//#endregion
|
|
334
|
+
//#region lib/types/client/locales.js
|
|
335
|
+
/** `goal` namespace dictionaries. */
|
|
336
|
+
/** Simplified Chinese dictionary (the key-set source of truth). */
|
|
337
|
+
const zh = {
|
|
338
|
+
"phase.active": "进行中的目标",
|
|
339
|
+
"phase.paused": "已暂停的目标",
|
|
340
|
+
"phase.blocked": "受阻的目标",
|
|
341
|
+
"objective.aria": "目标内容",
|
|
342
|
+
"commandInput.aria": "指令输入",
|
|
343
|
+
"action.save": "保存目标",
|
|
344
|
+
"action.cancel": "取消编辑",
|
|
345
|
+
"action.pause": "暂停目标",
|
|
346
|
+
"action.resume": "恢复目标",
|
|
347
|
+
"action.edit": "编辑目标",
|
|
348
|
+
"action.clear": "清除目标"
|
|
349
|
+
};
|
|
350
|
+
/** English dictionary, checked complete against the zh key set. */
|
|
351
|
+
const en = {
|
|
352
|
+
"phase.active": "Ongoing Goal",
|
|
353
|
+
"phase.paused": "Paused Goal",
|
|
354
|
+
"phase.blocked": "Blocked Goal",
|
|
355
|
+
"objective.aria": "Goal objective",
|
|
356
|
+
"commandInput.aria": "Command input",
|
|
357
|
+
"action.save": "Save goal",
|
|
358
|
+
"action.cancel": "Cancel edit",
|
|
359
|
+
"action.pause": "Pause goal",
|
|
360
|
+
"action.resume": "Resume goal",
|
|
361
|
+
"action.edit": "Edit goal",
|
|
362
|
+
"action.clear": "Clear goal"
|
|
363
|
+
};
|
|
364
|
+
//#endregion
|
|
365
|
+
//#region lib/types/client/index.js
|
|
366
|
+
/** Dictionary namespace owned by this plugin. */
|
|
367
|
+
const NS = "goal";
|
|
368
|
+
/** Required services for the Goal dock, command-input projection, Remote mutations, and copy. */
|
|
369
|
+
const inject = [
|
|
370
|
+
"slots",
|
|
371
|
+
"sessions",
|
|
372
|
+
"remote",
|
|
373
|
+
"remote.goals",
|
|
374
|
+
"locale",
|
|
375
|
+
"uiConversation"
|
|
376
|
+
];
|
|
377
|
+
/**
|
|
378
|
+
* Client plugin body: the GoalBar dock entry with its mutation verbs.
|
|
379
|
+
* @param ctx - client root context.
|
|
380
|
+
*/
|
|
381
|
+
function apply(ctx) {
|
|
382
|
+
ctx.uiConversation.events.register(goalCommandInputDefinition);
|
|
383
|
+
ctx.effect(() => ctx.locale.register(NS, {
|
|
384
|
+
zh,
|
|
385
|
+
en
|
|
386
|
+
}), "ui-goal: dictionaries");
|
|
387
|
+
ctx.slots.inject("conversation.chat.node", () => ctx.slots.register({
|
|
388
|
+
name: "conversation.chat.node",
|
|
389
|
+
key: "command-input",
|
|
390
|
+
locale: NS
|
|
391
|
+
}, GoalCommandInputView));
|
|
392
|
+
const sessions = ctx.sessions;
|
|
393
|
+
/** The session's current projected CAS ref, read at verb call time (no staleness fence: the RPC's CAS is the guard). */
|
|
394
|
+
const refOf = (sessionId) => {
|
|
395
|
+
const projection = (sessions.binding(sessionId)?.session.projections.faceOf("goal"))?.getSnapshot();
|
|
396
|
+
if (projection == null) return void 0;
|
|
397
|
+
return {
|
|
398
|
+
id: projection.goal.id,
|
|
399
|
+
revision: projection.goal.revision
|
|
400
|
+
};
|
|
401
|
+
};
|
|
402
|
+
const noCurrentGoal = {
|
|
403
|
+
ok: false,
|
|
404
|
+
error: {
|
|
405
|
+
code: "no-current-goal",
|
|
406
|
+
message: "no current goal to mutate",
|
|
407
|
+
details: {}
|
|
408
|
+
}
|
|
409
|
+
};
|
|
410
|
+
ctx.slots.inject("conversation.input.dock", () => ctx.slots.register({
|
|
411
|
+
name: "conversation.input.dock",
|
|
412
|
+
id: "goal",
|
|
413
|
+
order: 10,
|
|
414
|
+
locale: NS,
|
|
415
|
+
inject: (sessionId) => ({
|
|
416
|
+
onEdit: async (objective) => {
|
|
417
|
+
const ref = refOf(sessionId);
|
|
418
|
+
if (ref === void 0) return noCurrentGoal;
|
|
419
|
+
return await ctx.remote.goals.edit(sessionId, ref, { objective });
|
|
420
|
+
},
|
|
421
|
+
onPause: async () => {
|
|
422
|
+
const ref = refOf(sessionId);
|
|
423
|
+
if (ref === void 0) return noCurrentGoal;
|
|
424
|
+
return await ctx.remote.goals.pause(sessionId, ref);
|
|
425
|
+
},
|
|
426
|
+
onResume: async () => {
|
|
427
|
+
const ref = refOf(sessionId);
|
|
428
|
+
if (ref === void 0) return noCurrentGoal;
|
|
429
|
+
return await ctx.remote.goals.resume(sessionId, ref);
|
|
430
|
+
},
|
|
431
|
+
onClear: async () => {
|
|
432
|
+
const ref = refOf(sessionId);
|
|
433
|
+
if (ref === void 0) return noCurrentGoal;
|
|
434
|
+
return await ctx.remote.goals.clear(sessionId, ref);
|
|
435
|
+
}
|
|
436
|
+
})
|
|
437
|
+
}, GoalDock));
|
|
438
|
+
}
|
|
439
|
+
//#endregion
|
|
440
|
+
exports.GoalBar = GoalBar;
|
|
441
|
+
exports.GoalDock = GoalDock;
|
|
442
|
+
exports.apply = apply;
|
|
443
|
+
exports.inject = inject;
|
|
444
|
+
return module.exports;
|
|
445
|
+
}
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
//# sourceMappingURL=client.js.map
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//#region lib/types/index.js
|
|
2
|
+
/**
|
|
3
|
+
* Goal surface plugin, node half. Pure UI plugin: the empty apply exists so
|
|
4
|
+
* the plugin appears in the host cordis.yml / Loader; the browser half
|
|
5
|
+
* ships via exports["./client"], discovered through the package.json
|
|
6
|
+
* dsh.client declaration.
|
|
7
|
+
*/
|
|
8
|
+
/** Host plugin body — no host-side behavior for this surface plugin. */
|
|
9
|
+
function apply() {}
|
|
10
|
+
//#endregion
|
|
11
|
+
export { apply };
|
package/lib/invariant.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
//#region lib/types/invariant.js
|
|
2
|
+
/**
|
|
3
|
+
* Package-owned invariant companion for `@prettier-ai/dsh-client-ui-goal`.
|
|
4
|
+
* @module @prettier-ai/dsh-client-ui-goal/invariant
|
|
5
|
+
*/
|
|
6
|
+
const PACKAGE_NAME = "@prettier-ai/dsh-client-ui-goal";
|
|
7
|
+
/** Cordis companion plugin name. */
|
|
8
|
+
const name = "client-ui-goal-invariant";
|
|
9
|
+
/** Service required before the companion can reserve package ownership. */
|
|
10
|
+
const inject = ["invariants"];
|
|
11
|
+
/**
|
|
12
|
+
* No runtime invariant: a single GoalBar dock registration whose disposal is
|
|
13
|
+
* proven by the HMR-safety spec — the plugin owns no store (state arrives on
|
|
14
|
+
* the goal projection), emits no cordis events, and holds no cross-plugin
|
|
15
|
+
* mutable state.
|
|
16
|
+
*/
|
|
17
|
+
const install = () => {};
|
|
18
|
+
/**
|
|
19
|
+
* Register this package's invariant companion.
|
|
20
|
+
* @param ctx - Cordis context carrying the invariant service.
|
|
21
|
+
* @returns the installed registration's disposer after setup succeeds.
|
|
22
|
+
*/
|
|
23
|
+
const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
|
|
24
|
+
//#endregion
|
|
25
|
+
export { apply, inject, name };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GoalBar: the goal indicator docked above the message composer (input dock
|
|
3
|
+
* strip). A present goal shows a goal glyph, a phase label, the truncated
|
|
4
|
+
* objective, and icon actions — resume when paused, edit (inline form in the
|
|
5
|
+
* same strip), and clear. Goal creation lives on the `/goal` command, not
|
|
6
|
+
* here: loading (undefined), no goal (null), and complete goals render
|
|
7
|
+
* nothing. Live state arrives as the projected whole snapshot; the verbs are
|
|
8
|
+
* the injected face.
|
|
9
|
+
*/
|
|
10
|
+
import type { GoalSnapshot } from '@prettier-ai/dsh-goal/client';
|
|
11
|
+
import type { PropsLocale } from '@prettier-ai/dsh-client-ui-slots';
|
|
12
|
+
import type { GoalBarActions } from './slots.ts';
|
|
13
|
+
export interface GoalBarProps extends GoalBarActions {
|
|
14
|
+
/** Current goal snapshot; undefined = capability absent or loading, null = no goal set. */
|
|
15
|
+
goal: GoalSnapshot | null | undefined;
|
|
16
|
+
}
|
|
17
|
+
export declare function GoalBar({ goal, onEdit, onPause, onResume, onClear, t }: GoalBarProps & PropsLocale<'goal'>): import("react").JSX.Element | null;
|
|
18
|
+
/** Full props of the dock entry: InputZone owner share + session standard kit + injected verbs + the locale seat. */
|
|
19
|
+
export type GoalDockProps = import('@prettier-ai/dsh-client-ui-slots').PropsRuntime<'conversation.input.dock'> & GoalBarActions & PropsLocale<'goal'>;
|
|
20
|
+
/** Dock adapter: reads the host-computed 'goal' projection (whole value; absent or null renders nothing). */
|
|
21
|
+
export declare function GoalDock({ useProjection, onEdit, onPause, onResume, onClear, t }: GoalDockProps): import("react").JSX.Element;
|
|
22
|
+
//# sourceMappingURL=GoalBar.d.ts.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { PropsLocale, PropsRuntime } from '@prettier-ai/dsh-client-ui-slots';
|
|
2
|
+
type GoalCommandInputViewProps = PropsRuntime<'conversation.chat.node', 'command-input'> & PropsLocale<'goal'>;
|
|
3
|
+
/** Right-aligned `/goal` input bubble without ordinary message actions. */
|
|
4
|
+
export declare const GoalCommandInputView: import("react").MemoExoticComponent<({ node, t, }: GoalCommandInputViewProps) => import("react").JSX.Element>;
|
|
5
|
+
export {};
|
|
6
|
+
//# sourceMappingURL=GoalCommandInputView.d.ts.map
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { SessionEvent } from '@prettier-ai/dsh-session/types';
|
|
2
|
+
import type { CommandId } from '@prettier-ai/dsh-commands/brand';
|
|
3
|
+
import type { ConversationNodeDefinition } from '@prettier-ai/dsh-client-ui-conversation/client';
|
|
4
|
+
/** Goal-owned human command input projected independently of model messages. */
|
|
5
|
+
export interface GoalCommandInputData {
|
|
6
|
+
readonly commandId: CommandId;
|
|
7
|
+
readonly text: string;
|
|
8
|
+
readonly time: number;
|
|
9
|
+
}
|
|
10
|
+
declare module '@prettier-ai/dsh-client-ui-chat/client' {
|
|
11
|
+
interface ChatNodeDataMap {
|
|
12
|
+
/** Human-entered `/goal` command input. */
|
|
13
|
+
'command-input': GoalCommandInputData;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
interface GoalCommandInputState extends GoalCommandInputData {
|
|
17
|
+
readonly seq: number;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Derive the visible command line from its structured durable run.
|
|
21
|
+
* @param event - `/goal` command run.
|
|
22
|
+
* @returns command text with trailing parser whitespace removed.
|
|
23
|
+
*/
|
|
24
|
+
export declare function goalCommandText(event: SessionEvent<'command/run'>): string;
|
|
25
|
+
/** Goal-owned command input projection; the generic command Definition retains the result row. */
|
|
26
|
+
export declare const goalCommandInputDefinition: ConversationNodeDefinition<GoalCommandInputState>;
|
|
27
|
+
export {};
|
|
28
|
+
//# sourceMappingURL=goal-command-input.d.ts.map
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Goal surface plugin, browser half: the GoalBar entry in the
|
|
3
|
+
* conversation.input.dock strip. Projection-mode surface — the live goal
|
|
4
|
+
* arrives through `useProjection('goal')` (seeded by the history tail page,
|
|
5
|
+
* updated by session/projection frames), so this plugin owns no store, no
|
|
6
|
+
* refresh chain, and no event listener. The inject face carries only the
|
|
7
|
+
* four mutation verbs through the generated Goal Remote API;
|
|
8
|
+
* their CAS ref reads the session's current projected value at call time.
|
|
9
|
+
* This plugin does not create goals; deployments may expose /goal separately.
|
|
10
|
+
*/
|
|
11
|
+
import type { Context as ClientContext } from '@prettier-ai/cordis';
|
|
12
|
+
import { type GoalKey } from './locales.ts';
|
|
13
|
+
export { GoalBar, GoalDock } from './GoalBar.tsx';
|
|
14
|
+
export type { GoalActionResult, GoalBarActions } from './slots.ts';
|
|
15
|
+
export type { GoalKey } from './locales.ts';
|
|
16
|
+
declare module '@prettier-ai/dsh-client-ui-slots' {
|
|
17
|
+
interface LocaleNamespaceMap {
|
|
18
|
+
/** The goal strip's copy. */
|
|
19
|
+
goal: GoalKey;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/** Required services for the Goal dock, command-input projection, Remote mutations, and copy. */
|
|
23
|
+
export declare const inject: string[];
|
|
24
|
+
/**
|
|
25
|
+
* Client plugin body: the GoalBar dock entry with its mutation verbs.
|
|
26
|
+
* @param ctx - client root context.
|
|
27
|
+
*/
|
|
28
|
+
export declare function apply(ctx: ClientContext): void;
|
|
29
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** `goal` namespace dictionaries. */
|
|
2
|
+
/** Simplified Chinese dictionary (the key-set source of truth). */
|
|
3
|
+
export declare const zh: {
|
|
4
|
+
'phase.active': string;
|
|
5
|
+
'phase.paused': string;
|
|
6
|
+
'phase.blocked': string;
|
|
7
|
+
'objective.aria': string;
|
|
8
|
+
'commandInput.aria': string;
|
|
9
|
+
'action.save': string;
|
|
10
|
+
'action.cancel': string;
|
|
11
|
+
'action.pause': string;
|
|
12
|
+
'action.resume': string;
|
|
13
|
+
'action.edit': string;
|
|
14
|
+
'action.clear': string;
|
|
15
|
+
};
|
|
16
|
+
/** The goal namespace key union. */
|
|
17
|
+
export type GoalKey = keyof typeof zh;
|
|
18
|
+
/** English dictionary, checked complete against the zh key set. */
|
|
19
|
+
export declare const en: {
|
|
20
|
+
'phase.active': string;
|
|
21
|
+
'phase.paused': string;
|
|
22
|
+
'phase.blocked': string;
|
|
23
|
+
'objective.aria': string;
|
|
24
|
+
'commandInput.aria': string;
|
|
25
|
+
'action.save': string;
|
|
26
|
+
'action.cancel': string;
|
|
27
|
+
'action.pause': string;
|
|
28
|
+
'action.resume': string;
|
|
29
|
+
'action.edit': string;
|
|
30
|
+
'action.clear': string;
|
|
31
|
+
};
|
|
32
|
+
//# sourceMappingURL=locales.d.ts.map
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GoalBar's injected face. The target 'conversation.input.dock' slot is
|
|
3
|
+
* declared (children table) and typed by ui-conversation; this package only
|
|
4
|
+
* contributes the entry, so no SlotMap merge lives here. The live goal value
|
|
5
|
+
* is NOT part of this face — it arrives through `useProjection('goal')`
|
|
6
|
+
* (the framework standard kit); inject carries only the mutation verbs
|
|
7
|
+
* (callbacks from inject, live state from useProjection).
|
|
8
|
+
*/
|
|
9
|
+
import type { RemoteResult } from '@prettier-ai/dsh-typert-protocol';
|
|
10
|
+
/**
|
|
11
|
+
* Settled outcome of one goal mutation, rendered inline by the strip. The
|
|
12
|
+
* strip renders the failure only — the mutated goal arrives through the
|
|
13
|
+
* projection — so the success value stays unread here.
|
|
14
|
+
*/
|
|
15
|
+
export type GoalActionResult = RemoteResult<unknown>;
|
|
16
|
+
/** Injected business face of the GoalBar dock entry: the mutation verbs (function properties: the strip destructures them freely). */
|
|
17
|
+
export interface GoalBarActions {
|
|
18
|
+
/**
|
|
19
|
+
* Replace the current goal's objective (CAS on the projected ref).
|
|
20
|
+
* @param objective - replacement objective text.
|
|
21
|
+
*/
|
|
22
|
+
onEdit: (objective: string) => Promise<GoalActionResult>;
|
|
23
|
+
/** Pause an active goal. */
|
|
24
|
+
onPause: () => Promise<GoalActionResult>;
|
|
25
|
+
/** Resume a paused goal. */
|
|
26
|
+
onResume: () => Promise<GoalActionResult>;
|
|
27
|
+
/** Clear the current goal (tombstone). */
|
|
28
|
+
onClear: () => Promise<GoalActionResult>;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=slots.d.ts.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Goal surface plugin, node half. Pure UI plugin: the empty apply exists so
|
|
3
|
+
* the plugin appears in the host cordis.yml / Loader; the browser half
|
|
4
|
+
* ships via exports["./client"], discovered through the package.json
|
|
5
|
+
* dsh.client declaration.
|
|
6
|
+
*/
|
|
7
|
+
/** Host plugin body — no host-side behavior for this surface plugin. */
|
|
8
|
+
export declare function apply(): void;
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Package-owned invariant companion for `@prettier-ai/dsh-client-ui-goal`.
|
|
3
|
+
* @module @prettier-ai/dsh-client-ui-goal/invariant
|
|
4
|
+
*/
|
|
5
|
+
import type { Context } from '@prettier-ai/cordis';
|
|
6
|
+
/** Cordis companion plugin name. */
|
|
7
|
+
export declare const name = "client-ui-goal-invariant";
|
|
8
|
+
/** Service required before the companion can reserve package ownership. */
|
|
9
|
+
export declare const inject: string[];
|
|
10
|
+
/**
|
|
11
|
+
* Register this package's invariant companion.
|
|
12
|
+
* @param ctx - Cordis context carrying the invariant service.
|
|
13
|
+
* @returns the installed registration's disposer after setup succeeds.
|
|
14
|
+
*/
|
|
15
|
+
export declare const apply: (ctx: Context) => Promise<() => void>;
|
|
16
|
+
//# sourceMappingURL=invariant.d.ts.map
|
package/package.json
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@prettier-ai/dsh-client-ui-goal",
|
|
3
|
+
"description": "Session goal surface: GoalBar docked above the composer, read from the goal session projection",
|
|
4
|
+
"version": "0.1.2-alpha.1",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public"
|
|
7
|
+
},
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/deepseek-ai/deepseek-harness.git",
|
|
11
|
+
"directory": "packages/client/ui-goal"
|
|
12
|
+
},
|
|
13
|
+
"type": "module",
|
|
14
|
+
"main": "lib/index.js",
|
|
15
|
+
"types": "lib/types/index.d.ts",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./lib/types/index.d.ts",
|
|
19
|
+
"default": "./lib/index.js"
|
|
20
|
+
},
|
|
21
|
+
"./invariant": {
|
|
22
|
+
"types": "./lib/types/invariant.d.ts",
|
|
23
|
+
"default": "./lib/invariant.js"
|
|
24
|
+
},
|
|
25
|
+
"./client": {
|
|
26
|
+
"types": "./lib/types/client/index.d.ts",
|
|
27
|
+
"default": "./lib/client.js"
|
|
28
|
+
},
|
|
29
|
+
"./src/*": "./src/*",
|
|
30
|
+
"./package.json": "./package.json"
|
|
31
|
+
},
|
|
32
|
+
"dsh": {
|
|
33
|
+
"client": {
|
|
34
|
+
"inject": [
|
|
35
|
+
"@prettier-ai/dsh-api-remotes",
|
|
36
|
+
"@prettier-ai/dsh-api-session-controller",
|
|
37
|
+
"@prettier-ai/dsh-client-locale",
|
|
38
|
+
"@prettier-ai/dsh-client-ui-chat",
|
|
39
|
+
"@prettier-ai/dsh-client-ui-conversation",
|
|
40
|
+
"@prettier-ai/dsh-client-ui-renderer",
|
|
41
|
+
"@prettier-ai/dsh-client-ui-session"
|
|
42
|
+
],
|
|
43
|
+
"platform": "web"
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"license": "MIT",
|
|
47
|
+
"peerDependencies": {
|
|
48
|
+
"@prettier-ai/dsh-api-remotes": "^0.1.2-alpha.1",
|
|
49
|
+
"@prettier-ai/dsh-api-session-controller": "^0.1.2-alpha.1",
|
|
50
|
+
"@prettier-ai/dsh-client-ui-chat": "^0.1.2-alpha.1",
|
|
51
|
+
"@prettier-ai/dsh-client-ui-conversation": "^0.1.2-alpha.1",
|
|
52
|
+
"@prettier-ai/dsh-client-ui-renderer": "^0.1.2-alpha.1",
|
|
53
|
+
"@prettier-ai/dsh-client-locale": "^0.1.2-alpha.1",
|
|
54
|
+
"@prettier-ai/dsh-client-ui-session": "^0.1.2-alpha.1",
|
|
55
|
+
"@prettier-ai/dsh-goal": "^0.1.2-alpha.1",
|
|
56
|
+
"@prettier-ai/dsh-session": "^0.1.2-alpha.1",
|
|
57
|
+
"@prettier-ai/dsh-commands": "^0.1.2-alpha.1",
|
|
58
|
+
"@prettier-ai/dsh-typert-protocol": "^0.1.2-alpha.1",
|
|
59
|
+
"@prettier-ai/dsh-invariants": "^0.1.2-alpha.1",
|
|
60
|
+
"@prettier-ai/cordis": "^4.0.1"
|
|
61
|
+
},
|
|
62
|
+
"devDependencies": {
|
|
63
|
+
"@testing-library/react": "^16.1.0",
|
|
64
|
+
"@types/react": "~18.3.1",
|
|
65
|
+
"react": "^18.2.0",
|
|
66
|
+
"react-dom": "^18.2.0",
|
|
67
|
+
"@prettier-ai/dsh-api-remotes": "^0.1.2-alpha.1",
|
|
68
|
+
"@prettier-ai/dsh-api-session-controller": "^0.1.2-alpha.1",
|
|
69
|
+
"@prettier-ai/dsh-client-locale": "^0.1.2-alpha.1",
|
|
70
|
+
"@prettier-ai/dsh-client-test-runtime": "^0.1.2-alpha.1",
|
|
71
|
+
"@prettier-ai/dsh-client-ui-chat": "^0.1.2-alpha.1",
|
|
72
|
+
"@prettier-ai/dsh-client-ui-conversation": "^0.1.2-alpha.1",
|
|
73
|
+
"@prettier-ai/dsh-client-ui-primitives": "^0.1.2-alpha.1",
|
|
74
|
+
"@prettier-ai/dsh-client-ui-slots": "^0.1.2-alpha.1",
|
|
75
|
+
"@prettier-ai/dsh-client-ui-renderer": "^0.1.2-alpha.1",
|
|
76
|
+
"@prettier-ai/dsh-client-ui-session": "^0.1.2-alpha.1",
|
|
77
|
+
"@prettier-ai/dsh-goal": "^0.1.2-alpha.1",
|
|
78
|
+
"@prettier-ai/cordis": "^4.0.1",
|
|
79
|
+
"@prettier-ai/dsh-commands": "^0.1.2-alpha.1",
|
|
80
|
+
"@prettier-ai/dsh-invariants": "^0.1.2-alpha.1",
|
|
81
|
+
"@prettier-ai/dsh-session": "^0.1.2-alpha.1",
|
|
82
|
+
"@prettier-ai/dsh-typert-protocol": "^0.1.2-alpha.1"
|
|
83
|
+
},
|
|
84
|
+
"files": [
|
|
85
|
+
"lib/index.js",
|
|
86
|
+
"lib/invariant.js",
|
|
87
|
+
"lib/client.js",
|
|
88
|
+
"lib/types/**/*.d.ts"
|
|
89
|
+
],
|
|
90
|
+
"scripts": {
|
|
91
|
+
"bundle": "tsdown",
|
|
92
|
+
"watch": "tsdown --watch"
|
|
93
|
+
}
|
|
94
|
+
}
|