@vyuhlabs/dxkit 2.21.2 → 2.22.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.
Files changed (50) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/dist/analyzers/flow/config.d.ts +10 -0
  3. package/dist/analyzers/flow/config.d.ts.map +1 -1
  4. package/dist/analyzers/flow/config.js +29 -0
  5. package/dist/analyzers/flow/config.js.map +1 -1
  6. package/dist/analyzers/flow/contract.d.ts +12 -0
  7. package/dist/analyzers/flow/contract.d.ts.map +1 -1
  8. package/dist/analyzers/flow/contract.js +20 -0
  9. package/dist/analyzers/flow/contract.js.map +1 -1
  10. package/dist/analyzers/flow/diagnose.d.ts +62 -0
  11. package/dist/analyzers/flow/diagnose.d.ts.map +1 -0
  12. package/dist/analyzers/flow/diagnose.js +120 -0
  13. package/dist/analyzers/flow/diagnose.js.map +1 -0
  14. package/dist/analyzers/flow/publish.d.ts +47 -0
  15. package/dist/analyzers/flow/publish.d.ts.map +1 -0
  16. package/dist/analyzers/flow/publish.js +146 -0
  17. package/dist/analyzers/flow/publish.js.map +1 -0
  18. package/dist/analyzers/flow/setup.d.ts +71 -0
  19. package/dist/analyzers/flow/setup.d.ts.map +1 -0
  20. package/dist/analyzers/flow/setup.js +136 -0
  21. package/dist/analyzers/flow/setup.js.map +1 -0
  22. package/dist/cli.d.ts.map +1 -1
  23. package/dist/cli.js +52 -2
  24. package/dist/cli.js.map +1 -1
  25. package/dist/doctor.d.ts +7 -0
  26. package/dist/doctor.d.ts.map +1 -1
  27. package/dist/doctor.js +38 -1
  28. package/dist/doctor.js.map +1 -1
  29. package/dist/flow-cli.d.ts +10 -0
  30. package/dist/flow-cli.d.ts.map +1 -1
  31. package/dist/flow-cli.js +46 -0
  32. package/dist/flow-cli.js.map +1 -1
  33. package/dist/generator.d.ts.map +1 -1
  34. package/dist/generator.js +6 -0
  35. package/dist/generator.js.map +1 -1
  36. package/dist/prompts.d.ts +15 -0
  37. package/dist/prompts.d.ts.map +1 -1
  38. package/dist/prompts.js +66 -0
  39. package/dist/prompts.js.map +1 -1
  40. package/dist/workspace.d.ts +52 -0
  41. package/dist/workspace.d.ts.map +1 -0
  42. package/dist/workspace.js +130 -0
  43. package/dist/workspace.js.map +1 -0
  44. package/package.json +1 -1
  45. package/templates/.claude/skills/dxkit-config/SKILL.md +14 -0
  46. package/templates/.claude/skills/dxkit-fix/SKILL.md +2 -0
  47. package/templates/.claude/skills/dxkit-flow/SKILL.md +83 -0
  48. package/templates/.claude/skills/dxkit-hooks/SKILL.md +1 -1
  49. package/templates/.claude/skills/dxkit-init/SKILL.md +5 -0
  50. package/templates/.claude/skills/dxkit-onboard/SKILL.md +2 -0
package/CHANGELOG.md CHANGED
@@ -7,6 +7,37 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [2.22.0] - 2026-07-02
11
+
12
+ ### Added — the flow feature becomes agent-operable (setup, diagnose, publish, repair)
13
+
14
+ The UI→API integration gate now has the surfaces an agent (or a person) needs to
15
+ configure, diagnose, and repair it — folded into the commands you already run so
16
+ the CLI stays small.
17
+
18
+ - **Setup folds into `init`.** There is no standalone `flow init`. When `init`
19
+ detects a UI→API surface (client calls and/or server routes) it offers the
20
+ integration gate and asks for the posture — `warn` (default), `block`, or
21
+ `off` — with a one-line description of each; a repo with no such surface stays
22
+ silent. `--flow` forces it on with `warn`; `--no-flow` skips it. The dominant
23
+ base-URL helper to strip and any multiple backend services are surfaced as
24
+ confirm prompts.
25
+ - **`.dxkit/workspace.json`** — a new top-level participants primitive naming the
26
+ repos/services of a multi-repo system (path, optional git ref, base URLs).
27
+ - **Diagnose folds into `doctor`.** There is no standalone `flow doctor`. When the
28
+ repo has a UI→API surface, `doctor` reports a flow-contract diagnosis — the
29
+ unresolved client calls (each with a reason and a suggested next step), the
30
+ served routes nobody consumes, and how the served side is resolved — and
31
+ `doctor --json` carries the whole `flow` object for an agent to read.
32
+ - **`flow publish`** — the multi-repo handshake. Reads `workspace.json` and unions
33
+ every participant's served routes into this repo's `served.json`, so a consumer
34
+ repo gates its calls against a provider it does not co-locate. Participants are
35
+ gathered from a local path, optionally pinned at a git ref; fail-open per
36
+ participant. A content-hash on the snapshot lets a consumer detect drift.
37
+ - **`dxkit-flow` skill** — the operator surface: setup, diagnose, fix (repair a
38
+ net-new broken integration a guardrail flagged — never suppress it), and the
39
+ cross-repo handshake. Thin orchestration over the CLI; `--flow` installs it.
40
+
10
41
  ## [2.21.2] - 2026-07-02
