@dev-loops/core 0.1.1 → 0.1.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dev-loops/core",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "type": "module",
5
5
  "description": "Shared deterministic support package for dev-loop skills, repo-local scripts, and GitHub automation.",
6
6
  "exports": {
@@ -53,6 +53,7 @@
53
53
  },
54
54
  "files": [
55
55
  "src/**/*.mjs",
56
+ "src/**/*.yaml",
56
57
  "bin/**/*.mjs"
57
58
  ],
58
59
  "scripts": {
@@ -1,6 +1,7 @@
1
1
  import { readFile } from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  import { parse as parseYaml } from "yaml";
4
+ import { fileURLToPath } from "node:url";
4
5
  import { z } from "zod";
5
6
 
6
7
  // ============================================================================
@@ -302,11 +303,25 @@ export function resolveReviewerRole(config, angle) {
302
303
  * @typedef {object} ConfigLoadError
303
304
  * @property {string} path - Human-readable file path or layer name
304
305
  * @property {string} message - Error description
305
- * @property {"defaults"|"settings"|"merged"} layer - Which config layer failed
306
+ * @property {"defaults"|"settings"|"extensionDefaults"|"merged"} layer - Which config layer failed
306
307
  */
307
308
 
308
309
  // ============================================================================
309
310
  // Helpers
311
+
312
+ /**
313
+ * Resolve the base path (without extension) for extension-packaged defaults.
314
+ * In normal use the file lives next to config.mjs inside the installed package.
315
+ * Tests can override this via `options.extensionDefaultsBasePath`.
316
+ * @param {{ extensionDefaultsBasePath?: string }} [options]
317
+ * @returns {string}
318
+ */
319
+ function resolveExtensionDefaultsPath(options = {}) {
320
+ if (options.extensionDefaultsBasePath) return options.extensionDefaultsBasePath;
321
+ const moduleDir = path.dirname(fileURLToPath(import.meta.url));
322
+ return path.join(moduleDir, "extension-defaults");
323
+ }
324
+
310
325
  // ============================================================================
311
326
 
312
327
  /**
@@ -490,7 +505,7 @@ async function applyLayer(merged, basePaths, layer, warnings, errors, options =
490
505
 
491
506
  if (data === null) {
492
507
  if (options.warnOnMissing) {
493
- warnings.push(`Committed ${layer} config not found (tried .yaml, .yml, and .json), using built-in defaults`);
508
+ warnings.push(`${layer} config not found (tried .yaml, .yml, and .json), falling back to previously merged defaults`);
494
509
  }
495
510
  return merged;
496
511
  }
@@ -523,14 +538,15 @@ async function applyLayer(merged, basePaths, layer, warnings, errors, options =
523
538
  /**
524
539
  * @typedef {object} LoadOptions
525
540
  * @property {string} [repoRoot] - Path to repository root (default: process.cwd())
541
+ * @property {string} [extensionDefaultsBasePath] - Base path (no extension) to extension defaults; overrides the package-relative default
526
542
  */
527
543
 
528
544
  /**
529
545
  * Load the dev-loop configuration with full precedence:
530
- * settings.(yaml|yml|json) > legacy overrides.(yaml|yml|json) > defaults.(yaml|yml|json) > built-in defaults
546
+ * settings.(yaml|yml|json) > legacy overrides.(yaml|yml|json) > repo .pi/dev-loop/defaults.(yaml|yml|json) > extension defaults > built-in defaults
531
547
  *
532
548
  * Never throws for config-related problems.
533
- * Returns built-in defaults even when all files are missing or broken.
549
+ * Returns extension defaults (with built-in defaults as the final fallback) even when all repo-local config files are missing or broken.
534
550
  *
535
551
  * @param {LoadOptions} [options]
536
552
  * @returns {Promise<LoadResult>}
@@ -548,6 +564,8 @@ export async function loadDevLoopConfig(options = {}) {
548
564
  const errors = [];
549
565
 
550
566
  let merged = { ...BUILT_IN_DEFAULTS };
567
+ merged = await applyLayer(merged, resolveExtensionDefaultsPath(options), "extensionDefaults", warnings, errors, { warnOnMissing: true });
568
+
551
569
 
552
570
  merged = await applyLayer(merged, defaultsPath, "defaults", warnings, errors, {
553
571
  warnOnMissing: true,
@@ -0,0 +1,461 @@
1
+ version: 1
2
+
3
+ # Extension-packaged defaults shipped inside @dev-loops/core.
4
+ # Precedence: built-in defaults < extension defaults < repo .pi/dev-loop/defaults.* < repo .devloops
5
+
6
+ # Default strategy: extension intends local-first; consumers can still override via repo defaults.
7
+ strategy:
8
+ default: local-first
9
+
10
+ # Local-first input source: tracker issues vs phase docs.
11
+ inputSource:
12
+ default: tracker
13
+
14
+ # Refinement fan-out defaults.
15
+ refinement:
16
+ fanOut: 3
17
+ mode: parallel
18
+ maxCopilotRounds: 5
19
+ stopOnLowSignal: false
20
+ lowSignalRoundThreshold: 3
21
+ lowSignalMaxComments: 2
22
+ roles:
23
+ - scope
24
+ - coverage
25
+ - dry
26
+ - kiss
27
+
28
+ # Gate review angle definitions for all consumers.
29
+ gates:
30
+ draft:
31
+ angles:
32
+ - scope
33
+ - coverage
34
+ - correctness
35
+ - ci-guard
36
+ - contract-surface
37
+ - link-check
38
+ - config-drift
39
+ - gate-evidence
40
+ - no-op
41
+ - input-validation
42
+ - packaging-runtime
43
+ - state-concurrency
44
+ - renderer-security
45
+ - determinism
46
+ - pr-comments
47
+ excludeAngles: []
48
+ required: true
49
+ requireCi: true
50
+ mandatoryAngles:
51
+ - pr-description
52
+ preApproval:
53
+ angles:
54
+ - dry
55
+ - kiss
56
+ - yagni
57
+ - srp
58
+ - soc
59
+ - deep
60
+ - ocp
61
+ - lsp
62
+ - isp
63
+ - dip
64
+ - docs
65
+ - pr-checklist-matrix
66
+ excludeAngles: []
67
+ required: true
68
+ mandatoryAngles:
69
+ - pr-checklist-matrix
70
+
71
+ # Autonomy: only merge requires operator confirmation by default.
72
+ autonomy:
73
+ stopAt:
74
+ - merge
75
+
76
+ # Workflow enforcement defaults.
77
+ workflow:
78
+ asyncStartMode: required
79
+ requireRetrospective: true
80
+ requireRetrospectiveGate: true
81
+ requireDraftFirst: true
82
+ devModeDefault: true
83
+
84
+ # Light-mode threshold for small local changes.
85
+ localImplementation:
86
+ lightMode:
87
+ enabled: true
88
+ maxFiles: 2
89
+ maxLines: 100
90
+
91
+ # Queue defaults (repo-specific projectNumber/boardTitle omitted by design).
92
+ queue:
93
+ maxParallel: 3
94
+ maxAutoFiledIssues: 10
95
+ reDispatchMaxRetries: 1
96
+
97
+ # Persona registry used by gate review angle resolution.
98
+ personas:
99
+ refiner:
100
+ persona: refiner
101
+ prompt: |-
102
+ For every refinement, include an AC/DoD/Non-goal coverage matrix:
103
+
104
+ | Item | Type (AC/DoD/Non-goal) | Status (Met/Partial/Unmet/Unverified) | Evidence | Notes |
105
+ |---|---|---|---|---|
106
+ | <exact item text> | AC | Unverified | <reference> | |
107
+
108
+ Use exact wording from the source issue(s); when the governing input is a phase doc or other spec instead of an issue, use that source wording exactly for every explicit item.
109
+ Include every explicit acceptance criterion, definition-of-done item, and non-goal; do not skip items.
110
+ If no explicit definition of done exists, add a `Proposed DoD` subsection before the matrix.
111
+ Treat any `Partial`, `Unmet`, or `Unverified` row as incomplete refinement.
112
+ A refinement is complete only when no item has `Partial`, `Unmet`, or `Unverified` status.
113
+
114
+ When a bounded audit artifact is supplied, add an `Audit inputs` subsection.
115
+ Summarize the audited scope, list prioritized findings, include the highest-value follow-up candidates,
116
+ and add an explicit `Will not rewrite/broaden in this phase` statement.
117
+ For each prioritized finding, classify it as exactly one of: current-phase scope/AC,
118
+ DoD expectation, explicit non-goal/defer, or risk/watchpoint.
119
+ Do not fabricate audit evidence when none was provided.
120
+ defaultModel: null
121
+
122
+ audit:
123
+ persona: review
124
+ prompt: >-
125
+ Run a bounded refinement audit. Audit only the named files/areas.
126
+ Prefer delete / merge / trim / defer framing over additive rewrite plans.
127
+ Produce prioritized findings and highest-value follow-up candidates,
128
+ not a whole-repo essay.
129
+ Always include a bounded-scope statement and a `not rewriting in this phase`
130
+ statement. Findings are planning inputs, not automatic rewrite authorization.
131
+ defaultModel: null
132
+
133
+ scope:
134
+ persona: review
135
+ prompt: >-
136
+ Check whether every changed file belongs in this PR.
137
+ Flag unrelated or out-of-scope changes.
138
+ The PR description's scope section is the contract.
139
+ defaultModel: null
140
+
141
+ coverage:
142
+ persona: review
143
+ prompt: >-
144
+ Check whether tests cover the changed behavior adequately.
145
+ Look for missing edge cases, untested error paths,
146
+ and acceptance-criteria gaps.
147
+ Also flag test-name quality issues: test names that misrepresent
148
+ what is actually asserted, overly broad names that hide gaps, and
149
+ names that don't match the behavior under test.
150
+ Flag missing negative-case coverage: malformed-argument tests,
151
+ error-contract tests, and edge-case coverage for boundary
152
+ conditions, empty inputs, and unexpected states.
153
+ Do not accept happy-path-only test suites.
154
+ defaultModel: null
155
+
156
+ correctness:
157
+ persona: review
158
+ prompt: >-
159
+ Check whether the implementation matches the acceptance criteria
160
+ and PR description. Flag logic errors, contract violations,
161
+ and behavior mismatches.
162
+ defaultModel: null
163
+
164
+ docs:
165
+ persona: docs
166
+ prompt: >-
167
+ Review documentation correctness for the current change. Check that
168
+ relative markdown links resolve, symlink-backed doc pointers resolve,
169
+ navigable doc references are actual markdown links rather than bare
170
+ backtick path mentions, command/script references still exist and use
171
+ current names, and index/surface references match the current file tree.
172
+ Also flag stale command references: removed or renamed npm scripts,
173
+ CLI commands, or tool invocations that no longer match the current
174
+ codebase. When the repo provides `scripts/docs/validate-links.mjs`,
175
+ use it for the mechanical link pass; otherwise keep the review scoped
176
+ to the touched doc surface and current change only.
177
+ defaultModel: null
178
+
179
+ deep:
180
+ persona: review
181
+ prompt: >-
182
+ Perform a structural code quality audit of this PR.
183
+
184
+ Bring the same rigor as a full-codebase deslop audit, scoped to this
185
+ change:
186
+ - Question whether every new file, export, layer, or abstraction is
187
+ genuinely necessary. Prefer deletion over addition.
188
+ - Flag files crossing 1000 lines without strong justification.
189
+ - Flag new conditionals bolted onto unrelated paths. Push logic into its
190
+ own boundary instead of scattering special cases.
191
+ - Flag thin wrappers, re-export-only files, and identity abstractions
192
+ that add indirection without buying clarity.
193
+ - Flag feature logic leaking into shared or general-purpose modules.
194
+ - Question cast-heavy, optionality-heavy, or any-typed contracts that
195
+ obscure the real invariant.
196
+
197
+ Be ambitious about simplification:
198
+ - Look for "code judo" moves: restructurings that preserve behavior while
199
+ deleting whole categories of complexity.
200
+ - Prefer the simpler model. If the change adds moving parts, ask whether
201
+ fewer would achieve the same result.
202
+
203
+ Do not rubber-stamp working-but-messier code.
204
+ Approval bar:
205
+ - no structural regression
206
+ - no missed simplification opportunity
207
+ - no unjustified file-size explosion
208
+ - no spaghetti branching growth
209
+ - no unnecessary abstraction or indirection
210
+
211
+ This persona complements full-repo deslop audits: same rigor,
212
+ applied per-PR.
213
+ defaultModel: null
214
+
215
+ dry:
216
+ persona: review
217
+ prompt: >-
218
+ Flag duplicated logic, repeated patterns, and copy-pasted code.
219
+ Prefer one canonical path. Check for restated policies across
220
+ docs and skills.
221
+ defaultModel: null
222
+
223
+ kiss:
224
+ persona: review
225
+ prompt: >-
226
+ Flag over-engineering and unnecessary complexity.
227
+ Prefer simple solutions. Question extra layers, abstractions,
228
+ and indirection that don't earn their keep.
229
+ defaultModel: null
230
+
231
+ srp:
232
+ persona: review
233
+ prompt: >-
234
+ Single Responsibility Principle: check that each module, file,
235
+ class, and function has exactly one reason to change.
236
+ Flag multi-concern files, god objects, mixed abstractions,
237
+ and modules that own unrelated responsibilities.
238
+ defaultModel: null
239
+
240
+ ocp:
241
+ persona: review
242
+ prompt: >-
243
+ Open/Closed Principle: flag code that requires modifying existing
244
+ modules to add new behavior. Prefer extension points, plugin
245
+ architectures, and config-driven dispatch over patching internals.
246
+ defaultModel: null
247
+
248
+ lsp:
249
+ persona: review
250
+ prompt: >-
251
+ Liskov Substitution Principle: flag subtypes or implementations
252
+ that weaken base contracts, throw unexpected errors, or require
253
+ special-casing in callers. Subtypes must be fully substitutable
254
+ for their base types.
255
+ defaultModel: null
256
+
257
+ isp:
258
+ persona: review
259
+ prompt: >-
260
+ Interface Segregation Principle: flag fat interfaces and modules
261
+ that force consumers to depend on methods or exports they never
262
+ use. Prefer narrow, role-specific interfaces.
263
+ defaultModel: null
264
+
265
+ dip:
266
+ persona: review
267
+ prompt: >-
268
+ Dependency Inversion Principle: flag high-level modules depending
269
+ on low-level implementation details. Check that abstractions are
270
+ owned by the consumer, not the implementation. Flag concrete
271
+ imports where an interface/contract should exist.
272
+ defaultModel: null
273
+
274
+ soc:
275
+ persona: review
276
+ prompt: >-
277
+ Separation of Concerns: flag modules that mix distinct concerns
278
+ (e.g., business logic + I/O, data access + presentation,
279
+ orchestration + implementation). Each concern should live in
280
+ its own module with a clear boundary.
281
+ defaultModel: null
282
+
283
+ yagni:
284
+ persona: review
285
+ prompt: >-
286
+ Flag speculative features, future-proofing, and compatibility shims
287
+ not required by the current acceptance criteria.
288
+ YAGNI = You Aren't Gonna Need It.
289
+ defaultModel: null
290
+
291
+ contract-surface:
292
+ persona: review
293
+ prompt: >-
294
+ Review this change for public contract-surface drift. Check whether documented schema fields, state/sentinel names, runtime values, tests, and CLI output agree. Verify CLI --help usage matches accepted flags. Compare stdout JSON success shape and stderr JSON error shape against documented examples. Flag optional fields documented as always emitted but conditionally omitted, or fields emitted but undocumented. Stay repo-agnostic; cite concrete changed files and give minimal fixes.
295
+ defaultModel: null
296
+
297
+ input-validation:
298
+ persona: review
299
+ prompt: >-
300
+ Review this change for input-validation drift. Check repo slug, issue number, host, SHA, whitespace, and sentinel normalization. Prefer shared parsers/helpers over ad hoc validation. Flag malformed inputs that slip through, confusing errors, path traversal-like segments, and inconsistent trimming/normalization across CLI/API entrypoints. Recommend minimal tests for accepted and rejected forms.
301
+ defaultModel: null
302
+
303
+ packaging-runtime:
304
+ persona: review
305
+ prompt: >-
306
+ Review this change for packaging/runtime asset contract gaps. Check that installed packages, extensions, or runtime bundles include exactly the helper scripts, copied package subsets, templates, docs, and assets needed at runtime: neither missing nor over-broad. Compare install docs, fixture assertions, allow-lists, and import paths. Flag runtime-only dependencies not covered by packaging tests.
307
+ defaultModel: null
308
+
309
+ state-concurrency:
310
+ persona: review
311
+ prompt: >-
312
+ Review this change for state concurrency and locking risks. Check state-file read/modify/write paths, lock acquisition/release, stale lock handling, concurrent invocations, atomic writes, managed process cleanup, and stderr/error capture. Flag races that can clobber state or leave orphaned locks/processes. Recommend narrow deterministic concurrency or cleanup tests.
313
+ defaultModel: null
314
+
315
+ renderer-security:
316
+ persona: review
317
+ prompt: >-
318
+ Review this change for renderer security. Check HTML text escaping, URL encoding, attribute encoding, JSON/script embedding, and rendering of user-controlled content. Treat titles, names, URLs, statuses, errors, and external payload fields as untrusted. Flag raw interpolation into HTML or attributes and tests that expect unsafe output.
319
+ defaultModel: null
320
+
321
+ determinism:
322
+ persona: review
323
+ prompt: >-
324
+ Review this change for determinism. Check ordering, tie-breakers, localeCompare use, time/random/environment dependence, polling/count assumptions, and mocks/stubs that allow unexpected extra calls. Require stable sorting, strict stubs, deterministic fixture data, and tests independent of locale, timezone, filesystem order, and network timing.
325
+ defaultModel: null
326
+
327
+ ci-guard:
328
+ persona: review
329
+ prompt: >-
330
+ Audit CI/workflow semantics for reproducibility and correctness:
331
+ - Verify CI configuration is deterministic (no floating version ranges
332
+ in install steps, lockfile is respected).
333
+ - Check that branch-protection rules and status-check requirements
334
+ match the stated merge policy.
335
+ - Flag non-reproducible install steps and missing lockfile enforcement.
336
+ - Verify that CI failure precedence is correct: a failing required check
337
+ must block merge regardless of other passing checks.
338
+ - Flag pending check-run states that could silently hide failures.
339
+ - Flag Node.js support-floor mismatches between CI matrices,
340
+ package.json engines, and documented requirements.
341
+ defaultModel: null
342
+
343
+ link-check:
344
+ persona: review
345
+ prompt: >-
346
+ Validate link and path correctness:
347
+ - Check that all Markdown relative links resolve to existing files
348
+ or sections.
349
+ - Flag placeholder links (e.g. href targets still using example URLs,
350
+ 404 references, or TODO links).
351
+ - When the repo provides `scripts/docs/validate-links.mjs`, run it
352
+ for the mechanical link pass and report any failures.
353
+ - Flag symlink-backed doc pointers that point to missing targets.
354
+ - This persona complements mechanical link validation with context-aware
355
+ judgment for link intent and anchor correctness.
356
+ defaultModel: null
357
+
358
+ pr-description:
359
+ persona: review
360
+ prompt: >-
361
+ Review the PR description for completeness, contract fitness, and checkbox formatting before this PR is marked ready for review.
362
+ The PR body is the implementation contract — it must have:
363
+ - A Summary section explaining what changed and why
364
+ - A Scope and context section defining the boundary of the change
365
+ - A File-by-file changes section listing every touched file and what changed in it
366
+ - An Acceptance criteria section with the linked issue acceptance criteria
367
+ - A Definition of done section
368
+ - A Non-goals section
369
+ - A Validation command section describing exactly how to verify the change
370
+ - The "Closes #N" line must match the linked issue; flag changes that alter or remove the operator-intended close target
371
+ Checkboxes (`- [ ]` / `- [x]`, or `* [ ]` / `* [x]`) must appear inside genuine Markdown list items. Flag any checkbox marker used outside a list item (including table cells) as a worth-fixing-now finding.
372
+ Flag any checkbox marker wrapped in backticks (e.g. `` `[x]` ``) as a worth-fixing-now finding.
373
+ Flag PRs where the body is a single sentence or lacks any of these sections.
374
+ Do not block on formatting preferences other than checkbox correctness.
375
+ defaultModel: null
376
+
377
+ pr-checklist-matrix:
378
+ persona: review
379
+ prompt: >-
380
+ Verify before approval that the PR checklist and AC/DoD/non-goals matrix are complete.
381
+ - Every PR checkbox (`- [ ]`) must be checked. If any box is unchecked, flag it as a blocking finding.
382
+ - The PR body must contain an AC/DoD/non-goals matrix that maps each acceptance criterion
383
+ to its definition-of-done item(s) and lists explicit non-goals.
384
+ - The matrix must have a markdown table with at least a header row and one content row.
385
+ - Flag the matrix as incomplete if any acceptance criterion, definition-of-done item, or non-goal is missing.
386
+ defaultModel: null
387
+
388
+ pr-comments:
389
+ persona: review
390
+ prompt: >-
391
+ Scan PR comments for unresolved issues before declaring the gate clean.
392
+ Check all PR comments and review threads for:
393
+ - Comments from the repository owner or collaborators that point out
394
+ implementation bugs, logic errors, contract violations, or security
395
+ issues
396
+ - Unresolved review threads that raise implementation concerns
397
+ Flag any unresolved comment that identifies a concrete implementation
398
+ problem as a blocking finding (severity: must-fix or worth-fixing-now).
399
+ Do not flag:
400
+ - Resolved threads
401
+ - Style nits, formatting suggestions, or cosmetic feedback
402
+ - Comments from non-collaborators or bots
403
+ - Outdated comments that were already addressed in a later commit
404
+ If no unresolved implementation concerns exist, return clean.
405
+ config-drift:
406
+ persona: review
407
+ prompt: >-
408
+ Cross-check config, schema, and documentation for contract drift:
409
+ - Verify that configuration files (.pi/dev-loop/settings.yaml,
410
+ package.json, CI workflows, skill manifests) agree on canonical
411
+ status tokens, support floors, and required flags.
412
+ - Flag any instance where two sources of truth disagree about the
413
+ supported contract (e.g. one doc says a flag is required, another
414
+ says it's optional).
415
+ - Check that the engines.node field matches CI matrix and any
416
+ documented Node.js support floor.
417
+ - Flag inconsistencies within a single doc that could confuse
418
+ consumers (e.g. one section says "default: true" and another
419
+ section implies the opposite).
420
+ defaultModel: null
421
+
422
+ gate-evidence:
423
+ persona: review
424
+ prompt: >-
425
+ Verify that required workflow checkpoint evidence is present and valid:
426
+ - Check that the draft checkpoint verdict comment exists. While the PR is
427
+ still draft, it must also reference the current head SHA. After the PR
428
+ leaves draft, the `draft_gate` checkpoint verdict comment is a one-time transition record
429
+ and head-SHA matching no longer applies.
430
+ - Check that the pre-approval checkpoint verdict comment exists when the PR
431
+ is in a ready/merge state.
432
+ - Flag any PR that transitions to ready/merge states without visible
433
+ checkpoint evidence for the current head.
434
+ - When draft-first enforcement is configured, verify that a draft-gate
435
+ comment was posted before the PR was marked ready.
436
+ - This persona is opt-in for the draft gate (uncomment to add).
437
+ On first PR it checks for any checkpoint evidence (not only draft_gate since
438
+ no prior gate exists).
439
+ defaultModel: null
440
+
441
+ no-op:
442
+ persona: review
443
+ prompt: >-
444
+ Flag workflow or tool invocations that are effectively no-ops:
445
+ - Check that shell commands and tool calls actually affect output,
446
+ state, or exit behavior rather than discarding their effect.
447
+ - Flag tool invocations that look successful but pass arguments in
448
+ a way that produces no meaningful change.
449
+ - Flag commands whose output is generated but never consumed.
450
+ - Flag patterns where a tool is called in a loop but only the last
451
+ iteration's result is used (or none at all).
452
+ defaultModel: null
453
+
454
+ # Internal path patterns for internal-only PR detection.
455
+ internalPathPatterns:
456
+ - "^scripts/"
457
+ - "^docs/"
458
+ - "^skills/docs/"
459
+ - "^\\.pi/"
460
+ - "^\\.github/"
461
+ - "^test/"