friction-log 0.0.0-stage → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/LICENSE +21 -0
  3. package/README.md +98 -2
  4. package/dist/cli.d.ts +2 -0
  5. package/dist/cli.js +504 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/commands/bilanz.d.ts +23 -0
  8. package/dist/commands/bilanz.js +106 -0
  9. package/dist/commands/bilanz.js.map +1 -0
  10. package/dist/commands/digest.d.ts +36 -0
  11. package/dist/commands/digest.js +288 -0
  12. package/dist/commands/digest.js.map +1 -0
  13. package/dist/commands/export.d.ts +36 -0
  14. package/dist/commands/export.js +118 -0
  15. package/dist/commands/export.js.map +1 -0
  16. package/dist/commands/file.d.ts +18 -0
  17. package/dist/commands/file.js +51 -0
  18. package/dist/commands/file.js.map +1 -0
  19. package/dist/commands/import.d.ts +31 -0
  20. package/dist/commands/import.js +283 -0
  21. package/dist/commands/import.js.map +1 -0
  22. package/dist/commands/init.d.ts +44 -0
  23. package/dist/commands/init.js +256 -0
  24. package/dist/commands/init.js.map +1 -0
  25. package/dist/commands/list.d.ts +16 -0
  26. package/dist/commands/list.js +57 -0
  27. package/dist/commands/list.js.map +1 -0
  28. package/dist/commands/log.d.ts +18 -0
  29. package/dist/commands/log.js +52 -0
  30. package/dist/commands/log.js.map +1 -0
  31. package/dist/commands/rm.d.ts +9 -0
  32. package/dist/commands/rm.js +22 -0
  33. package/dist/commands/rm.js.map +1 -0
  34. package/dist/commands/scan.d.ts +25 -0
  35. package/dist/commands/scan.js +73 -0
  36. package/dist/commands/scan.js.map +1 -0
  37. package/dist/commands/search.d.ts +15 -0
  38. package/dist/commands/search.js +37 -0
  39. package/dist/commands/search.js.map +1 -0
  40. package/dist/commands/sync-export.d.ts +46 -0
  41. package/dist/commands/sync-export.js +80 -0
  42. package/dist/commands/sync-export.js.map +1 -0
  43. package/dist/commands/update.d.ts +12 -0
  44. package/dist/commands/update.js +24 -0
  45. package/dist/commands/update.js.map +1 -0
  46. package/dist/config.d.ts +31 -0
  47. package/dist/config.js +145 -0
  48. package/dist/config.js.map +1 -0
  49. package/dist/db.d.ts +81 -0
  50. package/dist/db.js +548 -0
  51. package/dist/db.js.map +1 -0
  52. package/dist/index.d.ts +15 -0
  53. package/dist/index.js +16 -0
  54. package/dist/index.js.map +1 -0
  55. package/dist/paths.d.ts +12 -0
  56. package/dist/paths.js +34 -0
  57. package/dist/paths.js.map +1 -0
  58. package/dist/scanners/claude-code.d.ts +6 -0
  59. package/dist/scanners/claude-code.js +202 -0
  60. package/dist/scanners/claude-code.js.map +1 -0
  61. package/dist/scanners/index.d.ts +4 -0
  62. package/dist/scanners/index.js +12 -0
  63. package/dist/scanners/index.js.map +1 -0
  64. package/dist/sinks/agent-tasks.d.ts +36 -0
  65. package/dist/sinks/agent-tasks.js +153 -0
  66. package/dist/sinks/agent-tasks.js.map +1 -0
  67. package/dist/sinks/github-issues.d.ts +20 -0
  68. package/dist/sinks/github-issues.js +98 -0
  69. package/dist/sinks/github-issues.js.map +1 -0
  70. package/dist/sinks/index.d.ts +11 -0
  71. package/dist/sinks/index.js +48 -0
  72. package/dist/sinks/index.js.map +1 -0
  73. package/dist/sinks/linear.d.ts +25 -0
  74. package/dist/sinks/linear.js +157 -0
  75. package/dist/sinks/linear.js.map +1 -0
  76. package/dist/sinks/markdown-file.d.ts +7 -0
  77. package/dist/sinks/markdown-file.js +54 -0
  78. package/dist/sinks/markdown-file.js.map +1 -0
  79. package/dist/sinks/stdout-json.d.ts +15 -0
  80. package/dist/sinks/stdout-json.js +49 -0
  81. package/dist/sinks/stdout-json.js.map +1 -0
  82. package/dist/templates/auth-expiry.yml +30 -0
  83. package/dist/templates/doc-gap.yml +30 -0
  84. package/dist/templates/output-overflow.yml +25 -0
  85. package/dist/templates/schema-drift.yml +26 -0
  86. package/dist/templates/tool-error.yml +34 -0
  87. package/dist/templates/tool-missing-capability.yml +26 -0
  88. package/dist/templates/workflow-friction.yml +26 -0
  89. package/dist/templates.d.ts +5 -0
  90. package/dist/templates.js +88 -0
  91. package/dist/templates.js.map +1 -0
  92. package/dist/types.d.ts +79 -0
  93. package/dist/types.js +2 -0
  94. package/dist/types.js.map +1 -0
  95. package/docs/commands.md +74 -0
  96. package/docs/design.md +25 -0
  97. package/docs/sinks.md +79 -0
  98. package/docs/storage.md +20 -0
  99. package/docs/sync-export.md +23 -0
  100. package/package.json +64 -4
  101. package/templates/auth-expiry.yml +30 -0
  102. package/templates/doc-gap.yml +30 -0
  103. package/templates/output-overflow.yml +25 -0
  104. package/templates/schema-drift.yml +26 -0
  105. package/templates/tool-error.yml +34 -0
  106. package/templates/tool-missing-capability.yml +26 -0
  107. package/templates/workflow-friction.yml +26 -0