11
42
 
12
43
  ### Fixed — the flow gate now runs in committed-baseline modes too
@@ -34,4 +34,14 @@ export interface FlowConfig {
34
34
  * config behaves as "monorepo, block on exact net-new breaks".
35
35
  */
36
36
  export declare function readFlowConfig(cwd: string): FlowConfig;
37
+ /**
38
+ * Write into `.dxkit/policy.json:flow`, merging the patch over the existing
39
+ * `flow` block and PRESERVING every other policy section (loop, baseline, …) —
40
+ * the same discipline `ensureLoopPreset` uses for `loop.preset`. This is the
41
+ * single writer of the flow policy section (Rule 2), paired with the reader
42
+ * above. Returns `true` if the file changed, `false` if it was already at the
43
+ * target (idempotent) or could not be parsed (malformed policy is left
44
+ * untouched — the caller reports it rather than clobbering hand-edits).
45
+ */
46
+ export declare function writeFlowPolicy(cwd: string, patch: Partial<Pick<FlowConfig, 'mode' | 'stripUrlPrefixes' | 'specs'>>): boolean;
37
47
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/analyzers/flow/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH;;;;;;8CAM8C;AAC9C,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,MAAM,GAAG,KAAK,CAAC;AAEpD,MAAM,WAAW,UAAU;IACzB;+CAC2C;IAC3C,QAAQ,CAAC,gBAAgB,EAAE,MAAM,EAAE,CAAC;IACpC,2EAA2E;IAC3E,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC;IACzB,yDAAyD;IACzD,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B;iEAC6D;IAC7D,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACjC;AAwBD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAiBtD"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/analyzers/flow/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH;;;;;;8CAM8C;AAC9C,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,MAAM,GAAG,KAAK,CAAC;AAEpD,MAAM,WAAW,UAAU;IACzB;+CAC2C;IAC3C,QAAQ,CAAC,gBAAgB,EAAE,MAAM,EAAE,CAAC;IACpC,2EAA2E;IAC3E,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC;IACzB,yDAAyD;IACzD,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B;iEAC6D;IAC7D,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACjC;AAwBD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAiBtD;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,kBAAkB,GAAG,OAAO,CAAC,CAAC,GACtE,OAAO,CAgBT"}
@@ -44,6 +44,7 @@ var __importStar = (this && this.__importStar) || (function () {
44
44
  })();
45
45
  Object.defineProperty(exports, "__esModule", { value: true });
46
46
  exports.readFlowConfig = readFlowConfig;
47
+ exports.writeFlowPolicy = writeFlowPolicy;
47
48
  const fs = __importStar(require("fs"));
48
49
  const path = __importStar(require("path"));
49
50
  const DEFAULTS = {
@@ -81,4 +82,32 @@ function readFlowConfig(cwd) {
81
82
  : DEFAULTS.blockThreshold,
82
83
  };
83
84
  }
