@namewta/speculo 1.0.15 → 1.0.17

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 (94) hide show
  1. package/README.md +17 -5
  2. package/dist/src/agent-files.d.ts +9 -0
  3. package/dist/src/agent-files.js +106 -0
  4. package/dist/src/agent-files.js.map +1 -0
  5. package/dist/src/cli.js +64 -14
  6. package/dist/src/cli.js.map +1 -1
  7. package/dist/src/doctor.d.ts +2 -0
  8. package/dist/src/doctor.js +120 -53
  9. package/dist/src/doctor.js.map +1 -1
  10. package/dist/src/external-files.d.ts +22 -0
  11. package/dist/src/external-files.js +110 -0
  12. package/dist/src/external-files.js.map +1 -0
  13. package/dist/src/index.d.ts +3 -0
  14. package/dist/src/index.js +31 -182
  15. package/dist/src/index.js.map +1 -1
  16. package/dist/src/paths.d.ts +12 -0
  17. package/dist/src/paths.js +57 -0
  18. package/dist/src/paths.js.map +1 -0
  19. package/dist/src/transaction.d.ts +27 -0
  20. package/dist/src/transaction.js +187 -0
  21. package/dist/src/transaction.js.map +1 -0
  22. package/dist/src/utils.js +4 -2
  23. package/dist/src/utils.js.map +1 -1
  24. package/dist/src/workflows.js +3 -4
  25. package/dist/src/workflows.js.map +1 -1
  26. package/package.json +6 -4
  27. package/template/.speculo/README.md +9 -3
  28. package/template/.speculo/refresh-contract.json +6 -2
  29. package/template/AGENTS.md +1 -1
  30. package/template/canonical/canonical-specdev-goal-plan.md +23 -12
  31. package/template/canonical/canonical-specdev-tickets.md +1 -1
  32. package/template/commands/docs-sync.md +13 -11
  33. package/template/skills/archive-and-consolidate/SKILL.md +2 -4
  34. package/template/skills/docs-sync/SKILL.md +22 -11
  35. package/template/skills/docs-sync/references/agents-contract.md +6 -4
  36. package/template/skills/docs-sync/references/document-lifecycle-contract.md +2 -0
  37. package/template/skills/docs-sync/references/entry-procedure.md +2 -17
  38. package/template/skills/docs-sync/references/git-state-contract.md +1 -1
  39. package/template/skills/docs-sync/references/mode-contract.md +21 -0
  40. package/template/skills/docs-sync/references/workflow-scope-contract.md +5 -3
  41. package/template/skills/engineering-standards-builder/SKILL.md +3 -1
  42. package/template/skills/engineering-standards-builder/examples/README.md +6 -0
  43. package/template/skills/engineering-standards-builder/manifest.txt +1 -0
  44. package/template/skills/engineering-standards-builder/scripts/self-test.mjs +1 -0
  45. package/template/skills/engineering-standards-builder/scripts/sync-manifest.mjs +2 -2
  46. package/template/skills/engineering-standards-builder/scripts/validate-builder.mjs +12 -4
  47. package/template/skills/git-history-squash/SKILL.md +3 -3
  48. package/template/skills/github-npm-ops/SKILL.md +2 -4
  49. package/template/skills/source-code-zip/SKILL.md +0 -1
  50. package/template/skills/speculo-retro/SKILL.md +2 -4
  51. package/template/skills/upstream-fork-sync/SKILL.md +1 -3
  52. package/template/skills/writing-great-skills/SKILL.md +3 -3
  53. package/template/workflows/learning/A-archive/A-archive.md +2 -0
  54. package/template/workflows/learning/A-assess-and-plan/A-assess-and-plan.md +2 -0
  55. package/template/workflows/learning/C-consolidate/C-consolidate.md +2 -0
  56. package/template/workflows/learning/G-goal/G-goal.md +6 -0
  57. package/template/workflows/learning/G-goal/references/external-goal-runner.md +4 -0
  58. package/template/workflows/learning/H-homework/H-homework.md +2 -0
  59. package/template/workflows/learning/L-lesson/L-lesson.md +2 -0
  60. package/template/workflows/learning/Q-question/Q-question.md +2 -0
  61. package/template/workflows/learning/R-review/R-review.md +2 -0
  62. package/template/workflows/learning/README.md +4 -53
  63. package/template/workflows/learning/common/rules/artifact-layouts.md +46 -0
  64. package/template/workflows/learning/common/rules/consolidation-contract.md +5 -0
  65. package/template/workflows/learning/common/rules/homework-contract.md +3 -0
  66. package/template/workflows/learning/common/rules/lesson-contract.md +7 -0
  67. package/template/workflows/learning/common/skills/socratic-questioning/SKILL.md +1 -0
  68. package/template/workflows/learning/common/skills/topic-synthesis/SKILL.md +1 -0
  69. package/template/workflows/ops/README.md +7 -3
  70. package/template/workflows/ops/_state/status.json +2 -1
  71. package/template/workflows/ops/common/USAGE.md +4 -0
  72. package/template/workflows/ops/common/rules/persistence-and-secrets.md +4 -2
  73. package/template/workflows/ops/common/schemas/plan.schema.json +4 -0
  74. package/template/workflows/ops/common/schemas/spec.schema.json +4 -0
  75. package/template/workflows/ops/common/schemas/status.schema.json +4 -0
  76. package/template/workflows/ops/common/tests/test_ops.mjs +33 -2
  77. package/template/workflows/ops/common/tools/opslib/core.mjs +1 -1
  78. package/template/workflows/ops/common/tools/opslib/docs.mjs +12 -7
  79. package/template/workflows/ops/common/tools/opslib/planner.mjs +7 -1
  80. package/template/workflows/specdev/P-goal-plan/P-goal-plan.md +4 -2
  81. package/template/workflows/specdev/P-goal-plan/goal-plan-template.md +2 -0
  82. package/template/workflows/specdev/P-goal-plan/planning-modes.md +13 -8
  83. package/template/workflows/specdev/P-goal-plan/references/map-control.md +1 -1
  84. package/template/workflows/specdev/P-goal-plan/references/single-change-plan.md +4 -2
  85. package/template/workflows/specdev/README.md +2 -2
  86. package/template/workflows/specdev/common/rules/path-reference-contract.md +6 -0
  87. package/template/workflows/specdev/common/rules/workflow-routing.md +2 -2
  88. package/template/workflows/specdev/common/skills/code-review/SKILL.md +3 -1
  89. package/template/workflows/specdev/common/skills/dev-worktree/SKILL.md +1 -0
  90. package/template/workflows/specdev/common/skills/plan-quality-review/SKILL.md +3 -1
  91. package/template/workflows/specdev/common/skills/research/SKILL.md +3 -1
  92. package/template/workflows/specdev/common/skills/subagent-delivery/SKILL.md +1 -0
  93. package/template/workflows/specdev/common/tools/README.md +7 -1
  94. package/template/workflows/specdev/common/tools/validate-specdev.mjs +19 -18
