dsh-foreman 0.3.2 → 0.3.4

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/CHANGELOG.md CHANGED
@@ -6,6 +6,43 @@
6
6
 
7
7
  本项目自己的版本从 `0.1.0` 开始。
8
8
 
9
+ ## 0.3.4 — 2026-11-08
10
+
11
+ ### 修复:设备回报只进了账本,主会话从没收到
12
+
13
+ 远程设备的 `report` 帧只调了 `engine.report(...)`,**没有生成 relay**。后果是那张工单在面板上显示
14
+ `ready`、`ended`,但派它的主会话完全不知道——既不把结果转达给人,也不会据此继续处理。
15
+
16
+ 本地 worker 的 `orchestrator_report` 工具一直有这一步(`reportRelay` + `steer`),远程这条路径从来没接上。
17
+
18
+ 现在 `applyReport` 补上同一道缝:报告入账后生成 relay 并 steer 到发起该工单的主会话。
19
+ `reportRelay` 自己决定哪些值得打扰人——`progress` 仍然留在内部,`ready` / `blocked` / `failed`
20
+ 会唤醒主会话,由它决定是转达结果还是接着做下一步。
21
+
22
+ relay 失败只记日志:报告已经入账,不能因为通知不到就把它退回去。
23
+
24
+ ## 0.3.3 — 2026-11-08
25
+
26
+ ### 改进:派单时直接告诉设备「你就是那台机器」
27
+
28
+ 人在 hub 上写「看看宿舍电脑上的项目结构」。「宿舍电脑」就是收到这条任务的那台机器,但**派单文本里
29
+ 没有一句话说明这件事**——设备收到的只有标题和请求原文。
30
+
31
+ 于是模型每次都要先花不少步数去比对设备名、列目录、找自己在哪儿,确认之后才真正开始干活。
32
+
33
+ 现在每张派单的开头多了一段:
34
+
35
+ ```
36
+ ## Where this job runs
37
+
38
+ You are the device **宿舍电脑** (id `pc`) working in `F:\dsh`. When the request names this machine —
39
+ "宿舍电脑", or "this computer", "here", "the machine you are on" — it means you, and the files are
40
+ already under that directory. Do not go looking for another machine.
41
+ ```
42
+
43
+ 只把**登记的设备名**当作别名。目录的最后一段通常是项目名(`shop`),把它说成机器别名会让模型
44
+ 搞不清那是项目还是主机。
45
+
9
46
  ## 0.3.2 — 2026-11-08
10
47
 
11
48
  ### 修复:派单文本没有说要回报
