Skip to content

Releases: kjx-talesofai/dsh-plugin-localhost

v0.4.0 — auto-start per service, and a delete that deletes

Choose a tag to compare

@kjx-talesofai kjx-talesofai released this 21 Oct 05:02

An agent registered a service, wanted it gone, and found no Remove button and no remove action. So it edited the registry file by hand. The row vanished from disk, stayed in the panel, and the next save wrote it back. Only a restart cleared it.

A delete that deletes

  • serve remove for the agent, a Remove button (in the expanded tile) for you: the first click asks, the second removes, and the process stops first.
  • The registry file is now the truth and memory is its cache. Every read compares mtime:size, so a row deleted on disk is dropped and what it owned is stopped; a row added on disk shows up as stopped; a half-written file keeps the rows it had.
  • remove is idempotent — the second click of a confirm button deserves "done", not "no such service".

Auto-start, per service

  • "autoStart": true on register, or the pill on the tile. Default off.
  • The boot pass runs once the composition is up, not inside apply(): this plugin does not inject the subprocess service, so that seam may mount later. It retries from the existing 700 ms tick.
  • A failure — port taken, directory deleted — stays on its row and is never thrown. A static entry whose directory is gone refuses to start instead of binding a port that would only answer 404.

Smaller truth repairs

  • Stopping a service now drops idle keep-alive sockets, so "stopped" means the port no longer answers.
  • Tool budget 975 → 1073 characters; the two new verbs earned it.

59 tests (was 41). docs/plan.md §17 records the incident and the reasoning.

Restart DSH to load the new host half.

v0.3.0 — 在你看的那台设备上打开

Choose a tag to compare

@kjx-talesofai kjx-talesofai released this 17 Oct 20:44

手机点「打开」,Mac 弹出浏览器。这不是 bug —— 那个按钮的语义一直是在宿主上打开,而它只写了一半。

拆成两件事:

谁打开

  • 本机页面(dsh: / 127.0.0.1)→ 还是让 Host 跑 /usr/bin/open
  • 手机页面(https://…ts.net)→ window.open,在你手上这台打开

打开哪个地址
127.0.0.1:8840 在手机上指的是手机自己。Host 半边读 tailscale serve status --json,把已发布的端口映射成 https 地址,塞进每条服务的 remoteUrl。

  • 最多每 5 秒跑一次(列表请求触发 + 缓存,并发共享一次执行)
  • tailscale 没装/没登录/没配置 → 空表,"没发布"就是事实,面板照常工作
  • 只认 127.0.0.1 / localhost 的 proxy,别人的映射不碰

没发布的端口在手机上不给「打开」按钮,而是写「只在本机可访问」。

在你的机器上现在是这样:

https://jiaxin-mbpm2.taila3698f.ts.net:8443  → 127.0.0.1:8840   ← 电台

所以手机上点击会直接打开 https://…:8443/the-way-back/index.html。

45 条测试(含一条用假的 tailscale 可执行文件跑真实 execFile 路径的)。

改了 host 半边,需要重启 DSH。

v0.2.3 — 用 shell 自己的点

Choose a tag to compare

@kjx-talesofai kjx-talesofai released this 17 Oct 20:35

导航行那个点比 Tailscale 的大一圈。原因不是位置,是那两个 8px 不是一回事:

  • StateDot({ size: 8 }) 的 size 是画它的盒子,里面的圆更小;
  • 我手写了一个 width:8px 的圆,于是看起来正好大一倍。

改成直接向 primitives 要同一个组件:StateDot({ state: 'done', size: 8 }) —— 和 Tailscale 那行同源,同一尺寸、同一位置(right:-4 / bottom:-3)。拿不到 primitive 表时退回 6px 圆。

教训记在 docs/plan.md §15:能复用 shell 自己的零件就别自己画,尺寸这种东西"看一眼觉得不对、又说不出差在哪"最费时间。

39 条测试。只改客户端,刷新页面(⌘R)。

v0.2.2 — 导航行的绿点

Choose a tag to compare

@kjx-talesofai kjx-talesofai released this 17 Oct 20:31

侧边栏那一行是常驻的,面板不是。所以「有没有服务在跑」不该只能点进面板才知道。

现在有服务在跑时,Localhost 图标右下角有一个绿点——位置和尺寸照 Tailscale 那行的红点来(right:-4 / bottom:-3、8px、state-success-primary)。

  • 图标 10s 轮询一次,面板 2.5s 一次,共用同一个 fetchServices()
  • 没有做跨组件订阅:一个导航点晚几秒亮起来,不值得一套 store

39 条测试(新增 3 条:有服务亮、全停不亮、空表不亮)。

只改客户端,刷新页面(⌘R)即可。

v0.2.1 — 卡片,以及那个点不动的按钮

Choose a tag to compare

@kjx-talesofai kjx-talesofai released this 17 Oct 20:22

排版:一行一个 → tile

一行一个服务把宽度浪费在空白上。现在是自动填充的网格(minmax(296px, 1fr)),宽了多列、窄了一列。每张卡:

● Kibellah Radio            [command]
:8840   running
http://127.0.0.1:8840/the-way-back/index.html
[Open] [Stop]                              [▼]

URL 单独一行、省略号截断 —— 它才是"这东西在哪"的答案。展开是卡内详情(目录、命令、会话、日志)。

那个点不动的「跳到会话」

uiWorkspace 之前是 ctx.get('uiWorkspace') 拿的。客户端 ctx 是白名单代理:没在 inject 里声明的服务返回 undefined,于是点击静默无效 —— 没有报错,什么都没发生。

改成声明式 inject(和 palette 一样),并加测试真的点一下、断言 openSession 收到正确的 session id。

36 条测试。只改客户端半边,刷新页面(⌘R)就行,不用重启。

v0.2.0 — 工具瘦身到 244 tokens

Choose a tag to compare

@kjx-talesofai kjx-talesofai released this 17 Oct 20:16

serve 是全局工具:每个 agent、每次请求都在列表里。所以它的体积是配额,不是文风。

版本 模型可见负载
0.1.x 1668 字符 ≈ 417 tokens
0.2.0 975 字符 ≈ 244 tokens

砍掉的全是不承载信息的字:

  • description 两段并一句(管什么、端口谁分、什么时候停)
  • action / kind 的 enum 下面还各有一句重复枚举的 description —— 删
  • entry 参数删掉:静态页默认 index.html,要改有 path

测试钉了预算:序列化负载超过 1000 字符就红。以后加字段得先决定从哪儿省。

为什么没做 CLI + SKILL:skill 是按需加载的手册,而这里要防的是「起服务那一瞬间没想到登记」——手册救不了那一刻,工具列表可以。CLI 还要另造 token 认证和第二条与工具同步的输出契约(0.1.1、0.1.2 两个 bug 都是"两处要一致却没一致")。等有第二个消费者再谈。

BREAKING:entry 参数从工具里去掉了。注册表字段保留。

34 条测试。安装:github:kjx-talesofai/dsh-plugin-localhost#v0.2.0,装完重启。

v0.1.4 — 工具说明说清楚:面板读的是注册表

Choose a tag to compare

@kjx-talesofai kjx-talesofai released this 17 Oct 20:10

只改工具描述,没有行为改动,32 条测试不变。

那个会话的诊断里有一句推错了:「如果面板里看不到这一项,原因就在这条报错」。面板不看工具返回值 —— 它调 /api/localhost.list,直接读注册表。所以工具输出失败时面板照样能列出服务(你看到的也是这样)。

描述里现在还写清了:Open 打开的是 url,也就是端口 + 登记时给的 path。

(serve list 那条 entry is not a declared property 的报错是 0.1.3 修的;需要重启才会生效。)

v0.1.3 — 打开的是它真正服务的那个页面

Choose a tag to compare

@kjx-talesofai kjx-talesofai released this 17 Oct 20:07

第一件真实的东西登记进来了(kibellah-radio,python3 serve.py station),服务本身完全正常——/the-way-back/index.html 返回 200、Range 请求返回 206。但面板上的「打开」去的是 http://127.0.0.1:8840/,那个服务器没有根路由,于是 404。

模型错了,不是按钮错了

一个被托管的服务,"地址"不等于"它的根"。所以:

  • 登记项多一个 path,url = 端口 + path
  • 面板详情多一行「打开地址」,把按钮会去的完整 URL 写出来

另外三个

工具的输出被自己的 schema 拒收。 view() 返回 entry / pid / startedAt / createdAt,schema 只声明了子集,additionalProperties: false 于是报 "value.services[0].entry" is not a declared property —— 服务起来了,结果吐不出来,serve list 直接失败。现在字段表是一份数据,view() 和 schema 都从它派生,测试对比两边。

登记会话永远是空的。 我编了一个 context.__agent,真实字段是 exec.agent。那条 Kibellah 的 sessionId 因此是空字符串。

重复登记会占第二个端口。 同目录同命令再登记一次,现在是更新(补 path、改名字),不是新增。忘了 path 的 agent 不需要"删掉重来"——那会把一个正在工作的服务杀掉。

32 条测试。

安装:github:kjx-talesofai/dsh-plugin-localhost#v0.1.3。装完重启,然后让那个会话重新 serve register 一次(补上 path),条目会原地更新。

v0.1.2 — 404 与看不清的字

Choose a tag to compare

@kjx-talesofai kjx-talesofai released this 17 Oct 20:00

两个 bug,一个让数据拿不到,一个让字看不见。都不是"没写",是"写错了方言/选错了 token"。

1. HTTP 404

面板渲染出来了,但请求 /api/localhost.list 返回 404。

原因:ctx.tools.register() 收的是成品 ToolDefinition,parameters 和 output.schema 必须是 JSON Schema。我给了 defineTool() 用的那种"参数规格"方言(required: true 写在字段里),assertSupportedJsonSchema 直接抛错。Cordis 的 fiber 失败会回滚整个 apply —— 于是紧挨着的工具之前注册的那些路由,全被撤掉了。客户端半点独立于 host fiber,所以面板还在、数据没了。

修:改成真 JSON Schema。测试新增一条遍历 schema 的断言:只允许支持的关键词、required 必须是数组。

2. 字淡到看不见

奶油主题里 --dsw-alias-label-dimmed 是 mix(canvas, ink, 0.125) —— 12.5% 的墨,对比度约 1.2:1。它是给占位符和骨架屏的,我却拿来当副标题、页脚、空状态正文。

修:元信息用 label-tertiary(3.76:1),正文用 label-secondary(5.85:1)。另加一条测试:面板 CSS 里出现 label-dimmed 就红。

27 条测试全绿。

安装:github:kjx-talesofai/dsh-plugin-localhost#v0.1.2。装完重启。

v0.1.1 — 让插件真的挂上

Choose a tag to compare

@kjx-talesofai kjx-talesofai released this 17 Oct 19:57

0.1.0 装上了但从来没挂载过。 面板不出现,不是 UI 的问题,是补丁文件少了一层。

# 0.1.0(错的):顶层裸行 = 对某个已存在条目的 patch
- id: localhost
  name: dsh-plugin-localhost

# 0.1.1(对的):insert 才是"新增一行"
- insert:
    - id: localhost
      name: 'dsh-plugin-localhost'

在 Loader 的批量方言里,裸行是补丁:id 还不存在,就没有东西可补。于是 profile 把它记成 overrides: ["localhost"],bundle 组合出零行,插件根本没进 composition —— 所以既没有面板,也没有 serve 工具。同期六个插件都用 - insert:,只有这个是手写的。

测试补上了:新增两条断言,读 cordis.patch.yml 检查形状(必须有 insert:、不能有裸顶层行、id/name 与包名一致)。原来的测试只 import index.js,看不见组合层的问题——这正是它漏过去的原因。25 条。

安装:github:kjx-talesofai/dsh-plugin-localhost#v0.1.1