@harnessforce/cli 0.2.0 → 0.3.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.
Files changed (3) hide show
  1. package/README.md +33 -11
  2. package/dist/bin.js +618 -443
  3. package/package.json +5 -5
package/README.md CHANGED
@@ -35,6 +35,7 @@ harnessforce init
35
35
  | `harnessforce tune record` / `harnessforce tune --purge` | Records a proposal from stdin / deletes everything under `~/.harnessforce/tune/` |
36
36
  | `harnessforce top [--once] [--json] [--ascii] [--theme <auto\|light\|dark\|ansi>]` | Shows the Claude Code and Codex sessions on this machine in the terminal: state, tokens, context and tool failures. Reads only local files and never connects to Harnessforce |
37
37
  | `harnessforce hook session-start` | The entry of Codex's `SessionStart` hook: reads `session_id`, `cwd` and `source` from stdin, registers the session, and prints the session ID for the agent's context. Always exits 0 |
38
+ | `harnessforce hook post-tool-use` / `stop` | The entries of Codex's `PostToolUse` (`apply_patch`) and `Stop` hooks: record the repository and branch of the working trees the session works in, and send them at the end of a turn in which they changed. Always exit 0 |
38
39
  | `harnessforce --version` | Prints the version |
39
40
 
40
41
  ## Watching your sessions (`harnessforce top`)
@@ -62,6 +63,20 @@ no context percentage.
62
63
  - `~/.harnessforce/config.json` may set `{"top": {"ambiguous_width": 2, "braille": true}}`. An unreadable file or a
63
64
  value out of range falls back to the defaults and says so; the file is never written.
64
65
 
66
+ ## Codex work location hooks (`harnessforce hook post-tool-use` and `stop`)
67
+
68
+ Codex has no event for a change of the working directory, so these hooks record the repository and branch
69
+ of the working tree of each file named in an `apply_patch` patch (`*** Add File:`, `*** Update File:`,
70
+ `*** Delete File:` and `*** Move to:` lines; relative paths are resolved from `cwd`) and of `cwd` at the end
71
+ of each turn. At `Stop`, when the pairs differ from the pairs sent last, they are sent to
72
+ `/v1/sessions/locations` with the same destination and key as the `SessionStart` hook. Only the agent, the
73
+ session ID and up to 10 pairs of repository and branch are sent; paths, commits, file names and the content
74
+ of patches are not. Codex gives hooks no scratchpad, so the record is kept in
75
+ `<temporary directory>/harnessforce-locations/codex-<session_id>.json`; on macOS and Linux the directory
76
+ must be owned by you with mode `0700`, or nothing is recorded. `stop` always prints `{}`, and both always
77
+ exit 0. A machine set up with an earlier `harnessforce init` gets these hooks when you run it again and
78
+ trust them in `/hooks`.
79
+
65
80
  ## Codex `SessionStart` hook (`harnessforce hook session-start`)
66
81
 
67
82
  Codex runs this command through the `[[hooks.SessionStart]]` entry that `harnessforce init` writes into Codex's
