@corners/cli 0.0.3 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +395 -114
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +7 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js.map +1 -1
- package/dist/guidance.d.ts +17 -0
- package/dist/guidance.d.ts.map +1 -0
- package/dist/guidance.js +121 -0
- package/dist/guidance.js.map +1 -0
- package/dist/support.d.ts +1 -0
- package/dist/support.d.ts.map +1 -1
- package/dist/support.js +15 -0
- package/dist/support.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -4,8 +4,9 @@ import { basename, dirname, join, relative, resolve, sep } from "node:path";
|
|
|
4
4
|
import { parseArgs } from "node:util";
|
|
5
5
|
import { CornersApiClient as DefaultCornersApiClient, } from "./client.js";
|
|
6
6
|
import { ConfigStore, LOCAL_ROOT_CONFIG_RELATIVE_PATH, } from "./config.js";
|
|
7
|
+
import { buildExpectedManagedGuidanceBlock, buildGuidanceFileContent, buildGuidanceRevision, extractManagedGuidanceBlock, GUIDANCE_SYNC_COMMAND, GUIDANCE_TARGETS, normalizeGuidanceTargets, } from "./guidance.js";
|
|
7
8
|
import { createPromptApi } from "./prompts.js";
|
|
8
|
-
import { CLIError, getPackageVersion, normalizeApiUrl, openUrlInBrowser, printJson, printLine, readTextFromStdin, sleep, toGraphQLAttachmentKind, toGraphQLWorkstreamUpdateType, toIsoString, } from "./support.js";
|
|
9
|
+
import { CLIError, getPackageVersion, normalizeApiUrl, openUrlInBrowser, printJson, printLine, readTextFromStdin, sleep, toGraphQLAttachmentKind, toGraphQLWorkstreamStatus, toGraphQLWorkstreamUpdateType, toIsoString, } from "./support.js";
|
|
9
10
|
const WORKSTREAM_LOOKUP_QUERY = `
|
|
10
11
|
query CliWorkstreamLookup($id: ID!) {
|
|
11
12
|
workstream(id: $id) {
|
|
@@ -13,9 +14,11 @@ const WORKSTREAM_LOOKUP_QUERY = `
|
|
|
13
14
|
accountId
|
|
14
15
|
cornerId
|
|
15
16
|
name
|
|
17
|
+
isOpen
|
|
16
18
|
summary
|
|
17
19
|
category
|
|
18
20
|
status
|
|
21
|
+
statusDetails
|
|
19
22
|
updatedAt
|
|
20
23
|
topic {
|
|
21
24
|
id
|
|
@@ -31,9 +34,11 @@ const WORKSTREAM_PULL_QUERY = `
|
|
|
31
34
|
accountId
|
|
32
35
|
cornerId
|
|
33
36
|
name
|
|
37
|
+
isOpen
|
|
34
38
|
summary
|
|
35
39
|
category
|
|
36
40
|
status
|
|
41
|
+
statusDetails
|
|
37
42
|
createdAt
|
|
38
43
|
updatedAt
|
|
39
44
|
firstAttachmentActivityAt
|
|
@@ -283,6 +288,26 @@ const RECORD_WORKSTREAM_UPDATE_MUTATION = `
|
|
|
283
288
|
}
|
|
284
289
|
}
|
|
285
290
|
`;
|
|
291
|
+
const UPDATE_WORKSTREAM_MUTATION = `
|
|
292
|
+
mutation CliUpdateWorkstream($id: ID!, $input: UpdateWorkstreamInput!) {
|
|
293
|
+
updateWorkstream(id: $id, input: $input) {
|
|
294
|
+
id
|
|
295
|
+
accountId
|
|
296
|
+
cornerId
|
|
297
|
+
name
|
|
298
|
+
isOpen
|
|
299
|
+
summary
|
|
300
|
+
category
|
|
301
|
+
status
|
|
302
|
+
statusDetails
|
|
303
|
+
updatedAt
|
|
304
|
+
topic {
|
|
305
|
+
id
|
|
306
|
+
name
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
`;
|
|
286
311
|
const REVOKE_MCP_SESSION_MUTATION = `
|
|
287
312
|
mutation CliRevokeMcpSession($id: ID!) {
|
|
288
313
|
revokeMCPSession(id: $id)
|
|
@@ -318,9 +343,11 @@ const CREATE_WORKSTREAM_MUTATION = `
|
|
|
318
343
|
id
|
|
319
344
|
cornerId
|
|
320
345
|
name
|
|
346
|
+
isOpen
|
|
321
347
|
summary
|
|
322
348
|
category
|
|
323
349
|
status
|
|
350
|
+
statusDetails
|
|
324
351
|
updatedAt
|
|
325
352
|
topic {
|
|
326
353
|
id
|
|
@@ -351,10 +378,11 @@ function printMainHelp(runtime) {
|
|
|
351
378
|
"",
|
|
352
379
|
"Commands:",
|
|
353
380
|
" auth login|logout|status",
|
|
381
|
+
" guidance status|sync",
|
|
354
382
|
" init",
|
|
355
383
|
" corner use",
|
|
356
384
|
" whoami",
|
|
357
|
-
" workstream (ws) list|use|current|create|pull|push|question|attach|reply-thread",
|
|
385
|
+
" workstream (ws) list|use|current|create|pull|update|push|question|attach|reply-thread",
|
|
358
386
|
" help",
|
|
359
387
|
" version",
|
|
360
388
|
"",
|
|
@@ -375,6 +403,15 @@ function printInitHelp(runtime) {
|
|
|
375
403
|
" corners init [--profile <name>] [--api-url <url>] [--json]",
|
|
376
404
|
].join("\n"));
|
|
377
405
|
}
|
|
406
|
+
function printGuidanceHelp(runtime) {
|
|
407
|
+
printLine(runtime.stdout, [
|
|
408
|
+
"corners guidance",
|
|
409
|
+
"",
|
|
410
|
+
"Usage:",
|
|
411
|
+
" corners guidance status [--json]",
|
|
412
|
+
" corners guidance sync [--json]",
|
|
413
|
+
].join("\n"));
|
|
414
|
+
}
|
|
378
415
|
function printAuthHelp(runtime) {
|
|
379
416
|
printLine(runtime.stdout, [
|
|
380
417
|
"corners auth",
|
|
@@ -411,6 +448,7 @@ function printWorkstreamHelp(runtime) {
|
|
|
411
448
|
" corners workstream current [--json]",
|
|
412
449
|
" corners workstream create <name> [--summary <text>] [--corner <cornerNameOrId>] [--json]",
|
|
413
450
|
" corners workstream pull <workstreamId> [--json]",
|
|
451
|
+
" corners workstream update <workstreamId> [--status <status>] [--status-details <text> | --clear-status-details] [--json]",
|
|
414
452
|
" corners workstream push <workstreamId> [--type <type>] [--message <text>] [--summary <text>] [--file <path>] [--title <title>] [--json]",
|
|
415
453
|
" corners workstream question list <workstreamId> [--json]",
|
|
416
454
|
" corners workstream question ask <workstreamId> [--question <text>] [--rationale <text>] [--suggested-answer <text>]... [--json]",
|
|
@@ -418,6 +456,9 @@ function printWorkstreamHelp(runtime) {
|
|
|
418
456
|
" corners workstream attach <workstreamId> --kind <kind> --entity-id <id> [--json]",
|
|
419
457
|
" corners workstream reply-thread <threadId> [--text <text>] [--json]",
|
|
420
458
|
"",
|
|
459
|
+
"Lifecycle statuses:",
|
|
460
|
+
" scoping | in_progress | blocked | done",
|
|
461
|
+
"",
|
|
421
462
|
"Update types:",
|
|
422
463
|
" status | blocker | learning | outcome",
|
|
423
464
|
].join("\n"));
|
|
@@ -693,14 +734,104 @@ function resolveCornerForCwd(root, cwd) {
|
|
|
693
734
|
corner: resolveCornerForRelativePath(root.config, relativePath),
|
|
694
735
|
};
|
|
695
736
|
}
|
|
696
|
-
async function
|
|
737
|
+
async function resolveGuidanceState(root) {
|
|
738
|
+
const expectedBlock = buildExpectedManagedGuidanceBlock();
|
|
739
|
+
const fileEntries = await Promise.all(GUIDANCE_TARGETS.map(async (target) => ({
|
|
740
|
+
target,
|
|
741
|
+
content: await readOptionalUtf8(join(root.rootDir, target.relativePath)),
|
|
742
|
+
})));
|
|
743
|
+
const discoveredManagedTargets = GUIDANCE_TARGETS.map((target) => target.key).filter((key) => {
|
|
744
|
+
const entry = fileEntries.find((candidate) => candidate.target.key === key);
|
|
745
|
+
return extractManagedGuidanceBlock(entry?.content ?? null) !== null;
|
|
746
|
+
});
|
|
747
|
+
const configuredManagedTargets = root.config.guidance?.managedTargets;
|
|
748
|
+
const managedTargets = configuredManagedTargets !== undefined
|
|
749
|
+
? normalizeGuidanceTargets(configuredManagedTargets)
|
|
750
|
+
: discoveredManagedTargets;
|
|
751
|
+
const files = fileEntries.map(({ target, content }) => {
|
|
752
|
+
if (content === null) {
|
|
753
|
+
return {
|
|
754
|
+
target: target.key,
|
|
755
|
+
path: target.relativePath,
|
|
756
|
+
state: "missing",
|
|
757
|
+
};
|
|
758
|
+
}
|
|
759
|
+
if (!managedTargets.includes(target.key)) {
|
|
760
|
+
return {
|
|
761
|
+
target: target.key,
|
|
762
|
+
path: target.relativePath,
|
|
763
|
+
state: "unmanaged",
|
|
764
|
+
};
|
|
765
|
+
}
|
|
766
|
+
return {
|
|
767
|
+
target: target.key,
|
|
768
|
+
path: target.relativePath,
|
|
769
|
+
state: extractManagedGuidanceBlock(content) === expectedBlock
|
|
770
|
+
? "current"
|
|
771
|
+
: "stale",
|
|
772
|
+
};
|
|
773
|
+
});
|
|
774
|
+
const staleFiles = files
|
|
775
|
+
.filter((file) => file.state === "stale")
|
|
776
|
+
.map((file) => file.path);
|
|
777
|
+
return {
|
|
778
|
+
stale: staleFiles.length > 0,
|
|
779
|
+
lastSyncedAt: root.config.guidance?.syncedAt ?? null,
|
|
780
|
+
managedTargets,
|
|
781
|
+
staleFiles,
|
|
782
|
+
files,
|
|
783
|
+
};
|
|
784
|
+
}
|
|
785
|
+
function buildGuidanceWarning(guidance) {
|
|
786
|
+
if (!guidance.stale) {
|
|
787
|
+
return null;
|
|
788
|
+
}
|
|
789
|
+
const syncedSuffix = guidance.lastSyncedAt
|
|
790
|
+
? ` Last synced: ${guidance.lastSyncedAt}.`
|
|
791
|
+
: "";
|
|
792
|
+
return `Warning: managed Corners guidance is out of date in ${guidance.staleFiles.length} file(s).${syncedSuffix} Run \`${GUIDANCE_SYNC_COMMAND}\`.`;
|
|
793
|
+
}
|
|
794
|
+
function buildGuidanceJsonMetadata(guidance) {
|
|
795
|
+
return {
|
|
796
|
+
stale: guidance.stale,
|
|
797
|
+
lastSyncedAt: guidance.lastSyncedAt,
|
|
798
|
+
staleFiles: guidance.staleFiles,
|
|
799
|
+
syncCommand: GUIDANCE_SYNC_COMMAND,
|
|
800
|
+
};
|
|
801
|
+
}
|
|
802
|
+
function withGuidanceJsonMetadata(payload, guidance) {
|
|
803
|
+
if (!guidance) {
|
|
804
|
+
return payload;
|
|
805
|
+
}
|
|
806
|
+
return {
|
|
807
|
+
...payload,
|
|
808
|
+
_corners: {
|
|
809
|
+
guidance: buildGuidanceJsonMetadata(guidance),
|
|
810
|
+
},
|
|
811
|
+
};
|
|
812
|
+
}
|
|
813
|
+
async function resolveRootContext(runtime, common, root, options) {
|
|
814
|
+
const guidance = await resolveGuidanceState(root);
|
|
815
|
+
if ((options?.emitWarning ?? true) && !common.json) {
|
|
816
|
+
const warning = buildGuidanceWarning(guidance);
|
|
817
|
+
if (warning) {
|
|
818
|
+
printLine(runtime.stderr, warning);
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
return {
|
|
822
|
+
root,
|
|
823
|
+
guidance,
|
|
824
|
+
};
|
|
825
|
+
}
|
|
826
|
+
async function requireLocalRoot(runtime, common, options) {
|
|
697
827
|
const root = await runtime.config.findLocalRoot(runtime.cwd);
|
|
698
828
|
if (!root) {
|
|
699
829
|
throw new CLIError("No local Corners CLI root found. Run `corners init` from your project root first.", { json: common.json });
|
|
700
830
|
}
|
|
701
|
-
return root;
|
|
831
|
+
return resolveRootContext(runtime, common, root, options);
|
|
702
832
|
}
|
|
703
|
-
async function requirePinnedRootProfile(runtime, common,
|
|
833
|
+
async function requirePinnedRootProfile(runtime, common, rootContext) {
|
|
834
|
+
const { root, guidance } = rootContext;
|
|
704
835
|
if (common.profile && common.profile !== root.config.profile) {
|
|
705
836
|
throw new CLIError(`This initialized root is pinned to profile ${root.config.profile}.`, { json: common.json });
|
|
706
837
|
}
|
|
@@ -724,6 +855,7 @@ async function requirePinnedRootProfile(runtime, common, root) {
|
|
|
724
855
|
};
|
|
725
856
|
return {
|
|
726
857
|
root,
|
|
858
|
+
guidance,
|
|
727
859
|
profileName: selected.name,
|
|
728
860
|
profile,
|
|
729
861
|
client: runtime.createClient({
|
|
@@ -735,11 +867,13 @@ async function requirePinnedRootProfile(runtime, common, root) {
|
|
|
735
867
|
async function requireCommandProfile(runtime, common) {
|
|
736
868
|
const root = await runtime.config.findLocalRoot(runtime.cwd);
|
|
737
869
|
if (root) {
|
|
738
|
-
|
|
870
|
+
const rootContext = await resolveRootContext(runtime, common, root);
|
|
871
|
+
return requirePinnedRootProfile(runtime, common, rootContext);
|
|
739
872
|
}
|
|
740
873
|
const selected = await requireStoredProfile(runtime, common);
|
|
741
874
|
return {
|
|
742
875
|
root: null,
|
|
876
|
+
guidance: null,
|
|
743
877
|
...selected,
|
|
744
878
|
};
|
|
745
879
|
}
|
|
@@ -805,55 +939,6 @@ function upsertCornerOverride(config, relativePath, corner) {
|
|
|
805
939
|
cornerOverrides: overrides,
|
|
806
940
|
};
|
|
807
941
|
}
|
|
808
|
-
const GUIDANCE_SECTION_START = "<!-- corners-cli:start -->";
|
|
809
|
-
const GUIDANCE_SECTION_END = "<!-- corners-cli:end -->";
|
|
810
|
-
function buildGuidanceSection() {
|
|
811
|
-
return [
|
|
812
|
-
"## Corners CLI",
|
|
813
|
-
"",
|
|
814
|
-
"Corners CLI usage is local to each user. These shared instructions describe how AI should use the CLI, not which corners or workstreams a user has selected locally.",
|
|
815
|
-
"",
|
|
816
|
-
"- Only assume Corners CLI is initialized when `.corners/config.json` exists locally in the current repo root or an ancestor folder.",
|
|
817
|
-
"- The current folder selects the default corner through local path rules managed by `corners corner use`.",
|
|
818
|
-
"- Create new workstreams with `corners workstream create`.",
|
|
819
|
-
"- Connect existing workstreams to the local environment with `corners workstream use <workstreamId>`.",
|
|
820
|
-
"- Pass explicit workstream IDs to `corners workstream pull`, `push`, `question`, and `attach` commands.",
|
|
821
|
-
"- `corners workstream list` shows the workstreams connected for the current local environment.",
|
|
822
|
-
"",
|
|
823
|
-
"If `.corners/config.json` is absent, do not assume the repo is initialized for the current user.",
|
|
824
|
-
].join("\n");
|
|
825
|
-
}
|
|
826
|
-
function upsertManagedSection(existing, section) {
|
|
827
|
-
const block = `${GUIDANCE_SECTION_START}\n${section}\n${GUIDANCE_SECTION_END}`;
|
|
828
|
-
const startIndex = existing.indexOf(GUIDANCE_SECTION_START);
|
|
829
|
-
const endIndex = existing.indexOf(GUIDANCE_SECTION_END);
|
|
830
|
-
if (startIndex >= 0 && endIndex > startIndex) {
|
|
831
|
-
return ensureTrailingNewline(`${existing.slice(0, startIndex).trimEnd()}\n\n${block}\n${existing
|
|
832
|
-
.slice(endIndex + GUIDANCE_SECTION_END.length)
|
|
833
|
-
.trimStart()}`.trim());
|
|
834
|
-
}
|
|
835
|
-
const trimmed = existing.trim();
|
|
836
|
-
if (!trimmed) {
|
|
837
|
-
return ensureTrailingNewline(block);
|
|
838
|
-
}
|
|
839
|
-
return ensureTrailingNewline(`${trimmed}\n\n${block}`);
|
|
840
|
-
}
|
|
841
|
-
function buildGuidanceFileContent(target, existing) {
|
|
842
|
-
const section = buildGuidanceSection();
|
|
843
|
-
if (target === "cursor") {
|
|
844
|
-
const base = existing?.trim()
|
|
845
|
-
? existing
|
|
846
|
-
: [
|
|
847
|
-
"---",
|
|
848
|
-
"description: Corners CLI guidance",
|
|
849
|
-
"alwaysApply: true",
|
|
850
|
-
"---",
|
|
851
|
-
"",
|
|
852
|
-
].join("\n");
|
|
853
|
-
return upsertManagedSection(base, section);
|
|
854
|
-
}
|
|
855
|
-
return upsertManagedSection(existing ?? "", section);
|
|
856
|
-
}
|
|
857
942
|
async function buildPlannedEdit(path, nextContent) {
|
|
858
943
|
const existing = await readOptionalUtf8(path);
|
|
859
944
|
if (existing === nextContent) {
|
|
@@ -865,6 +950,16 @@ async function buildPlannedEdit(path, nextContent) {
|
|
|
865
950
|
content: nextContent,
|
|
866
951
|
};
|
|
867
952
|
}
|
|
953
|
+
function withUpdatedGuidanceConfig(config, managedTargets, syncedAt) {
|
|
954
|
+
return {
|
|
955
|
+
...config,
|
|
956
|
+
guidance: {
|
|
957
|
+
managedTargets: normalizeGuidanceTargets(managedTargets),
|
|
958
|
+
syncedAt,
|
|
959
|
+
revision: buildGuidanceRevision(),
|
|
960
|
+
},
|
|
961
|
+
};
|
|
962
|
+
}
|
|
868
963
|
function ensureGitignoreEntry(existing) {
|
|
869
964
|
const content = existing ?? "";
|
|
870
965
|
const lines = content
|
|
@@ -889,7 +984,16 @@ async function writePlannedEdits(edits) {
|
|
|
889
984
|
}
|
|
890
985
|
}
|
|
891
986
|
function formatWorkstreamLine(workstream) {
|
|
892
|
-
return
|
|
987
|
+
return [
|
|
988
|
+
workstream.id,
|
|
989
|
+
workstream.name,
|
|
990
|
+
workstream.isOpen ? "open" : "archived",
|
|
991
|
+
workstream.status.toLowerCase(),
|
|
992
|
+
workstream.statusDetails ?? null,
|
|
993
|
+
workstream.summary ? workstream.summary : null,
|
|
994
|
+
]
|
|
995
|
+
.filter((part) => Boolean(part))
|
|
996
|
+
.join(" ");
|
|
893
997
|
}
|
|
894
998
|
async function handleAuth(args, runtime, inherited) {
|
|
895
999
|
const subcommand = args[0];
|
|
@@ -1191,30 +1295,8 @@ async function handleInit(args, runtime, inherited) {
|
|
|
1191
1295
|
const rootDir = existingRoot?.rootDir ?? currentRootPath;
|
|
1192
1296
|
const existingConfig = existingRoot?.config ?? null;
|
|
1193
1297
|
return withPrompts(runtime, async (prompts) => {
|
|
1194
|
-
const guidanceTargets = [
|
|
1195
|
-
{
|
|
1196
|
-
key: "agents",
|
|
1197
|
-
label: "Manage AGENTS.md guidance",
|
|
1198
|
-
relativePath: "AGENTS.md",
|
|
1199
|
-
},
|
|
1200
|
-
{
|
|
1201
|
-
key: "claude",
|
|
1202
|
-
label: "Manage CLAUDE.md guidance",
|
|
1203
|
-
relativePath: "CLAUDE.md",
|
|
1204
|
-
},
|
|
1205
|
-
{
|
|
1206
|
-
key: "cursor",
|
|
1207
|
-
label: "Manage Cursor rule guidance",
|
|
1208
|
-
relativePath: ".cursor/rules/corners-cli.mdc",
|
|
1209
|
-
},
|
|
1210
|
-
{
|
|
1211
|
-
key: "copilot",
|
|
1212
|
-
label: "Manage Copilot instructions",
|
|
1213
|
-
relativePath: ".github/copilot-instructions.md",
|
|
1214
|
-
},
|
|
1215
|
-
];
|
|
1216
1298
|
const selectedTargets = [];
|
|
1217
|
-
for (const target of
|
|
1299
|
+
for (const target of GUIDANCE_TARGETS) {
|
|
1218
1300
|
const include = await prompts.confirm(target.label, {
|
|
1219
1301
|
defaultValue: true,
|
|
1220
1302
|
});
|
|
@@ -1230,7 +1312,8 @@ async function handleInit(args, runtime, inherited) {
|
|
|
1230
1312
|
});
|
|
1231
1313
|
const defaultCorner = joinedCorners.find((corner) => corner.id === selectedCornerId) ??
|
|
1232
1314
|
joinedCorners[0];
|
|
1233
|
-
const
|
|
1315
|
+
const syncedAt = toIsoString();
|
|
1316
|
+
const nextLocalConfig = withUpdatedGuidanceConfig({
|
|
1234
1317
|
version: 1,
|
|
1235
1318
|
profile: profileName,
|
|
1236
1319
|
workspace: profile.workspace,
|
|
@@ -1241,7 +1324,7 @@ async function handleInit(args, runtime, inherited) {
|
|
|
1241
1324
|
},
|
|
1242
1325
|
cornerOverrides: existingConfig?.cornerOverrides ?? [],
|
|
1243
1326
|
connectedWorkstreams: existingConfig?.connectedWorkstreams ?? [],
|
|
1244
|
-
};
|
|
1327
|
+
}, selectedTargets.map((target) => target.key), syncedAt);
|
|
1245
1328
|
const plannedEdits = [];
|
|
1246
1329
|
const gitignorePath = join(rootDir, ".gitignore");
|
|
1247
1330
|
const gitignoreContent = ensureGitignoreEntry(await readOptionalUtf8(gitignorePath));
|
|
@@ -1302,11 +1385,132 @@ async function handleInit(args, runtime, inherited) {
|
|
|
1302
1385
|
printJson(runtime.stdout, payload);
|
|
1303
1386
|
}
|
|
1304
1387
|
else {
|
|
1305
|
-
printLine(runtime.stdout, `Initialized Corners CLI at ${rootDir} with default corner ${defaultCorner.name}.`);
|
|
1388
|
+
printLine(runtime.stdout, `Initialized Corners CLI at ${rootDir} with default corner ${defaultCorner.name}. Run \`${GUIDANCE_SYNC_COMMAND}\` later to refresh managed guidance.`);
|
|
1306
1389
|
}
|
|
1307
1390
|
return 0;
|
|
1308
1391
|
});
|
|
1309
1392
|
}
|
|
1393
|
+
async function handleGuidance(args, runtime, inherited) {
|
|
1394
|
+
const subcommand = args[0];
|
|
1395
|
+
if (!subcommand || subcommand === "help" || subcommand === "--help") {
|
|
1396
|
+
printGuidanceHelp(runtime);
|
|
1397
|
+
return 0;
|
|
1398
|
+
}
|
|
1399
|
+
switch (subcommand) {
|
|
1400
|
+
case "status": {
|
|
1401
|
+
const parsed = parseArgs({
|
|
1402
|
+
args: args.slice(1),
|
|
1403
|
+
allowPositionals: false,
|
|
1404
|
+
options: {
|
|
1405
|
+
json: { type: "boolean" },
|
|
1406
|
+
help: { type: "boolean", short: "h" },
|
|
1407
|
+
},
|
|
1408
|
+
});
|
|
1409
|
+
const common = mergeCommonOptions(inherited, {
|
|
1410
|
+
json: parsed.values.json,
|
|
1411
|
+
});
|
|
1412
|
+
if (parsed.values.help) {
|
|
1413
|
+
printGuidanceHelp(runtime);
|
|
1414
|
+
return 0;
|
|
1415
|
+
}
|
|
1416
|
+
const rootContext = await requireLocalRoot(runtime, common, {
|
|
1417
|
+
emitWarning: false,
|
|
1418
|
+
});
|
|
1419
|
+
const payload = {
|
|
1420
|
+
ok: true,
|
|
1421
|
+
root: rootContext.root.rootDir,
|
|
1422
|
+
guidance: rootContext.guidance,
|
|
1423
|
+
};
|
|
1424
|
+
if (common.json) {
|
|
1425
|
+
printJson(runtime.stdout, payload);
|
|
1426
|
+
}
|
|
1427
|
+
else {
|
|
1428
|
+
printLine(runtime.stdout, [
|
|
1429
|
+
`Root: ${payload.root}`,
|
|
1430
|
+
`Stale: ${payload.guidance.stale ? "yes" : "no"}`,
|
|
1431
|
+
`Last synced: ${payload.guidance.lastSyncedAt ?? "-"}`,
|
|
1432
|
+
`Managed targets: ${payload.guidance.managedTargets.join(", ") || "-"}`,
|
|
1433
|
+
...payload.guidance.files.map((file) => `${file.path}: ${file.state}`),
|
|
1434
|
+
].join("\n"));
|
|
1435
|
+
}
|
|
1436
|
+
return 0;
|
|
1437
|
+
}
|
|
1438
|
+
case "sync": {
|
|
1439
|
+
const parsed = parseArgs({
|
|
1440
|
+
args: args.slice(1),
|
|
1441
|
+
allowPositionals: false,
|
|
1442
|
+
options: {
|
|
1443
|
+
json: { type: "boolean" },
|
|
1444
|
+
help: { type: "boolean", short: "h" },
|
|
1445
|
+
},
|
|
1446
|
+
});
|
|
1447
|
+
const common = mergeCommonOptions(inherited, {
|
|
1448
|
+
json: parsed.values.json,
|
|
1449
|
+
});
|
|
1450
|
+
if (parsed.values.help) {
|
|
1451
|
+
printGuidanceHelp(runtime);
|
|
1452
|
+
return 0;
|
|
1453
|
+
}
|
|
1454
|
+
const rootContext = await requireLocalRoot(runtime, common, {
|
|
1455
|
+
emitWarning: false,
|
|
1456
|
+
});
|
|
1457
|
+
const managedTargets = rootContext.root.config.guidance?.managedTargets !== undefined
|
|
1458
|
+
? normalizeGuidanceTargets(rootContext.root.config.guidance.managedTargets)
|
|
1459
|
+
: rootContext.guidance.managedTargets;
|
|
1460
|
+
const edits = [];
|
|
1461
|
+
const actions = new Map();
|
|
1462
|
+
for (const target of GUIDANCE_TARGETS) {
|
|
1463
|
+
if (!managedTargets.includes(target.key)) {
|
|
1464
|
+
actions.set(target.key, "skipped");
|
|
1465
|
+
continue;
|
|
1466
|
+
}
|
|
1467
|
+
const targetPath = join(rootContext.root.rootDir, target.relativePath);
|
|
1468
|
+
const nextContent = buildGuidanceFileContent(target.key, await readOptionalUtf8(targetPath));
|
|
1469
|
+
const edit = await buildPlannedEdit(targetPath, nextContent);
|
|
1470
|
+
if (edit) {
|
|
1471
|
+
edits.push(edit);
|
|
1472
|
+
actions.set(target.key, edit.action);
|
|
1473
|
+
}
|
|
1474
|
+
else {
|
|
1475
|
+
actions.set(target.key, "unchanged");
|
|
1476
|
+
}
|
|
1477
|
+
}
|
|
1478
|
+
if (edits.length > 0) {
|
|
1479
|
+
await writePlannedEdits(edits);
|
|
1480
|
+
}
|
|
1481
|
+
const syncedAt = toIsoString();
|
|
1482
|
+
const nextConfig = withUpdatedGuidanceConfig(rootContext.root.config, managedTargets, syncedAt);
|
|
1483
|
+
await runtime.config.writeLocalConfig(rootContext.root.rootDir, nextConfig);
|
|
1484
|
+
const nextRoot = {
|
|
1485
|
+
...rootContext.root,
|
|
1486
|
+
config: nextConfig,
|
|
1487
|
+
};
|
|
1488
|
+
const nextGuidance = await resolveGuidanceState(nextRoot);
|
|
1489
|
+
const guidance = {
|
|
1490
|
+
...nextGuidance,
|
|
1491
|
+
files: nextGuidance.files.map((file) => ({
|
|
1492
|
+
...file,
|
|
1493
|
+
action: actions.get(file.target) ?? "skipped",
|
|
1494
|
+
})),
|
|
1495
|
+
};
|
|
1496
|
+
const payload = {
|
|
1497
|
+
ok: true,
|
|
1498
|
+
root: nextRoot.rootDir,
|
|
1499
|
+
guidance,
|
|
1500
|
+
};
|
|
1501
|
+
if (common.json) {
|
|
1502
|
+
printJson(runtime.stdout, payload);
|
|
1503
|
+
}
|
|
1504
|
+
else {
|
|
1505
|
+
const updatedCount = guidance.files.filter((file) => file.action === "create" || file.action === "update").length;
|
|
1506
|
+
printLine(runtime.stdout, `Synchronized Corners guidance at ${payload.root}. Updated ${updatedCount} file(s).`);
|
|
1507
|
+
}
|
|
1508
|
+
return 0;
|
|
1509
|
+
}
|
|
1510
|
+
default:
|
|
1511
|
+
throw new CLIError(`Unknown guidance command: ${subcommand}`);
|
|
1512
|
+
}
|
|
1513
|
+
}
|
|
1310
1514
|
async function handleCorner(args, runtime, inherited) {
|
|
1311
1515
|
const subcommand = args[0];
|
|
1312
1516
|
if (!subcommand || subcommand === "help" || subcommand === "--help") {
|
|
@@ -1339,8 +1543,8 @@ async function handleCorner(args, runtime, inherited) {
|
|
|
1339
1543
|
if (!cornerNameOrId) {
|
|
1340
1544
|
throw new CLIError("Usage: corners corner use <cornerNameOrId> [--path <path>]", { json: common.json });
|
|
1341
1545
|
}
|
|
1342
|
-
const
|
|
1343
|
-
const { client } = await requirePinnedRootProfile(runtime, common,
|
|
1546
|
+
const rootContext = await requireLocalRoot(runtime, common);
|
|
1547
|
+
const { root, guidance, client } = await requirePinnedRootProfile(runtime, common, rootContext);
|
|
1344
1548
|
const corner = await resolveMemberCorner(client, common, cornerNameOrId);
|
|
1345
1549
|
const cwdPath = await realpath(runtime.cwd);
|
|
1346
1550
|
const targetAbsolutePath = resolvePathWithinRoot(root.rootDir, cwdPath, parsed.values.path);
|
|
@@ -1351,12 +1555,12 @@ async function handleCorner(args, runtime, inherited) {
|
|
|
1351
1555
|
});
|
|
1352
1556
|
await runtime.config.writeLocalConfig(root.rootDir, nextConfig);
|
|
1353
1557
|
if (common.json) {
|
|
1354
|
-
printJson(runtime.stdout, {
|
|
1558
|
+
printJson(runtime.stdout, withGuidanceJsonMetadata({
|
|
1355
1559
|
ok: true,
|
|
1356
1560
|
root: root.rootDir,
|
|
1357
1561
|
path: relativePath,
|
|
1358
1562
|
corner,
|
|
1359
|
-
});
|
|
1563
|
+
}, guidance));
|
|
1360
1564
|
}
|
|
1361
1565
|
else {
|
|
1362
1566
|
printLine(runtime.stdout, `Set default corner for ${relativePath} to ${corner.name}.`);
|
|
@@ -1394,8 +1598,8 @@ async function handleWorkstream(args, runtime, inherited) {
|
|
|
1394
1598
|
printWorkstreamHelp(runtime);
|
|
1395
1599
|
return 0;
|
|
1396
1600
|
}
|
|
1397
|
-
const
|
|
1398
|
-
const { client } = await requirePinnedRootProfile(runtime, common,
|
|
1601
|
+
const rootContext = await requireLocalRoot(runtime, common);
|
|
1602
|
+
const { root, guidance, client } = await requirePinnedRootProfile(runtime, common, rootContext);
|
|
1399
1603
|
const hydrated = await Promise.all(root.config.connectedWorkstreams.map(async (entry) => {
|
|
1400
1604
|
try {
|
|
1401
1605
|
return {
|
|
@@ -1417,11 +1621,11 @@ async function handleWorkstream(args, runtime, inherited) {
|
|
|
1417
1621
|
.filter((entry) => entry.workstream === null)
|
|
1418
1622
|
.map((entry) => entry.entry.id);
|
|
1419
1623
|
if (common.json) {
|
|
1420
|
-
printJson(runtime.stdout, {
|
|
1624
|
+
printJson(runtime.stdout, withGuidanceJsonMetadata({
|
|
1421
1625
|
root: root.rootDir,
|
|
1422
1626
|
workstreams,
|
|
1423
1627
|
missingWorkstreamIds,
|
|
1424
|
-
});
|
|
1628
|
+
}, guidance));
|
|
1425
1629
|
}
|
|
1426
1630
|
else {
|
|
1427
1631
|
if (missingWorkstreamIds.length > 0) {
|
|
@@ -1461,19 +1665,19 @@ async function handleWorkstream(args, runtime, inherited) {
|
|
|
1461
1665
|
json: common.json,
|
|
1462
1666
|
});
|
|
1463
1667
|
}
|
|
1464
|
-
const
|
|
1465
|
-
const { client } = await requirePinnedRootProfile(runtime, common,
|
|
1668
|
+
const rootContext = await requireLocalRoot(runtime, common);
|
|
1669
|
+
const { root, guidance, client } = await requirePinnedRootProfile(runtime, common, rootContext);
|
|
1466
1670
|
const workstream = await resolveExplicitWorkstream(client, common, workstreamId);
|
|
1467
1671
|
const nextConfig = connectWorkstream(root.config, workstream.id);
|
|
1468
1672
|
if (nextConfig !== root.config) {
|
|
1469
1673
|
await runtime.config.writeLocalConfig(root.rootDir, nextConfig);
|
|
1470
1674
|
}
|
|
1471
1675
|
if (common.json) {
|
|
1472
|
-
printJson(runtime.stdout, {
|
|
1676
|
+
printJson(runtime.stdout, withGuidanceJsonMetadata({
|
|
1473
1677
|
ok: true,
|
|
1474
1678
|
root: root.rootDir,
|
|
1475
1679
|
workstream,
|
|
1476
|
-
});
|
|
1680
|
+
}, guidance));
|
|
1477
1681
|
}
|
|
1478
1682
|
else {
|
|
1479
1683
|
printLine(runtime.stdout, `Connected ${workstream.id} (${workstream.name}) to ${root.rootDir}.`);
|
|
@@ -1496,7 +1700,7 @@ async function handleWorkstream(args, runtime, inherited) {
|
|
|
1496
1700
|
printWorkstreamHelp(runtime);
|
|
1497
1701
|
return 0;
|
|
1498
1702
|
}
|
|
1499
|
-
const root = await requireLocalRoot(runtime, common);
|
|
1703
|
+
const { root, guidance } = await requireLocalRoot(runtime, common);
|
|
1500
1704
|
const cwdPath = await realpath(runtime.cwd);
|
|
1501
1705
|
const resolvedCorner = resolveCornerForCwd(root, cwdPath);
|
|
1502
1706
|
const payload = {
|
|
@@ -1508,7 +1712,7 @@ async function handleWorkstream(args, runtime, inherited) {
|
|
|
1508
1712
|
connectedWorkstreamIds: root.config.connectedWorkstreams.map((entry) => entry.id),
|
|
1509
1713
|
};
|
|
1510
1714
|
if (common.json) {
|
|
1511
|
-
printJson(runtime.stdout, payload);
|
|
1715
|
+
printJson(runtime.stdout, withGuidanceJsonMetadata(payload, guidance));
|
|
1512
1716
|
}
|
|
1513
1717
|
else {
|
|
1514
1718
|
printLine(runtime.stdout, [
|
|
@@ -1548,8 +1752,8 @@ async function handleWorkstream(args, runtime, inherited) {
|
|
|
1548
1752
|
if (!name) {
|
|
1549
1753
|
throw new CLIError("Usage: corners workstream create <name> [--summary <text>] [--corner <cornerNameOrId>]", { json: common.json });
|
|
1550
1754
|
}
|
|
1551
|
-
const
|
|
1552
|
-
const { client } = await requirePinnedRootProfile(runtime, common,
|
|
1755
|
+
const rootContext = await requireLocalRoot(runtime, common);
|
|
1756
|
+
const { root, guidance, client } = await requirePinnedRootProfile(runtime, common, rootContext);
|
|
1553
1757
|
const cwdPath = await realpath(runtime.cwd);
|
|
1554
1758
|
const corner = parsed.values.corner
|
|
1555
1759
|
? await resolveMemberCorner(client, common, parsed.values.corner)
|
|
@@ -1566,12 +1770,12 @@ async function handleWorkstream(args, runtime, inherited) {
|
|
|
1566
1770
|
await runtime.config.writeLocalConfig(root.rootDir, nextConfig);
|
|
1567
1771
|
}
|
|
1568
1772
|
if (common.json) {
|
|
1569
|
-
printJson(runtime.stdout, {
|
|
1773
|
+
printJson(runtime.stdout, withGuidanceJsonMetadata({
|
|
1570
1774
|
ok: true,
|
|
1571
1775
|
root: root.rootDir,
|
|
1572
1776
|
corner,
|
|
1573
1777
|
workstream: result.createWorkstream,
|
|
1574
|
-
});
|
|
1778
|
+
}, guidance));
|
|
1575
1779
|
}
|
|
1576
1780
|
else {
|
|
1577
1781
|
printLine(runtime.stdout, `Created ${result.createWorkstream.id} (${result.createWorkstream.name}) in ${corner.name}.`);
|
|
@@ -1604,7 +1808,7 @@ async function handleWorkstream(args, runtime, inherited) {
|
|
|
1604
1808
|
json: common.json,
|
|
1605
1809
|
});
|
|
1606
1810
|
}
|
|
1607
|
-
const { client } = await requireCommandProfile(runtime, common);
|
|
1811
|
+
const { guidance, client } = await requireCommandProfile(runtime, common);
|
|
1608
1812
|
const workstream = await resolveExplicitWorkstream(client, common, workstreamId);
|
|
1609
1813
|
const data = await client.graphql(WORKSTREAM_PULL_QUERY, {
|
|
1610
1814
|
id: workstream.id,
|
|
@@ -1612,13 +1816,16 @@ async function handleWorkstream(args, runtime, inherited) {
|
|
|
1612
1816
|
feedFirst: 20,
|
|
1613
1817
|
});
|
|
1614
1818
|
if (common.json) {
|
|
1615
|
-
printJson(runtime.stdout, data.workstream);
|
|
1819
|
+
printJson(runtime.stdout, withGuidanceJsonMetadata(data.workstream, guidance));
|
|
1616
1820
|
}
|
|
1617
1821
|
else {
|
|
1618
1822
|
const snapshot = data.workstream;
|
|
1619
1823
|
printLine(runtime.stdout, [
|
|
1620
1824
|
`${snapshot.name} (${snapshot.id})`,
|
|
1621
1825
|
snapshot.summary ? `Summary: ${snapshot.summary}` : "Summary: -",
|
|
1826
|
+
`State: ${snapshot.isOpen === false ? "archived" : "open"}`,
|
|
1827
|
+
`Lifecycle status: ${(snapshot.status ?? "SCOPING").toLowerCase()}`,
|
|
1828
|
+
`Status details: ${snapshot.statusDetails ?? "-"}`,
|
|
1622
1829
|
`Open questions: ${snapshot.openQuestions?.length ?? 0}`,
|
|
1623
1830
|
`Answered questions: ${snapshot.answeredQuestions?.length ?? 0}`,
|
|
1624
1831
|
`Attachments: ${snapshot.attachments?.totalCount ?? 0}`,
|
|
@@ -1627,6 +1834,75 @@ async function handleWorkstream(args, runtime, inherited) {
|
|
|
1627
1834
|
}
|
|
1628
1835
|
return 0;
|
|
1629
1836
|
}
|
|
1837
|
+
case "update": {
|
|
1838
|
+
const parsed = parseArgs({
|
|
1839
|
+
args: args.slice(1),
|
|
1840
|
+
allowPositionals: true,
|
|
1841
|
+
options: {
|
|
1842
|
+
json: { type: "boolean" },
|
|
1843
|
+
help: { type: "boolean", short: "h" },
|
|
1844
|
+
profile: { type: "string" },
|
|
1845
|
+
"api-url": { type: "string" },
|
|
1846
|
+
status: { type: "string" },
|
|
1847
|
+
"status-details": { type: "string" },
|
|
1848
|
+
"clear-status-details": { type: "boolean" },
|
|
1849
|
+
},
|
|
1850
|
+
});
|
|
1851
|
+
const common = mergeCommonOptions(inherited, {
|
|
1852
|
+
json: parsed.values.json,
|
|
1853
|
+
profile: parsed.values.profile,
|
|
1854
|
+
apiUrl: parsed.values["api-url"],
|
|
1855
|
+
});
|
|
1856
|
+
if (parsed.values.help) {
|
|
1857
|
+
printWorkstreamHelp(runtime);
|
|
1858
|
+
return 0;
|
|
1859
|
+
}
|
|
1860
|
+
const workstreamId = parsed.positionals[0];
|
|
1861
|
+
if (!workstreamId) {
|
|
1862
|
+
throw new CLIError("Usage: corners workstream update <workstreamId> [--status <status>] [--status-details <text> | --clear-status-details]", { json: common.json });
|
|
1863
|
+
}
|
|
1864
|
+
const rawStatusDetails = parsed.values["status-details"];
|
|
1865
|
+
const clearStatusDetails = parsed.values["clear-status-details"] === true;
|
|
1866
|
+
if (rawStatusDetails !== undefined && clearStatusDetails) {
|
|
1867
|
+
throw new CLIError("Choose either --status-details or --clear-status-details, not both.", { json: common.json });
|
|
1868
|
+
}
|
|
1869
|
+
if (parsed.values.status === undefined &&
|
|
1870
|
+
rawStatusDetails === undefined &&
|
|
1871
|
+
!clearStatusDetails) {
|
|
1872
|
+
throw new CLIError("Provide --status, --status-details, or --clear-status-details.", { json: common.json });
|
|
1873
|
+
}
|
|
1874
|
+
const { guidance, client } = await requireCommandProfile(runtime, common);
|
|
1875
|
+
const workstream = await resolveExplicitWorkstream(client, common, workstreamId);
|
|
1876
|
+
const result = await client.graphql(UPDATE_WORKSTREAM_MUTATION, {
|
|
1877
|
+
id: workstream.id,
|
|
1878
|
+
input: {
|
|
1879
|
+
status: parsed.values.status === undefined
|
|
1880
|
+
? undefined
|
|
1881
|
+
: toGraphQLWorkstreamStatus(parsed.values.status),
|
|
1882
|
+
statusDetails: clearStatusDetails
|
|
1883
|
+
? null
|
|
1884
|
+
: rawStatusDetails === undefined
|
|
1885
|
+
? undefined
|
|
1886
|
+
: rawStatusDetails,
|
|
1887
|
+
},
|
|
1888
|
+
});
|
|
1889
|
+
const payload = {
|
|
1890
|
+
ok: true,
|
|
1891
|
+
workstream: result.updateWorkstream,
|
|
1892
|
+
};
|
|
1893
|
+
if (common.json) {
|
|
1894
|
+
printJson(runtime.stdout, withGuidanceJsonMetadata(payload, guidance));
|
|
1895
|
+
}
|
|
1896
|
+
else {
|
|
1897
|
+
printLine(runtime.stdout, [
|
|
1898
|
+
`Updated ${result.updateWorkstream.id}.`,
|
|
1899
|
+
`State: ${result.updateWorkstream.isOpen ? "open" : "archived"}`,
|
|
1900
|
+
`Lifecycle status: ${result.updateWorkstream.status.toLowerCase()}`,
|
|
1901
|
+
`Status details: ${result.updateWorkstream.statusDetails ?? "-"}`,
|
|
1902
|
+
].join("\n"));
|
|
1903
|
+
}
|
|
1904
|
+
return 0;
|
|
1905
|
+
}
|
|
1630
1906
|
case "push": {
|
|
1631
1907
|
const parsed = parseArgs({
|
|
1632
1908
|
args: args.slice(1),
|
|
@@ -1665,7 +1941,7 @@ async function handleWorkstream(args, runtime, inherited) {
|
|
|
1665
1941
|
if (!message) {
|
|
1666
1942
|
throw new CLIError("Workstream updates need a message. Use --message or pipe text on stdin.", { json: common.json });
|
|
1667
1943
|
}
|
|
1668
|
-
const { client } = await requireCommandProfile(runtime, common);
|
|
1944
|
+
const { guidance, client } = await requireCommandProfile(runtime, common);
|
|
1669
1945
|
const workstream = await resolveExplicitWorkstream(client, common, workstreamId);
|
|
1670
1946
|
let createdDocument = null;
|
|
1671
1947
|
if (parsed.values.file) {
|
|
@@ -1696,7 +1972,7 @@ async function handleWorkstream(args, runtime, inherited) {
|
|
|
1696
1972
|
document: createdDocument,
|
|
1697
1973
|
};
|
|
1698
1974
|
if (common.json) {
|
|
1699
|
-
printJson(runtime.stdout, payload);
|
|
1975
|
+
printJson(runtime.stdout, withGuidanceJsonMetadata(payload, guidance));
|
|
1700
1976
|
}
|
|
1701
1977
|
else {
|
|
1702
1978
|
printLine(runtime.stdout, `Recorded ${String(parsed.values.type ?? "status")} update on ${workstream.id}.`);
|
|
@@ -1734,7 +2010,7 @@ async function handleWorkstream(args, runtime, inherited) {
|
|
|
1734
2010
|
if (!workstreamId) {
|
|
1735
2011
|
throw new CLIError("Usage: corners workstream question list <workstreamId>", { json: common.json });
|
|
1736
2012
|
}
|
|
1737
|
-
const { client } = await requireCommandProfile(runtime, common);
|
|
2013
|
+
const { guidance, client } = await requireCommandProfile(runtime, common);
|
|
1738
2014
|
const workstream = await resolveExplicitWorkstream(client, common, workstreamId);
|
|
1739
2015
|
const data = await client.graphql(WORKSTREAM_QUESTION_LIST_QUERY, {
|
|
1740
2016
|
id: workstream.id,
|
|
@@ -1743,7 +2019,7 @@ async function handleWorkstream(args, runtime, inherited) {
|
|
|
1743
2019
|
throw new CLIError("Workstream not found", { json: common.json });
|
|
1744
2020
|
}
|
|
1745
2021
|
if (common.json) {
|
|
1746
|
-
printJson(runtime.stdout, data.workstream);
|
|
2022
|
+
printJson(runtime.stdout, withGuidanceJsonMetadata(data.workstream, guidance));
|
|
1747
2023
|
}
|
|
1748
2024
|
else {
|
|
1749
2025
|
printLine(runtime.stdout, [
|
|
@@ -1789,7 +2065,7 @@ async function handleWorkstream(args, runtime, inherited) {
|
|
|
1789
2065
|
if (!question) {
|
|
1790
2066
|
throw new CLIError("Question text is required. Use --question or pipe text on stdin.", { json: common.json });
|
|
1791
2067
|
}
|
|
1792
|
-
const { client } = await requireCommandProfile(runtime, common);
|
|
2068
|
+
const { guidance, client } = await requireCommandProfile(runtime, common);
|
|
1793
2069
|
const workstream = await resolveExplicitWorkstream(client, common, workstreamId);
|
|
1794
2070
|
const result = await client.graphql(CREATE_WORKSTREAM_QUESTION_MUTATION, {
|
|
1795
2071
|
input: {
|
|
@@ -1800,7 +2076,7 @@ async function handleWorkstream(args, runtime, inherited) {
|
|
|
1800
2076
|
},
|
|
1801
2077
|
});
|
|
1802
2078
|
if (common.json) {
|
|
1803
|
-
printJson(runtime.stdout, result.createWorkstreamQuestion);
|
|
2079
|
+
printJson(runtime.stdout, withGuidanceJsonMetadata(result.createWorkstreamQuestion, guidance));
|
|
1804
2080
|
}
|
|
1805
2081
|
else {
|
|
1806
2082
|
printLine(runtime.stdout, `Created question on ${workstream.id}.`);
|
|
@@ -1841,13 +2117,13 @@ async function handleWorkstream(args, runtime, inherited) {
|
|
|
1841
2117
|
json: common.json,
|
|
1842
2118
|
});
|
|
1843
2119
|
}
|
|
1844
|
-
const { client } = await requireCommandProfile(runtime, common);
|
|
2120
|
+
const { guidance, client } = await requireCommandProfile(runtime, common);
|
|
1845
2121
|
const result = await client.graphql(ANSWER_WORKSTREAM_QUESTION_MUTATION, {
|
|
1846
2122
|
questionId,
|
|
1847
2123
|
answerText: answer,
|
|
1848
2124
|
});
|
|
1849
2125
|
if (common.json) {
|
|
1850
|
-
printJson(runtime.stdout, result.answerWorkstreamQuestion);
|
|
2126
|
+
printJson(runtime.stdout, withGuidanceJsonMetadata(result.answerWorkstreamQuestion, guidance));
|
|
1851
2127
|
}
|
|
1852
2128
|
else {
|
|
1853
2129
|
printLine(runtime.stdout, `Answered ${questionId}.`);
|
|
@@ -1886,7 +2162,7 @@ async function handleWorkstream(args, runtime, inherited) {
|
|
|
1886
2162
|
if (!workstreamId || !kind || !entityId) {
|
|
1887
2163
|
throw new CLIError("Usage: corners workstream attach <workstreamId> --kind <kind> --entity-id <id>", { json: common.json });
|
|
1888
2164
|
}
|
|
1889
|
-
const { client } = await requireCommandProfile(runtime, common);
|
|
2165
|
+
const { guidance, client } = await requireCommandProfile(runtime, common);
|
|
1890
2166
|
const workstream = await resolveExplicitWorkstream(client, common, workstreamId);
|
|
1891
2167
|
const result = await client.graphql(ADD_WORKSTREAM_ATTACHMENT_MUTATION, {
|
|
1892
2168
|
workstreamId: workstream.id,
|
|
@@ -1894,7 +2170,7 @@ async function handleWorkstream(args, runtime, inherited) {
|
|
|
1894
2170
|
entityId,
|
|
1895
2171
|
});
|
|
1896
2172
|
if (common.json) {
|
|
1897
|
-
printJson(runtime.stdout, result.addWorkstreamAttachment);
|
|
2173
|
+
printJson(runtime.stdout, withGuidanceJsonMetadata(result.addWorkstreamAttachment, guidance));
|
|
1898
2174
|
}
|
|
1899
2175
|
else {
|
|
1900
2176
|
printLine(runtime.stdout, `Attached ${kind}:${entityId} to ${workstream.id}.`);
|
|
@@ -1930,7 +2206,7 @@ async function handleWorkstream(args, runtime, inherited) {
|
|
|
1930
2206
|
if (!threadId || !text) {
|
|
1931
2207
|
throw new CLIError("Usage: corners workstream reply-thread <threadId> [--text <text>]", { json: common.json });
|
|
1932
2208
|
}
|
|
1933
|
-
const { client } = await requireCommandProfile(runtime, common);
|
|
2209
|
+
const { guidance, client } = await requireCommandProfile(runtime, common);
|
|
1934
2210
|
const result = await client.graphql(REPLY_ARTIFACT_THREAD_MUTATION, {
|
|
1935
2211
|
id: threadId,
|
|
1936
2212
|
input: {
|
|
@@ -1938,7 +2214,7 @@ async function handleWorkstream(args, runtime, inherited) {
|
|
|
1938
2214
|
},
|
|
1939
2215
|
});
|
|
1940
2216
|
if (common.json) {
|
|
1941
|
-
printJson(runtime.stdout, result.replyArtifactThread);
|
|
2217
|
+
printJson(runtime.stdout, withGuidanceJsonMetadata(result.replyArtifactThread, guidance));
|
|
1942
2218
|
}
|
|
1943
2219
|
else {
|
|
1944
2220
|
printLine(runtime.stdout, `Replied to ${threadId}.`);
|
|
@@ -1970,6 +2246,9 @@ export async function runCli(argv, runtime = createRuntime()) {
|
|
|
1970
2246
|
if (parsed.rest[1] === "auth") {
|
|
1971
2247
|
printAuthHelp(runtime);
|
|
1972
2248
|
}
|
|
2249
|
+
else if (parsed.rest[1] === "guidance") {
|
|
2250
|
+
printGuidanceHelp(runtime);
|
|
2251
|
+
}
|
|
1973
2252
|
else if (parsed.rest[1] === "init") {
|
|
1974
2253
|
printInitHelp(runtime);
|
|
1975
2254
|
}
|
|
@@ -1991,6 +2270,8 @@ export async function runCli(argv, runtime = createRuntime()) {
|
|
|
1991
2270
|
return 0;
|
|
1992
2271
|
case "init":
|
|
1993
2272
|
return handleInit(parsed.rest.slice(1), runtime, parsed.common);
|
|
2273
|
+
case "guidance":
|
|
2274
|
+
return handleGuidance(parsed.rest.slice(1), runtime, parsed.common);
|
|
1994
2275
|
case "auth":
|
|
1995
2276
|
return handleAuth(parsed.rest.slice(1), runtime, parsed.common);
|
|
1996
2277
|
case "corner":
|