decision-memory 0.1.2 → 0.1.4
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/dist/{index.js → index.cjs} +469 -77
- package/dist/{mcp.js → mcp.cjs} +779 -413
- package/package.json +3 -4
- package/dist/chunk-43MFRJ7K.js +0 -389
- package/dist/chunk-5VFZ3YOK.js +0 -428
|
@@ -1,20 +1,34 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
10
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
14
28
|
|
|
15
29
|
// node_modules/commander/lib/error.js
|
|
16
30
|
var require_error = __commonJS({
|
|
17
|
-
"node_modules/commander/lib/error.js"(
|
|
31
|
+
"node_modules/commander/lib/error.js"(exports2) {
|
|
18
32
|
var CommanderError2 = class extends Error {
|
|
19
33
|
/**
|
|
20
34
|
* Constructs the CommanderError class
|
|
@@ -42,14 +56,14 @@ var require_error = __commonJS({
|
|
|
42
56
|
this.name = this.constructor.name;
|
|
43
57
|
}
|
|
44
58
|
};
|
|
45
|
-
|
|
46
|
-
|
|
59
|
+
exports2.CommanderError = CommanderError2;
|
|
60
|
+
exports2.InvalidArgumentError = InvalidArgumentError2;
|
|
47
61
|
}
|
|
48
62
|
});
|
|
49
63
|
|
|
50
64
|
// node_modules/commander/lib/argument.js
|
|
51
65
|
var require_argument = __commonJS({
|
|
52
|
-
"node_modules/commander/lib/argument.js"(
|
|
66
|
+
"node_modules/commander/lib/argument.js"(exports2) {
|
|
53
67
|
var { InvalidArgumentError: InvalidArgumentError2 } = require_error();
|
|
54
68
|
var Argument2 = class {
|
|
55
69
|
/**
|
|
@@ -169,14 +183,14 @@ var require_argument = __commonJS({
|
|
|
169
183
|
const nameOutput = arg.name() + (arg.variadic === true ? "..." : "");
|
|
170
184
|
return arg.required ? "<" + nameOutput + ">" : "[" + nameOutput + "]";
|
|
171
185
|
}
|
|
172
|
-
|
|
173
|
-
|
|
186
|
+
exports2.Argument = Argument2;
|
|
187
|
+
exports2.humanReadableArgName = humanReadableArgName;
|
|
174
188
|
}
|
|
175
189
|
});
|
|
176
190
|
|
|
177
191
|
// node_modules/commander/lib/help.js
|
|
178
192
|
var require_help = __commonJS({
|
|
179
|
-
"node_modules/commander/lib/help.js"(
|
|
193
|
+
"node_modules/commander/lib/help.js"(exports2) {
|
|
180
194
|
var { humanReadableArgName } = require_argument();
|
|
181
195
|
var Help2 = class {
|
|
182
196
|
constructor() {
|
|
@@ -584,13 +598,13 @@ var require_help = __commonJS({
|
|
|
584
598
|
}).join("\n");
|
|
585
599
|
}
|
|
586
600
|
};
|
|
587
|
-
|
|
601
|
+
exports2.Help = Help2;
|
|
588
602
|
}
|
|
589
603
|
});
|
|
590
604
|
|
|
591
605
|
// node_modules/commander/lib/option.js
|
|
592
606
|
var require_option = __commonJS({
|
|
593
|
-
"node_modules/commander/lib/option.js"(
|
|
607
|
+
"node_modules/commander/lib/option.js"(exports2) {
|
|
594
608
|
var { InvalidArgumentError: InvalidArgumentError2 } = require_error();
|
|
595
609
|
var Option2 = class {
|
|
596
610
|
/**
|
|
@@ -855,14 +869,14 @@ var require_option = __commonJS({
|
|
|
855
869
|
}
|
|
856
870
|
return { shortFlag, longFlag };
|
|
857
871
|
}
|
|
858
|
-
|
|
859
|
-
|
|
872
|
+
exports2.Option = Option2;
|
|
873
|
+
exports2.DualOptions = DualOptions;
|
|
860
874
|
}
|
|
861
875
|
});
|
|
862
876
|
|
|
863
877
|
// node_modules/commander/lib/suggestSimilar.js
|
|
864
878
|
var require_suggestSimilar = __commonJS({
|
|
865
|
-
"node_modules/commander/lib/suggestSimilar.js"(
|
|
879
|
+
"node_modules/commander/lib/suggestSimilar.js"(exports2) {
|
|
866
880
|
var maxDistance = 3;
|
|
867
881
|
function editDistance(a, b) {
|
|
868
882
|
if (Math.abs(a.length - b.length) > maxDistance)
|
|
@@ -936,18 +950,18 @@ var require_suggestSimilar = __commonJS({
|
|
|
936
950
|
}
|
|
937
951
|
return "";
|
|
938
952
|
}
|
|
939
|
-
|
|
953
|
+
exports2.suggestSimilar = suggestSimilar;
|
|
940
954
|
}
|
|
941
955
|
});
|
|
942
956
|
|
|
943
957
|
// node_modules/commander/lib/command.js
|
|
944
958
|
var require_command = __commonJS({
|
|
945
|
-
"node_modules/commander/lib/command.js"(
|
|
946
|
-
var EventEmitter =
|
|
947
|
-
var childProcess =
|
|
948
|
-
var
|
|
949
|
-
var
|
|
950
|
-
var process2 =
|
|
959
|
+
"node_modules/commander/lib/command.js"(exports2) {
|
|
960
|
+
var EventEmitter = require("events").EventEmitter;
|
|
961
|
+
var childProcess = require("child_process");
|
|
962
|
+
var path3 = require("path");
|
|
963
|
+
var fs5 = require("fs");
|
|
964
|
+
var process2 = require("process");
|
|
951
965
|
var { Argument: Argument2, humanReadableArgName } = require_argument();
|
|
952
966
|
var { CommanderError: CommanderError2 } = require_error();
|
|
953
967
|
var { Help: Help2 } = require_help();
|
|
@@ -1879,11 +1893,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1879
1893
|
let launchWithNode = false;
|
|
1880
1894
|
const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
|
|
1881
1895
|
function findFile(baseDir, baseName) {
|
|
1882
|
-
const localBin =
|
|
1883
|
-
if (
|
|
1884
|
-
if (sourceExt.includes(
|
|
1896
|
+
const localBin = path3.resolve(baseDir, baseName);
|
|
1897
|
+
if (fs5.existsSync(localBin)) return localBin;
|
|
1898
|
+
if (sourceExt.includes(path3.extname(baseName))) return void 0;
|
|
1885
1899
|
const foundExt = sourceExt.find(
|
|
1886
|
-
(ext) =>
|
|
1900
|
+
(ext) => fs5.existsSync(`${localBin}${ext}`)
|
|
1887
1901
|
);
|
|
1888
1902
|
if (foundExt) return `${localBin}${foundExt}`;
|
|
1889
1903
|
return void 0;
|
|
@@ -1895,21 +1909,21 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1895
1909
|
if (this._scriptPath) {
|
|
1896
1910
|
let resolvedScriptPath;
|
|
1897
1911
|
try {
|
|
1898
|
-
resolvedScriptPath =
|
|
1912
|
+
resolvedScriptPath = fs5.realpathSync(this._scriptPath);
|
|
1899
1913
|
} catch (err) {
|
|
1900
1914
|
resolvedScriptPath = this._scriptPath;
|
|
1901
1915
|
}
|
|
1902
|
-
executableDir =
|
|
1903
|
-
|
|
1916
|
+
executableDir = path3.resolve(
|
|
1917
|
+
path3.dirname(resolvedScriptPath),
|
|
1904
1918
|
executableDir
|
|
1905
1919
|
);
|
|
1906
1920
|
}
|
|
1907
1921
|
if (executableDir) {
|
|
1908
1922
|
let localFile = findFile(executableDir, executableFile);
|
|
1909
1923
|
if (!localFile && !subcommand._executableFile && this._scriptPath) {
|
|
1910
|
-
const legacyName =
|
|
1924
|
+
const legacyName = path3.basename(
|
|
1911
1925
|
this._scriptPath,
|
|
1912
|
-
|
|
1926
|
+
path3.extname(this._scriptPath)
|
|
1913
1927
|
);
|
|
1914
1928
|
if (legacyName !== this._name) {
|
|
1915
1929
|
localFile = findFile(
|
|
@@ -1920,7 +1934,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1920
1934
|
}
|
|
1921
1935
|
executableFile = localFile || executableFile;
|
|
1922
1936
|
}
|
|
1923
|
-
launchWithNode = sourceExt.includes(
|
|
1937
|
+
launchWithNode = sourceExt.includes(path3.extname(executableFile));
|
|
1924
1938
|
let proc;
|
|
1925
1939
|
if (process2.platform !== "win32") {
|
|
1926
1940
|
if (launchWithNode) {
|
|
@@ -2762,7 +2776,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2762
2776
|
* @return {Command}
|
|
2763
2777
|
*/
|
|
2764
2778
|
nameFromFilename(filename) {
|
|
2765
|
-
this._name =
|
|
2779
|
+
this._name = path3.basename(filename, path3.extname(filename));
|
|
2766
2780
|
return this;
|
|
2767
2781
|
}
|
|
2768
2782
|
/**
|
|
@@ -2776,9 +2790,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2776
2790
|
* @param {string} [path]
|
|
2777
2791
|
* @return {(string|null|Command)}
|
|
2778
2792
|
*/
|
|
2779
|
-
executableDir(
|
|
2780
|
-
if (
|
|
2781
|
-
this._executableDir =
|
|
2793
|
+
executableDir(path4) {
|
|
2794
|
+
if (path4 === void 0) return this._executableDir;
|
|
2795
|
+
this._executableDir = path4;
|
|
2782
2796
|
return this;
|
|
2783
2797
|
}
|
|
2784
2798
|
/**
|
|
@@ -2983,29 +2997,29 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2983
2997
|
return arg;
|
|
2984
2998
|
});
|
|
2985
2999
|
}
|
|
2986
|
-
|
|
3000
|
+
exports2.Command = Command2;
|
|
2987
3001
|
}
|
|
2988
3002
|
});
|
|
2989
3003
|
|
|
2990
3004
|
// node_modules/commander/index.js
|
|
2991
3005
|
var require_commander = __commonJS({
|
|
2992
|
-
"node_modules/commander/index.js"(
|
|
3006
|
+
"node_modules/commander/index.js"(exports2) {
|
|
2993
3007
|
var { Argument: Argument2 } = require_argument();
|
|
2994
3008
|
var { Command: Command2 } = require_command();
|
|
2995
3009
|
var { CommanderError: CommanderError2, InvalidArgumentError: InvalidArgumentError2 } = require_error();
|
|
2996
3010
|
var { Help: Help2 } = require_help();
|
|
2997
3011
|
var { Option: Option2 } = require_option();
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3012
|
+
exports2.program = new Command2();
|
|
3013
|
+
exports2.createCommand = (name) => new Command2(name);
|
|
3014
|
+
exports2.createOption = (flags, description) => new Option2(flags, description);
|
|
3015
|
+
exports2.createArgument = (name, description) => new Argument2(name, description);
|
|
3016
|
+
exports2.Command = Command2;
|
|
3017
|
+
exports2.Option = Option2;
|
|
3018
|
+
exports2.Argument = Argument2;
|
|
3019
|
+
exports2.Help = Help2;
|
|
3020
|
+
exports2.CommanderError = CommanderError2;
|
|
3021
|
+
exports2.InvalidArgumentError = InvalidArgumentError2;
|
|
3022
|
+
exports2.InvalidOptionArgumentError = InvalidArgumentError2;
|
|
3009
3023
|
}
|
|
3010
3024
|
});
|
|
3011
3025
|
|
|
@@ -3027,26 +3041,404 @@ var {
|
|
|
3027
3041
|
} = import_index.default;
|
|
3028
3042
|
|
|
3029
3043
|
// packages/cli/src/commands/init.ts
|
|
3030
|
-
|
|
3031
|
-
|
|
3044
|
+
var fs2 = __toESM(require("fs"));
|
|
3045
|
+
var path2 = __toESM(require("path"));
|
|
3046
|
+
|
|
3047
|
+
// packages/core/src/idgen.ts
|
|
3048
|
+
var ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
3049
|
+
function encodeBase36(n) {
|
|
3050
|
+
if (n === 0) return "0";
|
|
3051
|
+
let result = "";
|
|
3052
|
+
while (n > 0) {
|
|
3053
|
+
result = ALPHABET[n % 36] + result;
|
|
3054
|
+
n = Math.floor(n / 36);
|
|
3055
|
+
}
|
|
3056
|
+
return result;
|
|
3057
|
+
}
|
|
3058
|
+
function generateNextId(currentCount) {
|
|
3059
|
+
const next = currentCount + 1;
|
|
3060
|
+
if (next <= 999) {
|
|
3061
|
+
return `D${String(next).padStart(3, "0")}`;
|
|
3062
|
+
}
|
|
3063
|
+
const encoded = encodeBase36(next).padStart(4, "0");
|
|
3064
|
+
return `D${encoded}`;
|
|
3065
|
+
}
|
|
3066
|
+
|
|
3067
|
+
// packages/core/src/parser.ts
|
|
3068
|
+
function splitCsvRow(line) {
|
|
3069
|
+
const fields = [];
|
|
3070
|
+
let current = "";
|
|
3071
|
+
let inQuote = false;
|
|
3072
|
+
let i = 0;
|
|
3073
|
+
while (i < line.length) {
|
|
3074
|
+
const ch = line[i];
|
|
3075
|
+
if (inQuote) {
|
|
3076
|
+
if (ch === "\\") {
|
|
3077
|
+
const next = line[i + 1];
|
|
3078
|
+
if (next === '"') {
|
|
3079
|
+
current += '"';
|
|
3080
|
+
i += 2;
|
|
3081
|
+
continue;
|
|
3082
|
+
} else if (next === "n") {
|
|
3083
|
+
current += "\n";
|
|
3084
|
+
i += 2;
|
|
3085
|
+
continue;
|
|
3086
|
+
} else if (next === "\\") {
|
|
3087
|
+
current += "\\";
|
|
3088
|
+
i += 2;
|
|
3089
|
+
continue;
|
|
3090
|
+
}
|
|
3091
|
+
current += ch;
|
|
3092
|
+
} else if (ch === '"') {
|
|
3093
|
+
inQuote = false;
|
|
3094
|
+
} else {
|
|
3095
|
+
current += ch;
|
|
3096
|
+
}
|
|
3097
|
+
} else {
|
|
3098
|
+
if (ch === '"') {
|
|
3099
|
+
inQuote = true;
|
|
3100
|
+
} else if (ch === ",") {
|
|
3101
|
+
fields.push(current);
|
|
3102
|
+
current = "";
|
|
3103
|
+
} else {
|
|
3104
|
+
current += ch;
|
|
3105
|
+
}
|
|
3106
|
+
}
|
|
3107
|
+
i++;
|
|
3108
|
+
}
|
|
3109
|
+
fields.push(current);
|
|
3110
|
+
return fields;
|
|
3111
|
+
}
|
|
3112
|
+
function parseTableHeader(line) {
|
|
3113
|
+
const match = line.match(/^decisions\[(\d+)\]\{([^}]+)\}:$/);
|
|
3114
|
+
if (!match) return null;
|
|
3115
|
+
return {
|
|
3116
|
+
count: parseInt(match[1], 10),
|
|
3117
|
+
fields: match[2].split(",")
|
|
3118
|
+
};
|
|
3119
|
+
}
|
|
3120
|
+
function isSummaryLine(line) {
|
|
3121
|
+
return line.startsWith("summary{");
|
|
3122
|
+
}
|
|
3123
|
+
function parseDecisionRow(fields, values) {
|
|
3124
|
+
const get = (name) => {
|
|
3125
|
+
const idx = fields.indexOf(name);
|
|
3126
|
+
return idx >= 0 ? values[idx] ?? "" : "";
|
|
3127
|
+
};
|
|
3128
|
+
const impactRaw = get("impact");
|
|
3129
|
+
const validImpacts = ["low", "medium", "high", "critical"];
|
|
3130
|
+
const impact = validImpacts.includes(impactRaw) ? impactRaw : "medium";
|
|
3131
|
+
const tagsRaw = get("tags");
|
|
3132
|
+
const tags = tagsRaw ? tagsRaw.split("|").filter(Boolean) : [];
|
|
3133
|
+
return {
|
|
3134
|
+
id: get("id"),
|
|
3135
|
+
ts: get("ts"),
|
|
3136
|
+
topic: get("topic"),
|
|
3137
|
+
decision: get("decision"),
|
|
3138
|
+
rationale: get("rationale"),
|
|
3139
|
+
impact,
|
|
3140
|
+
tags
|
|
3141
|
+
};
|
|
3142
|
+
}
|
|
3143
|
+
function parseDecisionFile(content) {
|
|
3144
|
+
const lines = content.split("\n");
|
|
3145
|
+
const meta = {
|
|
3146
|
+
project: "unknown",
|
|
3147
|
+
version: "1",
|
|
3148
|
+
created: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
|
|
3149
|
+
updated: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10)
|
|
3150
|
+
};
|
|
3151
|
+
const decisions = [];
|
|
3152
|
+
let tableFields = [];
|
|
3153
|
+
let inTable = false;
|
|
3154
|
+
let inSummary = false;
|
|
3155
|
+
for (const rawLine of lines) {
|
|
3156
|
+
const line = rawLine.trimEnd();
|
|
3157
|
+
if (!line || line.startsWith("#")) continue;
|
|
3158
|
+
if (isSummaryLine(line)) {
|
|
3159
|
+
inTable = false;
|
|
3160
|
+
inSummary = true;
|
|
3161
|
+
continue;
|
|
3162
|
+
}
|
|
3163
|
+
if (inSummary) continue;
|
|
3164
|
+
const tableHeader = parseTableHeader(line);
|
|
3165
|
+
if (tableHeader) {
|
|
3166
|
+
tableFields = tableHeader.fields;
|
|
3167
|
+
inTable = true;
|
|
3168
|
+
continue;
|
|
3169
|
+
}
|
|
3170
|
+
if (inTable && tableFields.length > 0) {
|
|
3171
|
+
const values = splitCsvRow(line);
|
|
3172
|
+
if (values.length >= tableFields.length) {
|
|
3173
|
+
decisions.push(parseDecisionRow(tableFields, values));
|
|
3174
|
+
}
|
|
3175
|
+
continue;
|
|
3176
|
+
}
|
|
3177
|
+
const colonIdx = line.indexOf(":");
|
|
3178
|
+
if (colonIdx > 0) {
|
|
3179
|
+
const key = line.slice(0, colonIdx).trim();
|
|
3180
|
+
const value = line.slice(colonIdx + 1).trim();
|
|
3181
|
+
if (key === "project") meta.project = value;
|
|
3182
|
+
else if (key === "version") meta.version = value;
|
|
3183
|
+
else if (key === "created") meta.created = value;
|
|
3184
|
+
else if (key === "updated") meta.updated = value;
|
|
3185
|
+
}
|
|
3186
|
+
}
|
|
3187
|
+
return { meta, decisions };
|
|
3188
|
+
}
|
|
3189
|
+
function serializeDecisionRow(d) {
|
|
3190
|
+
const escapeField = (s) => {
|
|
3191
|
+
if (s.includes(",") || s.includes('"') || s.includes("\n")) {
|
|
3192
|
+
return '"' + s.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n") + '"';
|
|
3193
|
+
}
|
|
3194
|
+
return s;
|
|
3195
|
+
};
|
|
3196
|
+
const tags = d.tags.join("|");
|
|
3197
|
+
return [
|
|
3198
|
+
d.id,
|
|
3199
|
+
d.ts,
|
|
3200
|
+
d.topic,
|
|
3201
|
+
escapeField(d.decision),
|
|
3202
|
+
escapeField(d.rationale),
|
|
3203
|
+
d.impact,
|
|
3204
|
+
tags
|
|
3205
|
+
].join(",");
|
|
3206
|
+
}
|
|
3207
|
+
|
|
3208
|
+
// packages/core/src/searcher.ts
|
|
3209
|
+
var IMPACT_WEIGHT = {
|
|
3210
|
+
critical: 4,
|
|
3211
|
+
high: 3,
|
|
3212
|
+
medium: 2,
|
|
3213
|
+
low: 1
|
|
3214
|
+
};
|
|
3215
|
+
function computeMatchedFields(d, keywords, tags) {
|
|
3216
|
+
const matched = [];
|
|
3217
|
+
const kws = keywords.map((k) => k.toLowerCase());
|
|
3218
|
+
if (tags.length > 0 && tags.some((t) => d.tags.map((dt) => dt.toLowerCase()).includes(t))) {
|
|
3219
|
+
matched.push("tags");
|
|
3220
|
+
}
|
|
3221
|
+
if (kws.some((k) => d.topic.toLowerCase().includes(k))) matched.push("topic");
|
|
3222
|
+
if (kws.some((k) => d.decision.toLowerCase().includes(k))) matched.push("decision");
|
|
3223
|
+
if (kws.some((k) => d.rationale.toLowerCase().includes(k))) matched.push("rationale");
|
|
3224
|
+
return matched;
|
|
3225
|
+
}
|
|
3226
|
+
function searchDecisions(file, query) {
|
|
3227
|
+
const keywords = (query.keywords ?? []).map((k) => k.toLowerCase());
|
|
3228
|
+
const tags = (query.tags ?? []).map((t) => t.toLowerCase());
|
|
3229
|
+
const impactFilter = query.impact;
|
|
3230
|
+
const limit = query.limit ?? 5;
|
|
3231
|
+
if (keywords.length === 0 && tags.length === 0 && !impactFilter) {
|
|
3232
|
+
return file.decisions.slice(-limit).reverse().map((d) => ({ decision: d, matchedFields: [] }));
|
|
3233
|
+
}
|
|
3234
|
+
const results = [];
|
|
3235
|
+
for (const d of file.decisions) {
|
|
3236
|
+
if (impactFilter && d.impact !== impactFilter) continue;
|
|
3237
|
+
const decisionLower = d.decision.toLowerCase();
|
|
3238
|
+
const rationaleLower = d.rationale.toLowerCase();
|
|
3239
|
+
const topicLower = d.topic.toLowerCase();
|
|
3240
|
+
const tagsLower = d.tags.map((t) => t.toLowerCase());
|
|
3241
|
+
const matchesTag = tags.length === 0 || tags.some((t) => tagsLower.includes(t));
|
|
3242
|
+
const matchesKeyword = keywords.length === 0 || keywords.some(
|
|
3243
|
+
(k) => topicLower.includes(k) || decisionLower.includes(k) || rationaleLower.includes(k) || tagsLower.some((t) => t.includes(k))
|
|
3244
|
+
);
|
|
3245
|
+
if (matchesTag && matchesKeyword) {
|
|
3246
|
+
results.push({
|
|
3247
|
+
decision: d,
|
|
3248
|
+
matchedFields: computeMatchedFields(d, keywords, tags)
|
|
3249
|
+
});
|
|
3250
|
+
}
|
|
3251
|
+
}
|
|
3252
|
+
results.sort((a, b) => {
|
|
3253
|
+
const weightDiff = IMPACT_WEIGHT[b.decision.impact] - IMPACT_WEIGHT[a.decision.impact];
|
|
3254
|
+
if (weightDiff !== 0) return weightDiff;
|
|
3255
|
+
return b.decision.ts.localeCompare(a.decision.ts);
|
|
3256
|
+
});
|
|
3257
|
+
return results.slice(0, limit);
|
|
3258
|
+
}
|
|
3259
|
+
|
|
3260
|
+
// packages/core/src/summary.ts
|
|
3261
|
+
var HIGH_IMPACT = ["high", "critical"];
|
|
3262
|
+
function topTopics(decisions, n = 5) {
|
|
3263
|
+
const counts = /* @__PURE__ */ new Map();
|
|
3264
|
+
for (const d of decisions) {
|
|
3265
|
+
counts.set(d.topic, (counts.get(d.topic) ?? 0) + 1);
|
|
3266
|
+
}
|
|
3267
|
+
return [...counts.entries()].sort((a, b) => b[1] - a[1]).slice(0, n).map(([topic]) => topic);
|
|
3268
|
+
}
|
|
3269
|
+
function buildContextSummary(file, options = {}) {
|
|
3270
|
+
const { includeRecent = true } = options;
|
|
3271
|
+
const { decisions } = file;
|
|
3272
|
+
const highImpactCount = decisions.filter(
|
|
3273
|
+
(d) => HIGH_IMPACT.includes(d.impact)
|
|
3274
|
+
).length;
|
|
3275
|
+
const lastUpdated = decisions.length > 0 ? decisions[decisions.length - 1].ts.slice(0, 10) : file.meta.updated;
|
|
3276
|
+
const recentDecisions = includeRecent ? decisions.filter((d) => HIGH_IMPACT.includes(d.impact)).slice(-5).reverse() : [];
|
|
3277
|
+
return {
|
|
3278
|
+
total: decisions.length,
|
|
3279
|
+
highImpactCount,
|
|
3280
|
+
lastUpdated,
|
|
3281
|
+
topTopics: topTopics(decisions),
|
|
3282
|
+
recentDecisions
|
|
3283
|
+
};
|
|
3284
|
+
}
|
|
3285
|
+
function buildSummaryBlock(file) {
|
|
3286
|
+
const summary = buildContextSummary(file, { includeRecent: false });
|
|
3287
|
+
const topics = summary.topTopics.join("|");
|
|
3288
|
+
return `summary{total,high_impact,last_updated,top_topics}:
|
|
3289
|
+
${summary.total},${summary.highImpactCount},${summary.lastUpdated},${topics}`;
|
|
3290
|
+
}
|
|
3291
|
+
function formatContextSummaryAsToon(file, includeRecent = true) {
|
|
3292
|
+
const summary = buildContextSummary(file, { includeRecent });
|
|
3293
|
+
const topics = summary.topTopics.join("|");
|
|
3294
|
+
let output2 = `summary{total,high_impact,last_updated,top_topics}:
|
|
3295
|
+
`;
|
|
3296
|
+
output2 += `${summary.total},${summary.highImpactCount},${summary.lastUpdated},${topics}`;
|
|
3297
|
+
if (includeRecent && summary.recentDecisions.length > 0) {
|
|
3298
|
+
output2 += `
|
|
3299
|
+
|
|
3300
|
+
recent_high_impact[${summary.recentDecisions.length}]{id,ts,topic,decision,impact}:
|
|
3301
|
+
`;
|
|
3302
|
+
for (const d of summary.recentDecisions) {
|
|
3303
|
+
const decisionField = d.decision.includes(",") ? `"${d.decision}"` : d.decision;
|
|
3304
|
+
output2 += `${d.id},${d.ts},${d.topic},${decisionField},${d.impact}
|
|
3305
|
+
`;
|
|
3306
|
+
}
|
|
3307
|
+
}
|
|
3308
|
+
return output2.trimEnd();
|
|
3309
|
+
}
|
|
3310
|
+
|
|
3311
|
+
// packages/core/src/writer.ts
|
|
3312
|
+
var fs = __toESM(require("fs"), 1);
|
|
3313
|
+
var path = __toESM(require("path"), 1);
|
|
3314
|
+
var os = __toESM(require("os"), 1);
|
|
3315
|
+
function initDecisionFile(filePath, projectName) {
|
|
3316
|
+
if (fs.existsSync(filePath)) {
|
|
3317
|
+
throw new Error(`Dosya zaten var: ${filePath}`);
|
|
3318
|
+
}
|
|
3319
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
3320
|
+
const content = `# decision-memory v1
|
|
3321
|
+
project: ${projectName}
|
|
3322
|
+
version: 1
|
|
3323
|
+
created: ${today}
|
|
3324
|
+
updated: ${today}
|
|
3325
|
+
|
|
3326
|
+
decisions[0]{id,ts,topic,decision,rationale,impact,tags}:
|
|
3327
|
+
|
|
3328
|
+
summary{total,high_impact,last_updated,top_topics}:
|
|
3329
|
+
0,0,${today},
|
|
3330
|
+
`;
|
|
3331
|
+
fs.writeFileSync(filePath, content, "utf-8");
|
|
3332
|
+
}
|
|
3333
|
+
function updateDecisionCount(filePath, newCount) {
|
|
3334
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
3335
|
+
const updated = content.replace(
|
|
3336
|
+
/^decisions\[(\d+)\]\{/m,
|
|
3337
|
+
`decisions[${newCount}]{`
|
|
3338
|
+
);
|
|
3339
|
+
const tmpPath = filePath + ".tmp";
|
|
3340
|
+
fs.writeFileSync(tmpPath, updated, "utf-8");
|
|
3341
|
+
fs.renameSync(tmpPath, filePath);
|
|
3342
|
+
}
|
|
3343
|
+
function updateSummaryBlock(filePath) {
|
|
3344
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
3345
|
+
const file = parseDecisionFile(content);
|
|
3346
|
+
const summaryBlock = buildSummaryBlock(file);
|
|
3347
|
+
const summaryStart = content.indexOf("\nsummary{");
|
|
3348
|
+
let base;
|
|
3349
|
+
if (summaryStart >= 0) {
|
|
3350
|
+
base = content.slice(0, summaryStart);
|
|
3351
|
+
} else {
|
|
3352
|
+
base = content.trimEnd();
|
|
3353
|
+
}
|
|
3354
|
+
const newContent = base + "\n" + summaryBlock + "\n";
|
|
3355
|
+
const tmpPath = filePath + ".tmp";
|
|
3356
|
+
fs.writeFileSync(tmpPath, newContent, "utf-8");
|
|
3357
|
+
fs.renameSync(tmpPath, filePath);
|
|
3358
|
+
}
|
|
3359
|
+
function appendDecision(filePath, input2) {
|
|
3360
|
+
if (!fs.existsSync(filePath)) {
|
|
3361
|
+
throw new Error(`DECISIONS.toon dosyas\u0131 bulunamad\u0131: ${filePath}
|
|
3362
|
+
\xD6nce 'decision-memory init' komutunu \xE7al\u0131\u015Ft\u0131r\u0131n.`);
|
|
3363
|
+
}
|
|
3364
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
3365
|
+
const countMatch = content.match(/^decisions\[(\d+)\]/m);
|
|
3366
|
+
const currentCount = countMatch ? parseInt(countMatch[1], 10) : 0;
|
|
3367
|
+
const id = generateNextId(currentCount);
|
|
3368
|
+
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z").replace(/:\d{2}Z$/, "Z");
|
|
3369
|
+
const decision = {
|
|
3370
|
+
id,
|
|
3371
|
+
ts,
|
|
3372
|
+
topic: input2.topic,
|
|
3373
|
+
decision: input2.decision,
|
|
3374
|
+
rationale: input2.rationale,
|
|
3375
|
+
impact: input2.impact,
|
|
3376
|
+
tags: input2.tags
|
|
3377
|
+
};
|
|
3378
|
+
const row = serializeDecisionRow(decision);
|
|
3379
|
+
const lines = content.split("\n");
|
|
3380
|
+
let tableEnd = -1;
|
|
3381
|
+
let inTable = false;
|
|
3382
|
+
for (let i = 0; i < lines.length; i++) {
|
|
3383
|
+
if (/^decisions\[\d+\]\{/.test(lines[i])) {
|
|
3384
|
+
inTable = true;
|
|
3385
|
+
tableEnd = i;
|
|
3386
|
+
continue;
|
|
3387
|
+
}
|
|
3388
|
+
if (inTable) {
|
|
3389
|
+
if (lines[i].startsWith("summary{") || lines[i] === "" && tableEnd >= 0) {
|
|
3390
|
+
if (lines[i].startsWith("summary{")) {
|
|
3391
|
+
tableEnd = i - 1;
|
|
3392
|
+
} else {
|
|
3393
|
+
tableEnd = i - 1;
|
|
3394
|
+
}
|
|
3395
|
+
break;
|
|
3396
|
+
}
|
|
3397
|
+
if (lines[i] !== "") {
|
|
3398
|
+
tableEnd = i;
|
|
3399
|
+
}
|
|
3400
|
+
}
|
|
3401
|
+
}
|
|
3402
|
+
lines.splice(tableEnd + 1, 0, row);
|
|
3403
|
+
const newContent = lines.join("\n");
|
|
3404
|
+
const tmpPath = filePath + ".tmp";
|
|
3405
|
+
fs.writeFileSync(tmpPath, newContent, "utf-8");
|
|
3406
|
+
fs.renameSync(tmpPath, filePath);
|
|
3407
|
+
updateDecisionCount(filePath, currentCount + 1);
|
|
3408
|
+
updateSummaryBlock(filePath);
|
|
3409
|
+
return decision;
|
|
3410
|
+
}
|
|
3411
|
+
function resolveDecisionFilePath(cwd) {
|
|
3412
|
+
if (process.env.DECISION_MEMORY_FILE) {
|
|
3413
|
+
return process.env.DECISION_MEMORY_FILE;
|
|
3414
|
+
}
|
|
3415
|
+
const dir = cwd ?? process.cwd();
|
|
3416
|
+
const local = path.join(dir, "DECISIONS.toon");
|
|
3417
|
+
if (fs.existsSync(local)) return local;
|
|
3418
|
+
const globalDir = path.join(os.homedir(), ".decision-memory");
|
|
3419
|
+
fs.mkdirSync(globalDir, { recursive: true });
|
|
3420
|
+
return path.join(globalDir, "global.toon");
|
|
3421
|
+
}
|
|
3422
|
+
|
|
3423
|
+
// packages/cli/src/commands/init.ts
|
|
3032
3424
|
function initCommand(options) {
|
|
3033
3425
|
const dir = options.dir ?? process.cwd();
|
|
3034
|
-
const filePath =
|
|
3035
|
-
if (
|
|
3426
|
+
const filePath = path2.join(dir, "DECISIONS.toon");
|
|
3427
|
+
if (fs2.existsSync(filePath)) {
|
|
3036
3428
|
console.error(`Hata: ${filePath} zaten mevcut.`);
|
|
3037
3429
|
process.exit(1);
|
|
3038
3430
|
}
|
|
3039
|
-
const projectName = options.project ??
|
|
3431
|
+
const projectName = options.project ?? path2.basename(dir);
|
|
3040
3432
|
initDecisionFile(filePath, projectName);
|
|
3041
|
-
const gitattributes =
|
|
3433
|
+
const gitattributes = path2.join(dir, ".gitattributes");
|
|
3042
3434
|
const entry = "DECISIONS.toon text eol=lf\n";
|
|
3043
|
-
if (
|
|
3044
|
-
const content =
|
|
3435
|
+
if (fs2.existsSync(gitattributes)) {
|
|
3436
|
+
const content = fs2.readFileSync(gitattributes, "utf-8");
|
|
3045
3437
|
if (!content.includes("DECISIONS.toon")) {
|
|
3046
|
-
|
|
3438
|
+
fs2.appendFileSync(gitattributes, entry);
|
|
3047
3439
|
}
|
|
3048
3440
|
} else {
|
|
3049
|
-
|
|
3441
|
+
fs2.writeFileSync(gitattributes, entry);
|
|
3050
3442
|
}
|
|
3051
3443
|
console.log(`\u2713 ${filePath} olu\u015Fturuldu.`);
|
|
3052
3444
|
console.log(`\u2713 .gitattributes g\xFCncellendi.`);
|
|
@@ -3057,8 +3449,8 @@ Ba\u015Flamak i\xE7in:`);
|
|
|
3057
3449
|
}
|
|
3058
3450
|
|
|
3059
3451
|
// packages/cli/src/commands/log.ts
|
|
3060
|
-
|
|
3061
|
-
|
|
3452
|
+
var readline = __toESM(require("readline/promises"));
|
|
3453
|
+
var import_node_process = require("process");
|
|
3062
3454
|
async function logCommand(options) {
|
|
3063
3455
|
if (options.topic && options.decision && options.rationale && options.impact) {
|
|
3064
3456
|
const inp = buildInput(options);
|
|
@@ -3067,7 +3459,7 @@ async function logCommand(options) {
|
|
|
3067
3459
|
console.log(`\u2713 Karar kaydedildi: ${entry.id} \u2014 ${entry.decision}`);
|
|
3068
3460
|
return;
|
|
3069
3461
|
}
|
|
3070
|
-
const rl = readline.createInterface({ input, output });
|
|
3462
|
+
const rl = readline.createInterface({ input: import_node_process.stdin, output: import_node_process.stdout });
|
|
3071
3463
|
try {
|
|
3072
3464
|
const topic = options.topic ?? await rl.question("Konu (\xF6rn: auth, database): ");
|
|
3073
3465
|
const decision = options.decision ?? await rl.question("Al\u0131nan karar: ");
|
|
@@ -3108,14 +3500,14 @@ function buildInput(options) {
|
|
|
3108
3500
|
}
|
|
3109
3501
|
|
|
3110
3502
|
// packages/cli/src/commands/search.ts
|
|
3111
|
-
|
|
3503
|
+
var fs3 = __toESM(require("fs"));
|
|
3112
3504
|
function searchCommand(options) {
|
|
3113
3505
|
const filePath = options.file ?? resolveDecisionFilePath();
|
|
3114
|
-
if (!
|
|
3506
|
+
if (!fs3.existsSync(filePath)) {
|
|
3115
3507
|
console.error(`Hata: ${filePath} bulunamad\u0131. \xD6nce 'decision-memory init' \xE7al\u0131\u015Ft\u0131r\u0131n.`);
|
|
3116
3508
|
process.exit(1);
|
|
3117
3509
|
}
|
|
3118
|
-
const content =
|
|
3510
|
+
const content = fs3.readFileSync(filePath, "utf-8");
|
|
3119
3511
|
const file = parseDecisionFile(content);
|
|
3120
3512
|
const keywords = options.keywords ? options.keywords.split(",").map((k) => k.trim()).filter(Boolean) : [];
|
|
3121
3513
|
const tags = options.tags ? options.tags.split(",").map((t) => t.trim()).filter(Boolean) : [];
|
|
@@ -3134,14 +3526,14 @@ function searchCommand(options) {
|
|
|
3134
3526
|
}
|
|
3135
3527
|
|
|
3136
3528
|
// packages/cli/src/commands/summary.ts
|
|
3137
|
-
|
|
3529
|
+
var fs4 = __toESM(require("fs"));
|
|
3138
3530
|
function summaryCommand(options) {
|
|
3139
3531
|
const filePath = options.file ?? resolveDecisionFilePath();
|
|
3140
|
-
if (!
|
|
3532
|
+
if (!fs4.existsSync(filePath)) {
|
|
3141
3533
|
console.error(`Hata: ${filePath} bulunamad\u0131. \xD6nce 'decision-memory init' \xE7al\u0131\u015Ft\u0131r\u0131n.`);
|
|
3142
3534
|
process.exit(1);
|
|
3143
3535
|
}
|
|
3144
|
-
const content =
|
|
3536
|
+
const content = fs4.readFileSync(filePath, "utf-8");
|
|
3145
3537
|
const file = parseDecisionFile(content);
|
|
3146
3538
|
const output2 = formatContextSummaryAsToon(file, !options.noRecent);
|
|
3147
3539
|
console.log(output2);
|