@codyswann/lisa 2.217.8 → 2.219.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 (106) hide show
  1. package/all/create-only/.claude/rules/PROJECT_LEARNINGS.md +7 -0
  2. package/dist/core/learnings-contract.d.ts +38 -0
  3. package/dist/core/learnings-contract.d.ts.map +1 -0
  4. package/dist/core/learnings-contract.js +36 -0
  5. package/dist/core/learnings-contract.js.map +1 -0
  6. package/dist/core/learnings-entry.d.ts +9 -0
  7. package/dist/core/learnings-entry.d.ts.map +1 -0
  8. package/dist/core/learnings-entry.js +233 -0
  9. package/dist/core/learnings-entry.js.map +1 -0
  10. package/dist/core/learnings-file-safety.d.ts +23 -0
  11. package/dist/core/learnings-file-safety.d.ts.map +1 -0
  12. package/dist/core/learnings-file-safety.js +84 -0
  13. package/dist/core/learnings-file-safety.js.map +1 -0
  14. package/dist/core/learnings-lock.d.ts +8 -0
  15. package/dist/core/learnings-lock.d.ts.map +1 -0
  16. package/dist/core/learnings-lock.js +227 -0
  17. package/dist/core/learnings-lock.js.map +1 -0
  18. package/dist/core/learnings-writer.d.ts +22 -0
  19. package/dist/core/learnings-writer.d.ts.map +1 -0
  20. package/dist/core/learnings-writer.js +128 -0
  21. package/dist/core/learnings-writer.js.map +1 -0
  22. package/dist/core/learnings.d.ts +4 -0
  23. package/dist/core/learnings.d.ts.map +1 -0
  24. package/dist/core/learnings.js +4 -0
  25. package/dist/core/learnings.js.map +1 -0
  26. package/dist/core/lisa.d.ts +26 -0
  27. package/dist/core/lisa.d.ts.map +1 -1
  28. package/dist/core/lisa.js +82 -8
  29. package/dist/core/lisa.js.map +1 -1
  30. package/dist/core/project-config.d.ts +19 -0
  31. package/dist/core/project-config.d.ts.map +1 -1
  32. package/dist/core/project-config.js +87 -14
  33. package/dist/core/project-config.js.map +1 -1
  34. package/dist/strategies/create-only.d.ts +10 -0
  35. package/dist/strategies/create-only.d.ts.map +1 -1
  36. package/dist/strategies/create-only.js +27 -7
  37. package/dist/strategies/create-only.js.map +1 -1
  38. package/dist/sync/registry.d.ts +0 -12
  39. package/dist/sync/registry.d.ts.map +1 -1
  40. package/dist/sync/registry.js +18 -0
  41. package/dist/sync/registry.js.map +1 -1
  42. package/package.json +2 -1
  43. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  44. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  45. package/plugins/lisa/.codex-plugin/skills/lisa-debrief-apply/SKILL.md +3 -3
  46. package/plugins/lisa/rules/eager/config-resolution.md +9 -0
  47. package/plugins/lisa/rules/reference/config-resolution.md +2 -0
  48. package/plugins/lisa/skills/lisa-debrief-apply/SKILL.md +3 -3
  49. package/plugins/lisa-agy/plugin.json +1 -1
  50. package/plugins/lisa-agy/skills/lisa-debrief-apply/SKILL.md +3 -3
  51. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  52. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  53. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  54. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  55. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  56. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  57. package/plugins/lisa-copilot/rules/eager/config-resolution.md +9 -0
  58. package/plugins/lisa-copilot/rules/reference/config-resolution.md +2 -0
  59. package/plugins/lisa-copilot/skills/lisa-debrief-apply/SKILL.md +3 -3
  60. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  61. package/plugins/lisa-cursor/rules/config-resolution-reference.mdc +2 -0
  62. package/plugins/lisa-cursor/rules/config-resolution.mdc +9 -0
  63. package/plugins/lisa-cursor/skills/lisa-debrief-apply/SKILL.md +3 -3
  64. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  65. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  66. package/plugins/lisa-expo-agy/plugin.json +1 -1
  67. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  68. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  69. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  70. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  71. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  72. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  73. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  74. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  75. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  76. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  77. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  78. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  79. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  80. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  81. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  82. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  83. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  84. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  85. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  86. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  87. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  88. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  89. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  90. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  91. package/plugins/lisa-rails-agy/plugin.json +1 -1
  92. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  93. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  94. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  95. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  96. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  97. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  98. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  99. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  100. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  101. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  102. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  103. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  104. package/plugins/src/base/rules/eager/config-resolution.md +9 -0
  105. package/plugins/src/base/rules/reference/config-resolution.md +2 -0
  106. package/plugins/src/base/skills/lisa-debrief-apply/SKILL.md +3 -3
