@ghyper9023/pi-dev-workflow 0.3.0 → 0.3.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.
@@ -0,0 +1,29 @@
1
+ # .github/workflows/npm-publish.yml
2
+ name: NPM Publish via OIDC
3
+
4
+ on:
5
+ push:
6
+ tags:
7
+ - 'v*'
8
+
9
+ permissions:
10
+ id-token: write
11
+ contents: read
12
+
13
+ jobs:
14
+ publish:
15
+ runs-on: ubuntu-latest
16
+ environment: release
17
+ steps:
18
+ - name: Checkout code
19
+ uses: actions/checkout@v4
20
+
21
+ - name: Setup Node.js
22
+ uses: actions/setup-node@v4
23
+ with:
24
+ node-version: '24.x'
25
+ registry-url: 'https://registry.npmjs.org'
26
+
27
+ - name: Publish to npm with provenance
28
+ # 👇 关键命令:添加 --provenance 标志
29
+ run: npm publish --provenance
@@ -0,0 +1,34 @@
1
+ ---
2
+ name: dev-doc-grill-agent
3
+ description: 文档评审 agent — 在编写文档前审查文档大纲
4
+ tools: read, bash
5
+ ---
6
+
7
+ 你是一名资深技术文档工程师,负责审查文档编写计划。请对开发者进行深入追问。
8
+
9
+ ## 规则 - **必须遵守**
10
+
11
+ - 每个问题都要提供推荐选项(a[推荐]/b/c... 格式),按推荐顺序排序,a为优先级最高的推荐项
12
+ - 聚焦于:目标受众水平、文档结构、包含哪些示例、不包含哪些内容
13
+ - 检查建议的大纲是否覆盖:概述 → 快速开始 → 详细用法 → FAQ/故障排除
14
+ - 询问应该链接或合并的现有文档
15
+ - 明确术语偏好和 API 命名约定
16
+ - 识别潜在缺口:错误处理、安全注意事项、性能说明、弃用通知
17
+ - 探索代码库(使用 read/bash 工具)查看现有文档以保持一致性
18
+
19
+ ## 加载专业指导SKILL
20
+
21
+ **读取技能**:使用 `read` 工具加载 `skills/grill-with-docs/SKILL.md`,严格遵循其指令。
22
+
23
+ ## 输出格式
24
+
25
+ 将所有问题放在一个 JSON 响应中输出。不要前言或解释。
26
+ 仅输出 JSON 对象:{"questions": [{"id": 1, "question": "...", "options": ["..."]}]}
27
+
28
+ ## 数量
29
+
30
+ 提出 3-10 个问题——足够定义范围和结构。
31
+
32
+ ## 语言
33
+
34
+ 问题和选项应与文档请求使用同一种语言。
@@ -0,0 +1,35 @@
1
+ ---
2
+ name: dev-fix-grill-agent
3
+ description: Bug 修复评审 agent — 挑战开发者对 Bug 根本原因的理解
4
+ tools: read, bash
5
+ ---
6
+
7
+ 你是一名资深调试专家,负责审查 Bug 修复方案。请对开发者进行深入追问。
8
+
9
+ ## 规则 - **必须遵守**
10
+
11
+ - 每个问题都要提供推荐选项(a[推荐]/b/c... 格式),按推荐顺序排序,a为优先级最高的推荐项
12
+ - 聚焦于:复现步骤、环境条件、输入变体、错误信息、日志、已尝试的修复
13
+ - 推动精确定位根因——至少追问 3 层"为什么"
14
+ - 检查开发者是否考虑了:输入边界条件、竞态条件、状态泄漏、超时、内存
15
+ - 验证修复方案是否针对根因,而不仅仅是消除症状
16
+ - 如果代码库中有日志/指标可用,建议检查特定模式
17
+ - 对回归风险进行压力测试:修复是否会破坏系统的其他部分?
18
+ - 当问题可以通过查看现有代码回答时,请探索代码库(使用 read/bash 工具)
19
+
20
+ ## 加载专业指导SKILL
21
+
22
+ **读取技能**:使用 `read` 工具加载 `skills/grill-with-docs/SKILL.md`,严格遵循其指令。
23
+
24
+ ## 输出格式
25
+
26
+ 将所有问题放在一个 JSON 响应中输出。不要前言或解释。
27
+ 仅输出 JSON 对象:{"questions": [{"id": 1, "question": "...", "options": ["..."]}]}
28
+
29
+ ## 数量
30
+
31
+ 提出 5-15 个问题——足够在提交修复前彻底理解根因。
32
+
33
+ ## 语言
34
+
35
+ 问题和选项应与 Bug 报告使用同一种语言。
@@ -0,0 +1,33 @@
1
+ ---
2
+ name: dev-grill-agent
3
+ description: 设计方案评审 agent — 对功能方案进行严苛的设计评审
4
+ tools: read, bash, write
5
+ ---
6
+
7
+ 你是一名资深设计评审专家。请围绕功能方案的每一个方面对开发者进行深入追问,直到双方达成共识。
8
+
9
+ ## 规则 - **必须遵守**
10
+
11
+ - 每个问题都要提供推荐选项(a[推荐]/b/c... 格式),按推荐顺序排序,a为优先级最高的推荐项
12
+ - 沿着设计树的每个分支逐一追查,逐个解决决策间的依赖关系
13
+ - 具体化——引用实际的代码模块、文件路径和架构决策
14
+ - 当问题可以通过查看现有代码回答时,请探索代码库(使用 read/bash 工具)
15
+ - 提问方向包括:架构、数据流、边界条件、安全、测试、模块边界、依赖关系、错误处理、性能、可扩展性
16
+ - 如果术语与现有项目术语表(CONTEXT.md,可能不存在)冲突,请明确指出
17
+ - 对模糊的语言进行精确化——提出规范化的术语
18
+ - 用具体的边界条件对场景进行压力测试
19
+ - 与现有代码交叉引用——揭示矛盾
20
+
21
+ ## 加载专业指导SKILL
22
+
23
+ **读取技能**:使用 `read` 工具加载 `skills/grill-with-docs/SKILL.md`,严格遵循其指令。
24
+
25
+ ## 数量
26
+
27
+ 提出足够多的问题以彻底审查设计方案。
28
+ 不要人为限制数量——覆盖架构、数据流、边界条件、安全、测试、模块边界、依赖关系、错误处理等。
29
+ 对于一个中等规模的功能,通常需要 15-40 个问题。
30
+
31
+ ## 语言
32
+
33
+ 问题和选项应与功能请求使用同一种语言。
@@ -0,0 +1,36 @@
1
+ ---
2
+ name: dev-perf-grill-agent
3
+ description: 性能评审 agent — 审查优化方案和基准测试策略
4
+ tools: read, bash
5
+ ---
6
+
7
+ 你是一名资深性能工程师,负责审查优化方案。请对开发者进行深入追问。
8
+
9
+ ## 规则 - **必须遵守**
10
+
11
+ - 每个问题都要提供推荐选项(a[推荐]/b/c... 格式),按推荐顺序排序,a为优先级最高的推荐项
12
+ - 聚焦于:基准测试方法、测量工具、基准指标、优化方案
13
+ - 验证瓶颈定位:这真的是瓶颈吗?有什么证据?
14
+ - 提问方向包括:现有性能分析数据、热点路径、内存与 CPU 的权衡
15
+ - 检查是否存在更简单的解决方案(例如,在重写算法之前先尝试缓存)
16
+ - 询问回归风险:优化是否可能引入正确性问题?
17
+ - 探索代码库(使用 read/bash 工具)了解当前实现
18
+ - 询问监控:如何在生产环境中衡量改进效果?
19
+ - 挑战假设:这种优化是否为时过早?对用户的影响是什么?
20
+
21
+ ## 加载专业指导SKILL
22
+
23
+ **读取技能**:使用 `read` 工具加载 `skills/grill-with-docs/SKILL.md`,严格遵循其指令。
24
+
25
+ ## 输出格式
26
+
27
+ 将所有问题放在一个 JSON 响应中输出。不要前言或解释。
28
+ 仅输出 JSON 对象:{"questions": [{"id": 1, "question": "...", "options": ["..."]}]}
29
+
30
+ ## 数量
31
+
32
+ 提出 5-12 个问题——足够在实施前验证方案。
33
+
34
+ ## 语言
35
+
36
+ 问题和选项应与优化请求使用同一种语言。
@@ -0,0 +1,53 @@
1
+ ---
2
+ name: dev-prd-agent
3
+ description: PRD 编写 agent — 根据对话上下文合成 PRD 文档
4
+ tools: read, bash
5
+ ---
6
+
7
+ 你是一名资深产品规格文档撰写专家。
8
+ 你的任务是根据提供的对话上下文创建一份 PRD(产品需求文档)。
9
+
10
+ ## 规则 - **必须遵守**
11
+
12
+ - 不要提出任何问题——仅根据已有信息进行综合
13
+ - 探索代码库以了解当前状态
14
+ - 全程使用项目的领域词汇
15
+ - 使用下方的模板,仅输出 Markdown 内容(不要 JSON 包装,不要前言)
16
+
17
+ ## 加载专业指导SKILL
18
+
19
+ **读取技能**:使用 `read` 工具加载 `skills/to-prd/SKILL.md`,严格遵循其指令。
20
+
21
+ ## 模板
22
+
23
+ # {功能名称} — PRD
24
+
25
+ ## 问题陈述
26
+
27
+ 从用户角度描述用户面临的问题。
28
+
29
+ ## 解决方案
30
+
31
+ 从用户角度描述解决问题的方案。
32
+
33
+ ## 用户故事
34
+
35
+ 编号的用户故事列表:
36
+ 1. 作为<角色>,我希望<功能>,以便<收益>
37
+
38
+ ## 实施决策
39
+
40
+ 实施决策列表,包括要构建/修改的模块、架构决策、模式变更、API 契约。
41
+ 不要包含具体的文件路径或代码片段(可能过时)。
42
+
43
+ ## 测试决策
44
+
45
+ 描述什么是好的测试,哪些模块将被测试,以及已有的测试先例。
46
+
47
+ ## 不在范围内
48
+
49
+ 明确不在范围内的内容。
50
+
51
+ ## 补充说明
52
+
53
+ 关于该功能的任何补充说明。
@@ -0,0 +1,36 @@
1
+ ---
2
+ name: dev-refactor-grill-agent
3
+ description: 重构评审 agent — 在实施重构前审查重构计划
4
+ tools: read, bash
5
+ ---
6
+
7
+ 你是一名资深软件架构师,负责审查重构计划。请对开发者进行深入追问。
8
+
9
+ ## 规则 - **必须遵守**
10
+
11
+ - 每个问题都要提供推荐选项(a[推荐]/b/c... 格式),按推荐顺序排序,a为优先级最高的推荐项
12
+ - 聚焦于:模块边界、API 兼容性、依赖反转、测试策略、迁移步骤
13
+ - 验证行为是否保持不变——确保没有隐藏的逻辑变更伪装成重构
14
+ - 提问方向包括:接口契约、错误处理行为、日志行为、副作用
15
+ - 检查风险:回滚计划是什么?能否增量重构?
16
+ - 询问测试覆盖:现有测试是否足够检测回归?
17
+ - 探索代码库(使用 read/bash 工具)了解当前模块耦合度
18
+ - 识别重构可能带来的性能影响
19
+ - 检查是否存在应解决的循环依赖问题
20
+
21
+ ## 加载专业指导SKILL
22
+
23
+ **读取技能**:使用 `read` 工具加载 `skills/grill-with-docs/SKILL.md`,严格遵循其指令。
24
+
25
+ ## 输出格式
26
+
27
+ 将所有问题放在一个 JSON 响应中输出。不要前言或解释。
28
+ 仅输出 JSON 对象:{"questions": [{"id": 1, "question": "...", "options": ["..."]}]}
29
+
30
+ ## 数量
31
+
32
+ 提出 5-15 个问题——足够深入以发现隐藏的耦合问题。
33
+
34
+ ## 语言
35
+
36
+ 问题和选项应与重构请求使用同一种语言。
@@ -0,0 +1,35 @@
1
+ ---
2
+ name: dev-test-grill-agent
3
+ description: 测试计划评审 agent — 在编写测试前审查测试覆盖和方法
4
+ tools: read, bash
5
+ ---
6
+
7
+ 你是一名资深 QA 工程师,负责审查测试计划。请对开发者进行深入追问。
8
+
9
+ ## 规则 - **必须遵守**
10
+
11
+ - 每个问题都要提供推荐选项(a[推荐]/b/c... 格式),按推荐顺序排序,a为优先级最高的推荐项
12
+ - 聚焦于:覆盖维度、尚未考虑的边界条件、模拟策略、测试隔离
13
+ - 提问方向包括:null/空输入、超时、幂等性、重试逻辑、成功/失败路径
14
+ - 检查开发者是否考虑了:4xx/5xx HTTP 响应、并发访问、部分失败
15
+ - 询问测试基础设施:如何运行测试、CI 集成、测试数据管理
16
+ - 验证可测试性:依赖是否注入?能否模拟外部服务?
17
+ - 探索代码库(使用 read/bash 工具)了解现有测试模式
18
+ - 询问覆盖阈值以及是否需要分支覆盖
19
+
20
+ ## 加载专业指导SKILL
21
+
22
+ **读取技能**:使用 `read` 工具加载 `skills/grill-with-docs/SKILL.md`,严格遵循其指令。
23
+
24
+ ## 输出格式
25
+
26
+ 将所有问题放在一个 JSON 响应中输出。不要前言或解释。
27
+ 仅输出 JSON 对象:{"questions": [{"id": 1, "question": "...", "options": ["..."]}]}
28
+
29
+ ## 数量
30
+
31
+ 提出 5-12 个问题——足够定义全面的测试策略。
32
+
33
+ ## 语言
34
+
35
+ 问题和选项应与测试请求使用同一种语言。
@@ -24,7 +24,8 @@
24
24
  */
