clikit-plugin 0.1.9 → 0.2.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/dist/cli.js +39 -9
- package/dist/hooks/comment-checker.d.ts +2 -2
- package/dist/hooks/comment-checker.d.ts.map +1 -1
- package/dist/hooks/compaction.d.ts.map +1 -1
- package/dist/hooks/security-check.d.ts.map +1 -1
- package/dist/hooks/session-notification.d.ts +2 -2
- package/dist/hooks/session-notification.d.ts.map +1 -1
- package/dist/hooks/truncator.d.ts.map +1 -1
- package/dist/index.js +31 -3
- package/memory/handoffs/2026-02-15-plugin-install-fix.md +140 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -6,9 +6,17 @@ import * as fs from "fs";
|
|
|
6
6
|
import * as path from "path";
|
|
7
7
|
import * as os from "os";
|
|
8
8
|
var PLUGIN_NAME = "clikit-plugin";
|
|
9
|
-
var VERSION = "0.
|
|
9
|
+
var VERSION = "0.2.0";
|
|
10
10
|
function getRealHome() {
|
|
11
|
-
|
|
11
|
+
if (process.env.SNAP_REAL_HOME) {
|
|
12
|
+
return process.env.SNAP_REAL_HOME;
|
|
13
|
+
}
|
|
14
|
+
const home = os.homedir();
|
|
15
|
+
const snapMatch = home.match(/^(\/home\/[^/]+)\/snap\//);
|
|
16
|
+
if (snapMatch) {
|
|
17
|
+
return snapMatch[1];
|
|
18
|
+
}
|
|
19
|
+
return home;
|
|
12
20
|
}
|
|
13
21
|
function getConfigDir() {
|
|
14
22
|
const home = getRealHome();
|
|
@@ -40,11 +48,25 @@ function parseConfig(configPath) {
|
|
|
40
48
|
}
|
|
41
49
|
const content = fs.readFileSync(configPath, "utf-8");
|
|
42
50
|
const cleaned = content.replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
|
|
43
|
-
|
|
44
|
-
|
|
51
|
+
const cleanedTrailing = cleaned.replace(/,\s*([}\]])/g, "$1");
|
|
52
|
+
return JSON.parse(cleanedTrailing);
|
|
53
|
+
} catch (err) {
|
|
54
|
+
console.error(`Warning: Failed to parse config at ${configPath}: ${err}`);
|
|
45
55
|
return {};
|
|
46
56
|
}
|
|
47
57
|
}
|
|
58
|
+
function backupConfig(configPath) {
|
|
59
|
+
try {
|
|
60
|
+
if (!fs.existsSync(configPath)) {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
const backupPath = `${configPath}.backup-${Date.now()}`;
|
|
64
|
+
fs.copyFileSync(configPath, backupPath);
|
|
65
|
+
return backupPath;
|
|
66
|
+
} catch {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
48
70
|
function writeConfig(configPath, config) {
|
|
49
71
|
ensureConfigDir();
|
|
50
72
|
const tmpPath = `${configPath}.tmp`;
|
|
@@ -67,12 +89,20 @@ async function install() {
|
|
|
67
89
|
}
|
|
68
90
|
const configPath = getConfigPath();
|
|
69
91
|
try {
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
92
|
+
const backupPath = backupConfig(configPath);
|
|
93
|
+
if (backupPath) {
|
|
94
|
+
console.log(` Backup created: ${backupPath}`);
|
|
95
|
+
}
|
|
96
|
+
const config = parseConfig(configPath);
|
|
97
|
+
const existingPlugins = Array.isArray(config.plugin) ? config.plugin : [];
|
|
98
|
+
const preservedKeys = Object.keys(config).filter((k) => k !== "plugin");
|
|
99
|
+
if (preservedKeys.length > 0) {
|
|
100
|
+
console.log(` Preserving existing config: ${preservedKeys.join(", ")}`);
|
|
101
|
+
}
|
|
102
|
+
const filteredPlugins = existingPlugins.filter((p) => p !== PLUGIN_NAME && !p.startsWith(`${PLUGIN_NAME}@`));
|
|
73
103
|
filteredPlugins.push(PLUGIN_NAME);
|
|
74
|
-
config
|
|
75
|
-
writeConfig(configPath,
|
|
104
|
+
const newConfig = { ...config, plugin: filteredPlugins };
|
|
105
|
+
writeConfig(configPath, newConfig);
|
|
76
106
|
console.log(`\u2713 Plugin added to ${configPath}`);
|
|
77
107
|
} catch (err) {
|
|
78
108
|
console.error(`\u2717 Failed to update OpenCode config: ${err}`);
|
|
@@ -11,7 +11,7 @@ export interface CommentCheckResult {
|
|
|
11
11
|
totalLines: number;
|
|
12
12
|
ratio: number;
|
|
13
13
|
}
|
|
14
|
-
export declare function checkCommentDensity(content:
|
|
15
|
-
export declare function hasExcessiveAIComments(content:
|
|
14
|
+
export declare function checkCommentDensity(content: unknown, threshold?: number): CommentCheckResult;
|
|
15
|
+
export declare function hasExcessiveAIComments(content: unknown): boolean;
|
|
16
16
|
export declare function formatCommentWarning(result: CommentCheckResult): string;
|
|
17
17
|
//# sourceMappingURL=comment-checker.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"comment-checker.d.ts","sourceRoot":"","sources":["../../src/hooks/comment-checker.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAWH,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"comment-checker.d.ts","sourceRoot":"","sources":["../../src/hooks/comment-checker.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAWH,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,GAAE,MAAY,GAAG,kBAAkB,CAqDjG;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAYhE;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM,CAGvE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compaction.d.ts","sourceRoot":"","sources":["../../src/hooks/compaction.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAMH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,UAAU;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,QAAQ,CAAC,EAAE,SAAS,EAAE,CAAC;IACvB,KAAK,CAAC,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/D,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAuFzE;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,GAAE,MAAW,GAAG,SAAS,EAAE,
|
|
1
|
+
{"version":3,"file":"compaction.d.ts","sourceRoot":"","sources":["../../src/hooks/compaction.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAMH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,UAAU;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,QAAQ,CAAC,EAAE,SAAS,EAAE,CAAC;IACvB,KAAK,CAAC,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/D,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAuFzE;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,GAAE,MAAW,GAAG,SAAS,EAAE,CA2DlF;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,iBAAiB,EAAE,QAAQ,GAAE,MAAa,GAAG,MAAM,CA4ChG;AAED,wBAAgB,wBAAwB,CACtC,UAAU,EAAE,MAAM,EAClB,MAAM,CAAC,EAAE,gBAAgB,GACxB,iBAAiB,CAYnB;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,iBAAiB,GAAG,MAAM,CAMtE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"security-check.d.ts","sourceRoot":"","sources":["../../src/hooks/security-check.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAyBH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,eAAe,EAAE,CAAC;CAC7B;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,mBAAmB,
|
|
1
|
+
{"version":3,"file":"security-check.d.ts","sourceRoot":"","sources":["../../src/hooks/security-check.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAyBH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,eAAe,EAAE,CAAC;CAC7B;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,mBAAmB,CAmB7F;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,mBAAmB,GAAG,MAAM,CAUzE"}
|
|
@@ -17,7 +17,7 @@ export interface NotificationPayload {
|
|
|
17
17
|
urgency?: "low" | "normal" | "critical";
|
|
18
18
|
}
|
|
19
19
|
export declare function sendNotification(payload: NotificationPayload): boolean;
|
|
20
|
-
export declare function buildIdleNotification(sessionId?:
|
|
21
|
-
export declare function buildErrorNotification(error: unknown, sessionId?:
|
|
20
|
+
export declare function buildIdleNotification(sessionId?: unknown, prefix?: string): NotificationPayload;
|
|
21
|
+
export declare function buildErrorNotification(error: unknown, sessionId?: unknown, prefix?: string): NotificationPayload;
|
|
22
22
|
export declare function formatNotificationLog(payload: NotificationPayload, sent: boolean): string;
|
|
23
23
|
//# sourceMappingURL=session-notification.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-notification.d.ts","sourceRoot":"","sources":["../../src/hooks/session-notification.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,WAAW,yBAAyB;IACxC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,UAAU,CAAC;CACzC;AA0BD,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAsBtE;AAED,wBAAgB,qBAAqB,CACnC,SAAS,CAAC,EAAE,
|
|
1
|
+
{"version":3,"file":"session-notification.d.ts","sourceRoot":"","sources":["../../src/hooks/session-notification.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,WAAW,yBAAyB;IACxC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,UAAU,CAAC;CACzC;AA0BD,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAsBtE;AAED,wBAAgB,qBAAqB,CACnC,SAAS,CAAC,EAAE,OAAO,EACnB,MAAM,CAAC,EAAE,MAAM,GACd,mBAAmB,CAUrB;AAED,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,OAAO,EACd,SAAS,CAAC,EAAE,OAAO,EACnB,MAAM,CAAC,EAAE,MAAM,GACd,mBAAmB,CAerB;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,mBAAmB,EAAE,IAAI,EAAE,OAAO,GAAG,MAAM,CAIzF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"truncator.d.ts","sourceRoot":"","sources":["../../src/hooks/truncator.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,OAAO,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;CACjB;AAOD,wBAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,eAAe,GACvB,OAAO,
|
|
1
|
+
{"version":3,"file":"truncator.d.ts","sourceRoot":"","sources":["../../src/hooks/truncator.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,OAAO,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;CACjB;AAOD,wBAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,eAAe,GACvB,OAAO,CAYT;AAED,wBAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,eAAe,GACvB,cAAc,CAsFhB;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAIlE"}
|
package/dist/index.js
CHANGED
|
@@ -3917,6 +3917,8 @@ var SENSITIVE_FILES = [
|
|
|
3917
3917
|
/id_ed25519$/
|
|
3918
3918
|
];
|
|
3919
3919
|
function scanContentForSecrets(content, filename) {
|
|
3920
|
+
if (typeof content !== "string")
|
|
3921
|
+
return { safe: true, findings: [] };
|
|
3920
3922
|
const findings = [];
|
|
3921
3923
|
const lines = content.split(`
|
|
3922
3924
|
`);
|
|
@@ -3984,6 +3986,9 @@ var EXCESSIVE_COMMENT_PATTERNS = [
|
|
|
3984
3986
|
/#\s*(?:This|The|A|An) (?:function|method|class|script)/i
|
|
3985
3987
|
];
|
|
3986
3988
|
function checkCommentDensity(content, threshold = 0.3) {
|
|
3989
|
+
if (typeof content !== "string") {
|
|
3990
|
+
return { excessive: false, count: 0, totalLines: 0, ratio: 0 };
|
|
3991
|
+
}
|
|
3987
3992
|
const lines = content.split(`
|
|
3988
3993
|
`);
|
|
3989
3994
|
const totalLines = lines.filter((l) => l.trim().length > 0).length;
|
|
@@ -4026,6 +4031,9 @@ function checkCommentDensity(content, threshold = 0.3) {
|
|
|
4026
4031
|
};
|
|
4027
4032
|
}
|
|
4028
4033
|
function hasExcessiveAIComments(content) {
|
|
4034
|
+
if (typeof content !== "string") {
|
|
4035
|
+
return false;
|
|
4036
|
+
}
|
|
4029
4037
|
let matches = 0;
|
|
4030
4038
|
for (const pattern of EXCESSIVE_COMMENT_PATTERNS) {
|
|
4031
4039
|
const found = content.match(new RegExp(pattern, "gm"));
|
|
@@ -4424,18 +4432,20 @@ function sendNotification(payload) {
|
|
|
4424
4432
|
}
|
|
4425
4433
|
function buildIdleNotification(sessionId, prefix) {
|
|
4426
4434
|
const titlePrefix = prefix || "OpenCode";
|
|
4435
|
+
const sid = typeof sessionId === "string" ? sessionId : undefined;
|
|
4427
4436
|
return {
|
|
4428
4437
|
title: `${titlePrefix} \u2014 Task Complete`,
|
|
4429
|
-
body:
|
|
4438
|
+
body: sid ? `Session ${sid.substring(0, 8)} is idle and waiting for input.` : "Session is idle and waiting for input.",
|
|
4430
4439
|
urgency: "normal"
|
|
4431
4440
|
};
|
|
4432
4441
|
}
|
|
4433
4442
|
function buildErrorNotification(error, sessionId, prefix) {
|
|
4434
4443
|
const titlePrefix = prefix || "OpenCode";
|
|
4435
4444
|
const errorStr = typeof error === "string" ? error : error instanceof Error ? error.message : String(error);
|
|
4445
|
+
const sid = typeof sessionId === "string" ? sessionId : undefined;
|
|
4436
4446
|
return {
|
|
4437
4447
|
title: `${titlePrefix} \u2014 Error`,
|
|
4438
|
-
body:
|
|
4448
|
+
body: sid ? `Session ${sid.substring(0, 8)}: ${errorStr.substring(0, 100)}` : errorStr.substring(0, 120),
|
|
4439
4449
|
urgency: "critical"
|
|
4440
4450
|
};
|
|
4441
4451
|
}
|
|
@@ -4448,6 +4458,8 @@ var DEFAULT_MAX_LINES = 500;
|
|
|
4448
4458
|
var DEFAULT_HEAD_LINES = 50;
|
|
4449
4459
|
var DEFAULT_TAIL_LINES = 50;
|
|
4450
4460
|
function shouldTruncate(content, config) {
|
|
4461
|
+
if (typeof content !== "string")
|
|
4462
|
+
return false;
|
|
4451
4463
|
const maxChars = config?.max_output_chars ?? DEFAULT_MAX_CHARS;
|
|
4452
4464
|
const maxLines = config?.max_output_lines ?? DEFAULT_MAX_LINES;
|
|
4453
4465
|
if (content.length > maxChars)
|
|
@@ -4459,6 +4471,16 @@ function shouldTruncate(content, config) {
|
|
|
4459
4471
|
return false;
|
|
4460
4472
|
}
|
|
4461
4473
|
function truncateOutput(content, config) {
|
|
4474
|
+
if (typeof content !== "string") {
|
|
4475
|
+
return {
|
|
4476
|
+
truncated: false,
|
|
4477
|
+
originalLength: 0,
|
|
4478
|
+
truncatedLength: 0,
|
|
4479
|
+
originalLines: 0,
|
|
4480
|
+
truncatedLines: 0,
|
|
4481
|
+
content: ""
|
|
4482
|
+
};
|
|
4483
|
+
}
|
|
4462
4484
|
const maxChars = config?.max_output_chars ?? DEFAULT_MAX_CHARS;
|
|
4463
4485
|
const maxLines = config?.max_output_lines ?? DEFAULT_MAX_LINES;
|
|
4464
4486
|
const headLines = config?.preserve_head_lines ?? DEFAULT_HEAD_LINES;
|
|
@@ -4630,6 +4652,8 @@ function readMemoryRefs(projectDir, limit = 10) {
|
|
|
4630
4652
|
const fullPath = path7.join(subdirPath, file);
|
|
4631
4653
|
const stat = fs7.statSync(fullPath);
|
|
4632
4654
|
const raw = fs7.readFileSync(fullPath, "utf-8");
|
|
4655
|
+
if (typeof raw !== "string" || !raw.trim())
|
|
4656
|
+
continue;
|
|
4633
4657
|
let summary;
|
|
4634
4658
|
const ext = path7.extname(file);
|
|
4635
4659
|
if (ext === ".md") {
|
|
@@ -4637,7 +4661,8 @@ function readMemoryRefs(projectDir, limit = 10) {
|
|
|
4637
4661
|
summary = headingMatch ? headingMatch[1] : raw.substring(0, 100).trim();
|
|
4638
4662
|
} else if (ext === ".json") {
|
|
4639
4663
|
const parsed = JSON.parse(raw);
|
|
4640
|
-
|
|
4664
|
+
const content = parsed.content;
|
|
4665
|
+
summary = parsed.summary || parsed.title || (typeof content === "string" ? content.substring(0, 100) : "") || "";
|
|
4641
4666
|
} else {
|
|
4642
4667
|
summary = raw.substring(0, 100).trim();
|
|
4643
4668
|
}
|
|
@@ -4698,6 +4723,9 @@ Recent Memory References:`);
|
|
|
4698
4723
|
lines.push("</compaction-context>");
|
|
4699
4724
|
const block = lines.join(`
|
|
4700
4725
|
`);
|
|
4726
|
+
if (typeof block !== "string")
|
|
4727
|
+
return `<compaction-context>
|
|
4728
|
+
</compaction-context>`;
|
|
4701
4729
|
if (block.length > maxChars) {
|
|
4702
4730
|
return block.substring(0, maxChars) + `
|
|
4703
4731
|
... [compaction context truncated]
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
---
|
|
2
|
+
date: 2026-02-15
|
|
3
|
+
phase: implementing
|
|
4
|
+
branch: main
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Handoff: CliKit Plugin Installation & Runtime Fixes
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Status Summary
|
|
12
|
+
|
|
13
|
+
CliKit plugin published to npm (v0.1.9 → v0.2.0). Fixed snap/bun path detection and multiple runtime errors. **CRITICAL ISSUE IDENTIFIED**: Installer overwrites `opencode.json` instead of merging with existing config, deleting user's existing settings. Multiple `.split()`, `.substring()` errors still occurring in hooks due to non-string arguments.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Artifacts
|
|
18
|
+
|
|
19
|
+
| Type | Path | Status |
|
|
20
|
+
|------|------|--------|
|
|
21
|
+
| Handoff | `.opencode/memory/handoffs/2026-02-15-installing.md` | 📚 Previous |
|
|
22
|
+
| Config | `~/.config/opencode/opencode.json` | ⚠️ Gets overwritten |
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Task Status
|
|
27
|
+
|
|
28
|
+
### ✅ Completed
|
|
29
|
+
- [x] T-001-T-007: Plugin implementation (10 agents, 19 commands, 48 skills, 14 hooks, 6 tools)
|
|
30
|
+
- [x] Fix snap/bun path detection using `SNAP_REAL_HOME` and regex fallback
|
|
31
|
+
- [x] Fix `buildErrorNotification` to handle Error objects
|
|
32
|
+
- [x] Fix `buildIdleNotification` to handle non-string sessionId
|
|
33
|
+
- [x] Fix `checkCommentDensity` and `hasExcessiveAIComments` to handle non-string content
|
|
34
|
+
- [x] Published v0.1.7, v0.1.8, v0.1.9, v0.2.0 to npm
|
|
35
|
+
|
|
36
|
+
### 🔄 In Progress
|
|
37
|
+
- [ ] **CRITICAL**: Fix installer to MERGE with existing opencode.json instead of overwriting
|
|
38
|
+
- **Current state:** `parseConfig()` reads existing config, but may not preserve all keys
|
|
39
|
+
- **User report:** "nó ghi đè file opencode.json làm xóa config có sẵn của tôi"
|
|
40
|
+
- **Root cause:** Need to deep merge, not shallow overwrite
|
|
41
|
+
|
|
42
|
+
- [ ] Fix remaining runtime errors in hooks
|
|
43
|
+
- **Files needing defensive type checks:**
|
|
44
|
+
- `src/hooks/truncator.ts` - `shouldTruncate()`, `truncateOutput()`
|
|
45
|
+
- `src/hooks/security-check.ts` - `scanContentForSecrets()`
|
|
46
|
+
- `src/hooks/compaction.ts` - multiple `.substring()` calls
|
|
47
|
+
- **Pattern:** Add `if (typeof content !== "string") return defaultResult;` at function start
|
|
48
|
+
|
|
49
|
+
### 📋 Not Started
|
|
50
|
+
- [ ] T-009: Verify plugin loads when OpenCode starts
|
|
51
|
+
- [ ] T-010: Test installation in fresh environment
|
|
52
|
+
- [ ] Add automated tests for installer
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Files Modified
|
|
57
|
+
|
|
58
|
+
| File | Status | Notes |
|
|
59
|
+
|------|--------|-------|
|
|
60
|
+
| `src/cli.ts` | Modified | Added `getRealHome()` for snap path detection |
|
|
61
|
+
| `src/hooks/session-notification.ts` | Modified | Fixed `buildIdleNotification`, `buildErrorNotification` |
|
|
62
|
+
| `src/hooks/comment-checker.ts` | Modified | Added type guards for content param |
|
|
63
|
+
| `src/index.ts` | Modified | Pass raw error to `buildErrorNotification` |
|
|
64
|
+
| `package.json` | Modified | Version bumps to 0.2.0 |
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Git State
|
|
69
|
+
|
|
70
|
+
- **Branch:** `main`
|
|
71
|
+
- **Last commit:** `31b200c` - Update README with simplified installation
|
|
72
|
+
- **Uncommitted changes:** Yes (5 modified files)
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Known Issues
|
|
77
|
+
|
|
78
|
+
1. **CRITICAL: Installer overwrites opencode.json** - deletes user's existing config (mcp, provider settings)
|
|
79
|
+
- Need to deep merge instead of shallow merge
|
|
80
|
+
- Should backup existing config before modifying
|
|
81
|
+
|
|
82
|
+
2. **Runtime TypeError: `.split()`, `.substring()` on undefined**
|
|
83
|
+
- Multiple hooks receive non-string arguments from OpenCode events
|
|
84
|
+
- Need defensive type checks in ALL functions that call string methods
|
|
85
|
+
|
|
86
|
+
3. **Snap/bun path mismatch** - partially fixed but user still sees wrong path
|
|
87
|
+
- `bun x` may cache old versions
|
|
88
|
+
- Need to verify `SNAP_REAL_HOME` detection works in user's environment
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Next Steps
|
|
93
|
+
|
|
94
|
+
1. [ ] **FIX INSTALLER** - Merge with existing config, don't overwrite:
|
|
95
|
+
```typescript
|
|
96
|
+
// In cli.ts, preserve existing config keys
|
|
97
|
+
const existingConfig = parseConfig(configPath);
|
|
98
|
+
const newConfig = { ...existingConfig, plugin: filteredPlugins };
|
|
99
|
+
writeConfig(configPath, newConfig);
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
2. [ ] Add defensive type checks to all hooks that use string methods:
|
|
103
|
+
- `truncator.ts`: `shouldTruncate()`, `truncateOutput()`
|
|
104
|
+
- `security-check.ts`: `scanContentForSecrets()`
|
|
105
|
+
- `compaction.ts`: All substring calls
|
|
106
|
+
|
|
107
|
+
3. [ ] Publish v0.2.1 with fixes
|
|
108
|
+
|
|
109
|
+
4. [ ] Test: `bun x clikit-plugin@latest install` should preserve existing config
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Context for Resumption
|
|
114
|
+
|
|
115
|
+
### The Core Problem
|
|
116
|
+
The installer's `writeConfig()` function writes the entire config object to disk. The current code does spread, but needs to ensure `parseConfig()` returns complete existing config.
|
|
117
|
+
|
|
118
|
+
### Solution Approach
|
|
119
|
+
```typescript
|
|
120
|
+
// cli.ts - install() function:
|
|
121
|
+
const existingConfig = parseConfig(configPath) || {};
|
|
122
|
+
const plugins = Array.isArray(existingConfig.plugin) ? [...existingConfig.plugin] : [];
|
|
123
|
+
// ... modify plugins array ...
|
|
124
|
+
config.plugin = filteredPlugins;
|
|
125
|
+
// existingConfig already has all keys, we just update plugin
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Files to Review
|
|
129
|
+
- `src/cli.ts:55-108` — Installer logic
|
|
130
|
+
- `src/hooks/truncator.ts` — Needs type guards
|
|
131
|
+
- `src/hooks/security-check.ts` — Needs type guards
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Resume Command
|
|
136
|
+
|
|
137
|
+
To resume, use `/resume` and it will:
|
|
138
|
+
1. Load this handoff
|
|
139
|
+
2. Check for drift
|
|
140
|
+
3. Propose fixing installer merge logic first
|