@mytegroupinc/myte-core 0.0.4 → 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/README.md +20 -0
- package/cli.js +263 -6
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -3,9 +3,12 @@
|
|
|
3
3
|
Internal implementation package for the `myte` CLI.
|
|
4
4
|
|
|
5
5
|
Most users should install the unscoped wrapper instead:
|
|
6
|
+
- `npm install myte` then `npx myte bootstrap`
|
|
6
7
|
- `npm install myte` then `npx myte query "..." --with-diff`
|
|
7
8
|
- `npm install myte` then `npm exec myte -- query "..." --with-diff`
|
|
9
|
+
- `npm i -g myte` then `myte bootstrap`
|
|
8
10
|
- `npm i -g myte` then `myte query "..." --with-diff`
|
|
11
|
+
- `npx myte@latest bootstrap`
|
|
9
12
|
- `npx myte@latest query "..." --with-diff`
|
|
10
13
|
- `npm install myte` then `npx myte create-prd ./drafts/auth-prd.md`
|
|
11
14
|
- `cat ./drafts/auth-prd.md | npx myte create-prd --stdin`
|
|
@@ -20,6 +23,9 @@ Requirements:
|
|
|
20
23
|
Notes:
|
|
21
24
|
- `npm install myte` installs the wrapper locally; use `npx myte` or `npm exec myte -- ...` to run it.
|
|
22
25
|
- `npm install myte` means the CLI is available locally; bare `myte ...` still requires a global install.
|
|
26
|
+
- `bootstrap` is a local file materialization path, not a hosted file download.
|
|
27
|
+
- `bootstrap` expects to run from a wrapper root that contains the project's configured repo folders.
|
|
28
|
+
- `bootstrap` writes `MyteCommandCenter/data/phases`, `epics`, `stories`, `missions`, `project.yml`, and `bootstrap-manifest.json`.
|
|
23
29
|
- `create-prd` is a deterministic PRD upload path, not an LLM generation command.
|
|
24
30
|
- `--with-diff` only searches repo folders whose names match the project repo names configured in Myte.
|
|
25
31
|
- `--with-diff` includes per-repo diagnostics in `print-context` payload:
|
|
@@ -28,4 +34,18 @@ Notes:
|
|
|
28
34
|
- clean/no-change repo summaries
|
|
29
35
|
- `--with-diff` query payload includes `diff_diagnostics` so backend/UI can report exactly why context may be missing.
|
|
30
36
|
|
|
37
|
+
Deterministic `create-prd` contract:
|
|
38
|
+
- Required: `MYTE_API_KEY`, a PRD markdown body, and a title.
|
|
39
|
+
- Title source: `myte-kanban.title`, the first markdown `# Heading`, or `--title`.
|
|
40
|
+
- Description source: `myte-kanban.description` or `--description`.
|
|
41
|
+
- The markdown body is stored verbatim as PRD content and is what the backend uses to build the PRD DOCX.
|
|
42
|
+
- Legacy `feedback_text` is still accepted for older payloads, but new callers should use `description`.
|
|
43
|
+
- Optional structured fields: `priority`, `status`, `tags`, `assigned_user_email`, `assigned_user_id`, `due_date`, `repo_name`, `repo_id`, `preview_url`, `source`.
|
|
44
|
+
|
|
45
|
+
Examples:
|
|
46
|
+
- `npx myte bootstrap`
|
|
47
|
+
- `npx myte bootstrap --dry-run --json`
|
|
48
|
+
- `npx myte create-prd ./drafts/auth-prd.md --description "Short card summary"`
|
|
49
|
+
- `npx myte create-prd ./drafts/auth-prd.md --print-context`
|
|
50
|
+
|
|
31
51
|
This package is published under the org scope for governance; the public `myte` wrapper delegates here.
|
package/cli.js
CHANGED
|
@@ -49,7 +49,7 @@ function loadEnv() {
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
function splitCommand(argv) {
|
|
52
|
-
const known = new Set(["query", "ask", "chat", "config", "create-prd", "add-prd", "prd", "help", "--help", "-h"]);
|
|
52
|
+
const known = new Set(["query", "ask", "chat", "config", "bootstrap", "create-prd", "add-prd", "prd", "help", "--help", "-h"]);
|
|
53
53
|
const first = argv[0];
|
|
54
54
|
if (first && known.has(first)) {
|
|
55
55
|
const cmd = first === "--help" || first === "-h" ? "help" : first;
|
|
@@ -63,7 +63,7 @@ function parseArgs(argv) {
|
|
|
63
63
|
// eslint-disable-next-line global-require
|
|
64
64
|
return require("minimist")(argv, {
|
|
65
65
|
boolean: ["with-diff", "diff", "print-context", "dry-run", "fetch", "json", "stdin"],
|
|
66
|
-
string: ["query", "q", "context", "ctx", "base-url", "timeout-ms", "diff-limit", "title"],
|
|
66
|
+
string: ["query", "q", "context", "ctx", "base-url", "timeout-ms", "diff-limit", "title", "description", "feedback-text", "output-dir"],
|
|
67
67
|
alias: {
|
|
68
68
|
q: "query",
|
|
69
69
|
d: "with-diff",
|
|
@@ -116,10 +116,11 @@ function printHelp() {
|
|
|
116
116
|
"Usage:",
|
|
117
117
|
" myte query \"<text>\" [--with-diff] [--context \"...\"]",
|
|
118
118
|
" myte config [--json]",
|
|
119
|
+
" myte bootstrap [--output-dir ./MyteCommandCenter] [--json]",
|
|
119
120
|
" myte chat",
|
|
120
|
-
" myte create-prd <file.md> [--json]",
|
|
121
|
+
" myte create-prd <file.md> [--json] [--title \"...\"] [--description \"...\"]",
|
|
121
122
|
" myte add-prd <file.md> [--json]",
|
|
122
|
-
" cat file.md | myte create-prd --stdin [--title \"...\"]",
|
|
123
|
+
" cat file.md | myte create-prd --stdin [--title \"...\"] [--description \"...\"]",
|
|
123
124
|
"",
|
|
124
125
|
"Run forms:",
|
|
125
126
|
" npm install myte then npx myte query \"...\" --with-diff",
|
|
@@ -130,19 +131,34 @@ function printHelp() {
|
|
|
130
131
|
"Auth:",
|
|
131
132
|
" - Set MYTE_API_KEY in a workspace .env (or env var)",
|
|
132
133
|
"",
|
|
134
|
+
"bootstrap contract:",
|
|
135
|
+
" - Run from the wrapper root that contains the project's configured repo folders",
|
|
136
|
+
" - Writes MyteCommandCenter/data/phases, epics, stories, and missions locally",
|
|
137
|
+
" - Uses the project-scoped bootstrap snapshot from the Myte API",
|
|
138
|
+
"",
|
|
139
|
+
"create-prd contract:",
|
|
140
|
+
" - Required: valid MYTE_API_KEY, PRD markdown body, title",
|
|
141
|
+
" - Title source: myte-kanban.title, first # heading, or --title",
|
|
142
|
+
" - Description source: myte-kanban.description or --description",
|
|
143
|
+
" - PRD DOCX content: the markdown body is stored verbatim",
|
|
144
|
+
"",
|
|
133
145
|
"Options:",
|
|
134
146
|
" --with-diff Include deterministic git diffs (project-scoped)",
|
|
135
147
|
" --diff-limit <chars> Truncate diff context to N chars (default: 200000)",
|
|
136
148
|
" --timeout-ms <ms> Request timeout (default: 300000)",
|
|
137
149
|
" --base-url <url> API base (default: https://api.myte.dev)",
|
|
150
|
+
" --output-dir <path> Bootstrap output directory (default: <wrapper-root>/MyteCommandCenter)",
|
|
138
151
|
" --stdin Read PRD content from stdin instead of a file path",
|
|
139
|
-
" --title <text>
|
|
152
|
+
" --title <text> Override PRD title for raw markdown uploads",
|
|
153
|
+
" --description <text> Set feedback description/card summary for raw markdown uploads",
|
|
140
154
|
" --print-context Print JSON payload and exit (no query call)",
|
|
141
155
|
" --no-fetch Don't git fetch origin main/master before diff",
|
|
142
156
|
"",
|
|
143
157
|
"Examples:",
|
|
144
158
|
" myte query \"What changed in logging?\" --with-diff",
|
|
145
|
-
" myte
|
|
159
|
+
" myte bootstrap",
|
|
160
|
+
" myte bootstrap --output-dir ./MyteCommandCenter",
|
|
161
|
+
" myte create-prd ./drafts/auth-prd.md --description \"Short card summary\"",
|
|
146
162
|
" cat ./drafts/auth-prd.md | myte create-prd --stdin",
|
|
147
163
|
" myte config",
|
|
148
164
|
].join("\n");
|
|
@@ -695,6 +711,28 @@ async function fetchProjectConfig({ apiBase, key, timeoutMs }) {
|
|
|
695
711
|
return body.data || {};
|
|
696
712
|
}
|
|
697
713
|
|
|
714
|
+
async function fetchBootstrapSnapshot({ apiBase, key, timeoutMs }) {
|
|
715
|
+
const fetchFn = await getFetch();
|
|
716
|
+
const url = `${apiBase}/project-assistant/bootstrap`;
|
|
717
|
+
const { resp, body } = await fetchJsonWithTimeout(
|
|
718
|
+
fetchFn,
|
|
719
|
+
url,
|
|
720
|
+
{
|
|
721
|
+
method: "GET",
|
|
722
|
+
headers: { Authorization: `Bearer ${key}` },
|
|
723
|
+
},
|
|
724
|
+
timeoutMs
|
|
725
|
+
);
|
|
726
|
+
|
|
727
|
+
if (!resp.ok || body.status !== "success") {
|
|
728
|
+
const msg = body?.message || `Bootstrap request failed (${resp.status})`;
|
|
729
|
+
const err = new Error(msg);
|
|
730
|
+
err.status = resp.status;
|
|
731
|
+
throw err;
|
|
732
|
+
}
|
|
733
|
+
return body.data || {};
|
|
734
|
+
}
|
|
735
|
+
|
|
698
736
|
async function callAssistantQuery({ apiBase, key, payload, timeoutMs, endpoint = "/project-assistant/query" }) {
|
|
699
737
|
const fetchFn = await getFetch();
|
|
700
738
|
const url = `${apiBase}${endpoint}`;
|
|
@@ -721,6 +759,121 @@ async function callAssistantQuery({ apiBase, key, payload, timeoutMs, endpoint =
|
|
|
721
759
|
return body.data || {};
|
|
722
760
|
}
|
|
723
761
|
|
|
762
|
+
function ensureDir(dirPath) {
|
|
763
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
function clearYamlDirectory(dirPath) {
|
|
767
|
+
if (!fs.existsSync(dirPath)) {
|
|
768
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
769
|
+
return;
|
|
770
|
+
}
|
|
771
|
+
for (const entry of fs.readdirSync(dirPath, { withFileTypes: true })) {
|
|
772
|
+
if (!entry.isFile()) continue;
|
|
773
|
+
if (!entry.name.toLowerCase().endsWith(".yml")) continue;
|
|
774
|
+
fs.rmSync(path.join(dirPath, entry.name), { force: true });
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
function stableItemId(item, keys, fallback) {
|
|
779
|
+
for (const key of keys) {
|
|
780
|
+
const value = String(item?.[key] || "").trim();
|
|
781
|
+
if (value) return value;
|
|
782
|
+
}
|
|
783
|
+
return fallback;
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
function stringifyYaml(value) {
|
|
787
|
+
// eslint-disable-next-line global-require
|
|
788
|
+
const YAML = require("yaml");
|
|
789
|
+
return YAML.stringify(value, { lineWidth: 0 });
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
function writeYamlFile(filePath, value) {
|
|
793
|
+
ensureDir(path.dirname(filePath));
|
|
794
|
+
fs.writeFileSync(filePath, stringifyYaml(value), "utf8");
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
function writeJsonFile(filePath, value) {
|
|
798
|
+
ensureDir(path.dirname(filePath));
|
|
799
|
+
fs.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`, "utf8");
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
function resolveBootstrapWorkspace(repoNames) {
|
|
803
|
+
const resolved = resolveConfiguredRepos(repoNames);
|
|
804
|
+
if (!resolved.root || !Array.isArray(resolved.repos) || !resolved.repos.length) {
|
|
805
|
+
const names = Array.isArray(repoNames) ? repoNames.join(", ") : "";
|
|
806
|
+
throw new Error(
|
|
807
|
+
`No configured project repos were found from the current workspace. Expected child folders matching: ${names || "(none)"}`
|
|
808
|
+
);
|
|
809
|
+
}
|
|
810
|
+
return resolved;
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
function writeBootstrapSnapshot({ snapshot, wrapperRoot, outputDir }) {
|
|
814
|
+
const targetRoot = outputDir
|
|
815
|
+
? path.resolve(process.cwd(), String(outputDir))
|
|
816
|
+
: path.join(wrapperRoot, "MyteCommandCenter");
|
|
817
|
+
const dataRoot = path.join(targetRoot, "data");
|
|
818
|
+
const phasesDir = path.join(dataRoot, "phases");
|
|
819
|
+
const epicsDir = path.join(dataRoot, "epics");
|
|
820
|
+
const storiesDir = path.join(dataRoot, "stories");
|
|
821
|
+
const missionsDir = path.join(dataRoot, "missions");
|
|
822
|
+
|
|
823
|
+
ensureDir(dataRoot);
|
|
824
|
+
clearYamlDirectory(phasesDir);
|
|
825
|
+
clearYamlDirectory(epicsDir);
|
|
826
|
+
clearYamlDirectory(storiesDir);
|
|
827
|
+
clearYamlDirectory(missionsDir);
|
|
828
|
+
|
|
829
|
+
const phases = Array.isArray(snapshot.phases) ? snapshot.phases : [];
|
|
830
|
+
const epics = Array.isArray(snapshot.epics) ? snapshot.epics : [];
|
|
831
|
+
const stories = Array.isArray(snapshot.stories) ? snapshot.stories : [];
|
|
832
|
+
const missions = Array.isArray(snapshot.missions) ? snapshot.missions : [];
|
|
833
|
+
|
|
834
|
+
phases.forEach((phase, index) => {
|
|
835
|
+
const phaseId = stableItemId(phase, ["phase_id", "id"], `P${String(index + 1).padStart(3, "0")}`);
|
|
836
|
+
writeYamlFile(path.join(phasesDir, `${phaseId}.yml`), phase);
|
|
837
|
+
});
|
|
838
|
+
epics.forEach((epic, index) => {
|
|
839
|
+
const epicId = stableItemId(epic, ["epic_id", "id"], `E${String(index + 1).padStart(3, "0")}`);
|
|
840
|
+
writeYamlFile(path.join(epicsDir, `${epicId}.yml`), epic);
|
|
841
|
+
});
|
|
842
|
+
stories.forEach((story, index) => {
|
|
843
|
+
const storyId = stableItemId(story, ["story_id", "id"], `S${String(index + 1).padStart(3, "0")}`);
|
|
844
|
+
writeYamlFile(path.join(storiesDir, `${storyId}.yml`), story);
|
|
845
|
+
});
|
|
846
|
+
missions.forEach((mission, index) => {
|
|
847
|
+
const missionId = stableItemId(mission, ["mission_id", "id", "_id"], `M${String(index + 1).padStart(3, "0")}`);
|
|
848
|
+
writeYamlFile(path.join(missionsDir, `${missionId}.yml`), mission);
|
|
849
|
+
});
|
|
850
|
+
|
|
851
|
+
if (snapshot.project && typeof snapshot.project === "object") {
|
|
852
|
+
writeYamlFile(path.join(dataRoot, "project.yml"), snapshot.project);
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
const manifest = {
|
|
856
|
+
schema_version: snapshot.schema_version || 1,
|
|
857
|
+
generated_at: snapshot.generated_at || null,
|
|
858
|
+
snapshot_hash: snapshot.snapshot_hash || null,
|
|
859
|
+
project: snapshot.project || null,
|
|
860
|
+
repo_names: Array.isArray(snapshot.repo_names) ? snapshot.repo_names : [],
|
|
861
|
+
counts: {
|
|
862
|
+
phases: phases.length,
|
|
863
|
+
epics: epics.length,
|
|
864
|
+
stories: stories.length,
|
|
865
|
+
missions: missions.length,
|
|
866
|
+
},
|
|
867
|
+
};
|
|
868
|
+
writeJsonFile(path.join(dataRoot, "bootstrap-manifest.json"), manifest);
|
|
869
|
+
|
|
870
|
+
return {
|
|
871
|
+
targetRoot,
|
|
872
|
+
dataRoot,
|
|
873
|
+
manifest,
|
|
874
|
+
};
|
|
875
|
+
}
|
|
876
|
+
|
|
724
877
|
async function runCreatePrd(args) {
|
|
725
878
|
const key = (process.env.MYTE_API_KEY || process.env.MYTE_PROJECT_API_KEY || "").trim();
|
|
726
879
|
if (!key) {
|
|
@@ -766,6 +919,7 @@ async function runCreatePrd(args) {
|
|
|
766
919
|
}
|
|
767
920
|
|
|
768
921
|
const inferredTitle = String(args.title || extractMarkdownTitle(trimmedSource) || (!useStdin && filePath ? path.parse(filePath).name : "")).trim();
|
|
922
|
+
const description = String(args.description || args["feedback-text"] || args.feedbackText || "").trim();
|
|
769
923
|
const payload = isMyteKanbanTicket(trimmedSource)
|
|
770
924
|
? {
|
|
771
925
|
ticket_markdown: trimmedSource,
|
|
@@ -775,6 +929,10 @@ async function runCreatePrd(args) {
|
|
|
775
929
|
title: inferredTitle,
|
|
776
930
|
};
|
|
777
931
|
|
|
932
|
+
if (!payload.ticket_markdown && description) {
|
|
933
|
+
payload.description = description;
|
|
934
|
+
}
|
|
935
|
+
|
|
778
936
|
if (!payload.ticket_markdown && !payload.title) {
|
|
779
937
|
console.error("A title is required when uploading raw markdown without a myte-kanban metadata block. Use --title or add a top-level # heading.");
|
|
780
938
|
process.exit(1);
|
|
@@ -874,6 +1032,100 @@ async function runConfig(args) {
|
|
|
874
1032
|
}
|
|
875
1033
|
}
|
|
876
1034
|
|
|
1035
|
+
async function runBootstrap(args) {
|
|
1036
|
+
const key = (process.env.MYTE_API_KEY || process.env.MYTE_PROJECT_API_KEY || "").trim();
|
|
1037
|
+
if (!key) {
|
|
1038
|
+
console.error("Missing MYTE_API_KEY (project key) in environment/.env");
|
|
1039
|
+
process.exit(1);
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
const timeoutRaw = args["timeout-ms"] || args.timeoutMs || args.timeout_ms;
|
|
1043
|
+
const timeoutParsed = timeoutRaw !== undefined ? Number(timeoutRaw) : 300_000;
|
|
1044
|
+
const timeoutMs = Number.isFinite(timeoutParsed) ? timeoutParsed : 300_000;
|
|
1045
|
+
|
|
1046
|
+
const baseRaw = args["base-url"] || args.baseUrl || args.base_url || process.env.MYTE_API_BASE || DEFAULT_API_BASE;
|
|
1047
|
+
const apiBase = normalizeApiBase(baseRaw);
|
|
1048
|
+
|
|
1049
|
+
let snapshot;
|
|
1050
|
+
try {
|
|
1051
|
+
snapshot = await fetchBootstrapSnapshot({ apiBase, key, timeoutMs });
|
|
1052
|
+
} catch (err) {
|
|
1053
|
+
console.error("Failed to fetch bootstrap snapshot:", err?.message || err);
|
|
1054
|
+
process.exit(1);
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
if (args["print-context"] || args.printContext) {
|
|
1058
|
+
console.log(JSON.stringify(snapshot, null, 2));
|
|
1059
|
+
return;
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
let resolved;
|
|
1063
|
+
try {
|
|
1064
|
+
resolved = resolveBootstrapWorkspace(snapshot.repo_names || []);
|
|
1065
|
+
} catch (err) {
|
|
1066
|
+
console.error(err?.message || err);
|
|
1067
|
+
process.exit(1);
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
const wrapperRoot = resolved.root;
|
|
1071
|
+
const outputDir = args["output-dir"] || args.outputDir || args.output_dir;
|
|
1072
|
+
const dryRun = Boolean(args["dry-run"] || args.dryRun);
|
|
1073
|
+
const summary = {
|
|
1074
|
+
api_base: apiBase,
|
|
1075
|
+
project_id: snapshot?.project?.id || null,
|
|
1076
|
+
wrapper_root: wrapperRoot,
|
|
1077
|
+
output_root: outputDir ? path.resolve(process.cwd(), String(outputDir)) : path.join(wrapperRoot, "MyteCommandCenter"),
|
|
1078
|
+
repo_names: Array.isArray(snapshot.repo_names) ? snapshot.repo_names : [],
|
|
1079
|
+
local: {
|
|
1080
|
+
mode: resolved.mode,
|
|
1081
|
+
found: (resolved.repos || []).map((repo) => repo.name),
|
|
1082
|
+
missing: resolved.missing || [],
|
|
1083
|
+
},
|
|
1084
|
+
counts: {
|
|
1085
|
+
phases: Array.isArray(snapshot.phases) ? snapshot.phases.length : 0,
|
|
1086
|
+
epics: Array.isArray(snapshot.epics) ? snapshot.epics.length : 0,
|
|
1087
|
+
stories: Array.isArray(snapshot.stories) ? snapshot.stories.length : 0,
|
|
1088
|
+
missions: Array.isArray(snapshot.missions) ? snapshot.missions.length : 0,
|
|
1089
|
+
},
|
|
1090
|
+
snapshot_hash: snapshot.snapshot_hash || null,
|
|
1091
|
+
generated_at: snapshot.generated_at || null,
|
|
1092
|
+
dry_run: dryRun,
|
|
1093
|
+
};
|
|
1094
|
+
|
|
1095
|
+
if (dryRun) {
|
|
1096
|
+
if (args.json) {
|
|
1097
|
+
console.log(JSON.stringify(summary, null, 2));
|
|
1098
|
+
} else {
|
|
1099
|
+
console.log(`Project: ${summary.project_id || "(unknown)"}`);
|
|
1100
|
+
console.log(`Wrapper root: ${summary.wrapper_root}`);
|
|
1101
|
+
console.log(`Output root: ${summary.output_root}`);
|
|
1102
|
+
console.log(`Configured repos: ${summary.repo_names.join(", ") || "(none)"}`);
|
|
1103
|
+
console.log(`Found locally: ${summary.local.found.join(", ") || "(none)"}`);
|
|
1104
|
+
if (summary.local.missing.length) console.log(`Missing locally: ${summary.local.missing.join(", ")}`);
|
|
1105
|
+
console.log(`Counts: phases=${summary.counts.phases}, epics=${summary.counts.epics}, stories=${summary.counts.stories}, missions=${summary.counts.missions}`);
|
|
1106
|
+
console.log("Dry run only - no files written.");
|
|
1107
|
+
}
|
|
1108
|
+
return;
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
const writeResult = writeBootstrapSnapshot({ snapshot, wrapperRoot, outputDir });
|
|
1112
|
+
summary.data_root = writeResult.dataRoot;
|
|
1113
|
+
|
|
1114
|
+
if (args.json) {
|
|
1115
|
+
console.log(JSON.stringify(summary, null, 2));
|
|
1116
|
+
return;
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
console.log(`Project: ${summary.project_id || "(unknown)"}`);
|
|
1120
|
+
console.log(`Wrapper root: ${summary.wrapper_root}`);
|
|
1121
|
+
console.log(`Output root: ${summary.output_root}`);
|
|
1122
|
+
console.log(`Configured repos: ${summary.repo_names.join(", ") || "(none)"}`);
|
|
1123
|
+
console.log(`Found locally: ${summary.local.found.join(", ") || "(none)"}`);
|
|
1124
|
+
if (summary.local.missing.length) console.log(`Missing locally: ${summary.local.missing.join(", ")}`);
|
|
1125
|
+
console.log(`Wrote: phases=${summary.counts.phases}, epics=${summary.counts.epics}, stories=${summary.counts.stories}, missions=${summary.counts.missions}`);
|
|
1126
|
+
console.log(`Snapshot: ${summary.snapshot_hash || "n/a"}`);
|
|
1127
|
+
}
|
|
1128
|
+
|
|
877
1129
|
async function runQuery(args) {
|
|
878
1130
|
const key = (process.env.MYTE_API_KEY || process.env.MYTE_PROJECT_API_KEY || "").trim();
|
|
879
1131
|
if (!key) {
|
|
@@ -1007,6 +1259,11 @@ async function main() {
|
|
|
1007
1259
|
return;
|
|
1008
1260
|
}
|
|
1009
1261
|
|
|
1262
|
+
if (command === "bootstrap") {
|
|
1263
|
+
await runBootstrap(args);
|
|
1264
|
+
return;
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1010
1267
|
if (command === "chat") {
|
|
1011
1268
|
await runChat(args);
|
|
1012
1269
|
return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mytegroupinc/myte-core",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"description": "Myte CLI core implementation (Project Assistant + deterministic diffs).",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "cli.js",
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"dotenv": "^16.5.0",
|
|
24
24
|
"minimist": "^1.2.8",
|
|
25
|
-
"node-fetch": "^3.3.2"
|
|
25
|
+
"node-fetch": "^3.3.2",
|
|
26
|
+
"yaml": "^2.8.1"
|
|
26
27
|
}
|
|
27
28
|
}
|