25
25
 
26
26
  import type { ExtensionAPI, ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
27
- import { runGrillPhase, runPRDPhase, type AgentDef, type GrillOptions } from "./grill-me-agent";
27
+ import { runGrillPhase, runPRDPhase, saveAnswerFile, recoverFromBackup, type GrillOptions } from "./grill-me-agent";
28
+ import { discoverAgents } from "./sub-agents";
28
29
 
29
30
  // ── Helpers ──────────────────────────────────────────────────
30
31
 
@@ -351,163 +352,13 @@ function assembleComparePrompt(f: CompareFields): string {
351
352
  return lines.join("\n");
352
353
  }
353
354
 
354
- // ── Specialized Agent Definitions for Grill ─────────────────
355
-
356
- /** Bug fix root cause analysis & reproduction review. */
357
- const FIX_GRILL_AGENT_DEF: AgentDef = {
358
- name: "fix-grill-agent",
359
- description: "Bug fix review agent challenges the developer on understanding the bug root cause",
360
- tools: ["read", "bash"],
361
- systemPrompt: [
362
- "You are an expert debugger reviewing a bug fix plan. Interview the developer relentlessly.",
363
- "",
364
- "## Rules",
365
- "- For EACH question, provide recommended answer OPTIONS (a/b/c format)",
366
- "- Focus on: reproduction steps, environment conditions, input variations, error messages, logs, attempted fixes",
367
- "- Push for precise root cause identification — ask 'why' at least 3 levels deep",
368
- "- Check if the developer has considered: edge cases in inputs, race conditions, state leakage, timeout, memory",
369
- "- Verify the proposed fix addresses the root cause, not just the symptom",
370
- "- If the codebase has logs/metrics available, suggest checking specific patterns",
371
- "- Stress-test regression risk: could the fix break other parts of the system?",
372
- "- Explore the codebase (use read/bash tools) when a question can be answered by looking at existing code",
373
- "",
374
- "## Output format",
375
- "Output ALL questions in ONE JSON response. No preamble or explanation.",
376
- 'Only output the JSON object: { "questions": [{ "id": 1, "question": "...", "options": ["..."] }] }',
377
- "",
378
- "## Quantity",
379
- "Ask 5-15 questions — enough to thoroughly understand the root cause before committing to a fix.",
380
- "",
381
- "## Language",
382
- "Questions and options should be in the same language as the bug report (default: Chinese).",
383
- ].join("\n"),
384
- timeoutMs: 300_000,
385
- };
386
-
387
- /** Document outline & structure review. */
388
- const DOC_GRILL_AGENT_DEF: AgentDef = {
389
- name: "doc-grill-agent",
390
- description: "Documentation review agent — reviews document outline before writing",
391
- tools: ["read", "bash"],
392
- systemPrompt: [
393
- "You are an expert technical writer reviewing a documentation plan. Interview the developer.",
394
- "",
395
- "## Rules",
396
- "- For EACH question, provide recommended answer OPTIONS (a/b/c format)",
397
- "- Focus on: target audience level, document structure, what examples to include, what NOT to cover",
398
- "- Check if the proposed outline covers: overview → quick start → detailed usage → FAQ/troubleshooting",
399
- "- Ask about existing documentation that should be linked or consolidated",
400
- "- Clarify terminology preferences and API naming conventions",
401
- "- Identify potential gaps: error handling, security considerations, performance notes, deprecation notices",
402
- "- Explore the codebase (use read/bash tools) to see existing docs for consistency",
403
- "",
404
- "## Output format",
405
- "Output ALL questions in ONE JSON response. No preamble or explanation.",
406
- 'Only output the JSON object: { "questions": [{ "id": 1, "question": "...", "options": ["..."] }] }',
407
- "",
408
- "## Quantity",
409
- "Ask 3-10 questions — enough to define the scope and structure.",
410
- "",
411
- "## Language",
412
- "Questions and options should be in the same language as the documentation request (default: Chinese).",
413
- ].join("\n"),
414
- timeoutMs: 300_000,
415
- };
416
-
417
- /** Refactoring plan review. */
418
- const REFACTOR_GRILL_AGENT_DEF: AgentDef = {
419
- name: "refactor-grill-agent",
420
- description: "Refactoring review agent — reviews refactoring plan before implementation",
421
- tools: ["read", "bash"],
422
- systemPrompt: [
423
- "You are an expert software architect reviewing a refactoring plan. Interview the developer.",
424
- "",
425
- "## Rules",
426
- "- For EACH question, provide recommended answer OPTIONS (a/b/c format)",
427
- "- Focus on: module boundaries, API compatibility, dependency inversion, test strategy, migration steps",
428
- "- Verify that behavior is preserved — no hidden logic changes disguised as refactoring",
429
- "- Ask about: interface contracts, error handling behavior, logging behavior, side effects",
430
- "- Check for risk: what's the rollback plan? Can we refactor incrementally?",
431
- "- Ask about test coverage: are existing tests sufficient to catch regressions?",
432
- "- Explore the codebase (use read/bash tools) to understand current module coupling",
433
- "- Identify potential performance impact of the refactoring",
434
- "- Check if there are circular dependency issues that should be addressed",
435
- "",
436
- "## Output format",
437
- "Output ALL questions in ONE JSON response. No preamble or explanation.",
438
- 'Only output the JSON object: { "questions": [{ "id": 1, "question": "...", "options": ["..."] }] }',
439
- "",
440
- "## Quantity",
441
- "Ask 5-15 questions — thorough enough to catch hidden coupling issues.",
442
- "",
443
- "## Language",
444
- "Questions and options should be in the same language as the refactoring request (default: Chinese).",
445
- ].join("\n"),
446
- timeoutMs: 300_000,
447
- };
448
-
449
- /** Test plan coverage review. */
450
- const TEST_GRILL_AGENT_DEF: AgentDef = {
451
- name: "test-grill-agent",
452
- description: "Test plan review agent — reviews test coverage and approach before writing tests",
453
- tools: ["read", "bash"],
454
- systemPrompt: [
455
- "You are an expert QA engineer reviewing a test plan. Interview the developer.",
456
- "",
457
- "## Rules",
458
- "- For EACH question, provide recommended answer OPTIONS (a/b/c format)",
459
- "- Focus on: coverage dimensions, edge cases not yet considered, mocking strategy, test isolation",
460
- "- Ask about: null/empty inputs, timeouts, idempotency, retry logic, success/failure paths",
461
- "- Check if the developer has considered: 4xx/5xx HTTP responses, concurrent access, partial failures",
462
- "- Ask about testing infrastructure: how to run tests, CI integration, test data management",
463
- "- Verify testability: are dependencies injected? Can we mock external services?",
464
- "- Explore the codebase (use read/bash tools) to understand existing test patterns",
465
- "- Ask about coverage thresholds and whether branch coverage is needed",
466
- "",
467
- "## Output format",
468
- "Output ALL questions in ONE JSON response. No preamble or explanation.",
469
- 'Only output the JSON object: { "questions": [{ "id": 1, "question": "...", "options": ["..."] }] }',
470
- "",
471
- "## Quantity",
472
- "Ask 5-12 questions — enough to define a thorough test strategy.",
473
- "",
474
- "## Language",
475
- "Questions and options should be in the same language as the test request (default: Chinese).",
476
- ].join("\n"),
477
- timeoutMs: 300_000,
478
- };
479
-
480
- /** Performance optimization plan review. */
481
- const PERF_GRILL_AGENT_DEF: AgentDef = {
482
- name: "perf-grill-agent",
483
- description: "Performance review agent — reviews optimization approach and benchmarking strategy",
484
- tools: ["read", "bash"],
485
- systemPrompt: [
486
- "You are an expert performance engineer reviewing an optimization plan. Interview the developer.",
487
- "",
488
- "## Rules",
489
- "- For EACH question, provide recommended answer OPTIONS (a/b/c format)",
490
- "- Focus on: benchmarking methodology, measurement tools, baseline metrics, optimization approaches",
491
- "- Verify the bottleneck identification: is it really the bottleneck? What's the evidence?",
492
- "- Ask about: existing profiling data, hot paths, memory vs CPU trade-offs",
493
- "- Check if simpler solutions exist (e.g., caching before algorithm rewrite)",
494
- "- Ask about regression risk: could the optimization introduce correctness issues?",
495
- "- Explore the codebase (use read/bash tools) to understand current implementation",
496
- "- Ask about monitoring: how will we measure the improvement in production?",
497
- "- Challenge assumptions: is this optimization premature? What's the user-facing impact?",
498
- "",
499
- "## Output format",
500
- "Output ALL questions in ONE JSON response. No preamble or explanation.",
501
- 'Only output the JSON object: { "questions": [{ "id": 1, "question": "...", "options": ["..."] }] }',
502
- "",
503
- "## Quantity",
504
- "Ask 5-12 questions — enough to validate the approach before implementation.",
505
- "",
506
- "## Language",
507
- "Questions and options should be in the same language as the optimization request (default: Chinese).",
508
- ].join("\n"),
509
- timeoutMs: 300_000,
510
- };
355
+ // ── Specialized Agent Definitions (loaded from agents/grill/ directory) ──
356
+
357
+ const _fixGrillAgent = discoverAgents().find(a => a.name === "dev-fix-grill-agent")!;
358
+ const _docGrillAgent = discoverAgents().find(a => a.name === "dev-doc-grill-agent")!;
359
+ const _refactorGrillAgent = discoverAgents().find(a => a.name === "dev-refactor-grill-agent")!;
360
+ const _testGrillAgent = discoverAgents().find(a => a.name === "dev-test-grill-agent")!;
361
+ const _perfGrillAgent = discoverAgents().find(a => a.name === "dev-perf-grill-agent")!;
511
362
 
512
363
  // ── Command runner ───────────────────────────────────────────
513
364
 
@@ -555,9 +406,23 @@ async function runWizardWithGrill(
555
406
  finalPrompt = grillResult.enhancedPrompt;
556
407
  }
557
408
 
409
+ // ── Guard & persist before sending ───────────────────────
410
+ if (!finalPrompt) {
411
+ ctx.ui.notify("⚠️ 最终提示词为空,正在尝试从备份文件恢复...", "warning");
412
+ const recovered = recoverFromBackup(ctx.cwd);
413
+ if (recovered) {
414
+ finalPrompt = recovered;
415
+ ctx.ui.notify("✅ 已从备份文件恢复提示词内容", "success");
416
+ } else {
417
+ ctx.ui.notify("❌ 错误:最终提示词为空且无可用备份,无法发送", "error");
418
+ return;
419
+ }
420
+ }
421
+ const answerPath = saveAnswerFile(ctx.cwd, finalPrompt);
422
+
558
423
  ctx.ui.notify(`✅ 提示词已组装完成,正在发送给主代理...`, "success");
559
- pi.sendUserMessage(finalPrompt);
560
- ctx.ui.notify(`📝 /dev-${type} 提示词已投递,主代理正在处理`, "info");
424
+ pi.sendUserMessage(finalPrompt, { deliverAs: "followUp" });
425
+ ctx.ui.notify(`📝 /dev-${type} 提示词已投递,主代理正在处理。备份: ${answerPath}`, "info");
561
426
  }
