hex-audit 0.4.4 → 0.4.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.
Files changed (89) hide show
  1. package/DEMO.md +3 -2
  2. package/README.md +45 -41
  3. package/dashboard/.next/BUILD_ID +1 -1
  4. package/dashboard/.next/app-build-manifest.json +18 -11
  5. package/dashboard/.next/app-path-routes-manifest.json +1 -1
  6. package/dashboard/.next/build-manifest.json +4 -4
  7. package/dashboard/.next/next-server.js.nft.json +1 -1
  8. package/dashboard/.next/prerender-manifest.js +1 -1
  9. package/dashboard/.next/prerender-manifest.json +1 -1
  10. package/dashboard/.next/required-server-files.json +1 -1
  11. package/dashboard/.next/routes-manifest.json +1 -1
  12. package/dashboard/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  13. package/dashboard/.next/server/app/_not-found.html +1 -1
  14. package/dashboard/.next/server/app/_not-found.rsc +4 -4
  15. package/dashboard/.next/server/app/access/page_client-reference-manifest.js +1 -1
  16. package/dashboard/.next/server/app/api/flows/route.js +1 -1
  17. package/dashboard/.next/server/app/api/issues/[id]/move/route.js +1 -1
  18. package/dashboard/.next/server/app/api/issues/[id]/route.js +1 -1
  19. package/dashboard/.next/server/app/calls/page_client-reference-manifest.js +1 -1
  20. package/dashboard/.next/server/app/conformance/page_client-reference-manifest.js +1 -1
  21. package/dashboard/.next/server/app/diagram/page_client-reference-manifest.js +1 -1
  22. package/dashboard/.next/server/app/diagram.html +1 -1
  23. package/dashboard/.next/server/app/diagram.rsc +4 -4
  24. package/dashboard/.next/server/app/flows/page_client-reference-manifest.js +1 -1
  25. package/dashboard/.next/server/app/flows.html +1 -1
  26. package/dashboard/.next/server/app/flows.rsc +4 -4
  27. package/dashboard/.next/server/app/functions/page_client-reference-manifest.js +1 -1
  28. package/dashboard/.next/server/app/issues/page.js +12 -1
  29. package/dashboard/.next/server/app/issues/page_client-reference-manifest.js +1 -1
  30. package/dashboard/.next/server/app/overleaf/page.js +1 -0
  31. package/dashboard/.next/server/app/overleaf/page.js.nft.json +1 -0
  32. package/dashboard/.next/server/app/overleaf/page_client-reference-manifest.js +1 -0
  33. package/dashboard/.next/server/app/page_client-reference-manifest.js +1 -1
  34. package/dashboard/.next/server/app/progress/page_client-reference-manifest.js +1 -1
  35. package/dashboard/.next/server/app/stats/page_client-reference-manifest.js +1 -1
  36. package/dashboard/.next/server/app-paths-manifest.json +8 -7
  37. package/dashboard/.next/server/chunks/431.js +1 -1
  38. package/dashboard/.next/server/functions-config-manifest.json +1 -1
  39. package/dashboard/.next/server/middleware-build-manifest.js +1 -1
  40. package/dashboard/.next/server/pages/404.html +1 -1
  41. package/dashboard/.next/server/pages/500.html +1 -1
  42. package/dashboard/.next/server/server-reference-manifest.js +1 -1
  43. package/dashboard/.next/server/server-reference-manifest.json +1 -1
  44. package/dashboard/.next/static/chunks/app/issues/page-30f7bcde0f4f6ddb.js +1 -0
  45. package/dashboard/.next/static/chunks/app/{layout-527d8aa86e483fbd.js → layout-cde7d75ea6df4f81.js} +1 -1
  46. package/dashboard/.next/static/chunks/app/overleaf/page-bcea12a80c97b92f.js +1 -0
  47. package/dashboard/.next/static/chunks/{main-70c6d841ad572657.js → main-8f1e837090aef5cf.js} +1 -1
  48. package/dashboard/.next/static/css/36c6bb859d4545fd.css +3 -0
  49. package/dashboard/app/api/flows/route.ts +4 -0
  50. package/dashboard/app/api/issues/[id]/move/route.ts +29 -58
  51. package/dashboard/app/api/issues/[id]/route.ts +11 -102
  52. package/dashboard/app/issues/IssuesBoardClient.tsx +109 -35
  53. package/dashboard/app/issues/page.tsx +37 -3
  54. package/dashboard/app/overleaf/OverleafClient.tsx +97 -0
  55. package/dashboard/app/overleaf/page.tsx +32 -0
  56. package/dashboard/components/DashboardLayout.tsx +8 -2
  57. package/dashboard/lib/finding-markdown.ts +59 -0
  58. package/dashboard/next.config.mjs +4 -0
  59. package/dist/analysis/external-calls.d.ts +8 -1
  60. package/dist/analysis/external-calls.d.ts.map +1 -1
  61. package/dist/analysis/external-calls.js +57 -13
  62. package/dist/analysis/external-calls.js.map +1 -1
  63. package/dist/commands/calls.d.ts.map +1 -1
  64. package/dist/commands/calls.js +15 -6
  65. package/dist/commands/calls.js.map +1 -1
  66. package/dist/commands/init.d.ts.map +1 -1
  67. package/dist/commands/init.js +17 -19
  68. package/dist/commands/init.js.map +1 -1
  69. package/dist/commands/issue.d.ts +3 -0
  70. package/dist/commands/issue.d.ts.map +1 -0
  71. package/dist/commands/issue.js +115 -0
  72. package/dist/commands/issue.js.map +1 -0
  73. package/dist/core/issues.d.ts +79 -0
  74. package/dist/core/issues.d.ts.map +1 -0
  75. package/dist/core/issues.js +253 -0
  76. package/dist/core/issues.js.map +1 -0
  77. package/dist/index.js +3 -1
  78. package/dist/index.js.map +1 -1
  79. package/dist/skills/init-audit.md +3 -1
  80. package/dist/skills/sync-issues.md +17 -34
  81. package/dist/skills/validate-issue.md +20 -10
  82. package/dist/skills/write-finding.md +1 -1
  83. package/package.json +1 -1
  84. package/dashboard/.next/server/app/api/flows.body +0 -1
  85. package/dashboard/.next/server/app/api/flows.meta +0 -1
  86. package/dashboard/.next/static/chunks/app/issues/page-dc110d4cc0a5c398.js +0 -1
  87. package/dashboard/.next/static/css/7a38e5062ba6d403.css +0 -3
  88. /package/dashboard/.next/static/{ePObaFrrwft0BlvlllUMo → 4HWoeGmBSZi6iGcKL3VWA}/_buildManifest.js +0 -0
  89. /package/dashboard/.next/static/{ePObaFrrwft0BlvlllUMo → 4HWoeGmBSZi6iGcKL3VWA}/_ssgManifest.js +0 -0