85
+ /**
86
+ * Write into `.dxkit/policy.json:flow`, merging the patch over the existing
87
+ * `flow` block and PRESERVING every other policy section (loop, baseline, …) —
88
+ * the same discipline `ensureLoopPreset` uses for `loop.preset`. This is the
89
+ * single writer of the flow policy section (Rule 2), paired with the reader
90
+ * above. Returns `true` if the file changed, `false` if it was already at the
91
+ * target (idempotent) or could not be parsed (malformed policy is left
92
+ * untouched — the caller reports it rather than clobbering hand-edits).
93
+ */
94
+ function writeFlowPolicy(cwd, patch) {
95
+ const abs = path.join(cwd, '.dxkit', 'policy.json');
96
+ let policy = {};
97
+ if (fs.existsSync(abs)) {
98
+ try {
99
+ policy = JSON.parse(fs.readFileSync(abs, 'utf8'));
100
+ }
101
+ catch {
102
+ return false; // malformed — leave it; caller surfaces the note
103
+ }
104
+ }
105
+ const nextFlow = { ...(policy.flow ?? {}), ...patch };
106
+ if (JSON.stringify(policy.flow ?? {}) === JSON.stringify(nextFlow))
107
+ return false;
108
+ policy.flow = nextFlow;
109
+ fs.mkdirSync(path.dirname(abs), { recursive: true });
110
+ fs.writeFileSync(abs, JSON.stringify(policy, null, 2) + '\n', 'utf8');
111
+ return true;
112
+ }
84
113
  //# sourceMappingURL=config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/analyzers/flow/config.ts"],"names":[],"mappings":";AAAA;;;;;;;;;GASG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsDH,wCAiBC;AArED,uCAAyB;AACzB,2CAA6B;AAwB7B,MAAM,QAAQ,GAAe;IAC3B,gBAAgB,EAAE,EAAE;IACpB,KAAK,EAAE,EAAE;IACT,IAAI,EAAE,OAAO;IACb,cAAc,EAAE,CAAC;CAClB,CAAC;AASF,SAAS,UAAU,CAAC,CAAU;IAC5B,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACrF,CAAC;AAED,SAAS,MAAM,CAAC,CAAU;IACxB,OAAO,CAAC,KAAK,OAAO,IAAI,CAAC,KAAK,MAAM,IAAI,CAAC,KAAK,KAAK,CAAC;AACtD,CAAC;AAED;;;;GAIG;AACH,SAAgB,cAAc,CAAC,GAAW;IACxC,IAAI,GAAY,CAAC;IACjB,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,EAAE,aAAa,CAAC,EAAE,MAAM,CAAC,CAAC;QAC9E,GAAG,GAAG,CAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAwB,EAAE,IAAI,IAAI,EAAE,CAAY,CAAC;IAC1E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,OAAO;QACL,gBAAgB,EAAE,UAAU,CAAC,GAAG,CAAC,gBAAgB,CAAC;QAClD,KAAK,EAAE,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC;QAC5B,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI;QACjD,cAAc,EACZ,OAAO,GAAG,CAAC,cAAc,KAAK,QAAQ,IAAI,GAAG,CAAC,cAAc,GAAG,CAAC;YAC9D,CAAC,CAAC,GAAG,CAAC,cAAc;YACpB,CAAC,CAAC,QAAQ,CAAC,cAAc;KAC9B,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/analyzers/flow/config.ts"],"names":[],"mappings":"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"}
@@ -47,6 +47,10 @@ interface SnapshotMeta {
47
47
  readonly generatedAt: string;
48
48
  /** Commit the snapshot was produced against, when known. */
49
49
  readonly commitSha?: string;
50
+ /** Change-detection digest of the contract's contents — lets a consumer see
51
+ * that a published contract drifted (routes changed) even when the commit or
52
+ * timestamp did not carry the signal. Set by `flow publish`. */
53
+ readonly contentHash?: string;
50
54
  }
