@unbrained/pm-cli 2026.5.1 → 2026.5.3-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/AGENTS.md +8 -1
- package/CHANGELOG.md +73 -4
- package/CONTRIBUTING.md +11 -5
- package/PRD.md +17 -1
- package/README.md +55 -1099
- package/SECURITY.md +6 -11
- package/dist/cli/bootstrap-args.d.ts +18 -0
- package/dist/cli/bootstrap-args.js +242 -0
- package/dist/cli/bootstrap-args.js.map +1 -0
- package/dist/cli/commander-usage.d.ts +17 -0
- package/dist/cli/commander-usage.js +178 -0
- package/dist/cli/commander-usage.js.map +1 -0
- package/dist/cli/commands/activity.d.ts +10 -0
- package/dist/cli/commands/activity.js +14 -10
- package/dist/cli/commands/activity.js.map +1 -1
- package/dist/cli/commands/aggregate.js.map +1 -1
- package/dist/cli/commands/append.js.map +1 -1
- package/dist/cli/commands/calendar.js +19 -34
- package/dist/cli/commands/calendar.js.map +1 -1
- package/dist/cli/commands/claim.js.map +1 -1
- package/dist/cli/commands/close.js.map +1 -1
- package/dist/cli/commands/comments-audit.js.map +1 -1
- package/dist/cli/commands/comments.js +1 -9
- package/dist/cli/commands/comments.js.map +1 -1
- package/dist/cli/commands/completion.js.map +1 -1
- package/dist/cli/commands/config.d.ts +21 -3
- package/dist/cli/commands/config.js +118 -2
- package/dist/cli/commands/config.js.map +1 -1
- package/dist/cli/commands/context.d.ts +90 -1
- package/dist/cli/commands/context.js +496 -12
- package/dist/cli/commands/context.js.map +1 -1
- package/dist/cli/commands/contracts.js.map +1 -1
- package/dist/cli/commands/create.js +2 -2
- package/dist/cli/commands/create.js.map +1 -1
- package/dist/cli/commands/dedupe-audit.js +2 -11
- package/dist/cli/commands/dedupe-audit.js.map +1 -1
- package/dist/cli/commands/delete.js.map +1 -1
- package/dist/cli/commands/deps.js.map +1 -1
- package/dist/cli/commands/docs.js.map +1 -1
- package/dist/cli/commands/extension.js.map +1 -1
- package/dist/cli/commands/files.js +14 -2
- package/dist/cli/commands/files.js.map +1 -1
- package/dist/cli/commands/gc.js.map +1 -1
- package/dist/cli/commands/get.js.map +1 -1
- package/dist/cli/commands/health.js +16 -12
- package/dist/cli/commands/health.js.map +1 -1
- package/dist/cli/commands/history.js +1 -9
- package/dist/cli/commands/history.js.map +1 -1
- package/dist/cli/commands/index.js.map +1 -1
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/learnings.js +1 -9
- package/dist/cli/commands/learnings.js.map +1 -1
- package/dist/cli/commands/list.d.ts +1 -0
- package/dist/cli/commands/list.js +13 -31
- package/dist/cli/commands/list.js.map +1 -1
- package/dist/cli/commands/normalize.js +14 -23
- package/dist/cli/commands/normalize.js.map +1 -1
- package/dist/cli/commands/notes.js +1 -9
- package/dist/cli/commands/notes.js.map +1 -1
- package/dist/cli/commands/reindex.js +2 -7
- package/dist/cli/commands/reindex.js.map +1 -1
- package/dist/cli/commands/restore.js.map +1 -1
- package/dist/cli/commands/search.js +4 -35
- package/dist/cli/commands/search.js.map +1 -1
- package/dist/cli/commands/stats.js.map +1 -1
- package/dist/cli/commands/templates.js.map +1 -1
- package/dist/cli/commands/test-all.js.map +1 -1
- package/dist/cli/commands/test-runs.js +1 -11
- package/dist/cli/commands/test-runs.js.map +1 -1
- package/dist/cli/commands/test.js.map +1 -1
- package/dist/cli/commands/update-many.js +1 -6
- package/dist/cli/commands/update-many.js.map +1 -1
- package/dist/cli/commands/update.js +2 -2
- package/dist/cli/commands/update.js.map +1 -1
- package/dist/cli/commands/validate.js +23 -18
- package/dist/cli/commands/validate.js.map +1 -1
- package/dist/cli/error-guidance.d.ts +13 -0
- package/dist/cli/error-guidance.js +56 -6
- package/dist/cli/error-guidance.js.map +1 -1
- package/dist/cli/extension-command-help.d.ts +48 -0
- package/dist/cli/extension-command-help.js +389 -0
- package/dist/cli/extension-command-help.js.map +1 -0
- package/dist/cli/extension-command-options.js.map +1 -1
- package/dist/cli/help-content.js +9 -3
- package/dist/cli/help-content.js.map +1 -1
- package/dist/cli/help-json-payload.d.ts +25 -0
- package/dist/cli/help-json-payload.js +265 -0
- package/dist/cli/help-json-payload.js.map +1 -0
- package/dist/cli/main.js +1000 -4456
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/migration-gates.d.ts +22 -0
- package/dist/cli/migration-gates.js +146 -0
- package/dist/cli/migration-gates.js.map +1 -0
- package/dist/cli/register-list-query.d.ts +2 -0
- package/dist/cli/register-list-query.js +317 -0
- package/dist/cli/register-list-query.js.map +1 -0
- package/dist/cli/register-mutation.d.ts +2 -0
- package/dist/cli/register-mutation.js +795 -0
- package/dist/cli/register-mutation.js.map +1 -0
- package/dist/cli/register-operations.d.ts +2 -0
- package/dist/cli/register-operations.js +610 -0
- package/dist/cli/register-operations.js.map +1 -0
- package/dist/cli/register-setup.d.ts +2 -0
- package/dist/cli/register-setup.js +334 -0
- package/dist/cli/register-setup.js.map +1 -0
- package/dist/cli/registration-helpers.d.ts +53 -0
- package/dist/cli/registration-helpers.js +669 -0
- package/dist/cli/registration-helpers.js.map +1 -0
- package/dist/cli/shared-parsers.d.ts +6 -0
- package/dist/cli/shared-parsers.js +40 -0
- package/dist/cli/shared-parsers.js.map +1 -0
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +3 -1
- package/dist/cli.js.map +1 -1
- package/dist/core/extensions/extension-types.d.ts +605 -0
- package/dist/core/extensions/extension-types.js +22 -0
- package/dist/core/extensions/extension-types.js.map +1 -0
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/item-fields.js.map +1 -1
- package/dist/core/extensions/loader.d.ts +2 -586
- package/dist/core/extensions/loader.js +3 -21
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runtime-registrations.js.map +1 -1
- package/dist/core/fs/fs-utils.js.map +1 -1
- package/dist/core/fs/index.js.map +1 -1
- package/dist/core/history/history-stream-policy.js.map +1 -1
- package/dist/core/history/history.js.map +1 -1
- package/dist/core/history/index.js.map +1 -1
- package/dist/core/item/id.js.map +1 -1
- package/dist/core/item/index.js.map +1 -1
- package/dist/core/item/item-format.js.map +1 -1
- package/dist/core/item/parent-reference-policy.js.map +1 -1
- package/dist/core/item/parse.js +6 -0
- package/dist/core/item/parse.js.map +1 -1
- package/dist/core/item/sprint-release-format.js.map +1 -1
- package/dist/core/item/status.js.map +1 -1
- package/dist/core/item/type-registry.js.map +1 -1
- package/dist/core/lock/index.js.map +1 -1
- package/dist/core/lock/lock.js +1 -6
- package/dist/core/lock/lock.js.map +1 -1
- package/dist/core/output/command-aware.js.map +1 -1
- package/dist/core/output/output.js.map +1 -1
- package/dist/core/schema/runtime-field-filters.js.map +1 -1
- package/dist/core/schema/runtime-field-values.js.map +1 -1
- package/dist/core/schema/runtime-schema.js.map +1 -1
- package/dist/core/search/cache.js +1 -7
- package/dist/core/search/cache.js.map +1 -1
- package/dist/core/search/embedding-batches.js +4 -0
- package/dist/core/search/embedding-batches.js.map +1 -1
- package/dist/core/search/http-client.d.ts +29 -0
- package/dist/core/search/http-client.js +64 -0
- package/dist/core/search/http-client.js.map +1 -0
- package/dist/core/search/providers.d.ts +3 -13
- package/dist/core/search/providers.js +19 -88
- package/dist/core/search/providers.js.map +1 -1
- package/dist/core/search/semantic-defaults.js +2 -7
- package/dist/core/search/semantic-defaults.js.map +1 -1
- package/dist/core/search/vector-stores.d.ts +4 -13
- package/dist/core/search/vector-stores.js +40 -93
- package/dist/core/search/vector-stores.js.map +1 -1
- package/dist/core/sentry/helpers.d.ts +27 -0
- package/dist/core/sentry/helpers.js +171 -0
- package/dist/core/sentry/helpers.js.map +1 -0
- package/dist/core/sentry/instrument.d.ts +25 -0
- package/dist/core/sentry/instrument.js +204 -0
- package/dist/core/sentry/instrument.js.map +1 -0
- package/dist/core/shared/command-types.js.map +1 -1
- package/dist/core/shared/conflict-markers.js.map +1 -1
- package/dist/core/shared/constants.d.ts +3 -0
- package/dist/core/shared/constants.js +58 -1
- package/dist/core/shared/constants.js.map +1 -1
- package/dist/core/shared/errors.js.map +1 -1
- package/dist/core/shared/index.d.ts +1 -0
- package/dist/core/shared/index.js +1 -0
- package/dist/core/shared/index.js.map +1 -1
- package/dist/core/shared/primitives.d.ts +13 -0
- package/dist/core/shared/primitives.js +33 -0
- package/dist/core/shared/primitives.js.map +1 -0
- package/dist/core/shared/serialization.js.map +1 -1
- package/dist/core/shared/text-normalization.js.map +1 -1
- package/dist/core/shared/time.js.map +1 -1
- package/dist/core/store/front-matter-cache.d.ts +6 -0
- package/dist/core/store/front-matter-cache.js +150 -0
- package/dist/core/store/front-matter-cache.js.map +1 -0
- package/dist/core/store/index.js.map +1 -1
- package/dist/core/store/item-format-migration.js.map +1 -1
- package/dist/core/store/item-store.js +46 -36
- package/dist/core/store/item-store.js.map +1 -1
- package/dist/core/store/paths.js.map +1 -1
- package/dist/core/store/settings.js +36 -0
- package/dist/core/store/settings.js.map +1 -1
- package/dist/core/telemetry/consent.js.map +1 -1
- package/dist/core/telemetry/observability.d.ts +24 -0
- package/dist/core/telemetry/observability.js +185 -0
- package/dist/core/telemetry/observability.js.map +1 -0
- package/dist/core/telemetry/runtime.d.ts +29 -3
- package/dist/core/telemetry/runtime.js +337 -25
- package/dist/core/telemetry/runtime.js.map +1 -1
- package/dist/core/test/background-runs.js.map +1 -1
- package/dist/core/test/item-test-run-tracking.js.map +1 -1
- package/dist/sdk/cli-contracts.js +28 -0
- package/dist/sdk/cli-contracts.js.map +1 -1
- package/dist/sdk/index.d.ts +1 -1
- package/dist/sdk/index.js.map +1 -1
- package/dist/types/index.js.map +1 -1
- package/dist/types.d.ts +21 -0
- package/dist/types.js +11 -0
- package/dist/types.js.map +1 -1
- package/docs/AGENT_GUIDE.md +125 -0
- package/docs/ARCHITECTURE.md +201 -478
- package/docs/COMMANDS.md +209 -0
- package/docs/CONFIGURATION.md +146 -0
- package/docs/EXTENSIONS.md +146 -645
- package/docs/QUICKSTART.md +108 -0
- package/docs/README.md +70 -0
- package/docs/RELEASING.md +92 -50
- package/docs/SDK.md +127 -68
- package/docs/TESTING.md +125 -0
- package/docs/examples/starter-extension/README.md +39 -25
- package/package.json +24 -11
- package/dist/command-types.d.ts +0 -1
- package/dist/command-types.js +0 -2
- package/dist/command-types.js.map +0 -1
- package/dist/constants.d.ts +0 -1
- package/dist/constants.js +0 -2
- package/dist/constants.js.map +0 -1
- package/dist/errors.d.ts +0 -1
- package/dist/errors.js +0 -2
- package/dist/errors.js.map +0 -1
- package/dist/fs-utils.d.ts +0 -1
- package/dist/fs-utils.js +0 -2
- package/dist/fs-utils.js.map +0 -1
- package/dist/history.d.ts +0 -1
- package/dist/history.js +0 -2
- package/dist/history.js.map +0 -1
- package/dist/id.d.ts +0 -1
- package/dist/id.js +0 -2
- package/dist/id.js.map +0 -1
- package/dist/item-format.d.ts +0 -1
- package/dist/item-format.js +0 -2
- package/dist/item-format.js.map +0 -1
- package/dist/item-store.d.ts +0 -1
- package/dist/item-store.js +0 -2
- package/dist/item-store.js.map +0 -1
- package/dist/lock.d.ts +0 -1
- package/dist/lock.js +0 -2
- package/dist/lock.js.map +0 -1
- package/dist/output.d.ts +0 -1
- package/dist/output.js +0 -2
- package/dist/output.js.map +0 -1
- package/dist/parse.d.ts +0 -1
- package/dist/parse.js +0 -2
- package/dist/parse.js.map +0 -1
- package/dist/paths.d.ts +0 -1
- package/dist/paths.js +0 -2
- package/dist/paths.js.map +0 -1
- package/dist/serialization.d.ts +0 -1
- package/dist/serialization.js +0 -2
- package/dist/serialization.js.map +0 -1
- package/dist/settings.d.ts +0 -1
- package/dist/settings.js +0 -2
- package/dist/settings.js.map +0 -1
- package/dist/time.d.ts +0 -1
- package/dist/time.js +0 -2
- package/dist/time.js.map +0 -1
|
@@ -1,15 +1,35 @@
|
|
|
1
|
-
import { EXIT_CODE } from "../../core/shared/constants.js";
|
|
1
|
+
import { SETTINGS_DEFAULTS, EXIT_CODE } from "../../core/shared/constants.js";
|
|
2
2
|
import { PmCliError } from "../../core/shared/errors.js";
|
|
3
3
|
import { compareTimestampStrings } from "../../core/shared/time.js";
|
|
4
4
|
import { normalizeStatusInput } from "../../core/item/status.js";
|
|
5
5
|
import { resolveRuntimeStatusRegistry } from "../../core/schema/runtime-schema.js";
|
|
6
6
|
import { resolvePmRoot } from "../../core/store/paths.js";
|
|
7
7
|
import { readSettings } from "../../core/store/settings.js";
|
|
8
|
+
import { CONTEXT_DEPTH_VALUES, CONTEXT_SECTION_VALUES } from "../../types/index.js";
|
|
9
|
+
import { parseIntegerLimit } from "../shared-parsers.js";
|
|
8
10
|
import { runCalendar } from "./calendar.js";
|
|
9
11
|
import { runList } from "./list.js";
|
|
12
|
+
import { runActivity } from "./activity.js";
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// Output format
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
10
16
|
export const CONTEXT_OUTPUT_VALUES = ["markdown", "toon", "json"];
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
// Constants
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
11
20
|
const HIGH_LEVEL_TYPES = new Set(["Epic", "Feature"]);
|
|
12
21
|
const DEFAULT_CONTEXT_LIMIT = 10;
|
|
22
|
+
const STANDARD_SECTIONS = ["hierarchy", "activity", "progress", "workload"];
|
|
23
|
+
const DEEP_SECTIONS = [
|
|
24
|
+
...STANDARD_SECTIONS,
|
|
25
|
+
"blockers",
|
|
26
|
+
"files",
|
|
27
|
+
"staleness",
|
|
28
|
+
"tests",
|
|
29
|
+
];
|
|
30
|
+
// ---------------------------------------------------------------------------
|
|
31
|
+
// Parsers
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
13
33
|
function parseOutputFormat(raw) {
|
|
14
34
|
if (!raw)
|
|
15
35
|
return undefined;
|
|
@@ -29,16 +49,59 @@ export function resolveContextOutputFormat(options, global) {
|
|
|
29
49
|
}
|
|
30
50
|
return commandFormat ?? "toon";
|
|
31
51
|
}
|
|
32
|
-
function
|
|
33
|
-
|
|
34
|
-
|
|
52
|
+
function parseContextLimit(raw) {
|
|
53
|
+
return parseIntegerLimit(raw, "--limit") ?? DEFAULT_CONTEXT_LIMIT;
|
|
54
|
+
}
|
|
55
|
+
export function parseContextDepth(raw, settings) {
|
|
56
|
+
if (!raw)
|
|
57
|
+
return settings.default_depth;
|
|
58
|
+
const normalized = raw.trim().toLowerCase();
|
|
59
|
+
if (!CONTEXT_DEPTH_VALUES.includes(normalized)) {
|
|
60
|
+
throw new PmCliError(`Context --depth must be one of ${CONTEXT_DEPTH_VALUES.join("|")}`, EXIT_CODE.USAGE);
|
|
61
|
+
}
|
|
62
|
+
return normalized;
|
|
63
|
+
}
|
|
64
|
+
export function parseContextSections(raw, depth, settings) {
|
|
65
|
+
if (raw && raw.length > 0) {
|
|
66
|
+
const sections = [];
|
|
67
|
+
for (const value of raw) {
|
|
68
|
+
const normalized = value.trim().toLowerCase();
|
|
69
|
+
if (!CONTEXT_SECTION_VALUES.includes(normalized)) {
|
|
70
|
+
throw new PmCliError(`Context --section must be one of ${CONTEXT_SECTION_VALUES.join("|")}`, EXIT_CODE.USAGE);
|
|
71
|
+
}
|
|
72
|
+
if (!sections.includes(normalized)) {
|
|
73
|
+
sections.push(normalized);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return sections;
|
|
77
|
+
}
|
|
78
|
+
if (depth === "brief")
|
|
79
|
+
return [];
|
|
80
|
+
const pool = depth === "deep" ? DEEP_SECTIONS : STANDARD_SECTIONS;
|
|
81
|
+
return pool.filter((section) => settings.sections[section]);
|
|
82
|
+
}
|
|
83
|
+
function parseActivityLimit(raw, settings) {
|
|
84
|
+
if (!raw)
|
|
85
|
+
return settings.activity_limit;
|
|
86
|
+
return parseIntegerLimit(raw, "--activity-limit") ?? settings.activity_limit;
|
|
87
|
+
}
|
|
88
|
+
function parseStaleThresholdDays(raw, settings) {
|
|
89
|
+
if (!raw)
|
|
90
|
+
return settings.stale_threshold_days;
|
|
91
|
+
const trimmed = raw.trim().toLowerCase();
|
|
92
|
+
const match = /^(\d+)d?$/.exec(trimmed);
|
|
93
|
+
if (!match) {
|
|
94
|
+
throw new PmCliError("--stale-threshold must be a number of days (e.g. 7 or 7d)", EXIT_CODE.USAGE);
|
|
35
95
|
}
|
|
36
|
-
const
|
|
37
|
-
if (
|
|
38
|
-
throw new PmCliError("
|
|
96
|
+
const days = parseInt(match[1], 10);
|
|
97
|
+
if (days <= 0) {
|
|
98
|
+
throw new PmCliError("--stale-threshold must be positive", EXIT_CODE.USAGE);
|
|
39
99
|
}
|
|
40
|
-
return
|
|
100
|
+
return days;
|
|
41
101
|
}
|
|
102
|
+
// ---------------------------------------------------------------------------
|
|
103
|
+
// Status helpers
|
|
104
|
+
// ---------------------------------------------------------------------------
|
|
42
105
|
function normalizeStatusForRegistry(status, statusRegistry) {
|
|
43
106
|
return normalizeStatusInput(status, statusRegistry) ?? status;
|
|
44
107
|
}
|
|
@@ -64,6 +127,27 @@ function statusRank(status, statusRegistry) {
|
|
|
64
127
|
return 7;
|
|
65
128
|
return 6;
|
|
66
129
|
}
|
|
130
|
+
function isTerminal(status, statusRegistry) {
|
|
131
|
+
return statusRegistry.terminal_statuses.has(normalizeStatusForRegistry(status, statusRegistry));
|
|
132
|
+
}
|
|
133
|
+
function isClosedStatus(status, statusRegistry) {
|
|
134
|
+
const closeStatus = normalizeStatusInput("closed", statusRegistry);
|
|
135
|
+
return closeStatus ? normalizeStatusForRegistry(status, statusRegistry) === closeStatus : false;
|
|
136
|
+
}
|
|
137
|
+
function isInProgressStatus(status, statusRegistry) {
|
|
138
|
+
const inProgressStatus = normalizeStatusInput("in_progress", statusRegistry);
|
|
139
|
+
return inProgressStatus ? normalizeStatusForRegistry(status, statusRegistry) === inProgressStatus : false;
|
|
140
|
+
}
|
|
141
|
+
function isOpenStatus(status, statusRegistry) {
|
|
142
|
+
const openStatus = normalizeStatusInput("open", statusRegistry) ?? statusRegistry.open_status;
|
|
143
|
+
return normalizeStatusForRegistry(status, statusRegistry) === openStatus;
|
|
144
|
+
}
|
|
145
|
+
function isBlockedStatus(status, statusRegistry) {
|
|
146
|
+
return statusRegistry.blocked_statuses.has(normalizeStatusForRegistry(status, statusRegistry));
|
|
147
|
+
}
|
|
148
|
+
// ---------------------------------------------------------------------------
|
|
149
|
+
// Sorting / mapping helpers (unchanged from original)
|
|
150
|
+
// ---------------------------------------------------------------------------
|
|
67
151
|
function compareOptionalOrder(left, right) {
|
|
68
152
|
const leftValue = left ?? null;
|
|
69
153
|
const rightValue = right ?? null;
|
|
@@ -145,6 +229,249 @@ function summarizeAgenda(events) {
|
|
|
145
229
|
function filterTerminalCalendarEvents(events, statusRegistry) {
|
|
146
230
|
return events.filter((event) => !statusRegistry.terminal_statuses.has(normalizeStatusForRegistry(event.item_status, statusRegistry)));
|
|
147
231
|
}
|
|
232
|
+
// ---------------------------------------------------------------------------
|
|
233
|
+
// Section builders
|
|
234
|
+
// ---------------------------------------------------------------------------
|
|
235
|
+
function buildHierarchy(allItems, activeItems, statusRegistry, limit) {
|
|
236
|
+
const itemMap = new Map();
|
|
237
|
+
for (const item of allItems) {
|
|
238
|
+
itemMap.set(item.id, item);
|
|
239
|
+
}
|
|
240
|
+
const childrenByParent = new Map();
|
|
241
|
+
for (const item of allItems) {
|
|
242
|
+
if (!item.parent)
|
|
243
|
+
continue;
|
|
244
|
+
const children = childrenByParent.get(item.parent) ?? [];
|
|
245
|
+
children.push(item);
|
|
246
|
+
childrenByParent.set(item.parent, children);
|
|
247
|
+
}
|
|
248
|
+
const activeHighLevelIds = new Set(activeItems.filter((item) => HIGH_LEVEL_TYPES.has(item.type)).map((item) => item.id));
|
|
249
|
+
const nodes = [];
|
|
250
|
+
for (const parentId of activeHighLevelIds) {
|
|
251
|
+
const parent = itemMap.get(parentId);
|
|
252
|
+
if (!parent)
|
|
253
|
+
continue;
|
|
254
|
+
const allDescendants = collectDescendants(parentId, childrenByParent);
|
|
255
|
+
const childItems = childrenByParent.get(parentId) ?? [];
|
|
256
|
+
let closedCount = 0;
|
|
257
|
+
let openCount = 0;
|
|
258
|
+
let inProgressCount = 0;
|
|
259
|
+
let blockedCount = 0;
|
|
260
|
+
for (const desc of allDescendants) {
|
|
261
|
+
if (isClosedStatus(desc.status, statusRegistry))
|
|
262
|
+
closedCount++;
|
|
263
|
+
else if (isInProgressStatus(desc.status, statusRegistry))
|
|
264
|
+
inProgressCount++;
|
|
265
|
+
else if (isBlockedStatus(desc.status, statusRegistry))
|
|
266
|
+
blockedCount++;
|
|
267
|
+
else if (isOpenStatus(desc.status, statusRegistry))
|
|
268
|
+
openCount++;
|
|
269
|
+
}
|
|
270
|
+
const children = childItems
|
|
271
|
+
.sort((a, b) => compareCriticalItems(a, b, statusRegistry))
|
|
272
|
+
.slice(0, limit)
|
|
273
|
+
.map((child) => {
|
|
274
|
+
const grandchildren = collectDescendants(child.id, childrenByParent);
|
|
275
|
+
const gcClosed = grandchildren.filter((gc) => isClosedStatus(gc.status, statusRegistry)).length;
|
|
276
|
+
return {
|
|
277
|
+
id: child.id,
|
|
278
|
+
title: child.title,
|
|
279
|
+
type: child.type,
|
|
280
|
+
status: child.status,
|
|
281
|
+
children_total: grandchildren.length,
|
|
282
|
+
children_closed: gcClosed,
|
|
283
|
+
};
|
|
284
|
+
});
|
|
285
|
+
nodes.push({
|
|
286
|
+
id: parent.id,
|
|
287
|
+
title: parent.title,
|
|
288
|
+
type: parent.type,
|
|
289
|
+
status: parent.status,
|
|
290
|
+
children_total: allDescendants.length,
|
|
291
|
+
children_closed: closedCount,
|
|
292
|
+
children_open: openCount,
|
|
293
|
+
children_in_progress: inProgressCount,
|
|
294
|
+
children_blocked: blockedCount,
|
|
295
|
+
children,
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
return nodes
|
|
299
|
+
.sort((a, b) => {
|
|
300
|
+
const aParent = itemMap.get(a.id);
|
|
301
|
+
const bParent = itemMap.get(b.id);
|
|
302
|
+
return compareCriticalItems(aParent, bParent, statusRegistry);
|
|
303
|
+
})
|
|
304
|
+
.slice(0, limit);
|
|
305
|
+
}
|
|
306
|
+
function collectDescendants(parentId, childrenByParent) {
|
|
307
|
+
const result = [];
|
|
308
|
+
const stack = [parentId];
|
|
309
|
+
const visited = new Set();
|
|
310
|
+
while (stack.length > 0) {
|
|
311
|
+
const current = stack.pop();
|
|
312
|
+
if (visited.has(current))
|
|
313
|
+
continue;
|
|
314
|
+
visited.add(current);
|
|
315
|
+
const children = childrenByParent.get(current) ?? [];
|
|
316
|
+
for (const child of children) {
|
|
317
|
+
result.push(child);
|
|
318
|
+
stack.push(child.id);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
return result;
|
|
322
|
+
}
|
|
323
|
+
async function buildActivity(activityLimit, global) {
|
|
324
|
+
const result = await runActivity({ compact: true, limit: String(activityLimit) }, global);
|
|
325
|
+
return result.compact_activity ?? [];
|
|
326
|
+
}
|
|
327
|
+
function buildProgress(allItems, activeItems, statusRegistry, limit) {
|
|
328
|
+
const childrenByParent = new Map();
|
|
329
|
+
for (const item of allItems) {
|
|
330
|
+
if (!item.parent)
|
|
331
|
+
continue;
|
|
332
|
+
const children = childrenByParent.get(item.parent) ?? [];
|
|
333
|
+
children.push(item);
|
|
334
|
+
childrenByParent.set(item.parent, children);
|
|
335
|
+
}
|
|
336
|
+
const activeHighLevel = activeItems.filter((item) => HIGH_LEVEL_TYPES.has(item.type));
|
|
337
|
+
const entries = [];
|
|
338
|
+
for (const parent of activeHighLevel) {
|
|
339
|
+
const descendants = collectDescendants(parent.id, childrenByParent);
|
|
340
|
+
const total = descendants.length;
|
|
341
|
+
if (total === 0)
|
|
342
|
+
continue;
|
|
343
|
+
let closed = 0;
|
|
344
|
+
let open = 0;
|
|
345
|
+
let inProgress = 0;
|
|
346
|
+
let blocked = 0;
|
|
347
|
+
for (const desc of descendants) {
|
|
348
|
+
if (isClosedStatus(desc.status, statusRegistry))
|
|
349
|
+
closed++;
|
|
350
|
+
else if (isInProgressStatus(desc.status, statusRegistry))
|
|
351
|
+
inProgress++;
|
|
352
|
+
else if (isBlockedStatus(desc.status, statusRegistry))
|
|
353
|
+
blocked++;
|
|
354
|
+
else if (isOpenStatus(desc.status, statusRegistry))
|
|
355
|
+
open++;
|
|
356
|
+
}
|
|
357
|
+
entries.push({
|
|
358
|
+
id: parent.id,
|
|
359
|
+
title: parent.title,
|
|
360
|
+
type: parent.type,
|
|
361
|
+
total,
|
|
362
|
+
closed,
|
|
363
|
+
open,
|
|
364
|
+
in_progress: inProgress,
|
|
365
|
+
blocked,
|
|
366
|
+
completion_pct: total > 0 ? Math.round((closed / total) * 100) : 0,
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
return entries
|
|
370
|
+
.sort((a, b) => a.completion_pct - b.completion_pct)
|
|
371
|
+
.slice(0, limit);
|
|
372
|
+
}
|
|
373
|
+
function buildBlockers(blockedItems, itemMap, limit) {
|
|
374
|
+
return blockedItems.slice(0, limit).map((item) => {
|
|
375
|
+
const blockerItem = item.blocked_by ? itemMap.get(item.blocked_by) : undefined;
|
|
376
|
+
return {
|
|
377
|
+
id: item.id,
|
|
378
|
+
title: item.title,
|
|
379
|
+
blocked_by: item.blocked_by ?? null,
|
|
380
|
+
blocked_by_title: blockerItem?.title ?? null,
|
|
381
|
+
blocked_by_status: blockerItem?.status ?? null,
|
|
382
|
+
blocked_reason: item.blocked_reason ?? null,
|
|
383
|
+
unblock_note: item.unblock_note ?? null,
|
|
384
|
+
};
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
function buildHotFiles(activeItems, limit) {
|
|
388
|
+
const fileMap = new Map();
|
|
389
|
+
for (const item of activeItems) {
|
|
390
|
+
for (const file of item.files ?? []) {
|
|
391
|
+
const existing = fileMap.get(file.path) ?? new Set();
|
|
392
|
+
existing.add(item.id);
|
|
393
|
+
fileMap.set(file.path, existing);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
return [...fileMap.entries()]
|
|
397
|
+
.map(([filePath, itemIds]) => ({
|
|
398
|
+
path: filePath,
|
|
399
|
+
references: itemIds.size,
|
|
400
|
+
items: [...itemIds].sort(),
|
|
401
|
+
}))
|
|
402
|
+
.sort((a, b) => b.references - a.references)
|
|
403
|
+
.slice(0, limit);
|
|
404
|
+
}
|
|
405
|
+
function buildWorkload(activeItems, statusRegistry, limit) {
|
|
406
|
+
const groups = new Map();
|
|
407
|
+
for (const item of activeItems) {
|
|
408
|
+
const key = item.assignee ?? null;
|
|
409
|
+
const existing = groups.get(key) ?? [];
|
|
410
|
+
existing.push(item);
|
|
411
|
+
groups.set(key, existing);
|
|
412
|
+
}
|
|
413
|
+
return [...groups.entries()]
|
|
414
|
+
.map(([assignee, items]) => ({
|
|
415
|
+
assignee,
|
|
416
|
+
active: items.length,
|
|
417
|
+
in_progress: items.filter((item) => isInProgressStatus(item.status, statusRegistry)).length,
|
|
418
|
+
items: items.map((item) => item.id).sort(),
|
|
419
|
+
}))
|
|
420
|
+
.sort((a, b) => b.active - a.active)
|
|
421
|
+
.slice(0, limit);
|
|
422
|
+
}
|
|
423
|
+
function buildStaleness(allNonTerminal, staleThresholdDays, now, limit) {
|
|
424
|
+
const cutoffMs = new Date(now).getTime() - staleThresholdDays * 24 * 60 * 60 * 1000;
|
|
425
|
+
return allNonTerminal
|
|
426
|
+
.filter((item) => new Date(item.updated_at).getTime() < cutoffMs)
|
|
427
|
+
.map((item) => ({
|
|
428
|
+
id: item.id,
|
|
429
|
+
title: item.title,
|
|
430
|
+
status: item.status,
|
|
431
|
+
updated_at: item.updated_at,
|
|
432
|
+
stale_days: Math.floor((new Date(now).getTime() - new Date(item.updated_at).getTime()) / (24 * 60 * 60 * 1000)),
|
|
433
|
+
}))
|
|
434
|
+
.sort((a, b) => b.stale_days - a.stale_days)
|
|
435
|
+
.slice(0, limit);
|
|
436
|
+
}
|
|
437
|
+
function buildTestHealth(activeItems) {
|
|
438
|
+
let itemsWithTests = 0;
|
|
439
|
+
let itemsWithRecentRuns = 0;
|
|
440
|
+
let passed = 0;
|
|
441
|
+
let failed = 0;
|
|
442
|
+
let skipped = 0;
|
|
443
|
+
const itemsFailing = [];
|
|
444
|
+
for (const item of activeItems) {
|
|
445
|
+
if ((item.tests ?? []).length > 0) {
|
|
446
|
+
itemsWithTests++;
|
|
447
|
+
}
|
|
448
|
+
const runs = item.test_runs ?? [];
|
|
449
|
+
if (runs.length > 0) {
|
|
450
|
+
itemsWithRecentRuns++;
|
|
451
|
+
let itemHasFailure = false;
|
|
452
|
+
for (const run of runs) {
|
|
453
|
+
passed += run.passed ?? 0;
|
|
454
|
+
failed += run.failed ?? 0;
|
|
455
|
+
skipped += run.skipped ?? 0;
|
|
456
|
+
if ((run.failed ?? 0) > 0) {
|
|
457
|
+
itemHasFailure = true;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
if (itemHasFailure) {
|
|
461
|
+
itemsFailing.push(item.id);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
return {
|
|
466
|
+
items_with_tests: itemsWithTests,
|
|
467
|
+
items_with_recent_runs: itemsWithRecentRuns,
|
|
468
|
+
recent_runs: { passed, failed, skipped },
|
|
469
|
+
items_failing: itemsFailing.sort(),
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
// ---------------------------------------------------------------------------
|
|
473
|
+
// Markdown formatting
|
|
474
|
+
// ---------------------------------------------------------------------------
|
|
148
475
|
function formatClock(timestamp) {
|
|
149
476
|
return `${new Date(timestamp).toISOString().slice(11, 16)}Z`;
|
|
150
477
|
}
|
|
@@ -170,9 +497,16 @@ export function renderContextMarkdown(result) {
|
|
|
170
497
|
lines.push("# pm context");
|
|
171
498
|
lines.push("");
|
|
172
499
|
lines.push(`- now: ${result.now}`);
|
|
500
|
+
lines.push(`- depth: ${result.depth}`);
|
|
173
501
|
lines.push(`- active_items: ${result.summary.active_items} (in_progress: ${result.summary.in_progress}, open: ${result.summary.open})`);
|
|
502
|
+
if (result.summary.total_items !== undefined) {
|
|
503
|
+
lines.push(`- total_items: ${result.summary.total_items} (closed: ${result.summary.closed ?? 0}, canceled: ${result.summary.canceled ?? 0})`);
|
|
504
|
+
}
|
|
174
505
|
lines.push(`- agenda_events: ${result.summary.agenda_events}`);
|
|
175
506
|
lines.push(`- blocked_fallback_used: ${result.summary.blocked_fallback_used}`);
|
|
507
|
+
if (result.sections_included.length > 0) {
|
|
508
|
+
lines.push(`- sections: ${result.sections_included.join(", ")}`);
|
|
509
|
+
}
|
|
176
510
|
lines.push("");
|
|
177
511
|
lines.push("## High-level focus");
|
|
178
512
|
if (result.high_level.length === 0) {
|
|
@@ -211,16 +545,112 @@ export function renderContextMarkdown(result) {
|
|
|
211
545
|
lines.push(`- ${formatAgendaLine(event)}`);
|
|
212
546
|
}
|
|
213
547
|
}
|
|
548
|
+
lines.push("");
|
|
549
|
+
if (result.hierarchy && result.hierarchy.length > 0) {
|
|
550
|
+
lines.push("## Hierarchy");
|
|
551
|
+
for (const node of result.hierarchy) {
|
|
552
|
+
const pct = node.children_total > 0 ? Math.round((node.children_closed / node.children_total) * 100) : 0;
|
|
553
|
+
lines.push(`- ${node.id} ${node.type} ${node.status} "${node.title}" [${node.children_closed}/${node.children_total} done ${pct}%]`);
|
|
554
|
+
for (const child of node.children) {
|
|
555
|
+
const cpct = child.children_total > 0 ? Math.round((child.children_closed / child.children_total) * 100) : 0;
|
|
556
|
+
lines.push(` - ${child.id} ${child.type} ${child.status} "${child.title}" [${child.children_closed}/${child.children_total} done ${cpct}%]`);
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
lines.push("");
|
|
560
|
+
}
|
|
561
|
+
if (result.progress && result.progress.length > 0) {
|
|
562
|
+
lines.push("## Progress");
|
|
563
|
+
for (const entry of result.progress) {
|
|
564
|
+
lines.push(`- ${entry.id} "${entry.title}" ${entry.completion_pct}% (${entry.closed}/${entry.total} closed, ${entry.in_progress} wip, ${entry.open} open, ${entry.blocked} blocked)`);
|
|
565
|
+
}
|
|
566
|
+
lines.push("");
|
|
567
|
+
}
|
|
568
|
+
if (result.activity && result.activity.length > 0) {
|
|
569
|
+
lines.push("## Recent activity");
|
|
570
|
+
for (const entry of result.activity) {
|
|
571
|
+
const msg = entry.msg ? ` ${entry.msg}` : "";
|
|
572
|
+
lines.push(`- ${entry.ts.slice(0, 16)}Z ${entry.id} ${entry.op} by:${entry.author}${msg}`);
|
|
573
|
+
}
|
|
574
|
+
lines.push("");
|
|
575
|
+
}
|
|
576
|
+
if (result.blockers && result.blockers.length > 0) {
|
|
577
|
+
lines.push("## Blockers");
|
|
578
|
+
for (const entry of result.blockers) {
|
|
579
|
+
const by = entry.blocked_by ? `blocked_by:${entry.blocked_by}(${entry.blocked_by_status ?? "?"})` : "blocked_by:-";
|
|
580
|
+
const reason = entry.blocked_reason ? ` reason:"${entry.blocked_reason}"` : "";
|
|
581
|
+
const note = entry.unblock_note ? ` unblock:"${entry.unblock_note}"` : "";
|
|
582
|
+
lines.push(`- ${entry.id} "${entry.title}" ${by}${reason}${note}`);
|
|
583
|
+
}
|
|
584
|
+
lines.push("");
|
|
585
|
+
}
|
|
586
|
+
if (result.files && result.files.length > 0) {
|
|
587
|
+
lines.push("## Hot files");
|
|
588
|
+
for (const file of result.files) {
|
|
589
|
+
lines.push(`- ${file.path} refs:${file.references} items:[${file.items.join(",")}]`);
|
|
590
|
+
}
|
|
591
|
+
lines.push("");
|
|
592
|
+
}
|
|
593
|
+
if (result.workload && result.workload.length > 0) {
|
|
594
|
+
lines.push("## Workload");
|
|
595
|
+
for (const entry of result.workload) {
|
|
596
|
+
const who = entry.assignee ?? "(unassigned)";
|
|
597
|
+
lines.push(`- ${who} active:${entry.active} wip:${entry.in_progress} items:[${entry.items.join(",")}]`);
|
|
598
|
+
}
|
|
599
|
+
lines.push("");
|
|
600
|
+
}
|
|
601
|
+
if (result.staleness && result.staleness.length > 0) {
|
|
602
|
+
lines.push("## Stale items");
|
|
603
|
+
for (const entry of result.staleness) {
|
|
604
|
+
lines.push(`- ${entry.id} ${entry.status} stale:${entry.stale_days}d last:${entry.updated_at.slice(0, 10)} "${entry.title}"`);
|
|
605
|
+
}
|
|
606
|
+
lines.push("");
|
|
607
|
+
}
|
|
608
|
+
if (result.tests) {
|
|
609
|
+
lines.push("## Test health");
|
|
610
|
+
lines.push(`- items_with_tests: ${result.tests.items_with_tests}`);
|
|
611
|
+
lines.push(`- items_with_recent_runs: ${result.tests.items_with_recent_runs}`);
|
|
612
|
+
lines.push(`- passed: ${result.tests.recent_runs.passed}, failed: ${result.tests.recent_runs.failed}, skipped: ${result.tests.recent_runs.skipped}`);
|
|
613
|
+
if (result.tests.items_failing.length > 0) {
|
|
614
|
+
lines.push(`- items_failing: [${result.tests.items_failing.join(",")}]`);
|
|
615
|
+
}
|
|
616
|
+
lines.push("");
|
|
617
|
+
}
|
|
618
|
+
const isEmpty = result.summary.active_items === 0 &&
|
|
619
|
+
result.summary.blocked === 0 &&
|
|
620
|
+
result.agenda.summary.events === 0;
|
|
621
|
+
if (isEmpty) {
|
|
622
|
+
lines.push("## Suggestions");
|
|
623
|
+
lines.push("No active work items or upcoming events. Consider:");
|
|
624
|
+
lines.push("- `pm create --type Task --title \"...\"` to add a new work item");
|
|
625
|
+
lines.push("- `pm list --status closed --limit 5` to review recent completions");
|
|
626
|
+
lines.push("- `pm search <keywords>` to find related past work");
|
|
627
|
+
lines.push("- `pm aggregate` for a full project status overview");
|
|
628
|
+
}
|
|
214
629
|
return lines.join("\n");
|
|
215
630
|
}
|
|
631
|
+
// ---------------------------------------------------------------------------
|
|
632
|
+
// Main runner
|
|
633
|
+
// ---------------------------------------------------------------------------
|
|
216
634
|
export async function runContext(options, global) {
|
|
217
635
|
const pmRoot = resolvePmRoot(process.cwd(), global.path);
|
|
218
636
|
const settings = await readSettings(pmRoot);
|
|
637
|
+
const contextSettings = settings.context ?? SETTINGS_DEFAULTS.context;
|
|
219
638
|
const statusRegistry = resolveRuntimeStatusRegistry(settings.schema);
|
|
220
|
-
const limit =
|
|
639
|
+
const limit = parseContextLimit(options.limit);
|
|
640
|
+
const depth = parseContextDepth(options.depth, contextSettings);
|
|
641
|
+
const sectionsIncluded = parseContextSections(options.section, depth, contextSettings);
|
|
642
|
+
const activityLimit = parseActivityLimit(options.activityLimit, contextSettings);
|
|
643
|
+
const staleThresholdDays = parseStaleThresholdDays(options.staleThreshold, contextSettings);
|
|
644
|
+
const needsAllItems = sectionsIncluded.some((s) => ["hierarchy", "progress", "blockers", "staleness"].includes(s));
|
|
221
645
|
const listOptions = { ...options, excludeTerminal: true };
|
|
222
646
|
const listed = await runList(undefined, listOptions, global);
|
|
223
647
|
const listedFrontMatter = listed.items;
|
|
648
|
+
let allItems = listedFrontMatter;
|
|
649
|
+
if (needsAllItems) {
|
|
650
|
+
const allListOptions = { ...options, excludeTerminal: false };
|
|
651
|
+
const allListed = await runList(undefined, allListOptions, global);
|
|
652
|
+
allItems = allListed.items;
|
|
653
|
+
}
|
|
224
654
|
const ranked = [...listedFrontMatter].sort((left, right) => compareCriticalItems(left, right, statusRegistry));
|
|
225
655
|
const activeStatuses = statusRegistry.active_statuses.size > 0
|
|
226
656
|
? statusRegistry.active_statuses
|
|
@@ -254,9 +684,36 @@ export async function runContext(options, global) {
|
|
|
254
684
|
? activeItems.filter((item) => normalizeStatusForRegistry(item.status, statusRegistry) === inProgressStatus).length
|
|
255
685
|
: 0;
|
|
256
686
|
const openCount = activeItems.filter((item) => normalizeStatusForRegistry(item.status, statusRegistry) === openStatus).length;
|
|
257
|
-
|
|
687
|
+
const now = agenda.now;
|
|
688
|
+
const itemMap = new Map();
|
|
689
|
+
for (const item of allItems) {
|
|
690
|
+
itemMap.set(item.id, item);
|
|
691
|
+
}
|
|
692
|
+
const allNonTerminal = allItems.filter((item) => !isTerminal(item.status, statusRegistry));
|
|
693
|
+
const has = (section) => sectionsIncluded.includes(section);
|
|
694
|
+
const hierarchy = has("hierarchy") ? buildHierarchy(allItems, activeItems, statusRegistry, limit) : undefined;
|
|
695
|
+
const activity = has("activity") ? await buildActivity(activityLimit, global) : undefined;
|
|
696
|
+
const progress = has("progress") ? buildProgress(allItems, activeItems, statusRegistry, limit) : undefined;
|
|
697
|
+
const blockersSection = has("blockers") ? buildBlockers(blockedItems, itemMap, limit) : undefined;
|
|
698
|
+
const filesSection = has("files") ? buildHotFiles(activeItems, limit) : undefined;
|
|
699
|
+
const workload = has("workload") ? buildWorkload(activeItems, statusRegistry, limit) : undefined;
|
|
700
|
+
const staleness = has("staleness") ? buildStaleness(allNonTerminal, staleThresholdDays, now, limit) : undefined;
|
|
701
|
+
const tests = has("tests") ? buildTestHealth(activeItems) : undefined;
|
|
702
|
+
const summaryExtras = needsAllItems
|
|
703
|
+
? {
|
|
704
|
+
total_items: allItems.length,
|
|
705
|
+
closed: allItems.filter((i) => isClosedStatus(i.status, statusRegistry)).length,
|
|
706
|
+
canceled: allItems.filter((i) => {
|
|
707
|
+
const canceledStatus = normalizeStatusInput("canceled", statusRegistry);
|
|
708
|
+
return canceledStatus ? normalizeStatusForRegistry(i.status, statusRegistry) === canceledStatus : false;
|
|
709
|
+
}).length,
|
|
710
|
+
}
|
|
711
|
+
: {};
|
|
712
|
+
const result = {
|
|
258
713
|
output_default: "toon",
|
|
259
|
-
now
|
|
714
|
+
now,
|
|
715
|
+
depth,
|
|
716
|
+
sections_included: sectionsIncluded,
|
|
260
717
|
window: {
|
|
261
718
|
anchor: agenda.anchor,
|
|
262
719
|
start: agenda.range.start,
|
|
@@ -285,6 +742,7 @@ export async function runContext(options, global) {
|
|
|
285
742
|
high_level: highLevel.length,
|
|
286
743
|
low_level: lowLevel.length,
|
|
287
744
|
agenda_events: agendaSummary.events,
|
|
745
|
+
...summaryExtras,
|
|
288
746
|
},
|
|
289
747
|
high_level: highLevel,
|
|
290
748
|
low_level: lowLevel,
|
|
@@ -293,7 +751,33 @@ export async function runContext(options, global) {
|
|
|
293
751
|
summary: agendaSummary,
|
|
294
752
|
events: agendaEvents,
|
|
295
753
|
},
|
|
296
|
-
...(warnings.length > 0 ? { warnings } : {}),
|
|
297
754
|
};
|
|
755
|
+
if (hierarchy)
|
|
756
|
+
result.hierarchy = hierarchy;
|
|
757
|
+
if (activity)
|
|
758
|
+
result.activity = activity;
|
|
759
|
+
if (progress)
|
|
760
|
+
result.progress = progress;
|
|
761
|
+
if (blockersSection)
|
|
762
|
+
result.blockers = blockersSection;
|
|
763
|
+
if (filesSection)
|
|
764
|
+
result.files = filesSection;
|
|
765
|
+
if (workload)
|
|
766
|
+
result.workload = workload;
|
|
767
|
+
if (staleness)
|
|
768
|
+
result.staleness = staleness;
|
|
769
|
+
if (tests)
|
|
770
|
+
result.tests = tests;
|
|
771
|
+
if (warnings.length > 0)
|
|
772
|
+
result.warnings = warnings;
|
|
773
|
+
if (activeItems.length === 0 && blockedItems.length === 0 && agendaEvents.length === 0) {
|
|
774
|
+
result.suggestions = [
|
|
775
|
+
'pm create --type Task --title "..." to add a new work item',
|
|
776
|
+
"pm list --status closed --limit 5 to review recent completions",
|
|
777
|
+
"pm search <keywords> to find related past work",
|
|
778
|
+
"pm aggregate for a full project status overview",
|
|
779
|
+
];
|
|
780
|
+
}
|
|
781
|
+
return result;
|
|
298
782
|
}
|
|
299
783
|
//# sourceMappingURL=context.js.map
|