kibi-cli 0.11.1 → 0.12.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 (76) hide show
  1. package/dist/commands/check.d.ts.map +1 -1
  2. package/dist/commands/check.js +1 -1
  3. package/dist/commands/init-helpers.d.ts.map +1 -1
  4. package/dist/commands/init-helpers.js +2 -3
  5. package/dist/commands/migrate.d.ts.map +1 -1
  6. package/dist/commands/migrate.js +7 -2
  7. package/dist/commands/skills.d.ts.map +1 -1
  8. package/dist/commands/sync/manifest.d.ts +1 -1
  9. package/dist/commands/sync/manifest.d.ts.map +1 -1
  10. package/dist/commands/sync/manifest.js +7 -4
  11. package/dist/commands/sync/staging.d.ts.map +1 -1
  12. package/dist/commands/sync/staging.js +2 -1
  13. package/dist/commands/sync.d.ts.map +1 -1
  14. package/dist/commands/sync.js +3 -1
  15. package/dist/extractors/manifest.d.ts.map +1 -1
  16. package/dist/extractors/manifest.js +3 -1
  17. package/dist/extractors/symbol-coordinates.d.ts.map +1 -1
  18. package/dist/extractors/symbol-coordinates.js +1 -1
  19. package/dist/extractors/symbols-coordinator.d.ts.map +1 -1
  20. package/dist/extractors/symbols-coordinator.js +2 -1
  21. package/dist/extractors/symbols-ts.d.ts.map +1 -1
  22. package/dist/extractors/symbols-ts.js +3 -1
  23. package/dist/prolog.d.ts.map +1 -1
  24. package/dist/prolog.js +14 -1
  25. package/dist/public/ignore-policy.d.ts.map +1 -1
  26. package/dist/public/ignore-policy.js +8 -4
  27. package/dist/public/operational-artifacts.d.ts.map +1 -1
  28. package/dist/public/operational-artifacts.js +1 -0
  29. package/dist/public/schemas/entity.d.ts +1 -127
  30. package/dist/public/schemas/entity.d.ts.map +1 -1
  31. package/dist/public/schemas/entity.js +79 -2
  32. package/dist/public/schemas/relationship.d.ts.map +1 -1
  33. package/dist/public/schemas/relationship.js +1 -0
  34. package/dist/public/skills/kibi-usage/SKILL.md +80 -0
  35. package/dist/public/skills/kibi-usage/resources/fact-lanes.md +78 -0
  36. package/dist/public/skills/kibi-usage/resources/workflows.md +0 -7
  37. package/dist/public/skills.d.ts.map +1 -1
  38. package/dist/public/skills.js +12 -4
  39. package/dist/schemas/entity.schema.json +81 -4
  40. package/dist/search-ranking.d.ts.map +1 -1
  41. package/dist/traceability/evidence-model.d.ts.map +1 -1
  42. package/dist/traceability/staged-diagnostics.d.ts.map +1 -1
  43. package/dist/traceability/staged-diagnostics.js +1 -1
  44. package/dist/traceability/staged-symbols-manifest.d.ts.map +1 -1
  45. package/dist/traceability/staged-symbols-manifest.js +8 -2
  46. package/dist/traceability/symbol-extract.d.ts.map +1 -1
  47. package/dist/traceability/symbol-extract.js +4 -1
  48. package/dist/types/entities.d.ts +11 -2
  49. package/dist/types/entities.d.ts.map +1 -1
  50. package/dist/types/relationships.d.ts +1 -1
  51. package/dist/types/relationships.d.ts.map +1 -1
  52. package/dist/utils/config.d.ts +3 -18
  53. package/dist/utils/config.d.ts.map +1 -1
  54. package/dist/utils/config.js +4 -40
  55. package/dist/utils/manifest-paths.d.ts.map +1 -1
  56. package/dist/utils/manifest-paths.js +3 -1
  57. package/dist/utils/schema-version.d.ts.map +1 -1
  58. package/dist/utils/strict-modeling.d.ts +1 -1
  59. package/dist/utils/strict-modeling.d.ts.map +1 -1
  60. package/dist/utils/strict-modeling.js +13 -3
  61. package/package.json +3 -13
  62. package/schema/config.json +0 -68
  63. package/src/public/ignore-policy.ts +26 -10
  64. package/src/public/operational-artifacts.ts +2 -1
  65. package/src/public/schemas/entity.ts +89 -5
  66. package/src/public/schemas/relationship.ts +1 -0
  67. package/src/public/skills/kibi-usage/SKILL.md +80 -0
  68. package/src/public/skills/kibi-usage/resources/fact-lanes.md +78 -0
  69. package/src/public/skills/kibi-usage/resources/workflows.md +0 -7
  70. package/src/public/skills.ts +93 -25
  71. package/src/schemas/entity.schema.json +81 -4
  72. package/src/schemas/relationship.schema.json +1 -0
  73. package/dist/public/brief-config.d.ts +0 -4
  74. package/dist/public/brief-config.d.ts.map +0 -1
  75. package/dist/public/brief-config.js +0 -21
  76. package/src/public/brief-config.ts +0 -25