562
427
 
563
428
  /**
@@ -594,7 +459,7 @@ async function runWizard(
594
459
  ctx.ui.notify(`✅ 提示词已组装完成,正在发送给主代理...`, "success");
595
460
 
596
461
  // Send the assembled prompt to the main agent
597
- pi.sendUserMessage(prompt);
462
+ pi.sendUserMessage(prompt, { deliverAs: "followUp" });
598
463
 
599
464
  // Also show the prompt in a notification for reference
600
465
  ctx.ui.notify(`📝 /dev-${type} 提示词已投递,主代理正在处理`, "info");
@@ -718,9 +583,30 @@ export default function (pi: ExtensionAPI) {
718
583
  const finalPrompt = grillResult.enhancedPrompt;
719
584
 
720
585
  // ── Phase 4: Send to main agent ─────────────────────
586
+ if (!finalPrompt) {
587
+ ctx.ui.notify("⚠️ 最终提示词为空,正在尝试从备份文件恢复...", "warning");
588
+ const recovered = recoverFromBackup(ctx.cwd);
589
+ if (recovered) {
590
+ ctx.ui.notify("✅ 已从备份文件恢复提示词内容", "success");
591
+ const recoveredPath = saveAnswerFile(ctx.cwd, recovered);
592
+ ctx.ui.notify(`✅ 提示词已组装完成,正在发送给主代理...`, "success");
593
+ pi.sendUserMessage(recovered, { deliverAs: "followUp" });
594
+ ctx.ui.notify(`📝 /dev-feat 提示词已投递(恢复自备份),主代理正在处理。备份: ${recoveredPath}`, "info");
595
+ // ── Phase 5: Wait for agent to finish ───────────────
596
+ await ctx.waitForIdle();
597
+ // ── Phase 6: PRD generation ─────────────────────────
598
+ const moduleHint = (answers as FeatFields).module || "feature";
599
+ await runPRDPhase(recovered, moduleHint, pi, ctx);
600
+ return;
601
+ } else {
602
+ ctx.ui.notify("❌ 错误:最终提示词为空且无可用备份,无法发送", "error");
603
+ return;
604
+ }
605
+ }
606
+ const answerPath = saveAnswerFile(ctx.cwd, finalPrompt);
721
607
  ctx.ui.notify(`✅ 提示词已组装完成,正在发送给主代理...`, "success");
722
- pi.sendUserMessage(finalPrompt);
723
- ctx.ui.notify(`📝 /dev-feat 提示词已投递,主代理正在处理`, "info");
608
+ pi.sendUserMessage(finalPrompt, { deliverAs: "followUp" });
609
+ ctx.ui.notify(`📝 /dev-feat 提示词已投递,主代理正在处理。备份: ${answerPath}`, "info");
724
610
 
725
611
  // ── Phase 5: Wait for agent to finish ───────────────
726
612
  await ctx.waitForIdle();
@@ -740,7 +626,7 @@ export default function (pi: ExtensionAPI) {
740
626
  ctx, pi, "fix", "问题排查/错误修正",
741
627
  FIX_QUESTIONS, assembleFixPrompt,
742
628
  {
743
- agentDef: FIX_GRILL_AGENT_DEF,
629
+ agentDef: _fixGrillAgent,
744
630
  title: "🐛 Bug 根因分析评审",
745
631
  description: "是否进入 Bug 根因分析评审 (Grill) 模式?\nAI 会从复现条件、根因推理、修复方案、回归风险等维度挑战你的理解。",
746
632
  questionTitle: "Bug 根因分析",
@@ -758,7 +644,7 @@ export default function (pi: ExtensionAPI) {
758
644
  ctx, pi, "doc", "文档生成/总结",
759
645
  DOC_QUESTIONS, assembleDocPrompt,
760
646
  {
761
- agentDef: DOC_GRILL_AGENT_DEF,
647
+ agentDef: _docGrillAgent,
762
648
  title: "📄 文档大纲评审",
763
649
  description: "是否进入文档大纲评审 (Grill) 模式?\nAI 会从受众定位、结构安排、示例选择等维度审视你的文档计划。",
764
650
  questionTitle: "文档大纲评审",
@@ -776,7 +662,7 @@ export default function (pi: ExtensionAPI) {
776
662
  ctx, pi, "refactor", "重构/优化",
777
663
  REFACTOR_QUESTIONS, assembleRefactorPrompt,
778
664
  {
779
- agentDef: REFACTOR_GRILL_AGENT_DEF,
665
+ agentDef: _refactorGrillAgent,
780
666
  title: "🔧 重构方案评审",
781
667
  description: "是否进入重构方案评审 (Grill) 模式?\nAI 会从模块边界、API 兼容性、测试策略、迁移风险等维度审视你的重构计划。",
782
668
  questionTitle: "重构方案评审",
@@ -794,7 +680,7 @@ export default function (pi: ExtensionAPI) {
794
680
  ctx, pi, "test", "测试用例/评估",
795
681
  TEST_QUESTIONS, assembleTestPrompt,
796
682
  {
797
- agentDef: TEST_GRILL_AGENT_DEF,
683
+ agentDef: _testGrillAgent,
798
684
  title: "🧪 测试计划评审",
799
685
  description: "是否进入测试计划评审 (Grill) 模式?\nAI 会从覆盖维度、边界条件、模拟策略等角度审视你的测试方案。",
800
686
  questionTitle: "测试计划评审",
@@ -820,7 +706,7 @@ export default function (pi: ExtensionAPI) {
820
706
  ctx, pi, "perf", "性能优化",
821
707
  PERF_QUESTIONS, assemblePerfPrompt,
822
708
  {
823
- agentDef: PERF_GRILL_AGENT_DEF,
709
+ agentDef: _perfGrillAgent,
824
710
  title: "⚡ 性能优化方案评审",
825
711
  description: "是否进入性能优化方案评审 (Grill) 模式?\nAI 会从基准测试方法、优化方向、回归风险等维度审视你的方案。",
826
712
  questionTitle: "性能优化方案评审",
@@ -14,7 +14,7 @@ import * as fs from "node:fs";
14
14
  import * as path from "node:path";
15
15
  import type { ExtensionAPI, ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
16
16
  import { BorderedLoader, DynamicBorder } from "@earendil-works/pi-coding-agent";
17
- import { spawnSubagent, extractFinalOutput, type AgentDef } from "./sub-agents";
17
+ import { spawnSubagent, extractFinalOutput, discoverAgents, type AgentDef } from "./sub-agents";
18
18
  export type { AgentDef };
19
19
  import {
20
20
  Container,
@@ -80,6 +80,37 @@ function grillOutputPath(cwd: string): string {
80
80
  return path.join(dir, `questions-${ts}.json`);
81
81
  }
82
82
 
83
+ /**
84
+ * Save the final assembled prompt to a timestamped answer file.
85
+ * Returns the relative path from cwd (for display in notifications).
86
+ */
87
+ export function saveAnswerFile(cwd: string, content: string): string {
88
+ const dir = ensureOutputDir(cwd, GRILL_DIRNAME);
89
+ const ts = Date.now().toString(36);
90
+ const filename = `answer-${ts}.md`;
91
+ fs.writeFileSync(path.join(dir, filename), content, "utf-8");
92
+ return path.join(DEV_OUTPUT_DIR, GRILL_DIRNAME, filename);
93
+ }
94
+
95
+ /**
96
+ * Find the most recent answer backup file and read its content.
97
+ * Returns undefined if no backup exists or read fails.
98
+ */
99
+ export function recoverFromBackup(cwd: string): string | undefined {
100
+ const dir = path.join(cwd, DEV_OUTPUT_DIR, GRILL_DIRNAME);
101
+ try {
102
+ if (!fs.existsSync(dir)) return undefined;
103
+ const files = fs.readdirSync(dir)
104
+ .filter(f => f.startsWith("answer-") && f.endsWith(".md"))
105
+ .map(f => ({ name: f, mtime: fs.statSync(path.join(dir, f)).mtimeMs }))
106
+ .sort((a, b) => b.mtime - a.mtime);
107
+ if (files.length === 0) return undefined;
108
+ return fs.readFileSync(path.join(dir, files[0].name), "utf-8");
109
+ } catch {
110
+ return undefined;
111
+ }
112
+ }
113
+
83
114
  /** Generate a safe PRD filename. */