@@ -0,0 +1,7 @@
1
+ # Project Learnings
2
+
3
+ <!-- lisa-learnings-contract:v1 -->
4
+
5
+ ```jsonl
6
+
7
+ ```
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Executable contract shared by every project-learnings writer and checker.
3
+ * Keeping the numeric limits here prevents documentation, writers, and CI
4
+ * from drifting to different budgets.
5
+ * @module learnings-contract
6
+ */
7
+ export declare const LEARNING_CONFIDENCE_VALUES: readonly ["low", "medium", "high"];
8
+ /** Confidence vocabulary persisted in every learning entry. */
9
+ export type LearningConfidence = (typeof LEARNING_CONFIDENCE_VALUES)[number];
10
+ export declare const LEARNINGS_CONTRACT: Readonly<{
11
+ readonly version: 1;
12
+ readonly fields: readonly ["id", "rule", "why", "provenance", "first_learned", "last_confirmed", "confidence"];
13
+ readonly maxRuleCharacters: 240;
14
+ readonly maxRuleLines: 2;
15
+ readonly maxProvenanceReferences: 20;
16
+ readonly maxEntries: 20;
17
+ readonly maxTokens: 4000;
18
+ readonly measurement: "utf8-bytes-upper-bound";
19
+ }>;
20
+ /** Complete persisted schema for one project learning. */
21
+ export interface LearningEntry {
22
+ readonly id: string;
23
+ readonly rule: string;
24
+ readonly why: string;
25
+ readonly provenance: readonly string[];
26
+ readonly first_learned: string;
27
+ readonly last_confirmed: string;
28
+ readonly confidence: LearningConfidence;
29
+ }
30
+ /**
31
+ * Estimate tokens deterministically without coupling the persisted contract to
32
+ * a model-specific tokenizer. A byte count is a conservative upper bound for
33
+ * byte-level tokenizers and is reproducible in both the writer and CI.
34
+ * @param content - Canonical full Markdown document
35
+ * @returns Reproducible estimated token count
36
+ */
37
+ export declare function estimateLearningTokens(content: string): number;
38
+ //# sourceMappingURL=learnings-contract.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"learnings-contract.d.ts","sourceRoot":"","sources":["../../src/core/learnings-contract.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,0BAA0B,oCAAqC,CAAC;AAE7E,+DAA+D;AAC/D,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,0BAA0B,CAAC,CAAC,MAAM,CAAC,CAAC;AAE7E,eAAO,MAAM,kBAAkB;;;;;;;;;EAiBpB,CAAC;AAEZ,0DAA0D;AAC1D,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,UAAU,EAAE,kBAAkB,CAAC;CACzC;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE9D"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Executable contract shared by every project-learnings writer and checker.
3
+ * Keeping the numeric limits here prevents documentation, writers, and CI
4
+ * from drifting to different budgets.
5
+ * @module learnings-contract
6
+ */
7
+ export const LEARNING_CONFIDENCE_VALUES = ["low", "medium", "high"];
8
+ export const LEARNINGS_CONTRACT = Object.freeze({
9
+ version: 1,
10
+ fields: Object.freeze([
11
+ "id",
12
+ "rule",
13
+ "why",
14
+ "provenance",
15
+ "first_learned",
16
+ "last_confirmed",
17
+ "confidence",
18
+ ]),
19
+ maxRuleCharacters: 240,
20
+ maxRuleLines: 2,
21
+ maxProvenanceReferences: 20,
22
+ maxEntries: 20,
23
+ maxTokens: 4000,
24
+ measurement: "utf8-bytes-upper-bound",
25
+ });
26
+ /**
27
+ * Estimate tokens deterministically without coupling the persisted contract to
28
+ * a model-specific tokenizer. A byte count is a conservative upper bound for
29
+ * byte-level tokenizers and is reproducible in both the writer and CI.
30
+ * @param content - Canonical full Markdown document
31
+ * @returns Reproducible estimated token count
32
+ */
33
+ export function estimateLearningTokens(content) {
34
+ return Buffer.byteLength(content, "utf8");
35
+ }
36
+ //# sourceMappingURL=learnings-contract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"learnings-contract.js","sourceRoot":"","sources":["../../src/core/learnings-contract.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,CAAU,CAAC;AAK7E,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAC,MAAM,CAAC;IAC9C,OAAO,EAAE,CAAC;IACV,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC;QACpB,IAAI;QACJ,MAAM;QACN,KAAK;QACL,YAAY;QACZ,eAAe;QACf,gBAAgB;QAChB,YAAY;KACJ,CAAC;IACX,iBAAiB,EAAE,GAAG;IACtB,YAAY,EAAE,CAAC;IACf,uBAAuB,EAAE,EAAE;IAC3B,UAAU,EAAE,EAAE;IACd,SAAS,EAAE,IAAI;IACf,WAAW,EAAE,wBAAwB;CAC7B,CAAC,CAAC;AAaZ;;;;;;GAMG;AACH,MAAM,UAAU,sBAAsB,CAAC,OAAe;IACpD,OAAO,MAAM,CAAC,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;AAC5C,CAAC"}
@@ -0,0 +1,9 @@
1
+ /** Strict validation for the seven-field project learning schema. */
2
+ import { type LearningEntry } from "./learnings-contract.js";
3
+ /**
4
+ * Validate an untrusted entry and return a normalized immutable copy.
5
+ * @param candidate - Value to validate against the executable contract
6
+ * @returns Validated learning entry
7
+ */
8
+ export declare function validateLearningEntry(candidate: unknown): LearningEntry;
9
+ //# sourceMappingURL=learnings-entry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"learnings-entry.d.ts","sourceRoot":"","sources":["../../src/core/learnings-entry.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,OAAO,EAIL,KAAK,aAAa,EACnB,MAAM,yBAAyB,CAAC;AAOjC;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,OAAO,GAAG,aAAa,CA0BvE"}
@@ -0,0 +1,233 @@
1
+ /** Strict validation for the seven-field project learning schema. */
2
+ import { LEARNINGS_CONTRACT, LEARNING_CONFIDENCE_VALUES, } from "./learnings-contract.js";
3
+ const ISO_DATE = /^\d{4}-\d{2}-\d{2}$/;
4
+ const STABLE_ID = /^[a-z0-9]+(?:[._-][a-z0-9]+)*$/;
5
+ /**
6
+ * Validate an untrusted entry and return a normalized immutable copy.
7
+ * @param candidate - Value to validate against the executable contract
8
+ * @returns Validated learning entry
9
+ */
10
+ export function validateLearningEntry(candidate) {
11
+ const descriptors = requireEntryDescriptors(candidate);
12
+ const value = (field) => readDataProperty(descriptors, field);
13
+ const id = requireStableId(value("id"));
14
+ const rule = requireRule(value("rule"));
15
+ const why = requireWhy(value("why"));
16
+ const provenance = requireProvenance(value("provenance"));
17
+ const firstLearned = requireIsoDate(value("first_learned"), "first_learned");
18
+ const lastConfirmed = requireIsoDate(value("last_confirmed"), "last_confirmed");
19
+ const confidence = requireConfidence(value("confidence"));
20
+ if (lastConfirmed < firstLearned) {
21
+ throw new Error("Invalid dates: last_confirmed precedes first_learned");
22
+ }
23
+ return Object.freeze({
24
+ id,
25
+ rule,
26
+ why,
27
+ provenance: Object.freeze(provenance),
28
+ first_learned: firstLearned,
29
+ last_confirmed: lastConfirmed,
30
+ confidence,
31
+ });
32
+ }
33
+ /**
34
+ * Require an object with exactly seven accessor-free own fields.
35
+ * @param candidate - Untrusted candidate object
36
+ * @returns Exact own-property descriptor map
37
+ */
38
+ function requireEntryDescriptors(candidate) {
39
+ if (candidate === null ||
40
+ typeof candidate !== "object" ||
41
+ Array.isArray(candidate)) {
42
+ throw new Error("Invalid learning entry: expected an object");
43
+ }
44
+ const descriptors = Object.getOwnPropertyDescriptors(candidate);
45
+ const ownKeys = Reflect.ownKeys(descriptors);
46
+ if (ownKeys.some(key => typeof key !== "string")) {
47
+ throw new Error("Invalid learning entry fields: symbol keys are not allowed");
48
+ }
49
+ if (ownKeys.length !== LEARNINGS_CONTRACT.fields.length ||
50
+ LEARNINGS_CONTRACT.fields.some(field => descriptors[field] === undefined)) {
51
+ throw new Error(`Invalid learning entry fields: expected exactly ${LEARNINGS_CONTRACT.fields.join(", ")}`);
52
+ }
53
+ return descriptors;
54
+ }
55
+ /**
56
+ * Read one exact-schema field without invoking an accessor.
57
+ * @param descriptors - Candidate descriptor map
58
+ * @param field - Required contract field
59
+ * @returns Stored data value
60
+ */
61
+ function readDataProperty(descriptors, field) {
62
+ const descriptor = descriptors[field];
63
+ if (descriptor === undefined || !("value" in descriptor)) {
64
+ throw new Error(`Invalid ${field}: accessors are not allowed`);
65
+ }
66
+ return descriptor.value;
67
+ }
68
+ /**
69
+ * Require and bound a stable learning id.
70
+ * @param value - Untrusted id value
71
+ * @returns Valid stable id
72
+ */
73
+ function requireStableId(value) {
74
+ const id = requireNonEmptyString(value, "id");
75
+ assertUtf8Budget(id, "id");
76
+ if (!STABLE_ID.test(id)) {
77
+ throw new Error("Invalid learning id: use lowercase letters, numbers, dots, underscores, or hyphens");
78
+ }
79
+ return id;
80
+ }
81
+ /**
82
+ * Require a rule within both hard character and line caps.
83
+ * @param value - Untrusted rule value
84
+ * @returns Valid bounded rule
85
+ */
86
+ function requireRule(value) {
87
+ const rule = requireNonEmptyString(value, "rule");
88
+ if (rule.length > LEARNINGS_CONTRACT.maxRuleCharacters) {
89
+ throw new Error(`rule exceeds maxRuleCharacters ${LEARNINGS_CONTRACT.maxRuleCharacters}`);
90
+ }
91
+ const ruleLines = rule
92
+ .replaceAll("\r\n", "\n")
93
+ .replaceAll("\r", "\n")
94
+ .replaceAll("\u0085", "\n")
95
+ .replaceAll("\u2028", "\n")
96
+ .replaceAll("\u2029", "\n")
97
+ .split("\n").length;
98
+ if (ruleLines > LEARNINGS_CONTRACT.maxRuleLines) {
99
+ throw new Error(`rule exceeds maxRuleLines ${LEARNINGS_CONTRACT.maxRuleLines}`);
100
+ }
101
+ return rule;
102
+ }
103
+ /**
104
+ * Require bounded explanatory text.
105
+ * @param value - Untrusted why value
106
+ * @returns Valid bounded explanation
107
+ */
108
+ function requireWhy(value) {
109
+ const why = requireNonBlankText(value, "why");
110
+ assertUtf8Budget(why, "why");
111
+ return why;
112
+ }
113
+ /**
114
+ * Validate a dense, accessor-free provenance list with bounded allocation.
115
+ * @param value - Untrusted provenance value
116
+ * @returns Valid provenance references
117
+ */
118
+ function requireProvenance(value) {
119
+ if (!Array.isArray(value)) {
120
+ throw new Error("Invalid provenance: expected an array of references");
121
+ }
122
+ const descriptors = Object.getOwnPropertyDescriptors(value);
123
+ const length = Object.getOwnPropertyDescriptor(value, "length")?.value;
124
+ if (typeof length !== "number" ||
125
+ !Number.isSafeInteger(length) ||
126
+ length < 1 ||
127
+ length > LEARNINGS_CONTRACT.maxProvenanceReferences) {
128
+ throw new Error(`Invalid provenance: expected 1-${LEARNINGS_CONTRACT.maxProvenanceReferences} references`);
129
+ }
130
+ const provenance = Array.from({ length }, (_unused, index) => requireProvenanceItem(descriptors, index));
131
+ if (new Set(provenance).size !== provenance.length) {
132
+ throw new Error("Invalid provenance: duplicate references are not allowed");
133
+ }
134
+ return provenance;
135
+ }
136
+ /**
137
+ * Read and bound one accessor-free provenance element.
138
+ * @param descriptors - Provenance array descriptors
139
+ * @param index - Reference index
140
+ * @returns Valid provenance reference
141
+ */
142
+ function requireProvenanceItem(descriptors, index) {
143
+ const descriptor = descriptors[String(index)];
144
+ if (descriptor === undefined || !("value" in descriptor)) {
145
+ throw new Error(`Invalid provenance[${index}]: accessors are not allowed`);
146
+ }
147
+ const reference = requireNonEmptyString(descriptor.value, `provenance[${index}]`);
148
+ assertUtf8Budget(reference, `provenance[${index}]`);
149
+ return reference;
150
+ }
151
+ /**
152
+ * Require one of the persisted confidence values.
153
+ * @param value - Untrusted confidence value
154
+ * @returns Valid confidence
155
+ */
156
+ function requireConfidence(value) {
157
+ if (typeof value !== "string" ||
158
+ !LEARNING_CONFIDENCE_VALUES.includes(value)) {
159
+ throw new Error(`Invalid confidence: expected ${LEARNING_CONFIDENCE_VALUES.join(" | ")}`);
160
+ }
161
+ return value;
162
+ }
163
+ /**
164
+ * Require a trimmed, non-empty, control-character-free string.
165
+ * @param value - Untrusted string value
166
+ * @param field - Field name for errors
167
+ * @returns Valid non-empty string
168
+ */
169
+ function requireNonEmptyString(value, field) {
170
+ if (typeof value !== "string" ||
171
+ value.length === 0 ||
172
+ value.trim() !== value ||
173
+ containsForbiddenTextControl(value)) {
174
+ throw new Error(`Invalid ${field}: expected a trimmed non-empty string`);
175
+ }
176
+ return value;
177
+ }
178
+ /**
179
+ * Require non-blank text and normalize its outer whitespace.
180
+ * @param value - Untrusted text value
181
+ * @param field - Field name for errors
182
+ * @returns Normalized non-blank text
183
+ */
184
+ function requireNonBlankText(value, field) {
185
+ if (typeof value !== "string" ||
186
+ value.trim().length === 0 ||
187
+ containsForbiddenTextControl(value)) {
188
+ throw new Error(`Invalid ${field}: expected non-blank text`);
189
+ }
190
+ return value.trim();
191
+ }
192
+ /**
193
+ * Require a real calendar date in ISO date form.
194
+ * @param value - Untrusted date value
195
+ * @param field - Field name for errors
196
+ * @returns Valid ISO date
197
+ */
198
+ function requireIsoDate(value, field) {
199
+ const result = requireNonEmptyString(value, field);
200
+ const date = new Date(`${result}T00:00:00.000Z`);
201
+ if (!ISO_DATE.test(result) ||
202
+ Number.isNaN(date.valueOf()) ||
203
+ date.toISOString().slice(0, 10) !== result) {
204
+ throw new Error(`Invalid ${field}: expected a real YYYY-MM-DD date`);
205
+ }
206
+ return result;
207
+ }
208
+ /**
209
+ * Bound individual untrusted fields before document rendering allocates them.
210
+ * @param value - Valid string value
211
+ * @param field - Field name for errors
212
+ */
213
+ function assertUtf8Budget(value, field) {
214
+ if (Buffer.byteLength(value, "utf8") > LEARNINGS_CONTRACT.maxTokens) {
215
+ throw new Error(`${field} exceeds maxTokens ${LEARNINGS_CONTRACT.maxTokens}`);
216
+ }
217
+ }
218
+ /**
219
+ * Reject non-whitespace controls while allowing rule line separators.
220
+ * @param value - Entry text
221
+ * @returns True when a forbidden control is present
222
+ */
223
+ function containsForbiddenTextControl(value) {
224
+ return Array.from(value).some(character => {
225
+ const code = character.charCodeAt(0);
226
+ return (code <= 8 ||
227
+ code === 11 ||
228
+ code === 12 ||
229
+ (code >= 14 && code <= 31) ||
230
+ code === 127);
231
+ });
232
+ }
233
+ //# sourceMappingURL=learnings-entry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"learnings-entry.js","sourceRoot":"","sources":["../../src/core/learnings-entry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Resolve the configured target without permitting project-root escape.
3
+ * @param projectRoot - Host project root
4
+ * @param relativeFile - Configured project-relative file
5
+ * @returns Resolved root and target paths
6
+ */
7
+ export declare function resolveSafeLearningTarget(projectRoot: string, relativeFile: string): {
8
+ readonly root: string;
9
+ readonly target: string;
10
+ };
11
+ /**
12
+ * Read only a bounded regular file from the inode that was safety-checked.
13
+ * @param target - Resolved learnings file path
14
+ * @returns Existing content, or undefined when the file does not exist
15
+ */
16
+ export declare function readExistingLearnings(target: string): Promise<string | undefined>;
17
+ /**
18
+ * Reject parent-directory symlinks that resolve outside the project root.
19
+ * @param root - Resolved project root
20
+ * @param parent - Target parent directory
21
+ */
22
+ export declare function assertSafeLearningParents(root: string, parent: string): Promise<void>;
23
+ //# sourceMappingURL=learnings-file-safety.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"learnings-file-safety.d.ts","sourceRoot":"","sources":["../../src/core/learnings-file-safety.ts"],"names":[],"mappings":"AAMA;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,GACnB;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CASpD;AAED;;;;GAIG;AACH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAmC7B;AAED;;;;GAIG;AACH,wBAAsB,yBAAyB,CAC7C,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,CAYf"}
@@ -0,0 +1,84 @@
1
+ /** Filesystem containment and safe reads for project learnings. */
2
+ import * as fse from "fs-extra";
3
+ import { lstat, open, realpath } from "node:fs/promises";
4
+ import * as path from "node:path";
5
+ import { LEARNINGS_CONTRACT } from "./learnings-contract.js";
6
+ /**
7
+ * Resolve the configured target without permitting project-root escape.
8
+ * @param projectRoot - Host project root
9
+ * @param relativeFile - Configured project-relative file
10
+ * @returns Resolved root and target paths
11
+ */
12
+ export function resolveSafeLearningTarget(projectRoot, relativeFile) {
13
+ const root = path.resolve(projectRoot);
14
+ const target = path.resolve(root, relativeFile);
15
+ if (target === root || !target.startsWith(`${root}${path.sep}`)) {
16
+ throw new Error("Unsafe projectRulesFile: learnings path escapes project root");
17
+ }
18
+ return { root, target };
19
+ }
20
+ /**
21
+ * Read only a bounded regular file from the inode that was safety-checked.
22
+ * @param target - Resolved learnings file path
23
+ * @returns Existing content, or undefined when the file does not exist
24
+ */
25
+ export async function readExistingLearnings(target) {
26
+ try {
27
+ const beforeOpen = await lstat(target);
28
+ if (!beforeOpen.isFile()) {
29
+ throw new Error("Unsafe project learnings path: target is not a regular file");
30
+ }
31
+ const handle = await open(target, "r");
32
+ try {
33
+ const opened = await handle.stat();
34
+ if (!opened.isFile() ||
35
+ opened.dev !== beforeOpen.dev ||
36
+ opened.ino !== beforeOpen.ino) {
37
+ throw new Error("Unsafe project learnings path: target changed during open");
38
+ }
39
+ if (opened.size > LEARNINGS_CONTRACT.maxTokens) {
40
+ throw new Error(`Project learnings payload exceeds maxTokens ${LEARNINGS_CONTRACT.maxTokens}`);
41
+ }
42
+ return handle.readFile({ encoding: "utf8" });
43
+ }
44
+ finally {
45
+ await handle.close();
46
+ }
47
+ }
48
+ catch (error) {
49
+ if (error.code === "ENOENT") {
50
+ return undefined;
51
+ }
52
+ throw error;
53
+ }
54
+ }
55
+ /**
56
+ * Reject parent-directory symlinks that resolve outside the project root.
57
+ * @param root - Resolved project root
58
+ * @param parent - Target parent directory
59
+ */
60
+ export async function assertSafeLearningParents(root, parent) {
61
+ const realRoot = await realpath(root);
62
+ const cursor = await findExistingAncestor(parent);
63
+ const realParent = await realpath(cursor);
64
+ if (realParent !== realRoot &&
65
+ !realParent.startsWith(`${realRoot}${path.sep}`)) {
66
+ throw new Error("Unsafe project learnings path: parent escapes project root");
67
+ }
68
+ }
69
+ /**
70
+ * Find the nearest existing ancestor without mutable traversal state.
71
+ * @param candidate - Starting filesystem path
72
+ * @returns Nearest existing ancestor
73
+ */
74
+ async function findExistingAncestor(candidate) {
75
+ if (await fse.pathExists(candidate)) {
76
+ return candidate;
77
+ }
78
+ const parent = path.dirname(candidate);
79
+ if (parent === candidate) {
80
+ throw new Error("Unsafe project learnings path: no project ancestor");
81
+ }
82
+ return findExistingAncestor(parent);
83
+ }
84
+ //# sourceMappingURL=learnings-file-safety.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"learnings-file-safety.js","sourceRoot":"","sources":["../../src/core/learnings-file-safety.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Serialize same-target writers across processes with an exclusive hard link.
3
+ * @param target - Absolute learnings target
4
+ * @param operation - Complete read, validate, and atomic-write transaction
5
+ * @returns Operation result
6
+ */
7
+ export declare function withLearningTargetLock<T>(target: string, operation: () => Promise<T>): Promise<T>;
8
+ //# sourceMappingURL=learnings-lock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"learnings-lock.d.ts","sourceRoot":"","sources":["../../src/core/learnings-lock.ts"],"names":[],"mappings":"AAoBA;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAAC,CAAC,EAC5C,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAC1B,OAAO,CAAC,CAAC,CAAC,CAaZ"}