@boyingliu01/xp-gate 0.27.4 → 0.27.5

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.
Files changed (100) hide show
  1. package/adapter-common.sh +0 -0
  2. package/adapters/cpp.sh +0 -0
  3. package/adapters/dart.sh +0 -0
  4. package/adapters/flutter.sh +0 -0
  5. package/adapters/gate-3.sh +59 -3
  6. package/adapters/gate-4.sh +73 -10
  7. package/adapters/gate-7.sh +4 -0
  8. package/adapters/go.sh +0 -0
  9. package/adapters/iac.sh +0 -0
  10. package/adapters/java.sh +0 -0
  11. package/adapters/kotlin.sh +0 -0
  12. package/adapters/objectivec.sh +0 -0
  13. package/adapters/plugins/book299-20132-python/scripts/install-gradle.sh +0 -0
  14. package/adapters/plugins/book299-20132-python/scripts/install-maven.sh +0 -0
  15. package/adapters/plugins/book299-4081-c/scripts/install-gradle.sh +0 -0
  16. package/adapters/plugins/book299-4081-c/scripts/install-maven.sh +0 -0
  17. package/adapters/plugins/book299-4083-javascriptes5/scripts/install-gradle.sh +0 -0
  18. package/adapters/plugins/book299-4083-javascriptes5/scripts/install-maven.sh +0 -0
  19. package/adapters/powershell.sh +8 -0
  20. package/adapters/python.sh +0 -0
  21. package/adapters/shell.sh +0 -0
  22. package/adapters/swift.sh +0 -0
  23. package/adapters/typescript.sh +0 -0
  24. package/bin/xp-gate.js +0 -0
  25. package/gate-10.sh +11 -0
  26. package/gate-3.sh +8 -0
  27. package/gate-4.sh +8 -0
  28. package/gate-7.sh +4 -0
  29. package/gate-8.sh +0 -0
  30. package/gate-9.sh +0 -0
  31. package/hooks/adapter-common.sh +0 -0
  32. package/hooks/gate-10.sh +11 -0
  33. package/hooks/gate-3.sh +8 -0
  34. package/hooks/gate-4.sh +8 -0
  35. package/hooks/gate-7.sh +4 -0
  36. package/hooks/gate-8.sh +0 -0
  37. package/hooks/gate-9.sh +0 -0
  38. package/hooks/post-merge +0 -0
  39. package/hooks/pre-commit +53 -11
  40. package/hooks/pre-push +0 -0
  41. package/hooks/sprint-gate.sh +0 -0
  42. package/lib/__tests__/doctor-delphi.test.js +293 -244
  43. package/lib/__tests__/sprint-audit.test.js +207 -207
  44. package/lib/doctor.js +46 -3
  45. package/lib/mattpocock-license-verdict.json +1 -1
  46. package/lib/sprint-audit.js +235 -235
  47. package/mock-policy/AGENTS.md +3 -3
  48. package/mutation/AGENTS.md +3 -3
  49. package/package.json +1 -1
  50. package/plugins/claude-code/.claude-plugin/plugin.json +1 -1
  51. package/plugins/claude-code/bin/delphi-review-guard.sh +0 -0
  52. package/plugins/claude-code/bin/xp-gate-check +0 -0
  53. package/plugins/claude-code/skills/batch-grill-me/SKILL.md +9 -2
  54. package/plugins/claude-code/skills/delphi-review/AGENTS.md +3 -3
  55. package/plugins/claude-code/skills/sprint-flow/AGENTS.md +3 -3
  56. package/plugins/claude-code/skills/test-specification-alignment/AGENTS.md +3 -3
  57. package/plugins/dsh/package.json +1 -1
  58. package/plugins/dsh/skills/batch-grill-me/SKILL.md +9 -2
  59. package/plugins/dsh/skills/delphi-review/AGENTS.md +3 -3
  60. package/plugins/dsh/skills/sprint-flow/AGENTS.md +3 -3
  61. package/plugins/dsh/skills/test-specification-alignment/AGENTS.md +3 -3
  62. package/plugins/opencode/package.json +1 -1
  63. package/plugins/opencode/skills/batch-grill-me/SKILL.md +9 -2
  64. package/plugins/opencode/skills/delphi-review/AGENTS.md +3 -3
  65. package/plugins/opencode/skills/sprint-flow/AGENTS.md +3 -3
  66. package/plugins/opencode/skills/test-specification-alignment/AGENTS.md +3 -3
  67. package/plugins/qoder/bin/sprint-flow-guard.sh +0 -0
  68. package/plugins/qoder/bin/xp-gate-check +0 -0
  69. package/plugins/qoder/plugin.json +1 -1
  70. package/plugins/qoder/skills/delphi-review/AGENTS.md +3 -3
  71. package/plugins/qoder/skills/sprint-flow/AGENTS.md +3 -3
  72. package/plugins/qoder/skills/test-specification-alignment/AGENTS.md +3 -3
  73. package/principles/AGENTS.md +3 -3
  74. package/skills/batch-grill-me/SKILL.md +9 -2
  75. package/skills/delphi-review/AGENTS.md +3 -3
  76. package/skills/sprint-flow/AGENTS.md +3 -3
  77. package/skills/test-specification-alignment/AGENTS.md +3 -3
  78. package/sprint-gate.sh +0 -0
  79. package/plugins/dsh/lib/command.d.ts +0 -32
  80. package/plugins/dsh/lib/command.d.ts.map +0 -1
  81. package/plugins/dsh/lib/command.js +0 -81
  82. package/plugins/dsh/lib/delphi-config.d.ts +0 -75
  83. package/plugins/dsh/lib/delphi-config.d.ts.map +0 -1
  84. package/plugins/dsh/lib/delphi-config.js +0 -183
  85. package/plugins/dsh/lib/delphi-run.d.ts +0 -24
  86. package/plugins/dsh/lib/delphi-run.d.ts.map +0 -1
  87. package/plugins/dsh/lib/delphi-run.js +0 -92
  88. package/plugins/dsh/lib/delphi.d.ts +0 -88
  89. package/plugins/dsh/lib/delphi.d.ts.map +0 -1
  90. package/plugins/dsh/lib/delphi.js +0 -161
  91. package/plugins/dsh/lib/dialect.d.ts +0 -24
  92. package/plugins/dsh/lib/dialect.d.ts.map +0 -1
  93. package/plugins/dsh/lib/dialect.js +0 -36
  94. package/plugins/dsh/lib/gate-runner.d.ts +0 -18
  95. package/plugins/dsh/lib/gate-runner.d.ts.map +0 -1
  96. package/plugins/dsh/lib/gate-runner.js +0 -46
  97. package/plugins/dsh/lib/index.d.ts +0 -5
  98. package/plugins/dsh/lib/index.d.ts.map +0 -1
  99. package/plugins/dsh/lib/index.js +0 -162
  100. package/plugins/dsh/node_modules/.vite/vitest/results.json +0 -1
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@boyingliu01/opencode-plugin",
3
- "version": "0.27.4",
3
+ "version": "0.27.5",
4
4
  "type": "module",