@@ -0,0 +1,115 @@
1
+ import { Command } from 'commander';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { logger } from '../core/logger.js';
5
+ import { loadConfig } from '../core/config.js';
6
+ import { getOutputDir } from '../core/paths.js';
7
+ import { reportError } from '../core/errors.js';
8
+ import { moveIssue, patchIssue, COLUMN_TO_STATUS } from '../core/issues.js';
9
+ function resolveOutputDir(opts) {
10
+ const projectDir = path.resolve(opts.project ?? process.cwd());
11
+ const config = loadConfig(projectDir);
12
+ return getOutputDir(config.project.project_dir, config.settings.output_dir);
13
+ }
14
+ const moveCmd = new Command('move')
15
+ .description('Move an issue between board columns (potential | verified | invalid | duplicate)')
16
+ .argument('<id>', 'Issue id (e.g. F001, SC-001, AA-003, github-12)')
17
+ .requiredOption('--to <column>', 'Target column: potential | verified | invalid | duplicate')
18
+ .option('--project <dir>', 'Project directory')
19
+ .action((id, opts) => {
20
+ try {
21
+ const column = opts.to;
22
+ if (!(column in COLUMN_TO_STATUS)) {
23
+ logger.error(`Invalid --to: ${opts.to}. Use one of: ${Object.keys(COLUMN_TO_STATUS).join(', ')}`);
24
+ process.exit(1);
25
+ }
26
+ const outputDir = resolveOutputDir(opts);
27
+ const entry = moveIssue(outputDir, id, column);
28
+ logger.success(`${id} → ${column} (status: ${entry.status})`);
29
+ }
30
+ catch (err) {
31
+ reportError(err);
32
+ process.exit(1);
33
+ }
34
+ });
35
+ const patchCmd = new Command('patch')
36
+ .description('Edit fields on an issue (materializes a findings.json entry if needed)')
37
+ .argument('<id>', 'Issue id')
38
+ .option('--title <title>', 'New title')
39
+ .option('--severity <severity>', 'Critical | High | Medium | Low | Info')
40
+ .option('--resolution <resolution>', 'Fixed | Mitigated | Acknowledged | Not Fixed | Unresolved')
41
+ .option('--description-file <path>', 'Read the description from this file')
42
+ .option('--recommendation-file <path>', 'Read the recommendation from this file')
43
+ .option('--update-from-client <text>', 'Client update text')
44
+ .option('--notes <text>', 'Tracking notes')
45
+ .option('--project <dir>', 'Project directory')
46
+ .action((id, opts) => {
47
+ try {
48
+ const updates = {};
49
+ if (opts.title != null)
50
+ updates.title = opts.title;
51
+ if (opts.severity != null)
52
+ updates.severity = opts.severity;
53
+ if (opts.resolution != null)
54
+ updates.resolution = opts.resolution;
55
+ if (opts.updateFromClient != null)
56
+ updates.update_from_client = opts.updateFromClient;
57
+ if (opts.notes != null)
58
+ updates.notes = opts.notes;
59
+ if (opts.descriptionFile != null) {
60
+ updates.description = fs.readFileSync(path.resolve(opts.descriptionFile), 'utf-8').trim();
61
+ }
62
+ if (opts.recommendationFile != null) {
63
+ updates.recommendation = fs
64
+ .readFileSync(path.resolve(opts.recommendationFile), 'utf-8')
65
+ .trim();
66
+ }
67
+ if (Object.keys(updates).length === 0) {
68
+ logger.error('Nothing to patch. Pass at least one of --title/--severity/--resolution/--description-file/--recommendation-file/--update-from-client/--notes.');
69
+ process.exit(1);
70
+ }
71
+ const outputDir = resolveOutputDir(opts);
72
+ const updated = patchIssue(outputDir, id, updates);
73
+ logger.success(`Patched ${id} (${Object.keys(updates).join(', ')})`);
74
+ logger.dim(`severity=${updated.severity} resolution=${updated.resolution ?? '(none)'}`);
75
+ }
76
+ catch (err) {
77
+ reportError(err);
78
+ process.exit(1);
79
+ }
80
+ });
81
+ const showCmd = new Command('show')
82
+ .description('Print the merged finding + tracking record for an issue id')
83
+ .argument('<id>', 'Issue id')
84
+ .option('--project <dir>', 'Project directory')
85
+ .action((id, opts) => {
86
+ try {
87
+ const outputDir = resolveOutputDir(opts);
88
+ const findings = JSON.parse(fs.readFileSync(path.join(outputDir, 'findings.json'), 'utf-8'));
89
+ const tracking = (() => {
90
+ try {
91
+ return JSON.parse(fs.readFileSync(path.join(outputDir, 'tracking.json'), 'utf-8'));
92
+ }
93
+ catch {
94
+ return { findings: [] };
95
+ }
96
+ })();
97
+ const finding = findings.findings.find((f) => f.id === id) ?? null;
98
+ const track = tracking.findings.find((t) => t.id === id) ?? null;
99
+ if (!finding && !track) {
100
+ logger.error(`No issue with id ${id} in findings.json or tracking.json`);
101
+ process.exit(1);
102
+ }
103
+ console.log(JSON.stringify({ id, finding, tracking: track }, null, 2));
104
+ }
105
+ catch (err) {
106
+ reportError(err);
107
+ process.exit(1);
108
+ }
109
+ });
110
+ export const issueCommand = new Command('issue')
111
+ .description('Inspect and mutate issues on the board (move / patch / show)')
112
+ .addCommand(moveCmd)
113
+ .addCommand(patchCmd)
114
+ .addCommand(showCmd);
115
+ //# sourceMappingURL=issue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"issue.js","sourceRoot":"","sources":["../../src/commands/issue.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,79 @@
1
+ export type BoardColumn = 'potential' | 'verified' | 'invalid' | 'duplicate';
2
+ export type Severity = 'Critical' | 'High' | 'Medium' | 'Low' | 'Info';
3
+ export type Resolution = 'Fixed' | 'Mitigated' | 'Acknowledged' | 'Not Fixed' | 'Unresolved';
4
+ export declare const SEVERITY_VALUES: readonly Severity[];
5
+ export declare const RESOLUTION_VALUES: readonly Resolution[];
6
+ export declare const COLUMN_TO_STATUS: Record<BoardColumn, string>;
7
+ /** Fields a user may edit through the board modal or `hex issue patch`. */
8
+ export declare const EDITABLE_FIELDS: readonly ["title", "severity", "description", "recommendation", "resolution", "update_from_client", "notes"];
9
+ export type EditableField = (typeof EDITABLE_FIELDS)[number];
10
+ interface FindingLocation {
11
+ file: string;
12
+ snippet?: string;
13
+ }
14
+ export interface Finding {
15
+ id: string;
16
+ title: string;
17
+ severity: Severity;
18
+ category: string;
19
+ description: string;
20
+ root_cause: {
21
+ locations: FindingLocation[];
22
+ };
23
+ poc: {
24
+ status: string;
25
+ file: string | null;
26
+ validation_memo: string | null;
27
+ };
28
+ recommendation: string;
29
+ references: {
30
+ external_links: string[];
31
+ };
32
+ created_at: string;
33
+ update_from_client?: string;
34
+ resolution?: Resolution;
35
+ github?: Record<string, unknown>;
36
+ [k: string]: unknown;
37
+ }
38
+ export interface TrackingEntry {
39
+ id: string;
40
+ title: string;
41
+ severity: Severity;
42
+ source: string;
43
+ status: string;
44
+ poc_status: string;
45
+ poc_file: string | null;
46
+ duplicates: string[];
47
+ duplicate_of?: string | null;
48
+ notes: string;
49
+ [k: string]: unknown;
50
+ }
51
+ export declare function isValidSeverity(v: unknown): v is Severity;
52
+ export declare function isValidResolution(v: unknown): v is Resolution;
53
+ /**
54
+ * Ensure a findings.json entry exists for `id`, materializing one from the
55
+ * source-specific record if needed. Idempotent: returns the existing entry
56
+ * untouched when present. Dispatches on id prefix.
57
+ */
58
+ export declare function ensureFindingExists(outputDir: string, id: string): Finding;
59
+ /**
60
+ * Move an issue between board columns. Materializes a findings.json entry first
61
+ * (so non-manual cards become reportable when promoted to Verified), then flips
62
+ * the tracking status.
63
+ *
64
+ * Note: this does NOT edit the user's source files. Source annotation
65
+ * (`// @audit-issue-verified ...`) remains the responsibility of the
66
+ * /validate-issue skill, which the auditor invokes deliberately — a drag-drop
67
+ * on the board should never silently rewrite .sol files.
68
+ */
69
+ export declare function moveIssue(outputDir: string, id: string, column: BoardColumn): TrackingEntry;
70
+ /**
71
+ * Patch editable fields on an issue. Materializes a findings.json entry first so
72
+ * description / recommendation / resolution / update_from_client always land on
73
+ * a real record (not just non-manual cards' tracking rows). Title / severity /
74
+ * notes are mirrored on the tracking entry so the board reads current values
75
+ * without re-reading findings.json.
76
+ */
77
+ export declare function patchIssue(outputDir: string, id: string, updates: Record<string, unknown>): Finding;
78
+ export {};
79
+ //# sourceMappingURL=issues.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"issues.d.ts","sourceRoot":"","sources":["../../src/core/issues.ts"],"names":[],"mappings":"AAmBA,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG,UAAU,GAAG,SAAS,GAAG,WAAW,CAAC;AAC7E,MAAM,MAAM,QAAQ,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;AACvE,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,WAAW,GAAG,cAAc,GAAG,WAAW,GAAG,YAAY,CAAC;AAE7F,eAAO,MAAM,eAAe,EAAE,SAAS,QAAQ,EAAkD,CAAC;AAClG,eAAO,MAAM,iBAAiB,EAAE,SAAS,UAAU,EAMlD,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,WAAW,EAAE,MAAM,CAKxD,CAAC;AAEF,2EAA2E;AAC3E,eAAO,MAAM,eAAe,8GAQlB,CAAC;AACX,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AAE7D,UAAU,eAAe;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,QAAQ,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE;QAAE,SAAS,EAAE,eAAe,EAAE,CAAA;KAAE,CAAC;IAC7C,GAAG,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IAC7E,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE;QAAE,cAAc,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AAoCD,wBAAgB,eAAe,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,QAAQ,CAEzD;AACD,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,UAAU,CAE7D;AAmED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CA2B1E;AAID;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,aAAa,CAmC3F;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CACxB,SAAS,EAAE,MAAM,EACjB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,OAAO,CA0CT"}
@@ -0,0 +1,253 @@
1
+ /**
2
+ * Canonical issue-mutation logic, shared by the `hex issue` CLI command and the
3
+ * dashboard's PATCH/move API routes. Pure: depends only on node:fs / node:path
4
+ * and is parameterized by `outputDir` (the project's `.hex/` directory) so it
5
+ * can run from the CLI (resolves outputDir via config) or from the dashboard
6
+ * server runtime (resolves outputDir via process.cwd()).
7
+ *
8
+ * The single source of truth for: materializing a findings.json entry from a
9
+ * source-specific record (conformance / auditagent / github), routing edits
10
+ * between findings.json and tracking.json, and column→status mapping.
11
+ *
12
+ * Deliberately NOT imported across the src/ <-> dashboard/ tree boundary as a
13
+ * dependency chain: it pulls in nothing beyond node builtins, so the dashboard
14
+ * can import it via `experimental.externalDir` without dragging CLI deps
15
+ * (chalk/ora/zod) into the Next.js bundle.
16
+ */
17
+ import fs from 'node:fs';
18
+ import path from 'node:path';
19
+ export const SEVERITY_VALUES = ['Critical', 'High', 'Medium', 'Low', 'Info'];
20
+ export const RESOLUTION_VALUES = [
21
+ 'Fixed',
22
+ 'Mitigated',
23
+ 'Acknowledged',
24
+ 'Not Fixed',
25
+ 'Unresolved',
26
+ ];
27
+ export const COLUMN_TO_STATUS = {
28
+ potential: 'pending_validation',
29
+ verified: 'verified',
30
+ invalid: 'rejected',
31
+ duplicate: 'duplicate',
32
+ };
33
+ /** Fields a user may edit through the board modal or `hex issue patch`. */
34
+ export const EDITABLE_FIELDS = [
35
+ 'title',
36
+ 'severity',
37
+ 'description',
38
+ 'recommendation',
39
+ 'resolution',
40
+ 'update_from_client',
41
+ 'notes',
42
+ ];
43
+ // ─── Low-level IO (atomic, JSON) ────────────────────────────────────
44
+ function readJson(file) {
45
+ try {
46
+ return JSON.parse(fs.readFileSync(file, 'utf-8'));
47
+ }
48
+ catch {
49
+ return null;
50
+ }
51
+ }
52
+ function writeJson(file, data) {
53
+ const dir = path.dirname(file);
54
+ if (!fs.existsSync(dir))
55
+ fs.mkdirSync(dir, { recursive: true });
56
+ const tmp = file + '.tmp';
57
+ fs.writeFileSync(tmp, JSON.stringify(data, null, 2) + '\n', 'utf-8');
58
+ fs.renameSync(tmp, file);
59
+ }
60
+ function loadFindings(outputDir) {
61
+ return readJson(path.join(outputDir, 'findings.json')) ?? { findings: [] };
62
+ }
63
+ function loadTracking(outputDir) {
64
+ return readJson(path.join(outputDir, 'tracking.json')) ?? { findings: [] };
65
+ }
66
+ // ─── Validation ─────────────────────────────────────────────────────
67
+ export function isValidSeverity(v) {
68
+ return typeof v === 'string' && SEVERITY_VALUES.includes(v);
69
+ }
70
+ export function isValidResolution(v) {
71
+ return typeof v === 'string' && RESOLUTION_VALUES.includes(v);
72
+ }
73
+ // ─── Source-specific materialization ────────────────────────────────
74
+ function newEmptyFinding(id, severity) {
75
+ return {
76
+ id,
77
+ title: id,
78
+ severity,
79
+ category: '',
80
+ description: '',
81
+ root_cause: { locations: [] },
82
+ poc: { status: 'not_started', file: null, validation_memo: null },
83
+ recommendation: '',
84
+ references: { external_links: [] },
85
+ created_at: new Date().toISOString(),
86
+ };
87
+ }
88
+ /** Build a findings.json record from a conformance item (`SC-*`). */
89
+ function findingFromConformance(outputDir, id, tracking) {
90
+ const spec = readJson(path.join(outputDir, 'spec-conformance.json'));
91
+ const item = spec?.items?.find((i) => i.id === id);
92
+ if (!item)
93
+ return null;
94
+ const f = newEmptyFinding(id, (tracking?.severity ?? item.severity_hint ?? 'Info'));
95
+ f.title = tracking?.title ?? String(item.spec_text ?? id);
96
+ f.category = 'Spec Conformance';
97
+ f.description = String(item.finding ?? item.spec_text ?? '');
98
+ const loc = item.code_location;
99
+ if (loc?.file)
100
+ f.root_cause.locations = [{ file: loc.file }];
101
+ f.notes = `Materialized from conformance item ${id}`;
102
+ return f;
103
+ }
104
+ /** Build a findings.json record from an ai-results or external/github record. */
105
+ function findingFromAiOrGithub(outputDir, id, kind, tracking) {
106
+ const nested = kind === 'auditagent'
107
+ ? path.join(outputDir, 'ai-results', 'auditagent', 'findings.json')
108
+ : path.join(outputDir, 'external', 'github', 'findings.json');
109
+ const file = readJson(nested);
110
+ const rec = file?.findings?.find((r) => r.id === id);
111
+ if (!rec)
112
+ return null;
113
+ const f = newEmptyFinding(id, rec.severity ?? tracking?.severity ?? 'Info');
114
+ f.title = String(rec.title ?? tracking?.title ?? id);
115
+ f.category = String(rec.category ?? '');
116
+ f.description = String(rec.description ?? '');
117
+ const affected = rec.affected_code ?? [];
118
+ f.root_cause.locations = affected.map((a) => ({ file: a.file, snippet: a.snippet }));
119
+ f.notes = `Materialized from ${kind} finding ${id}`;
120
+ return f;
121
+ }
122
+ /**
123
+ * Ensure a findings.json entry exists for `id`, materializing one from the
124
+ * source-specific record if needed. Idempotent: returns the existing entry
125
+ * untouched when present. Dispatches on id prefix.
126
+ */
127
+ export function ensureFindingExists(outputDir, id) {
128
+ const findings = loadFindings(outputDir);
129
+ const existing = findings.findings.find((f) => f.id === id);
130
+ if (existing)
131
+ return existing;
132
+ const tracking = loadTracking(outputDir).findings.find((t) => t.id === id);
133
+ let materialized = null;
134
+ if (id.startsWith('SC-')) {
135
+ materialized = findingFromConformance(outputDir, id, tracking);
136
+ }
137
+ else if (id.startsWith('AA-')) {
138
+ materialized = findingFromAiOrGithub(outputDir, id, 'auditagent', tracking);
139
+ }
140
+ else if (id.startsWith('github-')) {
141
+ materialized = findingFromAiOrGithub(outputDir, id, 'github', tracking);
142
+ }
143
+ // Fallback: synthesize a minimal record from the tracking entry (covers
144
+ // manual `F*` ids restored from GitHub, or any source record we couldn't read).
145
+ if (!materialized) {
146
+ materialized = newEmptyFinding(id, tracking?.severity ?? 'Info');
147
+ if (tracking?.title)
148
+ materialized.title = tracking.title;
149
+ materialized.notes = tracking ? `Materialized from tracking entry ${id}` : '';
150
+ }
151
+ findings.findings.push(materialized);
152
+ writeJson(path.join(outputDir, 'findings.json'), findings);
153
+ return materialized;
154
+ }
155
+ // ─── Mutations ──────────────────────────────────────────────────────
156
+ /**
157
+ * Move an issue between board columns. Materializes a findings.json entry first
158
+ * (so non-manual cards become reportable when promoted to Verified), then flips
159
+ * the tracking status.
160
+ *
161
+ * Note: this does NOT edit the user's source files. Source annotation
162
+ * (`// @audit-issue-verified ...`) remains the responsibility of the
163
+ * /validate-issue skill, which the auditor invokes deliberately — a drag-drop
164
+ * on the board should never silently rewrite .sol files.
165
+ */
166
+ export function moveIssue(outputDir, id, column) {
167
+ const nextStatus = COLUMN_TO_STATUS[column];
168
+ if (!nextStatus)
169
+ throw new Error(`Invalid column: ${column}`);
170
+ // Promoting to Verified should make the issue reportable.
171
+ if (column === 'verified')
172
+ ensureFindingExists(outputDir, id);
173
+ const tracking = loadTracking(outputDir);
174
+ let entry = tracking.findings.find((t) => t.id === id);
175
+ if (!entry) {
176
+ // The board only surfaces tracking entries, but be defensive: synthesize one
177
+ // from the (now-ensured) finding so a move never 404s on a real card.
178
+ const finding = ensureFindingExists(outputDir, id);
179
+ entry = {
180
+ id,
181
+ title: finding.title,
182
+ severity: finding.severity,
183
+ source: 'manual',
184
+ status: nextStatus,
185
+ poc_status: finding.poc?.status ?? 'not_started',
186
+ poc_file: finding.poc?.file ?? null,
187
+ duplicates: [],
188
+ duplicate_of: null,
189
+ notes: '',
190
+ };
191
+ tracking.findings.push(entry);
192
+ }
193
+ else {
194
+ entry.status = nextStatus;
195
+ }
196
+ // Clear a stale duplicate pointer when the card leaves the Duplicate column.
197
+ if (column !== 'duplicate' && entry.duplicate_of)
198
+ entry.duplicate_of = null;
199
+ writeJson(path.join(outputDir, 'tracking.json'), tracking);
200
+ return entry;
201
+ }
202
+ /**
203
+ * Patch editable fields on an issue. Materializes a findings.json entry first so
204
+ * description / recommendation / resolution / update_from_client always land on
205
+ * a real record (not just non-manual cards' tracking rows). Title / severity /
206
+ * notes are mirrored on the tracking entry so the board reads current values
207
+ * without re-reading findings.json.
208
+ */
209
+ export function patchIssue(outputDir, id, updates) {
210
+ const clean = {};
211
+ for (const key of EDITABLE_FIELDS) {
212
+ if (!(key in updates))
213
+ continue;
214
+ const value = updates[key];
215
+ if (key === 'severity' && value != null && !isValidSeverity(value)) {
216
+ throw new Error(`Invalid severity: ${String(value)}`);
217
+ }
218
+ if (key === 'resolution' && value != null && value !== '' && !isValidResolution(value)) {
219
+ throw new Error(`Invalid resolution: ${String(value)}`);
220
+ }
221
+ clean[key] = value;
222
+ }
223
+ if (Object.keys(clean).length === 0) {
224
+ throw new Error('No editable fields supplied');
225
+ }
226
+ const finding = ensureFindingExists(outputDir, id);
227
+ const findings = loadFindings(outputDir);
228
+ const target = findings.findings.find((f) => f.id === id) ?? finding;
229
+ for (const [key, value] of Object.entries(clean)) {
230
+ if (key === 'notes')
231
+ continue; // notes lives on tracking, not findings
232
+ if (key === 'resolution' && (value === '' || value == null)) {
233
+ delete target.resolution;
234
+ continue;
235
+ }
236
+ target[key] = value;
237
+ }
238
+ writeJson(path.join(outputDir, 'findings.json'), findings);
239
+ // Mirror title / severity / notes onto tracking.
240
+ const tracking = loadTracking(outputDir);
241
+ const entry = tracking.findings.find((t) => t.id === id);
242
+ if (entry) {
243
+ if ('title' in clean)
244
+ entry.title = clean.title;
245
+ if ('severity' in clean)
246
+ entry.severity = clean.severity;
247
+ if ('notes' in clean)
248
+ entry.notes = clean.notes;
249
+ writeJson(path.join(outputDir, 'tracking.json'), tracking);
250
+ }
251
+ return target;
252
+ }
253
+ //# sourceMappingURL=issues.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"issues.js","sourceRoot":"","sources":["../../src/core/issues.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAM7B,MAAM,CAAC,MAAM,eAAe,GAAwB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;AAClG,MAAM,CAAC,MAAM,iBAAiB,GAA0B;IACtD,OAAO;IACP,WAAW;IACX,cAAc;IACd,WAAW;IACX,YAAY;CACb,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAgC;IAC3D,SAAS,EAAE,oBAAoB;IAC/B,QAAQ,EAAE,UAAU;IACpB,OAAO,EAAE,UAAU;IACnB,SAAS,EAAE,WAAW;CACvB,CAAC;AAEF,2EAA2E;AAC3E,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,OAAO;IACP,UAAU;IACV,aAAa;IACb,gBAAgB;IAChB,YAAY;IACZ,oBAAoB;IACpB,OAAO;CACC,CAAC;AA8CX,uEAAuE;AAEvE,SAAS,QAAQ,CAAI,IAAY;IAC/B,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAM,CAAC;IACzD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,SAAS,CAAC,IAAY,EAAE,IAAa;IAC5C,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAChE,MAAM,GAAG,GAAG,IAAI,GAAG,MAAM,CAAC;IAC1B,EAAE,CAAC,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;IACrE,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;AAC3B,CAAC;AAED,SAAS,YAAY,CAAC,SAAiB;IACrC,OAAO,QAAQ,CAAe,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;AAC3F,CAAC;AACD,SAAS,YAAY,CAAC,SAAiB;IACrC,OAAO,QAAQ,CAAe,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;AAC3F,CAAC;AAED,uEAAuE;AAEvE,MAAM,UAAU,eAAe,CAAC,CAAU;IACxC,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAK,eAAqC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACrF,CAAC;AACD,MAAM,UAAU,iBAAiB,CAAC,CAAU;IAC1C,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAK,iBAAuC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACvF,CAAC;AAED,uEAAuE;AAEvE,SAAS,eAAe,CAAC,EAAU,EAAE,QAAkB;IACrD,OAAO;QACL,EAAE;QACF,KAAK,EAAE,EAAE;QACT,QAAQ;QACR,QAAQ,EAAE,EAAE;QACZ,WAAW,EAAE,EAAE;QACf,UAAU,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE;QAC7B,GAAG,EAAE,EAAE,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE;QACjE,cAAc,EAAE,EAAE;QAClB,UAAU,EAAE,EAAE,cAAc,EAAE,EAAE,EAAE;QAClC,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACrC,CAAC;AACJ,CAAC;AAED,qEAAqE;AACrE,SAAS,sBAAsB,CAC7B,SAAiB,EACjB,EAAU,EACV,QAAwB;IAExB,MAAM,IAAI,GAAG,QAAQ,CACnB,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,uBAAuB,CAAC,CAC9C,CAAC;IACF,MAAM,IAAI,GAAG,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;IACnD,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACvB,MAAM,CAAC,GAAG,eAAe,CACvB,EAAE,EACF,CAAC,QAAQ,EAAE,QAAQ,IAAK,IAAI,CAAC,aAA0B,IAAI,MAAM,CAAa,CAC/E,CAAC;IACF,CAAC,CAAC,KAAK,GAAG,QAAQ,EAAE,KAAK,IAAI,MAAM,CAAC,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC;IAC1D,CAAC,CAAC,QAAQ,GAAG,kBAAkB,CAAC;IAChC,CAAC,CAAC,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC;IAC7D,MAAM,GAAG,GAAG,IAAI,CAAC,aAA8C,CAAC;IAChE,IAAI,GAAG,EAAE,IAAI;QAAE,CAAC,CAAC,UAAU,CAAC,SAAS,GAAG,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;IAC7D,CAAC,CAAC,KAAK,GAAG,sCAAsC,EAAE,EAAE,CAAC;IACrD,OAAO,CAAC,CAAC;AACX,CAAC;AAED,iFAAiF;AACjF,SAAS,qBAAqB,CAC5B,SAAiB,EACjB,EAAU,EACV,IAA6B,EAC7B,QAAwB;IAExB,MAAM,MAAM,GACV,IAAI,KAAK,YAAY;QACnB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,EAAE,YAAY,EAAE,eAAe,CAAC;QACnE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,eAAe,CAAC,CAAC;IAClE,MAAM,IAAI,GAAG,QAAQ,CAAgD,MAAM,CAAC,CAAC;IAC7E,MAAM,GAAG,GAAG,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;IACrD,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,MAAM,CAAC,GAAG,eAAe,CAAC,EAAE,EAAG,GAAG,CAAC,QAAqB,IAAI,QAAQ,EAAE,QAAQ,IAAI,MAAM,CAAC,CAAC;IAC1F,CAAC,CAAC,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,IAAI,QAAQ,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;IACrD,CAAC,CAAC,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;IACxC,CAAC,CAAC,WAAW,GAAG,MAAM,CAAC,GAAG,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC;IAC9C,MAAM,QAAQ,GAAI,GAAG,CAAC,aAA2D,IAAI,EAAE,CAAC;IACxF,CAAC,CAAC,UAAU,CAAC,SAAS,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IACrF,CAAC,CAAC,KAAK,GAAG,qBAAqB,IAAI,YAAY,EAAE,EAAE,CAAC;IACpD,OAAO,CAAC,CAAC;AACX,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,SAAiB,EAAE,EAAU;IAC/D,MAAM,QAAQ,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC;IACzC,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;IAC5D,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAE9B,MAAM,QAAQ,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;IAE3E,IAAI,YAAY,GAAmB,IAAI,CAAC;IACxC,IAAI,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,YAAY,GAAG,sBAAsB,CAAC,SAAS,EAAE,EAAE,EAAE,QAAQ,CAAC,CAAC;IACjE,CAAC;SAAM,IAAI,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QAChC,YAAY,GAAG,qBAAqB,CAAC,SAAS,EAAE,EAAE,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC;IAC9E,CAAC;SAAM,IAAI,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QACpC,YAAY,GAAG,qBAAqB,CAAC,SAAS,EAAE,EAAE,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC1E,CAAC;IAED,wEAAwE;IACxE,gFAAgF;IAChF,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,YAAY,GAAG,eAAe,CAAC,EAAE,EAAE,QAAQ,EAAE,QAAQ,IAAI,MAAM,CAAC,CAAC;QACjE,IAAI,QAAQ,EAAE,KAAK;YAAE,YAAY,CAAC,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC;QACzD,YAAY,CAAC,KAAK,GAAG,QAAQ,CAAC,CAAC,CAAC,oCAAoC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAChF,CAAC;IAED,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACrC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,eAAe,CAAC,EAAE,QAAQ,CAAC,CAAC;IAC3D,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,uEAAuE;AAEvE;;;;;;;;;GASG;AACH,MAAM,UAAU,SAAS,CAAC,SAAiB,EAAE,EAAU,EAAE,MAAmB;IAC1E,MAAM,UAAU,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAC5C,IAAI,CAAC,UAAU;QAAE,MAAM,IAAI,KAAK,CAAC,mBAAmB,MAAM,EAAE,CAAC,CAAC;IAE9D,0DAA0D;IAC1D,IAAI,MAAM,KAAK,UAAU;QAAE,mBAAmB,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IAE9D,MAAM,QAAQ,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC;IACzC,IAAI,KAAK,GAAG,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;IACvD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,6EAA6E;QAC7E,sEAAsE;QACtE,MAAM,OAAO,GAAG,mBAAmB,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;QACnD,KAAK,GAAG;YACN,EAAE;YACF,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,MAAM,EAAE,QAAQ;YAChB,MAAM,EAAE,UAAU;YAClB,UAAU,EAAE,OAAO,CAAC,GAAG,EAAE,MAAM,IAAI,aAAa;YAChD,QAAQ,EAAE,OAAO,CAAC,GAAG,EAAE,IAAI,IAAI,IAAI;YACnC,UAAU,EAAE,EAAE;YACd,YAAY,EAAE,IAAI;YAClB,KAAK,EAAE,EAAE;SACV,CAAC;QACF,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAChC,CAAC;SAAM,CAAC;QACN,KAAK,CAAC,MAAM,GAAG,UAAU,CAAC;IAC5B,CAAC;IAED,6EAA6E;IAC7E,IAAI,MAAM,KAAK,WAAW,IAAI,KAAK,CAAC,YAAY;QAAE,KAAK,CAAC,YAAY,GAAG,IAAI,CAAC;IAE5E,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,eAAe,CAAC,EAAE,QAAQ,CAAC,CAAC;IAC3D,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CACxB,SAAiB,EACjB,EAAU,EACV,OAAgC;IAEhC,MAAM,KAAK,GAA4C,EAAE,CAAC;IAC1D,KAAK,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;QAClC,IAAI,CAAC,CAAC,GAAG,IAAI,OAAO,CAAC;YAAE,SAAS;QAChC,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QAC3B,IAAI,GAAG,KAAK,UAAU,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,EAAE,CAAC;YACnE,MAAM,IAAI,KAAK,CAAC,qBAAqB,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACxD,CAAC;QACD,IAAI,GAAG,KAAK,YAAY,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,KAAK,EAAE,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,EAAE,CAAC;YACvF,MAAM,IAAI,KAAK,CAAC,uBAAuB,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC1D,CAAC;QACD,KAAK,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IACrB,CAAC;IACD,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACpC,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;IACjD,CAAC;IAED,MAAM,OAAO,GAAG,mBAAmB,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IACnD,MAAM,QAAQ,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC;IACzC,MAAM,MAAM,GAAG,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,IAAI,OAAO,CAAC;IAErE,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACjD,IAAI,GAAG,KAAK,OAAO;YAAE,SAAS,CAAC,wCAAwC;QACvE,IAAI,GAAG,KAAK,YAAY,IAAI,CAAC,KAAK,KAAK,EAAE,IAAI,KAAK,IAAI,IAAI,CAAC,EAAE,CAAC;YAC5D,OAAO,MAAM,CAAC,UAAU,CAAC;YACzB,SAAS;QACX,CAAC;QACA,MAAkC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IACnD,CAAC;IACD,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,eAAe,CAAC,EAAE,QAAQ,CAAC,CAAC;IAE3D,iDAAiD;IACjD,MAAM,QAAQ,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC;IACzC,MAAM,KAAK,GAAG,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;IACzD,IAAI,KAAK,EAAE,CAAC;QACV,IAAI,OAAO,IAAI,KAAK;YAAE,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,KAAe,CAAC;QAC1D,IAAI,UAAU,IAAI,KAAK;YAAE,KAAK,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAoB,CAAC;QACrE,IAAI,OAAO,IAAI,KAAK;YAAE,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,KAAe,CAAC;QAC1D,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,eAAe,CAAC,EAAE,QAAQ,CAAC,CAAC;IAC7D,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
package/dist/index.js CHANGED
@@ -17,11 +17,12 @@ import { analyzeCommand } from './commands/analyze.js';
17
17
  import { doctorCommand } from './commands/doctor.js';