51
55
  export interface ServedContract extends SnapshotMeta {
52
56
  readonly side: 'served';
@@ -58,6 +62,14 @@ export interface ConsumedContract extends SnapshotMeta {
58
62
  }
59
63
  /** The `${method} ${path}` join key both sides meet on. */
60
64
  export declare function contractKey(method: string, routePath: string): string;
65
+ /**
66
+ * A short, stable content digest of a served route set. Lets a consumer detect
67
+ * that a published contract drifted (routes added/removed) even when the commit
68
+ * SHA or timestamp did not carry the signal. Non-cryptographic (FNV-1a): this
69
+ * is a change-detection digest, NOT a finding identity, so it deliberately does
70
+ * not route through the fingerprint helpers (Rule 9 governs identity, not this).
71
+ */
72
+ export declare function servedContentHash(routes: readonly ServedRoute[]): string;
61
73
  /**
62
74
  * The served inventory: every distinct `(method, path)` this repo serves,
63
75
  * deduped via the shared helper (spec wins). Sorted for byte-stable snapshots
@@ -1 +1 @@
1
- {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../../src/analyzers/flow/contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,OAAO,EAA6C,KAAK,SAAS,EAAE,MAAM,SAAS,CAAC;AAEpF,4EAA4E;AAC5E,eAAO,MAAM,QAAQ,QAA8B,CAAC;AACpD,eAAO,MAAM,eAAe,gBAAgB,CAAC;AAC7C,eAAO,MAAM,iBAAiB,kBAAkB,CAAC;AAEjD,wDAAwD;AACxD,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,GAAG,EAAE,WAAW,GAAG,aAAa,GAAG,MAAM,CAAC;CACpD;AAED;;;;wEAIwE;AACxE,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED,UAAU,YAAY;IACpB,QAAQ,CAAC,aAAa,EAAE,CAAC,CAAC;IAC1B;wDACoD;IACpD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,4DAA4D;IAC5D,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,cAAe,SAAQ,YAAY;IAClD,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC;CAChC;AAED,MAAM,WAAW,gBAAiB,SAAQ,YAAY;IACpD,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,eAAe,EAAE,CAAC;CACtC;AAED,2DAA2D;AAC3D,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAErE;AAID;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,YAAY,GAAG,cAAc,CAKxF;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,YAAY,GAAG,gBAAgB,CAsB5F;AAWD,oEAAoE;AACpE,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,GAAG,MAAM,CAEjF;AAED,sEAAsE;AACtE,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,gBAAgB,GAAG,MAAM,CAErF;AAgBD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAG7F;AAED,mEAAmE;AACnE,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAGjG;AAED;oEACoE;AACpE,wBAAgB,YAAY,CAAC,QAAQ,EAAE,cAAc,GAAG,GAAG,CAAC,MAAM,CAAC,CAElE"}
1
+ {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../../src/analyzers/flow/contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,OAAO,EAA6C,KAAK,SAAS,EAAE,MAAM,SAAS,CAAC;AAEpF,4EAA4E;AAC5E,eAAO,MAAM,QAAQ,QAA8B,CAAC;AACpD,eAAO,MAAM,eAAe,gBAAgB,CAAC;AAC7C,eAAO,MAAM,iBAAiB,kBAAkB,CAAC;AAEjD,wDAAwD;AACxD,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,GAAG,EAAE,WAAW,GAAG,aAAa,GAAG,MAAM,CAAC;CACpD;AAED;;;;wEAIwE;AACxE,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED,UAAU,YAAY;IACpB,QAAQ,CAAC,aAAa,EAAE,CAAC,CAAC;IAC1B;wDACoD;IACpD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,4DAA4D;IAC5D,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B;;qEAEiE;IACjE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,cAAe,SAAQ,YAAY;IAClD,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC;CAChC;AAED,MAAM,WAAW,gBAAiB,SAAQ,YAAY;IACpD,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,eAAe,EAAE,CAAC;CACtC;AAED,2DAA2D;AAC3D,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAErE;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,WAAW,EAAE,GAAG,MAAM,CAWxE;AAID;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,YAAY,GAAG,cAAc,CAKxF;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,YAAY,GAAG,gBAAgB,CAsB5F;AAWD,oEAAoE;AACpE,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,GAAG,MAAM,CAEjF;AAED,sEAAsE;AACtE,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,gBAAgB,GAAG,MAAM,CAErF;AAgBD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAG7F;AAED,mEAAmE;AACnE,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAGjG;AAED;oEACoE;AACpE,wBAAgB,YAAY,CAAC,QAAQ,EAAE,cAAc,GAAG,GAAG,CAAC,MAAM,CAAC,CAElE"}
@@ -53,6 +53,7 @@ var __importStar = (this && this.__importStar) || (function () {
53
53
  Object.defineProperty(exports, "__esModule", { value: true });
54
54
  exports.CONSUMED_SNAPSHOT = exports.SERVED_SNAPSHOT = exports.FLOW_DIR = void 0;
55
55
  exports.contractKey = contractKey;
56
+ exports.servedContentHash = servedContentHash;
56
57
  exports.buildServedContract = buildServedContract;
57
58
  exports.buildConsumedContract = buildConsumedContract;
58
59
  exports.writeServedContract = writeServedContract;
@@ -71,6 +72,25 @@ exports.CONSUMED_SNAPSHOT = 'consumed.json';
71
72
  function contractKey(method, routePath) {
72
73
  return `${method} ${routePath}`;
73
74
  }
75
+ /**
76
+ * A short, stable content digest of a served route set. Lets a consumer detect
77
+ * that a published contract drifted (routes added/removed) even when the commit
78
+ * SHA or timestamp did not carry the signal. Non-cryptographic (FNV-1a): this
79
+ * is a change-detection digest, NOT a finding identity, so it deliberately does
80
+ * not route through the fingerprint helpers (Rule 9 governs identity, not this).
81
+ */
82
+ function servedContentHash(routes) {
83
+ const canon = routes
84
+ .map((r) => contractKey(r.method, r.path))
85
+ .sort()
86
+ .join('\n');
87
+ let h = 0x811c9dc5;
88
+ for (let i = 0; i < canon.length; i++) {
89
+ h ^= canon.charCodeAt(i);
90
+ h = Math.imul(h, 0x01000193);
91
+ }
92
+ return (h >>> 0).toString(16).padStart(8, '0');
93
+ }
74
94
  // ─── Build (from a flow model) ────────────────────────────────────────────────
75
95
  /**
76
96
  * The served inventory: every distinct `(method, path)` this repo serves,
@@ -1 +1 @@
1
- {"version":3,"file":"contract.js","sourceRoot":"","sources":["../../../src/analyzers/flow/contract.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"contract.js","sourceRoot":"","sources":["../../../src/analyzers/flow/contract.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Flow diagnosis — the "diagnose" surface, folded into `doctor` (there is no
3
+ * standalone `flow doctor`). Where the gate answers "did this PR break an
4
+ * integration?", diagnose answers "what is the current state of the contract?":
5
+ * which client calls do NOT resolve to a served route and why, which served
6
+ * routes nobody consumes, and how the served side is being resolved (the
7
+ * connection-resolution ladder).
8
+ *
9
+ * The output is deliberately agent-legible — `doctor --json` carries the whole
10
+ * `FlowDiagnosis`, so the `dxkit-flow` skill reads it as a thin consumer rather
11
+ * than scraping console prose. Reuses the shared extractor (Rule 2); fail-open
12
+ * (any error → `null`, and doctor simply omits the flow section).
13
+ */
14
+ import type { FlowTopology } from './setup';
15
+ /** Why a client call did not cleanly bind to a served route. */
16
+ export type UnresolvedReason = 'no-route' | 'external' | 'placeholder-only';
17
+ /** The recommended next step for an unresolved call. `scaffold-resolver`
18
+ * (extend extraction to an unsupported framework) is intentionally NOT emitted
19
+ * here — an un-extracted call is absent, not unresolved; that path needs the
20
+ * extension SDK. */
21
+ export type FlowFixHint = 'add-route' | 'configure-participant' | 'adopt-spec' | 'annotate';
22
+ /** One client call that does not resolve, plus the reason and the suggested fix. */
23
+ export interface UnresolvedCall {
24
+ readonly method: string;
25
+ readonly rawUrl: string;
26
+ readonly path: string | null;
27
+ readonly file: string;
28
+ readonly line: number;
29
+ readonly reason: UnresolvedReason;
30
+ readonly suggestion: FlowFixHint;
31
+ }
32
+ /** A served route no client call binds to — a dead route, or a route consumed
33
+ * only by a repo dxkit cannot see (a cross-repo consumer). */
34
+ export interface UnconsumedRoute {
35
+ readonly method: string;
36
+ readonly path: string;
37
+ readonly file: string;
38
+ readonly line: number;
39
+ }
40
+ /** Which rung of the connection-resolution ladder produced the served set. */
41
+ export type ConnectionRung = 'monorepo' | 'committed-counterpart' | 'configured-participants' | 'unresolved';
42
+ export interface FlowDiagnosis {
43
+ readonly topology: FlowTopology;
44
+ readonly calls: number;
45
+ readonly routes: number;
46
+ readonly resolved: number;
47
+ /** Client calls that do not cleanly bind, each with a reason + suggestion. */
48
+ readonly unresolved: readonly UnresolvedCall[];
49
+ /** Served routes with no consuming call (dead-route / cross-repo candidates). */
50
+ readonly servedUnconsumed: readonly UnconsumedRoute[];
51
+ readonly connection: {
52
+ readonly rung: ConnectionRung;
53
+ readonly note: string;
54
+ };
55
+ }
56
+ /**
57
+ * Diagnose the repo's flow contract. Returns `null` (and doctor omits the flow
58
+ * section) when no flow-capable pack is active, when extraction finds nothing,
59
+ * or on any error.
60
+ */
61
+ export declare function diagnoseFlow(cwd: string): Promise<FlowDiagnosis | null>;
62
+ //# sourceMappingURL=diagnose.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diagnose.d.ts","sourceRoot":"","sources":["../../../src/analyzers/flow/diagnose.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAOH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C,gEAAgE;AAChE,MAAM,MAAM,gBAAgB,GAAG,UAAU,GAAG,UAAU,GAAG,kBAAkB,CAAC;AAE5E;;;qBAGqB;AACrB,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG,uBAAuB,GAAG,YAAY,GAAG,UAAU,CAAC;AAE5F,oFAAoF;AACpF,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAClC,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAC;CAClC;AAED;+DAC+D;AAC/D,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,8EAA8E;AAC9E,MAAM,MAAM,cAAc,GACtB,UAAU,GACV,uBAAuB,GACvB,yBAAyB,GACzB,YAAY,CAAC;AAEjB,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC;IAChC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,8EAA8E;IAC9E,QAAQ,CAAC,UAAU,EAAE,SAAS,cAAc,EAAE,CAAC;IAC/C,iFAAiF;IACjF,QAAQ,CAAC,gBAAgB,EAAE,SAAS,eAAe,EAAE,CAAC;IACtD,QAAQ,CAAC,UAAU,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/E;AA2DD;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CA2C7E"}
@@ -0,0 +1,120 @@
1
+ "use strict";
2
+ /**
3
+ * Flow diagnosis — the "diagnose" surface, folded into `doctor` (there is no
4
+ * standalone `flow doctor`). Where the gate answers "did this PR break an
5
+ * integration?", diagnose answers "what is the current state of the contract?":
6
+ * which client calls do NOT resolve to a served route and why, which served
7
+ * routes nobody consumes, and how the served side is being resolved (the
8
+ * connection-resolution ladder).
9
+ *
10
+ * The output is deliberately agent-legible — `doctor --json` carries the whole
11
+ * `FlowDiagnosis`, so the `dxkit-flow` skill reads it as a thin consumer rather
12
+ * than scraping console prose. Reuses the shared extractor (Rule 2); fail-open
13
+ * (any error → `null`, and doctor simply omits the flow section).
14
+ */
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.diagnoseFlow = diagnoseFlow;
17
+ const languages_1 = require("../../languages");
18
+ const gather_1 = require("./gather");
19
+ const model_1 = require("./model");
20
+ const contract_1 = require("./contract");
21
+ const workspace_1 = require("../../workspace");
22
+ function suggestionFor(reason, topology) {
23
+ switch (reason) {
24
+ case 'external':
25
+ return 'adopt-spec'; // add the external API's OpenAPI spec to verify it
26
+ case 'placeholder-only':
27
+ return 'annotate'; // too generic to verify — annotate if intentional
28
+ case 'no-route':
29
+ // A monorepo serves its own routes, so a miss is a missing/typo'd route;
30
+ // a consumer-only repo's provider lives elsewhere (configure it).
31
+ return topology === 'monorepo' ? 'add-route' : 'configure-participant';
32
+ }
33
+ }
34
+ /** Classify a binding into the unresolved tail, or `null` when it resolves. */
35
+ function classifyUnresolved(b, topology) {
36
+ let reason = null;
37
+ if (b.reason === 'external')
38
+ reason = 'external';
39
+ else if (b.reason === 'no-route')
40
+ reason = 'no-route';
41
+ else if (b.reason === 'placeholder-only')
42
+ reason = 'placeholder-only';
43
+ if (reason === null)
44
+ return null; // 'exact' → resolved
45
+ return {
46
+ method: b.call.method,
47
+ rawUrl: b.call.rawUrl,
48
+ path: b.call.path,
49
+ file: b.call.file,
50
+ line: b.call.line,
51
+ reason,
52
+ suggestion: suggestionFor(reason, topology),
53
+ };
54
+ }
55
+ function resolveConnection(cwd, model) {
56
+ if (model.routes.length > 0) {
57
+ return { rung: 'monorepo', note: 'This repo serves the routes its calls target.' };
58
+ }
59
+ if ((0, contract_1.readServedContract)(cwd)) {
60
+ return {
61
+ rung: 'committed-counterpart',
62
+ note: 'Resolving calls against the counterpart contract this repo commits.',
63
+ };
64
+ }
65
+ const ws = (0, workspace_1.readWorkspace)(cwd);
66
+ if (ws && ws.participants.length > 0) {
67
+ return {
68
+ rung: 'configured-participants',
69
+ note: `Configured participants: ${ws.participants.map((p) => p.name).join(', ')}.`,
70
+ };
71
+ }
72
+ return {
73
+ rung: 'unresolved',
74
+ note: 'No served side in this repo and no counterpart contract — the gate stays inert. Publish the provider contract or add a participant.',
75
+ };
76
+ }
77
+ /**
78
+ * Diagnose the repo's flow contract. Returns `null` (and doctor omits the flow
79
+ * section) when no flow-capable pack is active, when extraction finds nothing,
80
+ * or on any error.
81
+ */
82
+ async function diagnoseFlow(cwd) {
83
+ if ((0, languages_1.allFlowSourceExtensions)((0, languages_1.detectActiveLanguages)(cwd)).length === 0)
84
+ return null;
85
+ let model;
86
+ try {
87
+ model = await (0, gather_1.gatherFlowModel)({ roots: [cwd] });
88
+ }
89
+ catch {
90
+ return null;
91
+ }
92
+ const calls = model.calls.length;
93
+ const routes = model.routes.length;
94
+ if (calls === 0 && routes === 0)
95
+ return null;
96
+ const topology = calls > 0 && routes > 0 ? 'monorepo' : calls > 0 ? 'consumer-only' : 'provider-only';
97
+ const unresolved = model.bindings
98
+ .map((b) => classifyUnresolved(b, topology))
99
+ .filter((u) => u !== null);
100
+ const resolved = calls - unresolved.length;
101
+ // Served routes with no consuming binding. Consumed keys come from resolved
102
+ // bindings; the union with a committed counterpart's served set does NOT
103
+ // matter here — we only flag OUR served routes that nobody in scope calls.
104
+ const consumedKeys = new Set(model.bindings
105
+ .filter((b) => b.route !== null)
106
+ .map((b) => `${b.route.method} ${b.route.path}`));
107
+ const servedUnconsumed = model.routes
108
+ .filter((r) => !consumedKeys.has(`${r.method} ${r.path}`) && !(0, model_1.isPlaceholderOnlyPath)(r.path))
109
+ .map((r) => ({ method: r.method, path: r.path, file: r.file, line: r.line }));
110
+ return {
111
+ topology,
112
+ calls,
113
+ routes,
114
+ resolved,
115
+ unresolved,
116
+ servedUnconsumed,
117
+ connection: resolveConnection(cwd, model),
118
+ };
119
+ }
120
+ //# sourceMappingURL=diagnose.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diagnose.js","sourceRoot":"","sources":["../../../src/analyzers/flow/diagnose.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Flow publish — the multi-repo handshake behind `flow publish`.
3
+ *
4
+ * `flow refresh` writes ONE repo's served/consumed snapshots. `flow publish`
5
+ * goes further: it reads `.dxkit/workspace.json` and, for every participant,
6
+ * gathers that service's served routes (from its local path, optionally pinned
7
+ * at a git ref via `withRefWorktree`, Rule 11) and UNIONS them into this repo's
8
+ * `served.json`. The consuming repo then gates its calls against the whole mesh,
9
+ * not just the routes it happens to co-locate — the handshake that lets a
10
+ * frontend repo resolve calls to a backend it does not contain.
11
+ *
12
+ * With no participants it degenerates to a single-repo publish (this repo's own
13
+ * served ∪ nothing), the monorepo case. Fail-open per participant: a missing
14
+ * path or an unreachable ref drops that participant to zero routes rather than
15
+ * failing the publish. Reuses the canonical contract builders (Rule 2).
16
+ */
17
+ /** Where a participant's served routes came from. */
18
+ export type ParticipantSource = 'local' | 'ref' | 'missing';
19
+ export interface PublishedParticipant {
20
+ readonly name: string;
21
+ readonly routes: number;
22
+ readonly source: ParticipantSource;
23
+ }
24
+ export interface PublishResult {
25
+ readonly servedPath: string;
26
+ readonly consumedPath: string;
27
+ /** One entry per workspace participant (empty in the single-repo case). */
28
+ readonly participants: readonly PublishedParticipant[];
29
+ /** Total served routes in the unioned mesh contract. */
30
+ readonly totalServedRoutes: number;
31
+ /** This repo's own consumed bindings (the mesh's consumed side is per-repo). */
32
+ readonly consumedBindings: number;
33
+ readonly contentHash: string;
34
+ }
35
+ export interface PublishOptions {
36
+ readonly stripUrlPrefixes?: readonly string[];
37
+ readonly specs?: readonly string[];
38
+ /** Stamped onto the snapshot meta (kept out of this module for testability). */
39
+ readonly generatedAt: string;
40
+ readonly commitSha?: string;
41
+ }
42
+ /**
43
+ * Publish the mesh contract: this repo's served routes ∪ every participant's,
44
+ * written to `.dxkit/flow/served.json`, plus this repo's own `consumed.json`.
45
+ */
46
+ export declare function publishFlow(cwd: string, opts: PublishOptions): Promise<PublishResult>;
47
+ //# sourceMappingURL=publish.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publish.d.ts","sourceRoot":"","sources":["../../../src/analyzers/flow/publish.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAkBH,qDAAqD;AACrD,MAAM,MAAM,iBAAiB,GAAG,OAAO,GAAG,KAAK,GAAG,SAAS,CAAC;AAE5D,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;CACpC;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,2EAA2E;IAC3E,QAAQ,CAAC,YAAY,EAAE,SAAS,oBAAoB,EAAE,CAAC;IACvD,wDAAwD;IACxD,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,gFAAgF;IAChF,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9C,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,gFAAgF;IAChF,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAuDD;;;GAGG;AACH,wBAAsB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC,CAyC3F"}
@@ -0,0 +1,146 @@
1
+ "use strict";
2
+ /**
3
+ * Flow publish — the multi-repo handshake behind `flow publish`.
4
+ *
5
+ * `flow refresh` writes ONE repo's served/consumed snapshots. `flow publish`
6
+ * goes further: it reads `.dxkit/workspace.json` and, for every participant,
7
+ * gathers that service's served routes (from its local path, optionally pinned
8
+ * at a git ref via `withRefWorktree`, Rule 11) and UNIONS them into this repo's
9
+ * `served.json`. The consuming repo then gates its calls against the whole mesh,
10
+ * not just the routes it happens to co-locate — the handshake that lets a
11
+ * frontend repo resolve calls to a backend it does not contain.
12
+ *
13
+ * With no participants it degenerates to a single-repo publish (this repo's own
14
+ * served ∪ nothing), the monorepo case. Fail-open per participant: a missing
15
+ * path or an unreachable ref drops that participant to zero routes rather than
16
+ * failing the publish. Reuses the canonical contract builders (Rule 2).
17
+ */
18
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
19
+ if (k2 === undefined) k2 = k;
20
+ var desc = Object.getOwnPropertyDescriptor(m, k);
21
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
22
+ desc = { enumerable: true, get: function() { return m[k]; } };
23
+ }
24
+ Object.defineProperty(o, k2, desc);
25
+ }) : (function(o, m, k, k2) {
26
+ if (k2 === undefined) k2 = k;
27
+ o[k2] = m[k];
28
+ }));
29
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
30
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
31
+ }) : function(o, v) {
32
+ o["default"] = v;
33
+ });
34
+ var __importStar = (this && this.__importStar) || (function () {
35
+ var ownKeys = function(o) {
36
+ ownKeys = Object.getOwnPropertyNames || function (o) {
37
+ var ar = [];
38
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
39
+ return ar;
40
+ };
41
+ return ownKeys(o);
42
+ };
43
+ return function (mod) {
44
+ if (mod && mod.__esModule) return mod;
45
+ var result = {};
46
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
47
+ __setModuleDefault(result, mod);
48
+ return result;
49
+ };
50
+ })();
51
+ Object.defineProperty(exports, "__esModule", { value: true });
52
+ exports.publishFlow = publishFlow;
53
+ const fs = __importStar(require("fs"));
54
+ const path = __importStar(require("path"));
55
+ const workspace_1 = require("../../workspace");
56
+ const ref_baseline_1 = require("../../baseline/ref-baseline");
57
+ const gather_1 = require("./gather");
58
+ const contract_1 = require("./contract");
59
+ /** Meta with only the fields a participant gather needs — routes carry no
60
+ * timestamp of their own, so a clock-free placeholder keeps the gather pure. */
61
+ const GATHER_META = { schemaVersion: 1, generatedAt: '' };
62
+ /** Dedupe served routes to one per `(method, path)` — the mesh may serve the
63
+ * same route from this repo and a participant, or from two participants. */
64
+ function dedupeServed(routes) {
65
+ const seen = new Map();
66
+ for (const r of routes) {
67
+ const key = (0, contract_1.contractKey)(r.method, r.path);
68
+ if (!seen.has(key))
69
+ seen.set(key, r);
70
+ }
71
+ return [...seen.values()];
72
+ }
73
+ async function servedRoutesFrom(root, opts) {
74
+ const model = await (0, gather_1.gatherFlowModel)({
75
+ roots: [root],
76
+ ...(opts.specs ? { specs: opts.specs.map((s) => path.resolve(root, s)) } : {}),
77
+ ...(opts.stripUrlPrefixes ? { stripUrlPrefixes: [...opts.stripUrlPrefixes] } : {}),
78
+ relativeTo: root,
79
+ });
80
+ return (0, contract_1.buildServedContract)(model, GATHER_META).routes;
81
+ }
82
+ /** Gather one participant's served routes. Local path by default; pinned at a
83
+ * git ref when the participant declares one AND that ref resolves. Fail-open:
84
+ * a missing path → zero routes; an unresolvable ref → fall back to the tree. */
85
+ async function gatherParticipant(cwd, participant, opts) {
86
+ const abs = path.resolve(cwd, participant.path);
87
+ if (!fs.existsSync(abs))
88
+ return { routes: [], source: 'missing' };
89
+ if (participant.ref && (0, ref_baseline_1.resolveRefToSha)(abs, participant.ref)) {
90
+ try {
91
+ const routes = await (0, ref_baseline_1.withRefWorktree)({ cwd: abs, ref: participant.ref }, (wt) => servedRoutesFrom(wt, opts));
92
+ return { routes, source: 'ref' };
93
+ }
94
+ catch {
95
+ // Worktree/gather failure → fall through to the working tree.
96
+ }
97
+ }
98
+ try {
99
+ return { routes: await servedRoutesFrom(abs, opts), source: 'local' };
100
+ }
101
+ catch {
102
+ return { routes: [], source: 'missing' };
103
+ }
104
+ }
105
+ /**
106
+ * Publish the mesh contract: this repo's served routes ∪ every participant's,
107
+ * written to `.dxkit/flow/served.json`, plus this repo's own `consumed.json`.
108
+ */
109
+ async function publishFlow(cwd, opts) {
110
+ const baseMeta = {
111
+ schemaVersion: 1,
112
+ generatedAt: opts.generatedAt,
113
+ ...(opts.commitSha ? { commitSha: opts.commitSha } : {}),
114
+ };
115
+ // This repo's own model — its served routes seed the mesh; its consumed side
116
+ // is published as-is (consumed is inherently per-repo).
117
+ const selfModel = await (0, gather_1.gatherFlowModel)({
118
+ roots: [cwd],
119
+ ...(opts.specs ? { specs: opts.specs.map((s) => path.resolve(cwd, s)) } : {}),
120
+ ...(opts.stripUrlPrefixes ? { stripUrlPrefixes: [...opts.stripUrlPrefixes] } : {}),
121
+ relativeTo: cwd,
122
+ });
123
+ const selfServed = (0, contract_1.buildServedContract)(selfModel, baseMeta);
124
+ const consumed = (0, contract_1.buildConsumedContract)(selfModel, baseMeta);
125
+ const allRoutes = [...selfServed.routes];
126
+ const participants = [];
127
+ for (const p of (0, workspace_1.readWorkspace)(cwd)?.participants ?? []) {
128
+ const { routes, source } = await gatherParticipant(cwd, p, opts);
129
+ participants.push({ name: p.name, routes: routes.length, source });
130
+ allRoutes.push(...routes);
131
+ }
132
+ const mesh = dedupeServed(allRoutes);
133
+ const contentHash = (0, contract_1.servedContentHash)(mesh);
134
+ const servedContract = { side: 'served', ...baseMeta, contentHash, routes: mesh };
135
+ const servedPath = (0, contract_1.writeServedContract)(cwd, servedContract);
136
+ const consumedPath = (0, contract_1.writeConsumedContract)(cwd, consumed);
137
+ return {
138
+ servedPath,
139
+ consumedPath,
140
+ participants,
141
+ totalServedRoutes: mesh.length,
142
+ consumedBindings: consumed.bindings.length,
143
+ contentHash,
144
+ };
145
+ }
146
+ //# sourceMappingURL=publish.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publish.js","sourceRoot":"","sources":["../../../src/analyzers/flow/publish.ts"],"names":[],"mappings":"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"}