@@ -24,6 +24,84 @@ value_type: int
24
24
  value_int: 3
25
25
  ```
26
26
 
27
+ ## Granular Facts for Coherence Checks
28
+
29
+ Granular strict facts work best when each `property_value` represents one semantic claim about one `subject_key` and one `property_key`. This lets `domain-contradictions` compare current requirements that constrain the same subject and require incompatible values.
30
+
31
+ ### Role set conflict
32
+
33
+ `REQ-ROLE-SET-2` and `REQ-ROLE-SET-3` are incoherent if both are current: they each define the exact allowed role set, but one allows two roles and the other allows three.
34
+
35
+ ```yaml
36
+ subject:
37
+ id: FACT-USER-ROLES
38
+ title: User roles
39
+ status: active
40
+ fact_kind: subject
41
+ subject_key: user.roles
42
+
43
+ property_values:
44
+ - id: FACT-USER-ROLES-ALLOWED-2
45
+ title: User and admin roles only
46
+ status: active
47
+ fact_kind: property_value
48
+ subject_key: user.roles
49
+ property_key: user.roles.allowed_set
50
+ operator: eq
51
+ value_type: list
52
+ value_json: '["user", "admin"]'
53
+ - id: FACT-USER-ROLES-ALLOWED-3
54
+ title: User, admin, and superadmin roles
55
+ status: active
56
+ fact_kind: property_value
57
+ subject_key: user.roles
58
+ property_key: user.roles.allowed_set
59
+ operator: eq
60
+ value_type: list
61
+ value_json: '["user", "admin", "superadmin"]'
62
+
63
+ relationships:
64
+ - { type: constrains, from: REQ-ROLE-SET-2, to: FACT-USER-ROLES }
65
+ - { type: requires_property, from: REQ-ROLE-SET-2, to: FACT-USER-ROLES-ALLOWED-2 }
66
+ - { type: constrains, from: REQ-ROLE-SET-3, to: FACT-USER-ROLES }
67
+ - { type: requires_property, from: REQ-ROLE-SET-3, to: FACT-USER-ROLES-ALLOWED-3 }
68
+ ```
69
+
70
+ ### Permission actor conflict
71
+
72
+ `REQ-ADMIN-CAN-MANAGE-BILLING` and `REQ-ONLY-SUPERADMIN-MANAGES-BILLING` conflict when both define the exact allowed actor for the same permission.
73
+
74
+ ```yaml
75
+ subject:
76
+ id: FACT-BILLING-MANAGE
77
+ title: Billing management permission
78
+ status: active
79
+ fact_kind: subject
80
+ subject_key: billing.manage
81
+
82
+ property_values:
83
+ - id: FACT-BILLING-MANAGE-ACTOR-ADMIN
84
+ title: Admin can manage billing
85
+ status: active
86
+ fact_kind: property_value
87
+ subject_key: billing.manage
88
+ property_key: billing.manage.allowed_actor
89
+ operator: eq
90
+ value_type: string
91
+ value_string: admin
92
+ - id: FACT-BILLING-MANAGE-ACTOR-SUPERADMIN
93
+ title: Only superadmin can manage billing
94
+ status: active
95
+ fact_kind: property_value
96
+ subject_key: billing.manage
97
+ property_key: billing.manage.allowed_actor
98
+ operator: eq
99
+ value_type: string
100
+ value_string: superadmin
101
+ ```
102
+
103
+ When a contradiction is intentional evolution rather than a real conflict, link the replaced requirement to the replacement requirement with `supersedes`.
104
+
27
105
  ## Context Lane (Non-Blocking)
28
106
 
29
107
  ### fact_kind: observation
@@ -26,10 +26,3 @@ The canonical workflow for any KB operation follows this pattern:
26
26
  3. kb_upsert to add missing relationship rows (sequential)
27
27
  4. kb_check with rules: ["no-dangling-refs", "symbol-traceability"]
28
28
  ```
