trackqa 0.1.2 → 0.1.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.
package/README.md CHANGED
@@ -7,17 +7,19 @@ credentials. The connector does not install or authenticate the AI client itself
7
7
 
8
8
  ## Package status and installation
9
9
 
10
- **trackqa@0.1.1** was published and independently verified on November 5, 2026.
11
- The local **v0.1.2 candidate** fixes Codex launches from the Windows user home:
12
- the standard profile and application-data directories are no longer incorrectly
13
- rejected as workspace-local configuration. Workspace and package boundaries
14
- remain enforced. **v0.1.2 is not published; publication requires separate approval.**
15
- The published v0.1.0 and v0.1.1 artifacts are retained unchanged.
10
+ **trackqa@0.1.2** was published and independently verified on November 5, 2026.
11
+ It corrected default Codex profile and application-data validation, but separate
12
+ executable checks still reject user-installed clients when launched from the home.
13
+ The local **v0.1.3 candidate** corrects those executable checks and Gemini's default
14
+ home validation, and recognizes Gemini's bundled npm entry alongside its older
15
+ layout. Existing installation allowlists, workspace boundaries and compatibility
16
+ checks remain enforced. **v0.1.3 is not published.** Existing published artifacts
17
+ are retained unchanged; experimental client validation limits are unchanged.
16
18
 
17
19
  To verify an approved local tarball in a disposable directory:
18
20
 
19
21
  ```powershell
20
- npm install --ignore-scripts --no-audit --no-fund <absolute-path-to-trackqa-0.1.2.tgz>
22
+ npm install --ignore-scripts --no-audit --no-fund <absolute-path-to-trackqa-0.1.3.tgz>
21
23
  npm exec --offline -- trackqa --help
22
24
  ```
23
25
 
@@ -31,10 +33,9 @@ npx trackqa status --client codex
31
33
  npx trackqa disconnect --client codex --project <project-UUID>