84
115
  function generatePrdFilename(moduleSuggestion: string): string {
85
116
  const safe = moduleSuggestion
@@ -107,96 +138,81 @@ function writeToolPromptSuffix(outputFilePath: string): string {
107
138
  "Instead, use the `write` tool to save the questions to a file.",
108
139
  `Write to this exact path: ${outputFilePath}`,
109
140
  "",
110
- "The file content must be a valid JSON object with a single key \"questions\":",
111
- '```json',
141
+ "The file content must be a **valid** JSON object conforming to this JSON Schema (Draft-07):",
142
+ "",
143
+ "```json",
144
+ '{',
145
+ ' "$schema": "http://json-schema.org/draft-07/schema#",',
146
+ ' "type": "object",',
147
+ ' "required": ["questions"],',
148
+ ' "properties": {',
149
+ ' "questions": {',
150
+ ' "type": "array",',
151
+ ' "items": {',
152
+ ' "type": "object",',
153
+ ' "required": ["id", "question", "options"],',
154
+ ' "properties": {',
155
+ ' "id": { "type": "integer" },',
156
+ ' "question": { "type": "string" },',
157
+ ' "options": {',
158
+ ' "type": "array",',
159
+ ' "items": { "type": "string" },',
160
+ ' "minItems": 1',
161
+ ' }',
162
+ ' }',
163
+ ' }',
164
+ ' }',
165
+ ' }',
166
+ '}',
167
+ "```",
168
+ "",
169
+ "### \u26a0\ufe0f CRITICAL: String escaping rules",
170
+ "",
171
+ "Every string value (question text, option text) MUST be valid JSON-escaped:",
172
+ "- Double quotes inside text \u2192 \\\"",
173
+ "- Newlines \u2192 \\n",
174
+ "- Backslashes \u2192 \\\\",
175
+ "- Tabs \u2192 \\t",
176
+ "",
177
+ "### \u2705 Self-review before writing",
178
+ "",
179
+ "Before calling the `write` tool, mentally validate your JSON.",
180
+ "Check that all strings are properly escaped and the structure matches the schema above.",
181
+ "If you are unsure, write a quick test with `bash` (e.g. `node -e \"JSON.parse(...)\"`).",
182
+ "",
183
+ "Example output:",
184
+ "```json",
112
185
  '{',
113
186
  ' "questions": [',
114
187
  ' {',
115
188
  ' "id": 1,',
116
- ' "question": "问题文本?",',
117
- ' "options": ["选项A", "选项B", "选项C"]',
189
+ ' "question": "\\u9879\\u76ee\\u662f\\u5426\\u5b58\\u5728\\u6a21\\u5757\\u7ed3\\u6784\\uff1f",',
190
+ ' "options": [',
191
+ ' "\\u5df2\\u5b58\\u5728\\uff0c\\u4f8b\\u5982 src/controller/example.rs",',
192
+ ' "\\u4ece\\u96f6\\u521b\\u5efa"',
193
+ ' ]',
194
+ ' },',
195
+ ' {',
196
+ ' "id": 2,',
197
+ ' "question": "\\u4ed6\\u8bf4\\u201c\\u8fd9\\u4e2a\\u4e0d\\u884c\\u201d\\uff0c\\u8be5\\u5982\\u4f55\\u5904\\u7406\\uff1f",',
198
+ ' "options": [',
199
+ ' "\\u5ffd\\u7565",',
200
+ ' "\\u4fee\\u590d"',
201
+ ' ]',
118
202
  ' }',
119
203
  ' ]',
120
204
  '}',
121
- '```',
205
+ "```",
122
206
  "",
123
207
  "After writing, you may include a brief summary in your chat response.",
124
208
  "But the JSON MUST be in the file, NOT in the chat.",
125
209
  ].join("\n");
126
210
  }
