@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.
- package/LICENSE +202 -0
- package/README.md +1 -6
- package/dist/assets/api-TJJVHrjC.json +118 -0
- package/dist/assets/descriptor-BTtjzN9L.json +1382 -0
- package/dist/assets/package-BpQF9kR8.json +74 -0
- package/dist/assets/package-Ceo2h27X.json +89 -0
- package/dist/assets/source_context-D0atuL28.json +20 -0
- package/dist/assets/type-BFqO8SCZ.json +202 -0
- package/dist/auth/headless-detect.d.ts +14 -0
- package/dist/auth/headless-detect.js +25 -0
- package/dist/chunk-gOLHoazu.js +4 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +193 -0
- package/dist/commands/cancel.d.ts +22 -0
- package/dist/commands/cancel.js +124 -0
- package/dist/commands/compile.d.ts +17 -0
- package/dist/commands/compile.js +99 -0
- package/dist/commands/docs.d.ts +26 -0
- package/dist/commands/docs.js +60 -0
- package/dist/commands/drain-worker.d.ts +19 -0
- package/dist/commands/drain-worker.js +45 -0
- package/dist/commands/endpoints.d.ts +53 -0
- package/dist/commands/endpoints.js +185 -0
- package/dist/commands/fixture.d.ts +14 -0
- package/dist/commands/fixture.js +104 -0
- package/dist/commands/hook.d.ts +20 -0
- package/dist/commands/hook.js +97 -0
- package/dist/commands/index.d.ts +33 -0
- package/dist/commands/index.js +20 -0
- package/dist/commands/init.d.ts +35 -0
- package/dist/commands/init.js +393 -0
- package/dist/commands/login.d.ts +23 -0
- package/dist/commands/login.js +144 -0
- package/dist/commands/logout.d.ts +18 -0
- package/dist/commands/logout.js +55 -0
- package/dist/commands/org.d.ts +27 -0
- package/dist/commands/org.js +126 -0
- package/dist/commands/run.d.ts +21 -0
- package/dist/commands/run.js +562 -0
- package/dist/commands/secrets-list.d.ts +16 -0
- package/dist/commands/secrets-list.js +85 -0
- package/dist/commands/status.d.ts +30 -0
- package/dist/commands/status.js +210 -0
- package/dist/commands/test.d.ts +61 -0
- package/dist/commands/test.js +220 -0
- package/dist/commands/types.d.ts +18 -0
- package/dist/commands/types.js +74 -0
- package/dist/commands/watch.d.ts +14 -0
- package/dist/commands/watch.js +97 -0
- package/dist/commands/workflows.d.ts +28 -0
- package/dist/commands/workflows.js +154 -0
- package/dist/comment-created.json +30 -0
- package/dist/create-branch.json +17 -0
- package/dist/delete-branch.json +15 -0
- package/dist/dispatch.json +15 -0
- package/dist/errors/capability-gap.d.ts +50 -0
- package/dist/errors/capability-gap.js +54 -0
- package/dist/errors/codes.d.ts +25 -0
- package/dist/errors/formatter.d.ts +32 -0
- package/dist/errors/formatter.js +35 -0
- package/dist/errors/index.d.ts +5 -0
- package/dist/errors/index.js +4 -0
- package/dist/execution/executor.d.ts +61 -0
- package/dist/execution/executor.js +230 -0
- package/dist/execution/index.d.ts +4 -0
- package/dist/execution/index.js +3 -0
- package/dist/execution/sdk-alias.d.ts +33 -0
- package/dist/execution/sdk-alias.js +102 -0
- package/dist/fixtures/compiler.d.ts +47 -0
- package/dist/fixtures/compiler.js +177 -0
- package/dist/fixtures/defaults/comment-created.json +30 -0
- package/dist/fixtures/defaults/create-branch.json +17 -0
- package/dist/fixtures/defaults/delete-branch.json +15 -0
- package/dist/fixtures/defaults/dispatch.json +15 -0
- package/dist/fixtures/defaults/fork.json +19 -0
- package/dist/fixtures/defaults/index.d.ts +16 -0
- package/dist/fixtures/defaults/index.js +105 -0
- package/dist/fixtures/defaults/index.ts +145 -0
- package/dist/fixtures/defaults/pr-closed.json +28 -0
- package/dist/fixtures/defaults/pr-opened.json +27 -0
- package/dist/fixtures/defaults/pr-reopened.json +27 -0
- package/dist/fixtures/defaults/pr-synchronize.json +27 -0
- package/dist/fixtures/defaults/push.json +16 -0
- package/dist/fixtures/defaults/release-published.json +23 -0
- package/dist/fixtures/defaults/review-comment-created.json +36 -0
- package/dist/fixtures/defaults/review-submitted.json +35 -0
- package/dist/fixtures/defaults/star-created.json +15 -0
- package/dist/fixtures/defaults/status.json +26 -0
- package/dist/fixtures/defaults/tag-push.json +20 -0
- package/dist/fixtures/defaults/watch-started.json +15 -0
- package/dist/fixtures/defaults/workflow-run-completed.json +23 -0
- package/dist/fork.json +19 -0
- package/dist/format.d.ts +5 -0
- package/dist/format.js +20 -0
- package/dist/generators/secrets-dts.d.ts +29 -0
- package/dist/generators/secrets-dts.js +67 -0
- package/dist/hooks/detector.d.ts +39 -0
- package/dist/hooks/detector.js +133 -0
- package/dist/hooks/index.d.ts +6 -0
- package/dist/hooks/index.js +5 -0
- package/dist/hooks/installer.d.ts +24 -0
- package/dist/hooks/installer.js +328 -0
- package/dist/hooks/templates.d.ts +26 -0
- package/dist/hooks/templates.js +63 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +12 -0
- package/dist/llm-context/llms-full.txt +9974 -0
- package/dist/llm-context/llms.txt +61 -0
- package/dist/local-executor/dag-scheduler.d.ts +44 -0
- package/dist/local-executor/dag-scheduler.js +183 -0
- package/dist/local-executor/index.d.ts +23 -0
- package/dist/local-executor/index.js +309 -0
- package/dist/local-executor/job-runner.d.ts +40 -0
- package/dist/local-executor/job-runner.js +307 -0
- package/dist/local-executor/output-streamer.d.ts +31 -0
- package/dist/local-executor/output-streamer.js +166 -0
- package/dist/local-executor/payload-generator.d.ts +16 -0
- package/dist/local-executor/payload-generator.js +138 -0
- package/dist/local-executor/picker.d.ts +33 -0
- package/dist/local-executor/picker.js +109 -0
- package/dist/local-executor/secret-loader.d.ts +18 -0
- package/dist/local-executor/secret-loader.js +105 -0
- package/dist/local-executor/types.d.ts +80 -0
- package/dist/local-executor/types.js +2 -0
- package/dist/local-executor/workflow-lock.d.ts +81 -0
- package/dist/local-executor/workflow-lock.js +0 -0
- package/dist/lockfile/generator.d.ts +39 -0
- package/dist/lockfile/generator.js +688 -0
- package/dist/lockfile/hash-files.d.ts +14 -0
- package/dist/lockfile/hash-files.js +50 -0
- package/dist/lockfile/hasher.d.ts +36 -0
- package/dist/lockfile/hasher.js +46 -0
- package/dist/lockfile/index.d.ts +3 -0
- package/dist/lockfile/index.js +4 -0
- package/dist/lockfile/purity-analyzer.d.ts +25 -0
- package/dist/lockfile/purity-analyzer.js +204 -0
- package/dist/package-F7UXSDHW.json +74 -0
- package/dist/postinstall.d.ts +9 -0
- package/dist/postinstall.js +60 -0
- package/dist/pr-closed.json +28 -0
- package/dist/pr-opened.json +27 -0
- package/dist/pr-reopened.json +27 -0
- package/dist/pr-synchronize.json +27 -0
- package/dist/push.json +16 -0
- package/dist/release-published.json +23 -0
- package/dist/remote/client.d.ts +204 -0
- package/dist/remote/client.js +203 -0
- package/dist/remote/config.d.ts +54 -0
- package/dist/remote/config.js +92 -0
- package/dist/remote/encryption.d.ts +35 -0
- package/dist/remote/encryption.js +87 -0
- package/dist/remote/history.d.ts +91 -0
- package/dist/remote/history.js +146 -0
- package/dist/remote/oauth.d.ts +65 -0
- package/dist/remote/oauth.js +302 -0
- package/dist/remote/observer.d.ts +81 -0
- package/dist/remote/observer.js +174 -0
- package/dist/remote/output/json.d.ts +13 -0
- package/dist/remote/output/json.js +36 -0
- package/dist/remote/output/junit.d.ts +18 -0
- package/dist/remote/output/junit.js +50 -0
- package/dist/remote/output/streaming.d.ts +57 -0
- package/dist/remote/output/streaming.js +124 -0
- package/dist/remote/output/summary.d.ts +39 -0
- package/dist/remote/output/summary.js +99 -0
- package/dist/remote/uploader.d.ts +87 -0
- package/dist/remote/uploader.js +197 -0
- package/dist/review-comment-created.json +36 -0
- package/dist/review-submitted.json +35 -0
- package/dist/star-created.json +15 -0
- package/dist/status.json +26 -0
- package/dist/tag-push.json +20 -0
- package/dist/templates/agents-md.d.ts +8 -0
- package/dist/templates/agents-md.js +130 -0
- package/dist/templates/index.d.ts +43 -0
- package/dist/templates/index.js +48 -0
- package/dist/templates/package-json.d.ts +18 -0
- package/dist/templates/package-json.js +34 -0
- package/dist/templates/tsconfig-json.d.ts +9 -0
- package/dist/templates/tsconfig-json.js +26 -0
- package/dist/templates/workflows/hello-world.d.ts +2 -0
- package/dist/templates/workflows/hello-world.js +16 -0
- package/dist/templates/workflows/hello-world.ts +21 -0
- package/dist/templates/workflows/pr-checks.d.ts +2 -0
- package/dist/templates/workflows/pr-checks.js +40 -0
- package/dist/templates/workflows/pr-checks.ts +57 -0
- package/dist/test-runner/dry-run.d.ts +12 -0
- package/dist/test-runner/dry-run.js +66 -0
- package/dist/test-runner/event-types.d.ts +86 -0
- package/dist/test-runner/event-types.js +330 -0
- package/dist/test-runner/git-detector.d.ts +15 -0
- package/dist/test-runner/git-detector.js +30 -0
- package/dist/test-runner/index.d.ts +13 -0
- package/dist/test-runner/index.js +11 -0
- package/dist/test-runner/job-executor.d.ts +48 -0
- package/dist/test-runner/job-executor.js +245 -0
- package/dist/test-runner/output-formatter.d.ts +47 -0
- package/dist/test-runner/output-formatter.js +92 -0
- package/dist/test-runner/payload-builder.d.ts +20 -0
- package/dist/test-runner/payload-builder.js +216 -0
- package/dist/test-runner/rule-evaluator.d.ts +14 -0
- package/dist/test-runner/rule-evaluator.js +31 -0
- package/dist/test-runner/secrets-file.d.ts +24 -0
- package/dist/test-runner/secrets-file.js +62 -0
- package/dist/test-runner/step-context.d.ts +15 -0
- package/dist/test-runner/step-context.js +140 -0
- package/dist/test-runner/summary.d.ts +7 -0
- package/dist/types.d.ts +525 -0
- package/dist/types.js +33 -0
- package/dist/validation/index.d.ts +3 -0
- package/dist/validation/index.js +3 -0
- package/dist/validation/validator.d.ts +26 -0
- package/dist/validation/validator.js +164 -0
- package/dist/watch-started.json +15 -0
- package/dist/workflow-run-completed.json +23 -0
- package/dist/workflows/hello-world.ts +21 -0
- package/dist/workflows/pr-checks.ts +57 -0
- package/hack/postinstall.mjs +105 -0
- package/package.json +61 -5
- package/sbom.spdx.json +10997 -0
- 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
|