@allocator-one/harness-cli 1.16.0 → 1.17.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
@@ -927,6 +927,129 @@ refusal exits 1 with the server's message and what it means
927
927
  answers a capability that doesn't exist, ships disabled, or is switched off
928
928
  with the same 404.
929
929
 
930
+ ## Code index
931
+
932
+ ```sh
933
+ harness code sync # sync this worktree’s overlay
934
+ harness code sync --path ../app # use that worktree’s host/org config
935
+ harness code status --json # active version and local freshness
936
+ harness code status --skipped # include the base’s skipped-files report
937
+ ```
938
+
939
+ The repository must be shared through the organization’s Harness GitHub
940
+ connection and code indexing must be enabled for that org. The server builds
941
+ commit bases from GitHub. The CLI polls a fetching base with backoff, opens an
942
+ overlay sync, uploads only blobs that sync requests, and activates it. It never
943
+ uploads a base or follows source symlinks. A successful sync reports the server’s
944
+ state; `queued` means indexing has been requested, not that queries are ready.
945
+ Safe source reads require macOS 11 or later, or Linux with `/proc/self/fd`;
946
+ code sync refuses when these kernel facilities are unavailable.
947
+
948
+ Sync needs both `harness:read` and `harness:write`; ordinary `code status`
949
+ needs `harness:read`, and base-status requests also need `harness:write`. `--skipped` on sync or status asks the server for its base
950
+ exclusions (path and reason). Local binary, oversized, ignored and secret-shaped
951
+ files are excluded before upload. Built-in secret rules cannot be removed by
952
+ an ignore-file negation. Deny and secret-path matches use ASCII case-insensitive
953
+ checks; path identities are preserved. Served content expressions must exactly
954
+ match the reviewed sources bundled with this client, or be literal-only markers
955
+ matched as substrings. Other expressions stop sync with an upgrade message before
956
+ source scanning. Source content is never included in diagnostics.
957
+
958
+ `.harnesscodeignore` uses the code-index policy dialect, not Git's ignore
959
+ grammar: each line is trimmed; `#` and `!` lines are skipped; and a backslash
960
+ is literal. The CLI reports warnings for skipped `!` lines and backslashes.
961
+ Patterns are case-sensitive, limited to 256 bytes and eight `*` characters,
962
+ and an ignore file has at most 1,000 patterns and 64 KiB. Matching uses the
963
+ server's UTF-8 byte semantics (`?` matches one byte), ASCII-only case folding
964
+ for deny globs, and linear-time wildcard matching. Unicode whitespace is trimmed;
965
+ a byte-order mark is literal. The client refuses ignore files above 64 KiB and
966
+ Git metadata above 16 MiB. The server's indexed extensions are exact, so `.TS`
967
+ is distinct from `.ts`.
968
+
969
+ The working copy's `.harnesscodeignore` governs its view. The CLI compares it with
970
+ the committed ignore file: newly ignored base paths become delete entries, and
971
+ newly included files are read from the worktree through the usual policy checks.
972
+ It never reads unchanged source content from the base. If ignore changes exceed
973
+ 20,000 overlay paths, commit the ignore file so the server-built base honors it.
974
+
975
+ View/session state is isolated by server, organization, repository and worktree
976
+ under the user’s cache directory. `HARNESS_CODE_STATE_DIR` overrides the directory
977
+ and must be absolute when non-empty (an empty override is unset). It stores control metadata and hashes, not source bytes or
978
+ tokens. Retrying the same interrupted overlay reuses its client ID. An uncertain
979
+ activation retains its opened sync ID and timestamp; the CLI reads that sync and
980
+ records its original pending version once it is no longer receiving. A missing sync
981
+ is treated as a replaced, never-activated sync only within 60 minutes; an older
982
+ missing sync fails closed. The server keeps a client ID unique per view and
983
+ manifest across states, so the CLI never uses one for a different manifest. A stale
984
+ policy is fetched again and the overlay rescanned. Syncs of the same local view are serialized: a
985
+ second sync is refused while one is running, because opening a sync can replace older
986
+ unactivated syncs on the server. If the process is forcibly interrupted, its error
987
+ message names the lock directory; remove it only after confirming no sync is running.
988
+ The server refuses overlays above 20,000 paths; sync against a newer base commit. A failed index is reported as `failed` with exit
989
+ code 1. A worktree with no active or pending version, or a removed cached view,
990
+ is `not_synced`; an existing active snapshot that no longer matches is `stale`.
991
+ An activation receipt records an assigned version, including a superseded or
992
+ failed one; only `code status` reporting `current` proves that the indexed active
993
+ version matches the local snapshot.
994
+
995
+ ### Query the active view
996
+
997
+ ```sh
998
+ harness code search 'process' --kind function --limit 20
999
+ harness code explain 'OPAQUE_ID_FROM_SEARCH' --budget-tokens 4000
1000
+ harness code affected --symbol 'OPAQUE_ID' --file src/app.ts --depth 3
1001
+ harness code context --symbol 'OPAQUE_ID' --budget-tokens 2000 --json
1002
+ harness code context 'name' --path ../app
1003
+ ```
1004
+
1005
+ Queries need `harness:read` and an existing view from `code sync`. They read its
1006
+ active version, even while a later version is pending. The output includes base
1007
+ commit, overlay digest, active version and pending progress. Querying neither
1008
+ scans nor uploads local source. No code-index MCP tools are registered.
1009
+
1010
+ Human output cites `path:line@sha256`, indexed snippets, version and base/overlay
1011
+ origin. Search citations may lack snippet text: use `context` to retrieve it.
1012
+ Context items that exceed the budget remain citations explicitly lacking text.
1013
+ JSON preserves server `data` and `meta`, adding a `guidance` array. Resolved,
1014
+ possible, name-only and unresolved references remain separate. A snippet budget
1015
+ covers the server's indexed text, not command formatting or metadata.
1016
+
1017
+ Contract 1.3 `meta.truncation` is always displayed: the returned count, the total
1018
+ if the server supplies it, limits and next command or narrowing hint. The CLI
1019
+ never invents a total or silently pages beyond the request. A `not_tracked`
1020
+ coverage answer gives a local `rg` hint instead of asserting there are no callers.
1021
+ Results cite the indexed snapshot; inspect the current file before editing it.
1022
+
1023
+ IDs are opaque. Swift IDs include declaration positions and can stop resolving
1024
+ when an edit moves a declaration; qualified names can include argument labels.
1025
+ Do not parse or reconstruct either. `not_found` asks you to search again, rather
1026
+ than blindly retrying an old symbol. `--include-ambiguous` and `--include-types`
1027
+ explicitly expand the affected walk; without them, possible/type impact is
1028
+ reported separately. Limits are bounded (search 1–100; depth 1–6; at most 200
1029
+ seeds; snippet budget 100–16,000, or 100–32,000 for context).
1030
+
1031
+ ### Agent Skill
1032
+
1033
+ The portable source of truth ships as `skills/harness-code/SKILL.md` in both npm
1034
+ packages. Copy it into your consumer repo's skill tree, following that repo's
1035
+ adapters and metadata conventions. For an agent that discovers `.agents/skills`:
1036
+
1037
+ ```sh
1038
+ mkdir -p .agents/skills
1039
+ cp -R "$(npm root -g)/@allocator-one/harness-cli/skills/harness-code" .agents/skills/
1040
+ ```
1041
+
1042
+ A short `AGENTS.md`/`CLAUDE.md` snippet:
1043
+
1044
+ > For symbol relationships, callers, impact and cited context, use the
1045
+ > harness-code skill and `harness code search/explain/affected/context`. Start
1046
+ > with `code status`; use `rg` for literal text and `not_tracked` coverage.
1047
+ > Report truncation and indexed hashes/versions; search again after missing IDs.
1048
+
1049
+ Allocator-one adoption and a paired agent tool-use comparison against a grep-only
1050
+ baseline are delivered in the consumer follow-up to CLI-70, before publication.
1051
+
1052
+
930
1053
  ## Uploads
