@kaddo/cli 3.70.1 → 3.72.0
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/admin-dist/assets/index-Bz7DGBBm.js +38 -0
- package/dist/admin-dist/assets/index-J0BnLZHW.css +2 -0
- package/dist/admin-dist/index.html +2 -2
- package/dist/admin-server/index.js +251 -2
- package/dist/core.js +270 -0
- package/package.json +1 -1
- package/dist/admin-dist/assets/index-BrVaLM-z.js +0 -10
- package/dist/admin-dist/assets/index-zcGzKcF4.css +0 -2
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
|
|
2
|
+
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-outline-style:solid;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-ease:initial}}}@layer theme{:root,:host{--font-sans:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--ease-in-out:cubic-bezier(.4, 0, .2, 1);--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.collapse{visibility:collapse}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.table{display:table}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.border{border-style:var(--tw-border-style);border-width:1px}.font-mono{font-family:var(--font-mono)}.break-all{word-break:break-all}.capitalize{text-transform:capitalize}.uppercase{text-transform:uppercase}.italic{font-style:italic}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.ease-in-out{--tw-ease:var(--ease-in-out);transition-timing-function:var(--ease-in-out)}}:root{--background:#fff;--surface:#f8f9fa;--surface-muted:#f1f3f5;--foreground:#1a1a2e;--foreground-muted:#6c757d;--border:#dee2e6;--border-strong:#adb5bd;--primary:#4361ee;--primary-foreground:#fff;--success:#2d9f5c;--warning:#e9a820;--danger:#dc3545;--info:#3b82f6;--finding-blocking:#dc3545;--finding-warning:#e9a820;--finding-fyi:#6c757d;--work-item-draft:#6c757d;--work-item-ready:#3b82f6;--work-item-progress:#8b5cf6;--work-item-blocked:#dc3545;--work-item-completed:#2d9f5c;--work-item-archived:#adb5bd;--knowledge-ready:#2d9f5c;--knowledge-missing:#dc3545;--knowledge-placeholder:#e9a820;--knowledge-unknown:#6c757d;--module-core:#4361ee;--module-module:#3b82f6;--module-unavailable:#dc3545;--readiness-ready:#2d9f5c;--readiness-warning:#e9a820;--readiness-blocked:#dc3545;--font-sans:"Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;--font-mono:"JetBrains Mono", "Fira Code", "Cascadia Code", monospace;--radius:6px}@media (prefers-color-scheme:dark){:root:not([data-theme=light]){--background:#0f0f23;--surface:#1a1a2e;--surface-muted:#16213e;--foreground:#e8e8e8;--foreground-muted:#a0a0b0;--border:#2a2a3e;--border-strong:#4a4a5e;--primary:#6580f5;--primary-foreground:#fff;--success:#3cb371;--warning:#f0b840;--danger:#ef4444;--info:#60a5fa;--finding-blocking:#ef4444;--finding-warning:#f0b840;--finding-fyi:#a0a0b0;--work-item-draft:#a0a0b0;--work-item-ready:#60a5fa;--work-item-progress:#a78bfa;--work-item-blocked:#ef4444;--work-item-completed:#3cb371;--work-item-archived:#6a6a7e;--knowledge-ready:#3cb371;--knowledge-missing:#ef4444;--knowledge-placeholder:#f0b840;--knowledge-unknown:#a0a0b0;--module-core:#6580f5;--module-module:#60a5fa;--module-unavailable:#ef4444;--readiness-ready:#3cb371;--readiness-warning:#f0b840;--readiness-blocked:#ef4444}}:root[data-theme=dark]{--background:#0f0f23;--surface:#1a1a2e;--surface-muted:#16213e;--foreground:#e8e8e8;--foreground-muted:#a0a0b0;--border:#2a2a3e;--border-strong:#4a4a5e;--primary:#6580f5;--primary-foreground:#fff;--success:#3cb371;--warning:#f0b840;--danger:#ef4444;--info:#60a5fa;--finding-blocking:#ef4444;--finding-warning:#f0b840;--finding-fyi:#a0a0b0;--work-item-draft:#a0a0b0;--work-item-ready:#60a5fa;--work-item-progress:#a78bfa;--work-item-blocked:#ef4444;--work-item-completed:#3cb371;--work-item-archived:#6a6a7e;--knowledge-ready:#3cb371;--knowledge-missing:#ef4444;--knowledge-placeholder:#f0b840;--knowledge-unknown:#a0a0b0;--module-core:#6580f5;--module-module:#60a5fa;--module-unavailable:#ef4444;--readiness-ready:#3cb371;--readiness-warning:#f0b840;--readiness-blocked:#ef4444}body{font-family:var(--font-sans);background:var(--background);color:var(--foreground);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;margin:0}code,.font-mono{font-family:var(--font-mono)}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
7
|
<title>admin</title>
|
|
8
|
-
<script type="module" crossorigin src="/assets/index-
|
|
9
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-Bz7DGBBm.js"></script>
|
|
9
|
+
<link rel="stylesheet" crossorigin href="/assets/index-J0BnLZHW.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
12
12
|
<div id="root"></div>
|
|
@@ -54,8 +54,16 @@ import {
|
|
|
54
54
|
buildProjectExplanation,
|
|
55
55
|
buildReadinessReport,
|
|
56
56
|
buildProjectRoute,
|
|
57
|
+
knowledgeLayers,
|
|
57
58
|
loadConfig,
|
|
58
|
-
loadMappedModules
|
|
59
|
+
loadMappedModules,
|
|
60
|
+
discoverKnowledge,
|
|
61
|
+
getWorkItems as coreGetWorkItems,
|
|
62
|
+
getWorkItem as coreGetWorkItem,
|
|
63
|
+
WorkItemNotFoundError,
|
|
64
|
+
exists,
|
|
65
|
+
join,
|
|
66
|
+
readFile
|
|
59
67
|
} from "@kaddo/cli/core";
|
|
60
68
|
function getProjectSummary(dir) {
|
|
61
69
|
const config = loadConfig(dir);
|
|
@@ -90,6 +98,22 @@ function getWorkItemSummary(dir) {
|
|
|
90
98
|
}))
|
|
91
99
|
};
|
|
92
100
|
}
|
|
101
|
+
function getWorkItemsList(dir, filters = {}) {
|
|
102
|
+
return coreGetWorkItems(dir, filters);
|
|
103
|
+
}
|
|
104
|
+
function getWorkItemDetail(dir, workItemId) {
|
|
105
|
+
if (!workItemId || workItemId.includes("..") || workItemId.includes("/") || workItemId.includes("\\") || workItemId.startsWith(".")) {
|
|
106
|
+
throw new CoreError("INVALID_WORK_ITEM_ID", "Invalid Work Item identifier.");
|
|
107
|
+
}
|
|
108
|
+
try {
|
|
109
|
+
return coreGetWorkItem(dir, workItemId);
|
|
110
|
+
} catch (err) {
|
|
111
|
+
if (err instanceof WorkItemNotFoundError) {
|
|
112
|
+
throw new CoreError("WORK_ITEM_NOT_FOUND", "This Work Item does not exist in the current project.");
|
|
113
|
+
}
|
|
114
|
+
throw err;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
93
117
|
function getModules(dir) {
|
|
94
118
|
const mapped = loadMappedModules(dir);
|
|
95
119
|
return {
|
|
@@ -157,6 +181,71 @@ function getProjectOverview(dir) {
|
|
|
157
181
|
findings: getFindings(dir)
|
|
158
182
|
};
|
|
159
183
|
}
|
|
184
|
+
function getKnowledgeInventory(dir) {
|
|
185
|
+
const artifacts = discoverKnowledge(dir).filter((a) => !a.isWorkItem);
|
|
186
|
+
const layerSummary = knowledgeLayers(dir);
|
|
187
|
+
const layerMap = /* @__PURE__ */ new Map();
|
|
188
|
+
for (const ls of layerSummary) {
|
|
189
|
+
const id = ls.layer.toLowerCase();
|
|
190
|
+
layerMap.set(id, { id, label: ls.layer, status: ls.status, artifacts: [] });
|
|
191
|
+
}
|
|
192
|
+
for (const a of artifacts) {
|
|
193
|
+
const layerId = a.layer === "module" ? "tech" : a.layer;
|
|
194
|
+
if (!layerMap.has(layerId)) {
|
|
195
|
+
layerMap.set(layerId, { id: layerId, label: layerId.charAt(0).toUpperCase() + layerId.slice(1), status: "unknown", artifacts: [] });
|
|
196
|
+
}
|
|
197
|
+
const layer = layerMap.get(layerId);
|
|
198
|
+
const status = a.status || "available";
|
|
199
|
+
layer.artifacts.push({
|
|
200
|
+
id: a.id || a.relPath.replace(/[/\\]/g, "-").replace(/\.md$/, ""),
|
|
201
|
+
title: a.title || a.relPath.split("/").pop()?.replace(/\.md$/, "").replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()) || "Untitled",
|
|
202
|
+
layer: layerId,
|
|
203
|
+
path: a.relPath,
|
|
204
|
+
status: normalizeArtifactStatus(status),
|
|
205
|
+
type: a.type || void 0
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
return { layers: Array.from(layerMap.values()) };
|
|
209
|
+
}
|
|
210
|
+
function normalizeArtifactStatus(status) {
|
|
211
|
+
if (!status || status === "active" || status === "ready") return "available";
|
|
212
|
+
if (status === "placeholder" || status === "draft") return "placeholder";
|
|
213
|
+
if (status === "missing") return "missing";
|
|
214
|
+
if (status === "not-applicable" || status === "n/a") return "not-applicable";
|
|
215
|
+
return "available";
|
|
216
|
+
}
|
|
217
|
+
function getKnowledgeArtifactDetail(dir, artifactId) {
|
|
218
|
+
if (artifactId.includes("..") || artifactId.startsWith("/") || artifactId.includes("\\")) {
|
|
219
|
+
throw new CoreError("INVALID_PATH", "Invalid artifact identifier.");
|
|
220
|
+
}
|
|
221
|
+
const artifacts = discoverKnowledge(dir).filter((a) => !a.isWorkItem);
|
|
222
|
+
const match = artifacts.find((a) => {
|
|
223
|
+
const derivedId = a.id || a.relPath.replace(/[/\\]/g, "-").replace(/\.md$/, "");
|
|
224
|
+
return derivedId === artifactId;
|
|
225
|
+
});
|
|
226
|
+
if (!match) {
|
|
227
|
+
throw new CoreError("ARTIFACT_NOT_FOUND", "Knowledge artifact not found.");
|
|
228
|
+
}
|
|
229
|
+
const fullPath = join(dir, match.relPath);
|
|
230
|
+
if (!exists(fullPath)) {
|
|
231
|
+
throw new CoreError("ARTIFACT_UNAVAILABLE", "This artifact existed when the Knowledge inventory was loaded but can no longer be read.");
|
|
232
|
+
}
|
|
233
|
+
const raw = readFile(fullPath);
|
|
234
|
+
const contentStart = raw.indexOf("---", raw.indexOf("---") + 3);
|
|
235
|
+
const content = contentStart > 0 ? raw.slice(contentStart + 3).trim() : raw;
|
|
236
|
+
const layerId = match.layer === "module" ? "tech" : match.layer;
|
|
237
|
+
const status = normalizeArtifactStatus(match.status || "available");
|
|
238
|
+
return {
|
|
239
|
+
id: match.id || match.relPath.replace(/[/\\]/g, "-").replace(/\.md$/, ""),
|
|
240
|
+
title: match.title || match.relPath.split("/").pop()?.replace(/\.md$/, "").replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()) || "Untitled",
|
|
241
|
+
layer: layerId,
|
|
242
|
+
path: match.relPath,
|
|
243
|
+
status,
|
|
244
|
+
format: "markdown",
|
|
245
|
+
content,
|
|
246
|
+
type: match.type || void 0
|
|
247
|
+
};
|
|
248
|
+
}
|
|
160
249
|
var CoreError = class extends Error {
|
|
161
250
|
constructor(code, message) {
|
|
162
251
|
super(message);
|
|
@@ -218,11 +307,46 @@ async function createAdminServer(opts) {
|
|
|
218
307
|
app.get("/api/v1/admin/overview", coreRoute(getProjectOverview));
|
|
219
308
|
app.get("/api/v1/admin/project", coreRoute(getProjectSummary));
|
|
220
309
|
app.get("/api/v1/admin/knowledge", coreRoute(getKnowledgeSummary));
|
|
221
|
-
app.get(
|
|
310
|
+
app.get(
|
|
311
|
+
"/api/v1/admin/work-items",
|
|
312
|
+
async (request) => {
|
|
313
|
+
try {
|
|
314
|
+
const { status, module, query } = request.query;
|
|
315
|
+
return getWorkItemsList(projectDir, { status, module, query });
|
|
316
|
+
} catch (err) {
|
|
317
|
+
if (err instanceof CoreError) {
|
|
318
|
+
return { error: { code: err.code, message: err.message } };
|
|
319
|
+
}
|
|
320
|
+
throw err;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
);
|
|
324
|
+
app.get("/api/v1/admin/work-items/:workItemId", async (request, reply) => {
|
|
325
|
+
try {
|
|
326
|
+
return getWorkItemDetail(projectDir, request.params.workItemId);
|
|
327
|
+
} catch (err) {
|
|
328
|
+
if (err instanceof CoreError) {
|
|
329
|
+
const code = err.code === "WORK_ITEM_NOT_FOUND" ? 404 : err.code === "INVALID_WORK_ITEM_ID" ? 400 : 500;
|
|
330
|
+
return reply.code(code).send({ error: { code: err.code, message: err.message } });
|
|
331
|
+
}
|
|
332
|
+
throw err;
|
|
333
|
+
}
|
|
334
|
+
});
|
|
222
335
|
app.get("/api/v1/admin/modules", coreRoute(getModules));
|
|
223
336
|
app.get("/api/v1/admin/readiness", coreRoute(getProjectReadiness));
|
|
224
337
|
app.get("/api/v1/admin/route", coreRoute(getProjectRoute));
|
|
225
338
|
app.get("/api/v1/admin/findings", coreRoute(getFindings));
|
|
339
|
+
app.get("/api/v1/admin/knowledge/inventory", coreRoute(getKnowledgeInventory));
|
|
340
|
+
app.get("/api/v1/admin/knowledge/artifact/:artifactId", async (request) => {
|
|
341
|
+
try {
|
|
342
|
+
return getKnowledgeArtifactDetail(projectDir, request.params.artifactId);
|
|
343
|
+
} catch (err) {
|
|
344
|
+
if (err instanceof CoreError) {
|
|
345
|
+
return { error: { code: err.code, message: err.message } };
|
|
346
|
+
}
|
|
347
|
+
throw err;
|
|
348
|
+
}
|
|
349
|
+
});
|
|
226
350
|
if (staticDir) {
|
|
227
351
|
app.setNotFoundHandler(async (_request, reply) => {
|
|
228
352
|
return reply.sendFile("index.html");
|
|
@@ -427,6 +551,123 @@ var ProjectOverviewSchema = z.object({
|
|
|
427
551
|
route: ProjectRouteSchema,
|
|
428
552
|
findings: FindingsSummarySchema
|
|
429
553
|
});
|
|
554
|
+
var KnowledgeArtifactSummarySchema = z.object({
|
|
555
|
+
id: z.string(),
|
|
556
|
+
title: z.string(),
|
|
557
|
+
layer: z.string(),
|
|
558
|
+
path: z.string(),
|
|
559
|
+
status: z.string(),
|
|
560
|
+
type: z.string().optional()
|
|
561
|
+
});
|
|
562
|
+
var KnowledgeInventoryLayerSchema = z.object({
|
|
563
|
+
id: z.string(),
|
|
564
|
+
label: z.string(),
|
|
565
|
+
status: z.string(),
|
|
566
|
+
artifacts: z.array(KnowledgeArtifactSummarySchema)
|
|
567
|
+
});
|
|
568
|
+
var KnowledgeInventorySchema = z.object({
|
|
569
|
+
layers: z.array(KnowledgeInventoryLayerSchema)
|
|
570
|
+
});
|
|
571
|
+
var KnowledgeArtifactDetailSchema = z.object({
|
|
572
|
+
id: z.string(),
|
|
573
|
+
title: z.string(),
|
|
574
|
+
layer: z.string(),
|
|
575
|
+
path: z.string(),
|
|
576
|
+
status: z.string(),
|
|
577
|
+
format: z.string(),
|
|
578
|
+
content: z.string(),
|
|
579
|
+
type: z.string().optional()
|
|
580
|
+
});
|
|
581
|
+
var WorkItemsSummaryStatsSchema = z.object({
|
|
582
|
+
total: z.number(),
|
|
583
|
+
active: z.number(),
|
|
584
|
+
draft: z.number(),
|
|
585
|
+
ready: z.number(),
|
|
586
|
+
inProgress: z.number(),
|
|
587
|
+
blocked: z.number(),
|
|
588
|
+
completed: z.number(),
|
|
589
|
+
archived: z.number()
|
|
590
|
+
});
|
|
591
|
+
var WorkItemListItemSchema = z.object({
|
|
592
|
+
id: z.string(),
|
|
593
|
+
title: z.string(),
|
|
594
|
+
type: z.string(),
|
|
595
|
+
status: z.string(),
|
|
596
|
+
implementationStatus: z.string().nullable(),
|
|
597
|
+
validationStatus: z.string().nullable(),
|
|
598
|
+
releaseStatus: z.string().nullable(),
|
|
599
|
+
affectedModules: z.array(z.string()),
|
|
600
|
+
scopeConfidenceLevel: z.string().nullable(),
|
|
601
|
+
initiative: z.string().nullable()
|
|
602
|
+
});
|
|
603
|
+
var WorkItemsListSchema = z.object({
|
|
604
|
+
summary: WorkItemsSummaryStatsSchema,
|
|
605
|
+
items: z.array(WorkItemListItemSchema),
|
|
606
|
+
modules: z.array(z.string())
|
|
607
|
+
});
|
|
608
|
+
var CoverageEntrySchema = z.object({ id: z.string(), status: z.string(), reason: z.string().optional() });
|
|
609
|
+
var ImpactEntrySchema = z.object({
|
|
610
|
+
surface: z.string(),
|
|
611
|
+
status: z.string(),
|
|
612
|
+
reason: z.string().optional(),
|
|
613
|
+
question: z.string().optional()
|
|
614
|
+
});
|
|
615
|
+
var AcceptanceCriterionSchema = z.object({ text: z.string(), checked: z.boolean().nullable() });
|
|
616
|
+
var ReleaseGateEntrySchema = z.object({
|
|
617
|
+
id: z.string(),
|
|
618
|
+
status: z.string(),
|
|
619
|
+
reason: z.string().optional(),
|
|
620
|
+
requiredFor: z.string().optional()
|
|
621
|
+
});
|
|
622
|
+
var CompletionExceptionEntrySchema = z.object({
|
|
623
|
+
id: z.string(),
|
|
624
|
+
status: z.string(),
|
|
625
|
+
reason: z.string().optional(),
|
|
626
|
+
category: z.string().optional(),
|
|
627
|
+
impact: z.string().optional()
|
|
628
|
+
});
|
|
629
|
+
var RepoValidationSchema = z.object({ command: z.string(), status: z.string(), reason: z.string().optional() });
|
|
630
|
+
var RepoMigrationSchema = z.object({
|
|
631
|
+
id: z.string(),
|
|
632
|
+
environment: z.string(),
|
|
633
|
+
status: z.string(),
|
|
634
|
+
reason: z.string().optional()
|
|
635
|
+
});
|
|
636
|
+
var EvidenceRepoSchema = z.object({
|
|
637
|
+
module: z.string(),
|
|
638
|
+
role: z.string(),
|
|
639
|
+
status: z.string(),
|
|
640
|
+
changedPaths: z.array(z.string()),
|
|
641
|
+
validations: z.array(RepoValidationSchema),
|
|
642
|
+
migrations: z.array(RepoMigrationSchema)
|
|
643
|
+
});
|
|
644
|
+
var LinkedDecisionSchema = z.object({
|
|
645
|
+
id: z.string(),
|
|
646
|
+
title: z.string().optional(),
|
|
647
|
+
knowledgeId: z.string().optional(),
|
|
648
|
+
knowledgeLayer: z.string().optional()
|
|
649
|
+
});
|
|
650
|
+
var LinkedKnowledgeSchema = z.object({ id: z.string(), title: z.string(), layer: z.string() });
|
|
651
|
+
var WorkItemDetailSchema = WorkItemListItemSchema.extend({
|
|
652
|
+
actor: z.string().nullable(),
|
|
653
|
+
outcome: z.string().nullable(),
|
|
654
|
+
currentBehavior: z.string().nullable(),
|
|
655
|
+
targetBehavior: z.string().nullable(),
|
|
656
|
+
entryPoints: z.string().nullable(),
|
|
657
|
+
endToEndFlow: z.string().nullable(),
|
|
658
|
+
scopeConfidence: z.object({ level: z.string(), reasons: z.array(z.string()) }).nullable(),
|
|
659
|
+
scopeUnknowns: z.array(z.string()),
|
|
660
|
+
moduleCoverage: z.array(CoverageEntrySchema),
|
|
661
|
+
impactAnalysis: z.array(ImpactEntrySchema),
|
|
662
|
+
acceptanceCriteria: z.array(AcceptanceCriterionSchema),
|
|
663
|
+
implementationEvidence: z.array(EvidenceRepoSchema),
|
|
664
|
+
releaseGates: z.array(ReleaseGateEntrySchema),
|
|
665
|
+
completionExceptions: z.array(CompletionExceptionEntrySchema),
|
|
666
|
+
decisions: z.array(LinkedDecisionSchema),
|
|
667
|
+
relatedKnowledge: z.array(LinkedKnowledgeSchema),
|
|
668
|
+
source: z.object({ type: z.string(), id: z.string().optional(), inferred: z.boolean() }).passthrough(),
|
|
669
|
+
path: z.string()
|
|
670
|
+
});
|
|
430
671
|
var ErrorResponseSchema = z.object({
|
|
431
672
|
error: z.object({
|
|
432
673
|
code: z.string(),
|
|
@@ -436,6 +677,10 @@ var ErrorResponseSchema = z.object({
|
|
|
436
677
|
export {
|
|
437
678
|
ErrorResponseSchema,
|
|
438
679
|
FindingsSummarySchema,
|
|
680
|
+
KnowledgeArtifactDetailSchema,
|
|
681
|
+
KnowledgeArtifactSummarySchema,
|
|
682
|
+
KnowledgeInventoryLayerSchema,
|
|
683
|
+
KnowledgeInventorySchema,
|
|
439
684
|
KnowledgeSummarySchema,
|
|
440
685
|
ModuleSummarySchema,
|
|
441
686
|
ProjectOverviewSchema,
|
|
@@ -445,6 +690,10 @@ export {
|
|
|
445
690
|
RouteStepSchema,
|
|
446
691
|
SQLiteAdminStorage,
|
|
447
692
|
SessionManager,
|
|
693
|
+
WorkItemDetailSchema,
|
|
694
|
+
WorkItemListItemSchema,
|
|
448
695
|
WorkItemSummarySchema,
|
|
696
|
+
WorkItemsListSchema,
|
|
697
|
+
WorkItemsSummaryStatsSchema,
|
|
449
698
|
createAdminServer
|
|
450
699
|
};
|
package/dist/core.js
CHANGED
|
@@ -7450,15 +7450,285 @@ function analyzeCrossRepoEvidence(input) {
|
|
|
7450
7450
|
repoEvidence
|
|
7451
7451
|
};
|
|
7452
7452
|
}
|
|
7453
|
+
|
|
7454
|
+
// src/core/work-items.ts
|
|
7455
|
+
import matter6 from "gray-matter";
|
|
7456
|
+
var WorkItemNotFoundError = class extends Error {
|
|
7457
|
+
constructor(workItemId) {
|
|
7458
|
+
super(`Work Item "${workItemId}" was not found.`);
|
|
7459
|
+
this.workItemId = workItemId;
|
|
7460
|
+
this.name = "WorkItemNotFoundError";
|
|
7461
|
+
}
|
|
7462
|
+
workItemId;
|
|
7463
|
+
};
|
|
7464
|
+
function getWorkItemsSummary(dir) {
|
|
7465
|
+
return summarize2(discoverWorkItems(dir));
|
|
7466
|
+
}
|
|
7467
|
+
function summarize2(artifacts) {
|
|
7468
|
+
const states = artifacts.map((a) => lifecycleStateOf({ status: a.status, filePath: a.filePath }));
|
|
7469
|
+
const count = (s) => states.filter((x) => x === s).length;
|
|
7470
|
+
return {
|
|
7471
|
+
total: states.length,
|
|
7472
|
+
active: states.filter((s) => isActiveState(s)).length,
|
|
7473
|
+
draft: count("draft"),
|
|
7474
|
+
ready: count("ready"),
|
|
7475
|
+
inProgress: count("in-progress"),
|
|
7476
|
+
blocked: count("blocked"),
|
|
7477
|
+
completed: count("completed"),
|
|
7478
|
+
archived: count("archived")
|
|
7479
|
+
};
|
|
7480
|
+
}
|
|
7481
|
+
function getWorkItems(dir, filters = {}) {
|
|
7482
|
+
const artifacts = discoverWorkItems(dir);
|
|
7483
|
+
const summary = summarize2(artifacts);
|
|
7484
|
+
const allModules = /* @__PURE__ */ new Set();
|
|
7485
|
+
for (const a of artifacts) for (const m of a.affectedModules) allModules.add(m);
|
|
7486
|
+
let items = artifacts.map(toListItem);
|
|
7487
|
+
if (filters.status && filters.status !== "all") {
|
|
7488
|
+
items = items.filter((i) => i.status === filters.status);
|
|
7489
|
+
}
|
|
7490
|
+
if (filters.module && filters.module !== "all") {
|
|
7491
|
+
items = items.filter((i) => i.affectedModules.includes(filters.module));
|
|
7492
|
+
}
|
|
7493
|
+
if (filters.query && filters.query.trim()) {
|
|
7494
|
+
const q = filters.query.trim().toLowerCase();
|
|
7495
|
+
items = items.filter(
|
|
7496
|
+
(i) => i.id.toLowerCase().includes(q) || i.title.toLowerCase().includes(q) || i.affectedModules.some((m) => m.toLowerCase().includes(q))
|
|
7497
|
+
);
|
|
7498
|
+
}
|
|
7499
|
+
items.sort((a, b) => {
|
|
7500
|
+
const rank = (s) => isActiveState(s) ? 0 : s === "completed" ? 1 : 2;
|
|
7501
|
+
const r = rank(a.status) - rank(b.status);
|
|
7502
|
+
if (r !== 0) return r;
|
|
7503
|
+
return a.id.localeCompare(b.id, void 0, { numeric: true });
|
|
7504
|
+
});
|
|
7505
|
+
return { summary, items, modules: [...allModules].sort() };
|
|
7506
|
+
}
|
|
7507
|
+
function toListItem(a) {
|
|
7508
|
+
return {
|
|
7509
|
+
id: a.id || a.title,
|
|
7510
|
+
title: a.title || a.id,
|
|
7511
|
+
type: a.type,
|
|
7512
|
+
status: lifecycleStateOf({ status: a.status, filePath: a.filePath }),
|
|
7513
|
+
implementationStatus: a.implementationStatus || null,
|
|
7514
|
+
validationStatus: a.validationStatus || null,
|
|
7515
|
+
releaseStatus: a.releaseStatus || null,
|
|
7516
|
+
affectedModules: a.affectedModules,
|
|
7517
|
+
scopeConfidenceLevel: a.scopeConfidence?.level ?? null,
|
|
7518
|
+
initiative: a.initiative || null
|
|
7519
|
+
};
|
|
7520
|
+
}
|
|
7521
|
+
function getWorkItem(dir, workItemId) {
|
|
7522
|
+
const artifacts = discoverWorkItems(dir);
|
|
7523
|
+
const match = artifacts.find((a) => (a.id || a.title) === workItemId);
|
|
7524
|
+
if (!match) throw new WorkItemNotFoundError(workItemId);
|
|
7525
|
+
const base = toListItem(match);
|
|
7526
|
+
const body = readBody(match.filePath);
|
|
7527
|
+
const sections = splitSections(body);
|
|
7528
|
+
const fm = match.rawFrontmatter;
|
|
7529
|
+
const knowledge = discoverKnowledge(dir).filter((a) => !a.isWorkItem);
|
|
7530
|
+
const knowledgeById = new Map(knowledge.filter((k) => k.id).map((k) => [k.id, k]));
|
|
7531
|
+
return {
|
|
7532
|
+
...base,
|
|
7533
|
+
actor: sectionText(sections, ["actor"]),
|
|
7534
|
+
outcome: sectionText(sections, ["actor and outcome", "outcome", "expected result"]),
|
|
7535
|
+
currentBehavior: sectionText(sections, ["current behavior", "current behaviour"]),
|
|
7536
|
+
targetBehavior: sectionText(sections, ["target behavior", "target behaviour"]),
|
|
7537
|
+
entryPoints: sectionText(sections, ["entry points"]),
|
|
7538
|
+
endToEndFlow: sectionText(sections, ["end-to-end flow", "end to end flow", "flow"]),
|
|
7539
|
+
scopeConfidence: match.scopeConfidence,
|
|
7540
|
+
scopeUnknowns: sectionBullets(sections, ["scope unknowns", "open scope questions"]),
|
|
7541
|
+
moduleCoverage: normalizeCoverage(match.moduleCoverage),
|
|
7542
|
+
impactAnalysis: normalizeImpact(match.impactAnalysis),
|
|
7543
|
+
acceptanceCriteria: parseAcceptanceCriteria(sections),
|
|
7544
|
+
implementationEvidence: parseEvidence(fm),
|
|
7545
|
+
releaseGates: parseReleaseGates(fm),
|
|
7546
|
+
completionExceptions: parseExceptions(fm),
|
|
7547
|
+
decisions: parseDecisions(match.decisions, knowledgeById),
|
|
7548
|
+
relatedKnowledge: parseRelatedKnowledge(fm, knowledgeById),
|
|
7549
|
+
source: parseWorkItemSource(fm),
|
|
7550
|
+
path: match.relPath
|
|
7551
|
+
};
|
|
7552
|
+
}
|
|
7553
|
+
function readBody(filePath) {
|
|
7554
|
+
try {
|
|
7555
|
+
const raw = readFile(filePath);
|
|
7556
|
+
return matter6(raw).content;
|
|
7557
|
+
} catch {
|
|
7558
|
+
return "";
|
|
7559
|
+
}
|
|
7560
|
+
}
|
|
7561
|
+
function splitSections(body) {
|
|
7562
|
+
const sections = /* @__PURE__ */ new Map();
|
|
7563
|
+
const lines = body.split(/\r?\n/);
|
|
7564
|
+
let current = null;
|
|
7565
|
+
let buffer = [];
|
|
7566
|
+
const flush = () => {
|
|
7567
|
+
if (current !== null) sections.set(current, buffer.join("\n").trim());
|
|
7568
|
+
buffer = [];
|
|
7569
|
+
};
|
|
7570
|
+
for (const line of lines) {
|
|
7571
|
+
const m = line.match(/^#{1,6}\s+(.*?)\s*$/);
|
|
7572
|
+
if (m) {
|
|
7573
|
+
flush();
|
|
7574
|
+
current = m[1].toLowerCase().replace(/[`*_]/g, "").trim();
|
|
7575
|
+
} else if (current !== null) {
|
|
7576
|
+
buffer.push(line);
|
|
7577
|
+
}
|
|
7578
|
+
}
|
|
7579
|
+
flush();
|
|
7580
|
+
return sections;
|
|
7581
|
+
}
|
|
7582
|
+
function isPlaceholder(text3) {
|
|
7583
|
+
const t = text3.trim();
|
|
7584
|
+
if (!t) return true;
|
|
7585
|
+
if (/^tbd$/i.test(t)) return true;
|
|
7586
|
+
if (/^_[^_]*_$/.test(t) && !t.includes("\n")) return true;
|
|
7587
|
+
return false;
|
|
7588
|
+
}
|
|
7589
|
+
function sectionText(sections, headings) {
|
|
7590
|
+
for (const h of headings) {
|
|
7591
|
+
const body = sections.get(h);
|
|
7592
|
+
if (body != null && !isPlaceholder(body)) return body.trim();
|
|
7593
|
+
}
|
|
7594
|
+
return null;
|
|
7595
|
+
}
|
|
7596
|
+
function sectionBullets(sections, headings) {
|
|
7597
|
+
for (const h of headings) {
|
|
7598
|
+
const body = sections.get(h);
|
|
7599
|
+
if (body == null || isPlaceholder(body)) continue;
|
|
7600
|
+
const bullets = extractBullets(body);
|
|
7601
|
+
if (bullets.length > 0) return bullets.map((b) => b.text);
|
|
7602
|
+
}
|
|
7603
|
+
return [];
|
|
7604
|
+
}
|
|
7605
|
+
function extractBullets(body) {
|
|
7606
|
+
const out = [];
|
|
7607
|
+
for (const line of body.split(/\r?\n/)) {
|
|
7608
|
+
const m = line.match(/^\s*[-*+]\s+(.*)$/);
|
|
7609
|
+
if (!m) continue;
|
|
7610
|
+
let text3 = m[1].trim();
|
|
7611
|
+
let checked = null;
|
|
7612
|
+
const cb = text3.match(/^\[([ xX])\]\s*(.*)$/);
|
|
7613
|
+
if (cb) {
|
|
7614
|
+
checked = cb[1].toLowerCase() === "x";
|
|
7615
|
+
text3 = cb[2].trim();
|
|
7616
|
+
}
|
|
7617
|
+
if (!text3 || isPlaceholder(text3)) continue;
|
|
7618
|
+
out.push({ text: text3, checked });
|
|
7619
|
+
}
|
|
7620
|
+
return out;
|
|
7621
|
+
}
|
|
7622
|
+
function parseAcceptanceCriteria(sections) {
|
|
7623
|
+
const body = sections.get("acceptance criteria");
|
|
7624
|
+
if (body == null || isPlaceholder(body)) return [];
|
|
7625
|
+
return extractBullets(body).map((b) => ({ text: b.text, checked: b.checked }));
|
|
7626
|
+
}
|
|
7627
|
+
function normalizeCoverage(mc) {
|
|
7628
|
+
if (!mc) return [];
|
|
7629
|
+
return Object.entries(mc).map(([id, v]) => ({ id, status: v.status, ...v.reason ? { reason: v.reason } : {} }));
|
|
7630
|
+
}
|
|
7631
|
+
function normalizeImpact(ia) {
|
|
7632
|
+
if (!ia) return [];
|
|
7633
|
+
return Object.entries(ia).map(([surface, v]) => ({
|
|
7634
|
+
surface,
|
|
7635
|
+
status: v.status,
|
|
7636
|
+
...v.reason ? { reason: v.reason } : {},
|
|
7637
|
+
...v.question ? { question: v.question } : {}
|
|
7638
|
+
}));
|
|
7639
|
+
}
|
|
7640
|
+
function optStr2(v) {
|
|
7641
|
+
if (typeof v === "string" && v.trim()) return v.trim();
|
|
7642
|
+
return void 0;
|
|
7643
|
+
}
|
|
7644
|
+
function parseEvidence(fm) {
|
|
7645
|
+
const evidence = fm.implementation_evidence;
|
|
7646
|
+
const repos = evidence?.repositories;
|
|
7647
|
+
if (!repos || typeof repos !== "object" || Array.isArray(repos)) return [];
|
|
7648
|
+
const out = [];
|
|
7649
|
+
for (const [module, val] of Object.entries(repos)) {
|
|
7650
|
+
if (!val || typeof val !== "object" || Array.isArray(val)) continue;
|
|
7651
|
+
const d = val;
|
|
7652
|
+
const validations = Array.isArray(d.validations) ? d.validations.map((v) => ({
|
|
7653
|
+
command: String(v.command ?? ""),
|
|
7654
|
+
status: String(v.status ?? "unknown"),
|
|
7655
|
+
...optStr2(v.reason) ? { reason: optStr2(v.reason) } : {}
|
|
7656
|
+
})) : [];
|
|
7657
|
+
const migrations = Array.isArray(d.migrations) ? d.migrations.map((m) => ({
|
|
7658
|
+
id: String(m.id ?? ""),
|
|
7659
|
+
environment: String(m.environment ?? ""),
|
|
7660
|
+
status: String(m.status ?? "unknown"),
|
|
7661
|
+
...optStr2(m.reason) ? { reason: optStr2(m.reason) } : {}
|
|
7662
|
+
})) : [];
|
|
7663
|
+
out.push({
|
|
7664
|
+
module,
|
|
7665
|
+
role: String(d.role ?? (module === "core" ? "core" : "module")),
|
|
7666
|
+
status: String(d.status ?? "unknown"),
|
|
7667
|
+
changedPaths: Array.isArray(d.changed_paths) ? d.changed_paths.map(String).filter(Boolean) : [],
|
|
7668
|
+
validations,
|
|
7669
|
+
migrations
|
|
7670
|
+
});
|
|
7671
|
+
}
|
|
7672
|
+
return out;
|
|
7673
|
+
}
|
|
7674
|
+
function parseReleaseGates(fm) {
|
|
7675
|
+
if (!Array.isArray(fm.release_gates)) return [];
|
|
7676
|
+
return fm.release_gates.filter((g) => g && typeof g === "object").map((g) => ({
|
|
7677
|
+
id: String(g.id ?? ""),
|
|
7678
|
+
status: String(g.status ?? "pending"),
|
|
7679
|
+
...optStr2(g.reason) ? { reason: optStr2(g.reason) } : {},
|
|
7680
|
+
...optStr2(g.required_for) ? { requiredFor: optStr2(g.required_for) } : {}
|
|
7681
|
+
}));
|
|
7682
|
+
}
|
|
7683
|
+
function parseExceptions(fm) {
|
|
7684
|
+
if (!Array.isArray(fm.completion_exceptions)) return [];
|
|
7685
|
+
return fm.completion_exceptions.filter((e) => e && typeof e === "object").map((e) => ({
|
|
7686
|
+
id: String(e.id ?? ""),
|
|
7687
|
+
status: String(e.status ?? "proposed"),
|
|
7688
|
+
...optStr2(e.reason) ? { reason: optStr2(e.reason) } : {},
|
|
7689
|
+
...optStr2(e.category) ? { category: optStr2(e.category) } : {},
|
|
7690
|
+
...optStr2(e.impact) ? { impact: optStr2(e.impact) } : {}
|
|
7691
|
+
}));
|
|
7692
|
+
}
|
|
7693
|
+
function parseDecisions(decisions, knowledgeById) {
|
|
7694
|
+
return decisions.map((id) => {
|
|
7695
|
+
const k = knowledgeById.get(id);
|
|
7696
|
+
return {
|
|
7697
|
+
id,
|
|
7698
|
+
...k?.title ? { title: k.title } : {},
|
|
7699
|
+
...k ? { knowledgeId: k.id, knowledgeLayer: k.layer } : {}
|
|
7700
|
+
};
|
|
7701
|
+
});
|
|
7702
|
+
}
|
|
7703
|
+
function parseRelatedKnowledge(fm, knowledgeById) {
|
|
7704
|
+
const refs = /* @__PURE__ */ new Set();
|
|
7705
|
+
for (const field of ["related_knowledge", "knowledge", "related"]) {
|
|
7706
|
+
const v = fm[field];
|
|
7707
|
+
if (Array.isArray(v)) {
|
|
7708
|
+
for (const r of v) if (typeof r === "string" && r.trim()) refs.add(r.trim());
|
|
7709
|
+
}
|
|
7710
|
+
}
|
|
7711
|
+
const out = [];
|
|
7712
|
+
for (const ref of refs) {
|
|
7713
|
+
const k = knowledgeById.get(ref);
|
|
7714
|
+
if (k && k.id) out.push({ id: k.id, title: k.title || k.id, layer: k.layer });
|
|
7715
|
+
}
|
|
7716
|
+
return out;
|
|
7717
|
+
}
|
|
7453
7718
|
export {
|
|
7719
|
+
WorkItemNotFoundError,
|
|
7454
7720
|
analyzeCrossRepoEvidence,
|
|
7455
7721
|
analyzeScopeCoverage,
|
|
7456
7722
|
buildProjectExplanation,
|
|
7457
7723
|
buildProjectRoute,
|
|
7458
7724
|
buildReadinessReport,
|
|
7459
7725
|
cwd,
|
|
7726
|
+
discoverKnowledge,
|
|
7460
7727
|
discoverWorkItems,
|
|
7461
7728
|
exists,
|
|
7729
|
+
getWorkItem,
|
|
7730
|
+
getWorkItems,
|
|
7731
|
+
getWorkItemsSummary,
|
|
7462
7732
|
isActiveState,
|
|
7463
7733
|
isModule,
|
|
7464
7734
|
join,
|