@mytegroupinc/myte-core 0.0.15 → 0.0.16
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 +2 -1
- package/cli.js +108 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -76,7 +76,8 @@ Notes:
|
|
|
76
76
|
- `sync-qaqc` keeps QAQC state in one deterministic file so the working set grows and shrinks with current active-mission reality.
|
|
77
77
|
- `sync-qaqc` fully rewrites `MyteCommandCenter/data/qaqc.yml` on every sync and does not delete `MyteCommandCenter/data/missions/*.yml`.
|
|
78
78
|
- `feedback-sync` writes one deterministic feedback snapshot under `MyteCommandCenter/data/feedback.yml`.
|
|
79
|
-
- `feedback-sync`
|
|
79
|
+
- `feedback-sync` keeps feedback metadata plus comment turns in `MyteCommandCenter/data/feedback.yml`.
|
|
80
|
+
- `feedback-sync` writes full PRD context into `MyteCommandCenter/PRD/feedback-sync/*.md` and points to those files from `feedback.yml`.
|
|
80
81
|
- `feedback-sync` fully replaces the feedback-owned sync file to avoid stale local feedback noise.
|
|
81
82
|
- `feedback-sync` fully rewrites `MyteCommandCenter/data/feedback.yml` on every sync and does not delete `MyteCommandCenter/data/missions/*.yml`.
|
|
82
83
|
- `suggestions sync` writes one merge-safe workflow file at `MyteCommandCenter/data/mission-ops.yml`.
|
package/cli.js
CHANGED
|
@@ -266,7 +266,8 @@ function printHelp() {
|
|
|
266
266
|
"",
|
|
267
267
|
"feedback-sync contract:",
|
|
268
268
|
" - Runs from the wrapper root that contains the project's configured repo folders",
|
|
269
|
-
" - Writes open project feedback and
|
|
269
|
+
" - Writes open project feedback metadata and conversation turns into MyteCommandCenter/data/feedback.yml",
|
|
270
|
+
" - Stores full PRD context in MyteCommandCenter/PRD/feedback-sync/*.md and points to those files from feedback.yml",
|
|
270
271
|
"",
|
|
271
272
|
"Options:",
|
|
272
273
|
" --with-diff Include deterministic git diffs (project-scoped)",
|
|
@@ -290,7 +291,7 @@ function printHelp() {
|
|
|
290
291
|
" --target-contact-ids Comma-separated client contact ObjectIds",
|
|
291
292
|
" --status <value> Feedback status filter for feedback-sync (default: Pending)",
|
|
292
293
|
" --source <value> Feedback source filter for feedback-sync",
|
|
293
|
-
" --with-prd-text Include extracted PRD text
|
|
294
|
+
" --with-prd-text Include extracted PRD text so local PRD files can be materialized during feedback-sync (default: on)",
|
|
294
295
|
" --mission-ids <ids> Comma-separated mission business ids for run-qaqc (quote multi-id values on PowerShell)",
|
|
295
296
|
" --actor-scope <id> Actor workspace key inside mission-ops.yml (defaults to machine-cwd slug)",
|
|
296
297
|
" --wait Poll batch status until terminal completion for run-qaqc",
|
|
@@ -1082,6 +1083,9 @@ async function fetchFeedbackSyncSnapshot({ apiBase, key, timeoutMs, filters = {}
|
|
|
1082
1083
|
if (filters.includePrdText !== undefined) {
|
|
1083
1084
|
url.searchParams.set("include_prd_text", filters.includePrdText ? "true" : "false");
|
|
1084
1085
|
}
|
|
1086
|
+
if (filters.includeCommentTurns !== undefined) {
|
|
1087
|
+
url.searchParams.set("include_comment_turns", filters.includeCommentTurns ? "true" : "false");
|
|
1088
|
+
}
|
|
1085
1089
|
const { resp, body } = await fetchJsonWithTimeout(
|
|
1086
1090
|
fetchFn,
|
|
1087
1091
|
url.toString(),
|
|
@@ -1704,6 +1708,44 @@ function writeTextFile(filePath, value) {
|
|
|
1704
1708
|
fs.writeFileSync(filePath, String(value || ""), "utf8");
|
|
1705
1709
|
}
|
|
1706
1710
|
|
|
1711
|
+
function sanitizeFileSegment(value, fallback = "item") {
|
|
1712
|
+
const cleaned = String(value || "")
|
|
1713
|
+
.trim()
|
|
1714
|
+
.replace(/[<>:"/\\|?*\x00-\x1F]/g, "-")
|
|
1715
|
+
.replace(/\s+/g, "-")
|
|
1716
|
+
.replace(/-+/g, "-")
|
|
1717
|
+
.replace(/^\.+|\.+$/g, "")
|
|
1718
|
+
.replace(/^-+|-+$/g, "");
|
|
1719
|
+
return cleaned || fallback;
|
|
1720
|
+
}
|
|
1721
|
+
|
|
1722
|
+
function toPosixRelativePath(rootPath, targetPath) {
|
|
1723
|
+
return path.relative(rootPath, targetPath).split(path.sep).join("/");
|
|
1724
|
+
}
|
|
1725
|
+
|
|
1726
|
+
function ensureTrailingNewline(value) {
|
|
1727
|
+
const text = String(value || "");
|
|
1728
|
+
if (!text) return "";
|
|
1729
|
+
return text.endsWith("\n") ? text : `${text}\n`;
|
|
1730
|
+
}
|
|
1731
|
+
|
|
1732
|
+
function normalizeFeedbackConversationTurns(turns) {
|
|
1733
|
+
if (!Array.isArray(turns)) return [];
|
|
1734
|
+
return turns
|
|
1735
|
+
.map((turn) => {
|
|
1736
|
+
const content = String(turn?.content || "").trim();
|
|
1737
|
+
if (!content) return null;
|
|
1738
|
+
const normalized = {
|
|
1739
|
+
sender_name: firstNonEmptyString(turn?.sender_name, turn?.user_name, turn?.author_name) || "Unknown",
|
|
1740
|
+
content,
|
|
1741
|
+
};
|
|
1742
|
+
const createdAt = firstNonEmptyString(turn?.created_at, turn?.timestamp);
|
|
1743
|
+
if (createdAt) normalized.created_at = createdAt;
|
|
1744
|
+
return normalized;
|
|
1745
|
+
})
|
|
1746
|
+
.filter(Boolean);
|
|
1747
|
+
}
|
|
1748
|
+
|
|
1707
1749
|
function readJsonFile(filePath) {
|
|
1708
1750
|
if (!fs.existsSync(filePath) || !fs.statSync(filePath).isFile()) return null;
|
|
1709
1751
|
try {
|
|
@@ -1921,8 +1963,11 @@ function writeQaqcSnapshot({ snapshot, wrapperRoot, outputDir }) {
|
|
|
1921
1963
|
|
|
1922
1964
|
function writeFeedbackSnapshot({ snapshot, wrapperRoot, outputDir }) {
|
|
1923
1965
|
const { targetRoot, dataRoot } = resolveCommandCenterRoots(wrapperRoot, outputDir);
|
|
1966
|
+
const prdSyncDir = path.join(targetRoot, "PRD", "feedback-sync");
|
|
1924
1967
|
|
|
1925
1968
|
ensureDir(dataRoot);
|
|
1969
|
+
ensureDir(prdSyncDir);
|
|
1970
|
+
clearFileDirectory(prdSyncDir, [".md", ".markdown", ".txt"]);
|
|
1926
1971
|
pruneLegacyCommandCenterArtifacts(dataRoot, { bootstrap: true, feedback: true });
|
|
1927
1972
|
|
|
1928
1973
|
if (snapshot.project && typeof snapshot.project === "object") {
|
|
@@ -1930,15 +1975,58 @@ function writeFeedbackSnapshot({ snapshot, wrapperRoot, outputDir }) {
|
|
|
1930
1975
|
}
|
|
1931
1976
|
|
|
1932
1977
|
const items = Array.isArray(snapshot.items) ? snapshot.items : [];
|
|
1978
|
+
let prdFileCount = 0;
|
|
1979
|
+
const materializedItems = items.map((rawItem, index) => {
|
|
1980
|
+
const item = isPlainObject(rawItem) ? { ...rawItem } : {};
|
|
1981
|
+
const feedbackId = stableItemId(item, ["feedback_id", "id"], `F${String(index + 1).padStart(3, "0")}`);
|
|
1982
|
+
const conversationTurns = normalizeFeedbackConversationTurns(item.conversation_turns);
|
|
1983
|
+
const prdText = String(item.prd_text || "").trim();
|
|
1984
|
+
|
|
1985
|
+
let contextSource = "description_only";
|
|
1986
|
+
let contextNote = "No separate PRD. Use feedback_text as the context for this feedback item.";
|
|
1987
|
+
let prdFile = null;
|
|
1988
|
+
|
|
1989
|
+
if (prdText) {
|
|
1990
|
+
const prdFilename = `${sanitizeFileSegment(feedbackId, `feedback-${index + 1}`)}.md`;
|
|
1991
|
+
const prdPath = path.join(prdSyncDir, prdFilename);
|
|
1992
|
+
writeTextFile(prdPath, ensureTrailingNewline(prdText));
|
|
1993
|
+
prdFile = toPosixRelativePath(targetRoot, prdPath);
|
|
1994
|
+
contextSource = "prd_file";
|
|
1995
|
+
contextNote = "Full PRD context is stored in the linked file.";
|
|
1996
|
+
prdFileCount += 1;
|
|
1997
|
+
} else if (item.has_prd_text) {
|
|
1998
|
+
contextSource = "prd_declared_but_unavailable";
|
|
1999
|
+
contextNote = "A separate PRD exists for this feedback item, but readable PRD text was not included in this sync snapshot.";
|
|
2000
|
+
}
|
|
2001
|
+
|
|
2002
|
+
return {
|
|
2003
|
+
...item,
|
|
2004
|
+
feedback_id: feedbackId,
|
|
2005
|
+
conversation_turns: conversationTurns,
|
|
2006
|
+
context_source: contextSource,
|
|
2007
|
+
context_note: contextNote,
|
|
2008
|
+
prd_file: prdFile,
|
|
2009
|
+
};
|
|
2010
|
+
});
|
|
2011
|
+
const snapshotCounts = snapshot.counts && typeof snapshot.counts === "object"
|
|
2012
|
+
? { ...snapshot.counts }
|
|
2013
|
+
: { total_feedback: materializedItems.length };
|
|
2014
|
+
snapshotCounts.with_prd_files = prdFileCount;
|
|
2015
|
+
if (snapshotCounts.with_conversation_turns === undefined) {
|
|
2016
|
+
snapshotCounts.with_conversation_turns = materializedItems.filter((item) => Array.isArray(item?.conversation_turns) && item.conversation_turns.length > 0).length;
|
|
2017
|
+
}
|
|
2018
|
+
|
|
1933
2019
|
const payload = scrubBootstrapValue({
|
|
1934
|
-
schema_version: snapshot.schema_version ||
|
|
2020
|
+
schema_version: snapshot.schema_version || 2,
|
|
1935
2021
|
project: snapshot.project || null,
|
|
1936
2022
|
repo_names: Array.isArray(snapshot.repo_names) ? snapshot.repo_names : [],
|
|
1937
2023
|
filters: snapshot.filters && typeof snapshot.filters === "object" ? snapshot.filters : {},
|
|
1938
|
-
counts:
|
|
1939
|
-
|
|
1940
|
-
:
|
|
1941
|
-
|
|
2024
|
+
counts: snapshotCounts,
|
|
2025
|
+
artifacts: {
|
|
2026
|
+
feedback_prd_root: "PRD/feedback-sync",
|
|
2027
|
+
with_prd_files: prdFileCount,
|
|
2028
|
+
},
|
|
2029
|
+
queue: materializedItems
|
|
1942
2030
|
.filter((item) => String(item?.status || "").trim().toLowerCase() !== "resolved")
|
|
1943
2031
|
.map((item, index) => ({
|
|
1944
2032
|
feedback_id: stableItemId(item, ["feedback_id", "id"], `F${String(index + 1).padStart(3, "0")}`),
|
|
@@ -1946,7 +2034,11 @@ function writeFeedbackSnapshot({ snapshot, wrapperRoot, outputDir }) {
|
|
|
1946
2034
|
priority: item?.priority || null,
|
|
1947
2035
|
title: item?.title || null,
|
|
1948
2036
|
})),
|
|
1949
|
-
items
|
|
2037
|
+
items: materializedItems.map((item) => {
|
|
2038
|
+
const nextItem = { ...item };
|
|
2039
|
+
delete nextItem.prd_text;
|
|
2040
|
+
return nextItem;
|
|
2041
|
+
}),
|
|
1950
2042
|
pagination: snapshot.pagination && typeof snapshot.pagination === "object" ? snapshot.pagination : undefined,
|
|
1951
2043
|
generated_at: snapshot.generated_at || null,
|
|
1952
2044
|
snapshot_hash: snapshot.snapshot_hash || null,
|
|
@@ -1956,6 +2048,7 @@ function writeFeedbackSnapshot({ snapshot, wrapperRoot, outputDir }) {
|
|
|
1956
2048
|
return {
|
|
1957
2049
|
targetRoot,
|
|
1958
2050
|
dataRoot,
|
|
2051
|
+
prdSyncDir,
|
|
1959
2052
|
manifest: payload,
|
|
1960
2053
|
};
|
|
1961
2054
|
}
|
|
@@ -3024,6 +3117,7 @@ async function runFeedbackSync(args) {
|
|
|
3024
3117
|
status: firstNonEmptyString(args.status) || "Pending",
|
|
3025
3118
|
source: firstNonEmptyString(args.source) || "",
|
|
3026
3119
|
includePrdText,
|
|
3120
|
+
includeCommentTurns: true,
|
|
3027
3121
|
};
|
|
3028
3122
|
|
|
3029
3123
|
let snapshot;
|
|
@@ -3079,7 +3173,7 @@ async function runFeedbackSync(args) {
|
|
|
3079
3173
|
console.log(`Configured repos: ${summary.repo_names.join(", ") || "(none)"}`);
|
|
3080
3174
|
console.log(`Found locally: ${summary.local.found.join(", ") || "(none)"}`);
|
|
3081
3175
|
if (summary.local.missing.length) console.log(`Missing locally: ${summary.local.missing.join(", ")}`);
|
|
3082
|
-
console.log(`Counts: total_feedback=${summary.counts.total_feedback || 0}, with_prd_text=${summary.counts.with_prd_text || 0}`);
|
|
3176
|
+
console.log(`Counts: total_feedback=${summary.counts.total_feedback || 0}, with_prd_text=${summary.counts.with_prd_text || 0}, with_conversation_turns=${summary.counts.with_conversation_turns || 0}`);
|
|
3083
3177
|
console.log("Dry run only - no files written.");
|
|
3084
3178
|
}
|
|
3085
3179
|
return;
|
|
@@ -3087,6 +3181,9 @@ async function runFeedbackSync(args) {
|
|
|
3087
3181
|
|
|
3088
3182
|
const writeResult = writeFeedbackSnapshot({ snapshot, wrapperRoot, outputDir });
|
|
3089
3183
|
summary.data_root = writeResult.dataRoot;
|
|
3184
|
+
summary.prd_root = writeResult.prdSyncDir;
|
|
3185
|
+
summary.counts = writeResult.manifest?.counts || summary.counts;
|
|
3186
|
+
summary.artifacts = writeResult.manifest?.artifacts || null;
|
|
3090
3187
|
|
|
3091
3188
|
if (args.json) {
|
|
3092
3189
|
console.log(JSON.stringify(summary, null, 2));
|
|
@@ -3099,7 +3196,8 @@ async function runFeedbackSync(args) {
|
|
|
3099
3196
|
console.log(`Configured repos: ${summary.repo_names.join(", ") || "(none)"}`);
|
|
3100
3197
|
console.log(`Found locally: ${summary.local.found.join(", ") || "(none)"}`);
|
|
3101
3198
|
if (summary.local.missing.length) console.log(`Missing locally: ${summary.local.missing.join(", ")}`);
|
|
3102
|
-
console.log(`Wrote feedback: total_feedback=${summary.counts.total_feedback || 0}, with_prd_text=${summary.counts.with_prd_text || 0}`);
|
|
3199
|
+
console.log(`Wrote feedback: total_feedback=${summary.counts.total_feedback || 0}, with_prd_text=${summary.counts.with_prd_text || 0}, with_conversation_turns=${summary.counts.with_conversation_turns || 0}`);
|
|
3200
|
+
console.log(`PRD root: ${summary.prd_root}`);
|
|
3103
3201
|
console.log(`Snapshot: ${summary.snapshot_hash || "n/a"}`);
|
|
3104
3202
|
}
|
|
3105
3203
|
|