18
18
  import { aiStatusCommand } from './commands/ai-status.js';
19
19
  import { updateCommand } from './commands/update.js';
20
+ import { issueCommand } from './commands/issue.js';
20
21
  const program = new Command();
21
22
  program
22
23
  .name('hex')
23
24
  .description('CLI toolkit for Solidity smart contract auditors')
24
- .version('0.4.4');
25
+ .version('0.4.5');
25
26
  program.addCommand(initCommand);
26
27
  program.addCommand(statsCommand);
27
28
  program.addCommand(depsCommand);
@@ -39,5 +40,6 @@ program.addCommand(analyzeCommand);
39
40
  program.addCommand(doctorCommand);
40
41
  program.addCommand(aiStatusCommand);
41
42
  program.addCommand(updateCommand);
43
+ program.addCommand(issueCommand);
42
44
  program.parse();
43
45
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,KAAK,CAAC;KACX,WAAW,CAAC,kDAAkD,CAAC;KAC/D,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;AAChC,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;AACjC,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;AAChC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;AACjC,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;AACjC,OAAO,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC;AACpC,OAAO,CAAC,UAAU,CAAC,kBAAkB,CAAC,CAAC;AACvC,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;AACnC,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;AACnC,OAAO,CAAC,UAAU,CAAC,mBAAmB,CAAC,CAAC;AACxC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;AACrC,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;AACnC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC;AACpC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;AAElC,OAAO,CAAC,KAAK,EAAE,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,KAAK,CAAC;KACX,WAAW,CAAC,kDAAkD,CAAC;KAC/D,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;AAChC,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;AACjC,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;AAChC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;AACjC,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;AACjC,OAAO,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC;AACpC,OAAO,CAAC,UAAU,CAAC,kBAAkB,CAAC,CAAC;AACvC,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;AACnC,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;AACnC,OAAO,CAAC,UAAU,CAAC,mBAAmB,CAAC,CAAC;AACxC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;AACrC,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;AACnC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC;AACpC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;AAEjC,OAAO,CAAC,KAAK,EAAE,CAAC"}
@@ -236,7 +236,9 @@ Also write a human-readable `.hex/spec-conformance.md` rendering the same data g
236
236
 