@@ -2023,7 +2023,10 @@ function validateMap(path, errors, repoRoot = null) {
2023
2023
  }
2024
2024
 
2025
2025
  function validateGoalPlan(path, errors) {
2026
- if (!isFile(path)) return null;
2026
+ if (!isFile(path)) {
2027
+ errors.push(`missing Goal Plan: ${basename(path)}`);
2028
+ return null;
2029
+ }
2027
2030
  const { meta, body } = parseFrontmatter(path);
2028
2031
  const required = [
2029
2032
  "schema_version",
@@ -2084,6 +2087,7 @@ function validateGoalPlan(path, errors) {
2084
2087
  const validReadyStates = new Set(["ready", "in_progress"]);
2085
2088
  const validNotReadyStates = new Set(["draft", "blocked", "completed"]);
2086
2089
  if (
2090
+ typeof meta.ready_for_execution !== "boolean" ||
2087
2091
  (meta.ready_for_execution === true && !validReadyStates.has(meta.status)) ||
2088
2092
  (meta.ready_for_execution === false && !validNotReadyStates.has(meta.status))
2089
2093
  ) {
@@ -2314,6 +2318,10 @@ function validateTicket(path, errors) {
2314
2318
  const ticketId = String(meta.id);
2315
2319
  if (!/^T-\d{2,}$/.test(ticketId)) errors.push(`${basename(path)}: invalid Ticket id ${ticketId}`);
2316
2320
  if (!VALID_TICKET_STATUS.has(meta.status)) errors.push(`${basename(path)}: invalid status ${meta.status}`);
2321
+ if (typeof meta.ready !== "boolean") errors.push(`${basename(path)}: ready must be a boolean`);
2322
+ if (new Set(["ready", "in_progress", "review"]).has(meta.status) && meta.ready !== true) {
2323
+ errors.push(`${basename(path)}: executable Ticket must keep ready=true`);
2324
+ }
2317
2325
  if (meta.kind != null && meta.kind !== "" && !VALID_TICKET_KIND.has(meta.kind)) {
2318
2326
  errors.push(`${basename(path)}: invalid kind ${meta.kind}`);
2319
2327
  }
@@ -2810,12 +2818,10 @@ function validateGitEvidence(repoRoot, changeStatus, errors) {
2810
2818
  }
2811
2819
 
2812
2820
  function validateParentImplementation(change, parentStatus, stage, errors, warnings, repoRoot = null) {
2813
- const required = stage === "goal-plan";
2814
2821
  const mapPath = join(change, "implementation-map.md");
2815
2822
  const planPath = join(change, "implementation-plan.md");
2816
- if (!required && !isFile(mapPath) && !isFile(planPath)) return null;
2817
- if (!isFile(mapPath)) errors.push("goal-plan stage requires implementation-map.md");
2818
- if (!isFile(planPath)) errors.push("goal-plan stage requires implementation-plan.md");
2823
+ if (!isFile(mapPath)) errors.push("parent implementation requires implementation-map.md");
2824
+ if (!isFile(planPath)) errors.push("parent implementation requires implementation-plan.md");
2819
2825
  if (!isFile(mapPath) || !isFile(planPath)) return null;
2820
2826
 
2821
2827
  const parentName = basename(change);
@@ -3193,7 +3199,7 @@ function validateParentImplementation(change, parentStatus, stage, errors, warni
3193
3199
  if (count > 1) errors.push(`repository/ref integration must be serialized for ${ref}; found ${count}`);
3194
3200
  }
3195
3201
 
3196
- if (required && parentStatus && new Set(["active", "blocked"]).has(parentStatus.change_status) && !new Set(["specdev/goal-plan"]).has(parentStatus.current_work)) {
3202
+ if (stage === "goal-plan" && parentStatus && new Set(["active", "blocked"]).has(parentStatus.change_status) && !new Set(["specdev/goal-plan"]).has(parentStatus.current_work)) {
3197
3203
  errors.push("parent active/blocked status must keep current_work=specdev/goal-plan");
3198
3204
  }
3199
3205
  if (parentStatus?.change_status === "completed") {
@@ -3264,8 +3270,13 @@ function validateChange(change, stage = null, repoRoot = null) {
3264
3270
  const workspace = resolveWorkspaceContract(repoRoot, change);
3265
3271
  errors.push(...workspace.errors);
3266
3272
 
3273
+ // A partial parent must never fall back to the single-change artifact contract.
3274
+ const mapPath = join(change, "tickets-map.md");
3275
+ const isParentImplementation = isFile(join(change, "implementation-map.md")) ||
3276
+ isFile(join(change, "implementation-plan.md")) ||
3277
+ (isFile(mapPath) && parseFrontmatter(mapPath).meta.artifact === "goal-tickets-map");
3267
3278
  const changeStatus = validateChangeStatus(join(change, ".status.json"), basename(change), errors);
3268
- validateParentImplementation(change, changeStatus, stage, errors, warnings, repoRoot);
3279
+ if (isParentImplementation) validateParentImplementation(change, changeStatus, stage, errors, warnings, repoRoot);
3269
3280
  errors.push(...validateInitiative(change));
3270
3281
  if (isFile(join(change, "source-issue.md"))) {
3271
3282
  errors.push("obsolete source-issue.md is forbidden; use source.md without compatibility fallback");
@@ -3297,7 +3308,6 @@ function validateChange(change, stage = null, repoRoot = null) {
3297
3308
  validatePrototypes(change, stage === "prototype", errors);
3298
3309
  validateChangeLearning(change, stage === "learn-change", errors);
3299
3310
 
3300
- const isParentImplementation = isFile(join(change, "implementation-map.md"));
3301
3311
  const specRequired = new Set(["spec", "tickets", "goal-plan", "implement", "complete"]).has(stage) && !isParentImplementation;
3302
3312
  const specPath = join(change, "spec.md");
3303
3313
  const spec = isFile(specPath) || specRequired
@@ -3305,10 +3315,9 @@ function validateChange(change, stage = null, repoRoot = null) {
3305
3315
  : null;
3306
3316
  const ticketMode = isDirectory(join(change, "ticket"));
3307
3317
  const mapRequired = !isParentImplementation && (new Set(["tickets", "goal-plan"]).has(stage) || (stage === "implement" && ticketMode));
3308
- const mapPath = join(change, "tickets-map.md");
3309
3318
  const ticketsMap = isFile(mapPath) || mapRequired ? validateMap(mapPath, errors, repoRoot) : null;
3310
3319
  const goalPlanPath = join(change, "goal-plan.md");
3311
- const goalPlan = isFile(goalPlanPath) || stage === "goal-plan"
3320
+ const goalPlan = isFile(goalPlanPath) || (stage === "goal-plan" && !isParentImplementation)
3312
3321
  ? validateGoalPlan(goalPlanPath, errors)
3313
3322
  : null;
3314
3323
  validateDesignTree(join(change, "design-tree.json"), change, errors);
@@ -3527,14 +3536,6 @@ function validateChange(change, stage = null, repoRoot = null) {
3527
3536
  }
3528
3537
 
3529
3538
  if (goalPlan?.meta.ready_for_execution === true) {
3530
- const notReady = [...tickets]
3531
- .filter(
3532
- ([, artifact]) =>
3533
- !new Set(["done", "cancelled"]).has(artifact.meta.status) &&
3534
- artifact.meta.ready !== true,
3535
- )
3536
- .map(([ticketId]) => ticketId);
3537
- if (notReady.length) errors.push(`Goal Plan is Ready but Tickets are not Ready: ${JSON.stringify(notReady)}`);
3538
3539
  if (spec && spec.meta.ready_for_tickets !== true) {
3539
3540
  errors.push("Goal Plan is Ready but Spec is not ready_for_tickets");
3540
3541
  }