@hasna/hooks 0.7.10 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -6
- package/bin/index.js +2640 -1820
- package/bin/serve.js +742 -551
- package/dist/config.d.ts +25 -19
- package/dist/index.d.ts +3 -2
- package/dist/index.js +1251 -717
- package/dist/lib/app-home.d.ts +9 -0
- package/dist/lib/installer.d.ts +40 -10
- package/dist/lib/local-opt-in.d.ts +80 -0
- package/dist/lib/profiles.d.ts +10 -0
- package/dist/lib/registration.d.ts +75 -0
- package/dist/lib/registry.d.ts +14 -0
- package/dist/lib/resolver-types.d.ts +45 -0
- package/dist/lib/sync.d.ts +13 -8
- package/dist/lib/transport.d.ts +87 -0
- package/dist/openapi.d.ts +1 -1
- package/dist/storage.js +54 -63
- package/hooks/hook-affected-tests/package.json +1 -1
- package/hooks/hook-agent-rules-version-check/README.md +1 -1
- package/hooks/hook-agent-rules-version-check/package.json +1 -1
- package/hooks/hook-agentmessages/package.json +1 -1
- package/hooks/hook-announce-start/package.json +1 -1
- package/hooks/hook-announce-stop/package.json +1 -1
- package/hooks/hook-autoformat/package.json +1 -1
- package/hooks/hook-branchprotect/package.json +1 -1
- package/hooks/hook-checkbugs/package.json +1 -1
- package/hooks/hook-checkdocs/package.json +1 -1
- package/hooks/hook-checkfiles/package.json +1 -1
- package/hooks/hook-checklint/package.json +1 -1
- package/hooks/hook-checkpoint/package.json +1 -1
- package/hooks/hook-checksecurity/package.json +1 -1
- package/hooks/hook-checktasks/package.json +1 -1
- package/hooks/hook-checktests/package.json +1 -1
- package/hooks/hook-conflict-detect/package.json +1 -1
- package/hooks/hook-contextrefresh/package.json +1 -1
- package/hooks/hook-desktopnotify/package.json +1 -1
- package/hooks/hook-dm-inject/package.json +1 -1
- package/hooks/hook-envsetup/package.json +1 -1
- package/hooks/hook-failure-to-task/package.json +1 -1
- package/hooks/hook-filelock/package.json +1 -1
- package/hooks/hook-fleet-blockers-gate/package.json +1 -1
- package/hooks/hook-fleet-catchup/package.json +1 -1
- package/hooks/hook-gitguard/package.json +1 -1
- package/hooks/hook-packageage/package.json +1 -1
- package/hooks/hook-permissionguard/package.json +1 -1
- package/hooks/hook-phonenotify/package.json +1 -1
- package/hooks/hook-precompact/package.json +1 -1
- package/hooks/hook-protectfiles/package.json +1 -1
- package/hooks/hook-stylescheck/package.json +1 -1
- package/hooks/hook-trash-guard/README.md +132 -0
- package/hooks/hook-trash-guard/package.json +12 -0
- package/hooks/hook-trash-guard/src/hook.ts +1114 -0
- package/hooks/hook-typecheck-gate/package.json +1 -1
- package/package.json +7 -10
- package/scripts/ensure-profiles-dir.mjs +52 -1
- package/hooks/codewith-native-common.test.ts +0 -1935
- package/hooks/hook-affected-tests/tsconfig.json +0 -25
- package/hooks/hook-agent-rules-version-check/src/hook.test.ts +0 -104
- package/hooks/hook-agent-rules-version-check/tsconfig.json +0 -25
- package/hooks/hook-announce-start/tsconfig.json +0 -25
- package/hooks/hook-announce-stop/tsconfig.json +0 -25
- package/hooks/hook-autoformat/tsconfig.json +0 -25
- package/hooks/hook-branchprotect/tsconfig.json +0 -25
- package/hooks/hook-checkbugs/tsconfig.json +0 -15
- package/hooks/hook-checkdocs/tsconfig.json +0 -15
- package/hooks/hook-checkfiles/tsconfig.json +0 -15
- package/hooks/hook-checklint/tsconfig.json +0 -15
- package/hooks/hook-checkpoint/tsconfig.json +0 -25
- package/hooks/hook-checksecurity/tsconfig.json +0 -15
- package/hooks/hook-checktasks/tsconfig.json +0 -20
- package/hooks/hook-checktests/tsconfig.json +0 -15
- package/hooks/hook-conflict-detect/tsconfig.json +0 -25
- package/hooks/hook-contextrefresh/tsconfig.json +0 -25
- package/hooks/hook-desktopnotify/tsconfig.json +0 -25
- package/hooks/hook-dm-inject/tsconfig.json +0 -25
- package/hooks/hook-envsetup/tsconfig.json +0 -25
- package/hooks/hook-failure-to-task/tsconfig.json +0 -25
- package/hooks/hook-filelock/tsconfig.json +0 -25
- package/hooks/hook-fleet-blockers-gate/src/hook.test.ts +0 -302
- package/hooks/hook-fleet-blockers-gate/tsconfig.json +0 -25
- package/hooks/hook-fleet-catchup/src/hook.test.ts +0 -156
- package/hooks/hook-fleet-catchup/tsconfig.json +0 -25
- package/hooks/hook-gitguard/tsconfig.json +0 -25
- package/hooks/hook-knowledge-context/src/hook.test.ts +0 -379
- package/hooks/hook-packageage/tsconfig.json +0 -25
- package/hooks/hook-permissionguard/tsconfig.json +0 -25
- package/hooks/hook-phonenotify/tsconfig.json +0 -25
- package/hooks/hook-precompact/tsconfig.json +0 -25
- package/hooks/hook-protectfiles/tsconfig.json +0 -25
- package/hooks/hook-scanoutput/src/hook.test.ts +0 -217
- package/hooks/hook-spiral-detector/src/hook.test.ts +0 -72
- package/hooks/hook-stylescheck/tsconfig.json +0 -25
- package/hooks/hook-typecheck-gate/tsconfig.json +0 -25
- package/hooks/hook-workspace-repos-guard/src/hook.test.ts +0 -466
- package/hooks/hook-workspace-repos-guard/tsconfig.json +0 -21
- package/hooks/mention-context/src/hook.test.ts +0 -68
package/dist/storage.js
CHANGED
|
@@ -15,92 +15,77 @@ var __export = (target, all) => {
|
|
|
15
15
|
};
|
|
16
16
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
17
17
|
|
|
18
|
-
//
|
|
18
|
+
// src/lib/app-home.ts
|
|
19
|
+
import { existsSync } from "fs";
|
|
19
20
|
import { homedir } from "os";
|
|
20
|
-
import { join } from "path";
|
|
21
|
-
|
|
21
|
+
import { join, resolve } from "path";
|
|
22
|
+
import { homedir as pathsResolverHomedir } from "os";
|
|
23
|
+
import { join as pathsResolverJoin } from "path";
|
|
24
|
+
function pathsResolverAssertApp(app) {
|
|
22
25
|
if (typeof app !== "string" || app.length === 0) {
|
|
23
26
|
throw new TypeError("paths: app must be a non-empty string");
|
|
24
27
|
}
|
|
25
|
-
if (!
|
|
28
|
+
if (!PATHS_RESOLVER_APP_SLUG_RE.test(app)) {
|
|
26
29
|
throw new TypeError(`paths: invalid app slug "${app}" \u2014 expected lowercase kebab-case ([a-z0-9]+(-[a-z0-9]+)*)`);
|
|
27
30
|
}
|
|
28
31
|
}
|
|
29
|
-
function
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const value = envOf(options)[KIND_ENV[kind]];
|
|
34
|
-
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
35
|
-
}
|
|
36
|
-
function isMacOS(platform) {
|
|
37
|
-
return platform === "darwin";
|
|
32
|
+
function pathsResolverAssertKind(kind) {
|
|
33
|
+
if (!Object.keys(PATHS_RESOLVER_KIND_ENV).includes(kind)) {
|
|
34
|
+
throw new TypeError(`paths: invalid path kind "${kind}" \u2014 expected one of ${Object.keys(PATHS_RESOLVER_KIND_ENV).join(", ")}`);
|
|
35
|
+
}
|
|
38
36
|
}
|
|
39
|
-
function
|
|
40
|
-
|
|
41
|
-
|
|
37
|
+
function pathsResolverBaseDir(kind, options) {
|
|
38
|
+
pathsResolverAssertKind(kind);
|
|
39
|
+
const env = options.env ?? process.env;
|
|
40
|
+
const override = env[PATHS_RESOLVER_KIND_ENV[kind]];
|
|
41
|
+
if (typeof override === "string" && override.length > 0)
|
|
42
42
|
return override;
|
|
43
|
-
const home = options.home ??
|
|
43
|
+
const home = options.home ?? pathsResolverHomedir();
|
|
44
44
|
const platform = options.platform ?? process.platform;
|
|
45
|
-
if (
|
|
45
|
+
if (platform === "darwin") {
|
|
46
46
|
switch (kind) {
|
|
47
47
|
case "config":
|
|
48
48
|
case "data":
|
|
49
|
-
return
|
|
49
|
+
return pathsResolverJoin(home, "Library", "Application Support", "Hasna");
|
|
50
50
|
case "cache":
|
|
51
|
-
return
|
|
51
|
+
return pathsResolverJoin(home, "Library", "Caches", "Hasna");
|
|
52
52
|
case "state":
|
|
53
|
-
return
|
|
53
|
+
return pathsResolverJoin(home, "Library", "Logs", "Hasna");
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
switch (kind) {
|
|
57
57
|
case "config":
|
|
58
|
-
return
|
|
58
|
+
return pathsResolverJoin(home, ".config", "hasna");
|
|
59
59
|
case "data":
|
|
60
|
-
return
|
|
60
|
+
return pathsResolverJoin(home, ".local", "share", "hasna");
|
|
61
61
|
case "state":
|
|
62
|
-
return
|
|
62
|
+
return pathsResolverJoin(home, ".local", "state", "hasna");
|
|
63
63
|
case "cache":
|
|
64
|
-
return
|
|
64
|
+
return pathsResolverJoin(home, ".cache", "hasna");
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
|
-
function
|
|
68
|
-
|
|
69
|
-
const appSegment = options.internal === true ?
|
|
70
|
-
return
|
|
67
|
+
function pathsResolverResolve(kind, options) {
|
|
68
|
+
pathsResolverAssertApp(options.app);
|
|
69
|
+
const appSegment = options.internal === true ? pathsResolverJoin("internal", options.app) : options.app;
|
|
70
|
+
return pathsResolverJoin(pathsResolverBaseDir(kind, options), appSegment);
|
|
71
71
|
}
|
|
72
72
|
function dataDir(options) {
|
|
73
|
-
return
|
|
73
|
+
return pathsResolverResolve("data", options);
|
|
74
74
|
}
|
|
75
|
-
var KIND_ENV, APP_SLUG_RE;
|
|
76
|
-
var init_dist = __esm(() => {
|
|
77
|
-
KIND_ENV = {
|
|
78
|
-
config: "HASNA_CONFIG_HOME",
|
|
79
|
-
data: "HASNA_DATA_HOME",
|
|
80
|
-
state: "HASNA_STATE_HOME",
|
|
81
|
-
cache: "HASNA_CACHE_HOME"
|
|
82
|
-
};
|
|
83
|
-
APP_SLUG_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
// src/lib/app-home.ts
|
|
87
|
-
import { existsSync } from "fs";
|
|
88
|
-
import { homedir as homedir2 } from "os";
|
|
89
|
-
import { join as join2, resolve } from "path";
|
|
90
75
|
function getHomeDir(env = process.env) {
|
|
91
|
-
return env.HOME || env.USERPROFILE ||
|
|
76
|
+
return env.HOME || env.USERPROFILE || homedir();
|
|
92
77
|
}
|
|
93
78
|
function getResolverDataRoot(env = process.env) {
|
|
94
79
|
return dataDir({ app: "hooks", home: getHomeDir(env), env });
|
|
95
80
|
}
|
|
96
81
|
function getLegacyDataRoot(env = process.env) {
|
|
97
|
-
return
|
|
82
|
+
return join(getHomeDir(env), ".hasna", "hooks");
|
|
98
83
|
}
|
|
99
84
|
function adoptResolverDataRoot(resolved, env = process.env) {
|
|
100
85
|
const dataOverride = env.HASNA_DATA_HOME;
|
|
101
86
|
if (typeof dataOverride === "string" && dataOverride.trim().length > 0)
|
|
102
87
|
return true;
|
|
103
|
-
return existsSync(
|
|
88
|
+
return existsSync(join(resolved, STORE_MARKER));
|
|
104
89
|
}
|
|
105
90
|
function getExplicitDataDir(env = process.env) {
|
|
106
91
|
const dir = env.HASNA_HOOKS_DATA_DIR ?? env.HOOKS_DATA_DIR;
|
|
@@ -128,7 +113,7 @@ function getReportedDbPath(env = process.env) {
|
|
|
128
113
|
const explicit = getExplicitDbPath(env);
|
|
129
114
|
if (explicit)
|
|
130
115
|
return explicit;
|
|
131
|
-
return
|
|
116
|
+
return join(getEffectiveDataRoot(env), "hooks.db");
|
|
132
117
|
}
|
|
133
118
|
function getExplicitDbPath(env = process.env) {
|
|
134
119
|
const db = env.HASNA_HOOKS_DB_PATH ?? env.HOOKS_DB_PATH;
|
|
@@ -136,9 +121,15 @@ function getExplicitDbPath(env = process.env) {
|
|
|
136
121
|
return db.trim();
|
|
137
122
|
return;
|
|
138
123
|
}
|
|
139
|
-
var STORE_MARKER = "hooks.db";
|
|
124
|
+
var PATHS_RESOLVER_KIND_ENV, PATHS_RESOLVER_APP_SLUG_RE, STORE_MARKER = "hooks.db";
|
|
140
125
|
var init_app_home = __esm(() => {
|
|
141
|
-
|
|
126
|
+
PATHS_RESOLVER_KIND_ENV = {
|
|
127
|
+
config: "HASNA_CONFIG_HOME",
|
|
128
|
+
data: "HASNA_DATA_HOME",
|
|
129
|
+
state: "HASNA_STATE_HOME",
|
|
130
|
+
cache: "HASNA_CACHE_HOME"
|
|
131
|
+
};
|
|
132
|
+
PATHS_RESOLVER_APP_SLUG_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
142
133
|
});
|
|
143
134
|
|
|
144
135
|
// src/db/schema.ts
|
|
@@ -336,8 +327,8 @@ var init_migrations = __esm(() => {
|
|
|
336
327
|
|
|
337
328
|
// src/db/legacy-import.ts
|
|
338
329
|
import { existsSync as existsSync2, readdirSync, readFileSync } from "fs";
|
|
339
|
-
import { join as
|
|
340
|
-
import { homedir as
|
|
330
|
+
import { join as join2 } from "path";
|
|
331
|
+
import { homedir as homedir2 } from "os";
|
|
341
332
|
function ensureMetaTable(db) {
|
|
342
333
|
db.exec(`
|
|
343
334
|
CREATE TABLE IF NOT EXISTS _meta (
|
|
@@ -411,25 +402,25 @@ function importErrorsLog(db, filePath) {
|
|
|
411
402
|
} catch {}
|
|
412
403
|
return count;
|
|
413
404
|
}
|
|
414
|
-
function runLegacyImport(db, homeDir =
|
|
405
|
+
function runLegacyImport(db, homeDir = homedir2()) {
|
|
415
406
|
try {
|
|
416
407
|
if (isAlreadyDone(db))
|
|
417
408
|
return;
|
|
418
409
|
let total = 0;
|
|
419
|
-
const claudeProjectsDir =
|
|
410
|
+
const claudeProjectsDir = join2(homeDir, ".claude", "projects");
|
|
420
411
|
if (existsSync2(claudeProjectsDir)) {
|
|
421
412
|
try {
|
|
422
413
|
const projectDirs = readdirSync(claudeProjectsDir);
|
|
423
414
|
for (const dir of projectDirs) {
|
|
424
|
-
const projectDir =
|
|
415
|
+
const projectDir = join2(claudeProjectsDir, dir);
|
|
425
416
|
try {
|
|
426
417
|
const files = readdirSync(projectDir);
|
|
427
418
|
for (const file of files) {
|
|
428
419
|
if (file.match(/^session-log-\d{4}-\d{2}-\d{2}\.jsonl$/)) {
|
|
429
|
-
total += importJsonlFile(db,
|
|
420
|
+
total += importJsonlFile(db, join2(projectDir, file));
|
|
430
421
|
}
|
|
431
422
|
if (file === "errors.log") {
|
|
432
|
-
total += importErrorsLog(db,
|
|
423
|
+
total += importErrorsLog(db, join2(projectDir, file));
|
|
433
424
|
}
|
|
434
425
|
}
|
|
435
426
|
} catch {}
|
|
@@ -466,10 +457,10 @@ function runRetention(db, days) {
|
|
|
466
457
|
// src/db/index.ts
|
|
467
458
|
import { Database } from "bun:sqlite";
|
|
468
459
|
import { existsSync as existsSync3, mkdirSync, cpSync } from "fs";
|
|
469
|
-
import { join as
|
|
460
|
+
import { join as join3 } from "path";
|
|
470
461
|
function resolveDataDir() {
|
|
471
462
|
const effective = getEffectiveDataRoot();
|
|
472
|
-
const oldDir =
|
|
463
|
+
const oldDir = join3(getHomeDir(), ".hooks");
|
|
473
464
|
if (!existsSync3(effective) && existsSync3(oldDir)) {
|
|
474
465
|
mkdirSync(effective, { recursive: true });
|
|
475
466
|
cpSync(oldDir, effective, { recursive: true });
|
|
@@ -481,7 +472,7 @@ function getDbPath() {
|
|
|
481
472
|
if (explicitDb)
|
|
482
473
|
return explicitDb;
|
|
483
474
|
const dataDir2 = resolveDataDir();
|
|
484
|
-
return
|
|
475
|
+
return join3(dataDir2, "hooks.db");
|
|
485
476
|
}
|
|
486
477
|
function ensureDir(dbPath) {
|
|
487
478
|
const dir = dbPath.substring(0, dbPath.lastIndexOf("/"));
|
|
@@ -568,8 +559,8 @@ var init_redact = __esm(() => {
|
|
|
568
559
|
/AKIA[0-9A-Z]{16}/g,
|
|
569
560
|
/ASIA[0-9A-Z]{16}/g,
|
|
570
561
|
/eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}/g,
|
|
571
|
-
/-----BEGIN [A-Z0-9 ]*
|
|
572
|
-
/-----BEGIN OPENSSH
|
|
562
|
+
/-----BEGIN [A-Z0-9 ]*PRIVAT[E] KEY-----/g,
|
|
563
|
+
/-----BEGIN OPENSSH PRIVAT[E] KEY-----/g,
|
|
573
564
|
/\bBearer\s+[A-Za-z0-9._~+/=-]{6,}/g,
|
|
574
565
|
/\b[a-z][a-z0-9+.-]*:\/\/[^/\s:@]+:[^/\s@]+@/gi,
|
|
575
566
|
/\b(?:password|passwd|pwd|token|api[_-]?key|secret|access[_-]?key|client[_-]?secret|authorization|auth|credential|database_url|db_url|connection_string|dsn)\s*[:=]\s*(?:"[^"]*"|'[^']*'|[^\s,;"']{6,})/gi
|
|
@@ -43,7 +43,7 @@ export HOOKS_FLEET_TIMEOUT_MS=500 # configs CLI timeout (default 5
|
|
|
43
43
|
|
|
44
44
|
## Requirements
|
|
45
45
|
|
|
46
|
-
- `configs` CLI (@hasna/configs) — optional; without it the hook falls back to cross-artifact consistency checking
|
|
46
|
+
- `configs` CLI (@hasna/instructions — the package that ships the `configs` bin) — optional; without it the hook falls back to cross-artifact consistency checking
|
|
47
47
|
|
|
48
48
|
## Event
|
|
49
49
|
|