237
237
  ## Phase 6 — Materialize conformance items onto the board
238
238
 
239
- For every item in `spec-conformance.json.items` with `status` of `DEVIATES` or `PARTIAL`, append a tracking entry to `.hex/tracking.json` (creating the file if missing). Schema:
239
+ For every item in `spec-conformance.json.items` with `status` of `DEVIATES` or `PARTIAL`, append a tracking entry to `.hex/tracking.json`.
240
+
241
+ **Wrapper (required):** `.hex/tracking.json` MUST be `{ "findings": [<TrackingEntry>, ...] }`. The wrapper key is `findings` (NOT `issues`) — the dashboard's `TrackingFile` type and the `/api/issues` routes reject any other shape. If the file does not exist, create it as `{ "findings": [] }` and then append. If it exists, parse it, append to the `findings` array, and write it back. Match the per-entry schema below exactly.
240
242
 
241
243
  ```json
242
244
  {
@@ -156,61 +156,44 @@ Within candidates:
156
156
  - Has `github.issue_number` → update via `gh issue edit`.
157
157
  - No `github.issue_number` → create via `gh issue create`.
158
158
 
159
- **3b. Render the body** (write to a temp file, then `--body-file`):
159
+ **3b. Render the body** (write to a temp file, then `--body-file`). Use this exact template — nothing more, nothing less in the visible body. It mirrors `dashboard/lib/finding-markdown.ts::findingToGithubBody`, so the board's "Copy as HackMD" output and the pushed issue stay identical:
160
160
 
161
161
  ```markdown