package/lib/index.js CHANGED
@@ -9629,6 +9629,16 @@ function attachmentSection(names) {
9629
9629
  * wrote a complete answer, and never called `foreman_report`, so the hub sat at `running` with no report forever and
9630
9630
  * a person saw a job that never finished. The tool exists, but nothing told the model it was required or final.
9631
9631
  */
9632
+ /**
9633
+ * Where this job is running, stated so the device never has to deduce that the request referred to itself.
9634
+ *
9635
+ * A person at the hub writes about their machines by name ("the dorm computer", "my laptop"). The device that receives
9636
+ * that sentence IS one of those machines, but nothing in the text said which one, so the model spent its first steps
9637
+ * comparing names, listing directories and looking for itself. This is one line that ends that.
9638
+ */
9639
+ function locationSection(device) {
9640
+ return `\n## Where this job runs\n\nYou are the device **${device.name}** (id \`${device.id}\`) working in \`${device.directory}\`. When the request names this machine — "${device.name}", or "this computer", "here", "the machine you are on" — it means you, and the files are already under that directory. Do not go looking for another machine.\n`;
9641
+ }
9632
9642
  const REPORT_SECTION = [
9633
9643
  "\n## Reporting back\n",
9634
9644
  "\nWhen you have finished, call `foreman_report` — that tool is how this job reaches the person who asked, and ",
@@ -9654,9 +9664,11 @@ function renderForDevice(input) {
9654
9664
  }
9655
9665
  const scope = scopeOf(ticket);
9656
9666
  const request = trigger?.text?.trim() ?? "";
9667
+ const location = input.device === void 0 ? "" : locationSection(input.device);
9657
9668
  return {
9658
9669
  text: [
9659
9670
  `# ${ticket.title}`,
9671
+ location,
9660
9672
  scope === "" ? "" : `\n${scope}\n`,
9661
9673
  request === "" ? "" : `\n## The request as it was written\n\n${request}\n`,
9662
9674
  attachmentSection(attachments.map((attachment) => attachment.name ?? attachment.id)),
@@ -9812,7 +9824,11 @@ var ForemanExecutor = class {
9812
9824
  }));
9813
9825
  }
9814
9826
  assignFrame(ticket, assignment, deviceId, directory) {
9815
- const rendered = this.render(ticket);
9827
+ const device = this.input.deviceOf?.(deviceId);
9828
+ const rendered = this.render(ticket, device === void 0 ? void 0 : {
9829
+ ...device,
9830
+ directory
9831
+ });
9816
9832
  return {
9817
9833
  v: 1,
9818
9834
  type: "assign",
@@ -9829,11 +9845,12 @@ var ForemanExecutor = class {
9829
9845
  * The task as the device reads it. Rendered on the hub because the device has none of the hub's resources; the
9830
9846
  * device directory rides on the frame, not in the text.
9831
9847
  */
9832
- render(ticket) {
9848
+ render(ticket, device) {
9833
9849
  return renderForDevice({
9834
9850
  ticket,
9835
9851
  ...(this.input.triggerOf ?? (() => ({})))(ticket),
9836
- readAttachment: this.input.readAttachment ?? (() => Buffer.alloc(0))
9852
+ readAttachment: this.input.readAttachment ?? (() => Buffer.alloc(0)),
9853
+ ...device === void 0 ? {} : { device }
9837
9854
  });
9838
9855
  }
9839
9856
  /** Append work to the send chain, keeping the chain alive after a failure. */
@@ -10354,6 +10371,11 @@ function applyReport(input) {
10354
10371
  summary: frame.summary,
10355
10372
  ...frame.question === void 0 ? {} : { question: frame.question }
10356
10373
  });
10374
+ try {
10375
+ input.relay?.(where.ticketId);
10376
+ } catch (error) {
10377
+ input.log(`could not relay the report for ${where.ticketId}: ${String(error)}`);
10378
+ }
10357
10379
  };
10358
10380
  }
10359
10381
  /**
@@ -11924,6 +11946,13 @@ var Runtime = class extends Service {
11924
11946
  local: executor,
11925
11947
  readAttachment: (id) => readFileSync(attachmentPath(id)),
11926
11948
  triggerOf: (ticket) => ({ trigger: store.triggers.get(ticket.origin.triggerId) }),
11949
+ deviceOf: (id) => {
11950
+ const device = this.devices.get(id);
11951
+ return device === void 0 ? void 0 : {
11952
+ id: device.id,
11953
+ name: device.name
11954
+ };
11955
+ },
11927
11956
  engine: () => this.engine,
11928
11957
  transport: { send: (deviceId, frame) => this.hub?.send(deviceId, frame) ?? Promise.reject(/* @__PURE__ */ new Error(`the foreman hub is not listening, so ${deviceId} cannot be reached`)) },
11929
11958
  log: (text) => ctx.logger.warn("dsh-foreman: %s", text)
@@ -11972,6 +12001,14 @@ var Runtime = class extends Service {
11972
12001
  engine.report(ticketId, workerReport);
11973
12002
  },
11974
12003
  ticketOf: (assignmentId) => assignmentWhere(store, assignmentId),
12004
+ relay: (ticketId) => {
12005
+ const ticket = store.tickets.get(ticketId);
12006
+ if (ticket === void 0) return;
12007
+ const report = latestAssignment(ticket)?.report;
12008
+ if (report === void 0) return;
12009
+ const relay = reportRelay(ticket, report);
12010
+ if (relay !== void 0) sessions.relay(relay.id, relay.text, this.masterOf(store.triggers.get(ticket.origin.triggerId)));
12011
+ },
11975
12012
  log: (text) => ctx.logger.warn("dsh-foreman: %s", text)
11976
12013
  });
11977
12014
  const evals = board.claim("evals", {
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "dsh-foreman",
3
3
  "author": "niechao136",
4
4
  "license": "MIT",
5
- "version": "0.3.2",
5
+ "version": "0.3.4",
6
6
  "description": "dsh-foreman:主 loop 在多设备上派单的 DSH bundle:需求来自本机操作者的主会话而不是 GitHub/飞书,每个工作区各有一条主会话,主会话只负责路由,真正的活儿派给 Worker 在该工作区目录里执行。",
7
7
  "type": "module",
8
8
  "main": "lib/index.js",