5
5
  "main": "index.ts",
6
6
  "description": "XP-Gate quality gates + AI workflow skills + Sprint Flow TUI sidebar for OpenCode",
@@ -1,10 +1,17 @@
1
1
  ---
2
2
  name: batch-grill-me
3
- version: 1.0.0
4
- description: A relentless interview that asks every frontier question at once, round by round.
3
+ version: 1.1.0
4
+ description: A relentless interview that asks every frontier question at once, round by round. Thin alias of `grilling` (#540) — upstream mattpocock/skills absorbed this protocol into grilling; XP-Gate keeps this name as the sprint-flow Phase 2 entry point so orchestration docs stay stable.
5
5
  disable-model-invocation: true
6
6
  ---
7
7
 
8
+ > **Disposition (#540):** upstream deleted the standalone batch-grill-me skill — its round-based
9
+ > frontier protocol now IS upstream `grilling`. This file is intentionally a thin alias: keep it
10
+ > as the canonical sprint-flow reference name; protocol changes land in `skills/grilling/SKILL.md`
11
+ > (the single source), not here.
12
+
13
+ The protocol is identical to [`grilling`](../grilling/SKILL.md): read and follow that skill. Summary:
14
+
8
15
  Interview the user relentlessly until you reach a shared understanding. Map this as a **design tree**: every decision branches into the decisions that hang off it.
9
16
 
10
17
  Work the tree in **rounds**. The **frontier** is every decision whose prerequisites are already settled — the questions you can ask *now* without guessing at answers you haven't heard yet. Ask the whole frontier in one round: number each question and give your recommended answer. Then wait for the user's answers before the next round.
@@ -1,9 +1,9 @@
1
1
  # SKILLS/DELPHI-REVIEW KNOWLEDGE BASE
2
2
 
3
- **Generated:** 2026-10-17
4
- **Commit:** fff6c994
3
+ **Generated:** 2026-10-18
4
+ **Commit:** 41792f89
5
5
  **Branch:** main
6
- **Version:** 0.27.4.0
6
+ **Version:** 0.27.5.0
7
7
 
8
8
  ## OVERVIEW
9
9
  Delphi Consensus Review — multi-round anonymous expert review (≥90% threshold, exactly 3 experts with distinct executable model IDs). Supports design, requirements, and code-walkthrough modes.
@@ -1,9 +1,9 @@
1
1
  # SKILLS/SPRINT-FLOW KNOWLEDGE BASE
2
2
 
3
- **Generated:** 2026-10-17
4
- **Commit:** fff6c994
3
+ **Generated:** 2026-10-18
4
+ **Commit:** 41792f89
5
5
  **Branch:** main
6
- **Version:** 0.27.4.0
6
+ **Version:** 0.27.5.0
7
7
 
8
8
  ## OVERVIEW
9
9
  **6-phase** development pipeline (v2.0 compact redesign, Issue #290): PREP → DESIGN → BUILD → VERIFY → SHIP → CLOSE. Phase 3/6 BUILD default build mode is **ralph-loop** (REQ-level iteration, 40-67% token savings vs parallel). HARD-GATE between DESIGN (2/6) and BUILD (3/6): design must pass Delphi review (≥90% consensus) before any coding.
@@ -1,9 +1,9 @@
1
1
  # SKILLS/TEST-SPECIFICATION-ALIGNMENT KNOWLEDGE BASE
2
2
 
3
- **Generated:** 2026-10-17
4
- **Commit:** fff6c994
3
+ **Generated:** 2026-10-18
4
+ **Commit:** 41792f89
5
5
  **Branch:** main
6
- **Version:** 0.27.4.0
6
+ **Version:** 0.27.5.0
7
7
 
8
8
  ## OVERVIEW
9
9
  Test-Specification Alignment Engine — two-stage validation ensuring tests accurately reflect requirements and design specs.
File without changes
File without changes
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xp-gate",
3
- "version": "0.27.4",
3
+ "version": "0.27.5",
4
4
  "displayName": "XP-Gate",
5
5
  "description": "Extreme Programming quality gates + AI workflow skills for Qoder. Includes 12 pre-commit gates (Gate 0-11), 8 pre-push gates, Sprint Flow (6 phases), and Delphi multi-expert review (>=90% consensus).",
6
6
  "author": {
@@ -1,9 +1,9 @@
1
1
  # SKILLS/DELPHI-REVIEW KNOWLEDGE BASE
2
2
 
3
- **Generated:** 2026-10-17
4
- **Commit:** fff6c994
3
+ **Generated:** 2026-10-18
4
+ **Commit:** 41792f89
5
5
  **Branch:** main
6
- **Version:** 0.27.4.0
6
+ **Version:** 0.27.5.0
7
7
 
8
8
  ## OVERVIEW
9
9
  Delphi Consensus Review — multi-round anonymous expert review (≥90% threshold, exactly 3 experts with distinct executable model IDs). Supports design, requirements, and code-walkthrough modes.
@@ -1,9 +1,9 @@
1
1
  # SKILLS/SPRINT-FLOW KNOWLEDGE BASE
2
2
 
3
- **Generated:** 2026-10-17
4
- **Commit:** fff6c994
3
+ **Generated:** 2026-10-18
4
+ **Commit:** 41792f89
5
5
  **Branch:** main
6
- **Version:** 0.27.4.0
6
+ **Version:** 0.27.5.0
7
7
 
8
8
  ## OVERVIEW
9
9
  **6-phase** development pipeline (v2.0 compact redesign, Issue #290): PREP → DESIGN → BUILD → VERIFY → SHIP → CLOSE. Phase 3/6 BUILD default build mode is **ralph-loop** (REQ-level iteration, 40-67% token savings vs parallel). HARD-GATE between DESIGN (2/6) and BUILD (3/6): design must pass Delphi review (≥90% consensus) before any coding.
@@ -1,9 +1,9 @@
1
1
  # SKILLS/TEST-SPECIFICATION-ALIGNMENT KNOWLEDGE BASE
2
2
 
3
- **Generated:** 2026-10-17
4
- **Commit:** fff6c994
3
+ **Generated:** 2026-10-18
4
+ **Commit:** 41792f89
5
5
  **Branch:** main
6
- **Version:** 0.27.4.0
6
+ **Version:** 0.27.5.0
7
7
 
8
8
  ## OVERVIEW
9
9
  Test-Specification Alignment Engine — two-stage validation ensuring tests accurately reflect requirements and design specs.
@@ -1,9 +1,9 @@
1
1
  # PRINCIPLES CHECKER MODULE
2
2
 
3
- **Generated:** 2026-10-17
4
- **Commit:** fff6c994
3
+ **Generated:** 2026-10-18
4
+ **Commit:** 41792f89
5
5
  **Branch:** main
6
- **Version:** 0.27.4.0
6
+ **Version:** 0.27.5.0
7
7
 
8
8
  ## OVERVIEW
9
9
  Clean Code & SOLID principles checker — **Gate 4** of pre-commit. 14 rules × 9 language adapters, SARIF 2.1.0 output. Houses the **Boy Scout Rule** enforcement engine (Gate 6) and warning-baseline storage.
@@ -1,10 +1,17 @@
1
1
  ---
2
2
  name: batch-grill-me
3
- version: 1.0.0
4
- description: A relentless interview that asks every frontier question at once, round by round.
3
+ version: 1.1.0
4
+ description: A relentless interview that asks every frontier question at once, round by round. Thin alias of `grilling` (#540) — upstream mattpocock/skills absorbed this protocol into grilling; XP-Gate keeps this name as the sprint-flow Phase 2 entry point so orchestration docs stay stable.
5
5
  disable-model-invocation: true
6
6
  ---
7
7
 
8
+ > **Disposition (#540):** upstream deleted the standalone batch-grill-me skill — its round-based
9
+ > frontier protocol now IS upstream `grilling`. This file is intentionally a thin alias: keep it
10
+ > as the canonical sprint-flow reference name; protocol changes land in `skills/grilling/SKILL.md`
11
+ > (the single source), not here.
12
+
13
+ The protocol is identical to [`grilling`](../grilling/SKILL.md): read and follow that skill. Summary:
14
+
8
15
  Interview the user relentlessly until you reach a shared understanding. Map this as a **design tree**: every decision branches into the decisions that hang off it.
9
16
 
10
17
  Work the tree in **rounds**. The **frontier** is every decision whose prerequisites are already settled — the questions you can ask *now* without guessing at answers you haven't heard yet. Ask the whole frontier in one round: number each question and give your recommended answer. Then wait for the user's answers before the next round.
@@ -1,9 +1,9 @@
1
1
  # SKILLS/DELPHI-REVIEW KNOWLEDGE BASE
2
2
 
3
- **Generated:** 2026-10-17
4
- **Commit:** fff6c994
3
+ **Generated:** 2026-10-18
4
+ **Commit:** 41792f89
5
5
  **Branch:** main
6
- **Version:** 0.27.4.0
6
+ **Version:** 0.27.5.0
7
7
 
8
8
  ## OVERVIEW
9
9
  Delphi Consensus Review — multi-round anonymous expert review (≥90% threshold, exactly 3 experts with distinct executable model IDs). Supports design, requirements, and code-walkthrough modes.
@@ -1,9 +1,9 @@
1
1
  # SKILLS/SPRINT-FLOW KNOWLEDGE BASE
2
2
 
3
- **Generated:** 2026-10-17
4
- **Commit:** fff6c994
3
+ **Generated:** 2026-10-18
4
+ **Commit:** 41792f89
5
5
  **Branch:** main
6
- **Version:** 0.27.4.0
6
+ **Version:** 0.27.5.0
7
7
 
8
8
  ## OVERVIEW
9
9
  **6-phase** development pipeline (v2.0 compact redesign, Issue #290): PREP → DESIGN → BUILD → VERIFY → SHIP → CLOSE. Phase 3/6 BUILD default build mode is **ralph-loop** (REQ-level iteration, 40-67% token savings vs parallel). HARD-GATE between DESIGN (2/6) and BUILD (3/6): design must pass Delphi review (≥90% consensus) before any coding.
@@ -1,9 +1,9 @@
1
1
  # SKILLS/TEST-SPECIFICATION-ALIGNMENT KNOWLEDGE BASE
2
2
 
3
- **Generated:** 2026-10-17
4
- **Commit:** fff6c994
3
+ **Generated:** 2026-10-18
4
+ **Commit:** 41792f89
5
5
  **Branch:** main
6
- **Version:** 0.27.4.0
6
+ **Version:** 0.27.5.0
7
7
 
8
8
  ## OVERVIEW
9
9
  Test-Specification Alignment Engine — two-stage validation ensuring tests accurately reflect requirements and design specs.
package/sprint-gate.sh CHANGED
File without changes
@@ -1,32 +0,0 @@
1
- import { type ShellDialect } from "./dialect.js";
2
- export { type ShellDialect, detectDialect, shellQuote, shq } from "./dialect.js";
3
- /** Shown when the global `xp-gate` CLI is not on PATH. */
4
- export declare const FALLBACK_MESSAGE = "[XP-Gate] xp-gate CLI not installed. Install it with: npm install -g @boyingliu01/xp-gate";
5
- /**
6
- * Allowlist of xp-gate gate aliases that are safe to invoke standalone
7
- * (non-preCommitOnly gates + common aliases). Anything outside this set is
8
- * rejected before reaching the shell.
9
- */
10
- export declare const GATE_WHITELIST: readonly ["duplicates", "complexity", "principles", "arch", "architecture", "iac", "secrets", "sast"];
11
- export type GateId = (typeof GATE_WHITELIST)[number];
12
- export declare function isGateAllowed(gate: string): boolean;
13
- export interface BuildCommandOptions {
14
- subcommand: "check" | "principles" | "arch";
15
- target?: string;
16
- gates?: readonly string[];
17
- config?: string;
18
- /**
19
- * Executor dialect. Defaults to `"posix"` so existing callers keep working;
20
- * callers running under DSH on Windows must pass `"powershell"`.
21
- */
22
- dialect?: ShellDialect;
23
- }
24
- /**
25
- * Build a single guarded shell command: runs `xp-gate …` when the global CLI
26
- * is present, otherwise prints the graceful-degradation hint. A single
27
- * presence check avoids a separate probe/run race.
28
- */
29
- export declare function buildCommand(options: BuildCommandOptions): string;
30
- /** Resolve a model-supplied path against the session cwd; absolutes pass through. */
31
- export declare function resolveTarget(rawPath: string, cwd: string): string;
32
- //# sourceMappingURL=command.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../src/command.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,YAAY,EAAc,MAAM,cAAc,CAAA;AAI5D,OAAO,EAAE,KAAK,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,cAAc,CAAA;AAEhF,0DAA0D;AAC1D,eAAO,MAAM,gBAAgB,8FACgE,CAAA;AAE7F;;;;GAIG;AACH,eAAO,MAAM,cAAc,uGASjB,CAAA;AAEV,MAAM,MAAM,MAAM,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAA;AAEpD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEnD;AAED,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,OAAO,GAAG,YAAY,GAAG,MAAM,CAAA;IAC3C,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACzB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;;OAGG;IACH,OAAO,CAAC,EAAE,YAAY,CAAA;CACvB;AA+BD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,MAAM,CAmBjE;AAED,qFAAqF;AACrF,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAElE"}
@@ -1,81 +0,0 @@
1
- import { isAbsolute, resolve } from "node:path";
2
- import { shellQuote } from "./dialect.js";
3
- // Re-exported so existing importers of this module keep working; the dialect
4
- // primitives themselves live in ./dialect.ts.
5
- export { detectDialect, shellQuote, shq } from "./dialect.js";
6
- /** Shown when the global `xp-gate` CLI is not on PATH. */
7
- export const FALLBACK_MESSAGE = "[XP-Gate] xp-gate CLI not installed. Install it with: npm install -g @boyingliu01/xp-gate";
8
- /**
9
- * Allowlist of xp-gate gate aliases that are safe to invoke standalone
10
- * (non-preCommitOnly gates + common aliases). Anything outside this set is
11
- * rejected before reaching the shell.
12
- */
13
- export const GATE_WHITELIST = [
14
- "duplicates",
15
- "complexity",
16
- "principles",
17
- "arch",
18
- "architecture",
19
- "iac",
20
- "secrets",
21
- "sast",
22
- ];
23
- export function isGateAllowed(gate) {
24
- return GATE_WHITELIST.includes(gate);
25
- }
26
- function buildInner(options, dialect) {
27
- const { subcommand, target, gates, config } = options;
28
- const q = (value) => shellQuote(value, dialect);
29
- if (subcommand === "check") {
30
- const tokens = ["xp-gate", "check"];
31
- if (target !== undefined)
32
- tokens.push(q(target));
33
- if (gates !== undefined && gates.length > 0) {
34
- // Defense-in-depth: the JSON-schema enum already rejects unknown gate ids,
35
- // but we also whitelist here so a non-whitelisted value can never reach the shell.
36
- const allowed = gates.filter(isGateAllowed);
37
- if (allowed.length > 0)
38
- tokens.push("--gates", q(allowed.join(",")));
39
- }
40
- return tokens.join(" ");
41
- }
42
- if (subcommand === "principles") {
43
- const tokens = ["xp-gate", "principles"];
44
- if (target !== undefined)
45
- tokens.push(q(target));
46
- return tokens.join(" ");
47
- }
48
- // subcommand === "arch" — the only remaining member of the union.
49
- // #447: the default path runs the pinned local @archlinter/cli with its
50
- // built-in rules — no config needed. Forcing `--config architecture.yaml`
51
- // (the old default) hit the pre-0.16 schema that archlint itself rejects.
52
- // Only forward an explicitly provided config, via the opt-in --use-config.
53
- const tokens = ["xp-gate", "arch"];
54
- if (config !== undefined)
55
- tokens.push("--use-config", q(config));
56
- return tokens.join(" ");
57
- }
58
- /**
59
- * Build a single guarded shell command: runs `xp-gate …` when the global CLI
60
- * is present, otherwise prints the graceful-degradation hint. A single
61
- * presence check avoids a separate probe/run race.
62
- */
63
- export function buildCommand(options) {
64
- const dialect = options.dialect ?? "posix";
65
- const inner = buildInner(options, dialect);
66
- if (dialect === "posix") {
67
- return `if command -v xp-gate >/dev/null 2>&1; then ${inner}; else printf '%s\\n' ${shellQuote(FALLBACK_MESSAGE, dialect)}; fi`;
68
- }
69
- // PowerShell: `Get-Command` resolves the .cmd/.ps1 shims npm writes to
70
- // %APPDATA%\npm. Those shims are invisible to a Git-Bash PATH lookup, so this
71
- // branch is more reliable than `command -v` on Windows.
72
- //
73
- // The hint branch leaves $LASTEXITCODE untouched at 0, matching the POSIX
74
- // branch's `printf` behaviour.
75
- return `if (Get-Command xp-gate -ErrorAction SilentlyContinue) { ${inner} } else { Write-Output ${shellQuote(FALLBACK_MESSAGE, dialect)} }`;
76
- }
77
- /** Resolve a model-supplied path against the session cwd; absolutes pass through. */
78
- export function resolveTarget(rawPath, cwd) {
79
- return isAbsolute(rawPath) ? rawPath : resolve(cwd, rawPath);
80
- }
81
- //# sourceMappingURL=command.js.map
@@ -1,75 +0,0 @@
1
- /**
2
- * Delphi configuration loading for the DSH plugin.
3
- *
4
- * Reads the same `.delphi-config.json` the xp-gate skill already uses, so a
5
- * project configures its reviewers once and both the skill and the DSH tool
6
- * agree on who they are.
7
- *
8
- * @test REQ-DSH-016
9
- * @intent 复用项目既有的 .delphi-config.json,把 provider/api_key/专家席位解析成
10
- * DSH 工具可用的结构,并对 ${ENV} 占位符与缺失密钥给出可操作的报错。
11
- * @covers AC-DSH-016-02
12
- */
13
- import type { ExpertSeat, DelphiOptions } from "./delphi.js";
14
- /** Shape of one expert entry in .delphi-config.json. */
15
- interface RawExpert {
16
- id?: string;
17
- role?: string;
18
- name?: string;
19
- model?: string;
20
- requested_model?: string;
21
- max_tokens?: number;
22
- maxTokens?: number;
23
- /** Per-expert provider override; falls back to the profile default. */
24
- provider?: string;
25
- }
26
- interface RawProfile {
27
- provider?: string;
28
- providers?: Record<string, {
29
- base_url?: string;
30
- baseUrl?: string;
31
- api_key?: string;
32
- apiKey?: string;
33
- }>;
34
- /**
35
- * Experts appear in two shapes in the wild: an object keyed by role (what
36
- * xp-gate actually writes) and an array. Both are accepted.
37
- */
38
- experts?: RawExpert[] | Record<string, RawExpert>;
39
- consensus?: {
40
- threshold_percent?: number;
41
- max_review_rounds?: number;
42
- };
43
- }
44
- export interface RawDelphiConfig extends RawProfile {
45
- active_profile?: string;
46
- profiles?: Record<string, RawProfile>;
47
- }
48
- export interface ResolvedDelphiConfig {
49
- readonly seats: ExpertSeat[];
50
- readonly baseUrl: string;
51
- readonly apiKey: string;
52
- readonly thresholdPercent: number;
53
- readonly maxRounds: number;
54
- readonly provider: string;
55
- }
56
- /** Raised when config on disk cannot be turned into a usable review setup. */
57
- export declare class DelphiSetupError extends Error {
58
- }
59
- /**
60
- * Expand `${VAR}` and `{env:VAR}` placeholders from the environment.
61
- * Supports the two spellings already present in xp-gate config files.
62
- */
63
- export declare function expandEnv(value: string, env?: NodeJS.ProcessEnv): string;
64
- /**
65
- * Turn raw config into a ready-to-run review setup.
66
- * Fails loudly and specifically: a missing key or an unexpanded placeholder is
67
- * the most common way a Delphi run silently degrades.
68
- */
69
- export declare function resolveConfig(cfg: RawDelphiConfig, env?: NodeJS.ProcessEnv): ResolvedDelphiConfig;
70
- /** Read and resolve `.delphi-config.json` from a project root. */
71
- export declare function loadDelphiConfig(cwd: string, env?: NodeJS.ProcessEnv, globalPath?: string): ResolvedDelphiConfig;
72
- /** Build the transport options a round needs from a resolved config. */
73
- export declare function toDelphiOptions(cfg: ResolvedDelphiConfig): DelphiOptions;
74
- export {};
75
- //# sourceMappingURL=delphi-config.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"delphi-config.d.ts","sourceRoot":"","sources":["../src/delphi-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAG5D,wDAAwD;AACxD,UAAU,SAAS;IACjB,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,uEAAuE;IACvE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,UAAU,UAAU;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACtG;;;OAGG;IACH,OAAO,CAAC,EAAE,SAAS,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;IACjD,SAAS,CAAC,EAAE;QAAE,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CACvE;AAED,MAAM,WAAW,eAAgB,SAAQ,UAAU;IACjD,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;CACtC;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,KAAK,EAAE,UAAU,EAAE,CAAA;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAA;IACjC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAC1B;AAED,8EAA8E;AAC9E,qBAAa,gBAAiB,SAAQ,KAAK;CAAG;AAE9C;;;GAGG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAIrF;AA0ED;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EAAE,eAAe,EACpB,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,oBAAoB,CAuBtB;AAsCD,kEAAkE;AAClE,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,MAAM,EACX,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,UAAU,GAAE,MAAqE,GAChF,oBAAoB,CAkCtB;AAED,wEAAwE;AACxE,wBAAgB,eAAe,CAAC,GAAG,EAAE,oBAAoB,GAAG,aAAa,CAQxE"}
@@ -1,183 +0,0 @@
1
- /**
2
- * Delphi configuration loading for the DSH plugin.
3
- *
4
- * Reads the same `.delphi-config.json` the xp-gate skill already uses, so a
5
- * project configures its reviewers once and both the skill and the DSH tool
6
- * agree on who they are.
7
- *
8
- * @test REQ-DSH-016
9
- * @intent 复用项目既有的 .delphi-config.json,把 provider/api_key/专家席位解析成
10
- * DSH 工具可用的结构,并对 ${ENV} 占位符与缺失密钥给出可操作的报错。
11
- * @covers AC-DSH-016-02
12
- */
13
- import { readFileSync } from "node:fs";
14
- import { homedir } from "node:os";
15
- import { join, resolve } from "node:path";
16
- import { validateSeats } from "./delphi.js";
17
- /** Raised when config on disk cannot be turned into a usable review setup. */
18
- export class DelphiSetupError extends Error {
19
- }
20
- /**
21
- * Expand `${VAR}` and `{env:VAR}` placeholders from the environment.
22
- * Supports the two spellings already present in xp-gate config files.
23
- */
24
- export function expandEnv(value, env = process.env) {
25
- return value
26
- .replace(/\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g, (_m, name) => env[name] ?? "")
27
- .replace(/\{env:([A-Za-z_][A-Za-z0-9_]*)\}/g, (_m, name) => env[name] ?? "");
28
- }
29
- /** Pick the active profile, falling back to the top level. */
30
- function selectProfile(cfg) {
31
- const active = cfg.active_profile;
32
- if (active && cfg.profiles?.[active])
33
- return cfg.profiles[active];
34
- if (cfg.profiles && Object.keys(cfg.profiles).length > 0) {
35
- throw new DelphiSetupError(`No active_profile set. Available: ${Object.keys(cfg.profiles).join(", ")}`);
36
- }
37
- return cfg;
38
- }
39
- function seatFromRaw(raw, index, fallbackRole) {
40
- const model = raw.model ?? raw.requested_model ?? "";
41
- return {
42
- id: raw.id ?? raw.name ?? `Expert ${String.fromCharCode(65 + index)}`,
43
- role: raw.role ?? fallbackRole,
44
- model,
45
- maxTokens: raw.max_tokens ?? raw.maxTokens,
46
- };
47
- }
48
- /** Normalize either experts shape into an ordered list with roles attached. */
49
- function normalizeExperts(experts) {
50
- if (!experts)
51
- return [];
52
- if (Array.isArray(experts)) {
53
- return experts.map((raw, i) => ({ raw, role: raw.role ?? `expert${i}` }));
54
- }
55
- // Object form: the KEY is the role, which is how xp-gate writes it.
56
- return Object.entries(experts).map(([role, raw]) => ({ raw, role }));
57
- }
58
- /** Resolve every referenced provider's base_url + api_key, failing loudly. */
59
- function resolveProviders(profile, needed, env) {
60
- if (needed.size === 0) {
61
- throw new DelphiSetupError('No provider configured. Set "provider" on the profile or on each expert.');
62
- }
63
- const providerTable = profile.providers ?? {};
64
- const resolved = new Map();
65
- for (const name of needed) {
66
- const entry = providerTable[name];
67
- if (!entry) {
68
- throw new DelphiSetupError(`Provider "${name}" is not defined under "providers". ` +
69
- `Known: ${Object.keys(providerTable).join(", ") || "(none)"}`);
70
- }
71
- const baseUrl = entry.base_url ?? entry.baseUrl ?? "";
72
- if (!baseUrl)
73
- throw new DelphiSetupError(`Provider "${name}" has no base_url.`);
74
- const rawKey = entry.api_key ?? entry.apiKey ?? "";
75
- const apiKey = expandEnv(rawKey, env);
76
- if (!apiKey) {
77
- // Name the variable rather than echoing config, which may hold a literal key.
78
- const varName = /\$\{([A-Za-z_][A-Za-z0-9_]*)\}/.exec(rawKey)?.[1] ??
79
- /\{env:([A-Za-z_][A-Za-z0-9_]*)\}/.exec(rawKey)?.[1];
80
- throw new DelphiSetupError(varName
81
- ? `API key variable ${varName} is not set in the environment.`
82
- : `Provider "${name}" has no api_key.`);
83
- }
84
- resolved.set(name, { baseUrl, apiKey });
85
- }
86
- return resolved;
87
- }
88
- /**
89
- * Turn raw config into a ready-to-run review setup.
90
- * Fails loudly and specifically: a missing key or an unexpanded placeholder is
91
- * the most common way a Delphi run silently degrades.
92
- */
93
- export function resolveConfig(cfg, env = process.env) {
94
- const profile = selectProfile(cfg);
95
- const normalized = normalizeExperts(profile.experts);
96
- // An expert may name its own provider; otherwise there must be a profile-wide
97
- // default. Resolve base_url/api_key per provider so mixed setups work.
98
- const providerNames = new Set(normalized.map((e) => e.raw.provider ?? profile.provider).filter((p) => !!p));
99
- const resolvedProviders = resolveProviders(profile, providerNames, env);
100
- const seats = normalized.map((e, i) => seatFromRaw(e.raw, i, e.role));
101
- // Surface an unexpanded placeholder as a config error, not a provider 404.
102
- for (const s of seats) {
103
- if (s.model.includes("${") || s.model.includes("{env:")) {
104
- throw new DelphiSetupError(`Expert "${s.id}" model "${s.model}" is an unexpanded placeholder.`);
105
- }
106
- }
107
- validateSeats(seats);
108
- return buildResult(profile, normalized, resolvedProviders, seats, cfg);
109
- }
110
- /** Assemble the final result after seats and providers validated. */
111
- function buildResult(profile, normalized, resolvedProviders, seats, cfg) {
112
- // All seats share one gateway in the supported setup; require agreement so a
113
- // mixed list cannot silently send one seat's key to another host.
114
- const chosen = resolvedProviders.get(normalized[0].raw.provider ?? profile.provider ?? "");
115
- if (!chosen)
116
- throw new DelphiSetupError("Unable to resolve a provider for the first expert.");
117
- for (const e of normalized) {
118
- const name = e.raw.provider ?? profile.provider ?? "";
119
- const other = resolvedProviders.get(name);
120
- if (!other || other.baseUrl !== chosen.baseUrl) {
121
- throw new DelphiSetupError(`All experts must share one gateway base_url; "${name}" differs. ` +
122
- `Split the review or align the providers.`);
123
- }
124
- }
125
- // consensus may sit on the profile or at the document root; both occur.
126
- const consensus = profile.consensus ?? cfg.consensus;
127
- return {
128
- seats,
129
- baseUrl: chosen.baseUrl,
130
- apiKey: chosen.apiKey,
131
- thresholdPercent: consensus?.threshold_percent ?? 90,
132
- maxRounds: consensus?.max_review_rounds ?? 5,
133
- provider: normalized[0].raw.provider ?? profile.provider ?? "",
134
- };
135
- }
136
- /** Read and resolve `.delphi-config.json` from a project root. */
137
- export function loadDelphiConfig(cwd, env = process.env, globalPath = join(homedir(), ".config", "xp-gate", ".delphi-config.json")) {
138
- // Global fallback (AC-DSH-016-03): the machine-wide config at
139
- // ~/.config/xp-gate/.delphi-config.json is the single source of truth for
140
- // every project. Without it, each repo needed its own copy — and reading a
141
- // stale or differently-priced config from another project's directory caused
142
- // real money loss (2026-10-03: an expensive overseas model burned the daily
143
- // quota). A project-local config still wins, so per-project overrides work.
144
- const path = resolve(cwd, ".delphi-config.json");
145
- let raw;
146
- try {
147
- raw = readFileSync(path, "utf8");
148
- }
149
- catch (projectError) {
150
- // Fall back ONLY when the project file is genuinely absent (ENOENT); any
151
- // other read error must surface rather than silently route this run to
152
- // another config. Same semantics as delphi-external-review.cjs, which
153
- // gates the fallback on existsSync (walkthrough R8 MA-01).
154
- if (projectError?.code !== "ENOENT") {
155
- throw new DelphiSetupError(`Cannot read ${path}: ${projectError.message}`);
156
- }
157
- try {
158
- raw = readFileSync(globalPath, "utf8");
159
- }
160
- catch {
161
- throw new DelphiSetupError(`No .delphi-config.json found at ${path} or the global location ${globalPath}.`);
162
- }
163
- }
164
- let parsed;
165
- try {
166
- parsed = JSON.parse(raw);
167
- }
168
- catch (e) {
169
- throw new DelphiSetupError(`.delphi-config.json is not valid JSON: ${e.message}`);
170
- }
171
- return resolveConfig(parsed, env);
172
- }
173
- /** Build the transport options a round needs from a resolved config. */
174
- export function toDelphiOptions(cfg) {
175
- return {
176
- baseUrl: cfg.baseUrl,
177
- apiKey: cfg.apiKey,
178
- seats: cfg.seats,
179
- thresholdPercent: cfg.thresholdPercent,
180
- maxRounds: cfg.maxRounds,
181
- };
182
- }
183
- //# sourceMappingURL=delphi-config.js.map
@@ -1,24 +0,0 @@
1
- /**
2
- * Delphi review orchestration: iterate rounds until consensus or the cap.
3
- *
4
- * @test REQ-DSH-016
5
- * @intent 编排多轮交叉评审:首轮匿名独立评审,后续轮次反馈上一轮汇总,
6
- * 直到达到共识阈值(默认 90%)或触及轮次上限(默认 5),
7
- * 并把结果整理成可写成 .code-walkthrough-result.json 的证据。
8
- * @covers AC-DSH-016-03
9
- */
10
- import type { DelphiOptions, RoundResult } from "./delphi.js";
11
- export interface ReviewOutcome {
12
- readonly rounds: readonly RoundResult[];
13
- readonly consensus: boolean;
14
- readonly finalRatio: number;
15
- readonly totalRounds: number;
16
- }
17
- /**
18
- * Run a full review. Round 1 is anonymous; each later round sees the aggregate
19
- * plus whatever the caller says was addressed, then re-votes.
20
- */
21
- export declare function runReview(opts: DelphiOptions, subject: string, addressed?: string): Promise<ReviewOutcome>;
22
- /** Human-readable transcript for the tool result. */
23
- export declare function formatOutcome(outcome: ReviewOutcome): string;
24
- //# sourceMappingURL=delphi-run.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"delphi-run.d.ts","sourceRoot":"","sources":["../src/delphi-run.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAc,WAAW,EAAE,MAAM,aAAa,CAAA;AAOzE,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,MAAM,EAAE,SAAS,WAAW,EAAE,CAAA;IACvC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;CAC7B;AA0CD;;;GAGG;AACH,wBAAsB,SAAS,CAC7B,IAAI,EAAE,aAAa,EACnB,OAAO,EAAE,MAAM,EACf,SAAS,SAAK,GACb,OAAO,CAAC,aAAa,CAAC,CAoCxB;AAED,qDAAqD;AACrD,wBAAgB,aAAa,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,CAiB5D"}