@ttctl/core 0.0.0 → 0.1.0-rc.1

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 (195) hide show
  1. package/README.md +49 -9
  2. package/dist/__generated__/gateway.d.ts +4546 -0
  3. package/dist/__generated__/gateway.d.ts.map +1 -0
  4. package/dist/__generated__/gateway.js +9 -0
  5. package/dist/__generated__/gateway.js.map +1 -0
  6. package/dist/__generated__/talent-profile-zod-schemas.d.ts +1187 -0
  7. package/dist/__generated__/talent-profile-zod-schemas.d.ts.map +1 -0
  8. package/dist/__generated__/talent-profile-zod-schemas.js +1136 -0
  9. package/dist/__generated__/talent-profile-zod-schemas.js.map +1 -0
  10. package/dist/__generated__/talent-profile.d.ts +1397 -0
  11. package/dist/__generated__/talent-profile.d.ts.map +1 -0
  12. package/dist/__generated__/talent-profile.js +9 -0
  13. package/dist/__generated__/talent-profile.js.map +1 -0
  14. package/dist/__generated__/zod-schemas.d.ts +2895 -0
  15. package/dist/__generated__/zod-schemas.d.ts.map +1 -0
  16. package/dist/__generated__/zod-schemas.js +3121 -0
  17. package/dist/__generated__/zod-schemas.js.map +1 -0
  18. package/dist/__tests__/fixtures/profile/builders.d.ts +74 -0
  19. package/dist/__tests__/fixtures/profile/builders.d.ts.map +1 -0
  20. package/dist/__tests__/fixtures/profile/builders.js +196 -0
  21. package/dist/__tests__/fixtures/profile/builders.js.map +1 -0
  22. package/dist/__tests__/fixtures/profile/data.d.ts +39 -0
  23. package/dist/__tests__/fixtures/profile/data.d.ts.map +1 -0
  24. package/dist/__tests__/fixtures/profile/data.js +230 -0
  25. package/dist/__tests__/fixtures/profile/data.js.map +1 -0
  26. package/dist/__tests__/fixtures/profile/index.d.ts +9 -0
  27. package/dist/__tests__/fixtures/profile/index.d.ts.map +1 -0
  28. package/dist/__tests__/fixtures/profile/index.js +10 -0
  29. package/dist/__tests__/fixtures/profile/index.js.map +1 -0
  30. package/dist/__tests__/fixtures/profile/types.d.ts +53 -0
  31. package/dist/__tests__/fixtures/profile/types.d.ts.map +1 -0
  32. package/dist/__tests__/fixtures/profile/types.js +4 -0
  33. package/dist/__tests__/fixtures/profile/types.js.map +1 -0
  34. package/dist/auth/errors.d.ts +82 -0
  35. package/dist/auth/errors.d.ts.map +1 -0
  36. package/dist/auth/errors.js +68 -0
  37. package/dist/auth/errors.js.map +1 -0
  38. package/dist/auth.d.ts +192 -0
  39. package/dist/auth.d.ts.map +1 -0
  40. package/dist/auth.js +294 -0
  41. package/dist/auth.js.map +1 -0
  42. package/dist/config.d.ts +212 -0
  43. package/dist/config.d.ts.map +1 -0
  44. package/dist/config.js +349 -0
  45. package/dist/config.js.map +1 -0
  46. package/dist/configLock.d.ts +50 -0
  47. package/dist/configLock.d.ts.map +1 -0
  48. package/dist/configLock.js +88 -0
  49. package/dist/configLock.js.map +1 -0
  50. package/dist/configWriter.d.ts +97 -0
  51. package/dist/configWriter.d.ts.map +1 -0
  52. package/dist/configWriter.js +687 -0
  53. package/dist/configWriter.js.map +1 -0
  54. package/dist/index.d.ts +37 -0
  55. package/dist/index.d.ts.map +1 -0
  56. package/dist/index.js +28 -0
  57. package/dist/index.js.map +1 -0
  58. package/dist/kill-switch.d.ts +161 -0
  59. package/dist/kill-switch.d.ts.map +1 -0
  60. package/dist/kill-switch.js +235 -0
  61. package/dist/kill-switch.js.map +1 -0
  62. package/dist/lib/date.d.ts +58 -0
  63. package/dist/lib/date.d.ts.map +1 -0
  64. package/dist/lib/date.js +104 -0
  65. package/dist/lib/date.js.map +1 -0
  66. package/dist/lib/diagnostic-log.d.ts +159 -0
  67. package/dist/lib/diagnostic-log.d.ts.map +1 -0
  68. package/dist/lib/diagnostic-log.js +186 -0
  69. package/dist/lib/diagnostic-log.js.map +1 -0
  70. package/dist/lib/package-version.d.ts +19 -0
  71. package/dist/lib/package-version.d.ts.map +1 -0
  72. package/dist/lib/package-version.js +38 -0
  73. package/dist/lib/package-version.js.map +1 -0
  74. package/dist/lib/redact.d.ts +153 -0
  75. package/dist/lib/redact.d.ts.map +1 -0
  76. package/dist/lib/redact.js +207 -0
  77. package/dist/lib/redact.js.map +1 -0
  78. package/dist/lib/text.d.ts +14 -0
  79. package/dist/lib/text.d.ts.map +1 -0
  80. package/dist/lib/text.js +21 -0
  81. package/dist/lib/text.js.map +1 -0
  82. package/dist/lib/wire-shape.d.ts +131 -0
  83. package/dist/lib/wire-shape.d.ts.map +1 -0
  84. package/dist/lib/wire-shape.js +376 -0
  85. package/dist/lib/wire-shape.js.map +1 -0
  86. package/dist/onepassword.d.ts +29 -0
  87. package/dist/onepassword.d.ts.map +1 -0
  88. package/dist/onepassword.js +112 -0
  89. package/dist/onepassword.js.map +1 -0
  90. package/dist/services/_shared/transport.d.ts +148 -0
  91. package/dist/services/_shared/transport.d.ts.map +1 -0
  92. package/dist/services/_shared/transport.js +102 -0
  93. package/dist/services/_shared/transport.js.map +1 -0
  94. package/dist/services/applications/index.d.ts +210 -0
  95. package/dist/services/applications/index.d.ts.map +1 -0
  96. package/dist/services/applications/index.js +240 -0
  97. package/dist/services/applications/index.js.map +1 -0
  98. package/dist/services/availability/index.d.ts +254 -0
  99. package/dist/services/availability/index.d.ts.map +1 -0
  100. package/dist/services/availability/index.js +310 -0
  101. package/dist/services/availability/index.js.map +1 -0
  102. package/dist/services/contracts/index.d.ts +132 -0
  103. package/dist/services/contracts/index.d.ts.map +1 -0
  104. package/dist/services/contracts/index.js +211 -0
  105. package/dist/services/contracts/index.js.map +1 -0
  106. package/dist/services/engagements/index.d.ts +504 -0
  107. package/dist/services/engagements/index.d.ts.map +1 -0
  108. package/dist/services/engagements/index.js +613 -0
  109. package/dist/services/engagements/index.js.map +1 -0
  110. package/dist/services/jobs/index.d.ts +490 -0
  111. package/dist/services/jobs/index.d.ts.map +1 -0
  112. package/dist/services/jobs/index.js +753 -0
  113. package/dist/services/jobs/index.js.map +1 -0
  114. package/dist/services/payments/index.d.ts +415 -0
  115. package/dist/services/payments/index.d.ts.map +1 -0
  116. package/dist/services/payments/index.js +636 -0
  117. package/dist/services/payments/index.js.map +1 -0
  118. package/dist/services/profile/__tests__/fixtures.d.ts +214 -0
  119. package/dist/services/profile/__tests__/fixtures.d.ts.map +1 -0
  120. package/dist/services/profile/__tests__/fixtures.js +176 -0
  121. package/dist/services/profile/__tests__/fixtures.js.map +1 -0
  122. package/dist/services/profile/basic/index.d.ts +390 -0
  123. package/dist/services/profile/basic/index.d.ts.map +1 -0
  124. package/dist/services/profile/basic/index.js +1007 -0
  125. package/dist/services/profile/basic/index.js.map +1 -0
  126. package/dist/services/profile/certifications/index.d.ts +74 -0
  127. package/dist/services/profile/certifications/index.d.ts.map +1 -0
  128. package/dist/services/profile/certifications/index.js +169 -0
  129. package/dist/services/profile/certifications/index.js.map +1 -0
  130. package/dist/services/profile/education/index.d.ts +73 -0
  131. package/dist/services/profile/education/index.d.ts.map +1 -0
  132. package/dist/services/profile/education/index.js +168 -0
  133. package/dist/services/profile/education/index.js.map +1 -0
  134. package/dist/services/profile/employment/index.d.ts +111 -0
  135. package/dist/services/profile/employment/index.d.ts.map +1 -0
  136. package/dist/services/profile/employment/index.js +202 -0
  137. package/dist/services/profile/employment/index.js.map +1 -0
  138. package/dist/services/profile/external/index.d.ts +219 -0
  139. package/dist/services/profile/external/index.d.ts.map +1 -0
  140. package/dist/services/profile/external/index.js +560 -0
  141. package/dist/services/profile/external/index.js.map +1 -0
  142. package/dist/services/profile/index.d.ts +24 -0
  143. package/dist/services/profile/index.d.ts.map +1 -0
  144. package/dist/services/profile/index.js +26 -0
  145. package/dist/services/profile/index.js.map +1 -0
  146. package/dist/services/profile/industries/index.d.ts +130 -0
  147. package/dist/services/profile/industries/index.d.ts.map +1 -0
  148. package/dist/services/profile/industries/index.js +292 -0
  149. package/dist/services/profile/industries/index.js.map +1 -0
  150. package/dist/services/profile/portfolio/index.d.ts +352 -0
  151. package/dist/services/profile/portfolio/index.d.ts.map +1 -0
  152. package/dist/services/profile/portfolio/index.js +833 -0
  153. package/dist/services/profile/portfolio/index.js.map +1 -0
  154. package/dist/services/profile/resume/index.d.ts +60 -0
  155. package/dist/services/profile/resume/index.d.ts.map +1 -0
  156. package/dist/services/profile/resume/index.js +212 -0
  157. package/dist/services/profile/resume/index.js.map +1 -0
  158. package/dist/services/profile/reviews/index.d.ts +137 -0
  159. package/dist/services/profile/reviews/index.d.ts.map +1 -0
  160. package/dist/services/profile/reviews/index.js +431 -0
  161. package/dist/services/profile/reviews/index.js.map +1 -0
  162. package/dist/services/profile/shared.d.ts +127 -0
  163. package/dist/services/profile/shared.d.ts.map +1 -0
  164. package/dist/services/profile/shared.js +155 -0
  165. package/dist/services/profile/shared.js.map +1 -0
  166. package/dist/services/profile/skills/index.d.ts +212 -0
  167. package/dist/services/profile/skills/index.d.ts.map +1 -0
  168. package/dist/services/profile/skills/index.js +461 -0
  169. package/dist/services/profile/skills/index.js.map +1 -0
  170. package/dist/services/profile/visas/index.d.ts +74 -0
  171. package/dist/services/profile/visas/index.d.ts.map +1 -0
  172. package/dist/services/profile/visas/index.js +306 -0
  173. package/dist/services/profile/visas/index.js.map +1 -0
  174. package/dist/services/timesheet/index.d.ts +326 -0
  175. package/dist/services/timesheet/index.d.ts.map +1 -0
  176. package/dist/services/timesheet/index.js +324 -0
  177. package/dist/services/timesheet/index.js.map +1 -0
  178. package/dist/services/translations.d.ts +79 -0
  179. package/dist/services/translations.d.ts.map +1 -0
  180. package/dist/services/translations.js +136 -0
  181. package/dist/services/translations.js.map +1 -0
  182. package/dist/transport-resilience.d.ts +136 -0
  183. package/dist/transport-resilience.d.ts.map +1 -0
  184. package/dist/transport-resilience.js +247 -0
  185. package/dist/transport-resilience.js.map +1 -0
  186. package/dist/transport.d.ts +408 -0
  187. package/dist/transport.d.ts.map +1 -0
  188. package/dist/transport.js +691 -0
  189. package/dist/transport.js.map +1 -0
  190. package/dist/types.d.ts +41 -0
  191. package/dist/types.d.ts.map +1 -0
  192. package/dist/types.js +18 -0
  193. package/dist/types.js.map +1 -0
  194. package/package.json +40 -12
  195. package/index.js +0 -7
