grepmax 0.16.1 → 0.16.3

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.
@@ -48,6 +48,8 @@ exports.getProject = getProject;
48
48
  exports.removeProject = removeProject;
49
49
  exports.getParentProject = getParentProject;
50
50
  exports.getChildProjects = getChildProjects;
51
+ exports.resolveRootOrExit = resolveRootOrExit;
52
+ exports.resolveProjectRoot = resolveProjectRoot;
51
53
  const fs = __importStar(require("node:fs"));
52
54
  const path = __importStar(require("node:path"));
53
55
  const proper_lockfile_1 = __importDefault(require("proper-lockfile"));
@@ -126,3 +128,44 @@ function getChildProjects(root) {
126
128
  const prefix = root.endsWith("/") ? root : `${root}/`;
127
129
  return loadRegistry().filter((e) => e.root !== root && e.root.startsWith(prefix));
128
130
  }
131
+ /**
132
+ * Resolve a `--root` argument with cwd fallback, printing the helper's
133
+ * error message and setting process.exitCode = 1 on failure. Returns
134
+ * null when the caller should bail out. Used at command entry points.
135
+ */
136
+ function resolveRootOrExit(arg) {
137
+ if (!arg)
138
+ return process.cwd();
139
+ try {
140
+ return resolveProjectRoot(arg);
141
+ }
142
+ catch (err) {
143
+ console.error(err instanceof Error ? err.message : String(err));
144
+ process.exitCode = 1;
145
+ return null;
146
+ }
147
+ }
148
+ /**
149
+ * Resolve a `--root` argument that may be either a path or a registered
150
+ * project name. Throws on no-match or duplicate-name so callers can
151
+ * report a uniform error.
152
+ */
153
+ function resolveProjectRoot(arg) {
154
+ if (arg.includes("/") || arg.includes("\\"))
155
+ return path.resolve(arg);
156
+ const resolved = path.resolve(arg);
157
+ if (fs.existsSync(resolved))
158
+ return resolved;
159
+ const matches = loadRegistry().filter((p) => p.name === arg);
160
+ if (matches.length === 1)
161
+ return matches[0].root;
162
+ if (matches.length === 0) {
163
+ const all = loadRegistry();
164
+ const list = all.length > 0
165
+ ? all.map((p) => ` ${p.name.padEnd(24)} ${p.root}`).join("\n")
166
+ : " (none registered)";
167
+ throw new Error(`No registered project named "${arg}".\nAvailable:\n${list}`);
168
+ }
169
+ const paths = matches.map((p) => ` ${p.root}`).join("\n");
170
+ throw new Error(`Multiple registered projects named "${arg}":\n${paths}\nPass an absolute path to disambiguate.`);
171
+ }
@@ -0,0 +1,104 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.resolveScope = resolveScope;
37
+ exports.buildScopeWhere = buildScopeWhere;
38
+ const path = __importStar(require("node:path"));
39
+ const filter_builder_1 = require("./filter-builder");
40
+ function toArray(value) {
41
+ if (value === undefined)
42
+ return [];
43
+ const arr = Array.isArray(value) ? value : [value];
44
+ // Support comma-separated values within each occurrence so agents can pass
45
+ // either `--in a --in b` or `--in a,b` interchangeably.
46
+ return arr
47
+ .flatMap((v) => v.split(","))
48
+ .map((v) => v.trim())
49
+ .filter(Boolean);
50
+ }
51
+ function joinSubpath(projectRoot, sub) {
52
+ const rootWithSlash = projectRoot.endsWith("/") ? projectRoot : `${projectRoot}/`;
53
+ if (path.isAbsolute(sub))
54
+ return sub.endsWith("/") ? sub : `${sub}/`;
55
+ if (sub.startsWith(rootWithSlash))
56
+ return sub.endsWith("/") ? sub : `${sub}/`;
57
+ const joined = path.join(rootWithSlash, sub);
58
+ return joined.endsWith("/") ? joined : `${joined}/`;
59
+ }
60
+ function resolveScope(opts) {
61
+ const { projectRoot } = opts;
62
+ const ins = toArray(opts.in);
63
+ const excludes = toArray(opts.exclude);
64
+ const projectPrefix = projectRoot.endsWith("/")
65
+ ? projectRoot
66
+ : `${projectRoot}/`;
67
+ const inPrefixesAll = ins.map((v) => joinSubpath(projectRoot, v));
68
+ const excludePrefixes = excludes.map((v) => joinSubpath(projectRoot, v));
69
+ // Collapse a single --in into pathPrefix to keep WHERE clauses simple.
70
+ if (inPrefixesAll.length === 1) {
71
+ return {
72
+ pathPrefix: inPrefixesAll[0],
73
+ inPrefixes: [],
74
+ excludePrefixes,
75
+ };
76
+ }
77
+ return {
78
+ pathPrefix: projectPrefix,
79
+ inPrefixes: inPrefixesAll,
80
+ excludePrefixes,
81
+ };
82
+ }
83
+ /**
84
+ * Compose a SQL WHERE clause that AND-applies the resolved scope to an
85
+ * existing condition. Used by symbol commands that build their own table
86
+ * queries (peek/extract/similar/related) instead of going through
87
+ * Searcher.buildWhereClause or GraphBuilder.scopeWhere.
88
+ */
89
+ function buildScopeWhere(scope, condition) {
90
+ const parts = [];
91
+ if (condition)
92
+ parts.push(condition);
93
+ parts.push(`path LIKE '${(0, filter_builder_1.escapeSqlString)(scope.pathPrefix)}%'`);
94
+ for (const ex of scope.excludePrefixes) {
95
+ parts.push(`path NOT LIKE '${(0, filter_builder_1.escapeSqlString)(ex)}%'`);
96
+ }
97
+ if (scope.inPrefixes.length > 0) {
98
+ const ors = scope.inPrefixes
99
+ .map((p) => `path LIKE '${(0, filter_builder_1.escapeSqlString)(p)}%'`)
100
+ .join(" OR ");
101
+ parts.push(`(${ors})`);
102
+ }
103
+ return parts.join(" AND ");
104
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "grepmax",
3
- "version": "0.16.1",
3
+ "version": "0.16.3",
4
4
  "author": "Robert Owens <78518764+reowens@users.noreply.github.com>",
5
5
  "homepage": "https://github.com/reowens/grepmax",
6
6
  "bugs": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "grepmax",
3
- "version": "0.16.1",
3
+ "version": "0.16.3",
4
4
  "description": "Semantic code search for Claude Code. Automatically indexes your project and provides intelligent search capabilities.",
5
5
  "author": {
6
6
  "name": "Robert Owens",
@@ -125,9 +125,18 @@ gmax related src/lib/index/syncer.ts # dependencies + dependents
125
125
  gmax related src/lib/index/syncer.ts --root ~/project
126
126
  ```
127
127
 
128
- ### Recent changes — `gmax recent`
128
+ ### Commit history — `gmax log <path-or-symbol>`
129
129
  ```
130
- gmax recent # recently modified files
130
+ gmax log src/lib/auth.ts # commits touching this file
131
+ gmax log src/lib/ # commits touching this directory
132
+ gmax log handleAuth # commits across all files defining the symbol
133
+ gmax log handleAuth --in src/ # restrict symbol resolution to a sub-path
134
+ gmax log src/lib/auth.ts --limit 5 # last 5 commits
135
+ gmax log src/lib/auth.ts --from main # commits since main (range main..HEAD)
136
+ gmax log src/lib/auth.ts --since "2 weeks ago"
137
+ gmax log src/lib/auth.ts --author Robert
138
+ gmax log src/lib/auth.ts --no-follow # disable rename tracking (default: on for files)
139
+ gmax log src/lib/auth.ts --agent # TSV: hash\tisoDate\tauthor\tsubject\tfilesChanged\tins\tdel\ttouchedFiles
131
140
  ```
132
141
 
133
142
  ### Symbols — `gmax symbols`
@@ -137,15 +146,6 @@ gmax symbols auth -p src/ --root ~/proj # filter by name, path, project
137
146
  gmax symbols --agent # compact: symbol\tpath:line\tcount
138
147
  ```
139
148
 
140
- ### Diff — `gmax diff [ref]`
141
- ```
142
- gmax diff # uncommitted changes
143
- gmax diff HEAD~5 # last 5 commits
144
- gmax diff main # branch changes vs main
145
- gmax diff main --query "auth changes" # semantic search within changed files
146
- gmax diff --agent # compact output
147
- ```
148
-
149
149
  ### Test — `gmax test <symbol|file>`
150
150
  ```
151
151
  gmax test handleAuth # tests calling handleAuth