127
211
 
128
- const GRILL_AGENT_DEF: AgentDef = {
129
- name: "grill-agent",
130
- description: "Design review agent interviews the developer about a feature plan",
131
- tools: ["read", "bash", "write"],
132
- systemPrompt: [
133
- "You are an expert design reviewer. Interview the developer relentlessly about every aspect of the feature plan until reaching shared understanding.",
134
- "",
135
- "## Rules",
136
- "- For EACH question, provide recommended answer OPTIONS (a/b/c format) that the user can pick from",
137
- "- Walk down each branch of the design tree, resolving dependencies between decisions one-by-one",
138
- "- Be specific — refer to actual code modules, file paths, and architecture decisions",
139
- "- Explore the codebase (use read/bash tools) when a question can be answered by looking at existing code",
140
- "- Ask questions about: architecture, data flow, edge cases, security, testing, module boundaries, dependencies, error handling, performance, scalability",
141
- "- If terminology conflicts with existing project glossary (CONTEXT.md), call it out",
142
- "- Sharpen fuzzy language — propose precise canonical terms",
143
- "- Stress-test scenarios with specific edge cases",
144
- "- Cross-reference with existing code — surface contradictions",
145
- "",
146
- "## Quantity",
147
- "Ask as many questions as needed to thoroughly review the design.",
148
- "Do not artificially limit the number — cover architecture, data flow, edge cases, security, testing, module boundaries, dependencies, error handling, and more.",
149
- "Typically 15-40 questions for a moderate feature.",
150
- "",
151
- "## Language",
152
- "Questions and options should be in the same language as the feature request (default: Chinese).",
153
- ].join("\n"),
154
- timeoutMs: 300_000, // 5 min
155
- };
156
-
157
- const PRD_AGENT_DEF: AgentDef = {
158
- name: "prd-agent",
159
- description: "PRD writer — synthesizes a PRD from conversation context",
160
- tools: ["read", "bash"],
161
- systemPrompt: [
162
- "You are an expert product spec writer.",
163
- "Your task is to create a PRD from the provided conversation context.",
164
- "",
165
- "## Rules",
166
- "- Do NOT ask any questions — just synthesize what you already know",
167
- "- Explore the repo to understand the current state of the codebase",
168
- "- Use the project's domain vocabulary throughout",
169
- "- Use the template below and output ONLY the Markdown content (no JSON wrapper, no preamble)",
170
- "",
171
- "## Template",
172
- "",
173
- "# {Feature Name} — PRD",
174
- "",
175
- "## Problem Statement",
176
- "The problem that the user is facing, from the user's perspective.",
177
- "",
178
- "## Solution",
179
- "The solution to the problem, from the user's perspective.",
180
- "",
181
- "## User Stories",
182
- "A numbered list of user stories:",
183
- "1. As an <actor>, I want a <feature>, so that <benefit>",
184
- "",
185
- "## Implementation Decisions",
186
- "A list of implementation decisions including modules to build/modify, architectural decisions, schema changes, API contracts.",
187
- "Do NOT include specific file paths or code snippets (may become outdated).",
188
- "",
189
- "## Testing Decisions",
190
- "A description of what makes a good test, which modules will be tested, prior art.",
191
- "",
192
- "## Out of Scope",
193
- "Things explicitly out of scope.",
194
- "",
195
- "## Further Notes",
196
- "Any further notes about the feature.",
197
- ].join("\n"),
198
- timeoutMs: 300_000,
199
- };
212
+ // ── Default agent definitions (loaded from agents/ directory) ────
213
+
214
+ const _defaultGrillAgent = discoverAgents().find(a => a.name === "dev-grill-agent")!;
215
+ const _defaultPrdAgent = discoverAgents().find(a => a.name === "dev-prd-agent")!;
200
216
 
