pointer-feedback 0.1.3 → 0.2.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 +214 -4
- package/dist/cli.js +2797 -1072
- package/package.json +11 -5
package/README.md
CHANGED
|
@@ -18,7 +18,8 @@ npx pointer <command> [options]
|
|
|
18
18
|
|
|
19
19
|
### `pointer init`
|
|
20
20
|
Set up the feedback widget in your project.
|
|
21
|
-
- Scaffolds `.pointer/config.json`, `.pointer/
|
|
21
|
+
- Scaffolds `.pointer/config.json`, `.pointer/stack.json`, and authenticates — saving the API key
|
|
22
|
+
to this machine's **global credential store** by default (see **Authentication** below).
|
|
22
23
|
- Detects the application framework (Vite, Next.js, Angular, static HTML).
|
|
23
24
|
- Injects the `<pointer-feedback>` web component.
|
|
24
25
|
|
|
@@ -26,6 +27,209 @@ Set up the feedback widget in your project.
|
|
|
26
27
|
pointer init --server https://api.pointer.moamen.work --key ptr_... --project my-project
|
|
27
28
|
```
|
|
28
29
|
|
|
30
|
+
#### Committed vs. gitignored
|
|
31
|
+
|
|
32
|
+
`init` only expects these files to be shared via git: **`.pointer/config.json`**, **`.pointer/stack.json`**,
|
|
33
|
+
and — in a multi-project repo (see **Monorepos** below) — every **`.pointer/projects/<key>.stack.json`**.
|
|
34
|
+
Everything else (`pointer.sh`, `manifest.json`, and — only if you opted into `--local-credentials` —
|
|
35
|
+
`credentials.env`) is derived or per-machine and stays gitignored, along with every skill layout the
|
|
36
|
+
CLI can write: `.claude/skills/pointer-init/`, `.claude/skills/pointer-feedback/` (Claude Code),
|
|
37
|
+
`.cursor/rules/pointer-init.md`, `.cursor/rules/pointer-feedback.md` (Cursor),
|
|
38
|
+
`.windsurf/rules/pointer-init.md`, `.windsurf/rules/pointer-feedback.md` (Windsurf),
|
|
39
|
+
`.agents/skills/pointer-init/`, `.agents/skills/pointer-feedback/` (the Agent Skills standard layout
|
|
40
|
+
used by `other`/`antigravity`, and symlinked into from the three tools above), and — if you passed
|
|
41
|
+
`--skills-dir <dir>` — `<dir>/pointer-init/`, `<dir>/pointer-feedback/`. A repo that has not re-run
|
|
42
|
+
`init`/`update` since 2026-09-16 may still carry the older `.agents/pointer-init/`,
|
|
43
|
+
`.agents/pointer-feedback/` layout (pre-dating the `.agents/skills/...` convention); it stays
|
|
44
|
+
gitignored too, and the next install removes it. `init` manages the `.gitignore` block for you
|
|
45
|
+
(`upsertGitignore`), migrating an older repo's block — including one that still re-included
|
|
46
|
+
`pointer.sh` or the now-removed `credentials.env.example`, or predates any of the paths above —
|
|
47
|
+
automatically and idempotently. Both `init` (every mode, including a join) and `update` also delete
|
|
48
|
+
an actual leftover `.pointer/credentials.env.example` or `.pointer/.token_cache` file still on disk
|
|
49
|
+
from an older install — never `.pointer/credentials.env` itself.
|
|
50
|
+
|
|
51
|
+
That split is why a clone of an already-configured repo has `config.json`/`stack.json` (they were
|
|
52
|
+
committed) but is missing the skills and `pointer.sh` (they were never committed) — see **join
|
|
53
|
+
mode** below and `pointer update`. The API key never needs cloning at all, wherever it was saved —
|
|
54
|
+
see **Authentication**.
|
|
55
|
+
|
|
56
|
+
#### Join mode: re-running `init` in an already-configured repo
|
|
57
|
+
|
|
58
|
+
If `.pointer/config.json` already has a `server` **and** a `project` — because someone already ran
|
|
59
|
+
`init` here and committed the config — a further `init` run is a **join**, not a first install:
|
|
60
|
+
|
|
61
|
+
- Server, project, AI tool and delivery are all read back from the committed config; you are asked
|
|
62
|
+
for **nothing but your API key** (`--key`, or the interactive prompt) —
|
|
63
|
+
and not even that if one already resolves from the environment, this repo, or (the common case,
|
|
64
|
+
once you've run `pointer login` once) **this machine's global credential store**. See
|
|
65
|
+
**Authentication** below.
|
|
66
|
+
- Nothing is injected — the `<pointer-feedback>` snippet (or, for `delivery: "extension"`, nothing)
|
|
67
|
+
is already in the app's committed source.
|
|
68
|
+
- The skills and `.pointer/pointer.sh` ARE (re-)installed, since they are gitignored and this
|
|
69
|
+
clone/machine has none yet.
|
|
70
|
+
- `.pointer/stack.json` is only regenerated if it is missing — it is committed and rarely differs
|
|
71
|
+
machine to machine.
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
# In a repo that already has .pointer/config.json:
|
|
75
|
+
pointer init --yes --key ptr_... # no --project/--create needed
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
`--json`'s output gains a `mode` field: `"install"` for a first install, `"join"` for the above. The
|
|
79
|
+
human summary prints `Joined <product> project <key> as <you>` instead of `<product> is set up`.
|
|
80
|
+
|
|
81
|
+
#### Environments: managed in the dashboard, not asked here
|
|
82
|
+
|
|
83
|
+
`init` never asks which environment(s) an app runs in, and never writes `environment`/
|
|
84
|
+
`environments` to `.pointer/config.json`. Environments and their per-project activation live in the
|
|
85
|
+
dashboard, next to the project's URLs — the widget (and the Chrome extension) resolve the
|
|
86
|
+
environment for a comment from the page's own URL at runtime, and a signed-in reviewer can switch it
|
|
87
|
+
from the toolbar. The injected snippet correspondingly never carries a fixed `environment` attribute
|
|
88
|
+
by default.
|
|
89
|
+
|
|
90
|
+
`--environment <list>` (comma-separated: `local`, `staging`, `production`) remains as a deliberate,
|
|
91
|
+
**optional** opt-in: given, it activates the project for exactly those environments (server-side,
|
|
92
|
+
additive — it never deactivates one you didn't name) and pins the injected snippet's `environment`
|
|
93
|
+
attribute to the first of them in canonical order. Omitted, nothing about environments is asked,
|
|
94
|
+
activated, or recorded. A config written by a CLI from before this change may still carry
|
|
95
|
+
`environment`/`environments` — those fields are read for backward compatibility (deprecated, never
|
|
96
|
+
written any more).
|
|
97
|
+
|
|
98
|
+
#### Delivery: embed vs. extension
|
|
99
|
+
|
|
100
|
+
Interactively, `init` first asks **how reviewers will open the feedback widget**:
|
|
101
|
+
|
|
102
|
+
- **Embed it in this app** (default, recommended) — today's behaviour: the `<pointer-feedback>`
|
|
103
|
+
loader is injected into your app.
|
|
104
|
+
- **Chrome extension only** — no code change at all. Each reviewer installs the extension, signs
|
|
105
|
+
in, opens the app, picks the project from the extension popup and clicks **Activate**; the
|
|
106
|
+
widget is injected by the extension rather than by your app's own code.
|
|
107
|
+
|
|
108
|
+
Pass `--delivery embed` or `--delivery extension` to answer non-interactively (`--yes`/`--json`
|
|
109
|
+
default to `embed` and skip the question; `--no-inject` also stays `embed`, it just skips
|
|
110
|
+
injection). The choice is recorded in `.pointer/config.json` as `delivery`, and `pointer doctor`'s
|
|
111
|
+
widget check is mode-aware — it reports `ok` for an extension install instead of a false "widget
|
|
112
|
+
not found". The Chrome Web Store URL shown at the end of an extension-mode `init` (and by `doctor`)
|
|
113
|
+
comes from the server (`GET /api/branding`, a super-admin setting) at run time, never hard-coded.
|
|
114
|
+
|
|
115
|
+
#### Monorepos
|
|
116
|
+
|
|
117
|
+
A repo with many independently-deployed apps (an Nx workspace, or any monorepo) can register more
|
|
118
|
+
than one Pointer project against one `.pointer/config.json`. Single-project config is unchanged;
|
|
119
|
+
multi-project config drops the top-level `project` in favour of a `projects` map — there is **no
|
|
120
|
+
default project** in this mode:
|
|
121
|
+
|
|
122
|
+
```json
|
|
123
|
+
{
|
|
124
|
+
"server": "https://api.example.com",
|
|
125
|
+
"aiTool": "claude-code",
|
|
126
|
+
"delivery": "extension",
|
|
127
|
+
"cliVersion": "0.2.0",
|
|
128
|
+
"projects": {
|
|
129
|
+
"tuwaiq-profile": {
|
|
130
|
+
"path": "apps/profile",
|
|
131
|
+
"htmlPath": "apps/profile/src/index.html",
|
|
132
|
+
"delivery": "embed"
|
|
133
|
+
},
|
|
134
|
+
"tuwaiq-landing": { "path": "apps/landing" }
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Repo-level fields (`server`, `aiTool`, `skillsDir`, `cliVersion`, `delivery`) apply to every app
|
|
140
|
+
unless a project entry overrides them. Per-project fields: `path` (repo-relative app directory,
|
|
141
|
+
required), `htmlPath`, `delivery`. (`environment`/`environments` may still appear on an entry written
|
|
142
|
+
by an older CLI — deprecated, read for backward compatibility only; environments now live in the
|
|
143
|
+
dashboard, see above.)
|
|
144
|
+
|
|
145
|
+
**Resolution order**, identical for every command that touches a project: `--project <key>` → the
|
|
146
|
+
project whose `path` contains the current directory (the CLI walks up from `cwd` to the nearest
|
|
147
|
+
`.pointer/config.json` to find the repo root first, so this works from inside `apps/<x>` too) → the
|
|
148
|
+
only configured project → otherwise "every project" for commands that support it (`list`, `apply`,
|
|
149
|
+
`status --deployed`), or exit 2 with `Several projects configured — pass --project <key> (one of: a, b, c)`.
|
|
150
|
+
|
|
151
|
+
- **`list`/`apply`/`apply --plan`**: with no single project resolvable, run for **every** configured
|
|
152
|
+
project. `list --json` returns `[{ project, comments: [...] }]`; `apply`'s prompt gets one section
|
|
153
|
+
per project, headed with its key and `path`, so the AI edits the right app. `apply --mark`/`--fail`
|
|
154
|
+
act on a comment id (unique server-wide) and need no project; `--mark all` does, since it commits
|
|
155
|
+
the whole pending queue — pass `--project` or run from inside that app.
|
|
156
|
+
- **`doctor`**: `project`/`widget`/`stack`/`source-map` run once per project, the key folded into
|
|
157
|
+
the message (`[tuwaiq-profile] Widget found in apps/profile/src/index.html`); `config`/`server`/
|
|
158
|
+
`meta`/`clock`/`key`/`skills`/`stale`/`gitignore` run once for the whole repo.
|
|
159
|
+
- **`mcp`**: accepts `--project`; without it, every project-scoped tool call needs a `project`
|
|
160
|
+
argument once more than one project applies — call `pointer_list_projects` to see the choices.
|
|
161
|
+
- **`status --deployed`**: per project; with no single project resolvable, reports the build
|
|
162
|
+
against every configured one.
|
|
163
|
+
- **`.pointer/pointer.sh`** (the no-Node fallback): `-p <key>` (or `POINTER_PROJECT`) picks the
|
|
164
|
+
project; with neither, in a multi-project repo, it prints the configured keys and exits 2.
|
|
165
|
+
- Each app's own `.pointer/projects/<key>.stack.json` replaces the single `.pointer/stack.json` —
|
|
166
|
+
committed, exactly like `stack.json` is today.
|
|
167
|
+
|
|
168
|
+
**Setting it up**: `pointer init --path apps/<dir> --project <key> [--create "Name"]` adds (or
|
|
169
|
+
updates) one app; run it again with a different `--path`/`--project` to add another. The first time
|
|
170
|
+
this runs against a single-project config, that project is migrated into `projects` (best guess at
|
|
171
|
+
its `path` from the recorded `htmlPath`, or `.` if there is none — `init` warns you to check it). In
|
|
172
|
+
an Nx workspace (`nx.json` at the root), an interactive `init` also offers a multi-select of every
|
|
173
|
+
discovered `apps/*` app (from `project.json` with `projectType: "application"`, or a directory with
|
|
174
|
+
its own `index.html` but no `project.json`) instead of asking about the repo root.
|
|
175
|
+
|
|
176
|
+
### Authentication
|
|
177
|
+
|
|
178
|
+
Authenticate **once per machine**, not once per repo. `pointer login` validates an API key and
|
|
179
|
+
saves it to a global, per-machine credential store; every other command (`init` in join mode,
|
|
180
|
+
`doctor`, `apply`, `list`, `mcp`, and `.pointer/pointer.sh`) then finds it without being asked again
|
|
181
|
+
— in this repo, or any other repo on the same machine, against the same server.
|
|
182
|
+
|
|
183
|
+
**Resolution order**, identical everywhere a key is needed:
|
|
184
|
+
|
|
185
|
+
1. **`POINTER_API_KEY`** environment variable — the right choice for CI, and always wins outright.
|
|
186
|
+
2. This repo's **`.pointer/credentials.env`** — written only when you opt out of the global store
|
|
187
|
+
(`--local-credentials`, or answering "no" to the save prompt below).
|
|
188
|
+
3. The **global store**: `~/.config/pointer/credentials.json` (honours `$XDG_CONFIG_HOME`; on
|
|
189
|
+
Windows, `%APPDATA%\pointer\credentials.json`), keyed by server, mode `0600`.
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
# Once per machine, per server:
|
|
193
|
+
pointer login --server https://api.pointer.moamen.work
|
|
194
|
+
# API key (from Pointer -> profile -> API key; input hidden): ****************
|
|
195
|
+
|
|
196
|
+
pointer whoami
|
|
197
|
+
# https://api.pointer.moamen.work — Jane Doe (jane@example.com) — key source: global store
|
|
198
|
+
|
|
199
|
+
pointer logout # removes this machine's saved key for a server
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
- **`pointer login [--server <url>] [--key <key>]`** — resolves the server from `--server`, then
|
|
203
|
+
this repo's `.pointer/config.json`, then `$POINTER_SERVER`, then the build default. Prompts for
|
|
204
|
+
the key (hidden input) unless `--key` is given; validates it exactly like `init` does
|
|
205
|
+
(`/api/auth/login-with-key` + `/api/auth/me`); saves it to the global store.
|
|
206
|
+
- **`pointer logout [--server <url>]`** — removes this machine's saved entry for that server. Never
|
|
207
|
+
touches a repo's own `.pointer/credentials.env`.
|
|
208
|
+
- **`pointer whoami [--server <url>] [--json]`** — prints the server, the signed-in account, and
|
|
209
|
+
which source answered the key (`env` / `repo` / `global`) — **never the key itself**.
|
|
210
|
+
|
|
211
|
+
**`init` and the global store.** A first install that authenticates a key it did not already trust
|
|
212
|
+
(typed interactively, or passed via `--key`) asks:
|
|
213
|
+
|
|
214
|
+
```
|
|
215
|
+
Save this key for all repos on this machine? (Y/n)
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Answering yes (the default, and also the default under `--yes`/`--json` when `--key` is given)
|
|
219
|
+
saves it globally and writes **no** `.pointer/credentials.env` at all — there is nothing repo-local
|
|
220
|
+
to gitignore, review, or accidentally commit. Answering no, or passing **`--local-credentials`**,
|
|
221
|
+
keeps the pre-global-store behaviour: the key is written to `.pointer/credentials.env` instead
|
|
222
|
+
(still gitignored, still per-machine). A join (`init` run again in an already-configured repo) never
|
|
223
|
+
even asks, either way: it tries `resolveApiKey`'s three sources first and only prompts when none of
|
|
224
|
+
them resolve.
|
|
225
|
+
|
|
226
|
+
**CI**: set `POINTER_API_KEY` — it always wins, and nothing is written anywhere.
|
|
227
|
+
|
|
228
|
+
**Multiple accounts on one machine** (e.g. a personal key for most repos, a service account for
|
|
229
|
+
one): run `pointer init --key <key> --local-credentials` (or `pointer login` normally, then override
|
|
230
|
+
per-repo with `.pointer/credentials.env`) for the repo that needs the different key — the repo-local
|
|
231
|
+
file wins over the global store for that repo only.
|
|
232
|
+
|
|
29
233
|
### `pointer doctor`
|
|
30
234
|
Diagnose an existing installation and report issues.
|
|
31
235
|
- Checks config files, server reachability, API version compatibility, clock skew, and widget injection.
|
|
@@ -38,13 +242,19 @@ pointer doctor --fix
|
|
|
38
242
|
```
|
|
39
243
|
|
|
40
244
|
### `pointer update`
|
|
41
|
-
Refresh the local AI skills (`.claude/skills/`, `.agents/`) and `pointer.sh` from the configured
|
|
245
|
+
Refresh the local AI skills (`.claude/skills/`, `.agents/`) and `pointer.sh` from the configured
|
|
246
|
+
server — **and installs them if they are missing entirely**, not just when they're stale. Since
|
|
247
|
+
they're gitignored (see "Committed vs. gitignored" above), a freshly cloned repo that already has
|
|
248
|
+
`.pointer/config.json` has neither until `update` (or a join `init`) puts them there.
|
|
42
249
|
|
|
43
250
|
```bash
|
|
44
|
-
pointer update
|
|
45
|
-
pointer update --check
|
|
251
|
+
pointer update # installs anything missing, refreshes anything stale
|
|
252
|
+
pointer update --check # reports missing/stale files without changing anything
|
|
46
253
|
```
|
|
47
254
|
|
|
255
|
+
`pointer doctor` (below) surfaces the same gap as a `skills` warning — "Skills not installed — run
|
|
256
|
+
`npx pointer-feedback update`" — and `doctor --fix` runs the same install.
|
|
257
|
+
|
|
48
258
|
### `pointer apply`
|
|
49
259
|
Turn pending feedback comments into a self-contained AI apply prompt, or hand it off directly to an AI tool.
|
|
50
260
|
|