@@ -0,0 +1,376 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-only
2
+ // Copyright (C) 2026 Oleksii PELYKH
3
+ /**
4
+ * Maximum rendered length of a {@link WireShapeDiffEntry.value} field
5
+ * (per `docs/wire-validation-error-format.md` § Diff entries).
6
+ * Truncation appends `…` (a single ellipsis character, not three
7
+ * dots) to mark overflow.
8
+ */
9
+ export const MAX_VALUE_LENGTH = 32;
10
+ /**
11
+ * Verbatim hint string emitted alongside every `WIRE_SHAPE_ERROR`.
12
+ * Lifted into the CLI envelope's `hint` slot and the MCP error-text
13
+ * `Hint:` block; identical across all surfaces so an operator pattern-
14
+ * matches the message regardless of where it's encountered. The text
15
+ * comes directly from `docs/wire-validation-error-format.md` § Code +
16
+ * base fields (M2 / #281).
17
+ */
18
+ export const WIRE_SHAPE_HINT = "wire shape doesn't match expected — this typically means Toptal changed the API; please file an issue at https://github.com/alexey-pelykh/ttctl/issues with the operation name and timestamp.";
19
+ /**
20
+ * Walk a JSON path against a wire snapshot, returning the value at
21
+ * that path or {@link MISSING} when any segment doesn't resolve. The
22
+ * sentinel is distinct from `undefined` so callers can distinguish
23
+ * "value is undefined on the wire" (data present, field absent) from
24
+ * "path doesn't resolve" (entire branch missing or wireData omitted).
25
+ */
26
+ const MISSING = Symbol("wire-shape:missing");
27
+ function walkPath(wireData, path) {
28
+ let current = wireData;
29
+ for (const segment of path) {
30
+ if (current === null || current === undefined)
31
+ return MISSING;
32
+ if (typeof segment === "number") {
33
+ if (!Array.isArray(current))
34
+ return MISSING;
35
+ if (segment < 0 || segment >= current.length)
36
+ return MISSING;
37
+ current = current[segment];
38
+ }
39
+ else if (typeof segment === "string") {
40
+ if (typeof current !== "object" || Array.isArray(current))
41
+ return MISSING;
42
+ const key = segment;
43
+ const obj = current;
44
+ if (!(key in obj))
45
+ return MISSING;
46
+ current = obj[key];
47
+ }
48
+ else {
49
+ // Symbol — Zod permits in record/map keys though wire payloads
50
+ // never carry symbol keys. Fail closed: cannot walk a symbol
51
+ // path against a JSON wire snapshot.
52
+ return MISSING;
53
+ }
54
+ }
55
+ return current;
56
+ }
57
+ /**
58
+ * Render an unknown value into a short type tag for the `expected` /
59
+ * `actual` slots of a {@link WireShapeDiffEntry}. Pre-`typeof` array
60
+ * branch keeps `[]` from rendering as `"object"`.
61
+ */
62
+ function typeNameOf(value) {
63
+ if (value === null)
64
+ return "null";
65
+ if (Array.isArray(value))
66
+ return "array";
67
+ return typeof value;
68
+ }
69
+ /**
70
+ * Render an unknown wire value into a string for the
71
+ * {@link WireShapeDiffEntry.value} slot. Strings round-trip verbatim
72
+ * (no surrounding quotes — the pretty renderer adds them); primitives
73
+ * use `String(value)`; arrays/objects use `JSON.stringify`. Output is
74
+ * truncated to {@link MAX_VALUE_LENGTH} characters with `…` on
75
+ * overflow.
76
+ */
77
+ function renderValue(value) {
78
+ let rendered;
79
+ if (typeof value === "string") {
80
+ rendered = value;
81
+ }
82
+ else if (value === null || value === undefined || typeof value === "boolean" || typeof value === "number") {
83
+ rendered = String(value);
84
+ }
85
+ else if (typeof value === "bigint") {
86
+ rendered = `${value.toString()}n`;
87
+ }
88
+ else {
89
+ try {
90
+ rendered = JSON.stringify(value);
91
+ }
92
+ catch {
93
+ rendered = "[unstringifiable]";
94
+ }
95
+ }
96
+ if (rendered.length <= MAX_VALUE_LENGTH)
97
+ return rendered;
98
+ return `${rendered.slice(0, MAX_VALUE_LENGTH - 1)}…`;
99
+ }
100
+ /**
101
+ * Format a Zod issue path (array of `PropertyKey` segments) into the
102
+ * JSON path syntax required by {@link WireShapeDiffEntry.path}.
103
+ * Numeric segments fold into the preceding key as bracket-notation
104
+ * indices (`["records", 0, "duration"]` → `"records[0].duration"`).
105
+ *
106
+ * The empty-path case (top-level / refinement errors) returns the
107
+ * empty string. Callers handle prepending a base path when applicable
108
+ * (used by the `unrecognized_keys` branch in {@link issueToDiffEntries}).
109
+ */
110
+ function formatJsonPath(path) {
111
+ if (path.length === 0)
112
+ return "";
113
+ const parts = [];
114
+ for (const segment of path) {
115
+ if (typeof segment === "number") {
116
+ const head = parts.length === 0 ? "" : (parts[parts.length - 1] ?? "");
117
+ const next = `${head}[${segment.toString()}]`;
118
+ if (parts.length === 0) {
119
+ parts.push(next);
120
+ }
121
+ else {
122
+ parts[parts.length - 1] = next;
123
+ }
124
+ }
125
+ else if (typeof segment === "string") {
126
+ parts.push(segment);
127
+ }
128
+ else {
129
+ // Symbol — Zod allows it in record/map keys though wire payloads
130
+ // never carry symbol keys. Render via .toString() so the message
131
+ // is still readable rather than dropping the segment.
132
+ parts.push(segment.toString());
133
+ }
134
+ }
135
+ return parts.join(".");
136
+ }
137
+ /**
138
+ * Parse a path string back into segments for deterministic sorting.
139
+ * Numeric segments compare numerically (`[2]` before `[10]`); string
140
+ * segments compare lexicographically. The string `"records[0].duration"`
141
+ * decomposes into `["records", 0, "duration"]`.
142
+ */
143
+ function parsePathSegments(path) {
144
+ if (path.length === 0)
145
+ return [];
146
+ const segments = [];
147
+ for (const chunk of path.split(".")) {
148
+ const headEnd = chunk.indexOf("[");
149
+ const head = headEnd === -1 ? chunk : chunk.slice(0, headEnd);
150
+ if (head.length > 0)
151
+ segments.push(head);
152
+ const indexMatcher = /\[(\d+)\]/g;
153
+ let match;
154
+ while ((match = indexMatcher.exec(chunk)) !== null) {
155
+ segments.push(Number(match[1]));
156
+ }
157
+ }
158
+ return segments;
159
+ }
160
+ /**
161
+ * Compare two diff entries by `path` for deterministic ordering.
162
+ * Numeric path segments compare numerically (`records[2]` before
163
+ * `records[10]`); string segments compare lexicographically. When
164
+ * paths differ only in trailing segments, the shorter path sorts
165
+ * first. The result is byte-identical output across runs — essential
166
+ * for snapshot tests and human pattern-matching of repeat failures
167
+ * across logs.
168
+ */
169
+ function compareDiffEntries(a, b) {
170
+ const segA = parsePathSegments(a.path);
171
+ const segB = parsePathSegments(b.path);
172
+ const minLen = Math.min(segA.length, segB.length);
173
+ for (let i = 0; i < minLen; i++) {
174
+ const sa = segA[i];
175
+ const sb = segB[i];
176
+ if (sa === undefined || sb === undefined)
177
+ break;
178
+ if (typeof sa === "number" && typeof sb === "number") {
179
+ if (sa !== sb)
180
+ return sa - sb;
181
+ }
182
+ else {
183
+ const saStr = String(sa);
184
+ const sbStr = String(sb);
185
+ if (saStr !== sbStr)
186
+ return saStr < sbStr ? -1 : 1;
187
+ }
188
+ }
189
+ if (segA.length !== segB.length)
190
+ return segA.length - segB.length;
191
+ // Paths equal — preserve insertion order via tie-break on the diff
192
+ // entry fields so the comparator is total (required by `Array.sort`
193
+ // contract for stable cross-engine output).
194
+ if (a.op !== b.op)
195
+ return a.op < b.op ? -1 : 1;
196
+ return 0;
197
+ }
198
+ /**
199
+ * Extract `received <type>` from a Zod v4 `invalid_type` message
200
+ * (`"Invalid input: expected number, received string"`). Returns the
201
+ * received-type string when present, or `null` when the message
202
+ * doesn't match the expected pattern (locale change, custom error
203
+ * map). Used as a fallback when the wire snapshot isn't available
204
+ * via {@link walkPath}.
205
+ */
206
+ function extractReceivedFromMessage(message) {
207
+ const m = /received\s+(\S+)/.exec(message);
208
+ return m ? (m[1] ?? null) : null;
209
+ }
210
+ /**
211
+ * Project a single Zod issue into one or more {@link WireShapeDiffEntry}
212
+ * rows. The mapping is per `docs/wire-validation-error-format.md` §
213
+ * Diff entries:
214
+ *
215
+ * - `invalid_type` where the wire value at the issue path is
216
+ * `undefined` (or unresolvable) → `-` (schema-required field
217
+ * missing on wire). `value` omitted.
218
+ * - `invalid_type` otherwise → `~` (type mismatch). `value` is the
219
+ * raw wire value (extracted from the snapshot), truncated.
220
+ * - `unrecognized_keys` (strict-mode objects) → one `+` entry per
221
+ * unknown key. `value` omitted (Zod surfaces the key list but not
222
+ * each key's value).
223
+ * - `invalid_value`, `invalid_union`, and other codes → `~` with
224
+ * wire snapshot-derived `actual` / `value`.
225
+ *
226
+ * Fallback for unrecognized codes is `~` rather than skipping the
227
+ * issue — a future Zod release adding a new issue code shouldn't drop
228
+ * the diagnostic.
229
+ */
230
+ function issueToDiffEntries(issue, wireData) {
231
+ const basePath = formatJsonPath(issue.path);
232
+ if (issue.code === "unrecognized_keys") {
233
+ return issue.keys.map((key) => ({
234
+ op: "+",
235
+ path: basePath.length === 0 ? key : `${basePath}.${key}`,
236
+ expected: "<unset>",
237
+ actual: "unknown",
238
+ }));
239
+ }
240
+ const resolved = walkPath(wireData, issue.path);
241
+ if (issue.code === "invalid_type") {
242
+ // Field absent on wire OR resolved value is undefined → "-".
243
+ if (resolved === MISSING || resolved === undefined) {
244
+ const actualFromMessage = extractReceivedFromMessage(issue.message);
245
+ return [
246
+ {
247
+ op: "-",
248
+ path: basePath,
249
+ expected: issue.expected,
250
+ actual: actualFromMessage ?? "undefined",
251
+ },
252
+ ];
253
+ }
254
+ return [
255
+ {
256
+ op: "~",
257
+ path: basePath,
258
+ expected: issue.expected,
259
+ actual: typeNameOf(resolved),
260
+ value: renderValue(resolved),
261
+ },
262
+ ];
263
+ }
264
+ if (issue.code === "invalid_value") {
265
+ const expected = issue.values.length === 1 ? renderValue(issue.values[0]) : issue.values.map((v) => renderValue(v)).join(" | ");
266
+ if (resolved === MISSING) {
267
+ return [
268
+ {
269
+ op: "~",
270
+ path: basePath,
271
+ expected,
272
+ actual: "unknown",
273
+ },
274
+ ];
275
+ }
276
+ return [
277
+ {
278
+ op: "~",
279
+ path: basePath,
280
+ expected,
281
+ actual: typeNameOf(resolved),
282
+ value: renderValue(resolved),
283
+ },
284
+ ];
285
+ }
286
+ // invalid_union, invalid_format, too_big, too_small, custom, …
287
+ // Fall back to a structural diff entry. `actual` reflects the wire
288
+ // shape when resolvable; `expected` lifts the issue message so the
289
+ // operator sees the constraint that failed.
290
+ if (resolved === MISSING) {
291
+ return [
292
+ {
293
+ op: "~",
294
+ path: basePath,
295
+ expected: issue.message,
296
+ actual: "unknown",
297
+ },
298
+ ];
299
+ }
300
+ return [
301
+ {
302
+ op: "~",
303
+ path: basePath,
304
+ expected: issue.message,
305
+ actual: typeNameOf(resolved),
306
+ value: renderValue(resolved),
307
+ },
308
+ ];
309
+ }
310
+ /**
311
+ * Build the field-level diff from a {@link z.ZodError}. Issues are
312
+ * projected per {@link issueToDiffEntries} and sorted deterministically
313
+ * per {@link compareDiffEntries} so two runs against the same drifted
314
+ * wire response produce byte-identical output (load-bearing for
315
+ * snapshot tests and CI grep-fu).
316
+ *
317
+ * `wireData` is the original `body.data` snapshot that failed
318
+ * validation — walking it against each issue's `path` recovers the
319
+ * actual wire value (Zod v4 strips `input` from public issues; see
320
+ * file header). Pass `undefined` only in tests / migration paths
321
+ * where the snapshot is unavailable; entries will degrade to path-
322
+ * only render in that case.
323
+ *
324
+ * Exported for unit tests; callers should prefer
325
+ * {@link buildWireShapeError} which composes the full payload.
326
+ */
327
+ export function projectZodErrorToDiff(error, wireData) {
328
+ const entries = [];
329
+ for (const issue of error.issues) {
330
+ entries.push(...issueToDiffEntries(issue, wireData));
331
+ }
332
+ entries.sort(compareDiffEntries);
333
+ return entries;
334
+ }
335
+ /**
336
+ * Compose the `message` line of a `WIRE_SHAPE_ERROR` per
337
+ * `docs/wire-validation-error-format.md` § Code + base fields. The
338
+ * pluralisation is wire-stable (`1 field issue` vs `2 field issues`)
339
+ * so snapshot tests don't need locale-aware matchers.
340
+ *
341
+ * Exported for unit tests; callers should prefer
342
+ * {@link buildWireShapeError} which composes the full payload.
343
+ */
344
+ export function buildWireShapeMessage(operationName, diffEntryCount) {
345
+ const noun = diffEntryCount === 1 ? "issue" : "issues";
346
+ return `Wire shape doesn't match expected schema for operation \`${operationName}\` (${diffEntryCount.toString()} field ${noun}).`;
347
+ }
348
+ /**
349
+ * Convert a {@link z.ZodError} from a failed `schema.parse(body.data)`
350
+ * call into the full {@link WireShapeErrorPayload}. The payload is
351
+ * stable across surfaces (CLI envelope, MCP error text) and round-
352
+ * trips through JSON without redaction (body.data never carries the
353
+ * bearer).
354
+ *
355
+ * Each service's `callGateway` / `callTalentProfile` helper wraps the
356
+ * payload's `message` into its own domain-error class with
357
+ * `code: "WIRE_SHAPE_ERROR"` and `cause: zodError`; the CLI / MCP
358
+ * layers reconstruct the diff from `cause` when rendering.
359
+ *
360
+ * Pass `wireData` (the original `body.data` snapshot) so the diff
361
+ * can recover actual wire values via path walk — Zod v4 strips the
362
+ * `input` field from public issues, so the snapshot is the only way
363
+ * to render `actual` / `value` for non-`unrecognized_keys` entries.
364
+ *
365
+ * Z-3 (#286) wires the mechanism; no production op has `schema`
366
+ * passed in yet (Z-4 / #288 ships the first beachhead).
367
+ */
368
+ export function buildWireShapeError(operationName, error, wireData) {
369
+ const diff = projectZodErrorToDiff(error, wireData);
370
+ return {
371
+ message: buildWireShapeMessage(operationName, diff.length),
372
+ hint: WIRE_SHAPE_HINT,
373
+ diff,
374
+ };
375
+ }
376
+ //# sourceMappingURL=wire-shape.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wire-shape.js","sourceRoot":"","sources":["../../src/lib/wire-shape.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import type { Credentials } from "./types.js";
2
+ export declare class OnePasswordError extends Error {
3
+ readonly name = "OnePasswordError";
4
+ }
5
+ /**
6
+ * Resolve credentials from a 1Password item reference.
7
+ *
8
+ * Accepted forms:
9
+ * - `op://VAULT/ITEM` (2-segment) — `op` CLI uses its default account or
10
+ * `OP_ACCOUNT` env.
11
+ * - `op://ACCOUNT/VAULT/ITEM` (3-segment) — `--account ACCOUNT` is forwarded
12
+ * to `op item get` so users with multiple configured accounts can select
13
+ * one explicitly. ACCOUNT may be a UUID, shorthand, or sign-in email; `op`
14
+ * itself validates the value.
15
+ *
16
+ * Mechanism: shells out to `op item get ITEM --vault VAULT [--account ACCOUNT]
17
+ * --format json`, then matches credential fields by `purpose` (`USERNAME` /
18
+ * `PASSWORD`) — the canonical semantic identifier 1Password sets automatically
19
+ * for LOGIN-category items. The 1Password Desktop app brokers authentication
20
+ * (typically via biometric prompt) — no service-account token is required.
21
+ *
22
+ * Field-matching by `purpose` rather than `label` is necessary because
23
+ * browser-autosaved items inherit their `label` from the HTML form input name
24
+ * (e.g. `user[email]`, `user[password]`) — only `purpose` is canonical. The
25
+ * item must be a LOGIN-category item (any item with both USERNAME and PASSWORD
26
+ * purposes set).
27
+ */
28
+ export declare function resolveOnePasswordReference(ref: string): Credentials;
29
+ //# sourceMappingURL=onepassword.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"onepassword.d.ts","sourceRoot":"","sources":["../src/onepassword.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAgB9C,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,SAAkB,IAAI,sBAAsB;CAC7C;AA+BD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,CAqDpE"}
@@ -0,0 +1,112 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-only
2
+ // Copyright (C) 2026 Oleksii PELYKH
3
+ import { execFileSync } from "node:child_process";
4
+ import { z } from "zod";
5
+ /**
6
+ * Shape of `op item get --format json` output (subset; only fields we use).
7
+ */
8
+ const OpItemSchema = z.object({
9
+ fields: z.array(z.object({
10
+ id: z.string().optional(),
11
+ label: z.string().optional(),
12
+ value: z.string().optional(),
13
+ purpose: z.string().optional(),
14
+ })),
15
+ });
16
+ export class OnePasswordError extends Error {
17
+ name = "OnePasswordError";
18
+ }
19
+ /**
20
+ * Parse `op://[ACCOUNT/]VAULT/ITEM` into its components. Returns `null` for any
21
+ * shape outside the 2- or 3-segment grammar (matches `OnePasswordItemRefSchema`
22
+ * in `config.ts`).
23
+ *
24
+ * Splitting on `/` after stripping the `op://` prefix avoids regex capture-group
25
+ * contortions and produces clear branching on segment count.
26
+ */
27
+ function parseReference(ref) {
28
+ if (!ref.startsWith("op://"))
29
+ return null;
30
+ const segments = ref.slice("op://".length).split("/");
31
+ if (segments.some((s) => s.length === 0))
32
+ return null;
33
+ if (segments.length === 2) {
34
+ const [vault, item] = segments;
35
+ return { vault, item };
36
+ }
37
+ if (segments.length === 3) {
38
+ const [account, vault, item] = segments;
39
+ return { account, vault, item };
40
+ }
41
+ return null;
42
+ }
43
+ /**
44
+ * Resolve credentials from a 1Password item reference.
45
+ *
46
+ * Accepted forms:
47
+ * - `op://VAULT/ITEM` (2-segment) — `op` CLI uses its default account or
48
+ * `OP_ACCOUNT` env.
49
+ * - `op://ACCOUNT/VAULT/ITEM` (3-segment) — `--account ACCOUNT` is forwarded
50
+ * to `op item get` so users with multiple configured accounts can select
51
+ * one explicitly. ACCOUNT may be a UUID, shorthand, or sign-in email; `op`
52
+ * itself validates the value.
53
+ *
54
+ * Mechanism: shells out to `op item get ITEM --vault VAULT [--account ACCOUNT]
55
+ * --format json`, then matches credential fields by `purpose` (`USERNAME` /
56
+ * `PASSWORD`) — the canonical semantic identifier 1Password sets automatically
57
+ * for LOGIN-category items. The 1Password Desktop app brokers authentication
58
+ * (typically via biometric prompt) — no service-account token is required.
59
+ *
60
+ * Field-matching by `purpose` rather than `label` is necessary because
61
+ * browser-autosaved items inherit their `label` from the HTML form input name
62
+ * (e.g. `user[email]`, `user[password]`) — only `purpose` is canonical. The
63
+ * item must be a LOGIN-category item (any item with both USERNAME and PASSWORD
64
+ * purposes set).
65
+ */
66
+ export function resolveOnePasswordReference(ref) {
67
+ const parsed = parseReference(ref);
68
+ if (!parsed) {
69
+ throw new OnePasswordError(`Invalid reference: ${ref}. Expected op://[account/]vault/item.`);
70
+ }
71
+ const { account, vault, item } = parsed;
72
+ const args = ["item", "get", item, "--vault", vault];
73
+ if (account !== undefined)
74
+ args.push("--account", account);
75
+ args.push("--format", "json");
76
+ let raw;
77
+ try {
78
+ raw = execFileSync("op", args, {
79
+ encoding: "utf8",
80
+ stdio: ["ignore", "pipe", "pipe"],
81
+ });
82
+ }
83
+ catch (err) {
84
+ const e = err;
85
+ if (e.code === "ENOENT") {
86
+ throw new OnePasswordError("1Password CLI (`op`) not found. Install: https://developer.1password.com/docs/cli/get-started/");
87
+ }
88
+ throw new OnePasswordError(`op item get failed: ${e.message}`);
89
+ }
90
+ let parsedJson;
91
+ try {
92
+ parsedJson = JSON.parse(raw);
93
+ }
94
+ catch (err) {
95
+ throw new OnePasswordError(`op returned non-JSON output: ${err.message}`);
96
+ }
97
+ // `op item get --format json` returns the full item object with a `fields`
98
+ // array. Older `op` CLI versions returned a bare fields array instead;
99
+ // normalize both shapes into the wrapped form before schema validation.
100
+ const normalized = Array.isArray(parsedJson) ? { fields: parsedJson } : parsedJson;
101
+ const result = OpItemSchema.safeParse(normalized);
102
+ if (!result.success) {
103
+ throw new OnePasswordError(`Unexpected op output shape: ${result.error.message}`);
104
+ }
105
+ const username = result.data.fields.find((f) => f.purpose === "USERNAME")?.value;
106
+ const password = result.data.fields.find((f) => f.purpose === "PASSWORD")?.value;
107
+ if (!username || !password) {
108
+ throw new OnePasswordError(`Item ${vault}/${item} must have fields with USERNAME and PASSWORD purposes (LOGIN-category items have these by default).`);
109
+ }
110
+ return { email: username, password };
111
+ }
112
+ //# sourceMappingURL=onepassword.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"onepassword.js","sourceRoot":"","sources":["../src/onepassword.ts"],"names":[],"mappings":"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"}