@kici-dev/compiler 0.0.0 → 0.1.1

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 (221) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +1 -6
  3. package/dist/assets/api-TJJVHrjC.json +118 -0
  4. package/dist/assets/descriptor-BTtjzN9L.json +1382 -0
  5. package/dist/assets/package-BpQF9kR8.json +74 -0
  6. package/dist/assets/package-Ceo2h27X.json +89 -0
  7. package/dist/assets/source_context-D0atuL28.json +20 -0
  8. package/dist/assets/type-BFqO8SCZ.json +202 -0
  9. package/dist/auth/headless-detect.d.ts +14 -0
  10. package/dist/auth/headless-detect.js +25 -0
  11. package/dist/chunk-gOLHoazu.js +4 -0
  12. package/dist/cli.d.ts +3 -0
  13. package/dist/cli.js +193 -0
  14. package/dist/commands/cancel.d.ts +22 -0
  15. package/dist/commands/cancel.js +124 -0
  16. package/dist/commands/compile.d.ts +17 -0
  17. package/dist/commands/compile.js +99 -0
  18. package/dist/commands/docs.d.ts +26 -0
  19. package/dist/commands/docs.js +60 -0
  20. package/dist/commands/drain-worker.d.ts +19 -0
  21. package/dist/commands/drain-worker.js +45 -0
  22. package/dist/commands/endpoints.d.ts +53 -0
  23. package/dist/commands/endpoints.js +185 -0
  24. package/dist/commands/fixture.d.ts +14 -0
  25. package/dist/commands/fixture.js +104 -0
  26. package/dist/commands/hook.d.ts +20 -0
  27. package/dist/commands/hook.js +97 -0
  28. package/dist/commands/index.d.ts +33 -0
  29. package/dist/commands/index.js +20 -0
  30. package/dist/commands/init.d.ts +35 -0
  31. package/dist/commands/init.js +393 -0
  32. package/dist/commands/login.d.ts +23 -0
  33. package/dist/commands/login.js +144 -0
  34. package/dist/commands/logout.d.ts +18 -0
  35. package/dist/commands/logout.js +55 -0
  36. package/dist/commands/org.d.ts +27 -0
  37. package/dist/commands/org.js +126 -0
  38. package/dist/commands/run.d.ts +21 -0
  39. package/dist/commands/run.js +562 -0
  40. package/dist/commands/secrets-list.d.ts +16 -0
  41. package/dist/commands/secrets-list.js +85 -0
  42. package/dist/commands/status.d.ts +30 -0
  43. package/dist/commands/status.js +210 -0
  44. package/dist/commands/test.d.ts +61 -0
  45. package/dist/commands/test.js +220 -0
  46. package/dist/commands/types.d.ts +18 -0
  47. package/dist/commands/types.js +74 -0
  48. package/dist/commands/watch.d.ts +14 -0
  49. package/dist/commands/watch.js +97 -0
  50. package/dist/commands/workflows.d.ts +28 -0
  51. package/dist/commands/workflows.js +154 -0
  52. package/dist/comment-created.json +30 -0
  53. package/dist/create-branch.json +17 -0
  54. package/dist/delete-branch.json +15 -0
  55. package/dist/dispatch.json +15 -0
  56. package/dist/errors/capability-gap.d.ts +50 -0
  57. package/dist/errors/capability-gap.js +54 -0
  58. package/dist/errors/codes.d.ts +25 -0
  59. package/dist/errors/formatter.d.ts +32 -0
  60. package/dist/errors/formatter.js +35 -0
  61. package/dist/errors/index.d.ts +5 -0
  62. package/dist/errors/index.js +4 -0
  63. package/dist/execution/executor.d.ts +61 -0
  64. package/dist/execution/executor.js +230 -0
  65. package/dist/execution/index.d.ts +4 -0
  66. package/dist/execution/index.js +3 -0
  67. package/dist/execution/sdk-alias.d.ts +33 -0
  68. package/dist/execution/sdk-alias.js +102 -0
  69. package/dist/fixtures/compiler.d.ts +47 -0
  70. package/dist/fixtures/compiler.js +177 -0
  71. package/dist/fixtures/defaults/comment-created.json +30 -0
  72. package/dist/fixtures/defaults/create-branch.json +17 -0
  73. package/dist/fixtures/defaults/delete-branch.json +15 -0
  74. package/dist/fixtures/defaults/dispatch.json +15 -0
  75. package/dist/fixtures/defaults/fork.json +19 -0
  76. package/dist/fixtures/defaults/index.d.ts +16 -0
  77. package/dist/fixtures/defaults/index.js +105 -0
  78. package/dist/fixtures/defaults/index.ts +145 -0
  79. package/dist/fixtures/defaults/pr-closed.json +28 -0
  80. package/dist/fixtures/defaults/pr-opened.json +27 -0
  81. package/dist/fixtures/defaults/pr-reopened.json +27 -0
  82. package/dist/fixtures/defaults/pr-synchronize.json +27 -0
  83. package/dist/fixtures/defaults/push.json +16 -0
  84. package/dist/fixtures/defaults/release-published.json +23 -0
  85. package/dist/fixtures/defaults/review-comment-created.json +36 -0
  86. package/dist/fixtures/defaults/review-submitted.json +35 -0
  87. package/dist/fixtures/defaults/star-created.json +15 -0
  88. package/dist/fixtures/defaults/status.json +26 -0
  89. package/dist/fixtures/defaults/tag-push.json +20 -0
  90. package/dist/fixtures/defaults/watch-started.json +15 -0
  91. package/dist/fixtures/defaults/workflow-run-completed.json +23 -0
  92. package/dist/fork.json +19 -0
  93. package/dist/format.d.ts +5 -0
  94. package/dist/format.js +20 -0
  95. package/dist/generators/secrets-dts.d.ts +29 -0
  96. package/dist/generators/secrets-dts.js +67 -0
  97. package/dist/hooks/detector.d.ts +39 -0
  98. package/dist/hooks/detector.js +133 -0
  99. package/dist/hooks/index.d.ts +6 -0
  100. package/dist/hooks/index.js +5 -0
  101. package/dist/hooks/installer.d.ts +24 -0
  102. package/dist/hooks/installer.js +328 -0
  103. package/dist/hooks/templates.d.ts +26 -0
  104. package/dist/hooks/templates.js +63 -0
  105. package/dist/index.d.ts +12 -0
  106. package/dist/index.js +12 -0
  107. package/dist/llm-context/llms-full.txt +9974 -0
  108. package/dist/llm-context/llms.txt +61 -0
  109. package/dist/local-executor/dag-scheduler.d.ts +44 -0
  110. package/dist/local-executor/dag-scheduler.js +183 -0
  111. package/dist/local-executor/index.d.ts +23 -0
  112. package/dist/local-executor/index.js +309 -0
  113. package/dist/local-executor/job-runner.d.ts +40 -0
  114. package/dist/local-executor/job-runner.js +307 -0
  115. package/dist/local-executor/output-streamer.d.ts +31 -0
  116. package/dist/local-executor/output-streamer.js +166 -0
  117. package/dist/local-executor/payload-generator.d.ts +16 -0
  118. package/dist/local-executor/payload-generator.js +138 -0
  119. package/dist/local-executor/picker.d.ts +33 -0
  120. package/dist/local-executor/picker.js +109 -0
  121. package/dist/local-executor/secret-loader.d.ts +18 -0
  122. package/dist/local-executor/secret-loader.js +105 -0
  123. package/dist/local-executor/types.d.ts +80 -0
  124. package/dist/local-executor/types.js +2 -0
  125. package/dist/local-executor/workflow-lock.d.ts +81 -0
  126. package/dist/local-executor/workflow-lock.js +0 -0
  127. package/dist/lockfile/generator.d.ts +39 -0
  128. package/dist/lockfile/generator.js +688 -0
  129. package/dist/lockfile/hash-files.d.ts +14 -0
  130. package/dist/lockfile/hash-files.js +50 -0
  131. package/dist/lockfile/hasher.d.ts +36 -0
  132. package/dist/lockfile/hasher.js +46 -0
  133. package/dist/lockfile/index.d.ts +3 -0
  134. package/dist/lockfile/index.js +4 -0
  135. package/dist/lockfile/purity-analyzer.d.ts +25 -0
  136. package/dist/lockfile/purity-analyzer.js +204 -0
  137. package/dist/package-F7UXSDHW.json +74 -0
  138. package/dist/postinstall.d.ts +9 -0
  139. package/dist/postinstall.js +60 -0
  140. package/dist/pr-closed.json +28 -0
  141. package/dist/pr-opened.json +27 -0
  142. package/dist/pr-reopened.json +27 -0
  143. package/dist/pr-synchronize.json +27 -0
  144. package/dist/push.json +16 -0
  145. package/dist/release-published.json +23 -0
  146. package/dist/remote/client.d.ts +204 -0
  147. package/dist/remote/client.js +203 -0
  148. package/dist/remote/config.d.ts +54 -0
  149. package/dist/remote/config.js +92 -0
  150. package/dist/remote/encryption.d.ts +35 -0
  151. package/dist/remote/encryption.js +87 -0
  152. package/dist/remote/history.d.ts +91 -0
  153. package/dist/remote/history.js +146 -0
  154. package/dist/remote/oauth.d.ts +65 -0
  155. package/dist/remote/oauth.js +302 -0
  156. package/dist/remote/observer.d.ts +81 -0
  157. package/dist/remote/observer.js +174 -0
  158. package/dist/remote/output/json.d.ts +13 -0
  159. package/dist/remote/output/json.js +36 -0
  160. package/dist/remote/output/junit.d.ts +18 -0
  161. package/dist/remote/output/junit.js +50 -0
  162. package/dist/remote/output/streaming.d.ts +57 -0
  163. package/dist/remote/output/streaming.js +124 -0
  164. package/dist/remote/output/summary.d.ts +39 -0
  165. package/dist/remote/output/summary.js +99 -0
  166. package/dist/remote/uploader.d.ts +87 -0
  167. package/dist/remote/uploader.js +197 -0
  168. package/dist/review-comment-created.json +36 -0
  169. package/dist/review-submitted.json +35 -0
  170. package/dist/star-created.json +15 -0
  171. package/dist/status.json +26 -0
  172. package/dist/tag-push.json +20 -0
  173. package/dist/templates/agents-md.d.ts +8 -0
  174. package/dist/templates/agents-md.js +130 -0
  175. package/dist/templates/index.d.ts +43 -0
  176. package/dist/templates/index.js +48 -0
  177. package/dist/templates/package-json.d.ts +18 -0
  178. package/dist/templates/package-json.js +34 -0
  179. package/dist/templates/tsconfig-json.d.ts +9 -0
  180. package/dist/templates/tsconfig-json.js +26 -0
  181. package/dist/templates/workflows/hello-world.d.ts +2 -0
  182. package/dist/templates/workflows/hello-world.js +16 -0
  183. package/dist/templates/workflows/hello-world.ts +21 -0
  184. package/dist/templates/workflows/pr-checks.d.ts +2 -0
  185. package/dist/templates/workflows/pr-checks.js +40 -0
  186. package/dist/templates/workflows/pr-checks.ts +57 -0
  187. package/dist/test-runner/dry-run.d.ts +12 -0
  188. package/dist/test-runner/dry-run.js +66 -0
  189. package/dist/test-runner/event-types.d.ts +86 -0
  190. package/dist/test-runner/event-types.js +330 -0
  191. package/dist/test-runner/git-detector.d.ts +15 -0
  192. package/dist/test-runner/git-detector.js +30 -0
  193. package/dist/test-runner/index.d.ts +13 -0
  194. package/dist/test-runner/index.js +11 -0
  195. package/dist/test-runner/job-executor.d.ts +48 -0
  196. package/dist/test-runner/job-executor.js +245 -0
  197. package/dist/test-runner/output-formatter.d.ts +47 -0
  198. package/dist/test-runner/output-formatter.js +92 -0
  199. package/dist/test-runner/payload-builder.d.ts +20 -0
  200. package/dist/test-runner/payload-builder.js +216 -0
  201. package/dist/test-runner/rule-evaluator.d.ts +14 -0
  202. package/dist/test-runner/rule-evaluator.js +31 -0
  203. package/dist/test-runner/secrets-file.d.ts +24 -0
  204. package/dist/test-runner/secrets-file.js +62 -0
  205. package/dist/test-runner/step-context.d.ts +15 -0
  206. package/dist/test-runner/step-context.js +140 -0
  207. package/dist/test-runner/summary.d.ts +7 -0
  208. package/dist/types.d.ts +525 -0
  209. package/dist/types.js +33 -0
  210. package/dist/validation/index.d.ts +3 -0
  211. package/dist/validation/index.js +3 -0
  212. package/dist/validation/validator.d.ts +26 -0
  213. package/dist/validation/validator.js +164 -0
  214. package/dist/watch-started.json +15 -0
  215. package/dist/workflow-run-completed.json +23 -0
  216. package/dist/workflows/hello-world.ts +21 -0
  217. package/dist/workflows/pr-checks.ts +57 -0
  218. package/hack/postinstall.mjs +105 -0
  219. package/package.json +61 -5
  220. package/sbom.spdx.json +10997 -0
  221. package/index.js +0 -3
