clikit-plugin 0.2.5 → 0.2.7

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.
@@ -23,8 +23,8 @@ type FormatterEntry = {
23
23
  command: (file: string) => string;
24
24
  };
25
25
  export declare function detectFormatter(projectDir: string): FormatterEntry | undefined;
26
- export declare function shouldFormat(filePath: string, extensions?: string[]): boolean;
27
- export declare function runFormatter(filePath: string, projectDir: unknown, formatterOverride?: string): FormatResult;
26
+ export declare function shouldFormat(filePath: unknown, extensions?: string[]): boolean;
27
+ export declare function runFormatter(filePath: unknown, projectDir: unknown, formatterOverride?: string): FormatResult;
28
28
  export declare function formatAutoFormatLog(result: FormatResult): string;
29
29
  export {};
30
30
  //# sourceMappingURL=auto-format.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"auto-format.d.ts","sourceRoot":"","sources":["../../src/hooks/auto-format.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,OAAO,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,KAAK,cAAc,GAAG;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CACnC,CAAC;AAsBF,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CA2B9E;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAI7E;AAED,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,OAAO,EACnB,iBAAiB,CAAC,EAAE,MAAM,GACzB,YAAY,CAoCd;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAKhE"}
1
+ {"version":3,"file":"auto-format.d.ts","sourceRoot":"","sources":["../../src/hooks/auto-format.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,OAAO,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,KAAK,cAAc,GAAG;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CACnC,CAAC;AAsBF,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CA2B9E;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,OAAO,EAAE,UAAU,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAK9E;AAED,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,OAAO,EACjB,UAAU,EAAE,OAAO,EACnB,iBAAiB,CAAC,EAAE,MAAM,GACzB,YAAY,CAqCd;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAKhE"}
@@ -9,6 +9,6 @@ export interface GitGuardResult {
9
9
  command: string;
10
10
  reason?: string;
11
11
  }
12
- export declare function checkDangerousCommand(command: string, allowForceWithLease?: boolean): GitGuardResult;
12
+ export declare function checkDangerousCommand(command: unknown, allowForceWithLease?: boolean): GitGuardResult;
13
13
  export declare function formatBlockedWarning(result: GitGuardResult): string;
14
14
  //# sourceMappingURL=git-guard.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"git-guard.d.ts","sourceRoot":"","sources":["../../src/hooks/git-guard.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAaH,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,mBAAmB,UAAO,GAAG,cAAc,CAUjG;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAEnE"}
1
+ {"version":3,"file":"git-guard.d.ts","sourceRoot":"","sources":["../../src/hooks/git-guard.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAaH,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,EAAE,mBAAmB,UAAO,GAAG,cAAc,CAalG;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAEnE"}
@@ -5,7 +5,7 @@
5
5
  * Subagents should execute their task autonomously without clarification.
6
6
  * Runs on tool.execute.before for Task tool.
7
7
  */
8
- export declare function containsQuestion(text: string): boolean;
9
- export declare function isSubagentTool(toolName: string): boolean;
8
+ export declare function containsQuestion(text: unknown): boolean;
9
+ export declare function isSubagentTool(toolName: unknown): boolean;
10
10
  export declare function formatBlockerWarning(): string;
11
11
  //# sourceMappingURL=subagent-question-blocker.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"subagent-question-blocker.d.ts","sourceRoot":"","sources":["../../src/hooks/subagent-question-blocker.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAiBH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAGtD;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAExD;AAED,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C"}
1
+ {"version":3,"file":"subagent-question-blocker.d.ts","sourceRoot":"","sources":["../../src/hooks/subagent-question-blocker.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAiBH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAMvD;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,CAEzD;AAED,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C"}
@@ -24,8 +24,8 @@ export interface EnforcementResult {
24
24
  reason?: string;
25
25
  suggestion?: string;
26
26
  }
27
- export declare function isFileInScope(filePath: string, scope: TaskScope): boolean;
28
- export declare function checkEditPermission(filePath: string, scope: TaskScope | undefined, config?: SwarmEnforcerConfig): EnforcementResult;
29
- export declare function extractFileFromToolInput(toolName: string, input: Record<string, unknown>): string | undefined;
27
+ export declare function isFileInScope(filePath: unknown, scope: TaskScope): boolean;
28
+ export declare function checkEditPermission(filePath: unknown, scope: TaskScope | undefined, config?: SwarmEnforcerConfig): EnforcementResult;
29
+ export declare function extractFileFromToolInput(toolName: unknown, input: Record<string, unknown>): string | undefined;
30
30
  export declare function formatEnforcementWarning(result: EnforcementResult): string;
31
31
  //# sourceMappingURL=swarm-enforcer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"swarm-enforcer.d.ts","sourceRoot":"","sources":["../../src/hooks/swarm-enforcer.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,MAAM,WAAW,mBAAmB;IAClC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,SAAS,GACf,OAAO,CAqBT;AAED,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,SAAS,GAAG,SAAS,EAC5B,MAAM,CAAC,EAAE,mBAAmB,GAC3B,iBAAiB,CAqBnB;AAED,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,MAAM,GAAG,SAAS,CA4BpB;AAED,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM,CAM1E"}
1
+ {"version":3,"file":"swarm-enforcer.d.ts","sourceRoot":"","sources":["../../src/hooks/swarm-enforcer.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,MAAM,WAAW,mBAAmB;IAClC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,OAAO,EACjB,KAAK,EAAE,SAAS,GACf,OAAO,CAsBT;AAED,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,OAAO,EACjB,KAAK,EAAE,SAAS,GAAG,SAAS,EAC5B,MAAM,CAAC,EAAE,mBAAmB,GAC3B,iBAAiB,CAyBnB;AAED,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,OAAO,EACjB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,MAAM,GAAG,SAAS,CA6BpB;AAED,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM,CAM1E"}
@@ -23,9 +23,9 @@ export interface TypeCheckResult {
23
23
  errors: TypeDiagnostic[];
24
24
  checkedFile: string;
25
25
  }
26
- export declare function isTypeScriptFile(filePath: string): boolean;
27
- export declare function findTsConfig(projectDir: string, override?: string): string | undefined;
28
- export declare function hasTscInstalled(projectDir: string): boolean;
29
- export declare function runTypeCheck(filePath: string, projectDir: unknown, config?: TypeCheckConfig): TypeCheckResult;
26
+ export declare function isTypeScriptFile(filePath: unknown): boolean;
27
+ export declare function findTsConfig(projectDir: unknown, override?: string): string | undefined;
28
+ export declare function hasTscInstalled(projectDir: unknown): boolean;
29
+ export declare function runTypeCheck(filePath: unknown, projectDir: unknown, config?: TypeCheckConfig): TypeCheckResult;
30
30
  export declare function formatTypeCheckWarning(result: TypeCheckResult): string;
31
31
  //# sourceMappingURL=typecheck-gate.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"typecheck-gate.d.ts","sourceRoot":"","sources":["../../src/hooks/typecheck-gate.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,cAAc,EAAE,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;CACrB;AAID,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAetF;AAED,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAW3D;AAED,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,OAAO,EACnB,MAAM,CAAC,EAAE,eAAe,GACvB,eAAe,CAgCjB;AAqCD,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,CAetE"}
1
+ {"version":3,"file":"typecheck-gate.d.ts","sourceRoot":"","sources":["../../src/hooks/typecheck-gate.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,cAAc,EAAE,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;CACrB;AAID,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,CAG3D;AAED,wBAAgB,YAAY,CAAC,UAAU,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAgBvF;AAED,wBAAgB,eAAe,CAAC,UAAU,EAAE,OAAO,GAAG,OAAO,CAY5D;AAED,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,OAAO,EACjB,UAAU,EAAE,OAAO,EACnB,MAAM,CAAC,EAAE,eAAe,GACvB,eAAe,CAiCjB;AAsCD,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,CAetE"}
package/dist/index.js CHANGED
@@ -3884,6 +3884,9 @@ var DANGEROUS_PATTERNS = [
3884
3884
  { pattern: /git\s+branch\s+-D/, reason: "Force-deleting branch may lose unmerged work" }
3885
3885
  ];
3886
3886
  function checkDangerousCommand(command, allowForceWithLease = true) {
3887
+ if (typeof command !== "string") {
3888
+ return { blocked: false, command: "" };
3889
+ }
3887
3890
  for (const { pattern, reason } of DANGEROUS_PATTERNS) {
3888
3891
  if (pattern.test(command)) {
3889
3892
  if (allowForceWithLease && /--force-with-lease/.test(command)) {
@@ -3971,11 +3974,14 @@ var QUESTION_INDICATORS = [
3971
3974
  "could you provide"
3972
3975
  ];
3973
3976
  function containsQuestion(text) {
3977
+ if (typeof text !== "string" || !text) {
3978
+ return false;
3979
+ }
3974
3980
  const lower = text.toLowerCase();
3975
3981
  return QUESTION_INDICATORS.some((indicator) => lower.includes(indicator));
3976
3982
  }
3977
3983
  function isSubagentTool(toolName) {
3978
- return toolName === "task" || toolName === "Task";
3984
+ return typeof toolName === "string" && (toolName === "task" || toolName === "Task");
3979
3985
  }
3980
3986
  function formatBlockerWarning() {
3981
3987
  return `[CliKit:subagent-blocker] Subagent attempted to ask clarifying questions. Subagents should execute autonomously.`;
@@ -4263,23 +4269,26 @@ function detectFormatter(projectDir) {
4263
4269
  return;
4264
4270
  }
4265
4271
  function shouldFormat(filePath, extensions) {
4272
+ if (typeof filePath !== "string")
4273
+ return false;
4266
4274
  const ext = path5.extname(filePath).toLowerCase();
4267
4275
  const allowedExts = extensions || DEFAULT_EXTENSIONS;
4268
4276
  return allowedExts.includes(ext);
4269
4277
  }
4270
4278
  function runFormatter(filePath, projectDir, formatterOverride) {
4279
+ const safePath = typeof filePath === "string" && filePath ? filePath : "";
4271
4280
  const safeDir = typeof projectDir === "string" && projectDir ? projectDir : process.cwd();
4272
4281
  const formatter = formatterOverride ? FORMATTERS.find((f) => f.name === formatterOverride) : detectFormatter(safeDir);
4273
- if (!formatter) {
4282
+ if (!formatter || !safePath) {
4274
4283
  return {
4275
4284
  formatted: false,
4276
- file: filePath,
4285
+ file: safePath,
4277
4286
  formatter: "none",
4278
- error: "No formatter detected"
4287
+ error: formatter ? "No file path provided" : "No formatter detected"
4279
4288
  };
4280
4289
  }
4281
4290
  try {
4282
- const cmd = formatter.command(filePath);
4291
+ const cmd = formatter.command(safePath);
4283
4292
  execSync2(cmd, {
4284
4293
  cwd: safeDir,
4285
4294
  timeout: 1e4,
@@ -4287,13 +4296,13 @@ function runFormatter(filePath, projectDir, formatterOverride) {
4287
4296
  });
4288
4297
  return {
4289
4298
  formatted: true,
4290
- file: filePath,
4299
+ file: safePath,
4291
4300
  formatter: formatter.name
4292
4301
  };
4293
4302
  } catch (err) {
4294
4303
  return {
4295
4304
  formatted: false,
4296
- file: filePath,
4305
+ file: safePath,
4297
4306
  formatter: formatter.name,
4298
4307
  error: err instanceof Error ? err.message : String(err)
4299
4308
  };
@@ -4311,16 +4320,19 @@ import * as path6 from "path";
4311
4320
  import { execSync as execSync3 } from "child_process";
4312
4321
  var TS_EXTENSIONS = [".ts", ".tsx", ".mts", ".cts"];
4313
4322
  function isTypeScriptFile(filePath) {
4323
+ if (typeof filePath !== "string")
4324
+ return false;
4314
4325
  return TS_EXTENSIONS.includes(path6.extname(filePath).toLowerCase());
4315
4326
  }
4316
4327
  function findTsConfig(projectDir, override) {
4328
+ const safeDir = typeof projectDir === "string" && projectDir ? projectDir : process.cwd();
4317
4329
  if (override) {
4318
- const overridePath = path6.resolve(projectDir, override);
4330
+ const overridePath = path6.resolve(safeDir, override);
4319
4331
  return fs6.existsSync(overridePath) ? overridePath : undefined;
4320
4332
  }
4321
4333
  const candidates = ["tsconfig.json", "tsconfig.build.json"];
4322
4334
  for (const candidate of candidates) {
4323
- const fullPath = path6.join(projectDir, candidate);
4335
+ const fullPath = path6.join(safeDir, candidate);
4324
4336
  if (fs6.existsSync(fullPath)) {
4325
4337
  return fullPath;
4326
4338
  }
@@ -4328,10 +4340,11 @@ function findTsConfig(projectDir, override) {
4328
4340
  return;
4329
4341
  }
4330
4342
  function runTypeCheck(filePath, projectDir, config) {
4343
+ const safePath = typeof filePath === "string" && filePath ? filePath : "";
4331
4344
  const safeDir = typeof projectDir === "string" && projectDir ? projectDir : process.cwd();
4332
4345
  const tsConfig = findTsConfig(safeDir, config?.tsconfig);
4333
4346
  if (!tsConfig) {
4334
- return { clean: true, errors: [], checkedFile: filePath };
4347
+ return { clean: true, errors: [], checkedFile: safePath };
4335
4348
  }
4336
4349
  try {
4337
4350
  const tscCmd = `npx tsc --noEmit --pretty false -p "${tsConfig}"`;
@@ -4341,18 +4354,20 @@ function runTypeCheck(filePath, projectDir, config) {
4341
4354
  stdio: ["pipe", "pipe", "pipe"],
4342
4355
  encoding: "utf-8"
4343
4356
  });
4344
- return { clean: true, errors: [], checkedFile: filePath };
4357
+ return { clean: true, errors: [], checkedFile: safePath };
4345
4358
  } catch (err) {
4346
4359
  const output = err instanceof Error && "stdout" in err ? String(err.stdout) : "";
4347
- const errors = parseTscOutput(output, filePath);
4360
+ const errors = parseTscOutput(output, safePath);
4348
4361
  return {
4349
4362
  clean: errors.length === 0,
4350
4363
  errors,
4351
- checkedFile: filePath
4364
+ checkedFile: safePath
4352
4365
  };
4353
4366
  }
4354
4367
  }
4355
4368
  function parseTscOutput(output, filterFile) {
4369
+ if (typeof output !== "string")
4370
+ return [];
4356
4371
  const diagnostics = [];
4357
4372
  const lines = output.split(`
4358
4373
  `);
@@ -0,0 +1,136 @@
1
+ ---
2
+ date: 2026-02-15
3
+ phase: implementing
4
+ branch: main
5
+ ---
6
+
7
+ # Handoff: CliKit Complete Type Guard Audit
8
+
9
+ ---
10
+
11
+ ## Status Summary
12
+
13
+ CliKit plugin v0.2.6 published with many type guards. Typecheck passes. However, there are still potential runtime issues where OpenCode passes non-string values that could cause `.toLowerCase()`, `.test()`, `.split()` etc. to fail.
14
+
15
+ ---
16
+
17
+ ## Version History
18
+
19
+ | Version | Fix |
20
+ |---------|-----|
21
+ | 0.2.1 | Type guards in hooks (truncator, security-check, compaction) |
22
+ | 0.2.2 | Abort on JSON parse error |
23
+ | 0.2.3 | Fix JSONC comment stripping breaking URLs |
24
+ | 0.2.4 | Remove backup logic, fix `todos.filter` error |
25
+ | 0.2.5 | Fix `path.join` error - guards for projectDir/cwd params |
26
+ | 0.2.6 | Fix `text.toLowerCase` error in subagent-question-blocker |
27
+
28
+ ---
29
+
30
+ ## Remaining Issues (Need Type Guards)
31
+
32
+ ### 1. git-guard.ts: `checkDangerousCommand`
33
+ **Line 25:** `command: string` - no type guard
34
+ **Used:** `index.ts:221` - `toolInput.command as string | undefined`
35
+ **Risk:** `pattern.test(command)` fails if command is object
36
+
37
+ ```typescript
38
+ // Fix needed:
39
+ export function checkDangerousCommand(command: unknown, allowForceWithLease = true): GitGuardResult {
40
+ if (typeof command !== "string") {
41
+ return { blocked: false, command: "" };
42
+ }
43
+ // ... rest
44
+ }
45
+ ```
46
+
47
+ ### 2. swarm-enforcer.ts: `isFileInScope`
48
+ **Line 33-36:** `filePath: string` - no type guard
49
+ **Risk:** `path.resolve(filePath)` fails if filePath is not string
50
+
51
+ ```typescript
52
+ // Fix needed:
53
+ export function isFileInScope(filePath: unknown, scope: TaskScope): boolean {
54
+ if (typeof filePath !== "string") return false;
55
+ // ...
56
+ }
57
+ ```
58
+
59
+ ### 3. swarm-enforcer.ts: `checkEditPermission`
60
+ **Line 59-62:** `filePath: string` - no type guard
61
+
62
+ ### 4. index.ts: Tool input casting
63
+ Multiple places where `toolInput.X as string | undefined` is used but the value could be an object:
64
+ - Line 218: `toolInput.command`
65
+ - Line 269: `toolInput.prompt`
66
+ - Line 335: `toolInput.filePath`
67
+ - Line 351: `toolInput.filePath`
68
+
69
+ ---
70
+
71
+ ## Files Modified (Uncommitted)
72
+
73
+ | File | Status |
74
+ |------|--------|
75
+ | `.opencode/package.json` | v0.2.6 |
76
+ | `.opencode/src/cli.ts` | Removed backup, fixed JSONC |
77
+ | `.opencode/src/config.ts` | Type guard for loadCliKitConfig |
78
+ | `.opencode/src/index.ts` | Array.isArray for todos |
79
+ | `.opencode/src/hooks/auto-format.ts` | Type guards |
80
+ | `.opencode/src/hooks/comment-checker.ts` | Type guards |
81
+ | `.opencode/src/hooks/compaction.ts` | Type guards |
82
+ | `.opencode/src/hooks/env-context.ts` | Type guards |
83
+ | `.opencode/src/hooks/security-check.ts` | Type guards |
84
+ | `.opencode/src/hooks/session-notification.ts` | Type guards |
85
+ | `.opencode/src/hooks/subagent-question-blocker.ts` | Type guards |
86
+ | `.opencode/src/hooks/swarm-enforcer.ts` | Partial (extractFileFromToolInput only) |
87
+ | `.opencode/src/hooks/todo-enforcer.ts` | Type guards |
88
+ | `.opencode/src/hooks/truncator.ts` | Type guards |
89
+ | `.opencode/src/hooks/typecheck-gate.ts` | Type guards |
90
+
91
+ ---
92
+
93
+ ## Git State
94
+
95
+ - **Branch:** `main`
96
+ - **Last commit:** `31b200c` - Update README with simplified installation
97
+ - **Uncommitted changes:** 15 files
98
+
99
+ ---
100
+
101
+ ## Next Steps
102
+
103
+ 1. [ ] Add type guard to `git-guard.ts:checkDangerousCommand(command: unknown)`
104
+ 2. [ ] Add type guard to `swarm-enforcer.ts:isFileInScope(filePath: unknown)`
105
+ 3. [ ] Add type guard to `swarm-enforcer.ts:checkEditPermission(filePath: unknown)`
106
+ 4. [ ] Run typecheck
107
+ 5. [ ] Publish v0.2.7
108
+ 6. [ ] Test: `opencode` starts without errors
109
+
110
+ ---
111
+
112
+ ## Pattern for Type Guards
113
+
114
+ ```typescript
115
+ // Before (breaks on non-string):
116
+ export function myFunc(content: string): Result {
117
+ return content.split("\n"); // CRASH if content is object
118
+ }
119
+
120
+ // After (safe):
121
+ export function myFunc(content: unknown): Result {
122
+ if (typeof content !== "string") {
123
+ return defaultResult; // Safe fallback
124
+ }
125
+ return content.split("\n");
126
+ }
127
+ ```
128
+
129
+ ---
130
+
131
+ ## Resume Command
132
+
133
+ To resume, use `/resume` and it will:
134
+ 1. Load this handoff
135
+ 2. Propose fixing remaining type guards in git-guard.ts and swarm-enforcer.ts
136
+ 3. Publish v0.2.7
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clikit-plugin",
3
- "version": "0.2.5",
3
+ "version": "0.2.7",
4
4
  "description": "OpenCode plugin with 10 agents, 19 commands, 48 skills, 14 hooks",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",