@wave-ai-os/wave-cli 0.1.87 → 0.1.88

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.
package/dist/index.js CHANGED
@@ -5,7 +5,226 @@ import { CommanderError, InvalidArgumentError } from "commander";
5
5
  import { ZodError } from "zod";
6
6
 
7
7
  // src/cli.ts
8
- import { Command } from "commander";
8
+ import { Command, Option as Option2 } from "commander";
9
+
10
+ // src/authStorage.ts
11
+ import { execFile } from "child_process";
12
+ import { constants, existsSync } from "fs";
13
+ import { access, mkdir, readFile, rm, stat, writeFile, chmod } from "fs/promises";
14
+ import { homedir } from "os";
15
+ import { dirname, join } from "path";
16
+ import { promisify } from "util";
17
+ var execFileAsync = promisify(execFile);
18
+ var KEYCHAIN_SERVICE = "wave-cli";
19
+ var FILE_NAME = "auth-token.json";
20
+ var DEFAULT_STORAGE_MODE = "auto";
21
+ var activeOptions = {};
22
+ function configureAuthStorage(options) {
23
+ activeOptions = { ...options };
24
+ }
25
+ async function withAuthStorageOptions(options, callback) {
26
+ const previous = activeOptions;
27
+ activeOptions = { ...options };
28
+ try {
29
+ return await callback();
30
+ } finally {
31
+ activeOptions = previous;
32
+ }
33
+ }
34
+ function normalize(raw) {
35
+ if (typeof raw !== "string") return void 0;
36
+ const trimmed = raw.trim();
37
+ return trimmed.length > 0 ? trimmed : void 0;
38
+ }
39
+ function authHome() {
40
+ return normalize(activeOptions.home) ?? join(homedir(), ".wave");
41
+ }
42
+ function tokenPath() {
43
+ return join(authHome(), FILE_NAME);
44
+ }
45
+ function configPath() {
46
+ return normalize(activeOptions.configPath) ?? join(authHome(), "config.json");
47
+ }
48
+ function storageMode() {
49
+ return activeOptions.mode ?? DEFAULT_STORAGE_MODE;
50
+ }
51
+ function accountForBaseUrl(baseUrl) {
52
+ return normalize(baseUrl) ?? "default";
53
+ }
54
+ async function commandExists(command) {
55
+ try {
56
+ await access(command, constants.X_OK);
57
+ return true;
58
+ } catch {
59
+ return false;
60
+ }
61
+ }
62
+ async function keychainAvailable() {
63
+ if (process.platform !== "darwin") return false;
64
+ if (storageMode() === "file" || storageMode() === "disabled") return false;
65
+ return commandExists("/usr/bin/security");
66
+ }
67
+ async function preferredStorage() {
68
+ const mode = storageMode();
69
+ if (mode === "disabled") return "disabled";
70
+ if (mode === "file") return "file";
71
+ if (mode === "keychain") return await keychainAvailable() ? "keychain" : "file";
72
+ return await keychainAvailable() ? "keychain" : "file";
73
+ }
74
+ async function readKeychainToken(baseUrl) {
75
+ try {
76
+ const { stdout } = await execFileAsync("/usr/bin/security", [
77
+ "find-generic-password",
78
+ "-a",
79
+ accountForBaseUrl(baseUrl),
80
+ "-s",
81
+ KEYCHAIN_SERVICE,
82
+ "-w"
83
+ ], { encoding: "utf8" });
84
+ return normalize(String(stdout)) ?? null;
85
+ } catch {
86
+ return null;
87
+ }
88
+ }
89
+ async function writeKeychainToken(token, baseUrl) {
90
+ await execFileAsync("/usr/bin/security", [
91
+ "add-generic-password",
92
+ "-a",
93
+ accountForBaseUrl(baseUrl),
94
+ "-s",
95
+ KEYCHAIN_SERVICE,
96
+ "-w",
97
+ token,
98
+ "-U"
99
+ ]);
100
+ }
101
+ async function deleteKeychainToken(baseUrl) {
102
+ try {
103
+ await execFileAsync("/usr/bin/security", [
104
+ "delete-generic-password",
105
+ "-a",
106
+ accountForBaseUrl(baseUrl),
107
+ "-s",
108
+ KEYCHAIN_SERVICE
109
+ ]);
110
+ return true;
111
+ } catch {
112
+ return false;
113
+ }
114
+ }
115
+ async function readFileToken(baseUrl) {
116
+ const path = tokenPath();
117
+ if (!existsSync(path)) return null;
118
+ try {
119
+ const raw = await readFile(path, "utf8");
120
+ const payload = JSON.parse(raw);
121
+ const token = normalize(payload.token);
122
+ const storedBaseUrl = normalize(payload.baseUrl);
123
+ const requestedBaseUrl = normalize(baseUrl);
124
+ if (!token) return null;
125
+ if (storedBaseUrl !== requestedBaseUrl) return null;
126
+ return token;
127
+ } catch {
128
+ return null;
129
+ }
130
+ }
131
+ async function writeFileToken(token, baseUrl) {
132
+ const home = authHome();
133
+ const path = tokenPath();
134
+ await mkdir(home, { recursive: true, mode: 448 });
135
+ await writeFile(
136
+ path,
137
+ `${JSON.stringify({ token, baseUrl: baseUrl ?? null, updatedAt: (/* @__PURE__ */ new Date()).toISOString() })}
138
+ `,
139
+ { mode: 384 }
140
+ );
141
+ await chmod(path, 384);
142
+ }
143
+ async function deleteFileToken() {
144
+ const path = tokenPath();
145
+ if (!existsSync(path)) return false;
146
+ await rm(path, { force: true });
147
+ return true;
148
+ }
149
+ async function readStoredToken(baseUrl) {
150
+ const mode = await preferredStorage();
151
+ if (mode === "disabled") return null;
152
+ if (mode === "keychain") {
153
+ const keychainToken = await readKeychainToken(baseUrl);
154
+ if (keychainToken) return { token: keychainToken, source: "keychain" };
155
+ }
156
+ const fileToken = await readFileToken(baseUrl);
157
+ return fileToken ? { token: fileToken, source: "file" } : null;
158
+ }
159
+ async function writeStoredToken(token, baseUrl) {
160
+ const mode = await preferredStorage();
161
+ if (mode === "disabled") {
162
+ return { kind: "disabled", available: false };
163
+ }
164
+ if (mode === "keychain") {
165
+ try {
166
+ await writeKeychainToken(token, baseUrl);
167
+ return {
168
+ kind: "keychain",
169
+ available: true,
170
+ service: KEYCHAIN_SERVICE,
171
+ account: accountForBaseUrl(baseUrl)
172
+ };
173
+ } catch {
174
+ await writeFileToken(token, baseUrl);
175
+ return { kind: "file", available: true, path: tokenPath() };
176
+ }
177
+ }
178
+ await writeFileToken(token, baseUrl);
179
+ return { kind: "file", available: true, path: tokenPath() };
180
+ }
181
+ async function persistBaseUrl(baseUrl) {
182
+ const path = configPath();
183
+ let existing = {};
184
+ if (existsSync(path)) {
185
+ const raw = await readFile(path, "utf8");
186
+ const parsed = JSON.parse(raw);
187
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
188
+ throw new Error(`Wave config file must contain a JSON object: ${path}`);
189
+ }
190
+ existing = parsed;
191
+ }
192
+ await mkdir(dirname(path), { recursive: true, mode: 448 });
193
+ await writeFile(path, `${JSON.stringify({ ...existing, baseUrl }, null, 2)}
194
+ `, {
195
+ mode: 384
196
+ });
197
+ await chmod(path, 384);
198
+ return path;
199
+ }
200
+ async function removeStoredToken(baseUrl) {
201
+ const removedKeychain = await deleteKeychainToken(baseUrl);
202
+ const removedFile = await deleteFileToken();
203
+ return removedKeychain || removedFile;
204
+ }
205
+ async function getAuthStorageInfo(baseUrl) {
206
+ const mode = await preferredStorage();
207
+ if (mode === "disabled") return { kind: "disabled", available: false };
208
+ if (mode === "keychain") {
209
+ return {
210
+ kind: "keychain",
211
+ available: true,
212
+ service: KEYCHAIN_SERVICE,
213
+ account: accountForBaseUrl(baseUrl)
214
+ };
215
+ }
216
+ const path = tokenPath();
217
+ let available = true;
218
+ if (existsSync(path)) {
219
+ try {
220
+ const modeBits = (await stat(path)).mode & 511;
221
+ available = modeBits === 384;
222
+ } catch {
223
+ available = false;
224
+ }
225
+ }
226
+ return { kind: "file", available, path };
227
+ }
9
228
 
10
229
  // src/commands/tasks.ts
11
230
  import { z as z3 } from "zod";
@@ -191,7 +410,7 @@ var ATLAS_LEDGER_VARIABLE_TYPES = {
191
410
  };
192
411
  var SECRET_KEY_PATTERN = /(authorization|password|passwd|secret|token|jwt|credential|api[_-]?key)/i;
193
412
  var MAX_EVIDENCE_DEPTH = 5;
