@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/README.md +1 -15
- package/dist/index.cjs +793 -686
- package/dist/index.js +792 -685
- package/package.json +5 -1
- package/scripts/verify-dev-api.mjs +0 -151
- package/scripts/verify-reminder-artifact.mjs +34 -0
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
|
|
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 =
|
|
203
|
-
const memberId =
|
|
204
|
-
const chatId =
|
|
205
|
-
const assistantMessageId =
|
|
206
|
-
const activeTool =
|
|
207
|
-
const targetTool =
|
|
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:
|
|
219
|
-
actionId:
|
|
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 =
|
|
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(
|
|
2541
|
-
const
|
|
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(
|
|
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
|
|
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 =
|
|
2513
|
+
const record = asRecord(row);
|
|
2700
2514
|
if (!record) return "";
|
|
2701
|
-
const 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 =
|
|
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) =>
|
|
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 ??
|
|
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
|
-
|
|
3915
|
-
|
|
3916
|
-
|
|
3917
|
-
|
|
3918
|
-
|
|
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 ??
|
|
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
|
|
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 =
|
|
3984
|
+
const record = asRecord2(row);
|
|
4084
3985
|
if (!record) return row;
|
|
4085
|
-
const 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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
4387
|
-
const 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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
5306
|
-
const currentName =
|
|
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 =
|
|
5312
|
-
const memberId =
|
|
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 =
|
|
5335
|
-
const currentName =
|
|
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 =
|
|
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 =
|
|
5385
|
-
const currentName =
|
|
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 =
|
|
5415
|
-
const currentName =
|
|
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 =
|
|
5504
|
-
const currentName =
|
|
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 =
|
|
5510
|
-
const memberId =
|
|
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 =
|
|
5526
|
-
const currentName =
|
|
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 =
|
|
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 =
|
|
5597
|
-
const smartKpiViewId =
|
|
5598
|
-
const measurableGroupId =
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
6287
|
-
if (!
|
|
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 =
|
|
6311
|
-
if (!
|
|
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 =
|
|
6320
|
-
if (!
|
|
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([
|
|
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
|
|
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 =
|
|
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.
|
|
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 .
|
|
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
|
|
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 =
|
|
11242
|
+
const record = asRecord4(value);
|
|
11379
11243
|
if (!record) return null;
|
|
11380
|
-
const 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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
-
...
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
16022
|
-
const subject =
|
|
16023
|
-
const 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 =
|
|
16159
|
-
const fileKey =
|
|
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
|
|
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 =
|
|
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 =
|
|
16673
|
-
const 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 =
|
|
16759
|
-
const mutationData =
|
|
16760
|
-
const persisted =
|
|
16761
|
-
const attributes =
|
|
16762
|
-
const automationExecution =
|
|
16763
|
-
const meta =
|
|
16764
|
-
const 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 =
|
|
16796
|
-
const mutationData =
|
|
16797
|
-
const persisted =
|
|
16798
|
-
const 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 =
|
|
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 =
|
|
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
|
-
|
|
17577
|
-
|
|
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
|
-
"
|
|
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:
|
|
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
|
-
|
|
19267
|
-
|
|
19268
|
-
|
|
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([
|
|
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;
|