162
- **Severity:** <Severity>
162
+ **File(s)**: [`<file>`](<github-blob-url-or-empty>)
163
163
 
164
- <finding.description>
164
+ **Description**: <finding.description>
165
165
 
166
- ### Affected code
166
+ **Recommendation(s)**: <finding.recommendation>
167
167
 
168
- <for each finding.root_cause.locations[]>
169
- **`<location.file>`**
168
+ **Status**: <finding.resolution or "Unresolved">
170
169
 
171
- ```solidity
172
- <location.snippet>
173
- ```
174
- </for>
175
-
176
- ### Recommendation
177
-
178
- <finding.recommendation>
179
-
180
- ---
181
-
182
- *Synced from Hex audit `<config.project.name>` at commit `<config.project.commit>`.*
170
+ **Update from the client**: <finding.update_from_client or empty>
183
171
 
184
172
  <!-- hex-finding-id: <finding.id> -->
185
173
  ```
186
174
 
187
- The footer is the round-trip identity key — never omit.
188
-
189
- **3c. Labels.**
190
-
191
- ```
192
- <default_labels...> severity:<lowercased> source:<finding.source or 'manual'> status:<tracking.status>
193
- ```
194
-
195
- Apply via repeated `--label` flags.
175
+ Rules:
176
+ - **File(s)** — one markdown link per affected file in `root_cause.locations[]`, comma-separated when there is more than one: `` [`src/Vault.sol`](url1), [`src/MockToken.sol`](url2) ``. Build each URL as `<settings.report.repository_url>/blob/<settings.report.initial_commit>/<file>`. If either `repository_url` or `initial_commit` is missing from `config.json`, use an empty link target: `` [`<file>`]() ``.
177
+ - **Status** — the finding's `resolution` field if set, otherwise the literal `Unresolved`.
178
+ - **Update from the client** — the finding's `update_from_client` field if set, otherwise leave it blank after the colon.
179
+ - Do NOT add a `**Severity:**` line (severity is already in the title), an `### Affected code` section, code blocks, or a "Synced from Hex" attribution line.
180
+ - The `<!-- hex-finding-id: <finding.id> -->` HTML comment at the very bottom is **mandatory and load-bearing** — it is the round-trip dedup key, invisible in GitHub's rendered view. Never omit it.
196
181
 