@@ -82,10 +97,13 @@ Codex runs this command through the `[[hooks.SessionStart]]` entry that `harness
82
97
  ## What is never sent
83
98
 
84
99
  Harnessforce never turns on prompt or body logging by itself. `harnessforce run` never turns it on, and `harnessforce init`
85
- adds `OTEL_LOG_USER_PROMPTS=1` to the Claude Code user settings only with `--send-content`, and only
86
- when the credentials response says the Workspace has opted in to content. Without that, prompts,
87
- responses, tool inputs and outputs, and file contents are not sent. For a Workspace that has not opted
88
- in, `harnessforce init --send-content` leaves the setting alone, prints the reason, and still exits 0. `harnessforce run`
100
+ sets `OTEL_LOG_USER_PROMPTS`, `OTEL_LOG_ASSISTANT_RESPONSES`, `OTEL_LOG_TOOL_DETAILS` and
101
+ `OTEL_LOG_TOOL_CONTENT` in the Claude Code user settings to `1` only with `--send-content`, and only for
102
+ the categories the Workspace stores (prompts, and model responses with tool input and output). Without that,
103
+ `harnessforce init` writes all four as `0` (and Codex's `log_user_prompt` and `log_agent_responses` as
104
+ `false`), so a value left from an earlier run cannot keep sending. `OTEL_LOG_RAW_API_BODIES` is never written.
105
+ For a Workspace that stores no content, `harnessforce init --send-content` writes `0`, prints the reason, and
106
+ still exits 0. `harnessforce import` never sends content. `harnessforce run`
89
107
  never puts the user key or the API token in the agent's environment, arguments or settings. Keys and
90
108
  tokens are sent only to the origins pinned by `harnessforce init`.
91
109
 
@@ -120,26 +138,30 @@ tokens are sent only to the origins pinned by `harnessforce init`.
120
138
  5. It updates the Claude Code user settings (`~/.claude/settings.json`, or `$CLAUDE_CONFIG_DIR`),
121
139
  changing only these keys:
122
140
  - `env`: the OTel exporter variables, `HARNESSFORCE_URL`, `HARNESSFORCE_ENDPOINT` and
123
- `HARNESSFORCE_WORKSPACE_ID`, but no key. With `--send-content` and a Workspace that has opted in
124
- to content it also adds `OTEL_LOG_USER_PROMPTS=1`
141
+ `HARNESSFORCE_WORKSPACE_ID`, but no key, and the four `OTEL_LOG_*` content variables: `1` for a category
142
+ you send with `--send-content` and the Workspace stores, `0` otherwise
125
143
  - `otelHeadersHelper`: `harnessforce otel-headers`
126
144
  - `enabledPlugins["harnessforce@harnessforce-agent"]`
127
145
  - `extraKnownMarketplaces["harnessforce-agent"]` (or `additionalMarketplaces` when only that alias is
128
146
  present): the GitHub source and `autoUpdate: true`, so Claude Code updates the plugin in the
129
147
  background. `--no-plugin-auto-update` writes `false`; a value you set yourself is kept.
130
148
  6. It updates the Codex `config.toml` (`$CODEX_HOME` when it is an absolute path, otherwise `~/.codex`),
131
- changing only these three items and keeping every other key and comment:
149
+ changing only these items and keeping every other key and comment:
132
150
  - `[otel].exporter`: OTLP/HTTP (`protocol = "binary"`) to the ingest endpoint with
133
151
  `Authorization = "Bearer <user ingest key>"`. Codex cannot take the header from a command or expand
134
152
  `${VAR}`, so this is the one place a key is written to a plain file. It is the user ingest key only
135
- (never the API token), and you can revoke it on the Workspace's send keys page. With `--send-content`
136
- and a Workspace that has opted in to content it also sets `log_user_prompt = true`
153
+ (never the API token), and you can revoke it on the Workspace's send keys page. `log_user_prompt` and
154
+ `log_agent_responses` are set to `true` for a category you send with `--send-content` and the
155
+ Workspace stores, and `false` otherwise
137
156
  - `[[hooks.SessionStart]]`: a handler that runs `harnessforce hook session-start`
157
+ - `[[hooks.PostToolUse]]`: a handler with `matcher = "^apply_patch$"` that runs `harnessforce hook post-tool-use`
158
+ asynchronously
159
+ - `[[hooks.Stop]]`: a handler that runs `harnessforce hook stop` asynchronously
138
160
  - `[mcp_servers.harnessforce]`: `url = "<base URL>/mcp"`
139
161
 
140
162
  The file is written through a temporary file in the same directory and renamed into place, with mode
141
- `0600`. Running `harnessforce init` again replaces only these three items. Restart Codex afterwards,
142
- trust the hook with `/hooks` (Codex runs an untrusted hook only after you review it), and run
163
+ `0600`. Running `harnessforce init` again replaces only these items. Restart Codex afterwards,
164
+ trust the three hooks with `/hooks` (Codex runs an untrusted hook only after you review it), and run
143
165
  `codex mcp login harnessforce` to use the MCP server.
144
166
 
145
167
  `harnessforce otel-headers` prints `{"Authorization":"Bearer <key>"}`. The key is `HARNESSFORCE_INGEST_KEY` from