Add global and local profile scopes#35
Conversation
Pull the command-registration logic out of initiateCMD into a standalone buildProgram(defaultEnv) that returns a configured Command without parsing argv. The runtime CLI keeps the same behaviour while the new function becomes the single source of truth for the man-page generator. Guard the auto-run with an import.meta.url check so importing this module from a build tool no longer triggers program.parse().
Add a build-time roff generator at src/lib/generate-man.ts that walks buildProgram() and emits a single tagoio.1 page. Wire npm run man into the build chain plus prepublishOnly, ship the file via package.json files and man fields, gitignore the artifact, and document the install path (man tagoio plus fish_update_completions for fish users) in the README. A vitest snapshot test acts as the drift gate so CI fails when a flag or command changes without a matching snapshot regeneration; a companion mandoc/groff integration test catches roff syntax errors. The interactive prompt-driven flows (start-config, backup restore, export-setup) are excluded from the coverage threshold since they are covered by manual smokes, not unit tests.
The FILES section claimed ~/.tago-lock but the runtime writes per-environment locks at ./.tago-lock.<env>.lock (verified in src/lib/token.ts), and was missing ./.tagoio/personal.env where set-env persists TAGOIO_DEFAULT. Add an EXIT STATUS section documenting 0 (success) and 1 (any failure via errorHandler) as clig.dev recommends. Snapshot regenerated to match.
CI's `npm ci` was failing because package.json declared oxfmt@^0.47.0 / oxlint@1.62.0 but the committed lockfile still resolved to ^0.46.0 / 1.61.0. Regenerated the lockfile so transitive @oxfmt/* and @oxlint/* bindings align with the declared versions.
Replaces the developer-oriented stdout/stderr/JSON breakdown with a purpose-first summary: official CLI to TagoIO, manages the four top-level resources, suitable for interactive and CI/CD use.
Closes tago-io/project-sdk-and-tools#4. Adds a parent-walk resolver that finds
tagoconfig.json from any subdirectory and falls back to a per-user global
config under XDG/AppData. New `tagoio whoami` command and `--scope local|global`
flag on init/login, with mutating-command stderr banner, secure 0o700/0o600
perms on global, and analysis-* commands gated to local scope.
Six test files (login, start-config, four analysis-* commands) called resolveScope/requireLocalScope without mocking, which fails on hosts where the project root has no tagoconfig.json. Added resolve-scope and scope-notice mocks to each, plus a defensive setScopeOverride(undefined) reset in resolve-scope.test.ts so module-level state can't leak.
Static text bodies (description, exit-status, environment, files, see-also, author) move out of the inline roff arrays in generate-man.ts and into a dedicated MAN_CONTENT module written as plain English. The generator wraps each value with escapeRoff() and emits the same structural roff. Editing prose no longer requires counting backslashes.
- print the scope banner on data --post and dashboard copy-tab, two mutating commands that previously wrote remote state without showing which profile they were about to touch - extract a pure readConfigFile() helper (read + parse, no auto-create, no status output) and have whoami use it instead of duplicating the read/parse, keeping whoami strictly read-only - add the scope-notice / resolve-scope mocks to the data-post and copy-tab tests, matching the sibling pattern, so the banner does not leak to stderr
|
Reviewed the global/local profile work and ran the full functional test pass against a real TagoIO profile, then applied the findings and revalidated everything live. Improvements applied in this branch:
Functional test coverage (live, against the [Mateus] Second Profile): Full suite green (486 tests), tsc clean, 0 new lint warnings. |
Closes tago-io/project-sdk-and-tools#4.
Problem
The CLI resolves credentials strictly from
cwd, forcing users to either share one profile across every project or manually swap configs when switching. Running from a subdirectory of a project errors out, and there is no per-user, project-independent profile.Investigation
getEnvironmentConfig(),readToken(), and the dotenv path computation. Centralizing scope resolution in those three helpers means the 27+ command call sites do not need to change.~/.config/tagoioon Unix,%APPDATA%/tagoioon Windows) without adding a dependency.Solution
A new
resolveScope()primitive walks fromcwdup the parent chain (capped at 32 levels, logical-only — matchesgit/npmconvention) looking fortagoconfig.json. First match wins as local; if no ancestor matches, falls back to the platform-specific global directory. The decision is invisible to command-layer code.What's new
tagoio whoami— offline, scope-aware command. Prints scope, loaded path, active env, profile id/name/email, and a hard-codedloaded/missingtoken indicator (token bytes are never read into the output payload).--scope local|globalflag oninitandlogin. No flag falls through to the decision tree (local-exists → edit local; global-exists → edit global; neither → prompt; default fallback creates local).[INFO] Using <scope> profile (<path>)). Suppressed by--silentso CI flows stay clean.~/.tagoio/.scope-notice-shownso it cannot land in version control.Security guarantees
0o700; lock files written with0o600(unreadable by other local users).whoamisnapshot test asserts the token UUID never appears in stdout/stderr.Backward compatibility
Existing users see no behavior change except the one-time notice. Their on-disk layout (
<project>/tagoconfig.json+.tago-lock.<env>.lock+.tagoio/personal.env) is unchanged — the resolver finds it via parent-walk. Running from a subdirectory of a project now works (today's CLI errors out).Branch context
This is branched from
feat/cli-man-page, so the PR diff is scoped to the global/local profile changes only. Prior man-page and refactoring work lives in their own PRs.