kibi-cli 2.36.0 → 2.39.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.
- package/dist/cli-json-command.d.ts.map +1 -1
- package/dist/cli-json-command.js +4 -0
- package/dist/cli-operation-metadata.d.ts +1 -1
- package/dist/cli-operation-metadata.js +1 -1
- package/dist/cli-register-foundation.d.ts.map +1 -1
- package/dist/cli-register-foundation.js +2 -1
- package/dist/cli-register-maintenance.d.ts.map +1 -1
- package/dist/cli-register-maintenance.js +5 -0
- package/dist/cli-register-reporting.d.ts.map +1 -1
- package/dist/cli-register-reporting.js +1 -0
- package/dist/cli-validate.d.ts.map +1 -1
- package/dist/cli-validate.js +21 -2
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +19 -1
- package/dist/commands/aggregated-checks.d.ts.map +1 -1
- package/dist/commands/aggregated-checks.js +89 -16
- package/dist/commands/coverage.d.ts +1 -0
- package/dist/commands/coverage.d.ts.map +1 -1
- package/dist/commands/coverage.js +40 -0
- package/dist/commands/doctor.d.ts +5 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +70 -35
- package/dist/commands/github-init.d.ts.map +1 -1
- package/dist/commands/github-init.js +4 -2
- package/dist/commands/hook-managers.d.ts +43 -0
- package/dist/commands/hook-managers.d.ts.map +1 -0
- package/dist/commands/hook-managers.js +426 -0
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +40 -5
- package/dist/commands/migrate.d.ts.map +1 -1
- package/dist/commands/migrate.js +9 -3
- package/dist/commands/sync/persistence.d.ts.map +1 -1
- package/dist/commands/sync/persistence.js +49 -1
- package/dist/commands/telemetry.d.ts +7 -0
- package/dist/commands/telemetry.d.ts.map +1 -0
- package/dist/commands/telemetry.js +23 -0
- package/dist/decision-firmness.d.ts.map +1 -1
- package/dist/decision-firmness.js +11 -14
- package/dist/engine-limits.d.ts.map +1 -1
- package/dist/engine-limits.js +8 -10
- package/dist/entity-body-context.d.ts.map +1 -1
- package/dist/entity-body-context.js +39 -36
- package/dist/extractors/markdown.d.ts +6 -0
- package/dist/extractors/markdown.d.ts.map +1 -1
- package/dist/extractors/markdown.js +21 -0
- package/dist/extractors/symbol-coordinates.d.ts.map +1 -1
- package/dist/extractors/symbol-coordinates.js +23 -4
- package/dist/firm-decision-edit.d.ts.map +1 -1
- package/dist/firm-decision-edit.js +1 -3
- package/dist/intent-search.d.ts +5 -1
- package/dist/intent-search.d.ts.map +1 -1
- package/dist/intent-search.js +118 -33
- package/dist/logic/ir.d.ts.map +1 -1
- package/dist/logic/ir.js +82 -108
- package/dist/operations/bootstrap/discovery-evidence.d.ts.map +1 -1
- package/dist/operations/bootstrap/discovery-evidence.js +44 -2
- package/dist/operations/bootstrap/discovery.d.ts.map +1 -1
- package/dist/operations/bootstrap/discovery.js +1 -0
- package/dist/operations/bootstrap/guidance-actions.d.ts.map +1 -1
- package/dist/operations/bootstrap/guidance-actions.js +2 -1
- package/dist/operations/bootstrap/plugin-offers.d.ts +11 -2
- package/dist/operations/bootstrap/plugin-offers.d.ts.map +1 -1
- package/dist/operations/bootstrap/plugin-offers.js +48 -9
- package/dist/operations/proof/claim-bindings.d.ts.map +1 -1
- package/dist/operations/proof/claim-bindings.js +1 -0
- package/dist/operations/proof/code-certificates.d.ts +2 -0
- package/dist/operations/proof/code-certificates.d.ts.map +1 -1
- package/dist/operations/proof/code-certificates.js +34 -14
- package/dist/operations/proof/code-models.d.ts.map +1 -1
- package/dist/operations/proof/code-models.js +19 -5
- package/dist/operations/proof/code-runner.d.ts +16 -0
- package/dist/operations/proof/code-runner.d.ts.map +1 -1
- package/dist/operations/proof/code-runner.js +42 -6
- package/dist/operations/proof/explain.d.ts +63 -0
- package/dist/operations/proof/explain.d.ts.map +1 -1
- package/dist/operations/proof/explain.js +162 -0
- package/dist/operations/semantic-advisor/analyze-prose.d.ts +9 -1
- package/dist/operations/semantic-advisor/analyze-prose.d.ts.map +1 -1
- package/dist/operations/semantic-advisor/analyze-prose.js +21 -0
- package/dist/operations/semantic-advisor/case-preview.d.ts +24 -0
- package/dist/operations/semantic-advisor/case-preview.d.ts.map +1 -0
- package/dist/operations/semantic-advisor/case-preview.js +216 -0
- package/dist/operations/semantic-advisor/shared.d.ts.map +1 -1
- package/dist/operations/semantic-advisor/shared.js +3 -0
- package/dist/operations/semantic-advisor/types.d.ts +23 -0
- package/dist/operations/semantic-advisor/types.d.ts.map +1 -1
- package/dist/plugins/approved-source-analyzers.generated.d.ts +11 -8
- package/dist/plugins/approved-source-analyzers.generated.d.ts.map +1 -1
- package/dist/plugins/approved-source-analyzers.generated.js +11 -8
- package/dist/plugins/compose-search-hints.d.ts +29 -0
- package/dist/plugins/compose-search-hints.d.ts.map +1 -0
- package/dist/plugins/compose-search-hints.js +94 -0
- package/dist/plugins/external-allowlist.d.ts +7 -0
- package/dist/plugins/external-allowlist.d.ts.map +1 -1
- package/dist/plugins/external-allowlist.js +11 -0
- package/dist/plugins/registry.d.ts +8 -1
- package/dist/plugins/registry.d.ts.map +1 -1
- package/dist/plugins/registry.js +22 -3
- package/dist/plugins/source-classification.d.ts +2 -2
- package/dist/plugins/source-classification.d.ts.map +1 -1
- package/dist/plugins/source-classification.js +25 -1
- package/dist/prolog/codec.d.ts.map +1 -1
- package/dist/prolog/codec.js +10 -20
- package/dist/public/impact/coverage-depth-quality.d.ts.map +1 -1
- package/dist/public/impact/coverage-depth-quality.js +32 -16
- package/dist/public/impact/full-kb-quality.d.ts +6 -0
- package/dist/public/impact/full-kb-quality.d.ts.map +1 -1
- package/dist/public/impact/full-kb-quality.js +8 -3
- package/dist/public/impact/requirement-quality.d.ts.map +1 -1
- package/dist/public/impact/requirement-quality.js +56 -29
- package/dist/public/operations/catalog.d.ts +44 -4
- package/dist/public/operations/catalog.d.ts.map +1 -1
- package/dist/public/operations/check-executor.d.ts +6 -0
- package/dist/public/operations/check-executor.d.ts.map +1 -1
- package/dist/public/operations/check-executor.js +34 -2
- package/dist/public/operations/discovery-executors.d.ts +5 -1
- package/dist/public/operations/discovery-executors.d.ts.map +1 -1
- package/dist/public/operations/discovery-executors.js +65 -4
- package/dist/public/operations/evidence-floor.d.ts +8 -1
- package/dist/public/operations/evidence-floor.d.ts.map +1 -1
- package/dist/public/operations/evidence-floor.js +3 -4
- package/dist/public/operations/migration-plan.d.ts.map +1 -1
- package/dist/public/operations/migration-plan.js +41 -10
- package/dist/public/operations/node-ports.d.ts.map +1 -1
- package/dist/public/operations/node-ports.js +3 -1
- package/dist/public/operations/repair-plan.d.ts +46 -0
- package/dist/public/operations/repair-plan.d.ts.map +1 -1
- package/dist/public/operations/repair-plan.js +110 -1
- package/dist/public/operations/schema6-check-actions.js +1 -1
- package/dist/public/operations/source-analysis-cache.d.ts +22 -0
- package/dist/public/operations/source-analysis-cache.d.ts.map +1 -0
- package/dist/public/operations/source-analysis-cache.js +157 -0
- package/dist/public/operations/specs/check-rules.generated.d.ts +1 -1
- package/dist/public/operations/specs/check-rules.generated.d.ts.map +1 -1
- package/dist/public/operations/specs/check-rules.generated.js +2 -1
- package/dist/public/operations/specs/check.d.ts +1 -1
- package/dist/public/operations/specs/discovery.d.ts +7 -2
- package/dist/public/operations/specs/discovery.d.ts.map +1 -1
- package/dist/public/operations/specs/discovery.js +7 -2
- package/dist/public/operations/specs/mutation-schemas.d.ts +36 -1
- package/dist/public/operations/specs/mutation-schemas.d.ts.map +1 -1
- package/dist/public/operations/specs/mutation-schemas.js +30 -0
- package/dist/public/operations/specs/upsert.d.ts +36 -1
- package/dist/public/operations/specs/upsert.d.ts.map +1 -1
- package/dist/public/operations/symbol-granularity-check.d.ts +3 -1
- package/dist/public/operations/symbol-granularity-check.d.ts.map +1 -1
- package/dist/public/operations/symbol-granularity-check.js +21 -7
- package/dist/public/proof-protocol.d.ts +6 -1
- package/dist/public/proof-protocol.d.ts.map +1 -1
- package/dist/public/proof-protocol.js +12 -3
- package/dist/public/proof-sources.d.ts +2 -0
- package/dist/public/proof-sources.d.ts.map +1 -1
- package/dist/public/proof-sources.js +32 -6
- package/dist/public/schemas/entity.d.ts.map +1 -1
- package/dist/public/schemas/entity.js +59 -0
- package/dist/public/skills/kibi-bootstrap/SKILL.md +2 -2
- package/dist/public/skills/kibi-commit-review/SKILL.md +6 -2
- package/dist/public/skills/kibi-decisions/SKILL.md +7 -2
- package/dist/public/skills/kibi-decisions/resources/signoff-views.md +3 -1
- package/dist/public/skills/kibi-usage/SKILL.md +50 -3
- package/dist/public/skills/kibi-usage/resources/fact-lanes.md +34 -0
- package/dist/public/skills/kibi-usage/resources/proof.md +13 -5
- package/dist/public/skills/kibi-usage/resources/workflows.md +10 -0
- package/dist/relationships/shards.d.ts +2 -0
- package/dist/relationships/shards.d.ts.map +1 -1
- package/dist/relationships/shards.js +25 -1
- package/dist/schemas/entity.schema.json +98 -1
- package/dist/search-answer.d.ts +3 -2
- package/dist/search-answer.d.ts.map +1 -1
- package/dist/search-answer.js +57 -4
- package/dist/search-hints.d.ts +58 -0
- package/dist/search-hints.d.ts.map +1 -0
- package/dist/search-hints.js +187 -0
- package/dist/search-ranking.d.ts +7 -0
- package/dist/search-ranking.d.ts.map +1 -1
- package/dist/search-ranking.js +54 -56
- package/dist/search-token-cache.d.ts +30 -0
- package/dist/search-token-cache.d.ts.map +1 -0
- package/dist/search-token-cache.js +86 -0
- package/dist/traceability/impact-knowledge.d.ts.map +1 -1
- package/dist/traceability/impact-knowledge.js +2 -0
- package/dist/traceability/temp-kb.d.ts.map +1 -1
- package/dist/traceability/temp-kb.js +11 -1
- package/dist/types/entities.d.ts +12 -0
- package/dist/types/entities.d.ts.map +1 -1
- package/dist/usage-telemetry.d.ts +20 -0
- package/dist/usage-telemetry.d.ts.map +1 -0
- package/dist/usage-telemetry.js +93 -0
- package/dist/utils/branch-resolver.d.ts.map +1 -1
- package/dist/utils/branch-resolver.js +1 -0
- package/dist/utils/rule-registry.generated.d.ts +5 -0
- package/dist/utils/rule-registry.generated.d.ts.map +1 -1
- package/dist/utils/rule-registry.generated.js +6 -0
- package/package.json +5 -4
- package/schema/entities.pl +12 -0
- package/src/public/impact/coverage-depth-quality.ts +59 -21
- package/src/public/impact/full-kb-quality.ts +15 -1
- package/src/public/impact/requirement-quality.ts +95 -38
- package/src/public/operations/check-executor.ts +41 -1
- package/src/public/operations/discovery-executors.ts +92 -4
- package/src/public/operations/evidence-floor.ts +15 -3
- package/src/public/operations/migration-plan.ts +41 -9
- package/src/public/operations/node-ports.ts +3 -1
- package/src/public/operations/repair-plan.ts +152 -1
- package/src/public/operations/schema6-check-actions.ts +1 -1
- package/src/public/operations/source-analysis-cache.ts +196 -0
- package/src/public/operations/specs/check-rules.generated.ts +2 -1
- package/src/public/operations/specs/discovery.ts +8 -2
- package/src/public/operations/specs/mutation-schemas.ts +34 -0
- package/src/public/operations/symbol-granularity-check.ts +25 -5
- package/src/public/proof-protocol-types.d.ts +1 -1
- package/src/public/proof-protocol.ts +18 -4
- package/src/public/proof-sources.ts +37 -6
- package/src/public/schemas/entity.ts +65 -0
- package/src/public/skills/kibi-bootstrap/SKILL.md +2 -2
- package/src/public/skills/kibi-commit-review/SKILL.md +6 -2
- package/src/public/skills/kibi-decisions/SKILL.md +7 -2
- package/src/public/skills/kibi-decisions/resources/signoff-views.md +3 -1
- package/src/public/skills/kibi-usage/SKILL.md +50 -3
- package/src/public/skills/kibi-usage/resources/fact-lanes.md +34 -0
- package/src/public/skills/kibi-usage/resources/proof.md +13 -5
- package/src/public/skills/kibi-usage/resources/workflows.md +10 -0
- package/src/schemas/entity.schema.json +98 -1
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { type ManagedHookName } from "./init-helpers.js";
|
|
2
|
+
/** Git hook managers whose configuration Kibi can print and read. */
|
|
3
|
+
export declare const HOOK_MANAGER_NAMES: readonly ["lefthook", "husky", "pre-commit"];
|
|
4
|
+
export type HookManagerName = (typeof HOOK_MANAGER_NAMES)[number];
|
|
5
|
+
/** Formats `kibi init --print-hook` can emit. */
|
|
6
|
+
export declare const HOOK_SNIPPET_FORMATS: readonly ["shell", "lefthook", "husky", "pre-commit"];
|
|
7
|
+
export type HookSnippetFormat = (typeof HOOK_SNIPPET_FORMATS)[number];
|
|
8
|
+
export interface DetectedHookManager {
|
|
9
|
+
name: HookManagerName;
|
|
10
|
+
/** Repository-relative file or directory that holds the hook definitions. */
|
|
11
|
+
configPath: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* The hook manager that owns this repository's Git hooks, if any. Installed
|
|
15
|
+
* hook files are the strongest evidence (they show what Git runs today), then
|
|
16
|
+
* a core.hooksPath pointing into `.husky`, then a manager configuration file
|
|
17
|
+
* that has not been installed yet.
|
|
18
|
+
*/
|
|
19
|
+
export declare function detectHookManager(worktreeRoot: string, effectiveHooksDir: string, hooksPathConfig?: string | null): DetectedHookManager | null;
|
|
20
|
+
/**
|
|
21
|
+
* The commands a hook manager runs for one Git hook, read from its
|
|
22
|
+
* configuration, or null when the manager does not define that hook (or its
|
|
23
|
+
* configuration cannot be read).
|
|
24
|
+
*/
|
|
25
|
+
export declare function hookManagerCommands(manager: HookManagerName, worktreeRoot: string, hook: ManagedHookName): string[] | null;
|
|
26
|
+
/** Labels of the Kibi commands a hook definition never visibly runs. */
|
|
27
|
+
export declare function missingKibiHookCommands(hook: ManagedHookName, scripts: readonly string[]): string[];
|
|
28
|
+
/**
|
|
29
|
+
* Configuration that wires the given hooks to the commands Kibi's managed
|
|
30
|
+
* templates run, in a hook manager's own format. `shell` and `husky` print
|
|
31
|
+
* the hook-script snippets of `kibi init --print-hook`.
|
|
32
|
+
*/
|
|
33
|
+
export declare function hookManagerSnippet(format: HookSnippetFormat, hooks: readonly ManagedHookName[]): string;
|
|
34
|
+
export interface HookManagerCoverage {
|
|
35
|
+
hook: ManagedHookName;
|
|
36
|
+
/** Kibi commands the manager's definition of this hook does not visibly run. */
|
|
37
|
+
missing: string[];
|
|
38
|
+
/** Whether the manager defines the hook at all. */
|
|
39
|
+
configured: boolean;
|
|
40
|
+
}
|
|
41
|
+
/** What each Kibi-managed hook looks like in the manager's configuration. */
|
|
42
|
+
export declare function hookManagerCoverage(manager: HookManagerName, worktreeRoot: string): HookManagerCoverage[];
|
|
43
|
+
//# sourceMappingURL=hook-managers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hook-managers.d.ts","sourceRoot":"","sources":["../../src/commands/hook-managers.ts"],"names":[],"mappings":"AAqBA,OAAO,EAEL,KAAK,eAAe,EAErB,MAAM,mBAAmB,CAAC;AAE3B,qEAAqE;AACrE,eAAO,MAAM,kBAAkB,8CAA+C,CAAC;AAE/E,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC;AAElE,iDAAiD;AACjD,eAAO,MAAM,oBAAoB,uDAA4C,CAAC;AAE9E,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEtE,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,eAAe,CAAC;IACtB,6EAA6E;IAC7E,UAAU,EAAE,MAAM,CAAC;CACpB;AAqGD;;;;;GAKG;AAEH,wBAAgB,iBAAiB,CAC/B,YAAY,EAAE,MAAM,EACpB,iBAAiB,EAAE,MAAM,EACzB,eAAe,GAAE,MAAM,GAAG,IAAW,GACpC,mBAAmB,GAAG,IAAI,CAwB5B;AAmID;;;;GAIG;AAEH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,eAAe,EACxB,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,eAAe,GACpB,MAAM,EAAE,GAAG,IAAI,CAWjB;AAkED,wEAAwE;AAExE,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,eAAe,EACrB,OAAO,EAAE,SAAS,MAAM,EAAE,GACzB,MAAM,EAAE,CAKV;AAsFD;;;;GAIG;AAEH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE,SAAS,eAAe,EAAE,GAChC,MAAM,CAiBR;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,eAAe,CAAC;IACtB,gFAAgF;IAChF,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,mDAAmD;IACnD,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,6EAA6E;AAE7E,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,eAAe,EACxB,YAAY,EAAE,MAAM,GACnB,mBAAmB,EAAE,CASvB"}
|
|
@@ -0,0 +1,426 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Kibi — repo-local, per-branch, queryable long-term memory for software projects
|
|
3
|
+
Copyright (C) 2026 Piotr Franczyk
|
|
4
|
+
|
|
5
|
+
This program is free software: you can redistribute it and/or modify
|
|
6
|
+
it under the terms of the GNU Affero General Public License as published by
|
|
7
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
(at your option) any later version.
|
|
9
|
+
|
|
10
|
+
This program is distributed in the hope that it will be useful,
|
|
11
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
GNU Affero General Public License for more details.
|
|
14
|
+
|
|
15
|
+
You should have received a copy of the GNU Affero General Public License
|
|
16
|
+
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
+
*/
|
|
18
|
+
import { readFileSync, statSync } from "node:fs";
|
|
19
|
+
import * as path from "node:path";
|
|
20
|
+
import { parse as parseYaml } from "yaml";
|
|
21
|
+
import { MANAGED_HOOK_NAMES, hookDelegationSnippet, } from "./init-helpers.js";
|
|
22
|
+
/** Git hook managers whose configuration Kibi can print and read. */
|
|
23
|
+
export const HOOK_MANAGER_NAMES = ["lefthook", "husky", "pre-commit"];
|
|
24
|
+
/** Formats `kibi init --print-hook` can emit. */
|
|
25
|
+
export const HOOK_SNIPPET_FORMATS = ["shell", ...HOOK_MANAGER_NAMES];
|
|
26
|
+
// lefthook reads the first of these it finds; the -local variants are merged
|
|
27
|
+
// on top of the main file.
|
|
28
|
+
const LEFTHOOK_CONFIG_FILES = [
|
|
29
|
+
"lefthook.yml",
|
|
30
|
+
".lefthook.yml",
|
|
31
|
+
"lefthook.yaml",
|
|
32
|
+
".lefthook.yaml",
|
|
33
|
+
"lefthook.json",
|
|
34
|
+
".lefthook.json",
|
|
35
|
+
"lefthook.jsonc",
|
|
36
|
+
".lefthook.jsonc",
|
|
37
|
+
"lefthook.toml",
|
|
38
|
+
".lefthook.toml",
|
|
39
|
+
".config/lefthook.yml",
|
|
40
|
+
".config/lefthook.yaml",
|
|
41
|
+
];
|
|
42
|
+
const LEFTHOOK_LOCAL_CONFIG_FILES = [
|
|
43
|
+
"lefthook-local.yml",
|
|
44
|
+
".lefthook-local.yml",
|
|
45
|
+
"lefthook-local.yaml",
|
|
46
|
+
".lefthook-local.yaml",
|
|
47
|
+
"lefthook-local.json",
|
|
48
|
+
".lefthook-local.json",
|
|
49
|
+
];
|
|
50
|
+
const PRE_COMMIT_CONFIG_FILE = ".pre-commit-config.yaml";
|
|
51
|
+
const HUSKY_DIR = ".husky";
|
|
52
|
+
/** Hooks in the order a reader expects them: the commit gate first. */
|
|
53
|
+
const PRINT_ORDER = [
|
|
54
|
+
"pre-commit",
|
|
55
|
+
"post-checkout",
|
|
56
|
+
"post-merge",
|
|
57
|
+
"post-rewrite",
|
|
58
|
+
];
|
|
59
|
+
// The local runner every Node.js install ships with. `--no-install` never
|
|
60
|
+
// downloads a kibi outside the project lockfile.
|
|
61
|
+
const KIBI_COMMAND = "npx --no-install kibi";
|
|
62
|
+
function isFile(filePath) {
|
|
63
|
+
try {
|
|
64
|
+
return statSync(filePath).isFile();
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function isDirectory(filePath) {
|
|
71
|
+
try {
|
|
72
|
+
return statSync(filePath).isDirectory();
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function readText(filePath) {
|
|
79
|
+
try {
|
|
80
|
+
return readFileSync(filePath, "utf8");
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function firstExisting(root, candidates) {
|
|
87
|
+
return candidates.find((file) => isFile(path.join(root, file))) ?? null;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Which manager generated a hook file, from the marker text each one emits.
|
|
91
|
+
* husky is recognized by core.hooksPath instead: its hook files are the
|
|
92
|
+
* project's own scripts, which may mention husky without being generated.
|
|
93
|
+
*/
|
|
94
|
+
function hookFileManager(content) {
|
|
95
|
+
if (content.includes("File generated by pre-commit"))
|
|
96
|
+
return "pre-commit";
|
|
97
|
+
if (/\blefthook\b/.test(content))
|
|
98
|
+
return "lefthook";
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
function managerConfigPath(worktreeRoot, name) {
|
|
102
|
+
switch (name) {
|
|
103
|
+
case "lefthook":
|
|
104
|
+
return (firstExisting(worktreeRoot, LEFTHOOK_CONFIG_FILES) ?? "lefthook.yml");
|
|
105
|
+
case "husky":
|
|
106
|
+
return HUSKY_DIR;
|
|
107
|
+
case "pre-commit":
|
|
108
|
+
return PRE_COMMIT_CONFIG_FILE;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* The hook manager that owns this repository's Git hooks, if any. Installed
|
|
113
|
+
* hook files are the strongest evidence (they show what Git runs today), then
|
|
114
|
+
* a core.hooksPath pointing into `.husky`, then a manager configuration file
|
|
115
|
+
* that has not been installed yet.
|
|
116
|
+
*/
|
|
117
|
+
// implements REQ-git-hook-manager-integration
|
|
118
|
+
export function detectHookManager(worktreeRoot, effectiveHooksDir, hooksPathConfig = null) {
|
|
119
|
+
const found = (name) => ({
|
|
120
|
+
name,
|
|
121
|
+
configPath: managerConfigPath(worktreeRoot, name),
|
|
122
|
+
});
|
|
123
|
+
for (const hook of MANAGED_HOOK_NAMES) {
|
|
124
|
+
const content = readText(path.join(effectiveHooksDir, hook));
|
|
125
|
+
const manager = content === null ? null : hookFileManager(content);
|
|
126
|
+
if (manager)
|
|
127
|
+
return found(manager);
|
|
128
|
+
}
|
|
129
|
+
if (hooksPathConfig !== null &&
|
|
130
|
+
/(?:^|[\\/])\.husky(?:[\\/]_)?[\\/]?$/.test(hooksPathConfig.trim())) {
|
|
131
|
+
return found("husky");
|
|
132
|
+
}
|
|
133
|
+
if (firstExisting(worktreeRoot, LEFTHOOK_CONFIG_FILES)) {
|
|
134
|
+
return found("lefthook");
|
|
135
|
+
}
|
|
136
|
+
if (isDirectory(path.join(worktreeRoot, HUSKY_DIR)))
|
|
137
|
+
return found("husky");
|
|
138
|
+
if (isFile(path.join(worktreeRoot, PRE_COMMIT_CONFIG_FILE))) {
|
|
139
|
+
return found("pre-commit");
|
|
140
|
+
}
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
function parseConfig(filePath) {
|
|
144
|
+
const text = readText(filePath);
|
|
145
|
+
if (text === null)
|
|
146
|
+
return undefined;
|
|
147
|
+
try {
|
|
148
|
+
return parseYaml(text);
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
return undefined;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
function asRecord(value) {
|
|
155
|
+
return value !== null && typeof value === "object" && !Array.isArray(value)
|
|
156
|
+
? value
|
|
157
|
+
: null;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Every shell command lefthook runs for one hook: `run` strings of commands
|
|
161
|
+
* and jobs (including nested groups), plus the contents of the scripts it
|
|
162
|
+
* executes from `.lefthook/<hook>/`.
|
|
163
|
+
*/
|
|
164
|
+
function lefthookRuns(node, scriptDir, commands) {
|
|
165
|
+
if (Array.isArray(node)) {
|
|
166
|
+
for (const item of node)
|
|
167
|
+
lefthookRuns(item, scriptDir, commands);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
const record = asRecord(node);
|
|
171
|
+
if (!record)
|
|
172
|
+
return;
|
|
173
|
+
for (const [key, value] of Object.entries(record)) {
|
|
174
|
+
if (key === "run" && typeof value === "string") {
|
|
175
|
+
commands.push(value);
|
|
176
|
+
}
|
|
177
|
+
else if (key === "script" && typeof value === "string") {
|
|
178
|
+
const script = readText(path.join(scriptDir, value));
|
|
179
|
+
if (script !== null)
|
|
180
|
+
commands.push(script);
|
|
181
|
+
}
|
|
182
|
+
else if (key === "scripts" && asRecord(value)) {
|
|
183
|
+
for (const name of Object.keys(value)) {
|
|
184
|
+
const script = readText(path.join(scriptDir, name));
|
|
185
|
+
if (script !== null)
|
|
186
|
+
commands.push(script);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
lefthookRuns(value, scriptDir, commands);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
function lefthookCommands(worktreeRoot, hook) {
|
|
195
|
+
const main = firstExisting(worktreeRoot, LEFTHOOK_CONFIG_FILES);
|
|
196
|
+
const files = [
|
|
197
|
+
...(main ? [main] : []),
|
|
198
|
+
...LEFTHOOK_LOCAL_CONFIG_FILES.filter((file) => isFile(path.join(worktreeRoot, file))),
|
|
199
|
+
];
|
|
200
|
+
let configured = false;
|
|
201
|
+
const commands = [];
|
|
202
|
+
for (const file of files) {
|
|
203
|
+
// TOML configs are not read; their hooks count as not visible.
|
|
204
|
+
const hookNode = asRecord(parseConfig(path.join(worktreeRoot, file)))?.[hook];
|
|
205
|
+
if (hookNode === undefined || hookNode === null)
|
|
206
|
+
continue;
|
|
207
|
+
configured = true;
|
|
208
|
+
lefthookRuns(hookNode, path.join(worktreeRoot, ".lefthook", hook), commands);
|
|
209
|
+
}
|
|
210
|
+
return configured ? commands : null;
|
|
211
|
+
}
|
|
212
|
+
// pre-commit stage names before 3.2 dropped the `pre-` prefix.
|
|
213
|
+
const LEGACY_PRE_COMMIT_STAGES = {
|
|
214
|
+
commit: "pre-commit",
|
|
215
|
+
push: "pre-push",
|
|
216
|
+
"merge-commit": "pre-merge-commit",
|
|
217
|
+
};
|
|
218
|
+
function preCommitFrameworkCommands(worktreeRoot, hook) {
|
|
219
|
+
const config = asRecord(parseConfig(path.join(worktreeRoot, PRE_COMMIT_CONFIG_FILE)));
|
|
220
|
+
if (!config || !Array.isArray(config.repos))
|
|
221
|
+
return null;
|
|
222
|
+
const defaultStages = Array.isArray(config.default_stages)
|
|
223
|
+
? config.default_stages
|
|
224
|
+
: null;
|
|
225
|
+
let configured = false;
|
|
226
|
+
const commands = [];
|
|
227
|
+
for (const repo of config.repos) {
|
|
228
|
+
const hooks = asRecord(repo)?.hooks;
|
|
229
|
+
if (!Array.isArray(hooks))
|
|
230
|
+
continue;
|
|
231
|
+
for (const entry of hooks) {
|
|
232
|
+
const definition = asRecord(entry);
|
|
233
|
+
if (!definition)
|
|
234
|
+
continue;
|
|
235
|
+
const stages = Array.isArray(definition.stages)
|
|
236
|
+
? definition.stages
|
|
237
|
+
: defaultStages;
|
|
238
|
+
const runsHere = stages === null
|
|
239
|
+
? hook === "pre-commit"
|
|
240
|
+
: stages.some((stage) => typeof stage === "string" &&
|
|
241
|
+
(LEGACY_PRE_COMMIT_STAGES[stage] ?? stage) === hook);
|
|
242
|
+
if (!runsHere)
|
|
243
|
+
continue;
|
|
244
|
+
configured = true;
|
|
245
|
+
// Only local hooks carry a shell entry; remote hooks are opaque here.
|
|
246
|
+
if (typeof definition.entry === "string") {
|
|
247
|
+
const args = Array.isArray(definition.args)
|
|
248
|
+
? definition.args.filter((arg) => typeof arg === "string")
|
|
249
|
+
: [];
|
|
250
|
+
commands.push([definition.entry, ...args].join(" "));
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
return configured ? commands : null;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* The commands a hook manager runs for one Git hook, read from its
|
|
258
|
+
* configuration, or null when the manager does not define that hook (or its
|
|
259
|
+
* configuration cannot be read).
|
|
260
|
+
*/
|
|
261
|
+
// implements REQ-git-hook-manager-integration
|
|
262
|
+
export function hookManagerCommands(manager, worktreeRoot, hook) {
|
|
263
|
+
switch (manager) {
|
|
264
|
+
case "lefthook":
|
|
265
|
+
return lefthookCommands(worktreeRoot, hook);
|
|
266
|
+
case "husky": {
|
|
267
|
+
const script = readText(path.join(worktreeRoot, HUSKY_DIR, hook));
|
|
268
|
+
return script === null ? null : [script];
|
|
269
|
+
}
|
|
270
|
+
case "pre-commit":
|
|
271
|
+
return preCommitFrameworkCommands(worktreeRoot, hook);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Individual shell commands of a hook script, ignoring comments. Lines are
|
|
276
|
+
* split on command separators so `a && b` counts as two commands.
|
|
277
|
+
*/
|
|
278
|
+
function splitShellCommands(content) {
|
|
279
|
+
return content
|
|
280
|
+
.split("\n")
|
|
281
|
+
.filter((line) => !line.trimStart().startsWith("#"))
|
|
282
|
+
.flatMap((line) => line.split(/&&|\|\||;|\|/))
|
|
283
|
+
.map((command) => command.trim())
|
|
284
|
+
.filter((command) => command.length > 0);
|
|
285
|
+
}
|
|
286
|
+
// Matches `kibi <sub>`, `npx kibi <sub>`, `node_modules/.bin/kibi <sub>` and
|
|
287
|
+
// the template's `"$KIBI_BIN" <sub>`.
|
|
288
|
+
function invokesKibi(command, subcommand) {
|
|
289
|
+
return new RegExp(`(?:\\bkibi|\\bKIBI_BIN)["'}]*\\s+${subcommand}(?=[\\s"']|$)`).test(command);
|
|
290
|
+
}
|
|
291
|
+
// A flag ends at whitespace, a closing quote (`sh -c '... --staged'`) or the
|
|
292
|
+
// end of the command.
|
|
293
|
+
function hasFlag(command, flag) {
|
|
294
|
+
return new RegExp(`\\s${flag}(?=[\\s"']|$)`).test(command);
|
|
295
|
+
}
|
|
296
|
+
/** The commands each Kibi-managed hook template runs. */
|
|
297
|
+
const KIBI_HOOK_DELEGATIONS = (() => {
|
|
298
|
+
const sync = [
|
|
299
|
+
{
|
|
300
|
+
label: "kibi sync",
|
|
301
|
+
matches: (command) => invokesKibi(command, "sync"),
|
|
302
|
+
},
|
|
303
|
+
];
|
|
304
|
+
return {
|
|
305
|
+
"pre-commit": [
|
|
306
|
+
{
|
|
307
|
+
label: "kibi check-generated --staged --changed-only",
|
|
308
|
+
matches: (command) => invokesKibi(command, "check-generated") &&
|
|
309
|
+
hasFlag(command, "--staged") &&
|
|
310
|
+
hasFlag(command, "--changed-only"),
|
|
311
|
+
},
|
|
312
|
+
{
|
|
313
|
+
label: "kibi check --staged",
|
|
314
|
+
matches: (command) => invokesKibi(command, "check") && hasFlag(command, "--staged"),
|
|
315
|
+
},
|
|
316
|
+
],
|
|
317
|
+
"post-checkout": sync,
|
|
318
|
+
"post-merge": sync,
|
|
319
|
+
"post-rewrite": sync,
|
|
320
|
+
};
|
|
321
|
+
})();
|
|
322
|
+
/** Labels of the Kibi commands a hook definition never visibly runs. */
|
|
323
|
+
// implements REQ-git-hook-manager-integration
|
|
324
|
+
export function missingKibiHookCommands(hook, scripts) {
|
|
325
|
+
const commands = scripts.flatMap(splitShellCommands);
|
|
326
|
+
return KIBI_HOOK_DELEGATIONS[hook]
|
|
327
|
+
.filter((delegation) => !commands.some(delegation.matches))
|
|
328
|
+
.map((delegation) => delegation.label);
|
|
329
|
+
}
|
|
330
|
+
function ordered(hooks) {
|
|
331
|
+
return PRINT_ORDER.filter((hook) => hooks.includes(hook));
|
|
332
|
+
}
|
|
333
|
+
// Runs in lefthook's shell, where {N} is the Nth Git hook argument.
|
|
334
|
+
const LEFTHOOK_RUNS = {
|
|
335
|
+
"pre-commit": `${KIBI_COMMAND} check-generated --staged --changed-only && ${KIBI_COMMAND} check --staged`,
|
|
336
|
+
"post-checkout": `if [ "{3}" = "1" ]; then ${KIBI_COMMAND} sync; fi`,
|
|
337
|
+
"post-merge": `${KIBI_COMMAND} sync`,
|
|
338
|
+
"post-rewrite": `if [ "{1}" = "rebase" ]; then ${KIBI_COMMAND} sync; fi`,
|
|
339
|
+
};
|
|
340
|
+
function lefthookSnippet(hooks) {
|
|
341
|
+
const lines = [
|
|
342
|
+
"# Kibi git hook commands for lefthook. Merge these entries into your",
|
|
343
|
+
"# lefthook.yml (keep your existing commands), then run 'lefthook install'.",
|
|
344
|
+
];
|
|
345
|
+
for (const hook of hooks) {
|
|
346
|
+
lines.push(`${hook}:`, " commands:");
|
|
347
|
+
if (hook === "post-checkout") {
|
|
348
|
+
lines.push(" # {3} is 1 for a branch checkout, 0 for a file checkout.");
|
|
349
|
+
}
|
|
350
|
+
lines.push(` ${hook === "pre-commit" ? "kibi-check" : "kibi-sync"}:`, ` run: ${LEFTHOOK_RUNS[hook]}`);
|
|
351
|
+
}
|
|
352
|
+
return `${lines.join("\n")}\n`;
|
|
353
|
+
}
|
|
354
|
+
// pre-commit exposes post-checkout and post-rewrite arguments as variables.
|
|
355
|
+
const PRE_COMMIT_FRAMEWORK_HOOKS = {
|
|
356
|
+
"pre-commit": {
|
|
357
|
+
id: "kibi-check",
|
|
358
|
+
name: "kibi check --staged",
|
|
359
|
+
entry: `sh -c '${KIBI_COMMAND} check-generated --staged --changed-only && ${KIBI_COMMAND} check --staged'`,
|
|
360
|
+
},
|
|
361
|
+
"post-checkout": {
|
|
362
|
+
id: "kibi-sync-checkout",
|
|
363
|
+
name: "kibi sync (branch checkout)",
|
|
364
|
+
entry: `sh -c 'if [ "$PRE_COMMIT_CHECKOUT_TYPE" = "1" ]; then ${KIBI_COMMAND} sync; fi'`,
|
|
365
|
+
},
|
|
366
|
+
"post-merge": {
|
|
367
|
+
id: "kibi-sync-merge",
|
|
368
|
+
name: "kibi sync (merge)",
|
|
369
|
+
entry: `${KIBI_COMMAND} sync`,
|
|
370
|
+
},
|
|
371
|
+
"post-rewrite": {
|
|
372
|
+
id: "kibi-sync-rebase",
|
|
373
|
+
name: "kibi sync (rebase)",
|
|
374
|
+
entry: `sh -c 'if [ "$PRE_COMMIT_REWRITE_COMMAND" = "rebase" ]; then ${KIBI_COMMAND} sync; fi'`,
|
|
375
|
+
},
|
|
376
|
+
};
|
|
377
|
+
function preCommitFrameworkSnippet(hooks) {
|
|
378
|
+
const lines = [
|
|
379
|
+
"# Kibi git hooks for the pre-commit framework. Merge into your",
|
|
380
|
+
"# .pre-commit-config.yaml (add the hook types to any existing",
|
|
381
|
+
"# default_install_hook_types and the hooks to a local repo), then run",
|
|
382
|
+
`# 'pre-commit install'.`,
|
|
383
|
+
`default_install_hook_types: [${hooks.join(", ")}]`,
|
|
384
|
+
"repos:",
|
|
385
|
+
" - repo: local",
|
|
386
|
+
" hooks:",
|
|
387
|
+
];
|
|
388
|
+
for (const hook of hooks) {
|
|
389
|
+
const definition = PRE_COMMIT_FRAMEWORK_HOOKS[hook];
|
|
390
|
+
lines.push(` - id: ${definition.id}`, ` name: ${definition.name}`, ` entry: ${definition.entry}`, " language: system", " pass_filenames: false", " always_run: true", ` stages: [${hook}]`);
|
|
391
|
+
}
|
|
392
|
+
return `${lines.join("\n")}\n`;
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* Configuration that wires the given hooks to the commands Kibi's managed
|
|
396
|
+
* templates run, in a hook manager's own format. `shell` and `husky` print
|
|
397
|
+
* the hook-script snippets of `kibi init --print-hook`.
|
|
398
|
+
*/
|
|
399
|
+
// implements REQ-git-hook-manager-integration
|
|
400
|
+
export function hookManagerSnippet(format, hooks) {
|
|
401
|
+
const selected = ordered(hooks);
|
|
402
|
+
switch (format) {
|
|
403
|
+
case "shell":
|
|
404
|
+
return selected.map(hookDelegationSnippet).join("\n");
|
|
405
|
+
case "husky":
|
|
406
|
+
return selected
|
|
407
|
+
.map((hook) => `# --- ${HUSKY_DIR}/${hook} ---\n${hookDelegationSnippet(hook)}`)
|
|
408
|
+
.join("\n");
|
|
409
|
+
case "lefthook":
|
|
410
|
+
return lefthookSnippet(selected);
|
|
411
|
+
case "pre-commit":
|
|
412
|
+
return preCommitFrameworkSnippet(selected);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
/** What each Kibi-managed hook looks like in the manager's configuration. */
|
|
416
|
+
// implements REQ-git-hook-manager-integration
|
|
417
|
+
export function hookManagerCoverage(manager, worktreeRoot) {
|
|
418
|
+
return ordered(MANAGED_HOOK_NAMES).map((hook) => {
|
|
419
|
+
const commands = hookManagerCommands(manager, worktreeRoot, hook);
|
|
420
|
+
return {
|
|
421
|
+
hook,
|
|
422
|
+
configured: commands !== null,
|
|
423
|
+
missing: missingKibiHookCommands(hook, commands ?? []),
|
|
424
|
+
};
|
|
425
|
+
});
|
|
426
|
+
}
|
package/dist/commands/init.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AA8GA,UAAU,WAAW;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAkFD,wBAAsB,WAAW,CAC/B,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CA0L/B"}
|
package/dist/commands/init.js
CHANGED
|
@@ -24,7 +24,8 @@ import { resolveBranchAttachment } from "../utils/branch-resolver.js";
|
|
|
24
24
|
import { readLegacyKbConfig } from "../utils/config.js";
|
|
25
25
|
import { resolveGitRepository, } from "../utils/git-repository-context.js";
|
|
26
26
|
import { scaffoldGitHubIntegration } from "./github-init.js";
|
|
27
|
-
import {
|
|
27
|
+
import { HOOK_SNIPPET_FORMATS, detectHookManager, hookManagerCoverage, hookManagerSnippet, } from "./hook-managers.js";
|
|
28
|
+
import { MANAGED_HOOK_NAMES, copySchemaFiles, createKbDirectoryStructure, createManifestFile, ensureSymbolsManifestFile, installGitHooks, isManagedHookName, updateGitIgnore, } from "./init-helpers.js";
|
|
28
29
|
const __filename = fileURLToPath(import.meta.url);
|
|
29
30
|
const __dirname = path.dirname(__filename);
|
|
30
31
|
/**
|
|
@@ -83,6 +84,24 @@ function isRepositoryManagedHooksDir(context) {
|
|
|
83
84
|
// directory, which can sit outside the current worktree root.
|
|
84
85
|
return isWithin(hooksDir, commonGitDir) || isWithin(hooksDir, worktreeRoot);
|
|
85
86
|
}
|
|
87
|
+
/**
|
|
88
|
+
* Hooks owned by a hook manager are left to it: Kibi installs nothing into
|
|
89
|
+
* the hooks directory and prints the manager configuration that runs Kibi's
|
|
90
|
+
* commands for every hook the manager does not visibly cover yet.
|
|
91
|
+
*/
|
|
92
|
+
// implements REQ-git-hook-manager-integration
|
|
93
|
+
function reportHookManager(manager, worktreeRoot) {
|
|
94
|
+
const gaps = hookManagerCoverage(manager.name, worktreeRoot).filter((entry) => entry.missing.length > 0);
|
|
95
|
+
const owner = `Git hooks are managed by ${manager.name} (${manager.configPath})`;
|
|
96
|
+
if (gaps.length === 0) {
|
|
97
|
+
console.log(`✓ ${owner}, which already runs Kibi's hook commands; Kibi installed no hooks of its own.`);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const hooks = gaps.map((entry) => entry.hook);
|
|
101
|
+
console.log(`! ${owner}; Kibi installed no hooks of its own. ${manager.configPath} does not visibly run Kibi's commands for: ${hooks.join(", ")}. Add this (running the same commands through a task runner or script works too), or Kibi enforcement stays OFF for those hooks:\n`);
|
|
102
|
+
console.log(hookManagerSnippet(manager.name, hooks));
|
|
103
|
+
console.log(` Print it again with: kibi init --print-hook ${hooks.length === 1 ? hooks[0] : "all"} --format ${manager.name}`);
|
|
104
|
+
}
|
|
86
105
|
async function initNextAction(projectRoot) {
|
|
87
106
|
const sourceFiles = await nodeFilesystem.glob([
|
|
88
107
|
".kb/requirements/**/*.md",
|
|
@@ -121,15 +140,25 @@ async function initNextAction(projectRoot) {
|
|
|
121
140
|
// implements REQ-cli-init
|
|
122
141
|
// implements REQ-kibi-github-report-integration
|
|
123
142
|
export async function initCommand(options) {
|
|
143
|
+
if (options.format !== undefined && options.printHook === undefined) {
|
|
144
|
+
console.error("Error: --format applies only to --print-hook.");
|
|
145
|
+
return { exitCode: 1 };
|
|
146
|
+
}
|
|
124
147
|
if (options.printHook !== undefined) {
|
|
125
148
|
// Print-only mode: emit a delegation snippet for a hook Kibi does not
|
|
126
149
|
// own and touch nothing, not even the repository context.
|
|
127
|
-
// implements REQ-git-hook-effective-install
|
|
128
|
-
|
|
129
|
-
|
|
150
|
+
// implements REQ-git-hook-effective-install, REQ-git-hook-manager-integration
|
|
151
|
+
const printHook = options.printHook;
|
|
152
|
+
if (printHook !== "all" && !isManagedHookName(printHook)) {
|
|
153
|
+
console.error(`Error: unknown hook '${printHook}' for --print-hook. Expected one of: ${MANAGED_HOOK_NAMES.join(", ")}, all.`);
|
|
154
|
+
return { exitCode: 1 };
|
|
155
|
+
}
|
|
156
|
+
const format = options.format ?? "shell";
|
|
157
|
+
if (!HOOK_SNIPPET_FORMATS.includes(format)) {
|
|
158
|
+
console.error(`Error: unknown --format '${format}' for --print-hook. Expected one of: ${HOOK_SNIPPET_FORMATS.join(", ")}.`);
|
|
130
159
|
return { exitCode: 1 };
|
|
131
160
|
}
|
|
132
|
-
process.stdout.write(
|
|
161
|
+
process.stdout.write(hookManagerSnippet(format, printHook === "all" ? MANAGED_HOOK_NAMES : [printHook]));
|
|
133
162
|
return { exitCode: 0 };
|
|
134
163
|
}
|
|
135
164
|
if (options.badgeOnly === true && options.github !== true) {
|
|
@@ -202,9 +231,15 @@ export async function initCommand(options) {
|
|
|
202
231
|
ensureSymbolsManifestFile(projectRoot);
|
|
203
232
|
}
|
|
204
233
|
if (options.hooks) {
|
|
234
|
+
const manager = repoContext
|
|
235
|
+
? detectHookManager(repoContext.worktreeRoot, repoContext.effectiveHooksDir, repoContext.hooksPathConfig)
|
|
236
|
+
: null;
|
|
205
237
|
if (!repoContext) {
|
|
206
238
|
console.error("Warning: No git repository found, skipping hooks");
|
|
207
239
|
}
|
|
240
|
+
else if (manager) {
|
|
241
|
+
reportHookManager(manager, repoContext.worktreeRoot);
|
|
242
|
+
}
|
|
208
243
|
else if (!isRepositoryManagedHooksDir(repoContext)) {
|
|
209
244
|
// core.hooksPath is only the culprit when it is configured; the
|
|
210
245
|
// default hooks directory can also escape the repository through a
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../../src/commands/migrate.ts"],"names":[],"mappings":"AAmEA,OAAO,KAAK,EACV,eAAe,EAGhB,MAAM,wCAAwC,CAAC;
|
|
1
|
+
{"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../../src/commands/migrate.ts"],"names":[],"mappings":"AAmEA,OAAO,KAAK,EACV,eAAe,EAGhB,MAAM,wCAAwC,CAAC;AAyBhD,UAAU,cAAc;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC1B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,uFAAuF;IACvF,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,6EAA6E;IAC7E,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,qFAAqF;IACrF,uBAAuB,CAAC,EAAE,OAAO,CAAC;CACnC;AAED,MAAM,WAAW,oBAAoB;IACnC,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,uBAAuB,EAAE,SAAS,GAAG,WAAW,GAAG,gBAAgB,GAAG,IAAI,CAAC;IAC3E,MAAM,EAAE,SAAS,CAAC;IAClB,4BAA4B,EAAE,MAAM,CAAC;IACrC,8EAA8E;IAC9E,oBAAoB,EAAE,MAAM,CAAC;IAC7B,8DAA8D;IAC9D,4BAA4B,EAAE,MAAM,CAAC;IACrC,sEAAsE;IACtE,oBAAoB,EAAE,MAAM,CAAC;IAC7B,4FAA4F;IAC5F,kBAAkB,EAAE,MAAM,CAAC;IAC3B,wHAAwH;IACxH,oBAAoB,EAAE,MAAM,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,oEAAoE;IACpE,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1B;AAED,iFAAiF;AACjF,MAAM,WAAW,mBAAmB;IAClC,kEAAkE;IAClE,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,oBAAoB,CAAC;IAC5B,0EAA0E;IAC1E,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAqLD,wBAAgB,mBAAmB,CACjC,gBAAgB,EAAE,OAAO,EACzB,UAAU,EAAE,MAAM,GAAG,IAAI,GACxB,MAAM,CAUR;AAwXD,wBAAgB,+BAA+B,IAAI;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAKtE;AAGD,wBAAsB,cAAc,CAClC,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,mBAAmB,CAAA;CAAE,CAAC,CAgkB9D;AAED;;;;GAIG;AAEH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,mBAAmB,GAAG,MAAM,CAGzE;AAoZD;;;;;GAKG;AAEH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,IAAI,CAAC,eAAe,EAAE,MAAM,CAAC,GACpC,OAAO,CAOT"}
|
package/dist/commands/migrate.js
CHANGED
|
@@ -27,6 +27,7 @@ import { applySourcePathRepairs, findSourceRepairs, } from "../operations/migrat
|
|
|
27
27
|
import { applySupersededClosures, planSupersededClosures, } from "../operations/migration/superseded-closure.js";
|
|
28
28
|
import { coordinateRefreshFailureMessage, readGeneratedManifestBytes, refreshCoordinatesAfterMigration, } from "../operations/migration/symbol-coordinates-refresh.js";
|
|
29
29
|
import { applySymbolLegacyLinks, planSymbolLegacyLinks, } from "../operations/migration/symbol-legacy-links.js";
|
|
30
|
+
import { noteCliErrorCategory } from "../usage-telemetry.js";
|
|
30
31
|
import { resolveBranchAttachment } from "../utils/branch-resolver.js";
|
|
31
32
|
import { defaultKbManifest, readKbManifest, readKbManifestStatus, writeKbManifest, } from "../utils/kb-manifest.js";
|
|
32
33
|
import { CANONICAL_ENTITY_PATHS, KB_PATHS } from "../utils/kb-paths.js";
|
|
@@ -1067,11 +1068,13 @@ async function migratePlanCommand(options) {
|
|
|
1067
1068
|
? plan.planHash
|
|
1068
1069
|
: options.approvedPlanHash;
|
|
1069
1070
|
if (!approvedPlanHash) {
|
|
1070
|
-
|
|
1071
|
+
noteCliErrorCategory("migrate:approved_plan_hash_missing");
|
|
1072
|
+
console.error(`--apply-safe requires --approved-plan-hash <sha256>. Review the plan with 'kibi migrate', then approve its current hash: kibi migrate --apply-safe --approved-plan-hash ${plan.planHash}`);
|
|
1071
1073
|
return { exitCode: 2 };
|
|
1072
1074
|
}
|
|
1073
1075
|
if (approvedPlanHash !== plan.planHash) {
|
|
1074
|
-
|
|
1076
|
+
noteCliErrorCategory("migrate:plan_hash_changed");
|
|
1077
|
+
console.error(`Migration plan changed; regenerate the plan and approve its current hash: kibi migrate --apply-safe --approved-plan-hash ${plan.planHash}`);
|
|
1075
1078
|
return { exitCode: 2 };
|
|
1076
1079
|
}
|
|
1077
1080
|
const explicitActionIds = approveWholePlan
|
|
@@ -1109,8 +1112,11 @@ async function migratePlanCommand(options) {
|
|
|
1109
1112
|
console.log(result.content[0]?.text ?? "Migration applied.");
|
|
1110
1113
|
printApplySummary(result.structuredContent);
|
|
1111
1114
|
}
|
|
1115
|
+
const outcome = result.structuredContent?.outcome;
|
|
1116
|
+
if (outcome !== "applied")
|
|
1117
|
+
noteCliErrorCategory(`migrate:${outcome}`);
|
|
1112
1118
|
return {
|
|
1113
|
-
exitCode:
|
|
1119
|
+
exitCode: outcome === "applied" ? 0 : 1,
|
|
1114
1120
|
};
|
|
1115
1121
|
}
|
|
1116
1122
|
if (options.format === "json") {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"persistence.d.ts","sourceRoot":"","sources":["../../../src/commands/sync/persistence.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAEV,qBAAqB,EACrB,gBAAgB,EACjB,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"persistence.d.ts","sourceRoot":"","sources":["../../../src/commands/sync/persistence.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAEV,qBAAqB,EACrB,gBAAgB,EACjB,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAgIrD,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,OAAO,CAAC;CACrB;AA0HD,iFAAiF;AACjF,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,aAAa,EACrB,WAAW,EAAE,SAAS,MAAM,EAAE,GAC7B,OAAO,CAAC,MAAM,CAAC,CA+BjB;AAED,0EAA0E;AAC1E,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,aAAa,EACrB,SAAS,EAAE,SAAS,MAAM,EAAE,GAC3B,OAAO,CAAC,MAAM,CAAC,CAmBjB;AAED,8EAA8E;AAC9E,wBAAsB,8BAA8B,CAClD,MAAM,EAAE,aAAa,EACrB,SAAS,EAAE,SAAS,MAAM,EAAE,GAC3B,OAAO,CAAC,IAAI,CAAC,CAoBf;AAED,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,aAAa,EACrB,aAAa,EAAE,SAAS,qBAAqB,EAAE,GAC9C,OAAO,CAAC,MAAM,CAAC,CAuBjB;AAmCD,6EAA6E;AAE7E,MAAM,MAAM,WAAW,GAAG,QAAQ,CAAC;IACjC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC,CAAC;AAEH;;;GAGG;AAEH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,IAAI,CAAC,aAAa,EAAE,OAAO,CAAC,GACnC,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC,CAmBlC;AAED,wBAAsB,eAAe,CAEnC,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,gBAAgB,EAAE,EAC3B,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,EACtB,OAAO,GAAE;IAAE,qBAAqB,CAAC,EAAE,OAAO,CAAA;CAAO,GAChD,OAAO,CAAC;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,CAAC,CA2RvD;AA4BD,wBAAgB,0BAA0B,CACxC,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,UAAU,EAAE,MAAM,GAAG,SAAS,GAC7B,MAAM,CAER;AAGD,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,gBAAgB,EAAE,EAC3B,kBAAkB,EAAE,qBAAqB,EAAE,EAC3C,OAAO,GAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAA;CAAO,GACvC,OAAO,CAAC;IAAE,iBAAiB,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,CAAC,CA4P7D"}
|