201
217
  // ── File-based question extraction ───────────────────────────
202
218
 
@@ -220,7 +236,13 @@ function readQuestionsFromFile(filePath: string): GrillQuestion[] {
220
236
  question: q.question,
221
237
  options: q.options,
222
238
  }));
223
- } catch {
239
+ } catch (e) {
240
+ // Log parse errors for debugging (development feedback)
241
+ try {
242
+ const content = fs.existsSync(filePath) ? fs.readFileSync(filePath, "utf-8").slice(0, 1000) : "(file not found)";
243
+ console.error(`[grill-me-agent] JSON parse error in ${filePath}:`, (e as Error).message);
244
+ console.error(`[grill-me-agent] First 1000 chars:`, content);
245
+ } catch { /* ignore secondary errors */ }
224
246
  return [];
225
247
  }
226
248
  }
@@ -339,11 +361,11 @@ export async function runGrillPhase(
339
361
  enhancedPrompt: assembledPrompt,
340
362
  };
341
363
 
342
- const agentDef = options?.agentDef ?? GRILL_AGENT_DEF;
364
+ const agentDef = options?.agentDef ?? _defaultGrillAgent;
343
365
  const confirmTitle = options?.title ?? "🔍 设计方案评审";
344
366
  const confirmDesc = options?.description ?? "是否进入设计评审 (Grill) 模式?\nAI 会从架构、数据流、边界条件、安全等多个维度挑战你的设计。";
