pumuki 6.3.39 → 6.3.40
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 +21 -12
- package/VERSION +1 -1
- package/core/gate/evaluateRules.test.ts +40 -0
- package/core/gate/evaluateRules.ts +7 -1
- package/core/rules/Consequence.ts +1 -0
- package/docs/CONFIGURATION.md +50 -0
- package/docs/INSTALLATION.md +38 -11
- package/docs/MCP_SERVERS.md +1 -1
- package/docs/README.md +1 -0
- package/docs/RELEASE_NOTES.md +44 -0
- package/docs/USAGE.md +191 -9
- package/docs/registro-maestro-de-seguimiento.md +2 -2
- package/docs/seguimiento-activo-pumuki-saas-supermercados.md +1592 -1
- package/docs/validation/README.md +2 -1
- package/docs/validation/ast-intelligence-roadmap.md +96 -0
- package/integrations/config/skillsCustomRules.ts +14 -0
- package/integrations/config/skillsDetectorRegistry.ts +11 -1
- package/integrations/config/skillsLock.ts +30 -0
- package/integrations/config/skillsMarkdownRules.ts +14 -3
- package/integrations/config/skillsRuleSet.ts +25 -3
- package/integrations/evidence/readEvidence.test.ts +3 -2
- package/integrations/evidence/readEvidence.ts +14 -4
- package/integrations/evidence/repoState.ts +10 -2
- package/integrations/evidence/schema.test.ts +3 -2
- package/integrations/evidence/schema.ts +3 -0
- package/integrations/evidence/writeEvidence.test.ts +3 -2
- package/integrations/gate/evaluateAiGate.ts +511 -2
- package/integrations/git/GitService.ts +5 -1
- package/integrations/git/astIntelligenceDualValidation.ts +275 -0
- package/integrations/git/gitAtomicity.ts +42 -9
- package/integrations/git/resolveGitRefs.ts +37 -0
- package/integrations/git/runPlatformGate.ts +228 -1
- package/integrations/git/runPlatformGateEvaluation.ts +4 -0
- package/integrations/git/stageRunners.ts +116 -2
- package/integrations/lifecycle/cli.ts +759 -22
- package/integrations/lifecycle/doctor.ts +62 -0
- package/integrations/lifecycle/index.ts +1 -0
- package/integrations/lifecycle/packageInfo.ts +25 -3
- package/integrations/lifecycle/policyReconcile.ts +304 -0
- package/integrations/lifecycle/preWriteAutomation.ts +42 -2
- package/integrations/lifecycle/watch.ts +365 -0
- package/integrations/mcp/aiGateCheck.ts +59 -2
- package/integrations/mcp/autoExecuteAiStart.ts +25 -1
- package/integrations/mcp/preFlightCheck.ts +13 -0
- package/integrations/sdd/evidenceScaffold.ts +223 -0
- package/integrations/sdd/index.ts +2 -0
- package/integrations/sdd/stateSync.ts +400 -0
- package/integrations/sdd/syncDocs.ts +97 -2
- package/package.json +4 -1
- package/scripts/backlog-action-reasons-lib.ts +38 -0
- package/scripts/backlog-id-issue-map-lib.ts +69 -0
- package/scripts/backlog-json-contract-lib.ts +3 -0
- package/scripts/framework-menu-consumer-preflight-lib.ts +6 -0
- package/scripts/package-install-smoke-command-resolution-lib.ts +64 -0
- package/scripts/package-install-smoke-consumer-npm-lib.ts +43 -0
- package/scripts/package-install-smoke-consumer-repo-setup-lib.ts +2 -0
- package/scripts/package-install-smoke-execution-steps-lib.ts +27 -9
- package/scripts/package-install-smoke-lifecycle-lib.ts +15 -4
- package/scripts/package-install-smoke-workspace-factory-lib.ts +4 -1
- package/scripts/reconcile-consumer-backlog-issues-lib.ts +651 -0
- package/scripts/reconcile-consumer-backlog-issues.ts +348 -0
- package/scripts/watch-consumer-backlog-lib.ts +465 -0
- package/scripts/watch-consumer-backlog.ts +326 -0
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { readFileSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { resolve } from 'node:path';
|
|
4
|
+
import {
|
|
5
|
+
buildReconcileActionRequiredReasons,
|
|
6
|
+
formatActionReasonsForHuman,
|
|
7
|
+
} from './backlog-action-reasons-lib';
|
|
8
|
+
import {
|
|
9
|
+
mergeIdIssueMapRecords,
|
|
10
|
+
parseIdIssueMapRecordFile,
|
|
11
|
+
recordToIdIssueMap,
|
|
12
|
+
type BacklogIdIssueMapRecord,
|
|
13
|
+
} from './backlog-id-issue-map-lib';
|
|
14
|
+
import {
|
|
15
|
+
BACKLOG_JSON_COMPAT_CONTRACT_ID,
|
|
16
|
+
BACKLOG_JSON_COMPAT_MIN_READER_VERSION,
|
|
17
|
+
BACKLOG_JSON_SCHEMA_VERSION,
|
|
18
|
+
} from './backlog-json-contract-lib';
|
|
19
|
+
import { runBacklogIssuesReconcile } from './reconcile-consumer-backlog-issues-lib';
|
|
20
|
+
import { collectBacklogIdIssueMap, resolveIssueNumberByIdWithGh } from './watch-consumer-backlog-lib';
|
|
21
|
+
|
|
22
|
+
type ParsedArgs = {
|
|
23
|
+
filePath: string;
|
|
24
|
+
repo?: string;
|
|
25
|
+
idIssueMapPath?: string;
|
|
26
|
+
idIssueMapSourcePath?: string;
|
|
27
|
+
idIssueMapRecord?: BacklogIdIssueMapRecord;
|
|
28
|
+
idIssueMapFromSource?: BacklogIdIssueMapRecord;
|
|
29
|
+
resolveMissingViaGh: boolean;
|
|
30
|
+
apply: boolean;
|
|
31
|
+
json: boolean;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const JSON_TOOL_NAME = 'backlog-reconcile';
|
|
35
|
+
|
|
36
|
+
const shellQuote = (value: string): string => `'${value.replace(/'/g, `'\\''`)}'`;
|
|
37
|
+
|
|
38
|
+
const HELP_TEXT = `Usage:
|
|
39
|
+
npx --yes tsx@4.21.0 scripts/reconcile-consumer-backlog-issues.ts --file=<markdown-path> [--repo=<owner/name>] [--id-issue-map=<json-path>] [--id-issue-map-from=<md-path>] [--resolve-missing-via-gh] [--apply] [--json]
|
|
40
|
+
|
|
41
|
+
Options:
|
|
42
|
+
--file=<path> Ruta del backlog markdown consumidor a reconciliar.
|
|
43
|
+
--repo=<owner/name> Repositorio GitHub a consultar con gh CLI (default: repo remoto actual).
|
|
44
|
+
--id-issue-map=<path> JSON con mapping {"PUMUKI-XXX": 123} para filas sin referencia upstream.
|
|
45
|
+
--id-issue-map-from=<path> Markdown canónico para extraer mapping ID->issue automáticamente.
|
|
46
|
+
--resolve-missing-via-gh Resolver IDs sin referencia upstream mediante búsqueda opcional en GitHub.
|
|
47
|
+
--apply Aplica cambios sobre el markdown (sin este flag es dry-run).
|
|
48
|
+
--json Imprime resultado en JSON.`;
|
|
49
|
+
|
|
50
|
+
class HelpRequestedError extends Error {
|
|
51
|
+
constructor() {
|
|
52
|
+
super(HELP_TEXT);
|
|
53
|
+
this.name = 'HelpRequestedError';
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const parseArgs = (argv: ReadonlyArray<string>): ParsedArgs => {
|
|
58
|
+
let filePath: string | undefined;
|
|
59
|
+
let repo: string | undefined;
|
|
60
|
+
let idIssueMapPath: string | undefined;
|
|
61
|
+
let idIssueMapSourcePath: string | undefined;
|
|
62
|
+
let idIssueMapRecord: BacklogIdIssueMapRecord | undefined;
|
|
63
|
+
let idIssueMapFromSource: BacklogIdIssueMapRecord | undefined;
|
|
64
|
+
let resolveMissingViaGh = false;
|
|
65
|
+
let apply = false;
|
|
66
|
+
let json = false;
|
|
67
|
+
|
|
68
|
+
for (const arg of argv) {
|
|
69
|
+
if (arg === '--help' || arg === '-h') {
|
|
70
|
+
throw new HelpRequestedError();
|
|
71
|
+
}
|
|
72
|
+
if (arg === '--apply') {
|
|
73
|
+
apply = true;
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
if (arg === '--json') {
|
|
77
|
+
json = true;
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
if (arg === '--resolve-missing-via-gh') {
|
|
81
|
+
resolveMissingViaGh = true;
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
if (arg.startsWith('--file=')) {
|
|
85
|
+
filePath = arg.slice('--file='.length).trim();
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
if (arg.startsWith('--repo=')) {
|
|
89
|
+
repo = arg.slice('--repo='.length).trim();
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
if (arg.startsWith('--id-issue-map=')) {
|
|
93
|
+
idIssueMapPath = arg.slice('--id-issue-map='.length).trim();
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
if (arg.startsWith('--id-issue-map-from=')) {
|
|
97
|
+
idIssueMapSourcePath = arg.slice('--id-issue-map-from='.length).trim();
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
throw new Error(`Unknown argument "${arg}"\n\n${HELP_TEXT}`);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (!filePath) {
|
|
104
|
+
throw new Error(`Missing --file\n\n${HELP_TEXT}`);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (idIssueMapPath && idIssueMapPath.length > 0) {
|
|
108
|
+
idIssueMapRecord = parseIdIssueMapRecordFile(idIssueMapPath);
|
|
109
|
+
}
|
|
110
|
+
if (idIssueMapSourcePath && idIssueMapSourcePath.length > 0) {
|
|
111
|
+
const sourceMarkdown = readFileSync(resolve(idIssueMapSourcePath), 'utf8');
|
|
112
|
+
idIssueMapFromSource = collectBacklogIdIssueMap(sourceMarkdown);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return {
|
|
116
|
+
filePath: resolve(filePath),
|
|
117
|
+
repo: repo && repo.length > 0 ? repo : undefined,
|
|
118
|
+
idIssueMapPath: idIssueMapPath && idIssueMapPath.length > 0 ? resolve(idIssueMapPath) : undefined,
|
|
119
|
+
idIssueMapSourcePath:
|
|
120
|
+
idIssueMapSourcePath && idIssueMapSourcePath.length > 0
|
|
121
|
+
? resolve(idIssueMapSourcePath)
|
|
122
|
+
: undefined,
|
|
123
|
+
idIssueMapRecord,
|
|
124
|
+
idIssueMapFromSource,
|
|
125
|
+
resolveMissingViaGh,
|
|
126
|
+
apply,
|
|
127
|
+
json,
|
|
128
|
+
};
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
const formatHumanOutput = (result: Awaited<ReturnType<typeof runBacklogIssuesReconcile>>): string => {
|
|
132
|
+
const lines: string[] = [];
|
|
133
|
+
const actionRequiredReasons = buildReconcileActionRequiredReasons({
|
|
134
|
+
referenceChangesCount: result.referenceChanges.length,
|
|
135
|
+
issueChangesCount: result.changes.length,
|
|
136
|
+
headingChangesCount: result.headingChanges.length,
|
|
137
|
+
summaryUpdated: result.summaryUpdated,
|
|
138
|
+
nextStepUpdated: result.nextStepUpdated,
|
|
139
|
+
});
|
|
140
|
+
lines.push(`[pumuki][backlog-reconcile] file=${result.filePath}`);
|
|
141
|
+
lines.push(`[pumuki][backlog-reconcile] entries_scanned=${result.entriesScanned} issues_resolved=${result.issuesResolved}`);
|
|
142
|
+
lines.push(
|
|
143
|
+
`[pumuki][backlog-reconcile] mapping_source=${result.mappingSource} resolved_by_map=${result.referenceResolution.resolvedByProvidedMap.length} resolved_by_lookup=${result.referenceResolution.resolvedByLookup.length} unresolved_refs=${result.referenceResolution.unresolvedReferenceIds.length}`
|
|
144
|
+
);
|
|
145
|
+
lines.push(
|
|
146
|
+
`[pumuki][backlog-reconcile] changes=${result.changes.length} heading_changes=${result.headingChanges.length} mode=${result.apply ? 'apply' : 'dry-run'}`
|
|
147
|
+
);
|
|
148
|
+
if (result.changes.length > 0) {
|
|
149
|
+
lines.push('[pumuki][backlog-reconcile] planned_changes:');
|
|
150
|
+
for (const change of result.changes) {
|
|
151
|
+
lines.push(
|
|
152
|
+
`- line ${change.lineNumber} issue #${change.issueNumber}: ${change.from} -> ${change.to} (state=${change.issueState})`
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
if (result.headingChanges.length > 0) {
|
|
157
|
+
lines.push('[pumuki][backlog-reconcile] heading_changes:');
|
|
158
|
+
for (const change of result.headingChanges) {
|
|
159
|
+
lines.push(`- line ${change.lineNumber} ${change.id}: ${change.from} -> ${change.to}`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
if (result.referenceChanges.length > 0) {
|
|
163
|
+
lines.push('[pumuki][backlog-reconcile] mapped_references:');
|
|
164
|
+
for (const change of result.referenceChanges) {
|
|
165
|
+
lines.push(`- line ${change.lineNumber} ${change.id}: ${change.from} -> ${change.to}`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
if (result.referenceResolution.resolvedByProvidedMap.length > 0) {
|
|
169
|
+
lines.push(
|
|
170
|
+
`[pumuki][backlog-reconcile] resolved_by_map_ids=${result.referenceResolution.resolvedByProvidedMap.join(',')}`
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
if (result.referenceResolution.resolvedByLookup.length > 0) {
|
|
174
|
+
lines.push(
|
|
175
|
+
`[pumuki][backlog-reconcile] resolved_by_lookup_ids=${result.referenceResolution.resolvedByLookup.join(',')}`
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
if (result.referenceResolution.unresolvedReferenceIds.length > 0) {
|
|
179
|
+
lines.push(
|
|
180
|
+
`[pumuki][backlog-reconcile] unresolved_reference_ids=${result.referenceResolution.unresolvedReferenceIds.join(',')}`
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
lines.push(`[pumuki][backlog-reconcile] next_step_updated=${result.nextStepUpdated ? 'yes' : 'no'}`);
|
|
184
|
+
lines.push(
|
|
185
|
+
`[pumuki][backlog-reconcile] action_required_reasons=${formatActionReasonsForHuman(
|
|
186
|
+
actionRequiredReasons
|
|
187
|
+
)}`
|
|
188
|
+
);
|
|
189
|
+
if (actionRequiredReasons.length > 0) {
|
|
190
|
+
lines.push(
|
|
191
|
+
'[pumuki][backlog-reconcile] hint=run with --json first (dry-run), then rerun with --apply to persist changes'
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
lines.push(
|
|
195
|
+
`[pumuki][backlog-reconcile] summary closed=${result.summary.closed} in_progress=${result.summary.inProgress} pending=${result.summary.pending} blocked=${result.summary.blocked}`
|
|
196
|
+
);
|
|
197
|
+
return `${lines.join('\n')}\n`;
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
const main = async (): Promise<void> => {
|
|
201
|
+
const parsed = parseArgs(process.argv.slice(2));
|
|
202
|
+
const mergedIdIssueRecord = mergeIdIssueMapRecords(parsed.idIssueMapFromSource, parsed.idIssueMapRecord);
|
|
203
|
+
const mergedIdIssueMap = recordToIdIssueMap(mergedIdIssueRecord);
|
|
204
|
+
const hasMarkdownMap = Boolean(parsed.idIssueMapFromSource && Object.keys(parsed.idIssueMapFromSource).length > 0);
|
|
205
|
+
const hasJsonMap = Boolean(parsed.idIssueMapRecord && Object.keys(parsed.idIssueMapRecord).length > 0);
|
|
206
|
+
const mappingSource = hasMarkdownMap && hasJsonMap ? 'merged' : hasJsonMap ? 'json' : hasMarkdownMap ? 'markdown' : 'none';
|
|
207
|
+
const result = await runBacklogIssuesReconcile({
|
|
208
|
+
filePath: parsed.filePath,
|
|
209
|
+
repo: parsed.repo,
|
|
210
|
+
mappingSource,
|
|
211
|
+
idIssueMap: mergedIdIssueMap,
|
|
212
|
+
resolveIssueNumberById: parsed.resolveMissingViaGh ? resolveIssueNumberByIdWithGh : undefined,
|
|
213
|
+
apply: parsed.apply,
|
|
214
|
+
});
|
|
215
|
+
const actionRequiredReasons = buildReconcileActionRequiredReasons({
|
|
216
|
+
referenceChangesCount: result.referenceChanges.length,
|
|
217
|
+
issueChangesCount: result.changes.length,
|
|
218
|
+
headingChangesCount: result.headingChanges.length,
|
|
219
|
+
summaryUpdated: result.summaryUpdated,
|
|
220
|
+
nextStepUpdated: result.nextStepUpdated,
|
|
221
|
+
});
|
|
222
|
+
const dryRunCommand = `npx --yes tsx@4.21.0 scripts/reconcile-consumer-backlog-issues.ts --file=${shellQuote(
|
|
223
|
+
parsed.filePath
|
|
224
|
+
)} --json`;
|
|
225
|
+
const applyCommand = `npx --yes tsx@4.21.0 scripts/reconcile-consumer-backlog-issues.ts --file=${shellQuote(
|
|
226
|
+
parsed.filePath
|
|
227
|
+
)} --apply`;
|
|
228
|
+
const nextCommands =
|
|
229
|
+
actionRequiredReasons.length > 0
|
|
230
|
+
? [
|
|
231
|
+
{
|
|
232
|
+
id: 1,
|
|
233
|
+
origin_tool: JSON_TOOL_NAME,
|
|
234
|
+
label: 'dry_run',
|
|
235
|
+
recommendation_type: 'reconcile_loop',
|
|
236
|
+
priority: 'high',
|
|
237
|
+
mode: 'dry-run',
|
|
238
|
+
safety: 'read_only',
|
|
239
|
+
idempotent: true,
|
|
240
|
+
max_retries: 2,
|
|
241
|
+
retry_strategy: 'immediate',
|
|
242
|
+
estimated_duration_ms: 3000,
|
|
243
|
+
requires_confirmation: false,
|
|
244
|
+
depends_on: null,
|
|
245
|
+
description: 'Inspect planned reconcile changes without mutating files.',
|
|
246
|
+
expected_outcome: 'Dry-run plan generated without file mutations.',
|
|
247
|
+
success_criteria: 'plan_generated_no_mutation',
|
|
248
|
+
success_probe: 'Check JSON includes dry_run/apply next_commands without mutating files.',
|
|
249
|
+
probe_kind: 'json_contract',
|
|
250
|
+
probe_timeout_ms: 1500,
|
|
251
|
+
failure_hint: 'Re-run dry_run with --json and inspect action_required_reasons before applying.',
|
|
252
|
+
command: dryRunCommand,
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
id: 2,
|
|
256
|
+
origin_tool: JSON_TOOL_NAME,
|
|
257
|
+
label: 'apply',
|
|
258
|
+
recommendation_type: 'reconcile_loop',
|
|
259
|
+
priority: 'medium',
|
|
260
|
+
mode: 'apply',
|
|
261
|
+
safety: 'mutating',
|
|
262
|
+
idempotent: true,
|
|
263
|
+
max_retries: 0,
|
|
264
|
+
retry_strategy: 'manual',
|
|
265
|
+
estimated_duration_ms: 5000,
|
|
266
|
+
requires_confirmation: true,
|
|
267
|
+
depends_on: 'dry_run',
|
|
268
|
+
description: 'Apply reconcile changes to the backlog markdown file.',
|
|
269
|
+
expected_outcome: 'Backlog markdown reconciled and persisted.',
|
|
270
|
+
success_criteria: 'backlog_reconciled_persisted',
|
|
271
|
+
success_probe: 'Re-run watch --json and confirm action_required_reasons are reduced or none.',
|
|
272
|
+
probe_kind: 'state_recheck',
|
|
273
|
+
probe_timeout_ms: 4000,
|
|
274
|
+
failure_hint: 'Run dry_run first, then retry apply on a clean worktree with file write permissions.',
|
|
275
|
+
command: applyCommand,
|
|
276
|
+
},
|
|
277
|
+
]
|
|
278
|
+
: undefined;
|
|
279
|
+
const nextCommand = nextCommands ? `${dryRunCommand} && ${applyCommand}` : undefined;
|
|
280
|
+
const nextCommandReason = nextCommand ? actionRequiredReasons[0] : undefined;
|
|
281
|
+
|
|
282
|
+
if (parsed.json) {
|
|
283
|
+
const generatedAt = new Date().toISOString();
|
|
284
|
+
const runId = randomUUID();
|
|
285
|
+
const nextCommandsWithExecutionGroup = nextCommands?.map((step) => ({
|
|
286
|
+
...step,
|
|
287
|
+
execution_group_id: runId,
|
|
288
|
+
origin_schema_version: BACKLOG_JSON_SCHEMA_VERSION,
|
|
289
|
+
origin_contract_id: BACKLOG_JSON_COMPAT_CONTRACT_ID,
|
|
290
|
+
}));
|
|
291
|
+
writeFileSync(
|
|
292
|
+
process.stdout.fd,
|
|
293
|
+
`${JSON.stringify(
|
|
294
|
+
{
|
|
295
|
+
tool: JSON_TOOL_NAME,
|
|
296
|
+
schema_version: BACKLOG_JSON_SCHEMA_VERSION,
|
|
297
|
+
generated_at: generatedAt,
|
|
298
|
+
run_id: runId,
|
|
299
|
+
invocation: {
|
|
300
|
+
mode: 'json',
|
|
301
|
+
repo: parsed.repo ?? null,
|
|
302
|
+
apply: parsed.apply,
|
|
303
|
+
resolve_missing_via_gh: parsed.resolveMissingViaGh,
|
|
304
|
+
id_issue_map: parsed.idIssueMapPath ? 'provided' : 'none',
|
|
305
|
+
id_issue_map_from: parsed.idIssueMapSourcePath ? 'provided' : 'none',
|
|
306
|
+
},
|
|
307
|
+
compat: {
|
|
308
|
+
contract_id: BACKLOG_JSON_COMPAT_CONTRACT_ID,
|
|
309
|
+
min_reader_version: BACKLOG_JSON_COMPAT_MIN_READER_VERSION,
|
|
310
|
+
is_backward_compatible: true,
|
|
311
|
+
breaking_changes: [],
|
|
312
|
+
},
|
|
313
|
+
classification_counts: {
|
|
314
|
+
issue_changes: result.changes.length,
|
|
315
|
+
reference_changes: result.referenceChanges.length,
|
|
316
|
+
heading_changes: result.headingChanges.length,
|
|
317
|
+
summary_closed: result.summary.closed,
|
|
318
|
+
summary_in_progress: result.summary.inProgress,
|
|
319
|
+
summary_pending: result.summary.pending,
|
|
320
|
+
summary_blocked: result.summary.blocked,
|
|
321
|
+
},
|
|
322
|
+
action_required_reasons: actionRequiredReasons,
|
|
323
|
+
...(nextCommand ? { next_command: nextCommand } : {}),
|
|
324
|
+
...(nextCommandReason ? { next_command_reason: nextCommandReason } : {}),
|
|
325
|
+
...(nextCommandsWithExecutionGroup ? { next_commands: nextCommandsWithExecutionGroup } : {}),
|
|
326
|
+
heading_changes_count: result.headingChanges.length,
|
|
327
|
+
...result,
|
|
328
|
+
},
|
|
329
|
+
null,
|
|
330
|
+
2
|
|
331
|
+
)}\n`
|
|
332
|
+
);
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
writeFileSync(process.stdout.fd, formatHumanOutput(result));
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
main().catch((error: unknown) => {
|
|
340
|
+
if (error instanceof HelpRequestedError) {
|
|
341
|
+
writeFileSync(process.stdout.fd, `${HELP_TEXT}\n`);
|
|
342
|
+
process.exitCode = 0;
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
346
|
+
writeFileSync(process.stderr.fd, `${message}\n`);
|
|
347
|
+
process.exitCode = 1;
|
|
348
|
+
});
|