@maplezzk/pi-dynamic-workflows 1.2.2 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maplezzk/pi-dynamic-workflows",
3
- "version": "1.2.2",
3
+ "version": "1.3.0",
4
4
  "description": "Claude-Code-style dynamic workflow orchestration for Pi. Fork of michaelliv/pi-dynamic-workflows.",
5
5
  "type": "module",
6
6
  "main": "./index.ts",
@@ -60,7 +60,7 @@
60
60
  ],
61
61
  "dependencies": {
62
62
  "acorn": "^8.16.0",
63
- "pi-extensions-i18n": "^0.4.1"
63
+ "pi-extensions-i18n": "^0.5.0"
64
64
  },
65
65
  "peerDependencies": {
66
66
  "@earendil-works/pi-ai": ">=0.80.0",
package/src/extension.ts CHANGED
@@ -1,12 +1,12 @@
1
1
  import { defineTool, type ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
2
  import { Box, Text } from "@earendil-works/pi-tui";
3
- import { createTranslator, loadCatalog } from "pi-extensions-i18n";
3
+ import { createTranslator, loadCatalog, notifyWithSource } from "pi-extensions-i18n";
4
4
  import { Type } from "typebox";
5
5
  import { loadConfig, saveConfig } from "./config.ts";
6
6
  import { cancelRunningWorkflow, createWorkflowTool, renderWorkflowThemed } from "./index.ts";
7
+ import { NOTICE_SOURCE } from "./notice.ts";
7
8
 
8
9
  const i18n = createTranslator(loadCatalog(new URL("../locales/index.json", import.meta.url)));
9
- const LOG_PREFIX = "[pi-dynamic-workflows]";
10
10
 
11
11
  export default function extension(pi: ExtensionAPI) {
12
12
  // Subagent session 不注册 workflow 工具:subagent 是 workflow 的执行节点,
@@ -122,13 +122,20 @@ function registerConfigCommand(pi: ExtensionAPI) {
122
122
 
123
123
  if (choice === choices[0]) {
124
124
  const saved = saveConfig({ backend: cfg.backend === "subagent" ? "workflow" : "subagent" });
125
- ctx.ui.notify(`${LOG_PREFIX} ${i18n.t("savedBackend", { value: saved.backend })}`, "info");
125
+ notifyWithSource({
126
+ ctx,
127
+ source: NOTICE_SOURCE,
128
+ level: "info",
129
+ message: i18n.t("savedBackend", { value: saved.backend }),
130
+ });
126
131
  } else if (choice === choices[1]) {
127
132
  const saved = saveConfig({ async: !cfg.async });
128
- ctx.ui.notify(
129
- `${LOG_PREFIX} ${i18n.t("savedAsync", { value: saved.async ? on : off })} ${i18n.t("reloadHint")}`,
130
- "info",
131
- );
133
+ notifyWithSource({
134
+ ctx,
135
+ source: NOTICE_SOURCE,
136
+ level: "info",
137
+ message: `${i18n.t("savedAsync", { value: saved.async ? on : off })} ${i18n.t("reloadHint")}`,
138
+ });
132
139
  }
133
140
  }
134
141
  },
package/src/notice.ts ADDED
@@ -0,0 +1,13 @@
1
+ /**
2
+ * 本扩展统一的提示来源定义。
3
+ * 所有 notifyWithSource 调用共用同一份标签与颜色,避免多个入口不一致。
4
+ */
5
+
6
+ import type { NoticeColor, NoticeSource } from "pi-extensions-i18n";
7
+
8
+ /** 本扩展的提示标签;短且唯一,便于在会话里定位来源。 */
9
+ export const NOTICE_TAG = "workflow";
10
+ /** 提示标签颜色;与其它扩展错开,避免看起来像同一条消息。 */
11
+ export const NOTICE_COLOR: NoticeColor = "accent";
12
+ /** 本扩展的提示来源。 */
13
+ export const NOTICE_SOURCE: NoticeSource = { tag: NOTICE_TAG, color: NOTICE_COLOR };
@@ -12,7 +12,8 @@
12
12
  // sentinel)导致的"子 agent 根本没启动就被判定完成"。herdr-split.log 9:01 失败批次
13
13
  // 模式:pane run 6ms 后 close,subagentSessionFile.jsonl 永远不存在。
14
14
  import { existsSync, statSync } from "node:fs";
15
- import { createTranslator, loadCatalog } from "pi-extensions-i18n";
15
+ import { createTranslator, loadCatalog, notifyWithSource, type NoticeColor } from "pi-extensions-i18n";
16
+ import { NOTICE_SOURCE } from "./notice.ts";
16
17
 
17
18
  const i18n = createTranslator(loadCatalog(new URL("../locales/index.json", import.meta.url)));
18
19
 
@@ -39,7 +40,13 @@ interface SubagentCtx {
39
40
  cwd: string;
40
41
  model?: unknown;
41
42
  modelRegistry?: unknown;
42
- ui?: { notify?(message: string, level: "info" | "warning" | "error"): void };
43
+ /** Pi 运行模式;只有 tui 能给来源标签上色。 */
44
+ mode?: string;
45
+ ui?: {
46
+ notify?(message: string, level: "info" | "warning" | "error"): void;
47
+ /** 主题;缺失时来源标签输出纯文本。 */
48
+ theme?: { fg(color: NoticeColor, text: string): string };
49
+ };
43
50
  [key: string]: unknown;
44
51
  }
45
52
 
@@ -117,6 +124,19 @@ export class SubagentWorkflowAgent {
117
124
  this.instructions = options.instructions;
118
125
  }
119
126
 
127
+ /** 统一提示出口:加上来源标签;ui 缺失时跳过提示,不影响流程。 */
128
+ private notify(message: string, level: "info" | "warning" | "error"): void {
129
+ const ui = this.launchCtx.ui;
130
+ if (!ui?.notify) return;
131
+ const notify = ui.notify.bind(ui);
132
+ notifyWithSource({
133
+ ctx: { mode: this.launchCtx.mode, ui: { notify, theme: ui.theme } },
134
+ source: NOTICE_SOURCE,
135
+ level,
136
+ message,
137
+ });
138
+ }
139
+
120
140
  async run(prompt: string, options: AgentRunOptions = {}): Promise<AgentRunResult> {
121
141
  const api = getSubagentApi();
122
142
 
@@ -139,7 +159,7 @@ export class SubagentWorkflowAgent {
139
159
  },
140
160
  this.launchCtx,
141
161
  );
142
- this.launchCtx.ui?.notify?.(`[workflow] "${options.label ?? "workflow-agent"}" launched (${Date.now() - launchedAt}ms)`, "info");
162
+ this.notify(`"${options.label ?? "workflow-agent"}" launched (${Date.now() - launchedAt}ms)`, "info");
143
163
 
144
164
  // Create abort signal that combines caller's signal with module-level abort
145
165
  const abortController = new AbortController();
@@ -157,8 +177,8 @@ export class SubagentWorkflowAgent {
157
177
  const watchStartedAt = Date.now();
158
178
  const result = await api.watchSubagent(running, abortController.signal);
159
179
  const watchTookMs = Date.now() - watchStartedAt;
160
- this.launchCtx.ui?.notify?.(
161
- `[workflow] "${options.label ?? "workflow-agent"}" done (${watchTookMs}ms) → ` +
180
+ this.notify(
181
+ `"${options.label ?? "workflow-agent"}" done (${watchTookMs}ms) → ` +
162
182
  `exitCode=${result.exitCode} hasOutput=${result.structuredOutput !== undefined}`,
163
183
  "info",
164
184
  );
@@ -171,8 +191,8 @@ export class SubagentWorkflowAgent {
171
191
  // 这种"假成功"比"明确失败"更危险——workflow 会把空数据当成结果继续往下走。
172
192
  const jsonlCheck = sessionFileLooksValid(running.sessionFile);
173
193
  if (!jsonlCheck.ok) {
174
- this.launchCtx.ui?.notify?.(
175
- `[workflow] "${options.label ?? "workflow-agent"}" SESSION FILE ${jsonlCheck.reason} ` +
194
+ this.notify(
195
+ `"${options.label ?? "workflow-agent"}" SESSION FILE ${jsonlCheck.reason} ` +
176
196
  `(${watchTookMs}ms, session ${running.sessionFile}) — ` +
177
197
  `subagent never actually started, likely pollForExit false positive`,
178
198
  "error",
@@ -188,8 +208,8 @@ export class SubagentWorkflowAgent {
188
208
 
189
209
  if (options.schema) {
190
210
  if (result.structuredOutput === undefined) {
191
- this.launchCtx.ui?.notify?.(
192
- `[workflow] "${options.label ?? "workflow-agent"}" ${watchTookMs}ms exitCode=${result.exitCode} ` +
211
+ this.notify(
212
+ `"${options.label ?? "workflow-agent"}" ${watchTookMs}ms exitCode=${result.exitCode} ` +
193
213
  `— finished without calling structured_output`,
194
214
  "warning",
195
215
  );