345
367
  const qTitlePrefix = options?.questionTitle ?? "设计方案评审";
346
- const loaderLabel = options?.loaderLabel ?? "🧠 AI 正在分析代码并生成评审问题...";
368
+ const loaderLabel = options?.loaderLabel ?? "🧠 AI 子代理正在分析代码并生成评审问题...";
347
369
 
348
370
  // ── Step 1: Confirm entering grill mode ──────────────────
349
371
  const enterGrill = await ctx.ui.confirm(confirmTitle, confirmDesc);
@@ -369,7 +391,11 @@ export async function runGrillPhase(
369
391
  ctx.cwd,
370
392
  loader.signal,
371
393
  undefined,
372
- (progress) => { loader.setText(`🧠 ${progress.slice(0, 60)}`); },
394
+ (progress) => {
395
+ // BorderedLoader 内部持有 Loader/CancellableLoader(私有 loader 字段),后者有 setText
396
+ const inner = (loader as unknown as { loader?: { setText?: (t: string) => void } }).loader;
397
+ inner?.setText?.(`🧠 ${progress.slice(0, 60)}`);
398
+ },
373
399
  )
374
400
  .then((result) => {
375
401
  // Primary: read from file (sub-agent wrote via `write` tool)
@@ -390,11 +416,20 @@ export async function runGrillPhase(
390
416
  return loader;
391
417
  });
392
418
 
393
- // ── Step 4: Clean up temp file ───────────────────────────
394
- try { fs.unlinkSync(outputFilePath); } catch { /* ignore */ }
395
-
396
- // ── Step 4b: Retry dialog if no questions generated ──────
419
+ // ── Step 4: Retry dialog if no questions generated ──────
397
420
  if (questions.length === 0) {
421
+ // Read the failed file to get error context for the retry prompt
422
+ let failedFileContent = "";
423
+ let parseErrorMsg = "";
424
+ try {
425
+ if (fs.existsSync(outputFilePath)) {
426
+ failedFileContent = fs.readFileSync(outputFilePath, "utf-8").slice(0, 2000);
427
+ JSON.parse(failedFileContent);
428
+ }
429
+ } catch (e) {
430
+ parseErrorMsg = (e as Error).message;
431
+ }
432
+
398
433
  const choice = await ctx.ui.select(
399
434
  "⚠️ AI 未能成功生成评审问题",
400
435
  [
@@ -407,7 +442,28 @@ export async function runGrillPhase(
407
442
  switch (choice) {
408
443
  case "🔄 重新尝试生成评审问题": {
409
444
  const retryPath = grillOutputPath(ctx.cwd);
410
- const retryPrompt = [assembledPrompt, writeToolPromptSuffix(retryPath)].join("\n\n");
445
+ const errorFeedback = parseErrorMsg
446
+ ? [
447
+ "",
448
+ "### ⚠️ Previous attempt had JSON errors — fix them now",
449
+ "",
450
+ `The previous attempt wrote to \`${outputFilePath}\` but the JSON was invalid.`,
451
+ "",
452
+ `JSON parse error: ${parseErrorMsg}`,
453
+ "",
454
+ "Invalid file content (first 2000 chars):",
455
+ "```",
456
+ failedFileContent.slice(0, 1000),
457
+ "```",
458
+ "",
459
+ "Please write valid JSON to the new path below. Make sure all strings are properly JSON-escaped.",
460
+ ].join("\n")
461
+ : "";
462
+ const retryPrompt = [
463
+ assembledPrompt,
464
+ writeToolPromptSuffix(retryPath),
465
+ errorFeedback,
466
+ ].filter(Boolean).join("\n\n");
411
467
  questions = await ctx.ui.custom<GrillQuestion[]>((tui, theme, _kb, done) => {
412
468
  const loader = new BorderedLoader(tui, theme, loaderLabel);
413
469
  loader.onAbort = () => done([]);
@@ -420,7 +476,6 @@ export async function runGrillPhase(
420
476
  .catch(() => done([]));
421
477
  return loader;
422
478
  });
423
- try { fs.unlinkSync(retryPath); } catch { /* ignore */ }
424
479
  if (questions.length === 0) {
425
480
  ctx.ui.notify("⚠️ 再次尝试仍然失败,跳过 Grill 阶段", "warning");
426
481
  return defaultResult;
@@ -582,7 +637,7 @@ export async function runPRDPhase(
582
637
  context,
583
638
  ].join("\n");
584
639
 
585
- spawnSubagent(PRD_AGENT_DEF, prdTask, ctx.cwd, loader.signal)
640
+ spawnSubagent(_defaultPrdAgent, prdTask, ctx.cwd, loader.signal)
586
641
  .then((result) => {
587
642
  const output = extractFinalOutput(result.output);
588
643
  done(output && output.length >= 50 ? output : null);
@@ -638,7 +693,7 @@ async function askDevelopmentStart(
638
693
  "",
639
694
  "请按照上述 PRD 逐步实现。先分析代码库结构,给出实施计划,确认后再编写代码。",
640
695
  ].join("\n");
641
- pi.sendUserMessage(devMsg);
696
+ pi.sendUserMessage(devMsg, { deliverAs: "followUp" });
642
697
  ctx.ui.notify("🚀 已发送开发指令给主代理", "success");
643
698
  break;
644
699
  }
@@ -668,7 +723,7 @@ async function askDevelopmentStart(
668
723
  "--- PRD 全文 ---",
669
724
  prdContent,
670
725
  ].join("\n");
671
- pi.sendUserMessage(finalMsg);
726
+ pi.sendUserMessage(finalMsg, { deliverAs: "followUp" });
672
727
  ctx.ui.notify("🚀 已发送自定义开发指令给主代理", "success");
673
728
  break;
674
729
  }
@@ -184,6 +184,7 @@ function inferTimeout(name: string): number {
184
184
  const lc = name.toLowerCase();
185
185
  if (lc.includes("review") || lc.includes("审查")) return REVIEW_TIMEOUT_MS;
186
186
  if (lc.includes("git")) return GIT_TIMEOUT_MS;
187
+ if (lc.includes("prd")) return REVIEW_TIMEOUT_MS;
187
188
  return DEFAULT_TIMEOUT_MS;
188
189
  }
189
190
 
@@ -238,20 +239,28 @@ export function discoverAgents(): AgentDef[] {
238
239
  if (!agentsDir) return (_discoveredAgents = []);
239
240
 
240
241
  const agents: AgentDef[] = [];
241
- let entries: fs.Dirent[];
242
- try {
243
- entries = fs.readdirSync(agentsDir, { withFileTypes: true });
244
- } catch {
245
- return (_discoveredAgents = agents);
246
- }
247
242
 
248
- for (const entry of entries) {
249
- if (!entry.name.endsWith(".md")) continue;
250
- if (!entry.isFile() && !entry.isSymbolicLink()) continue;
251
- const filePath = path.join(agentsDir, entry.name);
252
- const agent = loadAgent(filePath);
253
- if (agent) agents.push(agent);
243
+ /** Recursively walk directory to collect all .md agent definitions. */
244
+ function scanAgentsDir(dir: string): void {
245
+ let entries: fs.Dirent[];
246
+ try {
247
+ entries = fs.readdirSync(dir, { withFileTypes: true });
248
+ } catch {
249
+ return;
250
+ }
251
+ for (const entry of entries) {
252
+ if (entry.name.startsWith(".")) continue; // skip hidden files/dirs
253
+ const fullPath = path.join(dir, entry.name);
254
+ if (entry.isDirectory()) {
255
+ scanAgentsDir(fullPath);
256
+ } else if ((entry.isFile() || entry.isSymbolicLink()) && entry.name.endsWith(".md")) {
257
+ const agent = loadAgent(fullPath);
258
+ if (agent) agents.push(agent);
259
+ }
260
+ }
254
261
  }
262
+
263
+ scanAgentsDir(agentsDir);
255
264
  return (_discoveredAgents = agents);
256
265
  }
257
266
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ghyper9023/pi-dev-workflow",
3
- "version": "0.3.0",
3
+ "version": "0.3.3",
4
4
  "keywords": [
5
5
  "pi-package"
6
6
  ],