kibi-cli 2.28.1 → 2.30.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/bin/kibi +12 -1
  2. package/dist/cli-command.d.ts +3 -0
  3. package/dist/cli-command.d.ts.map +1 -1
  4. package/dist/cli-command.js +11 -0
  5. package/dist/cli-operation-metadata.d.ts +8 -8
  6. package/dist/cli-operation-metadata.js +8 -8
  7. package/dist/cli-register-reporting.d.ts.map +1 -1
  8. package/dist/cli-register-reporting.js +12 -0
  9. package/dist/cli.d.ts.map +1 -1
  10. package/dist/cli.js +5 -2
  11. package/dist/commands/check.d.ts.map +1 -1
  12. package/dist/commands/check.js +8 -1
  13. package/dist/commands/engine.d.ts.map +1 -1
  14. package/dist/commands/engine.js +26 -2
  15. package/dist/commands/signoff.d.ts +37 -0
  16. package/dist/commands/signoff.d.ts.map +1 -0
  17. package/dist/commands/signoff.js +152 -0
  18. package/dist/commands/sync.d.ts +10 -0
  19. package/dist/commands/sync.d.ts.map +1 -1
  20. package/dist/commands/sync.js +67 -3
  21. package/dist/engine.d.ts +11 -1
  22. package/dist/engine.d.ts.map +1 -1
  23. package/dist/engine.js +120 -34
  24. package/dist/operations/modeling/predicate-applicability.d.ts +5 -1
  25. package/dist/operations/modeling/predicate-applicability.d.ts.map +1 -1
  26. package/dist/operations/modeling/predicate-applicability.js +35 -2
  27. package/dist/operations/modeling/suggest-predicates.d.ts.map +1 -1
  28. package/dist/operations/modeling/suggest-predicates.js +3 -1
  29. package/dist/operations/mutation/contradictions.d.ts +7 -5
  30. package/dist/operations/mutation/contradictions.d.ts.map +1 -1
  31. package/dist/operations/mutation/contradictions.js +8 -6
  32. package/dist/operations/mutation/source-authoring.d.ts +15 -0
  33. package/dist/operations/mutation/source-authoring.d.ts.map +1 -1
  34. package/dist/operations/mutation/source-authoring.js +19 -7
  35. package/dist/operations/mutation/types.d.ts +5 -0
  36. package/dist/operations/mutation/types.d.ts.map +1 -1
  37. package/dist/operations/mutation/upsert.d.ts +14 -0
  38. package/dist/operations/mutation/upsert.d.ts.map +1 -1
  39. package/dist/operations/mutation/upsert.js +42 -36
  40. package/dist/operations/mutation/validate-upsert.d.ts.map +1 -1
  41. package/dist/operations/mutation/validate-upsert.js +61 -37
  42. package/dist/prolog/error-terms.d.ts.map +1 -1
  43. package/dist/prolog/error-terms.js +15 -9
  44. package/dist/prolog/store-lock.d.ts +11 -0
  45. package/dist/prolog/store-lock.d.ts.map +1 -1
  46. package/dist/prolog/store-lock.js +48 -1
  47. package/dist/public/operations/catalog.d.ts +29 -8
  48. package/dist/public/operations/catalog.d.ts.map +1 -1
  49. package/dist/public/operations/contracts.d.ts.map +1 -1
  50. package/dist/public/operations/contracts.js +2 -0
  51. package/dist/public/operations/specs/bootstrap.d.ts +1 -1
  52. package/dist/public/operations/specs/bootstrap.js +1 -1
  53. package/dist/public/operations/specs/composite.d.ts +1 -1
  54. package/dist/public/operations/specs/composite.js +1 -1
  55. package/dist/public/operations/specs/discovery.d.ts +1 -1
  56. package/dist/public/operations/specs/discovery.js +1 -1
  57. package/dist/public/operations/specs/impact-review-preparation.d.ts +2 -1
  58. package/dist/public/operations/specs/impact-review-preparation.d.ts.map +1 -1
  59. package/dist/public/operations/specs/impact-review-preparation.js +2 -1
  60. package/dist/public/operations/specs/planning.d.ts +1 -1
  61. package/dist/public/operations/specs/planning.js +1 -1
  62. package/dist/public/operations/specs/reporting.d.ts +23 -3
  63. package/dist/public/operations/specs/reporting.d.ts.map +1 -1
  64. package/dist/public/operations/specs/reporting.js +97 -21
  65. package/dist/public/skills/kibi-commit-review/SKILL.md +125 -0
  66. package/dist/public/skills/kibi-commit-review/resources/staged-gate.md +98 -0
  67. package/dist/public/skills/kibi-decisions/SKILL.md +130 -0
  68. package/dist/public/skills/kibi-decisions/resources/decision-records.md +142 -0
  69. package/dist/public/skills/kibi-decisions/resources/signoff-views.md +66 -0
  70. package/dist/public/skills/kibi-freshness/SKILL.md +2 -0
  71. package/dist/public/skills/kibi-traceability/SKILL.md +4 -0
  72. package/dist/public/skills/kibi-usage/SKILL.md +20 -15
  73. package/dist/signoff/collect.d.ts +39 -0
  74. package/dist/signoff/collect.d.ts.map +1 -0
  75. package/dist/signoff/collect.js +398 -0
  76. package/dist/signoff/html.d.ts +4 -0
  77. package/dist/signoff/html.d.ts.map +1 -0
  78. package/dist/signoff/html.js +210 -0
  79. package/dist/signoff/markdown.d.ts +20 -0
  80. package/dist/signoff/markdown.d.ts.map +1 -0
  81. package/dist/signoff/markdown.js +203 -0
  82. package/dist/signoff/model.d.ts +134 -0
  83. package/dist/signoff/model.d.ts.map +1 -0
  84. package/dist/signoff/model.js +138 -0
  85. package/dist/traceability/commit-amend.d.ts +7 -0
  86. package/dist/traceability/commit-amend.d.ts.map +1 -0
  87. package/dist/traceability/commit-amend.js +85 -0
  88. package/dist/traceability/staged-inventory-drift.d.ts +12 -2
  89. package/dist/traceability/staged-inventory-drift.d.ts.map +1 -1
  90. package/dist/traceability/staged-inventory-drift.js +22 -5
  91. package/package.json +2 -2
  92. package/src/public/operations/contracts.ts +2 -0
  93. package/src/public/operations/specs/bootstrap.ts +1 -1
  94. package/src/public/operations/specs/composite.ts +1 -1
  95. package/src/public/operations/specs/discovery.ts +1 -1
  96. package/src/public/operations/specs/impact-review-preparation.ts +3 -1
  97. package/src/public/operations/specs/planning.ts +1 -1
  98. package/src/public/operations/specs/reporting.ts +109 -21
  99. package/src/public/skills/kibi-commit-review/SKILL.md +125 -0
  100. package/src/public/skills/kibi-commit-review/resources/staged-gate.md +98 -0
  101. package/src/public/skills/kibi-decisions/SKILL.md +130 -0
  102. package/src/public/skills/kibi-decisions/resources/decision-records.md +142 -0
  103. package/src/public/skills/kibi-decisions/resources/signoff-views.md +66 -0
  104. package/src/public/skills/kibi-freshness/SKILL.md +2 -0
  105. package/src/public/skills/kibi-traceability/SKILL.md +4 -0
  106. package/src/public/skills/kibi-usage/SKILL.md +20 -15