32
34
  ```
33
35
 
34
- Until v0.1.2 is published, the bare registry command still resolves to v0.1.1.
35
- With v0.1.1, launch from your coding project folder rather than the user home to
36
- avoid `configuration_location_untrusted`. Validate the v0.1.2 candidate through
37
- a local tarball installation and `npm exec --offline -- trackqa ...`.
36
+ The published version is v0.1.2. Until v0.1.3 is published, run from your coding
37
+ project folder instead of the user home to avoid these location rejections.
38
+ Validate v0.1.3 through a disposable local tarball installation.
38
39
  Bare `connect` prompts for a client; `--client codex` is optional. No client is
39
40
  selected by default.
40
41
 
@@ -16,7 +16,7 @@ import { adapterLabel } from "./clients/adapter.js";
16
16
  import { ConnectorError, display, parseArgs, requireValue } from "./core.js";
17
17
  import { Store } from "./state.js";
18
18
  import { connect, disconnect, status } from "./workflow.js";
19
- export const help = `TrackQA Connect 0.1.2 - Windows, Owner-operated MVP release candidate
19
+ export const help = `TrackQA Connect 0.1.3 - Windows, Owner-operated MVP release candidate
20
20
  Usage after installing the approved package or local tarball:
21
21
  trackqa connect --client codex
22
22
  trackqa status --client codex
@@ -69,7 +69,7 @@ export async function locations(env = process.env, client = 'codex') {
69
69
  const geminiHome = env.GEMINI_CLI_HOME ?? os.homedir();
70
70
  const geminiCanonical = await realpath(geminiHome).catch(() => path.resolve(geminiHome));
71
71
  if (client === 'gemini') {
72
- requireValue(path.isAbsolute(geminiHome) && !under(geminiCanonical, repo) && !under(geminiCanonical, process.cwd()), 'configuration_location_untrusted');
72
+ requireValue(path.isAbsolute(geminiHome) && isSafeConfigurationRoot(geminiCanonical, cwd, repo, home, home), 'configuration_location_untrusted');
73
73
  const config = path.join(geminiCanonical, '.gemini');
74
74
  const resolved = await realpath(config).catch(() => config);
75
75
  requireValue(resolved.toLowerCase() === config.toLowerCase(), 'configuration_location_untrusted');
@@ -233,7 +233,7 @@ export async function main(args = process.argv.slice(2)) {
233
233
  if (code === 'configuration_write_failed' || code === 'configuration_write_uncertain')
234
234
  process.stdout.write('Settings replacement failed or its outcome is uncertain. Do not retry automatically. Inspect settings.json and any .trackqa-settings-recovery-*.bak in the selected Gemini home; preserve recovery metadata and compare/merge before restoring anything.\n');
235
235
  if (code === 'client_not_found')
236
- process.stdout.write('Selected client was not found in supported installation locations. No installation was attempted. For Gemini supply the existing @google/gemini-cli bin with --gemini-path; agy.exe is not Gemini CLI.\n');
236
+ process.stdout.write('Selected AI client was not found in supported installation locations. Install it independently or use the matching --codex-path, --gemini-path, --claude-path or --vscode-path option for an existing supported installation. No installation or login was attempted.\n');
237
237
  if (code === 'client_not_found' && args.includes('claude'))
238
238
  process.stdout.write('Claude Code requires an independently installed native Windows claude.exe; npm shims and Desktop are not selected. Use --claude-path for an existing supported native installation. No login or installation was attempted.\n');
239
239
  if (code === 'gemini_compatibility_unverified')
@@ -12,7 +12,9 @@ export function trustedClaudeLocation(file, home = os.homedir(), platform = proc
12
12
  if (!paths.isAbsolute(file) || paths.basename(file).toLowerCase() !== 'claude.exe' || platform !== 'win32')
13
13
  return false;
14
14
  const within = (root) => paths.resolve(file).toLowerCase().startsWith(paths.resolve(root).toLowerCase() + paths.sep);
15
- if (within(cwd) || paths.resolve(file).toLowerCase() === paths.resolve(cwd).toLowerCase())
15
+ const workspace = paths.resolve(cwd).toLowerCase(), relative = paths.relative(workspace, paths.resolve(file).toLowerCase());
16
+ const inWorkspace = relative === '' || (relative !== '..' && !relative.startsWith('..' + paths.sep) && !paths.isAbsolute(relative));
17
+ if (inWorkspace && workspace !== paths.resolve(home).toLowerCase())
16
18
  return false;
17
19
  const programFiles = process.env.ProgramFiles ?? 'C:\\Program Files';
18
20
  return [paths.join(home, '.local', 'bin'), paths.join(home, '.local', 'share', 'claude', 'versions'),
@@ -63,7 +63,7 @@ export async function verifyCodex(executable, codexHome, setup, token, signal, s
63
63
  child.stdin.write(JSON.stringify({ id, method, params }) + '\n');
64
64
  });
65
65
  try {
66
- await rpc('initialize', { clientInfo: { name: 'trackqa_connect', version: '0.1.2' } });
66
+ await rpc('initialize', { clientInfo: { name: 'trackqa_connect', version: '0.1.3' } });
67
67
  child.stdin.write(JSON.stringify({ method: 'initialized', params: {} }) + '\n');
68
68
  const config = await rpc('config/read');
69
69
  const servers = config?.config?.mcp_servers;
@@ -9,7 +9,9 @@ export function trustedLocation(file, home = os.homedir(), platform = process.pl
9
9
  const paths = platform === 'win32' ? path.win32 : path.posix;
10
10
  const normalized = paths.resolve(file).toLowerCase();
11
11
  const within = (root) => normalized.startsWith(paths.resolve(root).toLowerCase() + paths.sep);
12
- if (!paths.isAbsolute(file) || within(cwd) || normalized === paths.resolve(cwd).toLowerCase())
12
+ const workspace = paths.resolve(cwd).toLowerCase(), relative = paths.relative(workspace, normalized);
13
+ const inWorkspace = relative === '' || (relative !== '..' && !relative.startsWith('..' + paths.sep) && !paths.isAbsolute(relative));
14
+ if (!paths.isAbsolute(file) || (inWorkspace && workspace !== paths.resolve(home).toLowerCase()))
13
15
  return false;
14
16
  if (platform === 'win32') {
15
17
  if (paths.basename(file).toLowerCase() !== 'codex.exe')
@@ -16,7 +16,9 @@ export function trustedGeminiLocation(file, home = os.homedir(), platform = proc
16
16
  return false;
17
17
  const normalized = paths.resolve(file).toLowerCase();
18
18
  const inside = (root) => normalized.startsWith(paths.resolve(root).toLowerCase() + paths.sep);
19
- if (inside(cwd) || normalized === paths.resolve(cwd).toLowerCase())
19
+ const workspace = paths.resolve(cwd).toLowerCase(), relative = paths.relative(workspace, normalized);
20
+ const inWorkspace = relative === '' || (relative !== '..' && !relative.startsWith('..' + paths.sep) && !paths.isAbsolute(relative));
21
+ if (inWorkspace && workspace !== paths.resolve(home).toLowerCase())
20
22
  return false;
21
23
  const roots = platform === 'win32' ? [paths.join(home, 'AppData', 'Roaming', 'npm', 'node_modules', '@google', 'gemini-cli'),
22
24
  paths.join(process.env.ProgramFiles ?? 'C:\\Program Files', 'nodejs', 'node_modules', '@google', 'gemini-cli')]
@@ -187,7 +189,8 @@ export async function probeGemini(exe, run = capture) {
187
189
  }
188
190
  export async function detectGemini(explicit, source = process.env, run = capture, inspect = checkGeminiInstallation) {
189
191
  const prefixes = [...new Set([...(source.PATH ?? '').split(path.delimiter), source.APPDATA ? path.join(source.APPDATA, 'npm') : '', path.join(source.ProgramFiles ?? 'C:\\Program Files', 'nodejs')])].filter(folder => path.isAbsolute(folder));
190
- const candidates = explicit ? [explicit] : prefixes.map(folder => path.join(folder, 'node_modules', '@google', 'gemini-cli', 'dist', 'index.js'));
192
+ const candidates = explicit ? [explicit] : prefixes.flatMap(folder => ['dist/index.js', 'bundle/gemini.js']
193
+ .map(bin => path.join(folder, 'node_modules', '@google', 'gemini-cli', bin)));
191
194
  let incompatible = false;
192
195
  for (const file of candidates) {
193
196
  let exe;
@@ -10,7 +10,9 @@ export function trustedVSCodeLocation(file, home = os.homedir(), platform = proc
10
10
  if (platform !== 'win32')
11
11
  return false;
12
12
  const paths = path.win32, resolved = paths.resolve(file).toLowerCase();
13
- if (!paths.isAbsolute(file) || paths.basename(file).toLowerCase() !== 'code.exe' || resolved.startsWith(paths.resolve(cwd).toLowerCase() + paths.sep))
13
+ const workspace = paths.resolve(cwd).toLowerCase(), relative = paths.relative(workspace, resolved);
14
+ const inWorkspace = relative === '' || (relative !== '..' && !relative.startsWith('..' + paths.sep) && !paths.isAbsolute(relative));
15
+ if (!paths.isAbsolute(file) || paths.basename(file).toLowerCase() !== 'code.exe' || (inWorkspace && workspace !== paths.resolve(home).toLowerCase()))
14
16
  return false;
15
17
  return [paths.join(home, 'AppData', 'Local', 'Programs', 'Microsoft VS Code', 'Code.exe'),
16
18
  paths.join(process.env.ProgramFiles ?? 'C:\\Program Files', 'Microsoft VS Code', 'Code.exe')].some(candidate => paths.resolve(candidate).toLowerCase() === resolved);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "trackqa",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Owner-operated TrackQA MCP connector for Windows",
5
5
  "type": "module",
6
6
  "bin": { "trackqa": "dist/tools/trackqa-connect/src/cli.js" },