@@ -0,0 +1,29 @@
1
+ /**
2
+ * .d.ts generator for environment secret type augmentation.
3
+ *
4
+ * Produces a TypeScript declaration file that augments @kici-dev/sdk's
5
+ * KnownSecretKeys and EnvironmentSecrets interfaces, enabling compile-time
6
+ * autocomplete and type checking for `ctx.secrets.get()` and `ctx.secrets.expose()`
7
+ * key names per environment.
8
+ */
9
+ export interface EnvironmentMetadata {
10
+ name: string;
11
+ keys: string[];
12
+ }
13
+ interface GenerateSecretsDtsOptions {
14
+ environments: EnvironmentMetadata[];
15
+ endpoint: string;
16
+ generatedAt: Date;
17
+ }
18
+ /**
19
+ * Generate a .d.ts string from environment metadata.
20
+ *
21
+ * The output augments @kici-dev/sdk's KnownSecretKeys and EnvironmentSecrets
22
+ * interfaces, enabling compile-time autocomplete for secret keys per environment.
23
+ *
24
+ * @param options - Environment metadata, endpoint URL, and generation timestamp
25
+ * @returns The .d.ts file content as a string
26
+ */
27
+ export declare function generateSecretsDts(options: GenerateSecretsDtsOptions): string;
28
+ export {};
29
+ //# sourceMappingURL=secrets-dts.d.ts.map
@@ -0,0 +1,67 @@
1
+ import "../chunk-gOLHoazu.js";
2
+ //#region src/generators/secrets-dts.ts
3
+ /**
4
+ * Check if a string is a valid TypeScript identifier (unquoted property name).
5
+ */
6
+ function isValidIdentifier(name) {
7
+ return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
8
+ }
9
+ function escapeQuotes(s) {
10
+ return s.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
11
+ }
12
+ function formatProperty(name) {
13
+ return isValidIdentifier(name) ? name : `'${escapeQuotes(name)}'`;
14
+ }
15
+ /**
16
+ * Build a map of key -> list of environment names that provide it.
17
+ */
18
+ function buildKeySourceMap(environments) {
19
+ const map = /* @__PURE__ */ new Map();
20
+ for (const env of environments) for (const key of env.keys) {
21
+ const sources = map.get(key);
22
+ if (sources) sources.push(env.name);
23
+ else map.set(key, [env.name]);
24
+ }
25
+ return map;
26
+ }
27
+ /**
28
+ * Generate a .d.ts string from environment metadata.
29
+ *
30
+ * The output augments @kici-dev/sdk's KnownSecretKeys and EnvironmentSecrets
31
+ * interfaces, enabling compile-time autocomplete for secret keys per environment.
32
+ *
33
+ * @param options - Environment metadata, endpoint URL, and generation timestamp
34
+ * @returns The .d.ts file content as a string
35
+ */
36
+ function generateSecretsDts(options) {
37
+ const { environments, endpoint, generatedAt } = options;
38
+ const lines = [];
39
+ lines.push("// @generated by kici types -- DO NOT EDIT");
40
+ lines.push(`// Orchestrator: ${endpoint}`);
41
+ lines.push(`// Generated: ${generatedAt.toISOString()}`);
42
+ lines.push("// Run `kici types` to refresh");
43
+ lines.push("");
44
+ lines.push("declare module '@kici-dev/sdk' {");
45
+ const keySourceMap = buildKeySourceMap(environments);
46
+ lines.push(" interface KnownSecretKeys {");
47
+ for (const [key, sources] of keySourceMap) {
48
+ lines.push(` /** From environment: ${sources.join(", ")} */`);
49
+ lines.push(` ${formatProperty(key)}: string;`);
50
+ }
51
+ lines.push(" }");
52
+ lines.push("");
53
+ lines.push(" interface EnvironmentSecrets {");
54
+ for (const env of environments) if (env.keys.length === 0) lines.push(` ${formatProperty(env.name)}: never;`);
55
+ else {
56
+ const keyUnion = env.keys.map((k) => `'${escapeQuotes(k)}'`).join(" | ");
57
+ lines.push(` ${formatProperty(env.name)}: ${keyUnion};`);
58
+ }
59
+ lines.push(" }");
60
+ lines.push("}");
61
+ lines.push("");
62
+ return lines.join("\n");
63
+ }
64
+ //#endregion
65
+ export { generateSecretsDts };
66
+
67
+ //# sourceMappingURL=secrets-dts.js.map
@@ -0,0 +1,39 @@
1
+ /** Supported pre-commit hook tools */
2
+ export type HookToolName = 'husky' | 'lefthook' | 'pre-commit' | 'prek' | 'git';
3
+ /** Detected hook tool with metadata */
4
+ export interface HookTool {
5
+ readonly name: HookToolName;
6
+ readonly configPath: string;
7
+ readonly priority: number;
8
+ }
9
+ /**
10
+ * Detect which pre-commit tools are configured in the project.
11
+ *
12
+ * @param cwd - Directory to check (defaults to process.cwd())
13
+ * @returns Array of detected tools, sorted by priority (highest first)
14
+ */
15
+ export declare function detectHookTools(cwd?: string): Promise<HookTool[]>;
16
+ /**
17
+ * Check if running in a git repository.
18
+ *
19
+ * Handles both normal .git directories and .git files used by worktrees
20
+ * and submodules. For .git files, resolves the "gitdir:" pointer to the
21
+ * actual git directory.
22
+ *
23
+ * @param cwd - Directory to check (defaults to process.cwd())
24
+ * @returns Path to git directory if found, null otherwise
25
+ */
26
+ export declare function findGitDir(cwd?: string): Promise<string | null>;
27
+ /**
28
+ * Get git root directory (the directory containing .git/ or .git file).
29
+ *
30
+ * Unlike findGitDir which returns the resolved git directory path,
31
+ * this returns the working tree root — the directory where .git lives.
32
+ * For worktrees and submodules, this is the directory containing the
33
+ * .git file, not the parent of the resolved gitdir path.
34
+ *
35
+ * @param cwd - Directory to start from (defaults to process.cwd())
36
+ * @returns Path to git root, or cwd if not in a git repo
37
+ */
38
+ export declare function findGitRoot(cwd?: string): Promise<string>;
39
+ //# sourceMappingURL=detector.d.ts.map
@@ -0,0 +1,133 @@
1
+ import "../chunk-gOLHoazu.js";
2
+ import { readFile, stat } from "node:fs/promises";
3
+ import path from "node:path";
4
+ //#region src/hooks/detector.ts
5
+ const TOOL_CONFIGS = [
6
+ {
7
+ name: "husky",
8
+ configFiles: [".husky/"],
9
+ priority: 1
10
+ },
11
+ {
12
+ name: "lefthook",
13
+ configFiles: [
14
+ "lefthook.yml",
15
+ ".lefthook.yml",
16
+ ".config/lefthook.yml"
17
+ ],
18
+ priority: 2
19
+ },
20
+ {
21
+ name: "pre-commit",
22
+ configFiles: [".pre-commit-config.yaml"],
23
+ priority: 3
24
+ },
25
+ {
26
+ name: "prek",
27
+ configFiles: ["prek.toml", ".prek.toml"],
28
+ priority: 4
29
+ }
30
+ ];
31
+ /**
32
+ * Detect which pre-commit tools are configured in the project.
33
+ *
34
+ * @param cwd - Directory to check (defaults to process.cwd())
35
+ * @returns Array of detected tools, sorted by priority (highest first)
36
+ */
37
+ async function detectHookTools(cwd) {
38
+ const baseDir = cwd ?? process.cwd();
39
+ const detected = [];
40
+ for (const tool of TOOL_CONFIGS) for (const configFile of tool.configFiles) {
41
+ const configPath = path.join(baseDir, configFile);
42
+ try {
43
+ const stats = await stat(configPath);
44
+ if (stats.isDirectory() || stats.isFile()) {
45
+ detected.push({
46
+ name: tool.name,
47
+ configPath,
48
+ priority: tool.priority
49
+ });
50
+ break;
51
+ }
52
+ } catch {}
53
+ }
54
+ return detected.sort((a, b) => a.priority - b.priority);
55
+ }
56
+ /**
57
+ * Resolve a .git file (used by worktrees and submodules) to the actual git directory.
58
+ *
59
+ * Git worktrees and submodules use a .git file containing "gitdir: <path>"
60
+ * instead of a .git directory. The path may be absolute or relative to the
61
+ * directory containing the .git file.
62
+ *
63
+ * @param gitFilePath - Path to the .git file
64
+ * @returns Resolved absolute path to the git directory, or null if invalid
65
+ */
66
+ async function resolveGitFile(gitFilePath) {
67
+ try {
68
+ const content = (await readFile(gitFilePath, "utf-8")).trim();
69
+ if (!content.startsWith("gitdir:")) return null;
70
+ const gitdir = content.slice(7).trim();
71
+ if (!gitdir) return null;
72
+ const resolved = path.resolve(path.dirname(gitFilePath), gitdir);
73
+ if ((await stat(resolved)).isDirectory()) return resolved;
74
+ return null;
75
+ } catch {
76
+ return null;
77
+ }
78
+ }
79
+ /**
80
+ * Check if running in a git repository.
81
+ *
82
+ * Handles both normal .git directories and .git files used by worktrees
83
+ * and submodules. For .git files, resolves the "gitdir:" pointer to the
84
+ * actual git directory.
85
+ *
86
+ * @param cwd - Directory to check (defaults to process.cwd())
87
+ * @returns Path to git directory if found, null otherwise
88
+ */
89
+ async function findGitDir(cwd) {
90
+ let currentPath = path.resolve(cwd ?? process.cwd());
91
+ while (true) {
92
+ const gitPath = path.join(currentPath, ".git");
93
+ try {
94
+ const stats = await stat(gitPath);
95
+ if (stats.isDirectory()) return gitPath;
96
+ if (stats.isFile()) {
97
+ const resolved = await resolveGitFile(gitPath);
98
+ if (resolved) return resolved;
99
+ }
100
+ } catch {}
101
+ const parentPath = path.dirname(currentPath);
102
+ if (parentPath === currentPath) return null;
103
+ currentPath = parentPath;
104
+ }
105
+ }
106
+ /**
107
+ * Get git root directory (the directory containing .git/ or .git file).
108
+ *
109
+ * Unlike findGitDir which returns the resolved git directory path,
110
+ * this returns the working tree root — the directory where .git lives.
111
+ * For worktrees and submodules, this is the directory containing the
112
+ * .git file, not the parent of the resolved gitdir path.
113
+ *
114
+ * @param cwd - Directory to start from (defaults to process.cwd())
115
+ * @returns Path to git root, or cwd if not in a git repo
116
+ */
117
+ async function findGitRoot(cwd) {
118
+ let currentPath = path.resolve(cwd ?? process.cwd());
119
+ while (true) {
120
+ const gitPath = path.join(currentPath, ".git");
121
+ try {
122
+ const stats = await stat(gitPath);
123
+ if (stats.isDirectory() || stats.isFile()) return currentPath;
124
+ } catch {}
125
+ const parentPath = path.dirname(currentPath);
126
+ if (parentPath === currentPath) return cwd ?? process.cwd();
127
+ currentPath = parentPath;
128
+ }
129
+ }
130
+ //#endregion
131
+ export { detectHookTools, findGitDir, findGitRoot };
132
+
133
+ //# sourceMappingURL=detector.js.map
@@ -0,0 +1,6 @@
1
+ export { detectHookTools, findGitDir, findGitRoot } from './detector.js';
2
+ export type { HookTool, HookToolName } from './detector.js';
3
+ export { getHookTemplate, hasKiciHook, KICI_HOOK_MARKER } from './templates.js';
4
+ export { installHook } from './installer.js';
5
+ export type { InstallResult, InstallOptions } from './installer.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,5 @@
1
+ import "../chunk-gOLHoazu.js";
2
+ import { detectHookTools, findGitDir, findGitRoot } from "./detector.js";
3
+ import { KICI_HOOK_MARKER, getHookTemplate, hasKiciHook } from "./templates.js";
4
+ import { installHook } from "./installer.js";
5
+ export { KICI_HOOK_MARKER, detectHookTools, findGitDir, findGitRoot, getHookTemplate, hasKiciHook, installHook };
@@ -0,0 +1,24 @@
1
+ import type { HookToolName } from './detector.js';
2
+ /** Result of hook installation */
3
+ export interface InstallResult {
4
+ readonly success: boolean;
5
+ readonly tool: HookToolName;
6
+ readonly path: string;
7
+ readonly action: 'created' | 'updated' | 'skipped';
8
+ readonly message: string;
9
+ }
10
+ /** Options for hook installation */
11
+ export interface InstallOptions {
12
+ /** Working directory (defaults to process.cwd()) */
13
+ cwd?: string;
14
+ /** Use @kici-dev/compiler from local Verdaccio instead of the public kici package */
15
+ useVerdaccio?: boolean;
16
+ }
17
+ /**
18
+ * Install kici compile hook using the specified tool.
19
+ *
20
+ * Uses each tool's native CLI for initialization and git-hook wiring,
21
+ * falling back to manual file creation only when the CLI is unavailable.
22
+ */
23
+ export declare function installHook(tool: HookToolName, options?: InstallOptions): Promise<InstallResult>;
24
+ //# sourceMappingURL=installer.d.ts.map
@@ -0,0 +1,328 @@
1
+ import "../chunk-gOLHoazu.js";
2
+ import { findGitDir } from "./detector.js";
3
+ import { getHookTemplate, hasKiciHook } from "./templates.js";
4
+ import { chmod, mkdir, readFile, stat, writeFile } from "node:fs/promises";
5
+ import path from "node:path";
6
+ import { exec } from "node:child_process";
7
+ import { promisify } from "node:util";
8
+ //#region src/hooks/installer.ts
9
+ const execAsync = promisify(exec);
10
+ /** Run a shell command in a directory. Returns stdout on success. */
11
+ async function runCommand(cmd, cwd) {
12
+ const { stdout } = await execAsync(cmd, {
13
+ cwd,
14
+ timeout: 3e4
15
+ });
16
+ return stdout.trim();
17
+ }
18
+ /** Check if a directory exists */
19
+ async function dirExists(dirPath) {
20
+ try {
21
+ return (await stat(dirPath)).isDirectory();
22
+ } catch {
23
+ return false;
24
+ }
25
+ }
26
+ /**
27
+ * Install kici compile hook using the specified tool.
28
+ *
29
+ * Uses each tool's native CLI for initialization and git-hook wiring,
30
+ * falling back to manual file creation only when the CLI is unavailable.
31
+ */
32
+ async function installHook(tool, options = {}) {
33
+ const cwd = options.cwd ?? process.cwd();
34
+ const command = `${options.useVerdaccio ? "npx -y @kici-dev/compiler@latest" : "npx -y kici@latest"} compile && git add .kici/kici.lock.json`;
35
+ switch (tool) {
36
+ case "husky": return installHuskyHook(cwd, command);
37
+ case "lefthook": return installLefthookHook(cwd, command);
38
+ case "pre-commit":
39
+ case "prek": return installPreCommitHook(cwd, command, tool);
40
+ case "git": return installGitHook(cwd, command);
41
+ default: return {
42
+ success: false,
43
+ tool,
44
+ path: "",
45
+ action: "skipped",
46
+ message: `Unknown hook tool: ${tool}`
47
+ };
48
+ }
49
+ }
50
+ /**
51
+ * Install hook for Husky.
52
+ *
53
+ * When .husky/ doesn't exist, runs `npx husky init` to properly initialize
54
+ * (sets core.hooksPath, creates directory structure). Falls back to manual
55
+ * setup if the CLI is unavailable.
56
+ *
57
+ * Then creates or appends our command to .husky/pre-commit.
58
+ */
59
+ async function installHuskyHook(cwd, command) {
60
+ const hookDir = path.join(cwd, ".husky");
61
+ const hookPath = path.join(hookDir, "pre-commit");
62
+ const template = getHookTemplate("husky");
63
+ try {
64
+ const huskyReady = await dirExists(hookDir);
65
+ let freshInit = false;
66
+ if (!huskyReady) freshInit = await initHusky(cwd, hookDir);
67
+ let content = "";
68
+ let action = "created";
69
+ try {
70
+ content = await readFile(hookPath, "utf-8");
71
+ if (hasKiciHook(content)) return {
72
+ success: true,
73
+ tool: "husky",
74
+ path: hookPath,
75
+ action: "skipped",
76
+ message: "kici hook already installed"
77
+ };
78
+ if (freshInit) {
79
+ content = template.getFullScript(command);
80
+ action = "created";
81
+ } else {
82
+ content += template.getCommand(command);
83
+ action = "updated";
84
+ }
85
+ } catch {
86
+ content = template.getFullScript(command);
87
+ }
88
+ await writeFile(hookPath, content, "utf-8");
89
+ try {
90
+ await chmod(hookPath, 493);
91
+ } catch {}
92
+ return {
93
+ success: true,
94
+ tool: "husky",
95
+ path: hookPath,
96
+ action,
97
+ message: action === "created" ? "Created .husky/pre-commit with kici compile" : "Added kici compile to .husky/pre-commit"
98
+ };
99
+ } catch (err) {
100
+ return {
101
+ success: false,
102
+ tool: "husky",
103
+ path: hookPath,
104
+ action: "skipped",
105
+ message: `Failed to install husky hook: ${err.message}`
106
+ };
107
+ }
108
+ }
109
+ /**
110
+ * Initialize husky using its CLI, with manual fallback.
111
+ * Returns true if this was a fresh initialization.
112
+ */
113
+ async function initHusky(cwd, hookDir) {
114
+ try {
115
+ await runCommand("npx --yes husky init", cwd);
116
+ return true;
117
+ } catch {
118
+ await mkdir(hookDir, { recursive: true });
119
+ try {
120
+ await runCommand("git config core.hooksPath .husky", cwd);
121
+ } catch {}
122
+ return true;
123
+ }
124
+ }
125
+ /**
126
+ * Install hook for Lefthook.
127
+ *
128
+ * Edits lefthook.yml to add the kici-compile command, then runs
129
+ * `npx lefthook install` to wire up git hooks.
130
+ */
131
+ async function installLefthookHook(cwd, command) {
132
+ const configFiles = [
133
+ "lefthook.yml",
134
+ ".lefthook.yml",
135
+ ".config/lefthook.yml"
136
+ ];
137
+ let configPath = "";
138
+ let content = "";
139
+ for (const file of configFiles) {
140
+ const filePath = path.join(cwd, file);
141
+ try {
142
+ content = await readFile(filePath, "utf-8");
143
+ configPath = filePath;
144
+ break;
145
+ } catch {}
146
+ }
147
+ if (!configPath) {
148
+ configPath = path.join(cwd, "lefthook.yml");
149
+ content = `# Lefthook configuration
150
+ # https://lefthook.dev/configuration/
151
+
152
+ pre-commit:
153
+ parallel: true
154
+ commands:
155
+ `;
156
+ }
157
+ if (hasKiciHook(content)) return {
158
+ success: true,
159
+ tool: "lefthook",
160
+ path: configPath,
161
+ action: "skipped",
162
+ message: "kici hook already installed"
163
+ };
164
+ const hookConfig = getHookTemplate("lefthook").getCommand(command);
165
+ if (content.includes("pre-commit:")) {
166
+ const preCommitIdx = content.indexOf("pre-commit:");
167
+ const restAfterKey = content.slice(preCommitIdx + 11);
168
+ const sectionEnd = restAfterKey.match(/\n[a-zA-Z]/)?.index ?? restAfterKey.length;
169
+ if (restAfterKey.slice(0, sectionEnd).includes("commands:")) content = content.replace(/(pre-commit:[\s\S]*?commands:)/, `$1\n${hookConfig}`);
170
+ else content = content.replace(/(pre-commit:.*)/, `$1\n commands:\n${hookConfig}`);
171
+ } else content += `\npre-commit:\n parallel: true\n commands:\n${hookConfig}\n`;
172
+ try {
173
+ await writeFile(configPath, content, "utf-8");
174
+ try {
175
+ await runCommand("npx lefthook install", cwd);
176
+ } catch {}
177
+ return {
178
+ success: true,
179
+ tool: "lefthook",
180
+ path: configPath,
181
+ action: "updated",
182
+ message: "Added kici-compile command to lefthook.yml"
183
+ };
184
+ } catch (err) {
185
+ return {
186
+ success: false,
187
+ tool: "lefthook",
188
+ path: configPath,
189
+ action: "skipped",
190
+ message: `Failed to update lefthook config: ${err.message}`
191
+ };
192
+ }
193
+ }
194
+ /**
195
+ * Install hook for pre-commit or prek.
196
+ *
197
+ * Both use .pre-commit-config.yaml format.
198
+ * After editing the config, runs `pre-commit install` to wire up git hooks.
199
+ */
200
+ async function installPreCommitHook(cwd, command, tool) {
201
+ const configPath = path.join(cwd, ".pre-commit-config.yaml");
202
+ let content = "";
203
+ try {
204
+ content = await readFile(configPath, "utf-8");
205
+ } catch {
206
+ content = `# pre-commit configuration
207
+ # https://pre-commit.com/
208
+
209
+ repos:
210
+ `;
211
+ }
212
+ if (hasKiciHook(content)) return {
213
+ success: true,
214
+ tool,
215
+ path: configPath,
216
+ action: "skipped",
217
+ message: "kici hook already installed"
218
+ };
219
+ const hookConfig = getHookTemplate(tool).getCommand(command);
220
+ if (content.includes("repos:")) content = content.replace(/(repos:)/, `$1\n${hookConfig}`);
221
+ else content += `repos:\n${hookConfig}\n`;
222
+ try {
223
+ await writeFile(configPath, content, "utf-8");
224
+ const installCmd = tool === "prek" ? "prek install" : "pre-commit install";
225
+ try {
226
+ await runCommand(installCmd, cwd);
227
+ } catch {}
228
+ return {
229
+ success: true,
230
+ tool,
231
+ path: configPath,
232
+ action: "updated",
233
+ message: `Added kici hook to .pre-commit-config.yaml`
234
+ };
235
+ } catch (err) {
236
+ return {
237
+ success: false,
238
+ tool,
239
+ path: configPath,
240
+ action: "skipped",
241
+ message: `Failed to update pre-commit config: ${err.message}`
242
+ };
243
+ }
244
+ }
245
+ /**
246
+ * Resolve the common git directory for hook installation.
247
+ *
248
+ * Git worktrees have a `commondir` file pointing to the shared git directory.
249
+ * Hooks must be installed in the common directory (e.g., `.git/hooks/`) rather
250
+ * than the worktree-specific directory (e.g., `.git/worktrees/<name>/hooks/`),
251
+ * because git only looks for hooks in the common hooks directory.
252
+ */
253
+ async function resolveCommonGitDir(gitDir) {
254
+ try {
255
+ const commondir = (await readFile(path.join(gitDir, "commondir"), "utf-8")).trim();
256
+ return path.resolve(gitDir, commondir);
257
+ } catch {
258
+ return gitDir;
259
+ }
260
+ }
261
+ /**
262
+ * Install raw git hook.
263
+ * Creates or appends to .git/hooks/pre-commit.
264
+ * Handles worktrees by resolving the common git directory for hooks.
265
+ */
266
+ async function installGitHook(cwd, command) {
267
+ const gitDir = await findGitDir(cwd);
268
+ if (!gitDir) return {
269
+ success: false,
270
+ tool: "git",
271
+ path: "",
272
+ action: "skipped",
273
+ message: "Not in a git repository"
274
+ };
275
+ const commonGitDir = await resolveCommonGitDir(gitDir);
276
+ const hookDir = path.join(commonGitDir, "hooks");
277
+ const hookPath = path.join(hookDir, "pre-commit");
278
+ const template = getHookTemplate("git");
279
+ try {
280
+ await mkdir(hookDir, { recursive: true });
281
+ let content = "";
282
+ let action = "created";
283
+ try {
284
+ content = await readFile(hookPath, "utf-8");
285
+ action = "updated";
286
+ if (hasKiciHook(content)) return {
287
+ success: true,
288
+ tool: "git",
289
+ path: hookPath,
290
+ action: "skipped",
291
+ message: "kici hook already installed"
292
+ };
293
+ } catch {
294
+ content = template.getFullScript(command);
295
+ await writeFile(hookPath, content, "utf-8");
296
+ await chmod(hookPath, 493);
297
+ return {
298
+ success: true,
299
+ tool: "git",
300
+ path: hookPath,
301
+ action: "created",
302
+ message: "Created .git/hooks/pre-commit with kici compile"
303
+ };
304
+ }
305
+ content += template.getCommand(command);
306
+ await writeFile(hookPath, content, "utf-8");
307
+ await chmod(hookPath, 493);
308
+ return {
309
+ success: true,
310
+ tool: "git",
311
+ path: hookPath,
312
+ action,
313
+ message: "Added kici compile to .git/hooks/pre-commit"
314
+ };
315
+ } catch (err) {
316
+ return {
317
+ success: false,
318
+ tool: "git",
319
+ path: hookPath,
320
+ action: "skipped",
321
+ message: `Failed to install git hook: ${err.message}`
322
+ };
323
+ }
324
+ }
325
+ //#endregion
326
+ export { installHook };
327
+
328
+ //# sourceMappingURL=installer.js.map
@@ -0,0 +1,26 @@
1
+ import type { HookToolName } from './detector.js';
2
+ /** Marker comment to identify kici-added hooks */
3
+ export declare const KICI_HOOK_MARKER = "# KiCI: compile workflows on commit";
4
+ /** Template configuration for each hook tool */
5
+ interface HookTemplate {
6
+ /** Get shell command/config to add */
7
+ getCommand: (command: string) => string;
8
+ /** Full hook script template (for new hooks) */
9
+ getFullScript?: (command: string) => string;
10
+ }
11
+ /**
12
+ * Get the hook template for a specific tool.
13
+ *
14
+ * @param tool - Hook tool name
15
+ * @returns Template configuration for the tool
16
+ */
17
+ export declare function getHookTemplate(tool: HookToolName): HookTemplate;
18
+ /**
19
+ * Check if a file already contains the kici hook.
20
+ *
21
+ * @param content - File content to check
22
+ * @returns true if kici hook marker is present
23
+ */
24
+ export declare function hasKiciHook(content: string): boolean;
25
+ export {};
26
+ //# sourceMappingURL=templates.d.ts.map