package/bin/kibi CHANGED
@@ -16,6 +16,17 @@
16
16
  You should have received a copy of the GNU Affero General Public License
17
17
  along with this program. If not, see <https://www.gnu.org/licenses/>.
18
18
  */
19
- import { main } from "../dist/cli.js";
19
+ // Kibi needs Node.js 22+ (package "engines"), but npm only warns on a
20
+ // mismatch. Fail before loading anything, with the Node that was found.
21
+ const nodeMajor = Number(process.versions.node.split(".")[0]);
22
+ if (!globalThis.Bun && nodeMajor < 22) {
23
+ process.stderr.write(
24
+ `kibi requires Node.js 22 or later, but was started with Node.js ${process.versions.node} (${process.execPath}). ` +
25
+ "Put Node.js 22+ first on PATH, including for the host that launches it, and retry.\n",
26
+ );
27
+ process.exit(1);
28
+ }
29
+
30
+ const { main } = await import("../dist/cli.js");
20
31
 
21
32
  await main();
@@ -2,4 +2,7 @@ export interface CommandResult {
2
2
  readonly exitCode?: number;
3
3
  }
4
4
  export declare function withExitCode<TArgs extends unknown[]>(fn: (...args: TArgs) => Promise<CommandResult | undefined>): (...args: TArgs) => Promise<void>;
5
+ /** Note that a command already printed this error, so the CLI does not again. */
6
+ export declare function markErrorReported(error: unknown): void;
7
+ export declare function errorWasReported(error: unknown): boolean;
5
8
  //# sourceMappingURL=cli-command.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cli-command.d.ts","sourceRoot":"","sources":["../src/cli-command.ts"],"names":[],"mappings":"AACA,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAGD,wBAAgB,YAAY,CAAC,KAAK,SAAS,OAAO,EAAE,EAClD,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,KAAK,KAAK,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,GACzD,CAAC,GAAG,IAAI,EAAE,KAAK,KAAK,OAAO,CAAC,IAAI,CAAC,CAOnC"}
1
+ {"version":3,"file":"cli-command.d.ts","sourceRoot":"","sources":["../src/cli-command.ts"],"names":[],"mappings":"AACA,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAGD,wBAAgB,YAAY,CAAC,KAAK,SAAS,OAAO,EAAE,EAClD,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,KAAK,KAAK,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,GACzD,CAAC,GAAG,IAAI,EAAE,KAAK,KAAK,OAAO,CAAC,IAAI,CAAC,CAOnC;AAID,iFAAiF;AAEjF,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAEtD;AAGD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAIxD"}
@@ -7,3 +7,14 @@ export function withExitCode(fn) {
7
7
  }
8
8
  };
9
9
  }
