claude-access-for-all 0.1.0 → 0.1.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/README.md CHANGED
@@ -65,7 +65,7 @@ claude-access reminder --renewal 2026-12-01 --days-before 3 > renewal.ics
65
65
  open renewal.ics
66
66
  ```
67
67
 
68
- To install directly from GitHub, use `npm install -g github:AMark-CS/claude-access-for-all`. Use `claude-access help` to see the complete command list. `inspect` opens the local graphical browser inspector in your default browser. To check a separate browser profile, open its local file in that profile instead; see the [privacy inspector guide](docs/privacy-inspector.md).
68
+ To install directly from GitHub, use `npm install -g github:AMark-CS/claude-access-for-all`. Use `claude-access help` to see the complete command list. Diagnostics display a readable summary by default; use `claude-access doctor --json` or `claude-access audit --json` for machine-readable output. `inspect` opens the local graphical browser inspector in your default browser. To check a separate browser profile, open its local file in that profile instead; see the [privacy inspector guide](docs/privacy-inspector.md).
69
69
 
70
70
  For the calendar reminder, replace the example date with the next billing date shown by your billing provider. The file contains one all-day review event with an alert; import it into Apple Calendar and check your notification settings. It neither cancels nor renews anything, and must be regenerated when the billing date changes.
71
71
 
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { spawnSync } from 'node:child_process';
3
+ import { readFileSync } from 'node:fs';
3
4
  import { createInterface } from 'node:readline/promises';
4
5
  import { fileURLToPath } from 'node:url';
5
6
  import { dirname, join } from 'node:path';
@@ -10,8 +11,8 @@ const help = `Claude Access for All
10
11
  Usage: claude-access [command] [options]
11
12
 
12
13
  menu Open the interactive menu (default)
13
- doctor Check local installation and configuration presence
14
- audit Inspect CLI environment signals locally
14
+ doctor [--json] Check local installation and configuration presence
15
+ audit [--json] Inspect CLI environment signals locally
15
16
  cli [options] [-- ...] Launch Claude Code with scoped locale settings
16
17
  app [options] Launch Claude Desktop with scoped locale settings
17
18
  web [options] Launch Claude in a separate browser profile
@@ -56,7 +57,7 @@ function dispatch(command, args = []) {
56
57
  if (process.platform !== 'darwin') { console.error('The guide launcher requires macOS.'); return 1; }
57
58
  return run('/usr/bin/open', ['https://github.com/AMark-CS/claude-access-for-all/blob/main/docs/privacy-inspector.md']);
58
59
  case 'help': case '--help': case '-h': console.log(help); return 0;
59
- case 'version': case '--version': case '-v': console.log('0.1.0'); return 0;
60
+ case 'version': case '--version': case '-v': console.log(JSON.parse(readFileSync(join(root, 'package.json'), 'utf8')).version); return 0;
60
61
  default: console.error(`Unknown command: ${command}\n\n${help}`); return 2;
61
62
  }
62
63
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-access-for-all",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "A macOS guide and local privacy toolkit for Claude Code, Desktop, and web",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/tools/access.py CHANGED
@@ -9,6 +9,8 @@ import shutil
9
9
  import sys
10
10
  import uuid
11
11
 
