agentplane 0.3.10 → 0.3.11
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/assets/policy/governance.md +3 -4
- package/assets/policy/incidents.md +19 -88
- package/assets/policy/workflow.branch_pr.md +1 -1
- package/assets/policy/workflow.direct.md +2 -2
- package/bin/agentplane.js +56 -1
- package/bin/runtime-watch.js +1 -0
- package/bin/stale-dist-policy.d.ts +1 -1
- package/bin/stale-dist-policy.js +13 -0
- package/dist/.build-manifest.json +219 -154
- package/dist/cli/bootstrap-guide.d.ts.map +1 -1
- package/dist/cli/bootstrap-guide.js +3 -2
- package/dist/cli/command-guide.d.ts.map +1 -1
- package/dist/cli/command-guide.js +2 -1
- package/dist/cli/command-invocations.d.ts.map +1 -1
- package/dist/cli/command-invocations.js +4 -1
- package/dist/cli/run-cli/command-catalog/project.d.ts +1 -1
- package/dist/cli/run-cli/command-catalog/project.d.ts.map +1 -1
- package/dist/cli/run-cli/command-catalog/project.js +3 -1
- package/dist/cli/run-cli/command-catalog/task.d.ts +1 -1
- package/dist/cli/run-cli/command-catalog/task.d.ts.map +1 -1
- package/dist/cli/run-cli/command-catalog/task.js +10 -0
- package/dist/cli/run-cli/command-catalog.d.ts +1 -1
- package/dist/cli/run-cli/command-catalog.d.ts.map +1 -1
- package/dist/cli/run-cli/commands/core/preflight.d.ts.map +1 -1
- package/dist/cli/run-cli/commands/core/preflight.js +44 -1
- package/dist/cli/run-cli.test-helpers.d.ts.map +1 -1
- package/dist/cli/run-cli.test-helpers.js +12 -0
- package/dist/commands/branch/cleanup-merged.d.ts +2 -0
- package/dist/commands/branch/cleanup-merged.d.ts.map +1 -1
- package/dist/commands/branch/cleanup-merged.js +132 -28
- package/dist/commands/branch/work-start.d.ts.map +1 -1
- package/dist/commands/branch/work-start.js +60 -1
- package/dist/commands/cleanup/merged.command.d.ts +2 -0
- package/dist/commands/cleanup/merged.command.d.ts.map +1 -1
- package/dist/commands/cleanup/merged.command.js +24 -0
- package/dist/commands/doctor/branch-pr.d.ts +4 -0
- package/dist/commands/doctor/branch-pr.d.ts.map +1 -0
- package/dist/commands/doctor/branch-pr.js +96 -0
- package/dist/commands/doctor/fixes.d.ts +5 -0
- package/dist/commands/doctor/fixes.d.ts.map +1 -1
- package/dist/commands/doctor/fixes.js +70 -0
- package/dist/commands/doctor.run.d.ts.map +1 -1
- package/dist/commands/doctor.run.js +6 -1
- package/dist/commands/finish.run.d.ts.map +1 -1
- package/dist/commands/finish.run.js +11 -0
- package/dist/commands/finish.spec.d.ts +11 -0
- package/dist/commands/finish.spec.d.ts.map +1 -1
- package/dist/commands/finish.spec.js +51 -0
- package/dist/commands/guard/impl/close-message.d.ts.map +1 -1
- package/dist/commands/guard/impl/close-message.js +23 -6
- package/dist/commands/guard/impl/commands.d.ts.map +1 -1
- package/dist/commands/guard/impl/commands.js +24 -2
- package/dist/commands/guard/impl/env.d.ts +1 -0
- package/dist/commands/guard/impl/env.d.ts.map +1 -1
- package/dist/commands/guard/impl/env.js +1 -0
- package/dist/commands/hooks/index.d.ts.map +1 -1
- package/dist/commands/hooks/index.js +98 -1
- package/dist/commands/incidents/collect.command.d.ts.map +1 -1
- package/dist/commands/incidents/collect.command.js +12 -7
- package/dist/commands/incidents/incidents.command.js +1 -1
- package/dist/commands/incidents/shared.d.ts +34 -0
- package/dist/commands/incidents/shared.d.ts.map +1 -1
- package/dist/commands/incidents/shared.js +166 -12
- package/dist/commands/pr/check.d.ts.map +1 -1
- package/dist/commands/pr/check.js +238 -135
- package/dist/commands/pr/close-superseded.d.ts +9 -0
- package/dist/commands/pr/close-superseded.d.ts.map +1 -0
- package/dist/commands/pr/close-superseded.js +129 -0
- package/dist/commands/pr/close.d.ts +11 -0
- package/dist/commands/pr/close.d.ts.map +1 -0
- package/dist/commands/pr/close.js +116 -0
- package/dist/commands/pr/index.d.ts +2 -0
- package/dist/commands/pr/index.d.ts.map +1 -1
- package/dist/commands/pr/index.js +2 -0
- package/dist/commands/pr/integrate/artifacts.d.ts +7 -0
- package/dist/commands/pr/integrate/artifacts.d.ts.map +1 -1
- package/dist/commands/pr/integrate/artifacts.js +66 -1
- package/dist/commands/pr/integrate/cmd.d.ts.map +1 -1
- package/dist/commands/pr/integrate/cmd.js +16 -0
- package/dist/commands/pr/integrate/internal/bootstrap-guidance.d.ts +8 -0
- package/dist/commands/pr/integrate/internal/bootstrap-guidance.d.ts.map +1 -0
- package/dist/commands/pr/integrate/internal/bootstrap-guidance.js +59 -0
- package/dist/commands/pr/integrate/internal/finalize.d.ts.map +1 -1
- package/dist/commands/pr/integrate/internal/finalize.js +40 -12
- package/dist/commands/pr/integrate/internal/merge.d.ts.map +1 -1
- package/dist/commands/pr/integrate/internal/merge.js +36 -13
- package/dist/commands/pr/integrate/internal/post-integrate-bootstrap.d.ts +13 -0
- package/dist/commands/pr/integrate/internal/post-integrate-bootstrap.d.ts.map +1 -0
- package/dist/commands/pr/integrate/internal/post-integrate-bootstrap.js +25 -0
- package/dist/commands/pr/integrate/internal/prepare.d.ts +3 -2
- package/dist/commands/pr/integrate/internal/prepare.d.ts.map +1 -1
- package/dist/commands/pr/integrate/internal/prepare.js +101 -38
- package/dist/commands/pr/internal/freshness.d.ts +20 -0
- package/dist/commands/pr/internal/freshness.d.ts.map +1 -0
- package/dist/commands/pr/internal/freshness.js +50 -0
- package/dist/commands/pr/internal/gh-api.d.ts +6 -0
- package/dist/commands/pr/internal/gh-api.d.ts.map +1 -0
- package/dist/commands/pr/internal/gh-api.js +80 -0
- package/dist/commands/pr/internal/pr-paths.d.ts +10 -0
- package/dist/commands/pr/internal/pr-paths.d.ts.map +1 -1
- package/dist/commands/pr/internal/pr-paths.js +10 -0
- package/dist/commands/pr/internal/review-template.d.ts.map +1 -1
- package/dist/commands/pr/internal/review-template.js +37 -4
- package/dist/commands/pr/internal/sync.d.ts +9 -0
- package/dist/commands/pr/internal/sync.d.ts.map +1 -1
- package/dist/commands/pr/internal/sync.js +462 -122
- package/dist/commands/pr/open.d.ts +1 -0
- package/dist/commands/pr/open.d.ts.map +1 -1
- package/dist/commands/pr/open.js +13 -2
- package/dist/commands/pr/pr.command.d.ts +15 -0
- package/dist/commands/pr/pr.command.d.ts.map +1 -1
- package/dist/commands/pr/pr.command.js +118 -2
- package/dist/commands/pr/update.d.ts.map +1 -1
- package/dist/commands/pr/update.js +59 -1
- package/dist/commands/release/apply.command.d.ts.map +1 -1
- package/dist/commands/release/apply.command.js +3 -17
- package/dist/commands/release/apply.preflight.d.ts.map +1 -1
- package/dist/commands/release/apply.preflight.js +1 -1
- package/dist/commands/shared/gh-transport.d.ts +16 -0
- package/dist/commands/shared/gh-transport.d.ts.map +1 -0
- package/dist/commands/shared/gh-transport.js +71 -0
- package/dist/commands/shared/git-diff.d.ts +3 -1
- package/dist/commands/shared/git-diff.d.ts.map +1 -1
- package/dist/commands/shared/git-diff.js +10 -2
- package/dist/commands/shared/git-ops.d.ts +1 -0
- package/dist/commands/shared/git-ops.d.ts.map +1 -1
- package/dist/commands/shared/git-ops.js +15 -0
- package/dist/commands/shared/git-worktree.d.ts +2 -0
- package/dist/commands/shared/git-worktree.d.ts.map +1 -1
- package/dist/commands/shared/git-worktree.js +22 -2
- package/dist/commands/shared/post-commit-pr-artifacts.d.ts +9 -0
- package/dist/commands/shared/post-commit-pr-artifacts.d.ts.map +1 -0
- package/dist/commands/shared/post-commit-pr-artifacts.js +22 -0
- package/dist/commands/shared/pr-meta.d.ts +20 -0
- package/dist/commands/shared/pr-meta.d.ts.map +1 -1
- package/dist/commands/shared/pr-meta.js +125 -0
- package/dist/commands/shared/task-backend.d.ts +7 -0
- package/dist/commands/shared/task-backend.d.ts.map +1 -1
- package/dist/commands/shared/task-backend.js +34 -22
- package/dist/commands/task/close-duplicate.d.ts.map +1 -1
- package/dist/commands/task/close-duplicate.js +34 -1
- package/dist/commands/task/derive.js +1 -1
- package/dist/commands/task/doc-template.d.ts.map +1 -1
- package/dist/commands/task/doc-template.js +7 -11
- package/dist/commands/task/findings-add.command.d.ts +20 -0
- package/dist/commands/task/findings-add.command.d.ts.map +1 -0
- package/dist/commands/task/findings-add.command.js +165 -0
- package/dist/commands/task/findings.command.d.ts +7 -0
- package/dist/commands/task/findings.command.d.ts.map +1 -0
- package/dist/commands/task/findings.command.js +20 -0
- package/dist/commands/task/findings.d.ts +63 -0
- package/dist/commands/task/findings.d.ts.map +1 -0
- package/dist/commands/task/findings.js +188 -0
- package/dist/commands/task/finish-shared.d.ts +1 -0
- package/dist/commands/task/finish-shared.d.ts.map +1 -1
- package/dist/commands/task/finish-shared.js +55 -1
- package/dist/commands/task/finish.d.ts +10 -0
- package/dist/commands/task/finish.d.ts.map +1 -1
- package/dist/commands/task/finish.js +125 -6
- package/dist/commands/task/hosted-close-pr.command.d.ts +11 -0
- package/dist/commands/task/hosted-close-pr.command.d.ts.map +1 -0
- package/dist/commands/task/hosted-close-pr.command.js +414 -0
- package/dist/commands/task/hosted-close.command.d.ts.map +1 -1
- package/dist/commands/task/hosted-close.command.js +49 -1
- package/dist/commands/task/hosted-merge-sync.d.ts +38 -0
- package/dist/commands/task/hosted-merge-sync.d.ts.map +1 -1
- package/dist/commands/task/hosted-merge-sync.js +249 -17
- package/dist/commands/task/index.d.ts +1 -0
- package/dist/commands/task/index.d.ts.map +1 -1
- package/dist/commands/task/index.js +1 -0
- package/dist/commands/task/new.d.ts +1 -0
- package/dist/commands/task/new.d.ts.map +1 -1
- package/dist/commands/task/new.js +71 -1
- package/dist/commands/task/new.spec.d.ts.map +1 -1
- package/dist/commands/task/new.spec.js +7 -0
- package/dist/commands/task/normalize.command.d.ts +2 -0
- package/dist/commands/task/normalize.command.d.ts.map +1 -1
- package/dist/commands/task/normalize.command.js +45 -0
- package/dist/commands/task/normalize.d.ts +2 -0
- package/dist/commands/task/normalize.d.ts.map +1 -1
- package/dist/commands/task/normalize.js +85 -8
- package/dist/commands/task/plan.d.ts.map +1 -1
- package/dist/commands/task/plan.js +7 -10
- package/dist/commands/task/shared/docs.d.ts +6 -0
- package/dist/commands/task/shared/docs.d.ts.map +1 -1
- package/dist/commands/task/shared/docs.js +14 -0
- package/dist/commands/task/shared/transitions.d.ts.map +1 -1
- package/dist/commands/task/shared/transitions.js +11 -1
- package/dist/commands/task/shared.d.ts +1 -1
- package/dist/commands/task/shared.d.ts.map +1 -1
- package/dist/commands/task/shared.js +1 -1
- package/dist/commands/task/start-ready.d.ts.map +1 -1
- package/dist/commands/task/start-ready.js +86 -0
- package/dist/commands/task/start.d.ts.map +1 -1
- package/dist/commands/task/start.js +7 -10
- package/dist/commands/task/task.command.d.ts.map +1 -1
- package/dist/commands/task/task.command.js +4 -0
- package/dist/commands/task/verify-command-shared.d.ts +19 -0
- package/dist/commands/task/verify-command-shared.d.ts.map +1 -1
- package/dist/commands/task/verify-command-shared.js +152 -1
- package/dist/commands/task/verify-ok.command.d.ts.map +1 -1
- package/dist/commands/task/verify-ok.command.js +15 -2
- package/dist/commands/task/verify-record.d.ts +36 -0
- package/dist/commands/task/verify-record.d.ts.map +1 -1
- package/dist/commands/task/verify-record.js +166 -11
- package/dist/commands/task/verify-rework.command.d.ts.map +1 -1
- package/dist/commands/task/verify-rework.command.js +15 -2
- package/dist/commands/task/verify-show.command.d.ts +1 -1
- package/dist/commands/task/verify-show.command.d.ts.map +1 -1
- package/dist/commands/task/verify-show.command.js +28 -1
- package/dist/commands/verify.run.d.ts.map +1 -1
- package/dist/commands/verify.run.js +12 -0
- package/dist/commands/verify.spec.d.ts +2 -6
- package/dist/commands/verify.spec.d.ts.map +1 -1
- package/dist/commands/verify.spec.js +30 -3
- package/dist/runtime/incidents/index.d.ts +1 -1
- package/dist/runtime/incidents/index.d.ts.map +1 -1
- package/dist/runtime/incidents/resolve.d.ts.map +1 -1
- package/dist/runtime/incidents/resolve.js +319 -73
- package/dist/runtime/incidents/types.d.ts +14 -2
- package/dist/runtime/incidents/types.d.ts.map +1 -1
- package/dist/shared/env.d.ts +1 -0
- package/dist/shared/env.d.ts.map +1 -1
- package/dist/shared/env.js +22 -1
- package/dist/shared/protected-paths.d.ts +1 -1
- package/dist/shared/protected-paths.d.ts.map +1 -1
- package/dist/shared/protected-paths.js +4 -0
- package/package.json +2 -2
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
const
|
|
1
|
+
const STRUCTURED_INCIDENTS_HEADER = [
|
|
2
2
|
"# Policy Incidents Log",
|
|
3
3
|
"",
|
|
4
4
|
"This is the single file for incident-derived and situational policy rules.",
|
|
5
5
|
].join("\n");
|
|
6
|
+
const COMPACT_INCIDENTS_HEADER = [
|
|
7
|
+
"# Policy Incidents Log",
|
|
8
|
+
"- Append-only. Required fields: `id`, `date`, `scope`, `failure`, `rule`, `evidence`, `enforcement`, `state`; optional: `tags`, `match`, `advice`, `source_task`, `fixability`.",
|
|
9
|
+
].join("\n");
|
|
6
10
|
function normalizeLines(text) {
|
|
7
11
|
return text.replaceAll("\r\n", "\n").split("\n");
|
|
8
12
|
}
|
|
@@ -50,12 +54,26 @@ function parseCsvList(value) {
|
|
|
50
54
|
.map((item) => item.trim())
|
|
51
55
|
.filter(Boolean));
|
|
52
56
|
}
|
|
57
|
+
function incidentField(key, value) {
|
|
58
|
+
return [key, value];
|
|
59
|
+
}
|
|
53
60
|
function parseBoolean(value) {
|
|
54
61
|
const normalized = String(value ?? "")
|
|
55
62
|
.trim()
|
|
56
63
|
.toLowerCase();
|
|
57
64
|
return normalized === "true" || normalized === "yes" || normalized === "y" || normalized === "1";
|
|
58
65
|
}
|
|
66
|
+
function parseFixability(value) {
|
|
67
|
+
const normalized = String(value ?? "")
|
|
68
|
+
.trim()
|
|
69
|
+
.toLowerCase()
|
|
70
|
+
.replaceAll(/[\s_-]+/g, "");
|
|
71
|
+
if (normalized === "external")
|
|
72
|
+
return "external";
|
|
73
|
+
if (normalized === "repofixable" || normalized === "internal")
|
|
74
|
+
return "repo-fixable";
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
59
77
|
function parseEntryState(value) {
|
|
60
78
|
return value === "open" || value === "promoted" ? value : "stabilized";
|
|
61
79
|
}
|
|
@@ -66,21 +84,94 @@ function appendFieldValue(record, key, value, joiner = " ") {
|
|
|
66
84
|
}
|
|
67
85
|
record[key] = `${record[key]}${joiner}${value.trim()}`.trim();
|
|
68
86
|
}
|
|
69
|
-
function
|
|
87
|
+
function deriveSourceTask(explicitSourceTask, evidence) {
|
|
88
|
+
const direct = String(explicitSourceTask ?? "").trim();
|
|
89
|
+
if (direct)
|
|
90
|
+
return direct;
|
|
91
|
+
const match = /\btasks?\s+([A-Za-z0-9-]+)/iu.exec(String(evidence ?? ""));
|
|
92
|
+
return match?.[1]?.trim() ?? null;
|
|
93
|
+
}
|
|
94
|
+
function buildIncidentSignature(entry) {
|
|
70
95
|
return [
|
|
71
|
-
entry.sourceTask ?? "",
|
|
72
96
|
normalizeSearchText(entry.scope),
|
|
73
97
|
normalizeSearchText(entry.failure),
|
|
74
98
|
normalizeSearchText(entry.rule),
|
|
75
99
|
].join("|");
|
|
76
100
|
}
|
|
101
|
+
function buildIncidentFingerprint(entry) {
|
|
102
|
+
return [entry.sourceTask ?? "", buildIncidentSignature(entry)].join("|");
|
|
103
|
+
}
|
|
77
104
|
function buildMatchTerms(opts) {
|
|
78
105
|
const scopeTokens = tokenize(opts.scope);
|
|
79
|
-
|
|
106
|
+
const extraTokens = (opts.extraText ?? []).flatMap((value) => tokenize(value));
|
|
107
|
+
return dedupeCaseInsensitive([
|
|
108
|
+
...opts.explicitMatch,
|
|
109
|
+
...opts.tags,
|
|
110
|
+
...scopeTokens,
|
|
111
|
+
...extraTokens,
|
|
112
|
+
]).slice(0, 16);
|
|
113
|
+
}
|
|
114
|
+
function parseDateOnly(value) {
|
|
115
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(value))
|
|
116
|
+
return null;
|
|
117
|
+
const parsed = Date.parse(`${value}T00:00:00.000Z`);
|
|
118
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
119
|
+
}
|
|
120
|
+
function occursWithinDays(date, now, days) {
|
|
121
|
+
const timestamp = parseDateOnly(date);
|
|
122
|
+
if (timestamp === null)
|
|
123
|
+
return false;
|
|
124
|
+
const delta = now.getTime() - timestamp;
|
|
125
|
+
if (delta < 0)
|
|
126
|
+
return false;
|
|
127
|
+
return delta <= days * 24 * 60 * 60 * 1000;
|
|
128
|
+
}
|
|
129
|
+
function entryStateRank(state) {
|
|
130
|
+
if (state === "promoted")
|
|
131
|
+
return 2;
|
|
132
|
+
if (state === "stabilized")
|
|
133
|
+
return 1;
|
|
134
|
+
return 0;
|
|
135
|
+
}
|
|
136
|
+
function compareIncidentAdviceMatch(left, right) {
|
|
137
|
+
if (right.score !== left.score)
|
|
138
|
+
return right.score - left.score;
|
|
139
|
+
const rightState = entryStateRank(right.entry.state);
|
|
140
|
+
const leftState = entryStateRank(left.entry.state);
|
|
141
|
+
if (rightState !== leftState)
|
|
142
|
+
return rightState - leftState;
|
|
143
|
+
return right.entry.date.localeCompare(left.entry.date);
|
|
144
|
+
}
|
|
145
|
+
function summarizeTaskScope(scope, title) {
|
|
146
|
+
const lines = normalizeLines(scope ?? "");
|
|
147
|
+
for (const line of lines) {
|
|
148
|
+
const trimmed = line.trim();
|
|
149
|
+
if (!trimmed)
|
|
150
|
+
continue;
|
|
151
|
+
let candidate = trimmed.replace(/^-+\s*/, "");
|
|
152
|
+
candidate = candidate.replace(/^in scope:\s*/i, "").trim();
|
|
153
|
+
if (!candidate || /^out of scope:/i.test(candidate))
|
|
154
|
+
continue;
|
|
155
|
+
return candidate;
|
|
156
|
+
}
|
|
157
|
+
return title.trim();
|
|
158
|
+
}
|
|
159
|
+
function buildDerivedIncidentRule(scope) {
|
|
160
|
+
return `Analogous ${scope} work MUST review and apply the recorded external incident advice before retrying.`;
|
|
161
|
+
}
|
|
162
|
+
function resolveIncidentState(opts) {
|
|
163
|
+
const signature = buildIncidentSignature(opts.entry);
|
|
164
|
+
const similarEntries = opts.registry.entries.filter((candidate) => buildIncidentSignature(candidate) === signature);
|
|
165
|
+
if (similarEntries.some((candidate) => candidate.state === "promoted" ||
|
|
166
|
+
candidate.state === "stabilized" ||
|
|
167
|
+
occursWithinDays(candidate.date, opts.now, 30))) {
|
|
168
|
+
return "stabilized";
|
|
169
|
+
}
|
|
170
|
+
return "open";
|
|
80
171
|
}
|
|
81
172
|
export function createIncidentRegistrySkeleton() {
|
|
82
173
|
return [
|
|
83
|
-
|
|
174
|
+
STRUCTURED_INCIDENTS_HEADER,
|
|
84
175
|
"",
|
|
85
176
|
"## Entry contract",
|
|
86
177
|
"",
|
|
@@ -88,7 +179,9 @@ export function createIncidentRegistrySkeleton() {
|
|
|
88
179
|
"- Every entry MUST include: `id`, `date`, `scope`, `failure`, `rule`, `evidence`, `enforcement`, `state`.",
|
|
89
180
|
"- New machine-matched entries SHOULD also include: `tags`, `match`, `advice`, `source_task`, `fixability`.",
|
|
90
181
|
"- `rule` MUST be concrete and testable (`MUST` / `MUST NOT`).",
|
|
91
|
-
"- `fixability: external` means the issue cannot be removed by changing only repository code and should
|
|
182
|
+
"- `fixability: external` means the issue cannot be removed by changing only repository code and should stay as reusable operational advice.",
|
|
183
|
+
"- `fixability: repo-fixable` means the issue can be removed by repository code changes and should still be captured as reusable incident advice when explicitly marked.",
|
|
184
|
+
"- First auto-promoted reusable incidents normally enter as `open` and still participate in targeted advice lookup; recurring equivalent incidents can append later `stabilized` entries.",
|
|
92
185
|
"- `state` values: `open`, `stabilized`, `promoted`.",
|
|
93
186
|
"",
|
|
94
187
|
"## Entry template",
|
|
@@ -104,7 +197,7 @@ export function createIncidentRegistrySkeleton() {
|
|
|
104
197
|
"- evidence: `<task ids / logs / links>`",
|
|
105
198
|
"- enforcement: `<CI|test|lint|script|manual>`",
|
|
106
199
|
"- source_task: `<task id>`",
|
|
107
|
-
"- fixability: `<external>`",
|
|
200
|
+
"- fixability: `<external|repo-fixable>`",
|
|
108
201
|
"- state: `<open|stabilized|promoted>`",
|
|
109
202
|
"",
|
|
110
203
|
"## Entries",
|
|
@@ -114,7 +207,6 @@ export function createIncidentRegistrySkeleton() {
|
|
|
114
207
|
export function parseIncidentRegistry(text) {
|
|
115
208
|
const lines = normalizeLines(text);
|
|
116
209
|
const entries = [];
|
|
117
|
-
let inEntries = false;
|
|
118
210
|
let currentFields = null;
|
|
119
211
|
let currentLine = 0;
|
|
120
212
|
let currentKey = null;
|
|
@@ -122,7 +214,7 @@ export function parseIncidentRegistry(text) {
|
|
|
122
214
|
if (!currentFields)
|
|
123
215
|
return;
|
|
124
216
|
const id = currentFields.id?.trim();
|
|
125
|
-
if (!id) {
|
|
217
|
+
if (!id || !/^INC-\d{8}-\d+$/u.test(id)) {
|
|
126
218
|
currentFields = null;
|
|
127
219
|
currentKey = null;
|
|
128
220
|
currentLine = 0;
|
|
@@ -133,6 +225,7 @@ export function parseIncidentRegistry(text) {
|
|
|
133
225
|
const rule = currentFields.rule?.trim() ?? "";
|
|
134
226
|
const evidence = currentFields.evidence?.trim() ?? "";
|
|
135
227
|
const enforcement = currentFields.enforcement?.trim() ?? "manual";
|
|
228
|
+
const sourceTask = deriveSourceTask(currentFields.source_task, evidence);
|
|
136
229
|
entries.push({
|
|
137
230
|
id,
|
|
138
231
|
date: currentFields.date?.trim() ?? "",
|
|
@@ -145,8 +238,8 @@ export function parseIncidentRegistry(text) {
|
|
|
145
238
|
tags: parseCsvList(currentFields.tags),
|
|
146
239
|
match: parseCsvList(currentFields.match),
|
|
147
240
|
advice: currentFields.advice?.trim() || null,
|
|
148
|
-
sourceTask
|
|
149
|
-
fixability: currentFields.fixability
|
|
241
|
+
sourceTask,
|
|
242
|
+
fixability: parseFixability(currentFields.fixability),
|
|
150
243
|
rawFields: { ...currentFields },
|
|
151
244
|
line: currentLine,
|
|
152
245
|
});
|
|
@@ -156,23 +249,21 @@ export function parseIncidentRegistry(text) {
|
|
|
156
249
|
};
|
|
157
250
|
for (const [index, line] of lines.entries()) {
|
|
158
251
|
const trimmed = line.trim();
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
inEntries = true;
|
|
162
|
-
continue;
|
|
163
|
-
}
|
|
164
|
-
if (/^##\s+/.test(trimmed))
|
|
165
|
-
break;
|
|
166
|
-
const idMatch = /^- id:\s*(.+?)\s*$/.exec(trimmed);
|
|
167
|
-
if (idMatch) {
|
|
252
|
+
const inlineFields = parseInlineIncidentEntry(trimmed);
|
|
253
|
+
if (inlineFields) {
|
|
168
254
|
flush();
|
|
169
|
-
currentFields = {
|
|
170
|
-
|
|
255
|
+
currentFields = { ...inlineFields };
|
|
256
|
+
const keys = Object.keys(inlineFields);
|
|
257
|
+
currentKey = keys.at(-1) ?? "id";
|
|
171
258
|
currentLine = index + 1;
|
|
172
259
|
continue;
|
|
173
260
|
}
|
|
174
261
|
if (!currentFields)
|
|
175
262
|
continue;
|
|
263
|
+
if (/^##\s+/.test(trimmed)) {
|
|
264
|
+
flush();
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
176
267
|
const fieldMatch = /^\s{2}([a-z_]+):\s*(.*?)\s*$/.exec(line);
|
|
177
268
|
if (fieldMatch) {
|
|
178
269
|
currentKey = String(fieldMatch[1] ?? "").trim();
|
|
@@ -191,32 +282,151 @@ export function parseIncidentRegistry(text) {
|
|
|
191
282
|
return { entries };
|
|
192
283
|
}
|
|
193
284
|
export function formatIncidentRegistryEntry(entry) {
|
|
285
|
+
return formatIncidentRegistryEntryForStyle(entry, "structured");
|
|
286
|
+
}
|
|
287
|
+
function parseInlineIncidentEntry(trimmedLine) {
|
|
288
|
+
if (!trimmedLine.startsWith("- "))
|
|
289
|
+
return null;
|
|
290
|
+
const body = trimmedLine.slice(2).trim();
|
|
291
|
+
if (!body)
|
|
292
|
+
return null;
|
|
293
|
+
const segments = body.split(/\s+\|\s+(?=[a-z_]+:\s*)/u);
|
|
294
|
+
const fields = {};
|
|
295
|
+
for (const segment of segments) {
|
|
296
|
+
const match = /^([a-z_]+):\s*(.*?)\s*$/.exec(segment.trim());
|
|
297
|
+
if (!match)
|
|
298
|
+
return null;
|
|
299
|
+
const key = String(match[1] ?? "").trim();
|
|
300
|
+
if (!key)
|
|
301
|
+
return null;
|
|
302
|
+
fields[key] = match[2] ?? "";
|
|
303
|
+
}
|
|
304
|
+
return fields.id ? fields : null;
|
|
305
|
+
}
|
|
306
|
+
function formatIncidentRegistryEntryForStyle(entry, style) {
|
|
307
|
+
const compactFields = [
|
|
308
|
+
incidentField("id", entry.id),
|
|
309
|
+
incidentField("date", entry.date),
|
|
310
|
+
incidentField("scope", entry.scope),
|
|
311
|
+
...(entry.tags.length > 0 ? [incidentField("tags", entry.tags.join(", "))] : []),
|
|
312
|
+
...(entry.match.length > 0 ? [incidentField("match", entry.match.join(", "))] : []),
|
|
313
|
+
incidentField("failure", entry.failure),
|
|
314
|
+
...(entry.advice ? [incidentField("advice", entry.advice)] : []),
|
|
315
|
+
incidentField("rule", entry.rule),
|
|
316
|
+
incidentField("evidence", entry.evidence),
|
|
317
|
+
incidentField("enforcement", entry.enforcement),
|
|
318
|
+
...(entry.fixability ? [incidentField("fixability", entry.fixability)] : []),
|
|
319
|
+
incidentField("state", entry.state),
|
|
320
|
+
];
|
|
321
|
+
if (style === "compact") {
|
|
322
|
+
return `- ${compactFields.map(([key, value]) => `${key}: ${value}`).join(" | ")}`;
|
|
323
|
+
}
|
|
324
|
+
const structuredFields = [
|
|
325
|
+
incidentField("id", entry.id),
|
|
326
|
+
incidentField("date", entry.date),
|
|
327
|
+
incidentField("scope", entry.scope),
|
|
328
|
+
...(entry.tags.length > 0 ? [incidentField("tags", entry.tags.join(", "))] : []),
|
|
329
|
+
...(entry.match.length > 0 ? [incidentField("match", entry.match.join(", "))] : []),
|
|
330
|
+
incidentField("failure", entry.failure),
|
|
331
|
+
...(entry.advice ? [incidentField("advice", entry.advice)] : []),
|
|
332
|
+
incidentField("rule", entry.rule),
|
|
333
|
+
incidentField("evidence", entry.evidence),
|
|
334
|
+
incidentField("enforcement", entry.enforcement),
|
|
335
|
+
...(entry.sourceTask ? [incidentField("source_task", entry.sourceTask)] : []),
|
|
336
|
+
...(entry.fixability ? [incidentField("fixability", entry.fixability)] : []),
|
|
337
|
+
incidentField("state", entry.state),
|
|
338
|
+
];
|
|
194
339
|
return [
|
|
195
|
-
`-
|
|
196
|
-
`
|
|
197
|
-
` scope: ${entry.scope}`,
|
|
198
|
-
...(entry.tags.length > 0 ? [` tags: ${entry.tags.join(", ")}`] : []),
|
|
199
|
-
...(entry.match.length > 0 ? [` match: ${entry.match.join(", ")}`] : []),
|
|
200
|
-
` failure: ${entry.failure}`,
|
|
201
|
-
...(entry.advice ? [` advice: ${entry.advice}`] : []),
|
|
202
|
-
` rule: ${entry.rule}`,
|
|
203
|
-
` evidence: ${entry.evidence}`,
|
|
204
|
-
` enforcement: ${entry.enforcement}`,
|
|
205
|
-
...(entry.sourceTask ? [` source_task: ${entry.sourceTask}`] : []),
|
|
206
|
-
...(entry.fixability ? [` fixability: ${entry.fixability}`] : []),
|
|
207
|
-
` state: ${entry.state}`,
|
|
340
|
+
`- ${structuredFields[0]?.[0]}: ${structuredFields[0]?.[1] ?? ""}`,
|
|
341
|
+
...structuredFields.slice(1).map(([key, value]) => ` ${key}: ${value}`),
|
|
208
342
|
].join("\n");
|
|
209
343
|
}
|
|
344
|
+
function detectRegistryStyle(text) {
|
|
345
|
+
return /(^|\n)## Entries\s*$/mu.test(text) || /(^|\n)## Entry contract\s*$/mu.test(text)
|
|
346
|
+
? "structured"
|
|
347
|
+
: "compact";
|
|
348
|
+
}
|
|
349
|
+
function entryRichness(entry) {
|
|
350
|
+
return [
|
|
351
|
+
entry.sourceTask ? 4 : 0,
|
|
352
|
+
entry.advice ? 3 : 0,
|
|
353
|
+
entry.tags.length,
|
|
354
|
+
entry.match.length,
|
|
355
|
+
entry.fixability ? 1 : 0,
|
|
356
|
+
entry.evidence.length > 0 ? 1 : 0,
|
|
357
|
+
].reduce((sum, item) => sum + item, 0);
|
|
358
|
+
}
|
|
359
|
+
function nextIncidentIdForDate(dateStamp, usedIds, nextByDate) {
|
|
360
|
+
let next = nextByDate.get(dateStamp) ?? 0;
|
|
361
|
+
do {
|
|
362
|
+
next += 1;
|
|
363
|
+
} while (usedIds.has(`INC-${dateStamp}-${String(next).padStart(2, "0")}`));
|
|
364
|
+
nextByDate.set(dateStamp, next);
|
|
365
|
+
return `INC-${dateStamp}-${String(next).padStart(2, "0")}`;
|
|
366
|
+
}
|
|
367
|
+
function normalizeIncidentRegistryEntries(entries) {
|
|
368
|
+
const byFingerprint = new Map();
|
|
369
|
+
const orderedFingerprints = [];
|
|
370
|
+
for (const entry of entries) {
|
|
371
|
+
const fingerprint = buildIncidentFingerprint(entry);
|
|
372
|
+
const existing = byFingerprint.get(fingerprint);
|
|
373
|
+
if (!existing) {
|
|
374
|
+
byFingerprint.set(fingerprint, { ...entry });
|
|
375
|
+
orderedFingerprints.push(fingerprint);
|
|
376
|
+
continue;
|
|
377
|
+
}
|
|
378
|
+
if (entryRichness(entry) >= entryRichness(existing)) {
|
|
379
|
+
byFingerprint.set(fingerprint, { ...entry });
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
const normalized = orderedFingerprints.map((fingerprint) => byFingerprint.get(fingerprint));
|
|
383
|
+
const usedIds = new Set();
|
|
384
|
+
const nextByDate = new Map();
|
|
385
|
+
for (const entry of normalized) {
|
|
386
|
+
const match = /^INC-(\d{8})-(\d+)$/u.exec(entry.id);
|
|
387
|
+
if (!match)
|
|
388
|
+
continue;
|
|
389
|
+
const [, dateStamp, seqRaw] = match;
|
|
390
|
+
const seq = Number.parseInt(seqRaw ?? "", 10);
|
|
391
|
+
if (!Number.isInteger(seq))
|
|
392
|
+
continue;
|
|
393
|
+
const existing = nextByDate.get(dateStamp) ?? 0;
|
|
394
|
+
if (seq > existing)
|
|
395
|
+
nextByDate.set(dateStamp, seq);
|
|
396
|
+
}
|
|
397
|
+
return normalized.map((entry) => {
|
|
398
|
+
const dateStamp = /^\d{4}-\d{2}-\d{2}$/u.test(entry.date)
|
|
399
|
+
? entry.date.replaceAll("-", "")
|
|
400
|
+
: "00000000";
|
|
401
|
+
const nextId = usedIds.has(entry.id)
|
|
402
|
+
? nextIncidentIdForDate(dateStamp, usedIds, nextByDate)
|
|
403
|
+
: entry.id;
|
|
404
|
+
usedIds.add(nextId);
|
|
405
|
+
return nextId === entry.id ? entry : { ...entry, id: nextId };
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
function renderIncidentRegistryDocument(entries, style) {
|
|
409
|
+
const header = style === "structured" ? createIncidentRegistrySkeleton().trimEnd() : COMPACT_INCIDENTS_HEADER;
|
|
410
|
+
if (entries.length === 0)
|
|
411
|
+
return `${header}\n`;
|
|
412
|
+
const separator = style === "structured" ? "\n\n" : "\n";
|
|
413
|
+
return `${header}\n${entries.map((entry) => formatIncidentRegistryEntryForStyle(entry, style)).join(separator)}\n`;
|
|
414
|
+
}
|
|
210
415
|
export function appendIncidentRegistryEntries(currentText, entries) {
|
|
211
416
|
if (entries.length === 0)
|
|
212
417
|
return currentText;
|
|
213
|
-
const
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
const
|
|
217
|
-
return
|
|
418
|
+
const baseText = currentText.trim().length > 0 ? currentText : createIncidentRegistrySkeleton();
|
|
419
|
+
const style = detectRegistryStyle(baseText);
|
|
420
|
+
const existing = parseIncidentRegistry(baseText);
|
|
421
|
+
const merged = normalizeIncidentRegistryEntries([...existing.entries, ...entries]);
|
|
422
|
+
return renderIncidentRegistryDocument(merged, style);
|
|
218
423
|
}
|
|
219
424
|
export function extractIncidentCandidatesFromFindings(findings) {
|
|
425
|
+
return parseIncidentFindingBlocks(findings)
|
|
426
|
+
.filter((candidate) => candidate.shouldPromote)
|
|
427
|
+
.map(({ shouldPromote: _shouldPromote, ...candidate }) => candidate);
|
|
428
|
+
}
|
|
429
|
+
function parseIncidentFindingBlocks(findings) {
|
|
220
430
|
const lines = normalizeLines(findings);
|
|
221
431
|
const candidates = [];
|
|
222
432
|
let currentFields = null;
|
|
@@ -225,13 +435,11 @@ export function extractIncidentCandidatesFromFindings(findings) {
|
|
|
225
435
|
const flush = () => {
|
|
226
436
|
if (!currentFields)
|
|
227
437
|
return;
|
|
228
|
-
const promotion = currentFields.promotion?.trim()
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
return;
|
|
234
|
-
}
|
|
438
|
+
const promotion = currentFields.promotion?.trim() || null;
|
|
439
|
+
const fixability = parseFixability(currentFields.fixability);
|
|
440
|
+
const incidentExternal = parseBoolean(currentFields.incidentexternal) || fixability === "external";
|
|
441
|
+
const incidentInternal = parseBoolean(currentFields.incidentinternal) || fixability === "repo-fixable";
|
|
442
|
+
const shouldPromote = promotion?.toLowerCase() === "incident-candidate" || incidentExternal || incidentInternal;
|
|
235
443
|
const observation = currentFields.observation?.trim() ?? "";
|
|
236
444
|
if (!observation) {
|
|
237
445
|
currentFields = null;
|
|
@@ -249,7 +457,10 @@ export function extractIncidentCandidatesFromFindings(findings) {
|
|
|
249
457
|
incidentAdvice: currentFields.incidentadvice?.trim() || null,
|
|
250
458
|
incidentTags: parseCsvList(currentFields.incidenttags),
|
|
251
459
|
incidentMatch: parseCsvList(currentFields.incidentmatch),
|
|
252
|
-
incidentExternal
|
|
460
|
+
incidentExternal,
|
|
461
|
+
incidentInternal,
|
|
462
|
+
fixability,
|
|
463
|
+
shouldPromote,
|
|
253
464
|
line: currentLine,
|
|
254
465
|
rawFields: { ...currentFields },
|
|
255
466
|
});
|
|
@@ -313,47 +524,69 @@ function nextIncidentId(entries, now) {
|
|
|
313
524
|
}
|
|
314
525
|
function buildPromotionIssues(candidate) {
|
|
315
526
|
const missingFields = [];
|
|
316
|
-
if (!candidate.incidentExternal)
|
|
317
|
-
missingFields.push("IncidentExternal: true");
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
if (!candidate.incidentAdvice)
|
|
323
|
-
missingFields.push("IncidentAdvice");
|
|
527
|
+
if (!candidate.incidentExternal && !candidate.incidentInternal && candidate.fixability === null) {
|
|
528
|
+
missingFields.push("Fixability: external or IncidentExternal: true");
|
|
529
|
+
}
|
|
530
|
+
if (!candidate.incidentAdvice && !candidate.resolution) {
|
|
531
|
+
missingFields.push("Resolution or IncidentAdvice");
|
|
532
|
+
}
|
|
324
533
|
return missingFields.length > 0 ? { candidate, missingFields } : null;
|
|
325
534
|
}
|
|
326
535
|
function buildIncidentRegistryEntry(opts) {
|
|
327
536
|
const date = opts.now.toISOString().slice(0, 10);
|
|
537
|
+
const scope = opts.candidate.incidentScope ?? summarizeTaskScope(opts.task.scope, opts.task.title);
|
|
328
538
|
const tags = dedupeCaseInsensitive([
|
|
329
539
|
...opts.candidate.incidentTags,
|
|
330
540
|
...opts.task.tags.map((tag) => tag.trim()),
|
|
331
541
|
]);
|
|
542
|
+
const advice = opts.candidate.incidentAdvice ?? opts.candidate.resolution ?? opts.candidate.observation;
|
|
543
|
+
const rule = opts.candidate.incidentRule ?? buildDerivedIncidentRule(scope);
|
|
544
|
+
const state = resolveIncidentState({
|
|
545
|
+
registry: opts.registry,
|
|
546
|
+
entry: {
|
|
547
|
+
scope,
|
|
548
|
+
failure: opts.candidate.observation,
|
|
549
|
+
rule,
|
|
550
|
+
},
|
|
551
|
+
now: opts.now,
|
|
552
|
+
});
|
|
332
553
|
const match = buildMatchTerms({
|
|
333
|
-
scope
|
|
554
|
+
scope,
|
|
334
555
|
tags,
|
|
335
556
|
explicitMatch: opts.candidate.incidentMatch,
|
|
557
|
+
extraText: [opts.task.title, opts.task.description, advice],
|
|
336
558
|
});
|
|
337
559
|
return {
|
|
338
|
-
id: nextIncidentId(opts.
|
|
560
|
+
id: nextIncidentId(opts.registry.entries, opts.now),
|
|
339
561
|
date,
|
|
340
|
-
scope
|
|
562
|
+
scope,
|
|
341
563
|
failure: opts.candidate.observation,
|
|
342
|
-
rule
|
|
564
|
+
rule,
|
|
343
565
|
evidence: `task ${opts.task.id}${opts.task.commitHash ? `; commit ${opts.task.commitHash.slice(0, 12)}` : ""}`,
|
|
344
566
|
enforcement: "manual",
|
|
345
|
-
state
|
|
567
|
+
state,
|
|
346
568
|
tags,
|
|
347
569
|
match,
|
|
348
|
-
advice
|
|
570
|
+
advice,
|
|
349
571
|
sourceTask: opts.task.id,
|
|
350
|
-
fixability: "external",
|
|
572
|
+
fixability: opts.candidate.fixability ?? (opts.candidate.incidentInternal ? "repo-fixable" : "external"),
|
|
351
573
|
rawFields: {},
|
|
352
574
|
line: 0,
|
|
353
575
|
};
|
|
354
576
|
}
|
|
355
577
|
export function planIncidentCollection(opts) {
|
|
356
|
-
const
|
|
578
|
+
const parsed = parseIncidentFindingBlocks(opts.findings);
|
|
579
|
+
const candidates = parsed
|
|
580
|
+
.filter((candidate) => candidate.shouldPromote)
|
|
581
|
+
.map(({ shouldPromote: _shouldPromote, ...candidate }) => candidate);
|
|
582
|
+
const skipped = parsed
|
|
583
|
+
.filter((candidate) => !candidate.shouldPromote)
|
|
584
|
+
.map(({ observation, line, rawFields }) => ({
|
|
585
|
+
observation,
|
|
586
|
+
line,
|
|
587
|
+
reason: "not_marked_external_or_promotable",
|
|
588
|
+
rawFields,
|
|
589
|
+
}));
|
|
357
590
|
const issues = [];
|
|
358
591
|
const promotable = [];
|
|
359
592
|
const duplicates = [];
|
|
@@ -369,7 +602,10 @@ export function planIncidentCollection(opts) {
|
|
|
369
602
|
task: opts.task,
|
|
370
603
|
candidate,
|
|
371
604
|
now,
|
|
372
|
-
|
|
605
|
+
registry: parseIncidentRegistry(appendIncidentRegistryEntries(createIncidentRegistrySkeleton(), [
|
|
606
|
+
...opts.registry.entries,
|
|
607
|
+
...promotable.map((item) => item.entry),
|
|
608
|
+
])),
|
|
373
609
|
});
|
|
374
610
|
const fingerprint = buildIncidentFingerprint(entry);
|
|
375
611
|
const draft = { candidate, entry, fingerprint };
|
|
@@ -380,7 +616,15 @@ export function planIncidentCollection(opts) {
|
|
|
380
616
|
seenFingerprints.add(fingerprint);
|
|
381
617
|
promotable.push(draft);
|
|
382
618
|
}
|
|
383
|
-
return {
|
|
619
|
+
return {
|
|
620
|
+
candidates,
|
|
621
|
+
skipped,
|
|
622
|
+
promotable,
|
|
623
|
+
duplicates,
|
|
624
|
+
issues,
|
|
625
|
+
findingsTextPresent: opts.findings.trim().length > 0,
|
|
626
|
+
structuredFindingCount: parsed.length,
|
|
627
|
+
};
|
|
384
628
|
}
|
|
385
629
|
export function buildIncidentAdviceQueryFromTask(opts) {
|
|
386
630
|
return {
|
|
@@ -397,10 +641,8 @@ export function resolveIncidentAdviceMatches(opts) {
|
|
|
397
641
|
const haystack = [opts.query.title, opts.query.description, opts.query.scope ?? ""].join(" ");
|
|
398
642
|
const normalizedHaystack = normalizeSearchText(haystack);
|
|
399
643
|
const queryTokens = new Set([...tokenize(haystack), ...tagSet]);
|
|
400
|
-
const
|
|
644
|
+
const matchesBySignature = new Map();
|
|
401
645
|
for (const entry of opts.registry.entries) {
|
|
402
|
-
if (entry.state === "open")
|
|
403
|
-
continue;
|
|
404
646
|
const matchedTags = entry.tags.filter((tag) => tagSet.has(tag.trim().toLowerCase()));
|
|
405
647
|
const matchedTerms = entry.match.filter((term) => queryTokens.has(term.trim().toLowerCase()) ||
|
|
406
648
|
normalizedHaystack.includes(normalizeSearchText(term)));
|
|
@@ -409,12 +651,16 @@ export function resolveIncidentAdviceMatches(opts) {
|
|
|
409
651
|
const score = matchedTags.length * 5 + matchedTerms.length * 2 + (scopeMatched ? 3 : 0);
|
|
410
652
|
if (score <= 0)
|
|
411
653
|
continue;
|
|
412
|
-
|
|
654
|
+
const match = { entry, score, matchedTags, matchedTerms, scopeMatched };
|
|
655
|
+
const signature = buildIncidentSignature(entry);
|
|
656
|
+
const existing = matchesBySignature.get(signature);
|
|
657
|
+
if (!existing || compareIncidentAdviceMatch(match, existing) < 0) {
|
|
658
|
+
matchesBySignature.set(signature, match);
|
|
659
|
+
}
|
|
413
660
|
}
|
|
661
|
+
const matches = [...matchesBySignature.values()];
|
|
414
662
|
matches.sort((left, right) => {
|
|
415
|
-
|
|
416
|
-
return right.score - left.score;
|
|
417
|
-
return right.entry.date.localeCompare(left.entry.date);
|
|
663
|
+
return compareIncidentAdviceMatch(left, right);
|
|
418
664
|
});
|
|
419
665
|
return matches.slice(0, limit);
|
|
420
666
|
}
|
|
@@ -12,7 +12,7 @@ export type IncidentRegistryEntry = {
|
|
|
12
12
|
match: string[];
|
|
13
13
|
advice: string | null;
|
|
14
14
|
sourceTask: string | null;
|
|
15
|
-
fixability: "external" | null;
|
|
15
|
+
fixability: "external" | "repo-fixable" | null;
|
|
16
16
|
rawFields: Record<string, string>;
|
|
17
17
|
line: number;
|
|
18
18
|
};
|
|
@@ -23,20 +23,29 @@ export type IncidentFindingCandidate = {
|
|
|
23
23
|
observation: string;
|
|
24
24
|
impact: string | null;
|
|
25
25
|
resolution: string | null;
|
|
26
|
-
promotion: string;
|
|
26
|
+
promotion: string | null;
|
|
27
27
|
incidentScope: string | null;
|
|
28
28
|
incidentRule: string | null;
|
|
29
29
|
incidentAdvice: string | null;
|
|
30
30
|
incidentTags: string[];
|
|
31
31
|
incidentMatch: string[];
|
|
32
32
|
incidentExternal: boolean;
|
|
33
|
+
incidentInternal: boolean;
|
|
34
|
+
fixability: "external" | "repo-fixable" | null;
|
|
33
35
|
line: number;
|
|
34
36
|
rawFields: Record<string, string>;
|
|
35
37
|
};
|
|
38
|
+
export type IncidentSkippedFinding = {
|
|
39
|
+
observation: string;
|
|
40
|
+
line: number;
|
|
41
|
+
reason: "not_marked_external_or_promotable";
|
|
42
|
+
rawFields: Record<string, string>;
|
|
43
|
+
};
|
|
36
44
|
export type IncidentPromotionTaskContext = {
|
|
37
45
|
id: string;
|
|
38
46
|
title: string;
|
|
39
47
|
description: string;
|
|
48
|
+
scope?: string | null;
|
|
40
49
|
tags: string[];
|
|
41
50
|
commitHash?: string | null;
|
|
42
51
|
};
|
|
@@ -51,9 +60,12 @@ export type IncidentPromotionIssue = {
|
|
|
51
60
|
};
|
|
52
61
|
export type IncidentCollectionPlan = {
|
|
53
62
|
candidates: IncidentFindingCandidate[];
|
|
63
|
+
skipped: IncidentSkippedFinding[];
|
|
54
64
|
promotable: IncidentPromotionDraft[];
|
|
55
65
|
duplicates: IncidentPromotionDraft[];
|
|
56
66
|
issues: IncidentPromotionIssue[];
|
|
67
|
+
findingsTextPresent: boolean;
|
|
68
|
+
structuredFindingCount: number;
|
|
57
69
|
};
|
|
58
70
|
export type IncidentAdviceQuery = {
|
|
59
71
|
taskId?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/runtime/incidents/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,0BAA0B,GAAG,MAAM,GAAG,YAAY,GAAG,UAAU,CAAC;AAE5E,MAAM,MAAM,qBAAqB,GAAG;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,0BAA0B,CAAC;IAClC,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/runtime/incidents/types.ts"],"names":[],"mappings":"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"}
|
package/dist/shared/env.d.ts
CHANGED
package/dist/shared/env.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../src/shared/env.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../src/shared/env.ts"],"names":[],"mappings":"AAKA,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA4BhE;AAmBD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAE5F;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB/D"}
|