10
+ const reportedErrors = new WeakSet();
11
+ /** Note that a command already printed this error, so the CLI does not again. */
12
+ // implements REQ-kibi-operation-interface-parity
13
+ export function markErrorReported(error) {
14
+ if (typeof error === "object" && error !== null)
15
+ reportedErrors.add(error);
16
+ }
17
+ // implements REQ-kibi-operation-interface-parity
18
+ export function errorWasReported(error) {
19
+ return (typeof error === "object" && error !== null && reportedErrors.has(error));
20
+ }
@@ -31,19 +31,19 @@ export declare const CLI_OPERATION_METADATA: readonly [{
31
31
  }, {
32
32
  readonly name: "kb_status";
33
33
  readonly cliName: "status";
34
- readonly description: "Report current branch, KB snapshot, freshness metadata, schema status, and a typed kibi.migration-plan.v2 action graph. Read-only status inspection with no mutation side effects; damaged stores are diagnosed without starting the engine.";
34
+ readonly description: "Report current branch, KB snapshot, freshness metadata, schema status, and a typed kibi.migration-plan.v2 action graph. Call it first to orient on a branch or after a failed call; use kb_check for validation findings and kb_coverage for proof status. Read-only status inspection with no mutation side effects; damaged stores are diagnosed without starting the engine.";
35
35
  }, {
36
36
  readonly name: "kb_find_gaps";
37
37
  readonly cliName: "find-gaps";
38
- readonly description: "Run bulk missing/present relationship analysis over KB entities. Use for questions like which requirements lack scenarios or tests. No mutation side effects.";
38
+ readonly description: "List KB entities by the relationships they lack or have. Use for questions like which requirements lack scenarios or tests; all filters must match, and a relationship counts in either direction. Use kb_coverage instead for proof status and repair plans, and kb_check for rule violations. No mutation side effects.";
39
39
  }, {
40
40
  readonly name: "kb_coverage";
41
41
  readonly cliName: "coverage";
42
- readonly description: "Generate curated structural coverage and conservative end-to-end requirement proof reports for requirements, symbols, or grouped types. Reports include the compatible repair plan plus typed kibi.migration-plan.v2 actions; semantic and E2E actions remain review/execution work. Paginated plans identify incomplete scope and no mutation occurs.";
42
+ readonly description: "Generate curated structural coverage and conservative end-to-end requirement proof reports for requirements, symbols, or grouped types. Use it to ask which requirements are proven and what blocks the rest; use kb_find_gaps for a plain list of missing links and kb_check for rule violations. Reports include the compatible repair plan plus typed kibi.migration-plan.v2 actions; semantic and E2E actions remain review/execution work. Paginated plans identify incomplete scope and no mutation occurs.";
43
43
  }, {
44
44
  readonly name: "kb_graph";
45
45
  readonly cliName: "graph";
46
- readonly description: "Run bounded graph traversal from one or more seed IDs across curated relationship types. No mutation side effects.";
46
+ readonly description: "Run bounded graph traversal from one or more seed IDs across curated relationship types and return the nodes and edges reached. Use it to follow links from IDs you already have, such as a requirement to its scenarios and tests or a symbol to the requirements it implements; use kb_query to find entities by filter and kb_search to ask a question. Traversal stops at depth, maxNodes or maxEdges and then sets truncated. No mutation side effects.";
47
47
  }, {
48
48
  readonly name: "kb_semantic_advisor";
49
49
  readonly cliName: "semantic-advisor";
@@ -59,11 +59,11 @@ export declare const CLI_OPERATION_METADATA: readonly [{
59
59
  }, {
60
60
  readonly name: "kb_model";
61
61
  readonly cliName: "model";
62
- readonly description: "Turn requirement prose into checkable structure without writing the KB. mode:analyze returns the semantic advisor receipt: the clause ledger, what is grounded, what is ambiguous and suggested modeling (pass clauses for compound prose and optional typed kibi.logic.v1 interpretations). mode:requirement converts one claim (subjectKey, propertyKey, operator, value, or typed logic) into a strict-lane write set and applyPlan. mode:predicates ranks ontology predicate schemas and returns an applicable predicate-fact plan only for reviewed bindings, otherwise an ontology-gap observation. With requirementId, mode:predicates also returns a hash-bound plan (fact write plus requires_predicate link) for kb_apply_plan, whose contradictionAnalysis is the what-if over the current KB; other returned plans apply with kb_upsert, and kb_upsert dryRun with plannedFacts previews a requirement before its facts exist.";
62
+ readonly description: "Turn requirement prose into checkable structure without writing the KB. Use it for one requirement's prose; to plan a whole change request use kb_compile_intent. mode:analyze returns the semantic advisor receipt: the clause ledger, what is grounded, what is ambiguous and suggested modeling (pass clauses for compound prose and optional typed kibi.logic.v1 interpretations). mode:requirement converts one claim (subjectKey, propertyKey, operator, value, or typed logic) into a strict-lane write set and applyPlan. mode:predicates ranks ontology predicate schemas and returns an applicable predicate-fact plan only for reviewed bindings, otherwise an ontology-gap observation. With requirementId, mode:predicates also returns a hash-bound plan (fact write plus requires_predicate link) for kb_apply_plan, whose contradictionAnalysis is the what-if over the current KB; other returned plans apply with kb_upsert, and kb_upsert dryRun with plannedFacts previews a requirement before its facts exist.";
63
63
  }, {
64
64
  readonly name: "kb_plan_bootstrap";
65
65
  readonly cliName: "plan-bootstrap";
66
- readonly description: "Generate a deterministic, snapshot-bound kibi.bootstrap-plan.v1 for repository onboarding. Read-only analysis of the repository plus any declared knowledge sources and cited intent claims returns evidence, bounded context questions, exact dependency-ordered actions, a canonical plan hash, and no mutation side effects.";
66
+ readonly description: "Generate a deterministic, snapshot-bound kibi.bootstrap-plan.v1 for repository onboarding. Use it only to onboard a repository whose KB is empty or incomplete (the kibi-bootstrap skill drives it); for a change in an onboarded project use kb_compile_intent. Read-only analysis of the repository plus any declared knowledge sources and cited intent claims returns evidence, bounded context questions, exact dependency-ordered actions, a canonical plan hash, and no mutation side effects.";
67
67
  }, {
68
68
  readonly name: "kb_validate_upsert";
69
69
  readonly cliName: "validate-upsert";
@@ -83,7 +83,7 @@ export declare const CLI_OPERATION_METADATA: readonly [{
83
83
  }, {
84
84
  readonly name: "kb_prepare_impact_review";
85
85
  readonly cliName: "prepare-impact-review";
86
- readonly description: "Prepare complete content-bound impact-review authoring inputs from the current staged snapshot or explicitly selected immutable Git commits. Returns strict reviewer schemas and an unauthored template; it does not decide, approve, sign, stage, or prove the review.";
86
+ readonly description: "Prepare complete content-bound impact-review authoring inputs from the current staged snapshot or explicitly selected immutable Git commits. Use it when kb_check reports that changed files need an impact review; it does not plan KB changes. Returns strict reviewer schemas and an unauthored template; it does not decide, approve, sign, stage, or prove the review.";
87
87
  }, {
88
88
  readonly name: "kb_sparql_remote";
89
89
  readonly cliName: "sparql-remote";
@@ -91,7 +91,7 @@ export declare const CLI_OPERATION_METADATA: readonly [{
91
91
  }, {
92
92
  readonly name: "kb_compile_intent";
93
93
  readonly cliName: "compile-intent";
94
- readonly description: "Compile complete change intent into a deterministic, snapshot-bound read-only plan. Reuses intent-aware discovery and semantic modeling, accounts for every proposition, reports contradiction witnesses, proposes traceability links, and emits dependency-ordered kb_upsert-style steps only for resolved typed claims. contradictionAnalysis.outcome is no_conflict only when the check could decide: an unmodeled proposition or a related current requirement without logic leaves it unresolved with reasons and reviewCandidates to compare and judge through conflictReviews. No mutation side effects.";
94
+ readonly description: "Compile complete change intent into a deterministic, snapshot-bound read-only plan. Use it before editing code for a change request that may touch several requirements; use kb_model for one requirement's prose and kb_plan_bootstrap for first-time onboarding. Reuses intent-aware discovery and semantic modeling, accounts for every proposition, reports contradiction witnesses, proposes traceability links, and emits dependency-ordered kb_upsert-style steps only for resolved typed claims. contradictionAnalysis.outcome is no_conflict only when the check could decide: an unmodeled proposition or a related current requirement without logic leaves it unresolved with reasons and reviewCandidates to compare and judge through conflictReviews. No mutation side effects.";
95
95
  }, {
96
96
  readonly name: "kb_apply_plan";
97
97
  readonly cliName: "apply-plan";
@@ -35,22 +35,22 @@ export const CLI_OPERATION_METADATA = [
35
35
  {
36
36
  name: "kb_status",
37
37
  cliName: "status",
38
- description: "Report current branch, KB snapshot, freshness metadata, schema status, and a typed kibi.migration-plan.v2 action graph. Read-only status inspection with no mutation side effects; damaged stores are diagnosed without starting the engine.",
38
+ description: "Report current branch, KB snapshot, freshness metadata, schema status, and a typed kibi.migration-plan.v2 action graph. Call it first to orient on a branch or after a failed call; use kb_check for validation findings and kb_coverage for proof status. Read-only status inspection with no mutation side effects; damaged stores are diagnosed without starting the engine.",
39
39
  },
40
40
  {
41
41
  name: "kb_find_gaps",
42
42
  cliName: "find-gaps",
43
- description: "Run bulk missing/present relationship analysis over KB entities. Use for questions like which requirements lack scenarios or tests. No mutation side effects.",
43
+ description: "List KB entities by the relationships they lack or have. Use for questions like which requirements lack scenarios or tests; all filters must match, and a relationship counts in either direction. Use kb_coverage instead for proof status and repair plans, and kb_check for rule violations. No mutation side effects.",
44
44
  },
45
45
  {
46
46
  name: "kb_coverage",
47
47
  cliName: "coverage",
48
- description: "Generate curated structural coverage and conservative end-to-end requirement proof reports for requirements, symbols, or grouped types. Reports include the compatible repair plan plus typed kibi.migration-plan.v2 actions; semantic and E2E actions remain review/execution work. Paginated plans identify incomplete scope and no mutation occurs.",
48
+ description: "Generate curated structural coverage and conservative end-to-end requirement proof reports for requirements, symbols, or grouped types. Use it to ask which requirements are proven and what blocks the rest; use kb_find_gaps for a plain list of missing links and kb_check for rule violations. Reports include the compatible repair plan plus typed kibi.migration-plan.v2 actions; semantic and E2E actions remain review/execution work. Paginated plans identify incomplete scope and no mutation occurs.",
49
49
  },
50
50
  {
51
51
  name: "kb_graph",
52
52
  cliName: "graph",
53
- description: "Run bounded graph traversal from one or more seed IDs across curated relationship types. No mutation side effects.",
53
+ description: "Run bounded graph traversal from one or more seed IDs across curated relationship types and return the nodes and edges reached. Use it to follow links from IDs you already have, such as a requirement to its scenarios and tests or a symbol to the requirements it implements; use kb_query to find entities by filter and kb_search to ask a question. Traversal stops at depth, maxNodes or maxEdges and then sets truncated. No mutation side effects.",
54
54
  },
55
55
  {
56
56
  name: "kb_semantic_advisor",
@@ -70,12 +70,12 @@ export const CLI_OPERATION_METADATA = [
70
70
  {
71
71
  name: "kb_model",
72
72
  cliName: "model",
73
- description: "Turn requirement prose into checkable structure without writing the KB. mode:analyze returns the semantic advisor receipt: the clause ledger, what is grounded, what is ambiguous and suggested modeling (pass clauses for compound prose and optional typed kibi.logic.v1 interpretations). mode:requirement converts one claim (subjectKey, propertyKey, operator, value, or typed logic) into a strict-lane write set and applyPlan. mode:predicates ranks ontology predicate schemas and returns an applicable predicate-fact plan only for reviewed bindings, otherwise an ontology-gap observation. With requirementId, mode:predicates also returns a hash-bound plan (fact write plus requires_predicate link) for kb_apply_plan, whose contradictionAnalysis is the what-if over the current KB; other returned plans apply with kb_upsert, and kb_upsert dryRun with plannedFacts previews a requirement before its facts exist.",
73
+ description: "Turn requirement prose into checkable structure without writing the KB. Use it for one requirement's prose; to plan a whole change request use kb_compile_intent. mode:analyze returns the semantic advisor receipt: the clause ledger, what is grounded, what is ambiguous and suggested modeling (pass clauses for compound prose and optional typed kibi.logic.v1 interpretations). mode:requirement converts one claim (subjectKey, propertyKey, operator, value, or typed logic) into a strict-lane write set and applyPlan. mode:predicates ranks ontology predicate schemas and returns an applicable predicate-fact plan only for reviewed bindings, otherwise an ontology-gap observation. With requirementId, mode:predicates also returns a hash-bound plan (fact write plus requires_predicate link) for kb_apply_plan, whose contradictionAnalysis is the what-if over the current KB; other returned plans apply with kb_upsert, and kb_upsert dryRun with plannedFacts previews a requirement before its facts exist.",
74
74
  },
75
75
  {
76
76
  name: "kb_plan_bootstrap",
77
77
  cliName: "plan-bootstrap",
78
- description: "Generate a deterministic, snapshot-bound kibi.bootstrap-plan.v1 for repository onboarding. Read-only analysis of the repository plus any declared knowledge sources and cited intent claims returns evidence, bounded context questions, exact dependency-ordered actions, a canonical plan hash, and no mutation side effects.",
78
+ description: "Generate a deterministic, snapshot-bound kibi.bootstrap-plan.v1 for repository onboarding. Use it only to onboard a repository whose KB is empty or incomplete (the kibi-bootstrap skill drives it); for a change in an onboarded project use kb_compile_intent. Read-only analysis of the repository plus any declared knowledge sources and cited intent claims returns evidence, bounded context questions, exact dependency-ordered actions, a canonical plan hash, and no mutation side effects.",
79
79
  },
80
80
  {
81
81
  name: "kb_validate_upsert",
@@ -100,7 +100,7 @@ export const CLI_OPERATION_METADATA = [
100
100
  {
101
101
  name: "kb_prepare_impact_review",
102
102
  cliName: "prepare-impact-review",
103
- description: "Prepare complete content-bound impact-review authoring inputs from the current staged snapshot or explicitly selected immutable Git commits. Returns strict reviewer schemas and an unauthored template; it does not decide, approve, sign, stage, or prove the review.",
103
+ description: "Prepare complete content-bound impact-review authoring inputs from the current staged snapshot or explicitly selected immutable Git commits. Use it when kb_check reports that changed files need an impact review; it does not plan KB changes. Returns strict reviewer schemas and an unauthored template; it does not decide, approve, sign, stage, or prove the review.",
104
104
  },
105
105
  {
106
106
  name: "kb_sparql_remote",
@@ -110,7 +110,7 @@ export const CLI_OPERATION_METADATA = [
110
110
  {
111
111
  name: "kb_compile_intent",
112
112
  cliName: "compile-intent",
113
- description: "Compile complete change intent into a deterministic, snapshot-bound read-only plan. Reuses intent-aware discovery and semantic modeling, accounts for every proposition, reports contradiction witnesses, proposes traceability links, and emits dependency-ordered kb_upsert-style steps only for resolved typed claims. contradictionAnalysis.outcome is no_conflict only when the check could decide: an unmodeled proposition or a related current requirement without logic leaves it unresolved with reasons and reviewCandidates to compare and judge through conflictReviews. No mutation side effects.",
113
+ description: "Compile complete change intent into a deterministic, snapshot-bound read-only plan. Use it before editing code for a change request that may touch several requirements; use kb_model for one requirement's prose and kb_plan_bootstrap for first-time onboarding. Reuses intent-aware discovery and semantic modeling, accounts for every proposition, reports contradiction witnesses, proposes traceability links, and emits dependency-ordered kb_upsert-style steps only for resolved typed claims. contradictionAnalysis.outcome is no_conflict only when the check could decide: an unmodeled proposition or a related current requirement without logic leaves it unresolved with reasons and reviewCandidates to compare and judge through conflictReviews. No mutation side effects.",
114
114
  },
115
115
  {
116
116
  name: "kb_apply_plan",
@@ -1 +1 @@
1
- {"version":3,"file":"cli-register-reporting.d.ts","sourceRoot":"","sources":["../src/cli-register-reporting.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAYzC,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAsMhE"}
1
+ {"version":3,"file":"cli-register-reporting.d.ts","sourceRoot":"","sources":["../src/cli-register-reporting.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAYzC,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAkOhE"}
@@ -46,6 +46,18 @@ export function registerReportingCommands(program) {
46
46
  .action(async (options) => {
47
47
  await (await import("./commands/report.js")).reportCommand(options);
48
48
  });
49
+ program
50
+ .command("signoff")
51
+ .description("Show the requirements a change adds, rewrites or affects (or, with --questions, the decisions waiting for the person) as chat Markdown, a fenced block for host renderers, an HTML page or JSON for signoff")
52
+ .option("--staged", "Summarize staged changes instead of the working tree", false)
53
+ .option("--questions <path>", 'Render decision questions from a JSON file (use - for stdin): {"questions":[{"statement":"...","quote":"...","firmness":"firm"}]}')
54
+ .option("--format <format>", "Output format: chat (plain Markdown for a reply) | md (fenced block for host renderers) | html | json; default chat, or KIBI_SIGNOFF_FORMAT")
55
+ .option("--output <path>", "HTML file to write (default .kb/briefs/signoff/latest.html)")
56
+ .option("--open", "Open the HTML page in the default browser", false)
57
+ .option("--no-proof", "Skip the proof-state lookup (faster; no Prolog)")
58
+ .action(async (options) => {
59
+ await (await import("./commands/signoff.js")).signoffCommand(options);
60
+ });
49
61
  program
50
62
  .command("coverage")
51
63
  .description(getCliOperationMetadata("kb_coverage").description)
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAQpC,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAMtD,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAUrD;AAED,wBAAgB,eAAe,CAC7B,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,SAAS,EAAE,MAAM,GAChB,OAAO,CAIT;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAI7D;AAGD,wBAAgB,YAAY,IAAI,OAAO,CAiBtC;AAGD,wBAAsB,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC,CAe3C;AAED,wBAAsB,kBAAkB,CACtC,YAAY,UAAoD,EAChE,KAAK,cAAO,GACX,OAAO,CAAC,IAAI,CAAC,CAGf"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AASpC,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAMtD,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAUrD;AAED,wBAAgB,eAAe,CAC7B,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,SAAS,EAAE,MAAM,GAChB,OAAO,CAIT;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAM7D;AAGD,wBAAgB,YAAY,IAAI,OAAO,CAiBtC;AAGD,wBAAsB,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC,CAe3C;AAED,wBAAsB,kBAAkB,CACtC,YAAY,UAAoD,EAChE,KAAK,cAAO,GACX,OAAO,CAAC,IAAI,CAAC,CAGf"}
package/dist/cli.js CHANGED
@@ -20,6 +20,7 @@ import { readFileSync } from "node:fs";
20
20
  import { resolve } from "node:path";
21
21
  import { pathToFileURL } from "node:url";
22
22
  import { Command } from "commander";
23
+ import { errorWasReported } from "./cli-command.js";
23
24
  import { registerFoundationCommands } from "./cli-register-foundation.js";
24
25
  import { registerJsonOnlyCommands } from "./cli-register-json.js";
25
26
  import { registerMaintenanceCommands } from "./cli-register-maintenance.js";
@@ -41,8 +42,10 @@ export function isCliEntrypoint(argv1, moduleUrl) {
41
42
  return (argv1 !== undefined && moduleUrl === pathToFileURL(resolve(argv1)).href);
42
43
  }
43
44
  export function exitCodeFromCliFailure(error) {
44
- const message = error instanceof Error ? error.message : String(error);
45
- console.error(message);
45
+ if (!errorWasReported(error)) {
46
+ const message = error instanceof Error ? error.message : String(error);
47
+ console.error(message);
48
+ }
46
49
  return 1;
47
50
  }
48
51
  // implements REQ-kibi-operation-interface-parity
@@ -1 +1 @@
1
- {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"AAqCA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAmF7C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAE3D,YAAY,EAAE,SAAS,EAAE,CAAC;AAE1B,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC1B;AA6hBD,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,CAAC,EACtC,MAAM,EAAE,CAAC,GAAG,IAAI,GAAG,SAAS,EAC5B,MAAM,EAAE,CAAC,GAAG,IAAI,GAAG,SAAS,GAC3B,WAAW,CAAC,CAAC,GAAG,CAAC,CAAC,CAMpB;AAGD,wBAAsB,YAAY,CAChC,OAAO,EAAE,YAAY,GACpB,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAurB/B;AAED,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,SAAS,EAAE,CAAC,CAoDtB;AAID,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,MAAM,EAAE,CAAC,CAgBnB;AAED,wBAAsB,eAAe,CACnC,MAAM,EAAE,aAAa,EACrB,IAAI,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC,MAAM,EAAE,CAAC,CAiBnB;AAED,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,SAAS,EAAE,CAAC,CAkEtB;AAID,wBAAsB,aAAa,CACjC,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,SAAS,EAAE,CAAC,CAmGtB;AAED,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,aAAa,EACrB,YAAY,EAAE,MAAM,EAAE,GACrB,OAAO,CAAC,SAAS,EAAE,CAAC,CAyCtB;AAED,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,SAAS,EAAE,CAAC,CAgDtB;AAED,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,SAAS,EAAE,CAAC,CA0BtB;AAED,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,SAAS,EAAE,CAAC,CAqBtB;AAED,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,SAAS,EAAE,CAAC,CAqBtB;AAED,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,SAAS,EAAE,CAAC,CAqBtB"}
1
+ {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"AAqCA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAqF7C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAE3D,YAAY,EAAE,SAAS,EAAE,CAAC;AAE1B,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC1B;AA6hBD,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,CAAC,EACtC,MAAM,EAAE,CAAC,GAAG,IAAI,GAAG,SAAS,EAC5B,MAAM,EAAE,CAAC,GAAG,IAAI,GAAG,SAAS,GAC3B,WAAW,CAAC,CAAC,GAAG,CAAC,CAAC,CAMpB;AAGD,wBAAsB,YAAY,CAChC,OAAO,EAAE,YAAY,GACpB,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CA6rB/B;AAED,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,SAAS,EAAE,CAAC,CAoDtB;AAID,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,MAAM,EAAE,CAAC,CAgBnB;AAED,wBAAsB,eAAe,CACnC,MAAM,EAAE,aAAa,EACrB,IAAI,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC,MAAM,EAAE,CAAC,CAiBnB;AAED,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,SAAS,EAAE,CAAC,CAkEtB;AAID,wBAAsB,aAAa,CACjC,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,SAAS,EAAE,CAAC,CAmGtB;AAED,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,aAAa,EACrB,YAAY,EAAE,MAAM,EAAE,GACrB,OAAO,CAAC,SAAS,EAAE,CAAC,CAyCtB;AAED,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,SAAS,EAAE,CAAC,CAgDtB;AAED,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,SAAS,EAAE,CAAC,CA0BtB;AAED,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,SAAS,EAAE,CAAC,CAqBtB;AAED,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,SAAS,EAAE,CAAC,CAqBtB;AAED,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,SAAS,EAAE,CAAC,CAqBtB"}
@@ -25,7 +25,9 @@ import { PrologProcess } from "../prolog.js";
25
25
  import { escapeAtom, normalizeEntityId, parseTriples, parseViolationRows, } from "../prolog/codec.js";
26
26
  import { createSemanticReviewDiagnostics, createSymbolGranularityDiagnostics, createSymbolQualityDiagnostics, hasBlockingImpactDiagnostics, } from "../public/impact-diagnostics.js";
27
27
  import { executeCheck } from "../public/operations/check-executor.js";
28
+ import { nodeGit } from "../public/operations/node-ports.js";
28
29
  import { refreshDetachedSnapshot } from "../runtime/detached-snapshot.js";
30
+ import { amendsRootCommit } from "../traceability/commit-amend.js";
29
31
  import { KIBI_NO_IMPACT_DECLARATION, KIBI_SYMBOLS_MANIFEST_PATH, KIBI_SYMBOL_COORDINATES_PATH, } from "../traceability/evidence-model.js";
30
32
  import { captureStagedSnapshot } from "../traceability/git-change-snapshot.js";
31
33
  import { supportedStagedFiles, } from "../traceability/git-staged.js";
@@ -617,6 +619,8 @@ export async function checkCommand(options) {
617
619
  const inventoryDrift = stagedInventoryDriftViolations({
618
620
  stagedPaths: new Set(markdownFiles.map((file) => file.path)),
619
621
  snapshotEntities,
622
+ judgeNewRequirements: snapshot.headCommit !== null &&
623
+ !amendsRootCommit(process.cwd(), snapshot.headCommit),
620
624
  readBase: (filePath) => {
621
625
  try {
622
626
  return snapshot
@@ -634,7 +638,7 @@ export async function checkCommand(options) {
634
638
  coverage: stagedCoverage,
635
639
  violations: inventoryDrift,
636
640
  messages: [
637
- `${inventoryDrift.length} staged requirement(s) have a semantic inventory that no longer matches their prose:`,
641
+ `${inventoryDrift.length} staged requirement(s) have a semantic inventory that is missing or no longer matches their prose:`,
638
642
  ...inventoryDrift.map((violation) => ` ${violation.message}`),
639
643
  ],
640
644
  });
@@ -927,6 +931,9 @@ export async function checkCommand(options) {
927
931
  workspaceRoot: process.cwd(),
928
932
  signal: new AbortController().signal,
929
933
  clock: () => new Date(),
934
+ // The workspace snapshot lets quality diagnostics read the same
935
+ // proof receipt evidence as kibi coverage.
936
+ git: nodeGit,
930
937
  prolog: {
931
938
  query: (goal) => activeProlog.query(goal),
932
939
  ...(activeProlog instanceof EngineClient
@@ -1 +1 @@
1
- {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/commands/engine.ts"],"names":[],"mappings":"AAuCA,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CA4BzD;AAED,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAWvD;AAED,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC,CAE1D;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;GAMG;AAEH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAiDf;AAED,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC,CAkB3D;AAED,wBAAsB,oBAAoB,CAAC,OAAO,EAAE;IAClD,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,IAAI,CAAC,CAWhB"}
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/commands/engine.ts"],"names":[],"mappings":"AA6CA,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CA4BzD;AAcD,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAyBvD;AAED,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC,CAE1D;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;GAMG;AAEH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAiDf;AAED,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC,CAkB3D;AAED,wBAAsB,oBAAoB,CAAC,OAAO,EAAE;IAClD,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,IAAI,CAAC,CAWhB"}
@@ -1,5 +1,6 @@
1
1
  import path from "node:path";
2
2
  import { EngineClient } from "../engine.js";
3
+ import { classifyStoreLockHolder, describeLockHolderPid, lockHolderProcess, readStoreLockOwner, } from "../prolog/store-lock.js";
3
4
  import { resolveBranchAttachment, resolveReadBranchAttachment, } from "../utils/branch-resolver.js";
4
5
  // Engine maintenance never writes the KB, so a detached HEAD addresses the
5
6
  // daemon serving its read-only snapshot.
@@ -55,14 +56,37 @@ export async function engineStatusCommand() {
55
56
  await engine.terminate();
56
57
  }
57
58
  }
59
+ /** The pid of a live process holding the active branch store, if any. */
60
+ function liveStoreLockHolder(root) {
61
+ const attachment = resolveReadBranchAttachment(root);
62
+ if ("error" in attachment)
63
+ return null;
64
+ const recorded = readStoreLockOwner(attachment.storePath);
65
+ if (recorded === null)
66
+ return null;
67
+ const state = classifyStoreLockHolder(recorded.owner);
68
+ return state === "alive" && recorded.owner.pid !== undefined
69
+ ? recorded.owner.pid
70
+ : null;
71
+ }
58
72
  export async function engineStopCommand() {
59
73
  const engine = client();
60
74
  try {
61
75
  // Stopping an absent daemon must remain a no-op. Starting SWI merely to
62
76
  // shut it down defeats the maintenance command and can unexpectedly
63
77
  // migrate a legacy branch during an operator status check.
64
- await engine.stop(false);
65
- console.log("Kibi engine stopped");
78
+ const branch = currentBranch(workspaceRoot());
79
+ if (await engine.stop(false)) {
80
+ console.log("Kibi engine stopped");
81
+ return;
82
+ }
83
+ const { engineSocketPath } = await import("../engine.js");
84
+ console.log(`No Kibi engine answered at ${engineSocketPath(workspaceRoot(), branch)}`);
85
+ const holder = liveStoreLockHolder(workspaceRoot());
86
+ if (holder !== null) {
87
+ const owner = lockHolderProcess(holder);
88
+ console.log(`The branch store is still held by ${describeLockHolderPid(holder)}. That engine was likely started with a different KIBI_RUNTIME_DIR, XDG_RUNTIME_DIR or TMPDIR; stop it from the same environment, or end pid ${owner.pid}.`);
89
+ }
66
90
  }
67
91
  finally {
68
92
  await engine.terminate();
@@ -0,0 +1,37 @@
1
+ import { type SignoffCollectDeps } from "../signoff/collect.js";
2
+ import { type SignoffView } from "../signoff/model.js";
3
+ export type SignoffOptions = Readonly<{
4
+ staged?: boolean;
5
+ questions?: string;
6
+ format?: string;
7
+ output?: string;
8
+ open?: boolean;
9
+ proof?: boolean;
10
+ }>;
11
+ export type SignoffCommandDeps = SignoffCollectDeps & Readonly<{
12
+ cwd?: () => string;
13
+ readStdin?: () => string;
14
+ write?: (text: string) => void;
15
+ writeNote?: (text: string) => void;
16
+ env?: NodeJS.ProcessEnv;
17
+ openReport?: (filePath: string) => Promise<void>;
18
+ }>;
19
+ /** Sets the default signoff format for a host (`chat`, `md`, `html`, `json`). */
20
+ export declare const SIGNOFF_FORMAT_ENV = "KIBI_SIGNOFF_FORMAT";
21
+ /**
22
+ * The format `kibi signoff` prints when `--format` is not given. A fenced
23
+ * block only helps where a host renderer draws it (the OpenCode TUI, which
24
+ * sets KIBI_SIGNOFF_FORMAT=md for its shell); every other host renders
25
+ * assistant or message Markdown directly and shows a fence as code, so the
26
+ * default is the unfenced `chat` Markdown.
27
+ */
28
+ export declare function defaultSignoffFormat(env: NodeJS.ProcessEnv): string;
29
+ /**
30
+ * `kibi signoff`: print the requirements signoff view for the current change
31
+ * (or, with `--questions`, the decisions the agent asks the person to
32
+ * confirm) as chat Markdown, a fenced Markdown block, HTML or JSON, and keep the latest view
33
+ * in `.kb/briefs/signoff/` (latest.json, latest.md, latest.html) for editor
34
+ * plugins.
35
+ */
36
+ export declare function signoffCommand(options: SignoffOptions, deps?: SignoffCommandDeps): Promise<SignoffView>;
37
+ //# sourceMappingURL=signoff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signoff.d.ts","sourceRoot":"","sources":["../../src/commands/signoff.ts"],"names":[],"mappings":"AAOA,OAAO,EACL,KAAK,kBAAkB,EAKxB,MAAM,uBAAuB,CAAC;AAQ/B,OAAO,EAKL,KAAK,WAAW,EACjB,MAAM,qBAAqB,CAAC;AAG7B,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC;IACpC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC,CAAC;AAGH,MAAM,MAAM,kBAAkB,GAAG,kBAAkB,GACjD,QAAQ,CAAC;IACP,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAClD,CAAC,CAAC;AAKL,iFAAiF;AACjF,eAAO,MAAM,kBAAkB,wBAAwB,CAAC;AAGxD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,MAAM,CAGnE;AAoFD;;;;;;GAMG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,cAAc,EACvB,IAAI,GAAE,kBAAuB,GAC5B,OAAO,CAAC,WAAW,CAAC,CA4EtB"}
@@ -0,0 +1,152 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { readFileSync } from "node:fs";
3
+ import { mkdir, rename, rm, writeFile } from "node:fs/promises";
4
+ import path from "node:path";
5
+ import { coverageSpec } from "../public/operations/specs/reporting.js";
6
+ import { earliestUnmetGate } from "../report/html-report.js";
7
+ import { collectSignoffQuestions, collectSignoffSummary, parseSignoffQuestionsInput, } from "../signoff/collect.js";
8
+ import { renderSignoffHtml } from "../signoff/html.js";
9
+ import { renderQuestionsMarkdownBody, renderSignoffChatMarkdown, renderSignoffMarkdown, renderSummaryMarkdownBody, } from "../signoff/markdown.js";
10
+ import { SIGNOFF_LATEST_HTML, SIGNOFF_LATEST_JSON, SIGNOFF_LATEST_MARKDOWN, } from "../signoff/model.js";
11
+ import { openReport } from "./report.js";
12
+ const FORMATS = new Set(["chat", "md", "html", "json"]);
13
+ // implements REQ-kibi-signoff-views
14
+ /** Sets the default signoff format for a host (`chat`, `md`, `html`, `json`). */
15
+ export const SIGNOFF_FORMAT_ENV = "KIBI_SIGNOFF_FORMAT";
16
+ // implements REQ-kibi-signoff-views
17
+ /**
18
+ * The format `kibi signoff` prints when `--format` is not given. A fenced
19
+ * block only helps where a host renderer draws it (the OpenCode TUI, which
20
+ * sets KIBI_SIGNOFF_FORMAT=md for its shell); every other host renders
21
+ * assistant or message Markdown directly and shows a fence as code, so the
22
+ * default is the unfenced `chat` Markdown.
23
+ */
24
+ export function defaultSignoffFormat(env) {
25
+ const configured = env[SIGNOFF_FORMAT_ENV]?.trim().toLowerCase();
26
+ return configured && FORMATS.has(configured) ? configured : "chat";
27
+ }
28
+ async function writeAtomically(filePath, contents) {
29
+ await mkdir(path.dirname(filePath), { recursive: true });
30
+ const temporary = path.join(path.dirname(filePath), `.${path.basename(filePath)}.${randomUUID()}.tmp`);
31
+ try {
32
+ await writeFile(temporary, contents, "utf8");
33
+ await rename(temporary, filePath);
34
+ }
35
+ catch (error) {
36
+ await rm(temporary, { force: true });
37
+ throw error;
38
+ }
39
+ }
40
+ function record(value) {
41
+ return value !== null && typeof value === "object"
42
+ ? value
43
+ : {};
44
+ }
45
+ /** Proof state per requirement from the requirement coverage report. */
46
+ async function loadProof() {
47
+ const { createCliRuntime } = await import("../runtime/cli-runtime.js");
48
+ const runtime = createCliRuntime();
49
+ const spec = coverageSpec;
50
+ const context = await runtime.open(spec);
51
+ let rows = [];
52
+ try {
53
+ const result = await coverageSpec.execute({
54
+ by: "req",
55
+ tags: [],
56
+ includePassing: true,
57
+ includeTransitive: true,
58
+ limit: 100_000,
59
+ offset: 0,
60
+ }, context);
61
+ rows = (result.structuredContent?.rows ?? []);
62
+ }
63
+ catch (error) {
64
+ await runtime.close(context, { status: "error", error });
65
+ throw error;
66
+ }
67
+ await runtime.close(context, { status: "success", result: rows.length });
68
+ const proof = new Map();
69
+ for (const row of rows) {
70
+ if (typeof row.id !== "string")
71
+ continue;
72
+ const conflicts = (record(record(row.proofStages).contradictions)
73
+ .conflicts ?? []);
74
+ proof.set(row.id, {
75
+ status: typeof row.proofStatus === "string" ? row.proofStatus : "missing",
76
+ gate: earliestUnmetGate(row),
77
+ testCount: typeof row.testCount === "number" ? row.testCount : 0,
78
+ contradictions: conflicts
79
+ .map(record)
80
+ .filter((conflict) => conflict.status === "contradiction")
81
+ .map((conflict) => typeof conflict.reason === "string"
82
+ ? conflict.reason
83
+ : "Two current requirements encode incompatible claims."),
84
+ });
85
+ }
86
+ return proof;
87
+ }
88
+ function readQuestionsSource(source, cwd, readStdin) {
89
+ return source === "-"
90
+ ? readStdin()
91
+ : readFileSync(path.resolve(cwd, source), "utf8");
92
+ }
93
+ // implements REQ-kibi-signoff-views
94
+ /**
95
+ * `kibi signoff`: print the requirements signoff view for the current change
96
+ * (or, with `--questions`, the decisions the agent asks the person to
97
+ * confirm) as chat Markdown, a fenced Markdown block, HTML or JSON, and keep the latest view
98
+ * in `.kb/briefs/signoff/` (latest.json, latest.md, latest.html) for editor
99
+ * plugins.
100
+ */
101
+ export async function signoffCommand(options, deps = {}) {
102
+ const format = (options.format ?? defaultSignoffFormat(deps.env ?? process.env))
103
+ .trim()
104
+ .toLowerCase();
105
+ if (!FORMATS.has(format)) {
106
+ throw new Error(`Unknown signoff format "${options.format}": use chat, md, html or json`);
107
+ }
108
+ const cwd = (deps.cwd ?? (() => process.cwd()))();
109
+ const write = deps.write ?? ((text) => process.stdout.write(text));
110
+ const scope = options.staged ? "staged" : "working";
111
+ const view = options.questions !== undefined
112
+ ? collectSignoffQuestions(cwd, parseSignoffQuestionsInput(readQuestionsSource(options.questions, cwd, deps.readStdin ?? (() => readFileSync(0, "utf8")))), deps.now)
113
+ : await collectSignoffSummary(cwd, scope, {
114
+ ...(deps.git ? { git: deps.git } : {}),
115
+ ...(deps.loadAffected ? { loadAffected: deps.loadAffected } : {}),
116
+ ...(deps.now ? { now: deps.now } : {}),
117
+ ...(options.proof === false
118
+ ? {}
119
+ : { loadProof: deps.loadProof ?? loadProof }),
120
+ });
121
+ const html = renderSignoffHtml(view);
122
+ await writeAtomically(path.join(cwd, SIGNOFF_LATEST_JSON), `${JSON.stringify(view, null, 2)}\n`);
123
+ await writeAtomically(path.join(cwd, SIGNOFF_LATEST_MARKDOWN), `${view.kind === "summary"
124
+ ? renderSummaryMarkdownBody(view, Number.POSITIVE_INFINITY)
125
+ : renderQuestionsMarkdownBody(view)}\n`);
126
+ await writeAtomically(path.join(cwd, SIGNOFF_LATEST_HTML), html);
127
+ if (format === "json") {
128
+ write(`${JSON.stringify(view, null, 2)}\n`);
129
+ }
130
+ else if (format === "md") {
131
+ write(renderSignoffMarkdown(view));
132
+ }
133
+ else if (format === "chat") {
134
+ write(`${renderSignoffChatMarkdown(view)}\n`);
135
+ // The page path goes to stderr so stdout stays pasteable as the reply.
136
+ (deps.writeNote ?? ((text) => process.stderr.write(text)))(`Kibi signoff page: ${path.join(cwd, SIGNOFF_LATEST_HTML)} (attach or publish it next to the reply when the host can show a page)\n`);
137
+ }
138
+ else {
139
+ const target = options.output?.trim()
140
+ ? path.resolve(cwd, options.output.trim())
141
+ : path.join(cwd, SIGNOFF_LATEST_HTML);
142
+ if (target !== path.join(cwd, SIGNOFF_LATEST_HTML)) {
143
+ await writeAtomically(target, html);
144
+ }
145
+ write(`Kibi signoff page written to ${target}\n`);
146
+ if (options.open === true) {
147
+ await (deps.openReport ?? openReport)(target);
148
+ write("Opened the signoff page in the default browser\n");
149
+ }
150
+ }
151
+ return view;
152
+ }
@@ -6,6 +6,16 @@ import type { PendingSourceReceiptSnapshot } from "./sync/discovery.js";
6
6
  export declare class SyncError extends Error {
7
7
  constructor(message: string);
8
8
  }
9
+ /**
10
+ * Sources staged as new files (renames included) that HEAD does not contain yet. An empty branch
11
+ * store compiles its first sync as a semantic baseline, which accepts
12
+ * requirements without an inventory. Once another branch of the workspace has
13
+ * synced, that grace covers committed history only: a new branch must not
14
+ * accept a staged requirement its parent branch would refuse. Without a HEAD
15
+ * commit (or outside Git) there is no history to tell apart, and the set is
16
+ * empty.
17
+ */
18
+ export declare function stagedNewSourceKeys(workspaceRoot: string): Set<string>;
9
19
  export declare function trackedRelationshipFiles(workspaceRoot: string, relationshipsDir: string, recoverMissingPendingSources?: boolean, recoveredPendingReceiptPaths?: PendingSourceReceiptSnapshot[]): string[];
10
20
  export interface SyncResult extends SyncSummary {
11
21
  exitCode?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"AA6BA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AA6BjE,OAAO,EAEL,yBAAyB,EAE1B,MAAM,gDAAgD,CAAC;AAGxD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EACL,KAAK,gBAAgB,EAGtB,MAAM,6BAA6B,CAAC;AA0BrC,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,qBAAqB,CAAC;AAmCxE,qBAAa,SAAU,SAAQ,KAAK;gBACtB,OAAO,EAAE,MAAM;CAI5B;AAmCD,wBAAgB,wBAAwB,CACtC,aAAa,EAAE,MAAM,EACrB,gBAAgB,EAAE,MAAM,EACxB,4BAA4B,UAAQ,EACpC,4BAA4B,GAAE,4BAA4B,EAAO,GAChE,MAAM,EAAE,CAuGV;AAiFD,MAAM,WAAW,UAAW,SAAQ,WAAW;IAC7C,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,UAAU,yBAAyB;IACjC,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,OAAO,CAAC;CACvB;AAED,UAAU,kBAAkB;IAC1B,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,yBAAyB,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC3E,UAAU,CAAC,EAAE,CACX,OAAO,EAAE,yBAAyB,GAAG;QAAE,UAAU,EAAE,OAAO,CAAA;KAAE,KACzD,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC1B,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,KAAK,aAAa,CAAC;IAC/D,yBAAyB,CAAC,EAAE,OAAO,yBAAyB,CAAC;CAC9D;AA+FD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAGvE;AAGD,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,IAAI,GAChB,IAAI,CAMN;AAED,wBAAgB,4BAA4B,CAC1C,WAAW,EAAE,UAAU,EAAE,EACzB,QAAQ,EAAE,OAAO,EACjB,OAAO,EAAE,OAAO,EAChB,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,GACf,IAAI,CAIN;AAED,wBAAgB,0BAA0B,CAAC,MAAM,EAAE;IACjD,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,IAAI,CAMP;AAED,wBAAgB,iCAAiC,CAC/C,WAAW,EAAE,UAAU,EAAE,EACzB,oBAAoB,EAAE,OAAO,EAC7B,iBAAiB,EAAE,MAAM,EACzB,WAAW,EAAE,MAAM,GAClB,IAAI,CAUN;AAGD,wBAAsB,WAAW,CAC/B,OAAO,GAAE;IACP,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,2EAA2E;IAC3E,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,wEAAwE;IACxE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,uEAAuE;IACvE,KAAK,CAAC,EAAE,OAAO,CAAC;CACZ,EACN,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,UAAU,CAAC,CA2uCrB;AAED,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"AA8BA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AA6BjE,OAAO,EAEL,yBAAyB,EAE1B,MAAM,gDAAgD,CAAC;AAGxD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EACL,KAAK,gBAAgB,EAGtB,MAAM,6BAA6B,CAAC;AA2BrC,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,qBAAqB,CAAC;AAmCxE,qBAAa,SAAU,SAAQ,KAAK;gBACtB,OAAO,EAAE,MAAM;CAI5B;AAmCD;;;;;;;;GAQG;AAEH,wBAAgB,mBAAmB,CAAC,aAAa,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAqBtE;AAkCD,wBAAgB,wBAAwB,CACtC,aAAa,EAAE,MAAM,EACrB,gBAAgB,EAAE,MAAM,EACxB,4BAA4B,UAAQ,EACpC,4BAA4B,GAAE,4BAA4B,EAAO,GAChE,MAAM,EAAE,CAuGV;AAiFD,MAAM,WAAW,UAAW,SAAQ,WAAW;IAC7C,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,UAAU,yBAAyB;IACjC,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,OAAO,CAAC;CACvB;AAED,UAAU,kBAAkB;IAC1B,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,yBAAyB,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC3E,UAAU,CAAC,EAAE,CACX,OAAO,EAAE,yBAAyB,GAAG;QAAE,UAAU,EAAE,OAAO,CAAA;KAAE,KACzD,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC1B,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,KAAK,aAAa,CAAC;IAC/D,yBAAyB,CAAC,EAAE,OAAO,yBAAyB,CAAC;CAC9D;AA+FD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAGvE;AAGD,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,IAAI,GAChB,IAAI,CAMN;AAED,wBAAgB,4BAA4B,CAC1C,WAAW,EAAE,UAAU,EAAE,EACzB,QAAQ,EAAE,OAAO,EACjB,OAAO,EAAE,OAAO,EAChB,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,GACf,IAAI,CAIN;AAED,wBAAgB,0BAA0B,CAAC,MAAM,EAAE;IACjD,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,IAAI,CAMP;AAED,wBAAgB,iCAAiC,CAC/C,WAAW,EAAE,UAAU,EAAE,EACzB,oBAAoB,EAAE,OAAO,EAC7B,iBAAiB,EAAE,MAAM,EACzB,WAAW,EAAE,MAAM,GAClB,IAAI,CAUN;AAGD,wBAAsB,WAAW,CAC/B,OAAO,GAAE;IACP,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,2EAA2E;IAC3E,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,wEAAwE;IACxE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,uEAAuE;IACvE,KAAK,CAAC,EAAE,OAAO,CAAC;CACZ,EACN,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,UAAU,CAAC,CAmvCrB;AAED,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC"}