@@ -0,0 +1,118 @@
1
+ import { writeFileSync } from "node:fs";
2
+ import { FrictionDb } from "../db.js";
3
+ import { defaultDbPath } from "../paths.js";
4
+ import { parseAge } from "./list.js";
5
+ export function runExport(input) {
6
+ const db = new FrictionDb(input.dbPath ?? defaultDbPath());
7
+ try {
8
+ const filter = {
9
+ status: input.status,
10
+ tool: input.tool,
11
+ category: input.category,
12
+ source: input.source,
13
+ sinceIso: parseAge(input.age),
14
+ limit: input.limit,
15
+ };
16
+ const frictions = input.query && input.query.trim()
17
+ ? db.searchFrictions(input.query, filter)
18
+ : db.listFrictions(filter);
19
+ const records = frictions.map((f) => ({
20
+ ...frictionToExport(f),
21
+ tags: db.tagsFor(f.id),
22
+ }));
23
+ const rendered = render(input.format, records);
24
+ if (input.out) {
25
+ writeFileSync(input.out, rendered, "utf8");
26
+ }
27
+ return {
28
+ format: input.format,
29
+ rendered,
30
+ out: input.out ?? null,
31
+ count: records.length,
32
+ };
33
+ }
34
+ finally {
35
+ db.close();
36
+ }
37
+ }
38
+ export function frictionToExport(f) {
39
+ return {
40
+ id: f.id,
41
+ sessionId: f.sessionId,
42
+ toolSurface: f.toolSurface,
43
+ title: f.title,
44
+ description: f.description,
45
+ capturedAt: f.capturedAt,
46
+ severity: f.severity,
47
+ category: f.category,
48
+ status: f.status,
49
+ recurrenceOfId: f.recurrenceOfId,
50
+ source: f.source,
51
+ };
52
+ }
53
+ function render(format, records) {
54
+ if (format === "json")
55
+ return JSON.stringify(records, null, 2) + "\n";
56
+ if (format === "csv")
57
+ return renderCsv(records);
58
+ return renderMarkdown(records);
59
+ }
60
+ const CSV_COLUMNS = [
61
+ "id",
62
+ "sessionId",
63
+ "toolSurface",
64
+ "title",
65
+ "description",
66
+ "capturedAt",
67
+ "severity",
68
+ "category",
69
+ "status",
70
+ "recurrenceOfId",
71
+ "source",
72
+ "tags",
73
+ ];
74
+ function renderCsv(records) {
75
+ const header = CSV_COLUMNS.join(",");
76
+ const rows = records.map((r) => CSV_COLUMNS.map((c) => csvCell(r[c])).join(","));
77
+ return [header, ...rows].join("\n") + "\n";
78
+ }
79
+ function csvCell(v) {
80
+ if (v === null || v === undefined)
81
+ return "";
82
+ const s = Array.isArray(v) ? v.join("|") : String(v);
83
+ if (/[",\n\r]/.test(s)) {
84
+ return `"${s.replace(/"/g, '""')}"`;
85
+ }
86
+ return s;
87
+ }
88
+ function renderMarkdown(records) {
89
+ if (records.length === 0)
90
+ return "_no frictions match the filter_\n";
91
+ const parts = [
92
+ `# friction-log export (${records.length} records)`,
93
+ "",
94
+ ];
95
+ for (const r of records) {
96
+ parts.push(`## #${r.id}: ${r.title}`);
97
+ parts.push("");
98
+ parts.push(`- captured: \`${r.capturedAt}\``);
99
+ parts.push(`- status: ${r.status} source: ${r.source}`);
100
+ if (r.toolSurface)
101
+ parts.push(`- tool: \`${r.toolSurface}\``);
102
+ if (r.category)
103
+ parts.push(`- category: ${r.category}`);
104
+ if (r.severity)
105
+ parts.push(`- severity: ${r.severity}`);
106
+ if (r.recurrenceOfId != null)
107
+ parts.push(`- recurrence-of: #${r.recurrenceOfId}`);
108
+ if (r.tags.length)
109
+ parts.push(`- tags: ${r.tags.join(", ")}`);
110
+ if (r.description) {
111
+ parts.push("");
112
+ parts.push(r.description);
113
+ }
114
+ parts.push("");
115
+ }
116
+ return parts.join("\n");
117
+ }
118
+ //# sourceMappingURL=export.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"export.js","sourceRoot":"","sources":["../../src/commands/export.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import { type SinkConfig } from "../config.js";
2
+ export interface FileCommandInput {
3
+ frictionId: number;
4
+ sink?: string;
5
+ template?: string;
6
+ sinkTarget?: string;
7
+ sinkOpts?: SinkConfig;
8
+ configPath?: string;
9
+ dbPath?: string;
10
+ }
11
+ export interface FileCommandOutput {
12
+ taskId: number;
13
+ sinkName: string;
14
+ sinkTarget: string;
15
+ externalRef?: string;
16
+ message: string;
17
+ }
18
+ export declare function runFile(input: FileCommandInput): Promise<FileCommandOutput>;
@@ -0,0 +1,51 @@
1
+ import { loadConfig, mergeSinkOpts } from "../config.js";
2
+ import { FrictionDb } from "../db.js";
3
+ import { defaultDbPath } from "../paths.js";
4
+ import { loadSink } from "../sinks/index.js";
5
+ import { maybeSyncExport } from "./sync-export.js";
6
+ import { loadTemplate, pickTemplateForCategory, render } from "../templates.js";
7
+ export async function runFile(input) {
8
+ const dbPath = input.dbPath ?? defaultDbPath();
9
+ const db = new FrictionDb(dbPath);
10
+ try {
11
+ const friction = db.getFriction(input.frictionId);
12
+ if (!friction) {
13
+ throw new Error(`friction-log: friction id=${input.frictionId} not found`);
14
+ }
15
+ const sinkName = input.sink ?? "markdown-file";
16
+ const sink = await loadSink(sinkName);
17
+ const templateName = input.template ?? pickTemplateForCategory(friction.category);
18
+ const template = loadTemplate(templateName);
19
+ const rendered = render(template, friction);
20
+ // Merge per-sink config-file defaults with CLI overrides. CLI wins.
21
+ const config = loadConfig(input.configPath);
22
+ const mergedSinkOpts = mergeSinkOpts(config.sinks[sinkName], input.sinkOpts);
23
+ const result = await sink.file(friction, rendered, {
24
+ sinkTarget: input.sinkTarget,
25
+ sinkOpts: mergedSinkOpts,
26
+ });
27
+ if (!result.ok) {
28
+ throw new Error(`friction-log: sink "${sinkName}" failed: ${result.message ?? "unknown error"}`);
29
+ }
30
+ const task = db.insertTask({
31
+ frictionId: friction.id,
32
+ sinkName,
33
+ sinkTarget: result.sinkTarget,
34
+ externalRef: result.externalRef ?? null,
35
+ prUrl: result.prUrl ?? null,
36
+ });
37
+ db.updateFrictionStatus(friction.id, "filed");
38
+ maybeSyncExport({ dbPath, config });
39
+ return {
40
+ taskId: task.id,
41
+ sinkName,
42
+ sinkTarget: result.sinkTarget,
43
+ externalRef: result.externalRef,
44
+ message: result.message ?? "filed",
45
+ };
46
+ }
47
+ finally {
48
+ db.close();
49
+ }
50
+ }
51
+ //# sourceMappingURL=file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file.js","sourceRoot":"","sources":["../../src/commands/file.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,aAAa,EAAmB,MAAM,cAAc,CAAC;AAC1E,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,uBAAuB,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAoBhF,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,KAAuB;IAEvB,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,IAAI,aAAa,EAAE,CAAC;IAC/C,MAAM,EAAE,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;IAClC,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAClD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,CACb,6BAA6B,KAAK,CAAC,UAAU,YAAY,CAC1D,CAAC;QACJ,CAAC;QACD,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,IAAI,eAAe,CAAC;QAC/C,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACtC,MAAM,YAAY,GAChB,KAAK,CAAC,QAAQ,IAAI,uBAAuB,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAC/D,MAAM,QAAQ,GAAG,YAAY,CAAC,YAAY,CAAC,CAAC;QAC5C,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAC5C,oEAAoE;QACpE,MAAM,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAC5C,MAAM,cAAc,GAAG,aAAa,CAClC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,EACtB,KAAK,CAAC,QAAQ,CACf,CAAC;QACF,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,EAAE;YACjD,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,QAAQ,EAAE,cAAc;SACzB,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CACb,uBAAuB,QAAQ,aAAa,MAAM,CAAC,OAAO,IAAI,eAAe,EAAE,CAChF,CAAC;QACJ,CAAC;QACD,MAAM,IAAI,GAAG,EAAE,CAAC,UAAU,CAAC;YACzB,UAAU,EAAE,QAAQ,CAAC,EAAE;YACvB,QAAQ;YACR,UAAU,EAAE,MAAM,CAAC,UAAU;YAC7B,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,IAAI;YACvC,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,IAAI;SAC5B,CAAC,CAAC;QACH,EAAE,CAAC,oBAAoB,CAAC,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QAC9C,eAAe,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;QACpC,OAAO;YACL,MAAM,EAAE,IAAI,CAAC,EAAE;YACf,QAAQ;YACR,UAAU,EAAE,MAAM,CAAC,UAAU;YAC7B,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,OAAO;SACnC,CAAC;IACJ,CAAC;YAAS,CAAC;QACT,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC;AACH,CAAC"}
@@ -0,0 +1,31 @@
1
+ import type { Severity } from "../types.js";
2
+ export type ImportFormat = "markdown-frontmatter";
3
+ export interface ImportCommandInput {
4
+ format: ImportFormat;
5
+ path: string;
6
+ dbPath?: string;
7
+ configPath?: string;
8
+ }
9
+ export interface ImportCommandOutput {
10
+ scanned: number;
11
+ imported: number;
12
+ skipped: number;
13
+ errors: Array<{
14
+ file: string;
15
+ reason: string;
16
+ }>;
17
+ }
18
+ export declare function runImport(input: ImportCommandInput): ImportCommandOutput;
19
+ interface ParsedRecord {
20
+ title: string;
21
+ description: string | null;
22
+ toolSurface: string | null;
23
+ category: string | null;
24
+ severity: Severity | null;
25
+ sessionId: string | null;
26
+ capturedAt: string | undefined;
27
+ extraTags: string[];
28
+ }
29
+ export declare function parseMarkdownFile(file: string): ParsedRecord | null;
30
+ export declare function parseMarkdownContent(raw: string): ParsedRecord | null;
31
+ export {};
@@ -0,0 +1,283 @@
1
+ import { createHash } from "node:crypto";
2
+ import { readFileSync, readdirSync, statSync } from "node:fs";
3
+ import { join, relative } from "node:path";
4
+ import { parse as parseYaml } from "yaml";
5
+ import { FrictionDb } from "../db.js";
6
+ import { defaultDbPath } from "../paths.js";
7
+ import { maybeSyncExport } from "./sync-export.js";
8
+ const SEVERITY_VALUES = [
9
+ "low",
10
+ "medium",
11
+ "high",
12
+ "critical",
13
+ ];
14
+ export function runImport(input) {
15
+ if (input.format !== "markdown-frontmatter") {
16
+ throw new Error(`friction-log: import format "${input.format}" is not supported in M5`);
17
+ }
18
+ const files = walkMarkdown(input.path);
19
+ const dbPath = input.dbPath ?? defaultDbPath();
20
+ const db = new FrictionDb(dbPath);
21
+ let imported = 0;
22
+ let skipped = 0;
23
+ const errors = [];
24
+ try {
25
+ // Build the set of known import-hashes up front so dedup is O(1) per
26
+ // file instead of O(existing) per file.
27
+ const knownHashes = new Set();
28
+ for (const existing of db.listFrictions({
29
+ source: "import",
30
+ limit: 100_000,
31
+ })) {
32
+ for (const tag of db.tagsFor(existing.id)) {
33
+ if (tag.startsWith("import-hash:"))
34
+ knownHashes.add(tag.slice("import-hash:".length));
35
+ }
36
+ }
37
+ for (const file of files) {
38
+ try {
39
+ const parsed = parseMarkdownFile(file);
40
+ if (!parsed) {
41
+ skipped++;
42
+ continue;
43
+ }
44
+ const tagFingerprint = hashFor(parsed);
45
+ if (knownHashes.has(tagFingerprint)) {
46
+ skipped++;
47
+ continue;
48
+ }
49
+ const insert = {
50
+ title: parsed.title,
51
+ description: parsed.description,
52
+ toolSurface: parsed.toolSurface,
53
+ category: parsed.category,
54
+ severity: parsed.severity,
55
+ sessionId: parsed.sessionId,
56
+ capturedAt: parsed.capturedAt,
57
+ source: "import",
58
+ };
59
+ const friction = db.insertFriction(insert);
60
+ db.addTag(friction.id, `imported-from:${relative(input.path, file)}`);
61
+ db.addTag(friction.id, `import-hash:${tagFingerprint}`);
62
+ for (const extra of parsed.extraTags) {
63
+ db.addTag(friction.id, extra);
64
+ }
65
+ knownHashes.add(tagFingerprint);
66
+ imported++;
67
+ }
68
+ catch (err) {
69
+ errors.push({ file, reason: err.message });
70
+ }
71
+ }
72
+ // Skip write-through when nothing was actually imported (e.g. a full
73
+ // re-run of an already-imported directory, all deduped).
74
+ if (imported > 0) {
75
+ maybeSyncExport({ dbPath, configPath: input.configPath });
76
+ }
77
+ }
78
+ finally {
79
+ db.close();
80
+ }
81
+ return { scanned: files.length, imported, skipped, errors };
82
+ }
83
+ function walkMarkdown(root) {
84
+ const out = [];
85
+ function visit(dir) {
86
+ let entries;
87
+ try {
88
+ entries = readdirSync(dir);
89
+ }
90
+ catch {
91
+ return;
92
+ }
93
+ for (const name of entries) {
94
+ if (name.startsWith("."))
95
+ continue;
96
+ const full = join(dir, name);
97
+ let st;
98
+ try {
99
+ st = statSync(full);
100
+ }
101
+ catch {
102
+ continue;
103
+ }
104
+ if (st.isDirectory()) {
105
+ visit(full);
106
+ }
107
+ else if (st.isFile() &&
108
+ (name.endsWith(".md") || name.endsWith(".markdown"))) {
109
+ out.push(full);
110
+ }
111
+ }
112
+ }
113
+ let rootStat;
114
+ try {
115
+ rootStat = statSync(root);
116
+ }
117
+ catch {
118
+ throw new Error(`friction-log: import path does not exist: ${root}`);
119
+ }
120
+ if (rootStat.isFile()) {
121
+ out.push(root);
122
+ }
123
+ else {
124
+ visit(root);
125
+ }
126
+ return out;
127
+ }
128
+ const FRONTMATTER_PATTERN = /^---\s*\n([\s\S]*?)\n---\s*\n?/;
129
+ export function parseMarkdownFile(file) {
130
+ const raw = readFileSync(file, "utf8");
131
+ return parseMarkdownContent(raw);
132
+ }
133
+ export function parseMarkdownContent(raw) {
134
+ const match = FRONTMATTER_PATTERN.exec(raw);
135
+ let frontmatter = {};
136
+ let body;
137
+ if (match) {
138
+ const parsedYaml = parseYaml(match[1]);
139
+ if (parsedYaml &&
140
+ typeof parsedYaml === "object" &&
141
+ !Array.isArray(parsedYaml)) {
142
+ frontmatter = parsedYaml;
143
+ }
144
+ body = raw.slice(match[0].length);
145
+ }
146
+ else {
147
+ body = raw;
148
+ }
149
+ const title = pickTitle(frontmatter, body);
150
+ if (!title)
151
+ return null;
152
+ const description = pickDescription(frontmatter, body);
153
+ const toolSurface = pickString(frontmatter, [
154
+ "tool_surface",
155
+ "toolSurface",
156
+ "tool",
157
+ "surface",
158
+ ]);
159
+ const category = pickString(frontmatter, ["category", "type"]);
160
+ const severity = pickSeverity(frontmatter);
161
+ const sessionId = pickString(frontmatter, [
162
+ "session_id",
163
+ "sessionId",
164
+ "session",
165
+ ]);
166
+ const capturedAt = pickIsoDate(frontmatter, [
167
+ "captured_at",
168
+ "capturedAt",
169
+ "date",
170
+ ]);
171
+ const extraTags = collectExtraTags(frontmatter);
172
+ return {
173
+ title,
174
+ description,
175
+ toolSurface,
176
+ category,
177
+ severity,
178
+ sessionId,
179
+ capturedAt,
180
+ extraTags,
181
+ };
182
+ }
183
+ function pickTitle(frontmatter, body) {
184
+ const fmTitle = pickString(frontmatter, ["title"]);
185
+ if (fmTitle)
186
+ return fmTitle;
187
+ const h1 = /^#\s+(.+)$/m.exec(body);
188
+ return h1 ? h1[1].trim() : null;
189
+ }
190
+ function pickDescription(frontmatter, body) {
191
+ const fmDesc = pickString(frontmatter, ["description", "summary"]);
192
+ if (fmDesc)
193
+ return fmDesc;
194
+ const stripped = body.replace(/^#\s+.+\n+/m, "").trim();
195
+ return stripped || null;
196
+ }
197
+ function pickString(frontmatter, keys) {
198
+ for (const k of keys) {
199
+ const v = frontmatter[k];
200
+ if (typeof v === "string" && v.trim())
201
+ return v.trim();
202
+ }
203
+ return null;
204
+ }
205
+ function pickSeverity(frontmatter) {
206
+ const s = pickString(frontmatter, ["severity"]);
207
+ if (!s)
208
+ return null;
209
+ const lower = s.toLowerCase();
210
+ return SEVERITY_VALUES.includes(lower)
211
+ ? lower
212
+ : null;
213
+ }
214
+ function pickIsoDate(frontmatter, keys) {
215
+ for (const k of keys) {
216
+ const v = frontmatter[k];
217
+ if (typeof v === "string") {
218
+ const d = new Date(v);
219
+ if (!Number.isNaN(d.getTime()))
220
+ return d.toISOString();
221
+ }
222
+ else if (v instanceof Date && !Number.isNaN(v.getTime())) {
223
+ return v.toISOString();
224
+ }
225
+ }
226
+ return undefined;
227
+ }
228
+ const KNOWN_FRONTMATTER_KEYS = new Set([
229
+ "title",
230
+ "description",
231
+ "summary",
232
+ "tool_surface",
233
+ "toolSurface",
234
+ "tool",
235
+ "surface",
236
+ "category",
237
+ "type",
238
+ "severity",
239
+ "session_id",
240
+ "sessionId",
241
+ "session",
242
+ "captured_at",
243
+ "capturedAt",
244
+ "date",
245
+ ]);
246
+ function collectExtraTags(frontmatter) {
247
+ const tags = [];
248
+ // Honor an explicit "tags:" or "labels:" array first.
249
+ for (const k of ["tags", "labels"]) {
250
+ const v = frontmatter[k];
251
+ if (Array.isArray(v)) {
252
+ for (const item of v) {
253
+ if (typeof item === "string" && item.trim())
254
+ tags.push(item.trim());
255
+ }
256
+ }
257
+ }
258
+ // Then expose unknown scalar keys as `key:value` tags so context is not lost.
259
+ for (const [key, value] of Object.entries(frontmatter)) {
260
+ if (KNOWN_FRONTMATTER_KEYS.has(key))
261
+ continue;
262
+ if (key === "tags" || key === "labels")
263
+ continue;
264
+ if (value == null)
265
+ continue;
266
+ if (typeof value === "string" ||
267
+ typeof value === "number" ||
268
+ typeof value === "boolean") {
269
+ tags.push(`${key}:${String(value)}`);
270
+ }
271
+ }
272
+ return tags;
273
+ }
274
+ function hashFor(p) {
275
+ const h = createHash("sha1");
276
+ h.update(p.title);
277
+ h.update("");
278
+ h.update(p.description ?? "");
279
+ h.update("");
280
+ h.update(p.toolSurface ?? "");
281
+ return h.digest("hex").slice(0, 16);
282
+ }
283
+ //# sourceMappingURL=import.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"import.js","sourceRoot":"","sources":["../../src/commands/import.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ import type { SinkName } from "../sinks/index.js";
2
+ export type InitDefaultSink = SinkName;
3
+ export interface InitDetected {
4
+ claudeCodeSettingsPath: string | null;
5
+ ghAvailable: boolean;
6
+ linearKeyPresent: boolean;
7
+ agentTasksTokenPresent: boolean;
8
+ }
9
+ /** Mirrors config.ts's SyncExportConfig; kept as a separate, minimal shape
10
+ * here so init.ts does not need to import the config-loading module just
11
+ * for a type. */
12
+ export interface InitSyncExportInput {
13
+ path: string;
14
+ origin: string;
15
+ peerPaths?: string[];
16
+ }
17
+ export interface InitCommandInput {
18
+ configPath?: string;
19
+ sink?: InitDefaultSink;
20
+ yes?: boolean;
21
+ installStopHook?: boolean;
22
+ prompt?: Prompter;
23
+ detect?: () => InitDetected;
24
+ /** Opt-in only: when omitted, init never touches (or scaffolds) the
25
+ * sync_export block, so a plain `init` re-run stays a no-op for existing
26
+ * users who never asked for sync-export. */
27
+ syncExport?: InitSyncExportInput;
28
+ }
29
+ export interface InitCommandOutput {
30
+ configPath: string;
31
+ configWritten: boolean;
32
+ configExistedBefore: boolean;
33
+ defaultSink: InitDefaultSink;
34
+ stopHookWrittenTo: string | null;
35
+ detected: InitDetected;
36
+ nextSteps: string[];
37
+ }
38
+ export interface Prompter {
39
+ select(question: string, choices: readonly string[], def?: string): Promise<string>;
40
+ confirm(question: string, def?: boolean): Promise<boolean>;
41
+ }
42
+ export declare function runInit(input?: InitCommandInput): Promise<InitCommandOutput>;
43
+ export declare function mergeConfigYaml(existingYaml: string, defaultSink: InitDefaultSink, syncExport?: InitSyncExportInput): string;
44
+ export declare function mergeStopHook(existingJson: string): string;