29
-
30
- ## Before Risky Work
31
- ```
32
- 1. /brief-kibi or kb_briefing_generate for citation-backed briefing
33
- 2. Inspect briefingState; proceed only if ready
34
- 3. Use constraints, regressionRisks, and cited entities from the briefing
35
- ```
@@ -84,14 +84,17 @@ export class SkillOversizeError extends Error {
84
84
  readonly actualBytes: number;
85
85
 
86
86
  constructor(pathLike: string, maxBytes: number, actualBytes: number) {
87
- super(`Skill file exceeds ${maxBytes} bytes: ${pathLike} (${actualBytes} bytes)`);
87
+ super(
88
+ `Skill file exceeds ${maxBytes} bytes: ${pathLike} (${actualBytes} bytes)`,
89
+ );
88
90
  this.name = "SkillOversizeError";
89
91
  this.maxBytes = maxBytes;
90
92
  this.actualBytes = actualBytes;
91
93
  }
92
94
  }
93
95
 
94
- export function listBundledSkills(): SkillManifest[] { // implements REQ-001
96
+ export function listBundledSkills(): SkillManifest[] {
97
+ // implements REQ-001
95
98
  if (!existsSync(bundledSkillsDir)) {
96
99
  return [];
97
100
  }
@@ -104,7 +107,8 @@ export function listBundledSkills(): SkillManifest[] { // implements REQ-001
104
107
  .sort((left, right) => left.id.localeCompare(right.id));
105
108
  }
106
109
 
107
- export function loadBundledSkill(id: string): SkillBundle { // implements REQ-001
110
+ export function loadBundledSkill(id: string): SkillBundle {
111
+ // implements REQ-001
108
112
  const rootDir = findBundledSkillRoot(id);
109
113
  if (!rootDir) {
110
114
  throw new SkillNotFoundError(id);
@@ -116,7 +120,8 @@ export function loadBundledSkill(id: string): SkillBundle { // implements REQ-00
116
120
  export function readBundledSkillResource(
117
121
  id: string,
118
122
  resourcePath: string,
119
- ): string { // implements REQ-001
123
+ ): string {
124
+ // implements REQ-001
120
125
  const bundle = loadBundledSkill(id);
121
126
  const declaredResource = normalizeResourcePath(resourcePath);
122
127
 
@@ -146,14 +151,18 @@ export function readBundledSkillResource(
146
151
  return readFileSync(candidatePath, "utf8");
147
152
  }
148
153
 
149
- export function validateSkillBundle(
150
- pathLike: string,
151
- ): { valid: boolean; errors: SkillValidationError[] } { // implements REQ-001
154
+ export function validateSkillBundle(pathLike: string): {
155
+ valid: boolean;
156
+ errors: SkillValidationError[];
157
+ } {
158
+ // implements REQ-001
152
159
  const skillFilePath = resolveSkillFilePath(pathLike);
153
160
  const errors: SkillValidationError[] = [];
154
161
 
155
162
  if (!existsSync(skillFilePath)) {
156
- errors.push(new SkillValidationError("SKILL.md", `Missing ${SKILL_FILE_NAME}`));
163
+ errors.push(
164
+ new SkillValidationError("SKILL.md", `Missing ${SKILL_FILE_NAME}`),
165
+ );
157
166
  return { valid: false, errors };
158
167
  }
159
168
 
@@ -175,7 +184,12 @@ function validateBundleContents(
175
184
  try {
176
185
  assertMaxBytes(skillFilePath, SKILL_MARKDOWN_MAX_BYTES);
177
186
  } catch (error) {
178
- errors.push(new SkillValidationError("SKILL.md", error instanceof Error ? error.message : String(error)));
187
+ errors.push(
188
+ new SkillValidationError(
189
+ "SKILL.md",
190
+ error instanceof Error ? error.message : String(error),
191
+ ),
192
+ );
179
193
  }
180
194
 
181
195
  const rootDir = dirname(skillFilePath);
@@ -183,7 +197,12 @@ function validateBundleContents(
183
197
  try {
184
198
  realRootDir = realpathSync(rootDir);
185
199
  } catch (error) {
186
- errors.push(new SkillValidationError("SKILL.md", error instanceof Error ? error.message : String(error)));
200
+ errors.push(
201
+ new SkillValidationError(
202
+ "SKILL.md",
203
+ error instanceof Error ? error.message : String(error),
204
+ ),
205
+ );
187
206
  return;
188
207
  }
189
208
 
@@ -191,19 +210,34 @@ function validateBundleContents(
191
210
  const resourcePath = resolve(rootDir, resource);
192
211
  try {
193
212
  if (!existsSync(resourcePath)) {
194
- errors.push(new SkillValidationError("resources", `Missing skill resource: ${resource}`));
213
+ errors.push(
214
+ new SkillValidationError(
215
+ "resources",
216
+ `Missing skill resource: ${resource}`,
217
+ ),
218
+ );
195
219
  continue;
196
220
  }
197
221
 
198
222
  const realResourcePath = realpathSync(resourcePath);
199
223
  if (!isWithinRoot(realRootDir, realResourcePath)) {
200
- errors.push(new SkillValidationError("resources", `Skill resource escapes bundle root: ${resource}`));
224
+ errors.push(
225
+ new SkillValidationError(
226
+ "resources",
227
+ `Skill resource escapes bundle root: ${resource}`,
228
+ ),
229
+ );
201
230
  continue;
202
231
  }
203
232
 
204
233
  assertMaxBytes(resourcePath, RESOURCE_MAX_BYTES);
205
234
  } catch (error) {
206
- errors.push(new SkillValidationError("resources", error instanceof Error ? error.message : String(error)));
235
+ errors.push(
236
+ new SkillValidationError(
237
+ "resources",
238
+ error instanceof Error ? error.message : String(error),
239
+ ),
240
+ );
207
241
  }
208
242
  }
209
243
  }
@@ -250,7 +284,9 @@ function parseSkillBundle(rootDir: string): SkillBundle {
250
284
  };
251
285
  }
252
286
 
253
- function validateManifestData(data: Record<string, unknown>): SkillValidationError[] {
287
+ function validateManifestData(
288
+ data: Record<string, unknown>,
289
+ ): SkillValidationError[] {
254
290
  const errors: SkillValidationError[] = [];
255
291
  const requiredFields = [
256
292
  "id",
@@ -262,12 +298,25 @@ function validateManifestData(data: Record<string, unknown>): SkillValidationErr
262
298
 
263
299
  for (const field of requiredFields) {
264
300
  if (typeof data[field] !== "string" || data[field].trim() === "") {
265
- errors.push(new SkillValidationError(field, `Missing required skill field: ${field}`));
301
+ errors.push(
302
+ new SkillValidationError(
303
+ field,
304
+ `Missing required skill field: ${field}`,
305
+ ),
306
+ );
266
307
  }
267
308
  }
268
309
 
269
- if (typeof data.version === "string" && !/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/.test(data.version)) {
270
- errors.push(new SkillValidationError("version", `Invalid skill version: ${data.version}`));
310
+ if (
311
+ typeof data.version === "string" &&
312
+ !/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/.test(data.version)
313
+ ) {
314
+ errors.push(
315
+ new SkillValidationError(
316
+ "version",
317
+ `Invalid skill version: ${data.version}`,
318
+ ),
319
+ );
271
320
  }
272
321
 
273
322
  if (data.tags !== undefined && !isStringArray(data.tags)) {
@@ -276,13 +325,21 @@ function validateManifestData(data: Record<string, unknown>): SkillValidationErr
276
325
 
277
326
  if (data.resources !== undefined) {
278
327
  if (!isStringArray(data.resources)) {
279
- errors.push(new SkillValidationError("resources", "Skill resources must be strings"));
328
+ errors.push(
329
+ new SkillValidationError(
330
+ "resources",
331
+ "Skill resources must be strings",
332
+ ),
333
+ );
280
334
  } else {
281
335
  for (const resource of data.resources) {
282
336
  const normalized = normalizeResourcePath(resource);
283
337
  if (!normalized || isPathOutOfBounds(resource)) {
284
338
  errors.push(
285
- new SkillValidationError("resources", `Invalid skill resource: ${resource}`),
339
+ new SkillValidationError(
340
+ "resources",
341
+ `Invalid skill resource: ${resource}`,
342
+ ),
286
343
  );
287
344
  }
288
345
  }
@@ -306,14 +363,18 @@ function coerceManifest(data: Record<string, unknown>): SkillManifest {
306
363
  }
307
364
 
308
365
  if (isStringArray(data.resources)) {
309
- manifest.resources = data.resources.map((resource) => normalizeResourcePath(resource));
366
+ manifest.resources = data.resources.map((resource) =>
367
+ normalizeResourcePath(resource),
368
+ );
310
369
  }
311
370
 
312
371
  return manifest;
313
372
  }
314
373
 
315
374
  function isStringArray(value: unknown): value is string[] {
316
- return Array.isArray(value) && value.every((item) => typeof item === "string");
375
+ return (
376
+ Array.isArray(value) && value.every((item) => typeof item === "string")
377
+ );
317
378
  }
318
379
 
319
380
  function normalizeResourcePath(pathLike: string): string {
@@ -330,7 +391,10 @@ function isPathOutOfBounds(pathLike: string): boolean {
330
391
  );
331
392
  }
332
393
 
333
- function isDeclaredResource(manifest: SkillManifest, resourcePath: string): boolean {
394
+ function isDeclaredResource(
395
+ manifest: SkillManifest,
396
+ resourcePath: string,
397
+ ): boolean {
334
398
  return (manifest.resources ?? []).some(
335
399
  (declared) => normalizeResourcePath(declared) === resourcePath,
336
400
  );
@@ -338,7 +402,10 @@ function isDeclaredResource(manifest: SkillManifest, resourcePath: string): bool
338
402
 
339
403
  function isWithinRoot(rootDir: string, candidatePath: string): boolean {
340
404
  const relativePath = relative(rootDir, candidatePath);
341
- return relativePath === "" || (!relativePath.startsWith("..") && !isAbsolute(relativePath));
405
+ return (
406
+ relativePath === "" ||
407
+ (!relativePath.startsWith("..") && !isAbsolute(relativePath))
408
+ );
342
409
  }
343
410
 
344
411
  function assertMaxBytes(pathLike: string, maxBytes: number): void {
@@ -354,6 +421,7 @@ function resolveSkillFilePath(pathLike: string): string {
354
421
  return join(resolved, SKILL_FILE_NAME);
355
422
  }
356
423
 
357
- return resolved.endsWith(SKILL_FILE_NAME) ? resolved : join(resolved, SKILL_FILE_NAME);
424
+ return resolved.endsWith(SKILL_FILE_NAME)
425
+ ? resolved
426
+ : join(resolved, SKILL_FILE_NAME);
358
427
  }
359
-
@@ -62,7 +62,14 @@
62
62
  },
63
63
  "fact_kind": {
64
64
  "type": "string",
65
- "enum": ["subject", "property_value", "observation", "meta"]
65
+ "enum": [
66
+ "subject",
67
+ "property_value",
68
+ "observation",
69
+ "meta",
70
+ "predicate_schema",
71
+ "predicate"
72
+ ]
66
73
  },
67
74
  "subject_key": { "type": "string" },
68
75
  "property_key": { "type": "string" },
@@ -80,11 +87,26 @@
80
87
  "value_bool": { "type": "boolean" },
81
88
  "unit": { "type": "string" },
82
89
  "scope": { "type": "string" },
83
- "polarity": { "type": "string", "enum": ["require", "forbid"] },
90
+ "polarity": {
91
+ "type": "string",
92
+ "enum": ["require", "forbid", "assert", "deny"]
93
+ },
84
94
  "closed_world": { "type": "boolean" },
85
95
  "valid_from": { "type": "string" },
86
96
  "valid_to": { "type": "string" },
87
- "canonical_key": { "type": "string" }
97
+ "canonical_key": { "type": "string" },
98
+ "predicate_name": { "type": "string" },
99
+ "predicate_namespace": { "type": "string" },
100
+ "predicate_arity": { "type": "integer", "minimum": 1 },
101
+ "argument_names": { "type": "array", "items": { "type": "string" } },
102
+ "argument_types": { "type": "array", "items": { "type": "string" } },
103
+ "argument_descriptions": {
104
+ "type": "array",
105
+ "items": { "type": "string" }
106
+ },
107
+ "aliases": { "type": "array", "items": { "type": "string" } },
108
+ "examples": { "type": "array", "items": { "type": "string" } },
109
+ "predicate_args": { "type": "array", "items": { "type": "string" } }
88
110
  },
89
111
  "required": [
90
112
  "id",
@@ -133,10 +155,65 @@
133
155
  { "required": ["closed_world"] },
134
156
  { "required": ["valid_from"] },
135
157
  { "required": ["valid_to"] },
136
- { "required": ["canonical_key"] }
158
+ { "required": ["canonical_key"] },
159
+ { "required": ["predicate_name"] },
160
+ { "required": ["predicate_namespace"] },
161
+ { "required": ["predicate_arity"] },
162
+ { "required": ["argument_names"] },
163
+ { "required": ["argument_types"] },
164
+ { "required": ["argument_descriptions"] },
165
+ { "required": ["aliases"] },
166
+ { "required": ["examples"] },
167
+ { "required": ["predicate_args"] }
137
168
  ]
138
169
  }
139
170
  }
171
+ },
172
+ {
173
+ "if": {
174
+ "properties": {
175
+ "type": { "const": "fact" },
176
+ "fact_kind": { "const": "predicate_schema" }
177
+ },
178
+ "required": ["type", "fact_kind"]
179
+ },
180
+ "then": {
181
+ "required": [
182
+ "predicate_name",
183
+ "predicate_arity",
184
+ "argument_names",
185
+ "argument_types"
186
+ ]
187
+ }
188
+ },
189
+ {
190
+ "if": {
191
+ "properties": {
192
+ "type": { "const": "fact" },
193
+ "fact_kind": { "const": "predicate" }
194
+ },
195
+ "required": ["type", "fact_kind"]
196
+ },
197
+ "then": {
198
+ "required": ["predicate_name", "predicate_args", "canonical_key"],
199
+ "properties": {
200
+ "polarity": { "enum": ["assert", "deny"] }
201
+ }
202
+ }
203
+ },
204
+ {
205
+ "if": {
206
+ "properties": {
207
+ "type": { "const": "fact" },
208
+ "fact_kind": { "const": "property_value" }
209
+ },
210
+ "required": ["type", "fact_kind"]
211
+ },
212
+ "then": {
213
+ "properties": {
214
+ "polarity": { "enum": ["require", "forbid"] }
215
+ }
216
+ }
140
217
  }
141
218
  ],
142
219
  "additionalProperties": false
@@ -16,6 +16,7 @@
16
16
  "constrained_by",
17
17
  "constrains",
18
18
  "requires_property",
19
+ "requires_predicate",
19
20
  "guards",
20
21
  "publishes",
21
22
  "consumes",
@@ -1,4 +0,0 @@
1
- import { type BriefsConfig } from "../utils/config.js";
2
- export type { BriefsConfig } from "../utils/config.js";
3
- export declare function loadBriefConfig(cwd?: string): BriefsConfig;
4
- //# sourceMappingURL=brief-config.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"brief-config.d.ts","sourceRoot":"","sources":["../../src/public/brief-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEnE,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,wBAAgB,eAAe,CAAC,GAAG,GAAE,MAAsB,GAAG,YAAY,CAoBzE"}
@@ -1,21 +0,0 @@
1
- import { loadConfig } from "../utils/config.js";
2
- export function loadBriefConfig(cwd = process.cwd()) {
3
- const briefs = loadConfig(cwd).briefs;
4
- return {
5
- enabled: briefs?.enabled ?? true,
6
- retention: {
7
- maxPerBranch: briefs?.retention?.maxPerBranch ?? 200,
8
- maxAgeDays: briefs?.retention?.maxAgeDays ?? 14,
9
- keepUnread: briefs?.retention?.keepUnread ?? true,
10
- },
11
- channels: {
12
- vscode: briefs?.channels?.vscode ?? true,
13
- tui: briefs?.channels?.tui ?? true,
14
- },
15
- tui: {
16
- toast: briefs?.tui?.toast ?? true,
17
- appendPrompt: briefs?.tui?.appendPrompt ?? true,
18
- idleDelayMs: briefs?.tui?.idleDelayMs ?? 1500,
19
- },
20
- };
21
- }
@@ -1,25 +0,0 @@
1
- import { loadConfig, type BriefsConfig } from "../utils/config.js";
2
-
3
- export type { BriefsConfig } from "../utils/config.js";
4
-
5
- export function loadBriefConfig(cwd: string = process.cwd()): BriefsConfig { // implements REQ-003
6
- const briefs = loadConfig(cwd).briefs;
7
-
8
- return {
9
- enabled: briefs?.enabled ?? true,
10
- retention: {
11
- maxPerBranch: briefs?.retention?.maxPerBranch ?? 200,
12
- maxAgeDays: briefs?.retention?.maxAgeDays ?? 14,
13
- keepUnread: briefs?.retention?.keepUnread ?? true,
14
- },
15
- channels: {
16
- vscode: briefs?.channels?.vscode ?? true,
17
- tui: briefs?.channels?.tui ?? true,
18
- },
19
- tui: {
20
- toast: briefs?.tui?.toast ?? true,
21
- appendPrompt: briefs?.tui?.appendPrompt ?? true,
22
- idleDelayMs: briefs?.tui?.idleDelayMs ?? 1500,
23
- },
24
- };
25
- }