12
+ from report import render_doctor
13
+
12
14
  VARIABLES = (
13
15
  'ANTHROPIC_API_KEY', 'ANTHROPIC_AUTH_TOKEN', 'ANTHROPIC_BASE_URL',
14
16
  'CLAUDE_CODE_USE_BEDROCK', 'CLAUDE_CODE_USE_VERTEX', 'CLAUDE_CODE_USE_FOUNDRY',
@@ -92,13 +94,15 @@ def reminder(renewal, lead, today=None):
92
94
  def main():
93
95
  parser = argparse.ArgumentParser(description=__doc__)
94
96
  commands = parser.add_subparsers(dest='command', required=True)
95
- commands.add_parser('doctor', help='Print an offline JSON report; values stay private.')
97
+ diagnostic = commands.add_parser('doctor', help='Print an offline environment report.')
98
+ diagnostic.add_argument('--json', action='store_true', help='Output machine-readable JSON.')
96
99
  calendar = commands.add_parser('reminder', help='Print a one-time .ics calendar to stdout.')
97
100
  calendar.add_argument('--renewal', type=parse_date, required=True)
98
101
  calendar.add_argument('--days-before', type=days_before, default=3)
99
102
  args = parser.parse_args()
100
103
  if args.command == 'doctor':
101
- print(json.dumps(doctor(), indent=2))
104
+ result = doctor()
105
+ print(json.dumps(result, indent=2) if args.json else render_doctor(result))
102
106
  else:
103
107
  try:
104
108
  content = reminder(args.renewal, args.days_before)
package/tools/privacy.py CHANGED
@@ -12,6 +12,8 @@ import sys
12
12
  import tempfile
13
13
  import time
14
14
 
15
+ from report import render_audit
16
+
15
17
  ROUTING = ('ANTHROPIC_BASE_URL', 'HTTP_PROXY', 'HTTPS_PROXY', 'ALL_PROXY', 'NO_PROXY',
16
18
  'http_proxy', 'https_proxy', 'all_proxy', 'no_proxy')
17
19
  AUTH = ('ANTHROPIC_API_KEY', 'ANTHROPIC_AUTH_TOKEN')
@@ -65,7 +67,8 @@ def browser_command(browser, profile, language, timezone, locale):
65
67
  def main():
66
68
  parser = argparse.ArgumentParser(description=__doc__)
67
69
  sub = parser.add_subparsers(dest='command', required=True)
68
- sub.add_parser('audit', help='Show local signal presence without exposing secret values.')
70
+ diagnostic = sub.add_parser('audit', help='Show local signals without exposing secret values.')
71
+ diagnostic.add_argument('--json', action='store_true', help='Output machine-readable JSON.')
69
72
  for name in ('cli', 'app', 'web'):
70
73
  command = sub.add_parser(name, help='Launch ' + name + ' with process-scoped settings.')
71
74
  command.add_argument('--timezone', type=validate_timezone, default='UTC')
@@ -80,7 +83,8 @@ def main():
80
83
  command.add_argument('--language', default='en-US', type=validate_locale)
81
84
  args = parser.parse_args()
82
85
  if args.command == 'audit':
83
- print(json.dumps(audit(), indent=2))
86
+ result = audit()
87
+ print(json.dumps(result, indent=2) if args.json else render_audit(result))
84
88
  return
85
89
  if sys.platform != 'darwin':
86
90
  parser.error('Launch commands require macOS.')
@@ -0,0 +1,85 @@
1
+ """Readable, privacy-conscious CLI reports. JSON remains available via --json."""
2
+ import os
3
+ import sys
4
+
5
+
6
+ def style(text, code):
7
+ if sys.stdout.isatty() and not os.environ.get('NO_COLOR') and os.environ.get('TERM') != 'dumb':
8
+ return f'\033[{code}m{text}\033[0m'
9
+ return text
10
+
11
+
12
+ def title(name, subtitle):
13
+ return [
14
+ '',
15
+ ' ' + style('CLAUDE ACCESS', '1;36') + style(' / ' + name.upper(), '1'),
16
+ ' ' + style(subtitle, '2'),
17
+ '',
18
+ ]
19
+
20
+
21
+ def row(label, value):
22
+ return f' {label:<20} {value}'
23
+
24
+
25
+ def section(name):
26
+ return '\n ' + style(name, '1')
27
+
28
+
29
+ def group(label, names, values):
30
+ active = [name for name in names if values.get(name)]
31
+ if active:
32
+ return row(label, style('Set', '33') + ' ' + ', '.join(active))
33
+ return row(label, style('Not set', '2'))
34
+
35
+
36
+ def render_doctor(report):
37
+ env = report['environment_set']
38
+ system = report['system']
39
+ if system == 'Darwin':
40
+ system = 'macOS ' + (report['macos_version'] or '(version unavailable)')
41
+ lines = title('Environment check', 'Local diagnostic · no network requests')
42
+ lines += [
43
+ row('System', system + ' · ' + report['architecture']),
44
+ row('Claude Code', style('Found on PATH', '32') if report['claude_on_path'] else style('Not found on PATH', '33')),
45
+ section('Environment variables'),
46
+ group('Authentication', ('ANTHROPIC_API_KEY', 'ANTHROPIC_AUTH_TOKEN'), env),
47
+ group('Service endpoint', ('ANTHROPIC_BASE_URL',), env),
48
+ group('Cloud providers', ('CLAUDE_CODE_USE_BEDROCK', 'CLAUDE_CODE_USE_VERTEX', 'CLAUDE_CODE_USE_FOUNDRY'), env),
49
+ group('Proxy variables', ('HTTP_PROXY', 'HTTPS_PROXY', 'ALL_PROXY', 'NO_PROXY', 'http_proxy', 'https_proxy', 'all_proxy', 'no_proxy'), env),
50
+ group('TLS settings', ('NODE_EXTRA_CA_CERTS', 'NODE_TLS_REJECT_UNAUTHORIZED'), env),
51
+ '',
52
+ ]
53
+ if report['warnings']:
54
+ lines.append(' ' + style('Things to review', '1;33'))
55
+ lines.extend(' • ' + warning for warning in report['warnings'])
56
+ else:
57
+ lines.append(' ' + style('No local configuration warnings.', '32'))
58
+ lines += ['', ' Values are never shown. System proxies, app settings, credentials,',
59
+ ' billing, account eligibility and network access were not checked.', '']
60
+ return '\n'.join(lines)
61
+
62
+
63
+ def render_audit(report):
64
+ names = list(dict.fromkeys(name for name in report['process_timezone_names'] if name))
65
+ tz = ' / '.join(names) if names else 'Unavailable'
66
+ lines = title('CLI signal audit', 'Current terminal process · offline')
67
+ lines += [
68
+ row('System', report['system']),
69
+ row('Claude Code', style('Found on PATH', '32') if report['claude_on_path'] else style('Not found on PATH', '33')),
70
+ section('Locale & time'),
71
+ row('Timezone names', tz),
72
+ row('TZ override', style('Set', '33') if report['timezone_override_set'] else style('Not set', '2')),
73
+ group('Locale variables', ('LANG', 'LC_ALL', 'LC_TIME'), report['locale_overrides_set']),
74
+ section('Connection & authentication'),
75
+ group('Endpoint & proxies', report['routing_overrides_set'].keys(), report['routing_overrides_set']),
76
+ group('Credentials', report['credential_overrides_set'].keys(), report['credential_overrides_set']),
77
+ '',
78
+ ' Values are never shown. HKT and other abbreviations are timezone names,',
79
+ ' not proof of an exact location. Browser, Desktop, network, IP and',
80
+ ' account status were not checked.',
81
+ '',
82
+ ' Next: run ' + style('claude-access inspect', '1') + ' to inspect your default browser.',
83
+ '',
84
+ ]
85
+ return '\n'.join(lines)