931
1054
 
932
1055
  `harness upload <path>` uploads a file and prints a markdown reference to
@@ -11,14 +11,34 @@ var CLI_PACKAGE = pkg.name;
11
11
  // src/invocation.ts
12
12
  import { basename } from "path";
13
13
  var OPERATOR_PACKAGE = "@allocator-one/operator";
14
- function invokedName(argv1 = process.argv[1], packageName = CLI_PACKAGE) {
14
+ var INFRAONE_PACKAGE = "@allocator-one/infraone";
15
+ var PACKAGES = {
16
+ harness: "@allocator-one/harness-cli",
17
+ operator: OPERATOR_PACKAGE,
18
+ infraone: INFRAONE_PACKAGE
19
+ };
20
+ var operatorMount = false;
21
+ function mountOperatorUnderInfraone() {
22
+ operatorMount = true;
23
+ }
24
+ function operatorMounted() {
25
+ return operatorMount;
26
+ }
27
+ function invokedName(argv1 = process.argv[1], packageName = CLI_PACKAGE, infraoneBinary = typeof __INFRAONE_BINARY__ !== "undefined" && __INFRAONE_BINARY__ === true) {
28
+ if (operatorMount) return "operator";
29
+ if (infraoneBinary) return "infraone";
15
30
  const typed = basename(argv1 ?? "").replace(/\.[cm]?js$/i, "").toLowerCase();
16
- if (typed === "operator" || typed === "harness") return typed;
17
- return packageName === OPERATOR_PACKAGE ? "operator" : "harness";
31
+ if (typed === "operator" || typed === "harness" || typed === "infraone") return typed;
32
+ if (packageName === OPERATOR_PACKAGE) return "operator";
33
+ return packageName === INFRAONE_PACKAGE ? "infraone" : "harness";
18
34
  }
19
35
  function named(text, name = invokedName()) {
20
36
  if (name === "harness") return text;
21
- return text.replace(/^harness: /gm, `${name}: `).replace(/(?<![\w@/.-])harness (?=[a-z])(?!disagree)/g, `${name} `).replaceAll("@allocator-one/harness-cli", OPERATOR_PACKAGE);
37
+ if (name === "operator" && operatorMount) return mountedNamed(text);
38
+ return text.replace(/^harness: /gm, `${name}: `).replace(/(?<![\w@/.-])harness (?=[a-z])(?!disagree)/g, `${name} `).replaceAll(PACKAGES.harness, PACKAGES[name]);
39
+ }
40
+ function mountedNamed(text) {
41
+ return text.replace(/^(?:harness|operator): /gm, "infraone: ").replace(/(?<![\w@/.-])(?<!infraone )(?:harness|operator) (?=[a-z[<])(?!disagree)/g, "infraone operator ").replaceAll(PACKAGES.harness, INFRAONE_PACKAGE).replaceAll(OPERATOR_PACKAGE, INFRAONE_PACKAGE);
22
42
  }
23
43
  var OPERATOR_COMMANDS = [
24
44
  "run",
@@ -67,6 +87,8 @@ export {
67
87
  CLI_VERSION,
68
88
  CLI_PACKAGE,
69
89
  OPERATOR_PACKAGE,
90
+ mountOperatorUnderInfraone,
91
+ operatorMounted,
70
92
  invokedName,
71
93
  named,
72
94
  layoutOperatorHelp