agent-nuvira 3.3.1 → 3.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.
Files changed (154) hide show
  1. package/README.md +5 -8
  2. package/dist/agents/agents/runner.d.ts +9 -0
  3. package/dist/agents/agents/runner.d.ts.map +1 -1
  4. package/dist/agents/agents/runner.js +34 -12
  5. package/dist/agents/agents/runner.js.map +1 -1
  6. package/dist/agents/agents/writer-tool-calling.d.ts.map +1 -1
  7. package/dist/agents/agents/writer-tool-calling.js +7 -2
  8. package/dist/agents/agents/writer-tool-calling.js.map +1 -1
  9. package/dist/agents/agents/writer.d.ts.map +1 -1
  10. package/dist/agents/agents/writer.js +7 -1
  11. package/dist/agents/agents/writer.js.map +1 -1
  12. package/dist/agents/artifact-verification.d.ts +102 -0
  13. package/dist/agents/artifact-verification.d.ts.map +1 -0
  14. package/dist/agents/artifact-verification.js +216 -0
  15. package/dist/agents/artifact-verification.js.map +1 -0
  16. package/dist/agents/checkpoint-store.d.ts +73 -0
  17. package/dist/agents/checkpoint-store.d.ts.map +1 -1
  18. package/dist/agents/checkpoint-store.js +161 -0
  19. package/dist/agents/checkpoint-store.js.map +1 -1
  20. package/dist/agents/credential-store.d.ts +120 -0
  21. package/dist/agents/credential-store.d.ts.map +1 -1
  22. package/dist/agents/credential-store.js +358 -19
  23. package/dist/agents/credential-store.js.map +1 -1
  24. package/dist/agents/orchestrator.d.ts +10 -1
  25. package/dist/agents/orchestrator.d.ts.map +1 -1
  26. package/dist/agents/orchestrator.js +234 -75
  27. package/dist/agents/orchestrator.js.map +1 -1
  28. package/dist/agents/phase-engine.d.ts +61 -0
  29. package/dist/agents/phase-engine.d.ts.map +1 -1
  30. package/dist/agents/phase-engine.js +68 -2
  31. package/dist/agents/phase-engine.js.map +1 -1
  32. package/dist/agents/prompt-assembly.d.ts +11 -0
  33. package/dist/agents/prompt-assembly.d.ts.map +1 -1
  34. package/dist/agents/prompt-assembly.js +17 -0
  35. package/dist/agents/prompt-assembly.js.map +1 -1
  36. package/dist/agents/release-preflight.d.ts +121 -0
  37. package/dist/agents/release-preflight.d.ts.map +1 -0
  38. package/dist/agents/release-preflight.js +259 -0
  39. package/dist/agents/release-preflight.js.map +1 -0
  40. package/dist/agents/release-runner.d.ts +157 -0
  41. package/dist/agents/release-runner.d.ts.map +1 -0
  42. package/dist/agents/release-runner.js +719 -0
  43. package/dist/agents/release-runner.js.map +1 -0
  44. package/dist/agents/step-handoff.d.ts +190 -0
  45. package/dist/agents/step-handoff.d.ts.map +1 -0
  46. package/dist/agents/step-handoff.js +443 -0
  47. package/dist/agents/step-handoff.js.map +1 -0
  48. package/dist/cli/benchmark.d.ts.map +1 -1
  49. package/dist/cli/benchmark.js +11 -4
  50. package/dist/cli/benchmark.js.map +1 -1
  51. package/dist/cli/chat.d.ts.map +1 -1
  52. package/dist/cli/chat.js +25 -4
  53. package/dist/cli/chat.js.map +1 -1
  54. package/dist/cli/cli-program.d.ts.map +1 -1
  55. package/dist/cli/cli-program.js +3 -0
  56. package/dist/cli/cli-program.js.map +1 -1
  57. package/dist/cli/credentials.d.ts +28 -0
  58. package/dist/cli/credentials.d.ts.map +1 -0
  59. package/dist/cli/credentials.js +213 -0
  60. package/dist/cli/credentials.js.map +1 -0
  61. package/dist/cli/failover-runner.d.ts.map +1 -1
  62. package/dist/cli/failover-runner.js +9 -3
  63. package/dist/cli/failover-runner.js.map +1 -1
  64. package/dist/cli/loop-executor.d.ts.map +1 -1
  65. package/dist/cli/loop-executor.js +74 -7
  66. package/dist/cli/loop-executor.js.map +1 -1
  67. package/dist/cli/nlu.d.ts.map +1 -1
  68. package/dist/cli/nlu.js +8 -2
  69. package/dist/cli/nlu.js.map +1 -1
  70. package/dist/cli/publish.d.ts +22 -0
  71. package/dist/cli/publish.d.ts.map +1 -1
  72. package/dist/cli/publish.js +109 -13
  73. package/dist/cli/publish.js.map +1 -1
  74. package/dist/config/live-credentials.d.ts +57 -0
  75. package/dist/config/live-credentials.d.ts.map +1 -0
  76. package/dist/config/live-credentials.js +126 -0
  77. package/dist/config/live-credentials.js.map +1 -0
  78. package/dist/config/paths.d.ts +18 -0
  79. package/dist/config/paths.d.ts.map +1 -1
  80. package/dist/config/paths.js +25 -0
  81. package/dist/config/paths.js.map +1 -1
  82. package/dist/federation/a2a-types.js +1 -1
  83. package/dist/federation/a2a-types.js.map +1 -1
  84. package/dist/inference/model-validator.d.ts +6 -1
  85. package/dist/inference/model-validator.d.ts.map +1 -1
  86. package/dist/inference/model-validator.js +7 -2
  87. package/dist/inference/model-validator.js.map +1 -1
  88. package/dist/inference/route-resolver.d.ts +116 -0
  89. package/dist/inference/route-resolver.d.ts.map +1 -0
  90. package/dist/inference/route-resolver.js +159 -0
  91. package/dist/inference/route-resolver.js.map +1 -0
  92. package/dist/learning/autonomy-policy.d.ts +18 -0
  93. package/dist/learning/autonomy-policy.d.ts.map +1 -1
  94. package/dist/learning/autonomy-policy.js +35 -0
  95. package/dist/learning/autonomy-policy.js.map +1 -1
  96. package/dist/learning/reasoning-trace.d.ts +1 -1
  97. package/dist/learning/reasoning-trace.d.ts.map +1 -1
  98. package/dist/learning/reasoning-trace.js +25 -1
  99. package/dist/learning/reasoning-trace.js.map +1 -1
  100. package/dist/learning/resilient-call.d.ts.map +1 -1
  101. package/dist/learning/resilient-call.js +29 -17
  102. package/dist/learning/resilient-call.js.map +1 -1
  103. package/dist/learning/skill-store.d.ts.map +1 -1
  104. package/dist/learning/skill-store.js +30 -9
  105. package/dist/learning/skill-store.js.map +1 -1
  106. package/dist/mcp/catalog.js +2 -3
  107. package/dist/mcp/catalog.js.map +1 -1
  108. package/dist/mcp/manager.d.ts.map +1 -1
  109. package/dist/mcp/manager.js +5 -3
  110. package/dist/mcp/manager.js.map +1 -1
  111. package/dist/skills/secret-capture.d.ts.map +1 -1
  112. package/dist/skills/secret-capture.js +9 -4
  113. package/dist/skills/secret-capture.js.map +1 -1
  114. package/dist/tools/credentials-tool.d.ts +24 -0
  115. package/dist/tools/credentials-tool.d.ts.map +1 -0
  116. package/dist/tools/credentials-tool.js +125 -0
  117. package/dist/tools/credentials-tool.js.map +1 -0
  118. package/dist/tools/git-tool.d.ts +25 -7
  119. package/dist/tools/git-tool.d.ts.map +1 -1
  120. package/dist/tools/git-tool.js +155 -15
  121. package/dist/tools/git-tool.js.map +1 -1
  122. package/dist/tools/loop-project-context.d.ts.map +1 -1
  123. package/dist/tools/loop-project-context.js +16 -0
  124. package/dist/tools/loop-project-context.js.map +1 -1
  125. package/dist/tools/loop-route-feed.d.ts +57 -0
  126. package/dist/tools/loop-route-feed.d.ts.map +1 -0
  127. package/dist/tools/loop-route-feed.js +101 -0
  128. package/dist/tools/loop-route-feed.js.map +1 -0
  129. package/dist/tools/pipeline-tool.d.ts.map +1 -1
  130. package/dist/tools/pipeline-tool.js +8 -2
  131. package/dist/tools/pipeline-tool.js.map +1 -1
  132. package/dist/tools/publish-tool.d.ts.map +1 -1
  133. package/dist/tools/publish-tool.js +76 -10
  134. package/dist/tools/publish-tool.js.map +1 -1
  135. package/dist/tools/registry.d.ts +21 -1
  136. package/dist/tools/registry.d.ts.map +1 -1
  137. package/dist/tools/registry.js +44 -6
  138. package/dist/tools/registry.js.map +1 -1
  139. package/dist/tools/run-terminal.d.ts +9 -0
  140. package/dist/tools/run-terminal.d.ts.map +1 -1
  141. package/dist/tools/run-terminal.js +80 -2
  142. package/dist/tools/run-terminal.js.map +1 -1
  143. package/dist/tools/tool-loop.d.ts +12 -5
  144. package/dist/tools/tool-loop.d.ts.map +1 -1
  145. package/dist/tools/tool-loop.js +148 -0
  146. package/dist/tools/tool-loop.js.map +1 -1
  147. package/dist/tools/toolsets.js +2 -2
  148. package/dist/tools/toolsets.js.map +1 -1
  149. package/dist/workflow/registry.js +1 -1
  150. package/dist/workflow/registry.js.map +1 -1
  151. package/package.json +5 -4
  152. package/src/web-dashboard/public/assets/{index-CjvoBhlz.js → index-CxDj7p6i.js} +2 -2
  153. package/src/web-dashboard/public/assets/{index-CjvoBhlz.js.map → index-CxDj7p6i.js.map} +1 -1
  154. package/src/web-dashboard/public/index.html +1 -1
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Artifact verification — does the work actually exist?
3
+ *
4
+ * WHY THIS EXISTS (the live NVDA-addon failure):
5
+ * A WhatsApp task asked for an NVDA add-on packaged to
6
+ * /Users/dheeraj/Documents/kuttaaddon/. Over 19 attempts the pipeline never
7
+ * once produced the deliverable, and every attempt was reported as a SUCCESS.
8
+ * The trail, in order:
9
+ *
10
+ * 1. `write_file` was refused — the target is outside the workspace — so the
11
+ * three planned files were never created.
12
+ * 2. The packaging step ran `zip -r kuttaaddon.nvda-addon manifest.ini
13
+ * installTasks.py globalPlugins/` against files that did not exist. zip
14
+ * printed `zip warning: name not matched: …` for every input and still
15
+ * **exited 0**, emitting a valid 22-byte EMPTY archive.
16
+ * 3. `runResult.success` was derived from the exit code, so the step counted
17
+ * as done and every task flipped to `completed` (5/5).
18
+ * 4. `deliverableAuthored: false` was written into the same checkpoint
19
+ * metadata — the truth was recorded next to the false completion and
20
+ * nothing acted on it.
21
+ * 5. `fileChanges` claimed `installTasks.py` was `created`. It does not exist.
22
+ * The existing expectedFiles guard accepted that CLAIM as proof, so the one
23
+ * check that could have caught the lie waived it.
24
+ *
25
+ * The contract this module enforces, in one line: **a step is not done because a
26
+ * command exited 0, and not because the agent said it wrote something — it is
27
+ * done because the artifact is on disk, and is not empty.**
28
+ *
29
+ * Deliberately deterministic and LLM-free: existence, size and archive entry
30
+ * counts are facts. Everything here is best-effort and must never throw — a
31
+ * verification failure reports, it does not crash a pipeline.
32
+ */
33
+ /**
34
+ * The outcome of checking a set of declared artifacts.
35
+ *
36
+ * `missing` and `empty` are kept apart on purpose: "you never wrote it" and "you
37
+ * wrote an empty one" are different bugs with different repairs, and the live
38
+ * failure was the second one (a 22-byte archive that exists and holds nothing).
39
+ */
40
+ export interface ArtifactCheck {
41
+ ok: boolean;
42
+ /** Declared paths that do not exist on disk. */
43
+ missing: string[];
44
+ /** Declared paths that exist but carry no content. */
45
+ empty: string[];
46
+ /** One line naming what is wrong, or undefined when ok. */
47
+ reason?: string;
48
+ }
49
+ /** Options for {@link verifyArtifacts}. */
50
+ export interface VerifyOptions {
51
+ /**
52
+ * Files that are legitimately empty (touch-style markers). The add-on plan
53
+ * itself asked for "an empty installTasks.py", so treating every empty file
54
+ * as a failure would be wrong.
55
+ */
56
+ allowEmpty?: string[];
57
+ }
58
+ /** True when the path names a container format rather than a plain file. */
59
+ export declare function isArchivePath(path: string): boolean;
60
+ /**
61
+ * True when `file` is a zip that contains ZERO entries.
62
+ *
63
+ * This is the check that would have caught the live failure: an empty zip is a
64
+ * perfectly valid 22-byte file, so `existsSync` and a size check both pass it.
65
+ * The entry count lives in the End Of Central Directory record at the end of the
66
+ * file (the comment field can be up to 64KiB, so the record is searched from the
67
+ * tail rather than assumed to start at byte 0 of the trailer).
68
+ *
69
+ * Returns false for anything unreadable or not recognisably a zip — an
70
+ * unparseable archive is reported by the caller as unreadable, not as empty.
71
+ */
72
+ export declare function isEmptyArchive(file: string): boolean;
73
+ /** Resolve a declared path against the project root (absolute paths pass through). */
74
+ export declare function resolveArtifact(declared: string, root: string): string;
75
+ /**
76
+ * Verify that every declared path exists on disk, and that none of them is an
77
+ * empty shell.
78
+ *
79
+ * A declared path is satisfied ONLY by a real file. Callers must not pass in the
80
+ * agent's own report of what it wrote — that is exactly the substitution that
81
+ * let the live failure through, where `fileChanges` said a file had been created
82
+ * and the file did not exist.
83
+ */
84
+ export declare function verifyArtifacts(declared: string[], root: string, options?: VerifyOptions): ArtifactCheck;
85
+ /**
86
+ * Detect a command that finished successfully in the only sense the shell knows
87
+ * — exit code 0 — while provably doing nothing.
88
+ *
89
+ * Returns a human-readable reason (for the trace, the checkpoint and the user),
90
+ * or null when the command either genuinely ran or is not one we can judge.
91
+ *
92
+ * This exists because `zip` expresses "I matched none of your inputs" as a
93
+ * WARNING and still exits 0. Deriving success from the exit code therefore
94
+ * reports a fabricated deliverable as a finished one.
95
+ */
96
+ export declare function detectNoOpCommand(command: string, stdout: string, stderr: string): string | null;
97
+ /**
98
+ * Read a file's head for diagnostics, bounded. Never throws.
99
+ * Used to show what actually landed when a step's artifact is suspect.
100
+ */
101
+ export declare function peekFile(file: string, maxChars?: number): string;
102
+ //# sourceMappingURL=artifact-verification.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifact-verification.d.ts","sourceRoot":"","sources":["../../src/agents/artifact-verification.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAOH;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,OAAO,CAAC;IACZ,gDAAgD;IAChD,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,sDAAsD;IACtD,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,2DAA2D;IAC3D,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,2CAA2C;AAC3C,MAAM,WAAW,aAAa;IAC5B;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAaD,4EAA4E;AAC5E,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAGnD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CA8BpD;AAID,sFAAsF;AACtF,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAEtE;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,MAAM,EAAE,EAClB,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,aAAkB,GAC1B,aAAa,CAqCf;AAoCD;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,GACb,MAAM,GAAG,IAAI,CAQf;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,SAAM,GAAG,MAAM,CAM7D"}
@@ -0,0 +1,216 @@
1
+ /**
2
+ * Artifact verification — does the work actually exist?
3
+ *
4
+ * WHY THIS EXISTS (the live NVDA-addon failure):
5
+ * A WhatsApp task asked for an NVDA add-on packaged to
6
+ * /Users/dheeraj/Documents/kuttaaddon/. Over 19 attempts the pipeline never
7
+ * once produced the deliverable, and every attempt was reported as a SUCCESS.
8
+ * The trail, in order:
9
+ *
10
+ * 1. `write_file` was refused — the target is outside the workspace — so the
11
+ * three planned files were never created.
12
+ * 2. The packaging step ran `zip -r kuttaaddon.nvda-addon manifest.ini
13
+ * installTasks.py globalPlugins/` against files that did not exist. zip
14
+ * printed `zip warning: name not matched: …` for every input and still
15
+ * **exited 0**, emitting a valid 22-byte EMPTY archive.
16
+ * 3. `runResult.success` was derived from the exit code, so the step counted
17
+ * as done and every task flipped to `completed` (5/5).
18
+ * 4. `deliverableAuthored: false` was written into the same checkpoint
19
+ * metadata — the truth was recorded next to the false completion and
20
+ * nothing acted on it.
21
+ * 5. `fileChanges` claimed `installTasks.py` was `created`. It does not exist.
22
+ * The existing expectedFiles guard accepted that CLAIM as proof, so the one
23
+ * check that could have caught the lie waived it.
24
+ *
25
+ * The contract this module enforces, in one line: **a step is not done because a
26
+ * command exited 0, and not because the agent said it wrote something — it is
27
+ * done because the artifact is on disk, and is not empty.**
28
+ *
29
+ * Deliberately deterministic and LLM-free: existence, size and archive entry
30
+ * counts are facts. Everything here is best-effort and must never throw — a
31
+ * verification failure reports, it does not crash a pipeline.
32
+ */
33
+ import { closeSync, existsSync, openSync, readFileSync, readSync, statSync } from 'node:fs';
34
+ import { isAbsolute, resolve } from 'node:path';
35
+ // ─── Archive helpers ────────────────────────────────────────────────────────
36
+ /** Zip End Of Central Directory signature — `PK\x05\x06`. */
37
+ const ZIP_EOCD_SIGNATURE = 0x06054b50;
38
+ /** An EOCD record is 22 bytes; the comment field can push it further back. */
39
+ const ZIP_EOCD_MIN_SIZE = 22;
40
+ const ZIP_MAX_COMMENT = 0xffff;
41
+ /** Extensions whose whole purpose is to be a container of other files. */
42
+ const ARCHIVE_EXTENSIONS = ['.zip', '.nvda-addon', '.jar', '.whl', '.vsix', '.epub', '.xpi'];
43
+ /** True when the path names a container format rather than a plain file. */
44
+ export function isArchivePath(path) {
45
+ const lower = path.toLowerCase();
46
+ return ARCHIVE_EXTENSIONS.some((ext) => lower.endsWith(ext));
47
+ }
48
+ /**
49
+ * True when `file` is a zip that contains ZERO entries.
50
+ *
51
+ * This is the check that would have caught the live failure: an empty zip is a
52
+ * perfectly valid 22-byte file, so `existsSync` and a size check both pass it.
53
+ * The entry count lives in the End Of Central Directory record at the end of the
54
+ * file (the comment field can be up to 64KiB, so the record is searched from the
55
+ * tail rather than assumed to start at byte 0 of the trailer).
56
+ *
57
+ * Returns false for anything unreadable or not recognisably a zip — an
58
+ * unparseable archive is reported by the caller as unreadable, not as empty.
59
+ */
60
+ export function isEmptyArchive(file) {
61
+ let fd;
62
+ try {
63
+ const size = statSync(file).size;
64
+ // Smaller than an EOCD record cannot be a zip at all.
65
+ if (size < ZIP_EOCD_MIN_SIZE)
66
+ return false;
67
+ const readFrom = Math.max(0, size - ZIP_EOCD_MIN_SIZE - ZIP_MAX_COMMENT);
68
+ const length = size - readFrom;
69
+ const buffer = Buffer.alloc(length);
70
+ fd = openSync(file, 'r');
71
+ readSync(fd, buffer, 0, length, readFrom);
72
+ // Search backwards for the EOCD signature.
73
+ for (let i = buffer.length - ZIP_EOCD_MIN_SIZE; i >= 0; i -= 1) {
74
+ if (buffer.readUInt32LE(i) !== ZIP_EOCD_SIGNATURE)
75
+ continue;
76
+ // Offset 10 of the EOCD holds "total number of entries in the central
77
+ // directory" as a little-endian uint16.
78
+ return buffer.readUInt16LE(i + 10) === 0;
79
+ }
80
+ return false;
81
+ }
82
+ catch {
83
+ return false;
84
+ }
85
+ finally {
86
+ if (fd !== undefined) {
87
+ try {
88
+ closeSync(fd);
89
+ }
90
+ catch {
91
+ /* best-effort */
92
+ }
93
+ }
94
+ }
95
+ }
96
+ // ─── Artifact verification ──────────────────────────────────────────────────
97
+ /** Resolve a declared path against the project root (absolute paths pass through). */
98
+ export function resolveArtifact(declared, root) {
99
+ return isAbsolute(declared) ? declared : resolve(root, declared);
100
+ }
101
+ /**
102
+ * Verify that every declared path exists on disk, and that none of them is an
103
+ * empty shell.
104
+ *
105
+ * A declared path is satisfied ONLY by a real file. Callers must not pass in the
106
+ * agent's own report of what it wrote — that is exactly the substitution that
107
+ * let the live failure through, where `fileChanges` said a file had been created
108
+ * and the file did not exist.
109
+ */
110
+ export function verifyArtifacts(declared, root, options = {}) {
111
+ const allowEmpty = new Set((options.allowEmpty ?? []).map((p) => resolveArtifact(p, root)));
112
+ const missing = [];
113
+ const empty = [];
114
+ for (const path of declared) {
115
+ if (!path || !path.trim())
116
+ continue;
117
+ const abs = resolveArtifact(path, root);
118
+ try {
119
+ if (!existsSync(abs)) {
120
+ missing.push(path);
121
+ continue;
122
+ }
123
+ // A directory satisfies existence; only files can be empty shells.
124
+ const stat = statSync(abs);
125
+ if (stat.isDirectory())
126
+ continue;
127
+ if (stat.size === 0 && !allowEmpty.has(abs)) {
128
+ empty.push(path);
129
+ continue;
130
+ }
131
+ // The subtle case: non-zero size, but a container holding nothing.
132
+ if (isArchivePath(abs) && isEmptyArchive(abs)) {
133
+ empty.push(path);
134
+ }
135
+ }
136
+ catch {
137
+ // Unreadable is not the same as absent — report it as missing so the
138
+ // repair path is the same (re-do the step) rather than silently passing.
139
+ missing.push(path);
140
+ }
141
+ }
142
+ if (missing.length === 0 && empty.length === 0)
143
+ return { ok: true, missing, empty };
144
+ const parts = [];
145
+ if (missing.length)
146
+ parts.push(`not on disk: ${missing.join(', ')}`);
147
+ if (empty.length)
148
+ parts.push(`produced empty: ${empty.join(', ')}`);
149
+ return { ok: false, missing, empty, reason: parts.join(' | ') };
150
+ }
151
+ // ─── No-op command detection ────────────────────────────────────────────────
152
+ /**
153
+ * Tools whose entire job is to turn inputs into a container. Only these are
154
+ * considered for no-op detection, because "matched nothing" is unambiguously a
155
+ * failure for them.
156
+ */
157
+ const PRODUCER_TOOLS = ['zip', '7z', '7za', 'p7zip', 'tar', 'git'];
158
+ /**
159
+ * Output signatures that mean an archive/lookup command matched NOTHING while
160
+ * still exiting 0. Kept deliberately short and literal: a broad pattern like
161
+ * `/no such file/` would fail legitimate commands (a `grep` that finds nothing
162
+ * is not a broken build), so each entry here must be unambiguous on its own.
163
+ */
164
+ const NO_OP_SIGNATURES = [
165
+ // Info-ZIP's warning for an input that did not resolve. This is the exact line
166
+ // the live run produced, once per declared input, next to `exit code 0`.
167
+ { pattern: /zip warning: name not matched/i, what: 'zip matched none of its declared inputs' },
168
+ { pattern: /zip error: nothing to do/i, what: 'zip had nothing to add' },
169
+ { pattern: /nothing to commit|no changes added to commit/i, what: 'git found nothing to commit' },
170
+ { pattern: /nothing to do\b/i, what: 'the command had nothing to do' },
171
+ { pattern: /\b0 files? (?:added|archived|processed|packed)\b/i, what: 'the tool reported 0 files' },
172
+ ];
173
+ /** True when the command line invokes one of the producer tools. */
174
+ function invokesProducerTool(command) {
175
+ // First word of each shell segment, so `cd x && zip …` is recognised.
176
+ return command
177
+ .split(/\|\||&&|;|\|/)
178
+ .map((segment) => segment.trim().split(/\s+/)[0] ?? '')
179
+ .some((head) => PRODUCER_TOOLS.includes(head.replace(/^.*\//, '')));
180
+ }
181
+ /**
182
+ * Detect a command that finished successfully in the only sense the shell knows
183
+ * — exit code 0 — while provably doing nothing.
184
+ *
185
+ * Returns a human-readable reason (for the trace, the checkpoint and the user),
186
+ * or null when the command either genuinely ran or is not one we can judge.
187
+ *
188
+ * This exists because `zip` expresses "I matched none of your inputs" as a
189
+ * WARNING and still exits 0. Deriving success from the exit code therefore
190
+ * reports a fabricated deliverable as a finished one.
191
+ */
192
+ export function detectNoOpCommand(command, stdout, stderr) {
193
+ if (!command)
194
+ return null;
195
+ if (!invokesProducerTool(command))
196
+ return null;
197
+ const output = `${stdout}\n${stderr}`;
198
+ for (const { pattern, what } of NO_OP_SIGNATURES) {
199
+ if (pattern.test(output))
200
+ return what;
201
+ }
202
+ return null;
203
+ }
204
+ /**
205
+ * Read a file's head for diagnostics, bounded. Never throws.
206
+ * Used to show what actually landed when a step's artifact is suspect.
207
+ */
208
+ export function peekFile(file, maxChars = 200) {
209
+ try {
210
+ return readFileSync(file, 'utf-8').slice(0, maxChars);
211
+ }
212
+ catch {
213
+ return '';
214
+ }
215
+ }
216
+ //# sourceMappingURL=artifact-verification.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifact-verification.js","sourceRoot":"","sources":["../../src/agents/artifact-verification.ts"],"names":[],"mappings":"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"}
@@ -46,6 +46,79 @@ export declare function checkpointIdFor(goal: string, workingDirectory: string):
46
46
  export declare function saveCheckpoint(context: AgentContext, id?: string): string | null;
47
47
  /** Load a checkpoint by id (null if missing/corrupt). */
48
48
  export declare function loadCheckpoint(id: string): CheckpointFile | null;
49
+ /**
50
+ * The newest checkpoint for this project whose goal is the SAME ASK, possibly
51
+ * worded differently.
52
+ *
53
+ * `checkpointIdFor` hashes `workingDirectory + goal`, so a reworded ask hashes
54
+ * to a different id and finds nothing — which is why "do that addon thing"
55
+ * re-planned from zero while the previous attempt's plan sat on disk.
56
+ *
57
+ * The goal test is deliberately REQUIRED rather than taking the newest
58
+ * checkpoint in the directory. A bare "newest for this project" lookup would
59
+ * hand run B the plan of a completely unrelated run A that merely happened to
60
+ * use the same folder — and it would do so silently, which is worse than the
61
+ * re-plan it replaces. The caller reconciles whatever this returns against the
62
+ * filesystem before trusting a word of it (see `reconcileTaskPlan`).
63
+ *
64
+ * Newest-first among the matching goals, so the most recent attempt wins.
65
+ */
66
+ export declare function findRelatedCheckpointFor(workingDirectory: string, goal: string, options?: {
67
+ excludeId?: string;
68
+ }): CheckpointFile | null;
69
+ /**
70
+ * Are these two the same ask, worded differently?
71
+ *
72
+ * Both a floor and a ratio are required. The ratio alone passes two long goals
73
+ * that share a boilerplate opening; the floor alone passes two short goals that
74
+ * share one incidental noun. Together they mean "most of the shorter ask's
75
+ * subject matter appears in the other", which is what rewording looks like and
76
+ * what two unrelated asks in one folder do not.
77
+ *
78
+ * The floor is capped at the shorter goal's own token count, so a SHORT ask
79
+ * still matches its own rewording: "Package the add-on" and "package the addon
80
+ * for me" are two tokens each, and demanding three shared tokens would refuse
81
+ * the pair the rule exists for. At two tokens that means both must match — which
82
+ * is still enough to keep "update the readme" and "update the dockerfile"
83
+ * apart.
84
+ */
85
+ export declare function goalsLookSame(a: string, b: string): boolean;
86
+ /** The outcome of checking a saved plan against the filesystem. */
87
+ export interface PlanReconciliation {
88
+ /** The context with unverifiable completions demoted back to `pending`. */
89
+ context: AgentContext;
90
+ /** Steps that CLAIMED completion but whose artifacts are not on disk. */
91
+ demoted: Array<{
92
+ id: string;
93
+ reason: string;
94
+ }>;
95
+ }
96
+ /**
97
+ * Reconcile a saved task plan against what is actually on disk.
98
+ *
99
+ * WHY THIS EXISTS (the live NVDA-addon failure): the checkpoint for that goal
100
+ * said `5/5 tasks completed`, so "resume unless the user asks" looked correct —
101
+ * re-entering a finished plan would skip every task. But three of the five
102
+ * completions were false: the step claimed success, `zip` exited 0 on inputs
103
+ * that did not exist, and the packaged deliverable was a 22-byte empty archive.
104
+ * A checkpoint's statuses are therefore CLAIMS, and the only thing that makes
105
+ * them safe to skip is the artifact behind them.
106
+ *
107
+ * The rule, in one line: a completed step whose DECLARED files are not on disk
108
+ * (or are empty shells) is demoted to `pending`, so a resume re-runs exactly the
109
+ * work that is missing instead of skipping it.
110
+ *
111
+ * Deliberately narrow: only a step's explicit `expectedFiles` is checked. A
112
+ * description like "Delete legacy.js" would look like an unmet deliverable if we
113
+ * inferred artifacts from prose, so prose is never used to decide what re-runs —
114
+ * that stays the planner's declared contract. Steps with nothing declared are
115
+ * left exactly as they are rather than being demoted on a guess.
116
+ *
117
+ * Never throws: reconciliation failure reports, it does not break a resume.
118
+ */
119
+ export declare function reconcileTaskPlan(context: AgentContext, workingDirectory?: string): PlanReconciliation;
120
+ /** True when the plan still has work that can be run. */
121
+ export declare function planHasPendingWork(context: AgentContext): boolean;
49
122
  /** List all saved checkpoints, newest first (for `nuvira execute --checkpoint-list`). */
50
123
  export declare function listCheckpoints(): CheckpointMeta[];
51
124
  //# sourceMappingURL=checkpoint-store.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"checkpoint-store.d.ts","sourceRoot":"","sources":["../../src/agents/checkpoint-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAQH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAa/C,0DAA0D;AAC1D,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB,EAAE,MAAM,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,+EAA+E;AAC/E,MAAM,WAAW,cAAe,SAAQ,cAAc;IACpD,OAAO,EAAE,YAAY,CAAC;CACvB;AAID;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAM9E;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,YAAY,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAsBhF;AAED,yDAAyD;AACzD,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAUhE;AAED,yFAAyF;AACzF,wBAAgB,eAAe,IAAI,cAAc,EAAE,CA0BlD"}
1
+ {"version":3,"file":"checkpoint-store.d.ts","sourceRoot":"","sources":["../../src/agents/checkpoint-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAUH,OAAO,KAAK,EAAE,YAAY,EAAY,MAAM,YAAY,CAAC;AAazD,0DAA0D;AAC1D,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB,EAAE,MAAM,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,+EAA+E;AAC/E,MAAM,WAAW,cAAe,SAAQ,cAAc;IACpD,OAAO,EAAE,YAAY,CAAC;CACvB;AAID;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAM9E;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,YAAY,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAsBhF;AAED,yDAAyD;AACzD,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAUhE;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,wBAAwB,CACtC,gBAAgB,EAAE,MAAM,EACxB,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GACnC,cAAc,GAAG,IAAI,CAWvB;AA0CD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAS3D;AAED,mEAAmE;AACnE,MAAM,WAAW,kBAAkB;IACjC,2EAA2E;IAC3E,OAAO,EAAE,YAAY,CAAC;IACtB,yEAAyE;IACzE,OAAO,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAChD;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,YAAY,EACrB,gBAAgB,CAAC,EAAE,MAAM,GACxB,kBAAkB,CA8BpB;AAED,yDAAyD;AACzD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAEjE;AAED,yFAAyF;AACzF,wBAAgB,eAAe,IAAI,cAAc,EAAE,CA0BlD"}
@@ -19,6 +19,7 @@ import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from
19
19
  import { envBuff, resolveNuviraHome } from '../config/paths.js';
20
20
  import { join } from 'node:path';
21
21
  import { createHash } from 'node:crypto';
22
+ import { verifyArtifacts } from './artifact-verification.js';
22
23
  // ─── Storage ────────────────────────────────────────────────────────────────
23
24
  const DEFAULT_MEMORY_DIR = join(resolveNuviraHome(), 'memory');
24
25
  function checkpointsDir() {
@@ -86,6 +87,166 @@ export function loadCheckpoint(id) {
86
87
  return null;
87
88
  }
88
89
  }
90
+ /**
91
+ * The newest checkpoint for this project whose goal is the SAME ASK, possibly
92
+ * worded differently.
93
+ *
94
+ * `checkpointIdFor` hashes `workingDirectory + goal`, so a reworded ask hashes
95
+ * to a different id and finds nothing — which is why "do that addon thing"
96
+ * re-planned from zero while the previous attempt's plan sat on disk.
97
+ *
98
+ * The goal test is deliberately REQUIRED rather than taking the newest
99
+ * checkpoint in the directory. A bare "newest for this project" lookup would
100
+ * hand run B the plan of a completely unrelated run A that merely happened to
101
+ * use the same folder — and it would do so silently, which is worse than the
102
+ * re-plan it replaces. The caller reconciles whatever this returns against the
103
+ * filesystem before trusting a word of it (see `reconcileTaskPlan`).
104
+ *
105
+ * Newest-first among the matching goals, so the most recent attempt wins.
106
+ */
107
+ export function findRelatedCheckpointFor(workingDirectory, goal, options = {}) {
108
+ const wanted = normalizeDir(workingDirectory);
109
+ const candidates = listCheckpoints()
110
+ .filter((c) => normalizeDir(c.workingDirectory) === wanted && c.id !== options.excludeId)
111
+ .sort((a, b) => b.savedAt - a.savedAt);
112
+ for (const meta of candidates) {
113
+ if (!goalsLookSame(meta.goal, goal))
114
+ continue;
115
+ const file = loadCheckpoint(meta.id);
116
+ if (file)
117
+ return file;
118
+ }
119
+ return null;
120
+ }
121
+ /** Compare working directories without caring about a trailing slash. */
122
+ function normalizeDir(dir) {
123
+ return (dir || '').replace(/[\\/]+$/, '');
124
+ }
125
+ /** Words that carry no subject — dropped before comparing two goals. */
126
+ const GOAL_STOPWORDS = new Set([
127
+ 'the', 'a', 'an', 'and', 'or', 'but', 'to', 'of', 'in', 'on', 'at', 'for', 'with', 'from',
128
+ 'can', 'could', 'would', 'should', 'please', 'you', 'your', 'me', 'my', 'i', 'we', 'it', 'its',
129
+ 'is', 'are', 'was', 'be', 'been', 'do', 'does', 'did', 'make', 'made', 'need', 'want', 'get',
130
+ 'this', 'that', 'these', 'those', 'there', 'here', 'then', 'than', 'so', 'as', 'by', 'use',
131
+ 'using', 'into', 'out', 'up', 'down', 'again', 'also', 'just', 'new', 'now', 'save',
132
+ 'folder', 'file', 'path', 'directory', 'dir', 'create', 'build', 'develop', 'write',
133
+ ]);
134
+ /**
135
+ * Subject tokens of a goal. Hyphens and underscores are JOINED, not split, so
136
+ * "add-on" and "addon" are the same token — the exact pair a user is most
137
+ * likely to vary when re-asking.
138
+ */
139
+ function goalTokens(text) {
140
+ const flat = (text || '')
141
+ .toLowerCase()
142
+ .replace(/[-_]+/g, '')
143
+ .replace(/[^a-z0-9]+/g, ' ');
144
+ const tokens = new Set();
145
+ for (const raw of flat.split(' ')) {
146
+ const t = raw.trim();
147
+ if (!t || t.length < 3)
148
+ continue;
149
+ if (GOAL_STOPWORDS.has(t))
150
+ continue;
151
+ tokens.add(t);
152
+ }
153
+ return tokens;
154
+ }
155
+ /** Shared subject tokens needed before two goals are treated as the same ask. */
156
+ const MIN_SHARED_TOKENS = 3;
157
+ /** Fraction of the SHORTER goal's tokens that must be shared. */
158
+ const MIN_SHARED_RATIO = 0.6;
159
+ /**
160
+ * Are these two the same ask, worded differently?
161
+ *
162
+ * Both a floor and a ratio are required. The ratio alone passes two long goals
163
+ * that share a boilerplate opening; the floor alone passes two short goals that
164
+ * share one incidental noun. Together they mean "most of the shorter ask's
165
+ * subject matter appears in the other", which is what rewording looks like and
166
+ * what two unrelated asks in one folder do not.
167
+ *
168
+ * The floor is capped at the shorter goal's own token count, so a SHORT ask
169
+ * still matches its own rewording: "Package the add-on" and "package the addon
170
+ * for me" are two tokens each, and demanding three shared tokens would refuse
171
+ * the pair the rule exists for. At two tokens that means both must match — which
172
+ * is still enough to keep "update the readme" and "update the dockerfile"
173
+ * apart.
174
+ */
175
+ export function goalsLookSame(a, b) {
176
+ const ta = goalTokens(a);
177
+ const tb = goalTokens(b);
178
+ if (ta.size === 0 || tb.size === 0)
179
+ return false;
180
+ let shared = 0;
181
+ for (const t of ta)
182
+ if (tb.has(t))
183
+ shared += 1;
184
+ const smaller = Math.min(ta.size, tb.size);
185
+ if (shared < Math.min(MIN_SHARED_TOKENS, smaller))
186
+ return false;
187
+ return shared / smaller >= MIN_SHARED_RATIO;
188
+ }
189
+ /**
190
+ * Reconcile a saved task plan against what is actually on disk.
191
+ *
192
+ * WHY THIS EXISTS (the live NVDA-addon failure): the checkpoint for that goal
193
+ * said `5/5 tasks completed`, so "resume unless the user asks" looked correct —
194
+ * re-entering a finished plan would skip every task. But three of the five
195
+ * completions were false: the step claimed success, `zip` exited 0 on inputs
196
+ * that did not exist, and the packaged deliverable was a 22-byte empty archive.
197
+ * A checkpoint's statuses are therefore CLAIMS, and the only thing that makes
198
+ * them safe to skip is the artifact behind them.
199
+ *
200
+ * The rule, in one line: a completed step whose DECLARED files are not on disk
201
+ * (or are empty shells) is demoted to `pending`, so a resume re-runs exactly the
202
+ * work that is missing instead of skipping it.
203
+ *
204
+ * Deliberately narrow: only a step's explicit `expectedFiles` is checked. A
205
+ * description like "Delete legacy.js" would look like an unmet deliverable if we
206
+ * inferred artifacts from prose, so prose is never used to decide what re-runs —
207
+ * that stays the planner's declared contract. Steps with nothing declared are
208
+ * left exactly as they are rather than being demoted on a guess.
209
+ *
210
+ * Never throws: reconciliation failure reports, it does not break a resume.
211
+ */
212
+ export function reconcileTaskPlan(context, workingDirectory) {
213
+ const demoted = [];
214
+ let plan;
215
+ try {
216
+ plan = structuredClone(context.taskPlan ?? []);
217
+ }
218
+ catch {
219
+ // An unclonable plan is not a verdict — hand it back untouched.
220
+ return { context, demoted };
221
+ }
222
+ const root = workingDirectory || context.workingDirectory || process.cwd();
223
+ for (const step of plan) {
224
+ if (step.status !== 'completed')
225
+ continue;
226
+ const declared = (step.expectedFiles ?? []).filter((f) => f && f.trim());
227
+ if (declared.length === 0)
228
+ continue;
229
+ try {
230
+ const check = verifyArtifacts(declared, root);
231
+ if (check.ok)
232
+ continue;
233
+ step.status = 'pending';
234
+ step.result =
235
+ `re-opened on resume — the step reported success but its deliverable is not on disk (${check.reason})`;
236
+ demoted.push({ id: step.id, reason: check.reason ?? 'deliverable missing' });
237
+ }
238
+ catch {
239
+ // Best-effort: a filesystem error must not demote a step on a guess.
240
+ }
241
+ }
242
+ if (demoted.length === 0)
243
+ return { context, demoted };
244
+ return { context: { ...context, taskPlan: plan }, demoted };
245
+ }
246
+ /** True when the plan still has work that can be run. */
247
+ export function planHasPendingWork(context) {
248
+ return (context.taskPlan ?? []).some((s) => s.status === 'pending');
249
+ }
89
250
  /** List all saved checkpoints, newest first (for `nuvira execute --checkpoint-list`). */
90
251
  export function listCheckpoints() {
91
252
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"checkpoint-store.js","sourceRoot":"","sources":["../../src/agents/checkpoint-store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"checkpoint-store.js","sourceRoot":"","sources":["../../src/agents/checkpoint-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC1F,OAAO,EAAC,OAAO,EAAE,iBAAiB,EAAC,MAAM,iBAAiB,CAAC;AAC3D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAI7D,+EAA+E;AAE/E,MAAM,kBAAkB,GAAG,IAAI,CAAC,iBAAiB,EAAE,EAAE,QAAQ,CAAC,CAAC;AAE/D,SAAS,cAAc;IACrB,MAAM,IAAI,GAAG,OAAO,CAAC,YAAY,CAAC,IAAI,kBAAkB,CAAC;IACzD,OAAO,IAAI,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;AACnC,CAAC;AAmBD,+EAA+E;AAE/E;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,gBAAwB;IACpE,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC;SAC5B,MAAM,CAAC,GAAG,gBAAgB,SAAS,IAAI,EAAE,CAAC;SAC1C,MAAM,CAAC,KAAK,CAAC;SACb,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAChB,OAAO,MAAM,IAAI,EAAE,CAAC;AACtB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAAC,OAAqB,EAAE,EAAW;IAC/D,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,cAAc,EAAE,CAAC;QAC7B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1D,MAAM,GAAG,GAAG,EAAE,IAAI,eAAe,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAC;QAC1E,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC;QACrC,MAAM,IAAI,GAAmB;YAC3B,EAAE,EAAE,GAAG;YACP,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,gBAAgB,EAAE,OAAO,CAAC,gBAAgB;YAC1C,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE;YACnB,cAAc,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,MAAM;YACpE,UAAU,EAAE,KAAK,CAAC,MAAM;YACxB,yEAAyE;YACzE,OAAO;SACR,CAAC;QACF,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;QAChF,OAAO,GAAG,CAAC;IACb,CAAC;IAAC,MAAM,CAAC;QACP,6DAA6D;QAC7D,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,yDAAyD;AACzD,MAAM,UAAU,cAAc,CAAC,EAAU;IACvC,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,CAAC,cAAc,EAAE,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;QAClD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QACnC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAmB,CAAC;QACvE,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC;QACpE,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,wBAAwB,CACtC,gBAAwB,EACxB,IAAY,EACZ,UAAkC,EAAE;IAEpC,MAAM,MAAM,GAAG,YAAY,CAAC,gBAAgB,CAAC,CAAC;IAC9C,MAAM,UAAU,GAAG,eAAe,EAAE;SACjC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,gBAAgB,CAAC,KAAK,MAAM,IAAI,CAAC,CAAC,EAAE,KAAK,OAAO,CAAC,SAAS,CAAC;SACxF,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC;IACzC,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;QAC9B,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC;YAAE,SAAS;QAC9C,MAAM,IAAI,GAAG,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACrC,IAAI,IAAI;YAAE,OAAO,IAAI,CAAC;IACxB,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,yEAAyE;AACzE,SAAS,YAAY,CAAC,GAAW;IAC/B,OAAO,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;AAC5C,CAAC;AAED,wEAAwE;AACxE,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC;IAC7B,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM;IACzF,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK;IAC9F,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK;IAC5F,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK;IAC1F,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM;IACnF,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO;CACpF,CAAC,CAAC;AAEH;;;;GAIG;AACH,SAAS,UAAU,CAAC,IAAY;IAC9B,MAAM,IAAI,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC;SACtB,WAAW,EAAE;SACb,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC;SACrB,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC;IAC/B,MAAM,MAAM,GAAG,IAAI,GAAG,EAAU,CAAC;IACjC,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QAClC,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;QACrB,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC;YAAE,SAAS;QACjC,IAAI,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC;YAAE,SAAS;QACpC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAChB,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,iFAAiF;AACjF,MAAM,iBAAiB,GAAG,CAAC,CAAC;AAC5B,iEAAiE;AACjE,MAAM,gBAAgB,GAAG,GAAG,CAAC;AAE7B;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,aAAa,CAAC,CAAS,EAAE,CAAS;IAChD,MAAM,EAAE,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;IACzB,MAAM,EAAE,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;IACzB,IAAI,EAAE,CAAC,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACjD,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,KAAK,MAAM,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;YAAE,MAAM,IAAI,CAAC,CAAC;IAC/C,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;IAC3C,IAAI,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,iBAAiB,EAAE,OAAO,CAAC;QAAE,OAAO,KAAK,CAAC;IAChE,OAAO,MAAM,GAAG,OAAO,IAAI,gBAAgB,CAAC;AAC9C,CAAC;AAUD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,iBAAiB,CAC/B,OAAqB,EACrB,gBAAyB;IAEzB,MAAM,OAAO,GAAkC,EAAE,CAAC;IAClD,IAAI,IAAgB,CAAC;IACrB,IAAI,CAAC;QACH,IAAI,GAAG,eAAe,CAAC,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;IACjD,CAAC;IAAC,MAAM,CAAC;QACP,gEAAgE;QAChE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;IAC9B,CAAC;IAED,MAAM,IAAI,GAAG,gBAAgB,IAAI,OAAO,CAAC,gBAAgB,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IAE3E,KAAK,MAAM,IAAI,IAAI,IAAI,EAAE,CAAC;QACxB,IAAI,IAAI,CAAC,MAAM,KAAK,WAAW;YAAE,SAAS;QAC1C,MAAM,QAAQ,GAAG,CAAC,IAAI,CAAC,aAAa,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QACzE,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;YAAE,SAAS;QACpC,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,eAAe,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;YAC9C,IAAI,KAAK,CAAC,EAAE;gBAAE,SAAS;YACvB,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC;YACxB,IAAI,CAAC,MAAM;gBACT,uFAAuF,KAAK,CAAC,MAAM,GAAG,CAAC;YACzG,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,qBAAqB,EAAE,CAAC,CAAC;QAC/E,CAAC;QAAC,MAAM,CAAC;YACP,qEAAqE;QACvE,CAAC;IACH,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;IACtD,OAAO,EAAE,OAAO,EAAE,EAAE,GAAG,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC;AAC9D,CAAC;AAED,yDAAyD;AACzD,MAAM,UAAU,kBAAkB,CAAC,OAAqB;IACtD,OAAO,CAAC,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC;AACtE,CAAC;AAED,yFAAyF;AACzF,MAAM,UAAU,eAAe;IAC7B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,cAAc,EAAE,CAAC;QAC7B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,OAAO,EAAE,CAAC;QAChC,OAAO,WAAW,CAAC,GAAG,CAAC;aACpB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;aAClC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YACT,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAmB,CAAC;gBAC/E,OAAO;oBACL,EAAE,EAAE,IAAI,CAAC,EAAE;oBACX,IAAI,EAAE,IAAI,CAAC,IAAI;oBACf,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;oBACvC,OAAO,EAAE,IAAI,CAAC,OAAO;oBACrB,cAAc,EAAE,IAAI,CAAC,cAAc;oBACnC,UAAU,EAAE,IAAI,CAAC,UAAU;iBACV,CAAC;YACtB,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC,CAAC;aACD,MAAM,CAAC,CAAC,CAAC,EAAuB,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC;aAC9C,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC;IAC3C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC"}