194
- function normalize(raw) {
413
+ function normalize2(raw) {
195
414
  if (typeof raw !== "string") {
196
415
  return void 0;
197
416
  }
@@ -199,12 +418,12 @@ function normalize(raw) {
199
418
  return trimmed.length > 0 ? trimmed : void 0;
200
419
  }
201
420
  function atlasContextFromConfig(config) {
202
- const organizationId = normalize(config.organizationId);
203
- const memberId = normalize(config.atlasMemberId);
204
- const chatId = normalize(config.atlasChatId);
205
- const assistantMessageId = normalize(config.atlasAssistantMessageId);
206
- const activeTool = normalize(config.atlasActiveTool);
207
- const targetTool = normalize(config.atlasTargetTool);
421
+ const organizationId = normalize2(config.organizationId);
422
+ const memberId = normalize2(config.atlasMemberId);
423
+ const chatId = normalize2(config.atlasChatId);
424
+ const assistantMessageId = normalize2(config.atlasAssistantMessageId);
425
+ const activeTool = normalize2(config.atlasActiveTool);
426
+ const targetTool = normalize2(config.atlasTargetTool);
208
427
  if (!organizationId || !memberId || !chatId || !assistantMessageId || !activeTool || !targetTool) {
209
428
  return null;
210
429
  }
@@ -215,8 +434,8 @@ function atlasContextFromConfig(config) {
215
434
  assistantMessageId,
216
435
  activeTool,
217
436
  targetTool,
218
- routeReason: normalize(config.atlasRouteReason),
219
- actionId: normalize(config.atlasActionId)
437
+ routeReason: normalize2(config.atlasRouteReason),
438
+ actionId: normalize2(config.atlasActionId)
220
439
  };
221
440
  }
222
441
  function summarizeVariableShape(value, key = void 0, depth = 0) {
@@ -252,7 +471,7 @@ function shouldReportAtlasActionLedgerEvent(input) {
252
471
  return input.operationType === "mutation" && input.field !== ATLAS_LEDGER_FIELD;
253
472
  }
254
473
  function deterministicAtlasActionId(input, config) {
255
- const requestSegment = normalize(config.requestId) ? `:${config.requestId}` : "";
474
+ const requestSegment = normalize2(config.requestId) ? `:${config.requestId}` : "";
256
475
  return `cli:${input.command}:${input.field}${requestSegment}`;
257
476
  }
258
477
  function buildAtlasEvidenceRefs(params) {
@@ -583,118 +802,6 @@ function buildSparse422Diagnostic(input) {
583
802
  }
584
803
  };
585
804
  }
586
- function isFeedbackCreateCommand(input) {
587
- return input.operationType === "mutation" && input.command === "feedbacks.create";
588
- }
589
- function asRecord(value) {
590
- if (!value || typeof value !== "object" || Array.isArray(value)) {
591
- return null;
592
- }
593
- return value;
594
- }
595
- function asNonEmptyString(value) {
596
- if (typeof value !== "string") {
597
- return null;
598
- }
599
- const trimmed = value.trim();
600
- return trimmed.length > 0 ? trimmed : null;
601
- }
602
- function extractFeedbackIdentity(variables) {
603
- const organizationId = asNonEmptyString(variables.organization_id) ?? asNonEmptyString(variables.organizationId);
604
- const params = asRecord(variables.params);
605
- const feedback = params ? asRecord(params.feedback) : null;
606
- const name = feedback ? asNonEmptyString(feedback.name) : null;
607
- const quarter = feedback ? asNonEmptyString(feedback.quarter) : null;
608
- const year = feedback ? asNonEmptyString(feedback.year) : null;
609
- if (!organizationId || !name || !quarter || !year) {
610
- return null;
611
- }
612
- return {
613
- organizationId,
614
- name,
615
- quarter,
616
- year
617
- };
618
- }
619
- function collectMessageStrings(value) {
620
- if (typeof value === "string") {
621
- return [value];
622
- }
623
- if (Array.isArray(value)) {
624
- return value.flatMap((entry2) => collectMessageStrings(entry2));
625
- }
626
- if (!value || typeof value !== "object") {
627
- return [];
628
- }
629
- return Object.values(value).flatMap(
630
- (entry2) => collectMessageStrings(entry2)
631
- );
632
- }
633
- function isDuplicateFeedbackMutationError(mutationPayload) {
634
- const messages = collectMessageStrings(mutationPayload.errors);
635
- return messages.some(
636
- (message) => message.toLowerCase().includes("already been taken")
637
- );
638
- }
639
- function extractFeedbackListNode(graph) {
640
- const data = asRecord(graph.data);
641
- const feedbacks = data ? asRecord(data.feedbacks) : null;
642
- if (!feedbacks) {
643
- return null;
644
- }
645
- const rows = Array.isArray(feedbacks.data) ? feedbacks.data : [];
646
- const first = rows.find((entry2) => asRecord(entry2));
647
- return first ? first : null;
648
- }
649
- function buildFeedbackReuseEnvelope(params) {
650
- return {
651
- envelope: buildEnvelope({
652
- ok: true,
653
- command: params.command,
654
- status: params.status,
655
- data: {
656
- [params.field]: {
657
- ok: true,
658
- status: params.status,
659
- errorCode: null,
660
- data: {
661
- data: params.feedbackNode
662
- },
663
- errors: null,
664
- reusedExisting: true,
665
- idempotency: {
666
- reason: params.reason
667
- }
668
- }
669
- },
670
- error: null,
671
- requestId: params.requestId
672
- }),
673
- exitCode: EXIT_CODES.success
674
- };
675
- }
676
- function buildFeedbackFindRequestBody(command, identity) {
677
- return buildGraphqlBody({
678
- config: {
679
- baseUrl: "http://localhost",
680
- token: "placeholder",
681
- timeoutMs: 1e3,
682
- debug: false
683
- },
684
- command,
685
- operationType: "query",
686
- field: "feedbacks",
687
- variables: {
688
- organization_id: identity.organizationId,
689
- name: identity.name,
690
- quarter: identity.quarter,
691
- year: identity.year,
692
- page: 1,
693
- per: 1
694
- },
695
- selectionSet: "{ data { id type attributes { id name slug year quarter organizationId memberIds } } count currentPage totalPages }"
696
- });
697
- }
698
805
  async function requestGraphqlHttp(params) {
699
806
  const response = await fetch(params.url, {
700
807
  method: "POST",
@@ -786,29 +893,6 @@ async function finalizeGraphqlResult(input, url, result) {
786
893
  }
787
894
  return result;
788
895
  }
789
- async function findExistingFeedback(params) {
790
- const command = `${params.input.command}.find-existing`;
791
- const body = buildFeedbackFindRequestBody(command, params.identity);
792
- const http = await requestGraphqlHttp({
793
- input: params.input,
794
- url: params.url,
795
- requestId: params.requestId,
796
- body,
797
- controller: params.controller
798
- });
799
- const gqlErrors = http.graph.errors;
800
- if (Array.isArray(gqlErrors) && gqlErrors.length > 0) {
801
- return null;
802
- }
803
- const feedbackNode = extractFeedbackListNode(http.graph);
804
- if (!feedbackNode) {
805
- return null;
806
- }
807
- return {
808
- feedbackNode,
809
- requestId: http.requestId
810
- };
811
- }
812
896
  function graphqlTypeForValue(value) {
813
897
  if (Array.isArray(value)) {
814
898
  const firstNonNull = value.find((item) => item !== null && item !== void 0);
@@ -908,32 +992,6 @@ async function graphqlRequest(input) {
908
992
  const controller = new AbortController();
909
993
  const timeoutId = setTimeout(() => controller.abort(), input.config.timeoutMs);
910
994
  try {
911
- if (isFeedbackCreateCommand(input)) {
912
- const feedbackIdentity = extractFeedbackIdentity(input.variables);
913
- if (feedbackIdentity) {
914
- const existing = await findExistingFeedback({
915
- input,
916
- url,
917
- requestId,
918
- controller,
919
- identity: feedbackIdentity
920
- });
921
- if (existing) {
922
- return finalizeGraphqlResult(
923
- input,
924
- url,
925
- buildFeedbackReuseEnvelope({
926
- command: input.command,
927
- field: input.field,
928
- status: 200,
929
- requestId: existing.requestId,
930
- feedbackNode: existing.feedbackNode,
931
- reason: "preexisting"
932
- })
933
- );
934
- }
935
- }
936
- }
937
995
  const http = await requestGraphqlHttpWithRetry({
938
996
  input,
939
997
  url,
@@ -978,32 +1036,6 @@ async function graphqlRequest(input) {
978
1036
  const ok = Boolean(mutationPayload.ok);
979
1037
  const status = typeof mutationPayload.status === "number" ? mutationPayload.status : ok ? 200 : 400;
980
1038
  if (!ok) {
981
- if (isFeedbackCreateCommand(input) && isDuplicateFeedbackMutationError(mutationPayload)) {
982
- const feedbackIdentity = extractFeedbackIdentity(input.variables);
983
- if (feedbackIdentity) {
984
- const existing = await findExistingFeedback({
985
- input,
986
- url,
987
- requestId: responseRequestId,
988
- controller,
989
- identity: feedbackIdentity
990
- });
991
- if (existing) {
992
- return finalizeGraphqlResult(
993
- input,
994
- url,
995
- buildFeedbackReuseEnvelope({
996
- command: input.command,
997
- field: input.field,
998
- status: 200,
999
- requestId: existing.requestId,
1000
- feedbackNode: existing.feedbackNode,
1001
- reason: "duplicate_race"
1002
- })
1003
- );
1004
- }
1005
- }
1006
- }
1007
1039
  const mutationErrors = mutationPayload.errors ?? null;
1008
1040
  const details = {
1009
1041
  errors: mutationErrors,
@@ -1459,14 +1491,6 @@ var RESOURCE_QUERY_FIELDS = {
1459
1491
  "acceptedAnswerIds",
1460
1492
  "labelIds"
1461
1493
  ],
1462
- feedback: [
1463
- "name",
1464
- "slug",
1465
- "year",
1466
- "quarter",
1467
- "organizationId",
1468
- "memberIds"
1469
- ],
1470
1494
  survey: [
1471
1495
  "name",
1472
1496
  "slug",
@@ -1628,7 +1652,6 @@ var RESOURCE_FIELD_ALIASES = {
1628
1652
  stand_ups: "stand_up",
1629
1653
  headlines: "headline",
1630
1654
  questions: "question",
1631
- feedbacks: "feedback",
1632
1655
  surveys: "survey",
1633
1656
  responsibilities: "responsibility",
1634
1657
  smart_kpi_views: "smart_kpi_view",
@@ -1875,222 +1898,15 @@ async function runGraphqlMutationCommand(input) {
1875
1898
  message
1876
1899
  }),
1877
1900
  exitCode: EXIT_CODES.generic
1878
- });
1879
- }
1880
- }
1881
-
1882
- // src/commands/runtimeOptions.ts
1883
- import { existsSync as existsSync2 } from "fs";
1884
- import { readFile as readFile2 } from "fs/promises";
1885
- import { join as join2 } from "path";
1886
-
1887
- // src/authStorage.ts
1888
- import { execFile } from "child_process";
1889
- import { constants, existsSync } from "fs";
1890
- import { access, mkdir, readFile, rm, stat, writeFile, chmod } from "fs/promises";
1891
- import { homedir } from "os";
1892
- import { dirname, join } from "path";
1893
- import { promisify } from "util";
1894
- var execFileAsync = promisify(execFile);
1895
- var KEYCHAIN_SERVICE = "wave-cli";
1896
- var FILE_NAME = "auth-token.json";
1897
- function normalize2(raw) {
1898
- if (typeof raw !== "string") return void 0;
1899
- const trimmed = raw.trim();
1900
- return trimmed.length > 0 ? trimmed : void 0;
1901
- }
1902
- function authHome(env = process.env) {
1903
- return normalize2(env.WAVE_CLI_HOME) ?? join(homedir(), ".wave");
1904
- }
1905
- function tokenPath(env = process.env) {
1906
- return join(authHome(env), FILE_NAME);
1907
- }
1908
- function configPath(env = process.env) {
1909
- return normalize2(env.WAVE_CONFIG_PATH) ?? join(authHome(env), "config.json");
1910
- }
1911
- function storageMode(env = process.env) {
1912
- const raw = normalize2(env.WAVE_CLI_AUTH_STORAGE)?.toLowerCase();
1913
- if (raw === "keychain" || raw === "file" || raw === "disabled") return raw;
1914
- return "auto";
1915
- }
1916
- function accountForBaseUrl(baseUrl) {
1917
- return normalize2(baseUrl) ?? "default";
1918
- }
1919
- async function commandExists(command) {
1920
- try {
1921
- await access(command, constants.X_OK);
1922
- return true;
1923
- } catch {
1924
- return false;
1925
- }
1926
- }
1927
- async function keychainAvailable(env = process.env) {
1928
- if (process.platform !== "darwin") return false;
1929
- if (storageMode(env) === "file" || storageMode(env) === "disabled") return false;
1930
- return commandExists("/usr/bin/security");
1931
- }
1932
- async function preferredStorage(env = process.env) {
1933
- const mode = storageMode(env);
1934
- if (mode === "disabled") return "disabled";
1935
- if (mode === "file") return "file";
1936
- if (mode === "keychain") return await keychainAvailable(env) ? "keychain" : "file";
1937
- return await keychainAvailable(env) ? "keychain" : "file";
1938
- }
1939
- async function readKeychainToken(baseUrl) {
1940
- try {
1941
- const { stdout } = await execFileAsync("/usr/bin/security", [
1942
- "find-generic-password",
1943
- "-a",
1944
- accountForBaseUrl(baseUrl),
1945
- "-s",
1946
- KEYCHAIN_SERVICE,
1947
- "-w"
1948
- ], { encoding: "utf8" });
1949
- return normalize2(String(stdout)) ?? null;
1950
- } catch {
1951
- return null;
1952
- }
1953
- }
1954
- async function writeKeychainToken(token, baseUrl) {
1955
- await execFileAsync("/usr/bin/security", [
1956
- "add-generic-password",
1957
- "-a",
1958
- accountForBaseUrl(baseUrl),
1959
- "-s",
1960
- KEYCHAIN_SERVICE,
1961
- "-w",
1962
- token,
1963
- "-U"
1964
- ]);
1965
- }
1966
- async function deleteKeychainToken(baseUrl) {
1967
- try {
1968
- await execFileAsync("/usr/bin/security", [
1969
- "delete-generic-password",
1970
- "-a",
1971
- accountForBaseUrl(baseUrl),
1972
- "-s",
1973
- KEYCHAIN_SERVICE
1974
- ]);
1975
- return true;
1976
- } catch {
1977
- return false;
1978
- }
1979
- }
1980
- async function readFileToken(baseUrl, env = process.env) {
1981
- const path = tokenPath(env);
1982
- if (!existsSync(path)) return null;
1983
- try {
1984
- const raw = await readFile(path, "utf8");
1985
- const payload = JSON.parse(raw);
1986
- const token = normalize2(payload.token);
1987
- const storedBaseUrl = normalize2(payload.baseUrl);
1988
- const requestedBaseUrl = normalize2(baseUrl);
1989
- if (!token) return null;
1990
- if (storedBaseUrl !== requestedBaseUrl) return null;
1991
- return token;
1992
- } catch {
1993
- return null;
1994
- }
1995
- }
1996
- async function writeFileToken(token, baseUrl, env = process.env) {
1997
- const home = authHome(env);
1998
- const path = tokenPath(env);
1999
- await mkdir(home, { recursive: true, mode: 448 });
2000
- await writeFile(
2001
- path,
2002
- `${JSON.stringify({ token, baseUrl: baseUrl ?? null, updatedAt: (/* @__PURE__ */ new Date()).toISOString() })}
2003
- `,
2004
- { mode: 384 }
2005
- );
2006
- await chmod(path, 384);
2007
- }
2008
- async function deleteFileToken(env = process.env) {
2009
- const path = tokenPath(env);
2010
- if (!existsSync(path)) return false;
2011
- await rm(path, { force: true });
2012
- return true;
2013
- }
2014
- async function readStoredToken(baseUrl) {
2015
- const mode = await preferredStorage();
2016
- if (mode === "disabled") return null;
2017
- if (mode === "keychain") {
2018
- const keychainToken = await readKeychainToken(baseUrl);
2019
- if (keychainToken) return { token: keychainToken, source: "keychain" };
2020
- }
2021
- const fileToken = await readFileToken(baseUrl);
2022
- return fileToken ? { token: fileToken, source: "file" } : null;
2023
- }
2024
- async function writeStoredToken(token, baseUrl) {
2025
- const mode = await preferredStorage();
2026
- if (mode === "disabled") {
2027
- return { kind: "disabled", available: false };
2028
- }
2029
- if (mode === "keychain") {
2030
- try {
2031
- await writeKeychainToken(token, baseUrl);
2032
- return {
2033
- kind: "keychain",
2034
- available: true,
2035
- service: KEYCHAIN_SERVICE,
2036
- account: accountForBaseUrl(baseUrl)
2037
- };
2038
- } catch {
2039
- await writeFileToken(token, baseUrl);
2040
- return { kind: "file", available: true, path: tokenPath() };
2041
- }
2042
- }
2043
- await writeFileToken(token, baseUrl);
2044
- return { kind: "file", available: true, path: tokenPath() };
2045
- }
2046
- async function persistBaseUrl(baseUrl, env = process.env) {
2047
- const path = configPath(env);
2048
- let existing = {};
2049
- if (existsSync(path)) {
2050
- const raw = await readFile(path, "utf8");
2051
- const parsed = JSON.parse(raw);
2052
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
2053
- throw new Error(`Wave config file must contain a JSON object: ${path}`);
2054
- }
2055
- existing = parsed;
2056
- }
2057
- await mkdir(dirname(path), { recursive: true, mode: 448 });
2058
- await writeFile(path, `${JSON.stringify({ ...existing, baseUrl }, null, 2)}
2059
- `, {
2060
- mode: 384
2061
- });
2062
- await chmod(path, 384);
2063
- return path;
2064
- }
2065
- async function removeStoredToken(baseUrl) {
2066
- const removedKeychain = await deleteKeychainToken(baseUrl);
2067
- const removedFile = await deleteFileToken();
2068
- return removedKeychain || removedFile;
2069
- }
2070
- async function getAuthStorageInfo(baseUrl) {
2071
- const mode = await preferredStorage();
2072
- if (mode === "disabled") return { kind: "disabled", available: false };
2073
- if (mode === "keychain") {
2074
- return {
2075
- kind: "keychain",
2076
- available: true,
2077
- service: KEYCHAIN_SERVICE,
2078
- account: accountForBaseUrl(baseUrl)
2079
- };
2080
- }
2081
- const path = tokenPath();
2082
- let available = true;
2083
- if (existsSync(path)) {
2084
- try {
2085
- const modeBits = (await stat(path)).mode & 511;
2086
- available = modeBits === 384;
2087
- } catch {
2088
- available = false;
2089
- }
1901
+ });
2090
1902
  }
2091
- return { kind: "file", available, path };
2092
1903
  }
2093
1904
 
1905
+ // src/commands/runtimeOptions.ts
1906
+ import { existsSync as existsSync2 } from "fs";
1907
+ import { readFile as readFile2 } from "fs/promises";
1908
+ import { join as join2 } from "path";
1909
+
2094
1910
  // src/authClient.ts
2095
1911
  import { randomUUID as randomUUID2 } from "crypto";
2096
1912
 
@@ -2537,17 +2353,15 @@ async function resolveWithAuthenticatedOrganization(context) {
2537
2353
  if (organizationId) resolved.organizationId = organizationId;
2538
2354
  return resolved;
2539
2355
  }
2540
- function defaultConfigPath(env) {
2541
- const explicitEnv = normalize3(env.WAVE_CONFIG_PATH);
2542
- if (explicitEnv) return explicitEnv;
2543
- const candidate = join2(authHome(env), "config.json");
2356
+ function defaultConfigPath() {
2357
+ const candidate = join2(authHome(), "config.json");
2544
2358
  return existsSync2(candidate) ? candidate : void 0;
2545
2359
  }
2546
2360
  async function resolveConfigFileContext(options, env) {
2547
2361
  const path = firstDefined(
2548
2362
  normalize3(options.configPath),
2549
2363
  normalize3(options.config),
2550
- defaultConfigPath(env)
2364
+ defaultConfigPath()
2551
2365
  );
2552
2366
  if (!path) return {};
2553
2367
  if (!existsSync2(path)) {
@@ -2692,13 +2506,13 @@ function parseRequiredOption(raw, flag) {
2692
2506
  function optionKey(flag) {
2693
2507
  return flag.replace(/-([a-z])/g, (_, char) => char.toUpperCase());
2694
2508
  }
2695
- function asRecord2(value) {
2509
+ function asRecord(value) {
2696
2510
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
2697
2511
  }
2698
2512
  function visibleSearchText(row) {
2699
- const record = asRecord2(row);
2513
+ const record = asRecord(row);
2700
2514
  if (!record) return "";
2701
- const attributes = asRecord2(record.attributes);
2515
+ const attributes = asRecord(record.attributes);
2702
2516
  const values = [];
2703
2517
  for (const field of SEARCHABLE_VISIBLE_FIELDS) {
2704
2518
  const topLevelValue = record[field];
@@ -2712,7 +2526,7 @@ function matchesSearchQuery(row, query) {
2712
2526
  return visibleSearchText(row).includes(query.toLowerCase());
2713
2527
  }
2714
2528
  function filterListEnvelopeByQuery(payload, query) {
2715
- const record = asRecord2(payload);
2529
+ const record = asRecord(payload);
2716
2530
  if (!record || !Array.isArray(record.data)) return payload;
2717
2531
  const filteredData = record.data.filter((row) => matchesSearchQuery(row, query));
2718
2532
  return {
@@ -3639,9 +3453,65 @@ var subitemUpdateContract = {
3639
3453
  rootKey: "subitem",
3640
3454
  fields: subitemFields
3641
3455
  };
3456
+ var reminderFields = {
3457
+ title: { type: "string", example: "Follow up with customer" },
3458
+ description: { type: "string" },
3459
+ due_at: { type: "string" },
3460
+ starts_at: { type: "string" },
3461
+ timezone: { type: "string", example: "America/Phoenix" },
3462
+ schedule: {
3463
+ type: "object",
3464
+ example: { type: "once", due_at: "2026-09-01T09:00:00-07:00" }
3465
+ },
3466
+ notification: {
3467
+ type: "object",
3468
+ example: { channels: ["in_app"], lead_minutes: 15 }
3469
+ },
3470
+ resources_attributes: { type: "array" },
3471
+ reminder_delegates_attributes: { type: "array" }
3472
+ };
3473
+ var reminderCreateContract = {
3474
+ rootKey: "reminder",
3475
+ fields: reminderFields,
3476
+ required: ["title", "schedule", "notification"],
3477
+ additionalProperties: false
3478
+ };
3479
+ var reminderUpdateContract = {
3480
+ rootKey: "reminder",
3481
+ fields: reminderFields,
3482
+ additionalProperties: false
3483
+ };
3484
+ var sketchFields = {
3485
+ name: { type: "string" },
3486
+ creation_key: { type: "string" },
3487
+ member_id: { type: "string" },
3488
+ teams_ids: { type: "array", items: { type: "string" } },
3489
+ status: {
3490
+ type: "string",
3491
+ enum: ["backlog", "planned", "in_progress", "completed", "cancelled", "ready_for_qa", "blocked"]
3492
+ },
3493
+ priority: { type: "string", enum: PRIORITIES }
3494
+ };
3495
+ var sketchCreateContract = {
3496
+ rootKey: "sketch",
3497
+ fields: sketchFields,
3498
+ required: ["name", "teams_ids", "creation_key"],
3499
+ additionalProperties: false
3500
+ };
3501
+ var sketchMetadataUpdateContract = {
3502
+ rootKey: "sketch",
3503
+ fields: Object.fromEntries(
3504
+ Object.entries(sketchFields).filter(([field]) => field !== "creation_key")
3505
+ ),
3506
+ additionalProperties: false
3507
+ };
3642
3508
  var CONTRACTS = {
3643
3509
  "list-items.create": listItemCreateContract,
3644
3510
  "list-items.update": listItemUpdateContract,
3511
+ "reminders.create": reminderCreateContract,
3512
+ "reminders.update": reminderUpdateContract,
3513
+ "sketches.create": sketchCreateContract,
3514
+ "sketches.update-metadata": sketchMetadataUpdateContract,
3645
3515
  "subitems.create": subitemCreateContract,
3646
3516
  "subitems.update": subitemUpdateContract
3647
3517
  };
@@ -3713,8 +3583,10 @@ function validateOperationDataJson(operationId2, value) {
3713
3583
  const missing = (contract.required ?? []).filter(
3714
3584
  (field) => entity[field] === void 0 || entity[field] === null || entity[field] === ""
3715
3585
  );
3586
+ const unsupported = contract.additionalProperties === false ? Object.keys(entity).filter((field) => !Object.prototype.hasOwnProperty.call(contract.fields, field)) : [];
3716
3587
  return [
3717
3588
  ...missing.map((field) => `${contract.rootKey}.${field} is required.`),
3589
+ ...unsupported.map((field) => `${contract.rootKey}.${field} is not permitted.`),
3718
3590
  ...validateFields(contract.fields, entity, [contract.rootKey])
3719
3591
  ].map(
3720
3592
  (error) => `Invalid input value for dataJson: ${error}`
@@ -3758,14 +3630,25 @@ function entitySchema(contract) {
3758
3630
  ])
3759
3631
  ),
3760
3632
  ...contract.required ? { required: [...contract.required] } : {},
3761
- additionalProperties: true
3633
+ additionalProperties: contract.additionalProperties ?? true
3762
3634
  };
3763
3635
  }
3636
+ function exampleValue2(contract) {
3637
+ if (contract.example !== void 0) return contract.example;
3638
+ if (contract.type === "array") return [];
3639
+ if (contract.type === "object") return {};
3640
+ if (contract.type === "number") return 0;
3641
+ if (contract.type === "boolean") return false;
3642
+ return "example";
3643
+ }
3764
3644
  function exampleDataJsonForOperation(operationId2) {
3765
3645
  const contract = CONTRACTS[operationId2];
3766
3646
  if (!contract) return null;
3767
3647
  const entity = Object.fromEntries(
3768
- (contract.required ?? []).map((field) => [field, "example"])
3648
+ (contract.required ?? []).map((field) => {
3649
+ const fieldContract = contract.fields[field];
3650
+ return [field, fieldContract ? exampleValue2(fieldContract) : "example"];
3651
+ })
3769
3652
  );
3770
3653
  return { [contract.rootKey]: entity };
3771
3654
  }
@@ -3871,7 +3754,7 @@ function registerEntityCrudCommands(program, config) {
3871
3754
  const entityCommand = program.command(config.command).description(config.description);
3872
3755
  const createHelp4 = buildDataJsonHelp(config.rootKey, "create") ?? "JSON object, optionally wrapped with root key";
3873
3756
  const updateHelp5 = buildDataJsonHelp(config.rootKey, "update") ?? "JSON object, optionally wrapped with root key";
3874
- const listField2 = config.listField ?? (config.resourcePath === "feedback" ? "feedbacks" : config.resourcePath);
3757
+ const listField2 = config.listField ?? config.resourcePath;
3875
3758
  const list = entityCommand.command("list").option("--page <page>").option("--per <per>");
3876
3759
  const listParams = config.listParams ?? [];
3877
3760
  const listParamHelp = config.listParamHelp ?? {};
@@ -3911,12 +3794,14 @@ function registerEntityCrudCommands(program, config) {
3911
3794
  isList: true
3912
3795
  });
3913
3796
  });
3914
- registerGraphqlSearchCommand(entityCommand, {
3915
- command: config.command,
3916
- field: listField2,
3917
- variableTypes: config.listVariableTypes,
3918
- selectionSet: config.listSelectionSet
3919
- });
3797
+ if (config.registerSearch !== false) {
3798
+ registerGraphqlSearchCommand(entityCommand, {
3799
+ command: config.command,
3800
+ field: listField2,
3801
+ variableTypes: config.listVariableTypes,
3802
+ selectionSet: config.listSelectionSet
3803
+ });
3804
+ }
3920
3805
  const show = entityCommand.command("show").requiredOption("--id <id>");
3921
3806
  showParams.forEach((param) => {
3922
3807
  const cliParam = param.replace(/_/g, "-");
@@ -3927,7 +3812,7 @@ function registerEntityCrudCommands(program, config) {
3927
3812
  const context = await resolveCommandContext(cmd.optsWithGlobals());
3928
3813
  const organizationId = resolveOrganizationId(context.organizationId);
3929
3814
  const defaultCommand = `${config.command}.show`;
3930
- const defaultField = config.showField ?? (config.resourcePath === "feedback" ? "feedback" : toSingularResourceName(config.resourcePath));
3815
+ const defaultField = config.showField ?? toSingularResourceName(config.resourcePath);
3931
3816
  const mappedShowParams = Object.fromEntries(
3932
3817
  showParams.map((param) => {
3933
3818
  const optionKey2 = param.replace(/_([a-z])/g, (_, char) => char.toUpperCase());
@@ -4011,6 +3896,22 @@ function registerEntityCrudCommands(program, config) {
4011
3896
  }
4012
3897
  });
4013
3898
  });
3899
+ for (const mutation of config.idMutationCommands ?? []) {
3900
+ entityCommand.command(mutation.command).description(mutation.description).requiredOption("--id <id>").action(async (opts, cmd) => {
3901
+ const id = idSchema2.parse(opts.id);
3902
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
3903
+ const organizationId = resolveOrganizationId(context.organizationId);
3904
+ await runGraphqlMutationCommand({
3905
+ command: `${config.command}.${mutation.command}`,
3906
+ runtimeOptions: context.runtimeOptions,
3907
+ field: mutation.field,
3908
+ variables: {
3909
+ organization_id: organizationId,
3910
+ [mutation.idVariable]: id
3911
+ }
3912
+ });
3913
+ });
3914
+ }
4014
3915
  }
4015
3916
  var __testables = {
4016
3917
  toSingularResourceName,
@@ -4047,7 +3948,7 @@ var displayPreferenceAttributesSelectionSet = "attributes { id viewType favorite
4047
3948
  var filterPreferenceAttributesSelectionSet = "attributes { id filterType filter memberId focusMemberId focusTeamId filterableId filterableType preferenceType agendaItemId }";
4048
3949
  var healthUpdateSummarySelectionSet = "id type value memberId status createdAt updatedAt updatableType updatableId parentUpdateId emojis { id name memberId } resources { ...ResourceSummaryFull }";
4049
3950
  var projectShowFullSelectionSet = `{ id type name slug description status priority createdAt updatedAt startDate targetDate archivedAt memberId organizationId teamIds emoji { id name memberId } backgroundImage { backgroundType gradientStart gradientEnd gradientDegrees color imageUrl image { url lowUrl } } favorites { id memberId } resources { ...ResourceSummaryFull } displayPreference { id type ${displayPreferenceAttributesSelectionSet} viewType favorite groupingField groupToggleState memberId focusMemberId focusTeamId displayableId displayableType preferenceType agendaItemId } filterPreferences { id type ${filterPreferenceAttributesSelectionSet} filterType filter memberId focusMemberId focusTeamId filterableId filterableType preferenceType agendaItemId } healthUpdates { ${healthUpdateSummarySelectionSet} replies { ${healthUpdateSummarySelectionSet} replies { id type } } } } fragment ResourceSummaryFull on ResourceSummary { id resourceType slug url skillId skill { id name slug emoji scope description } metadata { urlName imageUrl siteName providerName mediaType skillId skillName skillSlug skillScope skillEmoji skillDescription } attachment { id fileKey filename url } content { id name slug type firstChildSlug childCount } }`;
4050
- function asRecord3(value) {
3951
+ function asRecord2(value) {
4051
3952
  return value && typeof value === "object" ? value : null;
4052
3953
  }
4053
3954
  function toNonEmptyString(value) {
@@ -4080,9 +3981,9 @@ function parseProjectPriority(value) {
4080
3981
  return parsed.data.toUpperCase();
4081
3982
  }
4082
3983
  function normalizeProjectRowForDisplay(row) {
4083
- const record = asRecord3(row);
3984
+ const record = asRecord2(row);
4084
3985
  if (!record) return row;
4085
- const attributes = asRecord3(record.attributes);
3986
+ const attributes = asRecord2(record.attributes);
4086
3987
  const topLevelName = toNonEmptyString(record.name);
4087
3988
  const topLevelTitle = toNonEmptyString(record.title);
4088
3989
  const attributeName = toNonEmptyString(attributes?.name);
@@ -4097,7 +3998,7 @@ function normalizeProjectRowForDisplay(row) {
4097
3998
  };
4098
3999
  }
4099
4000
  function normalizeProjectsListForDisplay(payload) {
4100
- const record = asRecord3(payload);
4001
+ const record = asRecord2(payload);
4101
4002
  if (!record || !Array.isArray(record.data)) return payload;
4102
4003
  return {
4103
4004
  ...record,
@@ -4315,7 +4216,7 @@ var MEETING_STATUSES = /* @__PURE__ */ new Set(["upcoming", "active", "completed
4315
4216
  var MEETING_REPEATS = /* @__PURE__ */ new Set(["never", "weekly", "biweekly", "monthly", "quarterly"]);
4316
4217
  var createHelp2 = buildDataJsonHelp("meeting", "create") ?? 'JSON object for meeting or {"meeting": {...}}';
4317
4218
  var updateHelp2 = buildDataJsonHelp("meeting", "update") ?? 'JSON object for meeting or {"meeting": {...}}';
4318
- function asNonEmptyString2(value) {
4219
+ function asNonEmptyString(value) {
4319
4220
  if (typeof value !== "string") {
4320
4221
  return void 0;
4321
4222
  }
@@ -4373,7 +4274,7 @@ function normalizeMeetingCreateBody(body) {
4373
4274
  });
4374
4275
  }
4375
4276
  const meeting = { ...entity };
4376
- const type = asNonEmptyString2(meeting.type);
4277
+ const type = asNonEmptyString(meeting.type);
4377
4278
  if (!type || !MEETING_TYPES.has(type)) {
4378
4279
  throw new CliError({
4379
4280
  message: "Invalid meeting.type. Use one of: TeamMeeting, OneOnOneMeeting.",
@@ -4383,8 +4284,8 @@ function normalizeMeetingCreateBody(body) {
4383
4284
  details: { field: "meeting.type", allowed: Array.from(MEETING_TYPES) }
4384
4285
  });
4385
4286
  }
4386
- const memberId = asNonEmptyString2(meeting.member_id);
4387
- const date = asNonEmptyString2(meeting.date);
4287
+ const memberId = asNonEmptyString(meeting.member_id);
4288
+ const date = asNonEmptyString(meeting.date);
4388
4289
  const startTime = toFiniteNumber(meeting.start_time, "meeting.start_time");
4389
4290
  const missingRequired = [];
4390
4291
  if (!memberId) missingRequired.push("member_id");
@@ -4399,7 +4300,7 @@ function normalizeMeetingCreateBody(body) {
4399
4300
  details: { requiredFields: ["member_id", "date", "start_time"], rootKey: "meeting" }
4400
4301
  });
4401
4302
  }
4402
- const status = asNonEmptyString2(meeting.status);
4303
+ const status = asNonEmptyString(meeting.status);
4403
4304
  if (status && !MEETING_STATUSES.has(status)) {
4404
4305
  throw new CliError({
4405
4306
  message: "Invalid meeting.status. Use one of: upcoming, active, completed.",
@@ -4409,7 +4310,7 @@ function normalizeMeetingCreateBody(body) {
4409
4310
  details: { field: "meeting.status", allowed: Array.from(MEETING_STATUSES) }
4410
4311
  });
4411
4312
  }
4412
- const repeats = asNonEmptyString2(meeting.repeats) ?? "never";
4313
+ const repeats = asNonEmptyString(meeting.repeats) ?? "never";
4413
4314
  if (!MEETING_REPEATS.has(repeats)) {
4414
4315
  throw new CliError({
4415
4316
  message: "Invalid meeting.repeats. Use one of: never, weekly, biweekly, monthly, quarterly.",
@@ -5138,13 +5039,35 @@ var SMART_KPI_NAMES = [
5138
5039
  var SMART_KPI_NAME_SET = new Set(SMART_KPI_NAMES);
5139
5040
 
5140
5041
  // src/commands/systemTools.ts
5042
+ var REMINDER_ATTRIBUTES_SELECTION = `
5043
+ id
5044
+ organizationId
5045
+ creatorId
5046
+ title
5047
+ description
5048
+ dueAt
5049
+ startsAt
5050
+ timezone
5051
+ schedule
5052
+ notification
5053
+ status
5054
+ nextTriggerAt
5055
+ lastTriggeredAt
5056
+ clearedAt
5057
+ reminderDelegates { id memberId organizationId }
5058
+ delegateMembers { id email firstName lastName organizationId }
5059
+ resources { id resourceType url creatorId attachment { id fileKey filename } }
5060
+ createdAt
5061
+ updatedAt
5062
+ `;
5063
+ var REMINDER_LIST_SELECTION = `{ data { id type attributes { ${REMINDER_ATTRIBUTES_SELECTION} } } count currentPage totalPages }`;
5064
+ var REMINDER_SHOW_SELECTION = `{ id type attributes { ${REMINDER_ATTRIBUTES_SELECTION} } }`;
5141
5065
  var TODO_STATUSES = /* @__PURE__ */ new Set(["open", "completed"]);
5142
5066
  var KNOWLEDGE_CONTENT_TYPES = /* @__PURE__ */ new Set(["company", "policy", "process"]);
5143
5067
  var KNOWLEDGE_STATUSES = /* @__PURE__ */ new Set(["draft", "published"]);
5144
5068
  var NEWS_STATUSES = /* @__PURE__ */ new Set(["active", "completed"]);
5145
5069
  var NEWS_HEADLINE_TYPES = /* @__PURE__ */ new Set(["team", "org_wide"]);
5146
5070
  var QUESTION_STATUSES = /* @__PURE__ */ new Set(["asked", "answered"]);
5147
- var PULSE_STATUSES = /* @__PURE__ */ new Set(["on_track", "at_risk", "off_track"]);
5148
5071
  var SURVEY_RECIPIENT_TYPES = /* @__PURE__ */ new Set(["member", "team", "org_wide"]);
5149
5072
  var SURVEY_NAMES = /* @__PURE__ */ new Set([
5150
5073
  "employee_net_promoter_score",
@@ -5157,21 +5080,6 @@ var SURVEY_NAMES = /* @__PURE__ */ new Set([
5157
5080
  "manager_review",
5158
5081
  "onboarding"
5159
5082
  ]);
5160
- var FEEDBACK_QUARTERS = /* @__PURE__ */ new Set(["q1", "q2", "q3", "q4"]);
5161
- var FEEDBACK_NAMES = /* @__PURE__ */ new Set([
5162
- "productivity_and_focus",
5163
- "company_collaboration",
5164
- "project_management",
5165
- "employee_engagement",
5166
- "training_and_development",
5167
- "innovation_and_creativity",
5168
- "customer_insights",
5169
- "process_improvement",
5170
- "leadership_and_management",
5171
- "company_culture",
5172
- "roadmap_and_strategy",
5173
- "customer_testing_and_feedback"
5174
- ]);
5175
5083
  var SCORECARD_INTERVALS = /* @__PURE__ */ new Set([
5176
5084
  "daily",
5177
5085
  "weekly",
@@ -5222,7 +5130,7 @@ function normalizeTodosCreateBody(body) {
5222
5130
  }
5223
5131
  return { ...body, todo };
5224
5132
  }
5225
- function asNonEmptyString3(value) {
5133
+ function asNonEmptyString2(value) {
5226
5134
  if (typeof value !== "string") {
5227
5135
  return void 0;
5228
5136
  }
@@ -5230,7 +5138,7 @@ function asNonEmptyString3(value) {
5230
5138
  return trimmed.length > 0 ? trimmed : void 0;
5231
5139
  }
5232
5140
  function validateEnumField(params) {
5233
- const value = asNonEmptyString3(params.rawValue);
5141
+ const value = asNonEmptyString2(params.rawValue);
5234
5142
  if (!value) {
5235
5143
  return void 0;
5236
5144
  }
@@ -5264,7 +5172,7 @@ function normalizeKnowledgeCreateBody(body) {
5264
5172
  message: "Invalid content.status. Use one of: draft, published."
5265
5173
  });
5266
5174
  content.status = status ?? "draft";
5267
- const memberId = asNonEmptyString3(content.member_id);
5175
+ const memberId = asNonEmptyString2(content.member_id);
5268
5176
  if (!memberId) {
5269
5177
  throwMissingRequiredCreateFields("content", ["member_id"]);
5270
5178
  }
@@ -5273,7 +5181,7 @@ function normalizeKnowledgeCreateBody(body) {
5273
5181
  }
5274
5182
  function normalizeNewsCreateBody(body) {
5275
5183
  const headline = ensureEntityObject(body, "headline");
5276
- const memberId = asNonEmptyString3(headline.member_id);
5184
+ const memberId = asNonEmptyString2(headline.member_id);
5277
5185
  if (!memberId) {
5278
5186
  throwMissingRequiredCreateFields("headline", ["member_id"]);
5279
5187
  }
@@ -5302,14 +5210,14 @@ function normalizeNewsCreateBody(body) {
5302
5210
  }
5303
5211
  function normalizeQuestionsCreateBody(body) {
5304
5212
  const question = ensureEntityObject(body, "question");
5305
- const summary = asNonEmptyString3(question.summary);
5306
- const currentName = asNonEmptyString3(question.name);
5213
+ const summary = asNonEmptyString2(question.summary);
5214
+ const currentName = asNonEmptyString2(question.name);
5307
5215
  if (!currentName && summary) {
5308
5216
  question.name = summary;
5309
5217
  }
5310
5218
  delete question.summary;
5311
- const name = asNonEmptyString3(question.name);
5312
- const memberId = asNonEmptyString3(question.member_id);
5219
+ const name = asNonEmptyString2(question.name);
5220
+ const memberId = asNonEmptyString2(question.member_id);
5313
5221
  const missing = [];
5314
5222
  if (!name) missing.push("name");
5315
5223
  if (!memberId) missing.push("member_id");
@@ -5331,13 +5239,13 @@ function normalizeQuestionsCreateBody(body) {
5331
5239
  }
5332
5240
  function normalizeQuestionsUpdateBody(body) {
5333
5241
  const question = ensureEntityObject(body, "question");
5334
- const summary = asNonEmptyString3(question.summary);
5335
- const currentName = asNonEmptyString3(question.name);
5242
+ const summary = asNonEmptyString2(question.summary);
5243
+ const currentName = asNonEmptyString2(question.name);
5336
5244
  if (!currentName && summary) {
5337
5245
  question.name = summary;
5338
5246
  }
5339
5247
  delete question.summary;
5340
- const name = asNonEmptyString3(question.name);
5248
+ const name = asNonEmptyString2(question.name);
5341
5249
  if (name) {
5342
5250
  question.name = name;
5343
5251
  }
@@ -5352,37 +5260,10 @@ function normalizeQuestionsUpdateBody(body) {
5352
5260
  }
5353
5261
  return { ...body, question };
5354
5262
  }
5355
- function normalizePulseCreateBody(body) {
5356
- const healthUpdate = ensureEntityObject(body, "health_update");
5357
- const healthUpdatableId = asNonEmptyString3(healthUpdate.health_updatable_id) ?? asNonEmptyString3(healthUpdate.updatable_id);
5358
- const healthUpdatableType = asNonEmptyString3(healthUpdate.health_updatable_type) ?? asNonEmptyString3(healthUpdate.updatable_type);
5359
- const memberId = asNonEmptyString3(healthUpdate.member_id);
5360
- const status = validateEnumField({
5361
- rawValue: healthUpdate.status,
5362
- field: "health_update.status",
5363
- allowed: PULSE_STATUSES,
5364
- message: "Invalid health_update.status. Use one of: on_track, at_risk, off_track."
5365
- });
5366
- const missing = [];
5367
- if (!healthUpdatableId) missing.push("health_updatable_id");
5368
- if (!healthUpdatableType) missing.push("health_updatable_type");
5369
- if (!memberId) missing.push("member_id");
5370
- if (!status) missing.push("status");
5371
- if (missing.length > 0) {
5372
- throwMissingRequiredCreateFields("health_update", missing);
5373
- }
5374
- healthUpdate.health_updatable_id = healthUpdatableId;
5375
- healthUpdate.health_updatable_type = healthUpdatableType;
5376
- healthUpdate.member_id = memberId;
5377
- healthUpdate.status = status;
5378
- delete healthUpdate.updatable_id;
5379
- delete healthUpdate.updatable_type;
5380
- return { ...body, health_update: healthUpdate };
5381
- }
5382
5263
  function normalizeSurveysCreateBody(body) {
5383
5264
  const survey = ensureEntityObject(body, "survey");
5384
- const title = asNonEmptyString3(survey.title);
5385
- const currentName = asNonEmptyString3(survey.name);
5265
+ const title = asNonEmptyString2(survey.title);
5266
+ const currentName = asNonEmptyString2(survey.name);
5386
5267
  if (!currentName && title) {
5387
5268
  survey.name = title;
5388
5269
  }
@@ -5411,8 +5292,8 @@ function normalizeSurveysCreateBody(body) {
5411
5292
  }
5412
5293
  function normalizeSurveysUpdateBody(body) {
5413
5294
  const survey = ensureEntityObject(body, "survey");
5414
- const title = asNonEmptyString3(survey.title);
5415
- const currentName = asNonEmptyString3(survey.name);
5295
+ const title = asNonEmptyString2(survey.title);
5296
+ const currentName = asNonEmptyString2(survey.name);
5416
5297
  if (!currentName && title) {
5417
5298
  survey.name = title;
5418
5299
  }
@@ -5437,77 +5318,16 @@ function normalizeSurveysUpdateBody(body) {
5437
5318
  }
5438
5319
  return { ...body, survey };
5439
5320
  }
5440
- function normalizeFeedbacksCreateBody(body) {
5441
- const feedback = ensureEntityObject(body, "feedback");
5442
- const title = asNonEmptyString3(feedback.title);
5443
- const currentName = asNonEmptyString3(feedback.name);
5444
- if (!currentName && title) {
5445
- feedback.name = title;
5446
- }
5447
- delete feedback.title;
5448
- const name = validateEnumField({
5449
- rawValue: feedback.name,
5450
- field: "feedback.name",
5451
- allowed: FEEDBACK_NAMES,
5452
- message: "Invalid feedback.name. Use one of: productivity_and_focus, company_collaboration, project_management, employee_engagement, training_and_development, innovation_and_creativity, customer_insights, process_improvement, leadership_and_management, company_culture, roadmap_and_strategy, customer_testing_and_feedback."
5453
- });
5454
- const quarter = validateEnumField({
5455
- rawValue: feedback.quarter,
5456
- field: "feedback.quarter",
5457
- allowed: FEEDBACK_QUARTERS,
5458
- message: "Invalid feedback.quarter. Use one of: q1, q2, q3, q4."
5459
- });
5460
- const year = asNonEmptyString3(feedback.year);
5461
- const missing = [];
5462
- if (!name) missing.push("name");
5463
- if (!quarter) missing.push("quarter");
5464
- if (!year) missing.push("year");
5465
- if (missing.length > 0) {
5466
- throwMissingRequiredCreateFields("feedback", missing);
5467
- }
5468
- feedback.name = name;
5469
- feedback.quarter = quarter;
5470
- feedback.year = year;
5471
- return { ...body, feedback };
5472
- }
5473
- function normalizeFeedbacksUpdateBody(body) {
5474
- const feedback = ensureEntityObject(body, "feedback");
5475
- const title = asNonEmptyString3(feedback.title);
5476
- const currentName = asNonEmptyString3(feedback.name);
5477
- if (!currentName && title) {
5478
- feedback.name = title;
5479
- }
5480
- delete feedback.title;
5481
- const name = validateEnumField({
5482
- rawValue: feedback.name,
5483
- field: "feedback.name",
5484
- allowed: FEEDBACK_NAMES,
5485
- message: "Invalid feedback.name. Use one of: productivity_and_focus, company_collaboration, project_management, employee_engagement, training_and_development, innovation_and_creativity, customer_insights, process_improvement, leadership_and_management, company_culture, roadmap_and_strategy, customer_testing_and_feedback."
5486
- });
5487
- if (name) {
5488
- feedback.name = name;
5489
- }
5490
- const quarter = validateEnumField({
5491
- rawValue: feedback.quarter,
5492
- field: "feedback.quarter",
5493
- allowed: FEEDBACK_QUARTERS,
5494
- message: "Invalid feedback.quarter. Use one of: q1, q2, q3, q4."
5495
- });
5496
- if (quarter) {
5497
- feedback.quarter = quarter;
5498
- }
5499
- return { ...body, feedback };
5500
- }
5501
5321
  function normalizeAccountabilityCreateBody(body) {
5502
5322
  const responsibility = ensureEntityObject(body, "responsibility");
5503
- const summary = asNonEmptyString3(responsibility.summary);
5504
- const currentName = asNonEmptyString3(responsibility.name);
5323
+ const summary = asNonEmptyString2(responsibility.summary);
5324
+ const currentName = asNonEmptyString2(responsibility.name);
5505
5325
  if (!currentName && summary) {
5506
5326
  responsibility.name = summary;
5507
5327
  }
5508
5328
  delete responsibility.summary;
5509
- const name = asNonEmptyString3(responsibility.name);
5510
- const memberId = asNonEmptyString3(responsibility.member_id);
5329
+ const name = asNonEmptyString2(responsibility.name);
5330
+ const memberId = asNonEmptyString2(responsibility.member_id);
5511
5331
  const missing = [];
5512
5332
  if (!name) missing.push("name");
5513
5333
  if (!memberId) missing.push("member_id");
@@ -5522,8 +5342,8 @@ function normalizeAccountabilityCreateBody(body) {
5522
5342
  }
5523
5343
  function normalizeAccountabilityUpdateBody(body) {
5524
5344
  const responsibility = ensureEntityObject(body, "responsibility");
5525
- const summary = asNonEmptyString3(responsibility.summary);
5526
- const currentName = asNonEmptyString3(responsibility.name);
5345
+ const summary = asNonEmptyString2(responsibility.summary);
5346
+ const currentName = asNonEmptyString2(responsibility.name);
5527
5347
  if (!currentName && summary) {
5528
5348
  responsibility.name = summary;
5529
5349
  }
@@ -5555,7 +5375,7 @@ function parseSmartKpiViewCreateBody(raw) {
5555
5375
  }
5556
5376
  function normalizeSmartKpiViewCreateBody(body) {
5557
5377
  const smartKpiView = ensureEntityObject(body, "smart_kpi_view");
5558
- const name = asNonEmptyString3(smartKpiView.name);
5378
+ const name = asNonEmptyString2(smartKpiView.name);
5559
5379
  if (!name) {
5560
5380
  throwMissingRequiredCreateFields("smart_kpi_view", ["name"]);
5561
5381
  }
@@ -5593,9 +5413,9 @@ function buildKpisCreateMutation(params) {
5593
5413
  });
5594
5414
  }
5595
5415
  const smartKpi = { ...entity };
5596
- const name = asNonEmptyString3(smartKpi.name);
5597
- const smartKpiViewId = asNonEmptyString3(smartKpi.smart_kpi_view_id);
5598
- const measurableGroupId = asNonEmptyString3(smartKpi.measurable_group_id);
5416
+ const name = asNonEmptyString2(smartKpi.name);
5417
+ const smartKpiViewId = asNonEmptyString2(smartKpi.smart_kpi_view_id);
5418
+ const measurableGroupId = asNonEmptyString2(smartKpi.measurable_group_id);
5599
5419
  const hasAllowedName = typeof name === "string" && SMART_KPI_NAME_SET.has(name);
5600
5420
  if (!name) {
5601
5421
  throw new CliError({
@@ -5615,7 +5435,7 @@ function buildKpisCreateMutation(params) {
5615
5435
  measurable_type: "number",
5616
5436
  condition: "greater_than_or_equal_to"
5617
5437
  };
5618
- const notes = asNonEmptyString3(smartKpi.notes);
5438
+ const notes = asNonEmptyString2(smartKpi.notes);
5619
5439
  if (notes) {
5620
5440
  measurable.notes = notes;
5621
5441
  }
@@ -5684,6 +5504,32 @@ function registerSmartKpiViewCommands(program) {
5684
5504
  });
5685
5505
  }
5686
5506
  function registerSystemToolCommands(program) {
5507
+ registerEntityCrudCommands(program, {
5508
+ command: "reminders",
5509
+ description: "Reminder operations",
5510
+ resourcePath: "reminders",
5511
+ rootKey: "reminder",
5512
+ requiredCreateFields: ["title"],
5513
+ listParams: ["status", "sort"],
5514
+ allowQueryJson: false,
5515
+ registerSearch: false,
5516
+ listSelectionSet: REMINDER_LIST_SELECTION,
5517
+ showSelectionSet: REMINDER_SHOW_SELECTION,
5518
+ idMutationCommands: [
5519
+ {
5520
+ command: "clear",
5521
+ description: "Clear a reminder while retaining its history",
5522
+ field: "clear_reminder",
5523
+ idVariable: "reminder_id"
5524
+ },
5525
+ {
5526
+ command: "destroy",
5527
+ description: "Cancel a reminder while retaining its history",
5528
+ field: "destroy_reminder",
5529
+ idVariable: "reminder_id"
5530
+ }
5531
+ ]
5532
+ });
5687
5533
  registerEntityCrudCommands(program, {
5688
5534
  command: "lists",
5689
5535
  description: "List operations",
@@ -5828,18 +5674,6 @@ function registerSystemToolCommands(program) {
5828
5674
  listParams: ["answered", "asked"],
5829
5675
  allowQueryJson: false
5830
5676
  });
5831
- registerEntityCrudCommands(program, {
5832
- command: "pulse",
5833
- description: "Pulse operations",
5834
- resourcePath: "health_updates",
5835
- rootKey: "health_update",
5836
- listField: "feedbacks",
5837
- showField: "feedback",
5838
- requiredCreateFields: ["health_updatable_id", "health_updatable_type", "member_id", "status"],
5839
- normalizeCreateBody: normalizePulseCreateBody,
5840
- listParams: ["last", "latest", "start_date", "name", "quarter", "year"],
5841
- allowQueryJson: false
5842
- });
5843
5677
  registerEntityCrudCommands(program, {
5844
5678
  command: "surveys",
5845
5679
  description: "Survey operations",
@@ -5851,17 +5685,6 @@ function registerSystemToolCommands(program) {
5851
5685
  listParams: ["completed", "current_member", "due", "exclude_completed", "sent"],
5852
5686
  allowQueryJson: false
5853
5687
  });
5854
- registerEntityCrudCommands(program, {
5855
- command: "feedbacks",
5856
- description: "Feedback operations",
5857
- resourcePath: "feedback",
5858
- rootKey: "feedback",
5859
- requiredCreateFields: ["name", "quarter", "year"],
5860
- normalizeCreateBody: normalizeFeedbacksCreateBody,
5861
- normalizeUpdateBody: normalizeFeedbacksUpdateBody,
5862
- listParams: ["last", "latest", "start_date"],
5863
- allowQueryJson: false
5864
- });
5865
5688
  registerEntityCrudCommands(program, {
5866
5689
  command: "accountability",
5867
5690
  description: "Accountability operations",
@@ -6018,7 +5841,7 @@ function ensureRootObject(body, rootKey) {
6018
5841
  }
6019
5842
  return { ...root };
6020
5843
  }
6021
- function asNonEmptyString4(value) {
5844
+ function asNonEmptyString3(value) {
6022
5845
  if (typeof value !== "string") {
6023
5846
  return void 0;
6024
5847
  }
@@ -6028,7 +5851,7 @@ function asNonEmptyString4(value) {
6028
5851
  function normalizeOrganizationUpdateBody(body) {
6029
5852
  const organization = ensureRootObject(body, "organization");
6030
5853
  const detail = isRecord3(organization.organization_detail_attributes) ? { ...organization.organization_detail_attributes } : {};
6031
- const workspaceName = asNonEmptyString4(organization.workspace_name);
5854
+ const workspaceName = asNonEmptyString3(organization.workspace_name);
6032
5855
  if (workspaceName) {
6033
5856
  detail.workspace_name = workspaceName;
6034
5857
  }
@@ -6041,7 +5864,7 @@ function normalizeOrganizationUpdateBody(body) {
6041
5864
  function normalizeOrganizationMetaProfileUpdateBody(body) {
6042
5865
  const root = ensureRootObject(body, "organization_meta_profile");
6043
5866
  const profile = isRecord3(root.profile) ? { ...root.profile } : {};
6044
- const title = asNonEmptyString4(root.title);
5867
+ const title = asNonEmptyString3(root.title);
6045
5868
  if (title) {
6046
5869
  const companyIdentity = isRecord3(profile.company_identity) ? { ...profile.company_identity } : {};
6047
5870
  companyIdentity.one_sentence_summary = title;
@@ -6071,7 +5894,7 @@ function normalizeOrganizationMetaProfileUpdateBody(body) {
6071
5894
  function normalizeKeyMetricMetaProfileUpdateBody(body) {
6072
5895
  const root = ensureRootObject(body, "key_metric_meta_profile");
6073
5896
  const profile = isRecord3(root.profile) ? { ...root.profile } : {};
6074
- const annualRevenue = asNonEmptyString4(root.annual_revenue);
5897
+ const annualRevenue = asNonEmptyString3(root.annual_revenue);
6075
5898
  if (annualRevenue) {
6076
5899
  const financial = isRecord3(profile.financial) ? { ...profile.financial } : {};
6077
5900
  financial.revenue = annualRevenue;
@@ -6255,7 +6078,7 @@ function ensureRootObject2(body, rootKey) {
6255
6078
  }
6256
6079
  return { ...root };
6257
6080
  }
6258
- function asNonEmptyString5(value) {
6081
+ function asNonEmptyString4(value) {
6259
6082
  if (typeof value !== "string") {
6260
6083
  return void 0;
6261
6084
  }
@@ -6283,8 +6106,8 @@ function normalizeStrategicPlanUpdateBody(body) {
6283
6106
  }
6284
6107
  function normalizeStrategicObjectiveUpdateBody(body) {
6285
6108
  const strategicObjective = ensureRootObject2(body, "strategic_objective");
6286
- const title = asNonEmptyString5(strategicObjective.title);
6287
- if (!asNonEmptyString5(strategicObjective.summary) && title) {
6109
+ const title = asNonEmptyString4(strategicObjective.title);
6110
+ if (!asNonEmptyString4(strategicObjective.summary) && title) {
6288
6111
  strategicObjective.summary = title;
6289
6112
  }
6290
6113
  delete strategicObjective.title;
@@ -6307,8 +6130,8 @@ function normalizeStrategicObjectiveUpdateBody(body) {
6307
6130
  }
6308
6131
  function normalizeAnnualObjectiveCreateBody(body) {
6309
6132
  const annualObjective = ensureRootObject2(body, "annual_objective");
6310
- const title = asNonEmptyString5(annualObjective.title);
6311
- if (!asNonEmptyString5(annualObjective.name) && title) {
6133
+ const title = asNonEmptyString4(annualObjective.title);
6134
+ if (!asNonEmptyString4(annualObjective.name) && title) {
6312
6135
  annualObjective.name = title;
6313
6136
  }
6314
6137
  delete annualObjective.title;
@@ -6316,8 +6139,8 @@ function normalizeAnnualObjectiveCreateBody(body) {
6316
6139
  }
6317
6140
  function normalizeQuarterlyObjectiveCreateBody(body) {
6318
6141
  const quarterlyObjective = ensureRootObject2(body, "quarterly_objective");
6319
- const title = asNonEmptyString5(quarterlyObjective.title);
6320
- if (!asNonEmptyString5(quarterlyObjective.name) && title) {
6142
+ const title = asNonEmptyString4(quarterlyObjective.title);
6143
+ if (!asNonEmptyString4(quarterlyObjective.name) && title) {
6321
6144
  quarterlyObjective.name = title;
6322
6145
  }
6323
6146
  delete quarterlyObjective.title;
@@ -6460,7 +6283,18 @@ function requiredParentSearchOption(parentFlag, parentKind) {
6460
6283
  }
6461
6284
  function buildChildResourceSelectionSet(parentField, extraFields = []) {
6462
6285
  const fields = Array.from(
6463
- /* @__PURE__ */ new Set(["id", "type", "name", "status", "priority", "rank", "dueDate", "memberId", parentField, ...extraFields])
6286
+ /* @__PURE__ */ new Set([
6287
+ "id",
6288
+ "type",
6289
+ "name",
6290
+ "status",
6291
+ "priority",
6292
+ "rank",
6293
+ "dueDate",
6294
+ "memberId",
6295
+ parentField,
6296
+ ...extraFields
6297
+ ])
6464
6298
  );
6465
6299
  const attributeFields = fields.filter((field) => field !== "type");
6466
6300
  return `{ ${fields.join(" ")} attributes { ${attributeFields.join(" ")} } }`;
@@ -6468,6 +6302,30 @@ function buildChildResourceSelectionSet(parentField, extraFields = []) {
6468
6302
  function buildChildListSelectionSet(parentField, extraFields = []) {
6469
6303
  return `{ data ${buildChildResourceSelectionSet(parentField, extraFields)} count currentPage totalPages }`;
6470
6304
  }
6305
+ function buildChildShowSelectionSet(parentField, extraFields = []) {
6306
+ const fields = Array.from(
6307
+ /* @__PURE__ */ new Set([
6308
+ "id",
6309
+ "type",
6310
+ "name",
6311
+ "status",
6312
+ "priority",
6313
+ "rank",
6314
+ "dueDate",
6315
+ "memberId",
6316
+ parentField,
6317
+ "notes",
6318
+ "hasNotes",
6319
+ "hasUnreadNotes",
6320
+ "notesUpdatedAt",
6321
+ "notesLastReadAt",
6322
+ "estimateIds",
6323
+ ...extraFields
6324
+ ])
6325
+ );
6326
+ const attributeFields = fields.filter((field) => field !== "type");
6327
+ return `{ ${fields.join(" ")} attributes { ${attributeFields.join(" ")} } }`;
6328
+ }
6471
6329
  function parseJsonObject2(raw) {
6472
6330
  try {
6473
6331
  const parsed = JSON.parse(raw);
@@ -6845,11 +6703,14 @@ function registerChildEntityCommands(program) {
6845
6703
  updateField: "update_talking_point",
6846
6704
  destroyField: "destroy_talking_point",
6847
6705
  idVariable: "talking_point_id",
6706
+ showField: "talking_point",
6848
6707
  listOperationName: "TalkingPointsList",
6708
+ showOperationName: "TalkingPointsShow",
6849
6709
  createOperationName: "TalkingPointsCreate",
6850
6710
  updateOperationName: "TalkingPointsUpdate",
6851
6711
  destroyOperationName: "TalkingPointsDestroy",
6852
6712
  listSelectionSet: buildChildListSelectionSet("meetingId", ["description", "creatorId", "slug"]),
6713
+ showSelectionSet: buildChildShowSelectionSet("meetingId", ["description", "creatorId", "slug"]),
6853
6714
  listParentTypedField: "meetingId"
6854
6715
  });
6855
6716
  }
@@ -7216,7 +7077,7 @@ import { z as z18 } from "zod";
7216
7077
 
7217
7078
  // src/internalOptions.ts
7218
7079
  var INTERNAL_OPTIONS_KEY = "__waveInternalOptions";
7219
- function asRecord4(value) {
7080
+ function asRecord3(value) {
7220
7081
  if (!value || typeof value !== "object" || Array.isArray(value)) {
7221
7082
  return null;
7222
7083
  }
@@ -7230,7 +7091,7 @@ function setInternalCliOptions(program, options) {
7230
7091
  function getInternalCliOptions(command) {
7231
7092
  let current = command;
7232
7093
  while (current) {
7233
- const record = asRecord4(current[INTERNAL_OPTIONS_KEY]);
7094
+ const record = asRecord3(current[INTERNAL_OPTIONS_KEY]);
7234
7095
  if (record) {
7235
7096
  return {
7236
7097
  enableRetryOnEmptyPhrase: record.enableRetryOnEmptyPhrase === true
@@ -8033,7 +7894,7 @@ import { Option } from "commander";
8033
7894
  import { createHash } from "crypto";
8034
7895
 
8035
7896
  // src/version.ts
8036
- var CLI_VERSION = "0.1.87";
7897
+ var CLI_VERSION = "0.1.88";
8037
7898
 
8038
7899
  // src/operationMetadata.ts
8039
7900
  var DISCOVERY_OPERATION_IDS = [
@@ -8069,8 +7930,6 @@ var DISCOVERY_OPERATION_IDS = [
8069
7930
  "doctor",
8070
7931
  "doctor.examples",
8071
7932
  "doctor.schema",
8072
- "feedbacks.examples",
8073
- "feedbacks.schema",
8074
7933
  "foundation.examples",
8075
7934
  "foundation.schema",
8076
7935
  "issue-groups.examples",
@@ -8107,8 +7966,6 @@ var DISCOVERY_OPERATION_IDS = [
8107
7966
  "project-content.schema",
8108
7967
  "projects.examples",
8109
7968
  "projects.schema",
8110
- "pulse.examples",
8111
- "pulse.schema",
8112
7969
  "questions.examples",
8113
7970
  "questions.schema",
8114
7971
  "recognition.examples",
@@ -8150,7 +8007,9 @@ var DISCOVERY_OPERATION_IDS = [
8150
8007
  "todos.examples",
8151
8008
  "todos.schema",
8152
8009
  "whiteboards.examples",
8153
- "whiteboards.schema"
8010
+ "whiteboards.schema",
8011
+ "sketches.examples",
8012
+ "sketches.schema"
8154
8013
  ];
8155
8014
  var READ_OPERATION_IDS = [
8156
8015
  "accountability.list",
@@ -8187,9 +8046,6 @@ var READ_OPERATION_IDS = [
8187
8046
  "desktop-context.member-statuses",
8188
8047
  "desktop-context.recent",
8189
8048
  "desktop-context.status",
8190
- "feedbacks.list",
8191
- "feedbacks.search",
8192
- "feedbacks.show",
8193
8049
  "find",
8194
8050
  "foundation.annual-objectives.list",
8195
8051
  "foundation.annual-objectives.search",
@@ -8225,6 +8081,7 @@ var READ_OPERATION_IDS = [
8225
8081
  "mail.message",
8226
8082
  "mail.messages",
8227
8083
  "mail.open",
8084
+ "mail.relay-evidence",
8228
8085
  "mail.settings",
8229
8086
  "mail.snippets",
8230
8087
  "mail.sync-status",
@@ -8289,9 +8146,6 @@ var READ_OPERATION_IDS = [
8289
8146
  "projects.list",
8290
8147
  "projects.search",
8291
8148
  "projects.show",
8292
- "pulse.list",
8293
- "pulse.search",
8294
- "pulse.show",
8295
8149
  "questions.list",
8296
8150
  "questions.search",
8297
8151
  "questions.show",
@@ -8303,6 +8157,8 @@ var READ_OPERATION_IDS = [
8303
8157
  "rock-collections.list",
8304
8158
  "rock-collections.search",
8305
8159
  "rock-collections.show",
8160
+ "reminders.list",
8161
+ "reminders.show",
8306
8162
  "rocks.list",
8307
8163
  "rocks.search",
8308
8164
  "rocks.show",
@@ -8315,6 +8171,8 @@ var READ_OPERATION_IDS = [
8315
8171
  "skills.list",
8316
8172
  "skills.show",
8317
8173
  "stand-ups.list",
8174
+ "signatures.list",
8175
+ "signatures.show",
8318
8176
  "stand-ups.search",
8319
8177
  "stand-ups.show",
8320
8178
  "subissues.list",
@@ -8338,13 +8196,12 @@ var READ_OPERATION_IDS = [
8338
8196
  "support.settings",
8339
8197
  "support.ticket-counts",
8340
8198
  "support.tickets",
8341
- "signatures.list",
8342
- "signatures.show",
8343
8199
  "surveys.list",
8344
8200
  "surveys.search",
8345
8201
  "surveys.show",
8346
8202
  "talking-points.list",
8347
8203
  "talking-points.search",
8204
+ "talking-points.show",
8348
8205
  "tasks.list",
8349
8206
  "tasks.search",
8350
8207
  "tasks.show",
@@ -8366,7 +8223,10 @@ var READ_OPERATION_IDS = [
8366
8223
  "tree",
8367
8224
  "whiteboards.list",
8368
8225
  "whiteboards.open",
8369
- "whiteboards.show"
8226
+ "whiteboards.show",
8227
+ "sketches.list",
8228
+ "sketches.open",
8229
+ "sketches.show"
8370
8230
  ];
8371
8231
  var WRITE_OPERATION_IDS = [
8372
8232
  "accountability.create",
@@ -8417,8 +8277,6 @@ var WRITE_OPERATION_IDS = [
8417
8277
  "datasheets.view.delete",
8418
8278
  "datasheets.view.reorder",
8419
8279
  "datasheets.view.update",
8420
- "feedbacks.create",
8421
- "feedbacks.update",
8422
8280
  "foundation.annual-objectives.create",
8423
8281
  "foundation.annual-objectives.update",
8424
8282
  "foundation.quarterly-objectives.create",
@@ -8466,8 +8324,6 @@ var WRITE_OPERATION_IDS = [
8466
8324
  "project-content.update",
8467
8325
  "projects.create",
8468
8326
  "projects.update",
8469
- "pulse.create",
8470
- "pulse.update",
8471
8327
  "questions.create",
8472
8328
  "questions.update",
8473
8329
  "rock-collections.create",
@@ -8475,6 +8331,10 @@ var WRITE_OPERATION_IDS = [
8475
8331
  "rocks.create",
8476
8332
  "rocks.update",
8477
8333
  "rocks.update-status",
8334
+ "reminders.clear",
8335
+ "reminders.create",
8336
+ "reminders.destroy",
8337
+ "reminders.update",
8478
8338
  "scorecard-groups.create",
8479
8339
  "scorecard-groups.update",
8480
8340
  "scorecards.create",
@@ -8516,7 +8376,9 @@ var WRITE_OPERATION_IDS = [
8516
8376
  "todo-groups.create",
8517
8377
  "todo-groups.update",
8518
8378
  "todos.create",
8519
- "todos.update"
8379
+ "todos.update",
8380
+ "sketches.create",
8381
+ "sketches.update-metadata"
8520
8382
  ];
8521
8383
  var DIRECT_MACHINE_WRITE_OPERATION_IDS = /* @__PURE__ */ new Set(["automations.create"]);
8522
8384
  var AUTH_OPERATION_IDS = ["login", "logout"];
@@ -8537,6 +8399,8 @@ var DESTRUCTIVE_OPERATION_IDS = /* @__PURE__ */ new Set([
8537
8399
  "datasheets.view.delete",
8538
8400
  "milestones.destroy",
8539
8401
  "project-content.destroy",
8402
+ "reminders.clear",
8403
+ "reminders.destroy",
8540
8404
  "signatures.destroy",
8541
8405
  "signatures.void",
8542
8406
  "subissues.destroy",
@@ -9834,15 +9698,15 @@ function normalizeAgentFilePath(file, parentRef) {
9834
9698
  const trimmed = nonEmptyString3.parse(file).trim().replace(/^\/+|\/+$/g, "");
9835
9699
  const fileName = trimmed.startsWith(".agent/") ? trimmed.slice(".agent/".length) : trimmed;
9836
9700
  const isThreadWorkspace = atlasThreadWorkspaceParentRefPattern.test(parentRef);
9837
- const isSupportedFile = isThreadWorkspace ? /^[a-z0-9][a-z0-9-]*\.(?:md|txt)$/.test(fileName) : isSupportedAgentOverlayFileName(fileName);
9701
+ const isSupportedFile = isThreadWorkspace ? /^[a-z0-9][a-z0-9-]*\.(?:md|txt|csv)$/.test(fileName) : isSupportedAgentOverlayFileName(fileName);
9838
9702
  if (fileName.includes("\\") || fileName.includes("/") || fileName === "." || fileName === ".." || !isSupportedFile) {
9839
9703
  throw new CliError({
9840
- message: isThreadWorkspace ? "Atlas task workspaces support only lowercase kebab-case .md or .txt basenames." : ".agent supports only notes.md, summary.md, or <lowercase-kebab-slug>.md.",
9704
+ message: isThreadWorkspace ? "Atlas task workspaces support only lowercase kebab-case .md, .txt, or .csv basenames." : ".agent supports only notes.md, summary.md, or <lowercase-kebab-slug>.md.",
9841
9705
  kind: "invalid_args",
9842
9706
  status: 400,
9843
9707
  exitCode: EXIT_CODES.invalidArgs,
9844
9708
  details: {
9845
- supportedFiles: isThreadWorkspace ? ["<lowercase-kebab-slug>.md", "<lowercase-kebab-slug>.txt"] : [...supportedAgentOverlaySystemFiles, "<lowercase-kebab-slug>.md"]
9709
+ supportedFiles: isThreadWorkspace ? ["<lowercase-kebab-slug>.md", "<lowercase-kebab-slug>.txt", "<lowercase-kebab-slug>.csv"] : [...supportedAgentOverlaySystemFiles, "<lowercase-kebab-slug>.md"]
9846
9710
  }
9847
9711
  });
9848
9712
  }
@@ -11325,7 +11189,7 @@ function positiveInt2(raw, fallback) {
11325
11189
  function requestTimeoutMs(totalTimeoutMs) {
11326
11190
  return Math.max(1e3, Math.min(totalTimeoutMs, 1e4));
11327
11191
  }
11328
- function asRecord5(value) {
11192
+ function asRecord4(value) {
11329
11193
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
11330
11194
  }
11331
11195
  function asString(value) {
@@ -11375,9 +11239,9 @@ function cliTokenFromPoll(payload) {
11375
11239
  return asString(payload.cliToken) ?? asString(payload.cli_token) ?? asString(payload.token);
11376
11240
  }
11377
11241
  function unwrapMutationResult(value) {
11378
- const record = asRecord5(value);
11242
+ const record = asRecord4(value);
11379
11243
  if (!record) return null;
11380
- const data = asRecord5(record.data);
11244
+ const data = asRecord4(record.data);
11381
11245
  if (data && (Object.prototype.hasOwnProperty.call(record, "ok") || Object.prototype.hasOwnProperty.call(record, "errors") || Object.prototype.hasOwnProperty.call(record, "errorCode") || Object.prototype.hasOwnProperty.call(record, "error_code"))) {
11382
11246
  return data;
11383
11247
  }
@@ -11442,7 +11306,7 @@ async function runTokenLogin(cmd, opts) {
11442
11306
  exitCode: mapStatusToExitCode(status.error.status)
11443
11307
  });
11444
11308
  }
11445
- const statusData = asRecord5(status.result.data.cliAuthStatus) ?? {};
11309
+ const statusData = asRecord4(status.result.data.cliAuthStatus) ?? {};
11446
11310
  const storage = await writeStoredToken(token, baseUrl);
11447
11311
  const configPath2 = opts.saveBaseUrl ? await persistBaseUrl(baseUrl) : void 0;
11448
11312
  return printEnvelopeAndExit({
@@ -11659,7 +11523,7 @@ async function runLogout(cmd) {
11659
11523
  });
11660
11524
  if (result.ok) {
11661
11525
  requestId = result.result.requestId;
11662
- const payload = asRecord5(result.result.data.revokeCliToken) ?? {};
11526
+ const payload = asRecord4(result.result.data.revokeCliToken) ?? {};
11663
11527
  revokedRemote = payload.ok !== false;
11664
11528
  } else {
11665
11529
  requestId = result.requestId;
@@ -11722,7 +11586,7 @@ async function runAuthStatus(cmd) {
11722
11586
  exitCode: mapStatusToExitCode(result.error.status)
11723
11587
  });
11724
11588
  }
11725
- const status = asRecord5(result.result.data.cliAuthStatus) ?? {};
11589
+ const status = asRecord4(result.result.data.cliAuthStatus) ?? {};
11726
11590
  const baseAuthStatus = status.baseAuthStatus;
11727
11591
  return printEnvelopeAndExit({
11728
11592
  envelope: envelope({
@@ -11989,6 +11853,26 @@ var RECENT_TOOL_SUPPORT_REGISTRY = [
11989
11853
  ]
11990
11854
  }
11991
11855
  }),
11856
+ entry({
11857
+ cliKey: "sketches",
11858
+ displayName: "Sketches",
11859
+ backend: backendToolKey("sketches"),
11860
+ routes: ["/sketches", "/sketches/[sketchId]"],
11861
+ capabilityCategories: ["collaboration", "design", "metadata", "read_only_discovery"],
11862
+ sensitiveOutputNotes: [
11863
+ "Sketch commands must not print document bytes, collaboration updates, embedded files, comments, or auth material."
11864
+ ],
11865
+ implementation: {
11866
+ milestone: "WAVE-12",
11867
+ status: "implemented_command_surface",
11868
+ enabledCommands: ["open", "list", "show", "create", "update-metadata"],
11869
+ forbiddenCommands: ["save-document", "render", "export", "import"],
11870
+ notes: [
11871
+ "The Sketch surface is limited to metadata and does not provide an editor, renderer, binary transport, or provider connector.",
11872
+ "Create and metadata update use the existing typed GraphQL mutations."
11873
+ ]
11874
+ }
11875
+ }),
11992
11876
  entry({
11993
11877
  cliKey: "time-tracking",
11994
11878
  displayName: "Time Tracking",
@@ -13026,6 +12910,158 @@ function registerWhiteboardsCommands(program) {
13026
12910
  });
13027
12911
  }
13028
12912
 
12913
+ // src/commands/sketches.ts
12914
+ var SKETCH_METADATA_SELECTION = "id name slug status priority archivedAt organizationId memberId teamIds documentGeneration documentVersion partytimeRoomId partytimeRoomVersion createdAt updatedAt";
12915
+ var SKETCHES_SELECTION = `{ count currentPage totalPages data { ${SKETCH_METADATA_SELECTION} } }`;
12916
+ var SKETCH_SELECTION = `{ ${SKETCH_METADATA_SELECTION} }`;
12917
+ function baseVariables4(contextOrganizationId) {
12918
+ return { organization_id: resolveOrganizationId(contextOrganizationId) };
12919
+ }
12920
+ function listFilters3(opts) {
12921
+ return {
12922
+ page: opts.page,
12923
+ per: opts.per,
12924
+ team_id: opts.teamId,
12925
+ member_id: opts.memberId,
12926
+ include_archived: opts.includeArchived
12927
+ };
12928
+ }
12929
+ function listVariableTypes3() {
12930
+ return {
12931
+ organization_id: "ID!",
12932
+ page: "Int",
12933
+ per: "Int",
12934
+ team_id: "ID",
12935
+ member_id: "ID",
12936
+ include_archived: "Boolean"
12937
+ };
12938
+ }
12939
+ async function runSketchQuery(cmd, config) {
12940
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
12941
+ await runGraphqlQueryCommand({
12942
+ command: config.command,
12943
+ operationName: config.operationName,
12944
+ runtimeOptions: context.runtimeOptions,
12945
+ field: config.field,
12946
+ variables: normalizeGraphqlVariables2({
12947
+ ...baseVariables4(context.organizationId),
12948
+ ...config.variables
12949
+ }),
12950
+ ...config.variableTypes ? { variableTypes: config.variableTypes } : {},
12951
+ ...config.isList ? { isList: true } : {},
12952
+ ...config.isShow ? { isShow: true } : {},
12953
+ selectionSet: config.selectionSet
12954
+ });
12955
+ }
12956
+ function addListFilterOptions3(command) {
12957
+ return command.option("--page <page>").option("--per <per>").option("--team-id <teamId>").option("--member-id <memberId>").option("--include-archived <includeArchived>");
12958
+ }
12959
+ function sketchOpenData() {
12960
+ const tool = getRecentToolSupport("sketches");
12961
+ return {
12962
+ cliKey: "sketches",
12963
+ displayName: "Sketches",
12964
+ backend: {
12965
+ toolKey: tool?.backend.toolKey ?? "sketches",
12966
+ status: tool?.backend.status ?? "verified_wave_02",
12967
+ sourceMilestone: tool?.backend.sourceMilestone ?? "WAVE-02"
12968
+ },
12969
+ route: tool?.safeRouteTargets.primaryRoute ?? "/sketches",
12970
+ safeRouteTargets: tool?.safeRouteTargets ?? {
12971
+ primaryRoute: "/sketches",
12972
+ deepLinkTemplates: ["/sketches", "/sketches/[sketchId]"],
12973
+ status: "verified_wave_03",
12974
+ sourceMilestone: "WAVE-03"
12975
+ },
12976
+ implementation: {
12977
+ enabledCommands: ["open", "list", "show", "create", "update-metadata"],
12978
+ excludedCommands: ["save-document", "render", "export", "import"]
12979
+ },
12980
+ sensitiveOutputNotes: tool?.sensitiveOutputNotes ?? [
12981
+ "Sketch commands return metadata only and never return document bytes, collaboration updates, embedded files, comments, or tokens."
12982
+ ]
12983
+ };
12984
+ }
12985
+ function registerSketchCommands(program) {
12986
+ const sketches = program.command("sketches").description("Sketch metadata operations with bounded create and update support");
12987
+ sketches.command("open").description("Return verified Sketches app routes without opening a browser").option("--readable", "Print the primary route path only").option("--json", "Emit the stable JSON envelope").action((opts) => {
12988
+ const data = sketchOpenData();
12989
+ if (opts.readable && !opts.json) return printTextAndExit({ text: String(data.route) });
12990
+ return printEnvelopeAndExit({
12991
+ envelope: {
12992
+ ok: true,
12993
+ command: "sketches.open",
12994
+ status: 200,
12995
+ data,
12996
+ error: null,
12997
+ meta: { requestId: "local_sketches" }
12998
+ }
12999
+ });
13000
+ });
13001
+ addListFilterOptions3(sketches.command("list").description("Read safe Sketch metadata")).action(
13002
+ async (opts, cmd) => {
13003
+ await runSketchQuery(cmd, {
13004
+ command: "sketches.list",
13005
+ operationName: "Sketches",
13006
+ field: "sketches",
13007
+ variables: listFilters3(opts),
13008
+ variableTypes: listVariableTypes3(),
13009
+ isList: true,
13010
+ selectionSet: SKETCHES_SELECTION
13011
+ });
13012
+ }
13013
+ );
13014
+ sketches.command("show").description("Read safe Sketch detail metadata").requiredOption("--slug <slug>").action(async (opts, cmd) => {
13015
+ await runSketchQuery(cmd, {
13016
+ command: "sketches.show",
13017
+ operationName: "Sketch",
13018
+ field: "sketch",
13019
+ variables: { slug: opts.slug },
13020
+ variableTypes: { organization_id: "ID!", slug: "ID!" },
13021
+ isShow: true,
13022
+ selectionSet: SKETCH_SELECTION
13023
+ });
13024
+ });
13025
+ sketches.command("create").description("Create a Sketch with a required team and idempotency key").requiredOption("--data-json <dataJson>", 'Sketch JSON or {"sketch": {...}}').action(async (opts, cmd) => {
13026
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
13027
+ const body = __testables.normalizeBody(String(opts.dataJson), "sketch");
13028
+ assertOperationPayload("sketches.create", body);
13029
+ await runGraphqlMutationCommand({
13030
+ command: "sketches.create",
13031
+ runtimeOptions: context.runtimeOptions,
13032
+ field: "create_sketch",
13033
+ variables: {
13034
+ organization_id: resolveOrganizationId(context.organizationId),
13035
+ params: body
13036
+ },
13037
+ variableTypes: {
13038
+ organization_id: "ID!",
13039
+ params: "CreateSketchParamsInput!"
13040
+ }
13041
+ });
13042
+ });
13043
+ sketches.command("update-metadata").description("Update bounded Sketch metadata; document content is never accepted").requiredOption("--id <id>").requiredOption("--data-json <dataJson>", 'Sketch metadata JSON or {"sketch": {...}}').action(async (opts, cmd) => {
13044
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
13045
+ const body = __testables.normalizeBody(String(opts.dataJson), "sketch");
13046
+ assertOperationPayload("sketches.update-metadata", body);
13047
+ await runGraphqlMutationCommand({
13048
+ command: "sketches.update-metadata",
13049
+ runtimeOptions: context.runtimeOptions,
13050
+ field: "update_sketch",
13051
+ variables: {
13052
+ organization_id: resolveOrganizationId(context.organizationId),
13053
+ sketch_id: String(opts.id),
13054
+ params: body
13055
+ },
13056
+ variableTypes: {
13057
+ organization_id: "ID!",
13058
+ sketch_id: "ID!",
13059
+ params: "UpdateSketchParamsInput!"
13060
+ }
13061
+ });
13062
+ });
13063
+ }
13064
+
13029
13065
  // src/commands/timeTracking.ts
13030
13066
  var TIME_TRACKING_ENTRY_SELECTION = "id organizationId memberId memberName taskId projectId projectName labelId createdByMemberId localDate durationMinutes startMinute endMinute startedAt endedAt status source createdAt updatedAt";
13031
13067
  var TIME_TRACKING_ENTRIES_SELECTION = `{ count currentPage totalPages data { ${TIME_TRACKING_ENTRY_SELECTION} } }`;
@@ -13056,7 +13092,7 @@ var TIME_TRACKING_FORBIDDEN_COMMANDS = [
13056
13092
  "payroll",
13057
13093
  "billing"
13058
13094
  ];
13059
- function baseVariables4(contextOrganizationId) {
13095
+ function baseVariables5(contextOrganizationId) {
13060
13096
  return {
13061
13097
  organization_id: resolveOrganizationId(contextOrganizationId)
13062
13098
  };
@@ -13111,7 +13147,7 @@ async function runTimeTrackingQuery(cmd, config) {
13111
13147
  runtimeOptions: context.runtimeOptions,
13112
13148
  field: config.field,
13113
13149
  variables: normalizeGraphqlVariables2({
13114
- ...baseVariables4(context.organizationId),
13150
+ ...baseVariables5(context.organizationId),
13115
13151
  ...config.variables
13116
13152
  }),
13117
13153
  variableTypes: config.variableTypes,
@@ -13373,11 +13409,11 @@ function sanitizePlannerJson(value) {
13373
13409
  }
13374
13410
  return output;
13375
13411
  }
13376
- function asRecord6(value) {
13412
+ function asRecord5(value) {
13377
13413
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
13378
13414
  }
13379
13415
  function readPlannerStateKey(value, keys) {
13380
- const record = asRecord6(value);
13416
+ const record = asRecord5(value);
13381
13417
  if (!record) {
13382
13418
  return null;
13383
13419
  }
@@ -13572,6 +13608,7 @@ var MAIL_ENABLED_COMMANDS = [
13572
13608
  "open",
13573
13609
  "validate-provider",
13574
13610
  "workspace",
13611
+ "relay-evidence",
13575
13612
  "accounts",
13576
13613
  "messages",
13577
13614
  "conversations",
@@ -13637,6 +13674,9 @@ var MAIL_SETTINGS_SELECTION = "{ id organizationId memberId defaultMailAccountId
13637
13674
  var MAIL_UNREAD_COUNT_SELECTION = "{ total byAccount byLabel }";
13638
13675
  var MAIL_SYNC_STATUS_SELECTION = "{ id status operationStatus operationToolKey accountId accountIds page per view importedCount updatedCount providerCount counts errorCode statusCode queuedAt startedAt completedAt createdAt updatedAt }";
13639
13676
  var MAIL_WORKSPACE_SELECTION = `{ accounts ${MAIL_ACCOUNT_SELECTION} messages ${MAIL_MESSAGES_SELECTION} labels ${MAIL_LABEL_SELECTION} snippets ${MAIL_SNIPPET_SELECTION} settings ${MAIL_SETTINGS_SELECTION} unreadCount ${MAIL_UNREAD_COUNT_SELECTION} }`;
13677
+ var MAIL_RELAY_EVIDENCE_ACCOUNT_SELECTION = "{ id provider service status connectionState syncStatus emailAddress displayName lastSyncedAt }";
13678
+ var MAIL_RELAY_EVIDENCE_MESSAGE_SELECTION = "{ id mailAccountId subject from status direction sentAt receivedAt snippet createdAt updatedAt }";
13679
+ var MAIL_RELAY_EVIDENCE_SELECTION = `{ accounts ${MAIL_RELAY_EVIDENCE_ACCOUNT_SELECTION} messages { count currentPage totalPages data ${MAIL_RELAY_EVIDENCE_MESSAGE_SELECTION} } }`;
13640
13680
  var OUTLOOK_PROVIDER_VALIDATION_EVIDENCE = {
13641
13681
  provider: "microsoft",
13642
13682
  oauthProviderId: "wave-microsoft-outlook",
@@ -13801,7 +13841,8 @@ function buildMailOpenData() {
13801
13841
  forbiddenCommands: [...MAIL_FORBIDDEN_COMMANDS]
13802
13842
  },
13803
13843
  sensitiveOutputNotes: tool?.sensitiveOutputNotes ?? [
13804
- "Mail commands are metadata-only and must not print message bodies, subjects, snippets, contacts, attachments, provider payloads, token material, account addresses/display names, label names/colors, snippet content, preferences, signatures, sync search text, sync error bodies, or user-authored mail content."
13844
+ "Default Mail commands are metadata-only and must not print message bodies, subjects, snippets, contacts, attachments, provider payloads, token material, account addresses/display names, label names/colors, snippet content, preferences, signatures, sync search text, sync error bodies, or user-authored mail content.",
13845
+ "mail relay-evidence is the explicit bounded exception for an authenticated, user-authorized relay: it exposes mailbox identity plus sender, subject, date, and snippet metadata, but never bodies, recipients, attachments, provider IDs, or token material."
13805
13846
  ]
13806
13847
  };
13807
13848
  }
@@ -13914,6 +13955,26 @@ function registerMailCommands(program) {
13914
13955
  isShow: true
13915
13956
  });
13916
13957
  });
13958
+ addPaginationOptions(
13959
+ mail.command("relay-evidence").description(
13960
+ "Read bounded mailbox identity and recent message metadata for an explicitly authorized relay"
13961
+ ).option("--account-id <accountId>")
13962
+ ).action(async (opts, cmd) => {
13963
+ await runMailQuery(cmd, opts, {
13964
+ command: "mail.relay-evidence",
13965
+ operationName: "MailRelayEvidence",
13966
+ field: "mail_workspace",
13967
+ variables: mailWorkspaceVariables,
13968
+ variableTypes: {
13969
+ organization_id: "ID!",
13970
+ account_id: "ID",
13971
+ page: "Int",
13972
+ per: "Int"
13973
+ },
13974
+ selectionSet: MAIL_RELAY_EVIDENCE_SELECTION,
13975
+ isShow: true
13976
+ });
13977
+ });
13917
13978
  mail.command("accounts").description("Read safe Mail account metadata").action(async (opts, cmd) => {
13918
13979
  await runMailQuery(cmd, opts, {
13919
13980
  command: "mail.accounts",
@@ -15955,7 +16016,7 @@ var URL_OR_TRANSPORT_KEY = /(?:^|_)(?:url|uri|token|nonce|post_fields|postfields
15955
16016
  function isRecord7(value) {
15956
16017
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
15957
16018
  }
15958
- function asNonEmptyString6(value) {
16019
+ function asNonEmptyString5(value) {
15959
16020
  if (typeof value !== "string") return null;
15960
16021
  const trimmed = value.trim();
15961
16022
  return trimmed.length > 0 ? trimmed : null;
@@ -16000,7 +16061,7 @@ function parseCreatePayload(raw, mode) {
16000
16061
  ["name", "subject", "message", "expires_at", "visibility", "metadata", "recipients"],
16001
16062
  "--data-json"
16002
16063
  );
16003
- const parsedMode = asNonEmptyString6(mode);
16064
+ const parsedMode = asNonEmptyString5(mode);
16004
16065
  if (parsedMode !== "request" && parsedMode !== "self_sign") {
16005
16066
  throw new CliError({
16006
16067
  message: "signatures create requires --mode request or --mode self_sign.",
@@ -16018,9 +16079,9 @@ function parseUpdatePayload(raw, options) {
16018
16079
  ["name", "subject", "message", "expires_at", "visibility", "recipients", "fields"],
16019
16080
  "--data-json"
16020
16081
  );
16021
- const name = asNonEmptyString6(options.name);
16022
- const subject = asNonEmptyString6(options.subject);
16023
- const message = asNonEmptyString6(options.message);
16082
+ const name = asNonEmptyString5(options.name);
16083
+ const subject = asNonEmptyString5(options.subject);
16084
+ const message = asNonEmptyString5(options.message);
16024
16085
  const patch = {
16025
16086
  ...data,
16026
16087
  ...name ? { name } : {},
@@ -16155,8 +16216,8 @@ function requireUploadTarget(payload) {
16155
16216
  exitCode: EXIT_CODES.networkOrUpstream
16156
16217
  });
16157
16218
  }
16158
- const postUrl = asNonEmptyString6(attributes.postUrl);
16159
- const fileKey = asNonEmptyString6(attributes.getUrl);
16219
+ const postUrl = asNonEmptyString5(attributes.postUrl);
16220
+ const fileKey = asNonEmptyString5(attributes.getUrl);
16160
16221
  const rawPostFields = attributes.postFields;
16161
16222
  if (!postUrl || !fileKey || !isRecord7(rawPostFields) || !fileKey.startsWith("uploads/signatures/")) {
16162
16223
  throw new CliError({
@@ -16627,7 +16688,7 @@ var AUTOMATION_RUN_STATUS_SELECTION = `{
16627
16688
  queuedAt
16628
16689
  completedAt
16629
16690
  }`;
16630
- function asRecord7(value) {
16691
+ function asRecord6(value) {
16631
16692
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
16632
16693
  }
16633
16694
  function asRequiredString(value) {
@@ -16658,7 +16719,7 @@ function requirePaginationInteger(value, key, minimum) {
16658
16719
  });
16659
16720
  }
16660
16721
  function normalizeAutomationList(payload) {
16661
- const page = asRecord7(payload);
16722
+ const page = asRecord6(payload);
16662
16723
  if (!page || !Array.isArray(page.data)) {
16663
16724
  throw new CliError({
16664
16725
  message: "Automation list response did not include a paginated data collection.",
@@ -16669,8 +16730,8 @@ function normalizeAutomationList(payload) {
16669
16730
  }
16670
16731
  const rows = page.data;
16671
16732
  const data = rows.map((value) => {
16672
- const row = asRecord7(value);
16673
- const attributes = asRecord7(row?.attributes);
16733
+ const row = asRecord6(value);
16734
+ const attributes = asRecord6(row?.attributes);
16674
16735
  if (!row || !attributes) {
16675
16736
  throw new CliError({
16676
16737
  message: "Automation list response included a malformed automation record.",
@@ -16755,13 +16816,13 @@ function parseJsonOption(value, optionName, schema) {
16755
16816
  return schema.parse(parseJson(String(value), optionName));
16756
16817
  }
16757
16818
  function normalizePersistedCreatePayload(payload) {
16758
- const mutation = asRecord7(payload);
16759
- const mutationData = asRecord7(mutation?.data);
16760
- const persisted = asRecord7(mutationData?.data) ?? mutationData;
16761
- const attributes = asRecord7(persisted?.attributes);
16762
- const automationExecution = asRecord7(attributes?.automation_execution) ?? asRecord7(attributes?.automationExecution);
16763
- const meta = asRecord7(mutationData?.meta);
16764
- const idempotency = asRecord7(meta?.atlas_idempotency);
16819
+ const mutation = asRecord6(payload);
16820
+ const mutationData = asRecord6(mutation?.data);
16821
+ const persisted = asRecord6(mutationData?.data) ?? mutationData;
16822
+ const attributes = asRecord6(persisted?.attributes);
16823
+ const automationExecution = asRecord6(attributes?.automation_execution) ?? asRecord6(attributes?.automationExecution);
16824
+ const meta = asRecord6(mutationData?.meta);
16825
+ const idempotency = asRecord6(meta?.atlas_idempotency);
16765
16826
  const id = asRequiredString(persisted?.id);
16766
16827
  const slug = asRequiredString(persisted?.slug) ?? asRequiredString(attributes?.slug);
16767
16828
  const replay = idempotency?.replay;
@@ -16792,10 +16853,10 @@ function normalizePersistedCreatePayload(payload) {
16792
16853
  };
16793
16854
  }
16794
16855
  function normalizePersistedUpdatePayload(payload) {
16795
- const mutation = asRecord7(payload);
16796
- const mutationData = asRecord7(mutation?.data);
16797
- const persisted = asRecord7(mutationData?.data) ?? mutationData;
16798
- const attributes = asRecord7(persisted?.attributes);
16856
+ const mutation = asRecord6(payload);
16857
+ const mutationData = asRecord6(mutation?.data);
16858
+ const persisted = asRecord6(mutationData?.data) ?? mutationData;
16859
+ const attributes = asRecord6(persisted?.attributes);
16799
16860
  const id = asRequiredString(persisted?.id);
16800
16861
  const slug = asRequiredString(persisted?.slug) ?? asRequiredString(attributes?.slug);
16801
16862
  const updateVersion = asRequiredString(persisted?.updateVersion) ?? asRequiredString(attributes?.updateVersion) ?? asRequiredString(attributes?.update_version);
@@ -16816,7 +16877,7 @@ function normalizePersistedUpdatePayload(payload) {
16816
16877
  };
16817
16878
  }
16818
16879
  function normalizeAutomationRunPayload(payload) {
16819
- const mutation = asRecord7(payload);
16880
+ const mutation = asRecord6(payload);
16820
16881
  if (!mutation) {
16821
16882
  throw new CliError({
16822
16883
  message: "Automation run response did not include a mutation payload.",
@@ -16834,7 +16895,7 @@ function normalizeAutomationRunPayload(payload) {
16834
16895
  data: mutation.data ?? null
16835
16896
  };
16836
16897
  }
16837
- const data = asRecord7(mutation.data);
16898
+ const data = asRecord6(mutation.data);
16838
16899
  const automationTaskId = asRequiredString(data?.automation_task_id);
16839
16900
  const automationTaskSlug = asRequiredString(data?.automation_task_slug);
16840
16901
  const agentId = asRequiredString(data?.agent_id);
@@ -17573,8 +17634,8 @@ name
17573
17634
  categories
17574
17635
  availability
17575
17636
  integrationKey
17576
- arcadeProvider
17577
- arcadeService
17637
+ connectorProvider
17638
+ connectorService
17578
17639
  logoAssetPath
17579
17640
  `.trim();
17580
17641
  var OVERVIEW_SELECTION = `
@@ -17908,6 +17969,7 @@ var PRIMARY_NAMESPACES = [
17908
17969
  "support",
17909
17970
  "recognition",
17910
17971
  "whiteboards",
17972
+ "sketches",
17911
17973
  "time-tracking",
17912
17974
  "planner",
17913
17975
  "mail",
@@ -17939,9 +18001,7 @@ var ADVANCED_NAMESPACES = [
17939
18001
  "stand-ups",
17940
18002
  "news",
17941
18003
  "questions",
17942
- "pulse",
17943
18004
  "surveys",
17944
- "feedbacks",
17945
18005
  "accountability",
17946
18006
  "kpis",
17947
18007
  "scorecard-groups",
@@ -18255,6 +18315,28 @@ var NAMESPACE_DOCS = {
18255
18315
  commands: ["open", "list", "show"]
18256
18316
  }
18257
18317
  },
18318
+ sketches: {
18319
+ name: "sketches",
18320
+ tier: "primary",
18321
+ description: "Sketch metadata, bounded create/update operations, and verified app-route metadata.",
18322
+ examples: [
18323
+ "wave sketches list --page 1 --per 20",
18324
+ "wave sketches show --slug SKT-02",
18325
+ `wave sketches create --data-json '{"name":"Design review","teams_ids":["team-1"],"creation_key":"design-review-1"}'`,
18326
+ `wave sketches update-metadata --id 123 --data-json '{"name":"Design review"}'`,
18327
+ "wave sketches open"
18328
+ ],
18329
+ schema: {
18330
+ output: "json-envelope-default",
18331
+ mutates: true,
18332
+ safety: [
18333
+ "Uses verified GraphQL fields sketches, sketch, createSketch, and updateSketch.",
18334
+ "Create requires a team and an idempotency creation key; update accepts only bounded metadata fields.",
18335
+ "Never accepts or emits native document bytes, collaboration updates, render/export data, embedded files, comments, or tokens."
18336
+ ],
18337
+ commands: ["open", "list", "show", "create", "update-metadata"]
18338
+ }
18339
+ },
18258
18340
  "time-tracking": {
18259
18341
  name: "time-tracking",
18260
18342
  tier: "primary",
@@ -18315,9 +18397,10 @@ var NAMESPACE_DOCS = {
18315
18397
  mail: {
18316
18398
  name: "mail",
18317
18399
  tier: "primary",
18318
- description: "Mail read-only metadata for workspace, accounts, messages, conversations, labels, snippets, settings, sync status, and verified app route metadata.",
18400
+ description: "Mail read-only metadata for workspace, explicitly authorized relay evidence, accounts, messages, conversations, labels, snippets, settings, sync status, and verified app route metadata.",
18319
18401
  examples: [
18320
18402
  "wave mail workspace --page 1 --per 20",
18403
+ "wave mail relay-evidence --account-id 123 --page 1 --per 20",
18321
18404
  "wave mail accounts",
18322
18405
  "wave mail messages --account-id 123 --view inbox --page 1 --per 20",
18323
18406
  "wave mail conversations --account-id 123 --view inbox --page 1 --per 20",
@@ -18339,7 +18422,8 @@ var NAMESPACE_DOCS = {
18339
18422
  "Microsoft Outlook Mail maps to service outlook_mail and Outlook Calendar maps to service outlook_calendar with custom OAuth provider wave-microsoft-outlook.",
18340
18423
  "Uses the verified WAVE-03 safe app route /mail.",
18341
18424
  "Account output is limited to ids, provider/service, status, connection state, sync status, and timestamps.",
18342
- "Message and conversation output omits bodies, subjects, snippets, contacts, attachments, provider payloads, provider ids, raw thread ids, and user-authored mail content.",
18425
+ "Default message and conversation output omits bodies, subjects, snippets, contacts, attachments, provider payloads, provider ids, raw thread ids, and user-authored mail content.",
18426
+ "relay-evidence is an explicit authenticated relay surface limited to mailbox identity plus sender, subject, date, and snippet metadata; it still omits bodies, recipients, attachments, provider ids, and token material.",
18343
18427
  "Label, snippet, settings, and sync-status output omits user label names/colors, snippet title/shortcut/body, signatures, preferences, sync search text, operation reasons, error bodies, and token material.",
18344
18428
  "Does not expose send, reply, reply-all, forward, draft, provider-action, sync/connect/disconnect, mark, archive, trash, star, label/snippet CRUD, export, print, or write commands."
18345
18429
  ],
@@ -18347,6 +18431,7 @@ var NAMESPACE_DOCS = {
18347
18431
  "open",
18348
18432
  "validate-provider",
18349
18433
  "workspace",
18434
+ "relay-evidence",
18350
18435
  "accounts",
18351
18436
  "messages",
18352
18437
  "conversations",
@@ -18943,7 +19028,11 @@ function buildCli(options) {
18943
19028
  "Explicit organization ID override"
18944
19029
  ).option(
18945
19030
  "--config <configPath>",
18946
- "Optional JSON config file (default: WAVE_CONFIG_PATH or ~/.wave/config.json when present)"
19031
+ "Optional JSON config file (default: ~/.wave/config.json when present)"
19032
+ ).addOption(
19033
+ new Option2("--auth-home <path>", "Credential storage directory (default: ~/.wave)")
19034
+ ).addOption(
19035
+ new Option2("--auth-storage <mode>", "Credential storage mode").choices(["auto", "keychain", "file", "disabled"]).default("auto")
18947
19036
  ).option("--timeout-ms <timeoutMs>", "HTTP timeout in milliseconds").option("--agent-name <agentName>", "Agent name for tracing").option("--agent-run-id <agentRunId>", "Agent run identifier for tracing").option("--request-id <requestId>", "Request identifier").option(
18948
19037
  "--atlas-member-id <memberId>",
18949
19038
  "Atlas ledger member ID (prefer WAVE_ATLAS_MEMBER_ID env var)"
@@ -18975,6 +19064,14 @@ function buildCli(options) {
18975
19064
  "--openapi-version <openapiVersion>",
18976
19065
  "Optional pinned OpenAPI version/hash"
18977
19066
  ).exitOverride();
19067
+ program.hook("preAction", (_thisCommand, actionCommand) => {
19068
+ const runtimeOptions = actionCommand.optsWithGlobals();
19069
+ configureAuthStorage({
19070
+ ...runtimeOptions.authHome ? { home: runtimeOptions.authHome } : {},
19071
+ ...runtimeOptions.config ? { configPath: runtimeOptions.config } : {},
19072
+ ...runtimeOptions.authStorage ? { mode: runtimeOptions.authStorage } : {}
19073
+ });
19074
+ });
18978
19075
  setInternalCliOptions(program, options?.internal);
18979
19076
  registerTaskCommands(program);
18980
19077
  registerProjectCommands(program);
@@ -18999,6 +19096,7 @@ function buildCli(options) {
18999
19096
  registerSupportCommands(program);
19000
19097
  registerRecognitionCommands(program);
19001
19098
  registerWhiteboardsCommands(program);
19099
+ registerSketchCommands(program);
19002
19100
  registerTimeTrackingCommands(program);
19003
19101
  registerPlannerCommands(program);
19004
19102
  registerMailCommands(program);
@@ -19263,9 +19361,10 @@ function withTrustedMachineAuth(auth, callback) {
19263
19361
  for (const key of Object.keys(process.env)) {
19264
19362
  if (key.startsWith("WAVE_")) delete process.env[key];
19265
19363
  }
19266
- process.env.WAVE_CLI_AUTH_STORAGE = "disabled";
19267
- process.env.WAVE_CLI_HOME = "/dev/null";
19268
- return withMachineRuntimeAuth(auth, callback).finally(() => {
19364
+ return withAuthStorageOptions(
19365
+ { home: "/dev/null", mode: "disabled" },
19366
+ () => withMachineRuntimeAuth(auth, callback)
19367
+ ).finally(() => {
19269
19368
  for (const key of Object.keys(process.env)) {
19270
19369
  if (key.startsWith("WAVE_")) delete process.env[key];
19271
19370
  }
@@ -19472,7 +19571,15 @@ async function maybeRunMachineExecute(argv, program) {
19472
19571
  }
19473
19572
  try {
19474
19573
  await withTrustedMachineAuth(auth, async () => {
19475
- await program.parseAsync([process.execPath, "wave", ...commandArgs(resolved.command, normalizedInput)]);
19574
+ await program.parseAsync([
19575
+ process.execPath,
19576
+ "wave",
19577
+ "--auth-storage",
19578
+ "disabled",
19579
+ "--auth-home",
19580
+ "/dev/null",
19581
+ ...commandArgs(resolved.command, normalizedInput)
19582
+ ]);
19476
19583
  });
19477
19584
  } catch (error) {
19478
19585
  if (isEnvelopeEmittedSignal(error)) return true;