197
- **3d. Create or update.**
182
+ **3c. Create or update — no labels.** Hex does not apply, add, or remove labels. The target repo's label set is the repo owner's concern; assuming labels exist (e.g. `severity:critical`) makes `gh issue create` fail when they don't.
198
183
 
199
184
  Create:
200
185
  ```bash
201
- gh issue create --repo <repo> --title "[<Severity>] <title>" --body-file <tmp> \
202
- --label "hex" --label "audit" --label "severity:..." --label "source:..." --label "status:..."
186
+ gh issue create --repo <repo> --title "[<Severity>] <title>" --body-file <tmp>
203
187
  ```
204
188
 
205
189
  Parse the returned URL to extract the issue number; update the local finding's `github` block.
206
190
 
207
191
  Update existing:
208
192
  ```bash
209
- gh issue edit <num> --repo <repo> --title "[<Severity>] <title>" --body-file <tmp> \
210
- --add-label "severity:..." --add-label "status:..."
193
+ gh issue edit <num> --repo <repo> --title "[<Severity>] <title>" --body-file <tmp>
211
194
  ```
212
195
 
213
- Do NOT `--remove-label` — teammates may have added labels we shouldn't strip.
196
+ (`settings.github.default_labels` in config is retained for backwards compatibility but is no longer applied.)
214
197
 
215
198
  If push fails for any single finding: capture stderr, set its `github.sync_status` to `conflict`, append a one-line error, continue with the next finding. Never abort the whole sync on one failure.
216
199
 
@@ -261,6 +244,6 @@ GitHub sync complete (<repo>)
261
244
 
262
245
  - Does not authenticate (use `gh auth login` once).
263
246
  - Does not post comments (auditors discuss inside GitHub).
264
- - Does not create labels (manual one-time setup; `gh issue create` errors if a label is missing).
247
+ - Does not apply, create, or remove labels (the repo owner manages its own labels).
265
248
  - Does not delete remote issues.
266
249
  - Does not push `rejected`, `unverified`, or `duplicate` findings.