@ictechgy/context-guard 0.4.12 → 0.4.14
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/CHANGELOG.md +11 -0
- package/README.ko.md +10 -3
- package/README.md +13 -3
- package/package.json +1 -1
- package/plugins/context-guard/.claude-plugin/plugin.json +1 -1
- package/plugins/context-guard/README.ko.md +5 -1
- package/plugins/context-guard/README.md +8 -2
- package/plugins/context-guard/bin/context-guard-experiments +456 -1
- package/plugins/context-guard/bin/context-guard-rewrite-bash +148 -12
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,17 @@ All notable changes for the ContextGuard plugin are documented here.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.4.14] - 2026-07-10
|
|
8
|
+
|
|
9
|
+
- Added the default-off `semantic-checkpoint` experimental planning gate with deterministic readiness payloads, explicit scope/metric/rollback validation, prompt-cache caveats, and hosted-savings claim boundaries.
|
|
10
|
+
- Documented semantic-checkpoint as a plan-only roadmap lane across README/plugin materials and updated the experimental token-reduction radar.
|
|
11
|
+
- Expanded regression coverage for semantic-checkpoint validation, preview truncation, config isolation, and plugin copy synchronization.
|
|
12
|
+
|
|
13
|
+
## [0.4.13] - 2026-06-22
|
|
14
|
+
|
|
15
|
+
- Kept the Bash rewrite hook stdout JSON-parseable while routing sanitizer-worthy read-only pipelines through `context-guard-sanitize-output`.
|
|
16
|
+
- Preserved fail-closed handling for side-effecting shell operators, redirections, here-strings, `tee`, network commands, environment-prefixed filters, and file-reading/writing filter options.
|
|
17
|
+
|
|
7
18
|
## [0.4.12] - 2026-06-22
|
|
8
19
|
|
|
9
20
|
- Published the post-merge README, Korean README, and GitHub Pages copy polish into the npm/package metadata so package consumers see the same setup, packaging, helper-trust, and conservative savings-claim guidance as the product site.
|
package/README.ko.md
CHANGED
|
@@ -78,7 +78,7 @@ ContextGuard는 provider 캐시, semantic cache, 프롬프트 압축 도구를
|
|
|
78
78
|
| Provider prompt/context caching | 안정적인 프롬프트 앞부분을 재사용합니다. | 보완 관계입니다. ContextGuard는 자주 바뀌는 컨텍스트 뒷부분을 더 작고 깨끗하게 유지하도록 돕고, `context-guard-audit`로 프롬프트 배치를 점검하며, `context-guard cost`로 Anthropic 요청이 cache read 대신 cache write가 될 가능성을 미리 알릴 수 있습니다. |
|
|
79
79
|
| Semantic response cache | 같거나 비슷한 요청의 이전 답변을 재사용합니다. | 보완 관계입니다. ContextGuard는 AI 답변 캐시를 제공하지 않습니다. |
|
|
80
80
|
| 프롬프트/컨텍스트 압축 | 이미 선택된 텍스트를 더 짧게 만듭니다. | 인접한 역할입니다. ContextGuard는 로컬 출력 축약과 요약을 제공하지만, 무손실 의미 압축을 보장하지 않습니다. |
|
|
81
|
-
| 실험 planner/runtime | local proxy는 dry-run plan, external-forwarding design plan, gate record, one-shot loopback forwarding MVP로만 검토합니다. context-diff, visual evidence-pack, learned-compression, self-hosted metrics도 명시적 로컬 런타임만 지원합니다. | 모두 기본 비활성이며 명시적 명령이 필요합니다. `record`는 listener·traffic forwarding·DNS lookup을 시작하지 않고, `serve local-proxy`는 literal loopback IP로 제한된 1회 요청만 bind/forward하며, `--response-sandbox`는 safe UTF-8 upstream body를 compact local artifact 재조회 envelope로 대체할 수 있습니다. 별도 근거 gate와 future PR gate 없이는 model/compressor 실행, OCR/crop service, external forwarding, credential persistence, hosted API 절감 주장으로 보지 않습니다. 자세한 내용은 “실험 기능 opt-in 관리” 섹션을 참고하세요. |
|
|
81
|
+
| 실험 planner/runtime | `image-context-pack`과 `semantic-checkpoint`는 plan-only gate로만 검토합니다. local proxy는 dry-run plan, external-forwarding design plan, gate record, one-shot loopback forwarding MVP로만 검토합니다. context-diff, visual evidence-pack, learned-compression, self-hosted metrics도 명시적 로컬 런타임만 지원합니다. | 모두 기본 비활성이며 명시적 명령이 필요합니다. `semantic-checkpoint`는 exact context fallback/re-expand, provenance review ack, provider-boundary ack, protected-zone denial, missed-context note가 있어야 JSON payload가 ready 상태가 됩니다. `record`는 listener·traffic forwarding·DNS lookup을 시작하지 않고, `serve local-proxy`는 literal loopback IP로 제한된 1회 요청만 bind/forward하며, `--response-sandbox`는 safe UTF-8 upstream body를 compact local artifact 재조회 envelope로 대체할 수 있습니다. 별도 근거 gate와 future PR gate 없이는 model/compressor 실행, OCR/crop service, external forwarding, credential persistence, runtime checkpoint replacement, hosted API 절감 주장으로 보지 않습니다. 자세한 내용은 “실험 기능 opt-in 관리” 섹션을 참고하세요. |
|
|
82
82
|
| ContextGuard | 불필요한 파일, 로그, 반복 실패, 과도한 출력이 에이전트 컨텍스트에 들어가기 전에 줄어들도록 돕습니다. | 로컬 가드레일, 되돌릴 수 있는 로컬 보관본, 측정 도구입니다. |
|
|
83
83
|
|
|
84
84
|
설계에 참고한 관련 패턴은 다음과 같습니다.
|
|
@@ -117,7 +117,7 @@ brief 모드는 코딩 에이전트가 군더더기를 줄이도록 요청하되
|
|
|
117
117
|
- setup이나 패키징 smoke check에서 명령 매니페스트를 코드로 실행하거나 임의 `PATH`/현재 작업 디렉터리 헬퍼를 신뢰하지 않습니다.
|
|
118
118
|
- 절감 수치가 필요할 때 직접 전후 비교 측정을 대신하지 않습니다.
|
|
119
119
|
- 로컬 RAM/디스크 보관본은 다음에 보낼 컨텍스트를 줄이는 데 도움이 될 수 있지만 Anthropic provider prompt cache를 대체하거나 cache hit를 보장하지 않습니다. 배포나 청구 설명 전에는 Anthropic prompt caching/pricing 문서를 다시 확인하세요: https://docs.anthropic.com/en/build-with-claude/prompt-caching 및 https://platform.claude.com/docs/en/about-claude/pricing.
|
|
120
|
-
- 실험 헬퍼는 대부분 dry-run 안전성 checker/planner이며 design-only external-forwarding opt-in gate를 포함합니다. 명시적 로컬 runtime은 caller-supplied context-diff replacement payload, caller-supplied visual crop/OCR evidence pack, caller-supplied learned-compression prose candidate, self-hosted metrics JSONL sidecar 기록, local-proxy runtime-gate JSONL 기록, private ready-file nonce가 필요한 one-shot `serve local-proxy` loopback forwarding, safe UTF-8 응답을 compact artifact envelope로 바꾸는 optional `--response-sandbox`, successful forwarded request용 optional shifted-cost diagnostic JSONL row만 제공합니다.
|
|
120
|
+
- 실험 헬퍼는 대부분 dry-run 안전성 checker/planner이며 plan-only `image-context-pack`/`semantic-checkpoint` 평가 gate와 design-only external-forwarding opt-in gate를 포함합니다. 명시적 로컬 runtime은 caller-supplied context-diff replacement payload, caller-supplied visual crop/OCR evidence pack, caller-supplied learned-compression prose candidate, self-hosted metrics JSONL sidecar 기록, local-proxy runtime-gate JSONL 기록, private ready-file nonce가 필요한 one-shot `serve local-proxy` loopback forwarding, safe UTF-8 응답을 compact artifact envelope로 바꾸는 optional `--response-sandbox`, successful forwarded request용 optional shifted-cost diagnostic JSONL row만 제공합니다.
|
|
121
121
|
- ContextGuard는 learned/synthetic compressor 실행·embedding·reranker·model call·생성형 replacement, screenshot 캡처·image crop·OCR 실행·image parsing·외부 OCR/image service, 명시적 local metrics 기록을 넘어선 self-hosted KV/latent inference optimization runtime, literal-loopback 1회 HTTP forwarding과 credential 차단을 넘어선 proxy forwarding은 제공하지 않습니다.
|
|
122
122
|
- 예전 `/claude-token-optimizer:*` Claude Code 슬래시 명령을 별칭으로 제공하지 않습니다. 설치 후에는 `/context-guard:*`를 사용하세요.
|
|
123
123
|
|
|
@@ -394,6 +394,8 @@ context-guard experiments plan context-diff-compaction --json < change.diff
|
|
|
394
394
|
context-guard experiments emit context-diff-compaction --receipt-id <artifact-id> --reexpand-command "context-guard-artifact get <artifact-id> --full" --replacement-file compact-diff.txt --json < change.diff
|
|
395
395
|
context-guard experiments plan visual-crop-ocr --json --full-evidence-receipt <id> --crop-label <label> --crop-bounds 0,0,100,100 --image-size 800,600 --missed-context-note "outside crop omitted"
|
|
396
396
|
context-guard experiments emit visual-crop-ocr --json --full-evidence-receipt <id> --crop-label <label> --crop-bounds 0,0,100,100 --image-size 800,600 --ocr-text "visible text" --ocr-confidence 0.9 --ocr-error-note "glyph may be uncertain" --missed-context-note "outside crop omitted"
|
|
397
|
+
context-guard experiments plan image-context-pack --json --exact-text-fallback-receipt <id> --reexpand-command "context-guard-artifact get <id> --full" --provider-boundary-ack --protected-zone-policy deny --missed-context-note "omitted text remains retrievable before any future image pack is used" --image-size 800,600 --packed-image-size 400,300
|
|
398
|
+
context-guard experiments plan semantic-checkpoint --json --goal "preserve current task state for review" --constraint "do not rewrite protected evidence" --decision "ship plan-only semantic-checkpoint gate first" --open-task "verify exact fallback before any checkpoint is used" --evidence-handle "roadmap=contextguard-artifact:0123456789abcdef" --missing-provenance-note "none known after review" --unresolved-question "which provenance handle fields become mandatory later" --exact-context-fallback-receipt 0123456789abcdef --reexpand-command "context-guard-artifact get 0123456789abcdef --full" --provider-boundary-ack --protected-zone-policy deny --missed-context-note "raw transcript remains retrievable before checkpoint metadata is used"
|
|
397
399
|
context-guard experiments plan learned-compression --json --sanitized --trusted-source --exact-fallback-receipt <id> --reexpand-command "context-guard-artifact get <id> --full" < sanitized-prose.txt
|
|
398
400
|
context-guard experiments emit learned-compression --json --sanitized --trusted-source --exact-fallback-receipt <id> --reexpand-command "context-guard-artifact get <id> --full" --replacement-file compact-prose.txt < sanitized-prose.txt
|
|
399
401
|
context-guard experiments plan self-hosted-metrics-ledger --json --latency-ms 123.5 --peak-memory-mb 2048 --quality-score 0.98
|
|
@@ -406,6 +408,8 @@ context-guard experiments enable output-receipt-trim --root .
|
|
|
406
408
|
context-guard experiments disable output-receipt-trim --root .
|
|
407
409
|
```
|
|
408
410
|
|
|
411
|
+
`plan semantic-checkpoint`는 plan-only/eval-only gate입니다. CLI flag는 dry-run 검토를 위해 optional이지만, JSON payload에서는 goal, exact fallback receipt, local re-expand command, provider-boundary ack, protected-zone policy `deny`, missed-context note, provenance review note가 없으면 readiness blocker로 남습니다. re-expand command는 `context-guard-artifact get <id> --full` 또는 `context-guard artifact get <id> --full` 형태의 로컬 artifact 재조회만 허용합니다. `--missing-provenance-note`는 `none known after review` 같은 검토 확인 문구일 수 있습니다. 이 gate는 `emit`/`record`/`serve` runtime, 새 `context-guard-semantic-checkpoint` binary, file write, transcript/prompt edit, model/provider/network call, replacement context, hosted token/cost savings claim을 제공하지 않습니다.
|
|
412
|
+
|
|
409
413
|
local-proxy 예시는 side effect 기준으로 나뉩니다.
|
|
410
414
|
|
|
411
415
|
- `plan local-proxy`는 advisory metadata만 만들며 forwarding을 켜지 않습니다.
|
|
@@ -420,6 +424,8 @@ local-proxy 예시는 side effect 기준으로 나뉩니다.
|
|
|
420
424
|
| --- | --- | --- |
|
|
421
425
|
| `context-diff-compaction` | dry-run diff 조언과 명시적 `emit ... --receipt-id ... --reexpand-command ...` 런타임으로 caller-supplied compact replacement를 출력합니다. | `plan`은 replacement를 emit하지 않습니다. `emit`은 reviewable hunk, input diff와 일치하는 exact local artifact content/re-expand metadata와 더 작은 caller-supplied replacement가 모두 있을 때만 동작하며, ContextGuard가 semantic compression을 생성하거나 hosted token/cost 절감 주장 근거로 쓰지 않습니다. |
|
|
422
426
|
| `visual-crop-ocr` | dry-run visual evidence 조언과 명시적 `emit visual-crop-ocr` 런타임으로 caller-supplied evidence pack을 출력합니다. | `emit`은 full visual evidence receipt, missed-context note, 완전한 user-supplied crop 및/또는 OCR evidence가 필요합니다. ContextGuard는 screenshot 캡처, image crop, OCR 실행, image parsing, 외부 service 호출, 파일 쓰기, hosted token/cost 절감 주장을 하지 않습니다. |
|
|
427
|
+
| `image-context-pack` | pxpipe-inspired image/context packing 평가를 위한 plan-only dry-run gate입니다. | 명시적 평가 의도, exact text artifact fallback, protected-zone denial, provider-measured matched-task boundary, missed-context guardrail, 그리고 `visual-crop-ocr`이 기존 caller-supplied visual evidence-pack surface라는 확인이 필요합니다. ContextGuard는 image rendering, OCR 실행, image parsing, model/provider call, proxy traffic, binary artifact 저장, replacement evidence 출력, hosted token/cost savings claim을 하지 않습니다. |
|
|
428
|
+
| `semantic-checkpoint` | 현재 작업 상태를 review용으로 보존할 준비가 되었는지 확인하는 plan-only/eval-only gate입니다. | CLI flag는 optional이지만 JSON readiness는 exact context fallback/re-expand, provider-boundary ack, protected-zone denial, missed-context note, provenance review note가 없으면 blocked입니다. `--missing-provenance-note`는 `none known after review` 같은 검토 확인 문구일 수 있습니다. ContextGuard는 file write, transcript/prompt edit, model/provider/network call, replacement context, `emit`/`record`/`serve` runtime, 새 binary, hosted token/cost savings claim을 하지 않습니다. |
|
|
423
429
|
| `learned-compression` | deny-by-default 정책 검사와 명시적 `emit learned-compression` 런타임으로 verified exact fallback content가 있는 caller-supplied compact prose candidate를 출력합니다. | `emit`은 sanitized trusted prose, protected-signal denial, input과 일치하는 verified local fallback artifact, 더 작은 caller-supplied prose candidate가 필요합니다. ContextGuard는 compressor, embedding, reranker, model call, subprocess, external service, 생성형 replacement, hosted savings claim을 실행/생성하지 않습니다. |
|
|
424
430
|
| `self-hosted-metrics-ledger` | dry-run preview와 명시적 `record ... --ledger-jsonl` 런타임으로 local/model-server latency, memory, quality, energy, throughput, local-cost metric을 기록합니다. | dry-run preview는 ledger 파일을 쓰지 않습니다. 명시적 record 명령만 로컬 JSONL sidecar를 쓰며, hosted API token/cost 절감 주장 근거로는 쓰지 않습니다. |
|
|
425
431
|
| `local-proxy` | 미래 local proxy 후보에 대한 localhost-only advisory metadata, future external forwarding용 design-only `plan local-proxy-external-forwarding` review, 명시적 `record local-proxy-runtime-gate --ledger-jsonl` gate row runtime, 명시적 one-shot `serve local-proxy` loopback forwarding MVP, safe UTF-8 응답을 compact artifact envelope로 바꾸는 optional `--response-sandbox`, successful forwarded request용 optional `--diagnostic-ledger-jsonl` shifted-cost diagnostics. | `plan`은 ledger를 쓰지 않습니다. `record`는 localhost-only metadata와 `--runtime-gate-ack`가 있을 때만 로컬 JSONL row를 쓰며 listener 시작이나 traffic forwarding, DNS lookup을 하지 않습니다. `serve`는 `--forwarding-gate-ack --once`, private `--ready-file` nonce handoff, literal loopback bind/target IP, nonzero port, byte/time limit, credential-free request가 필요하며 external forwarding, CONNECT/TLS proxying, API-key persistence, hosted API 절감 주장을 하지 않습니다. `--response-sandbox`는 safe UTF-8 response text만 sanitized local artifact receipt로 저장하고 raw body 대신 redacted rehydration command template가 담긴 compact envelope를 반환하며 hosted token/cost savings claim은 아닙니다. `--diagnostic-ledger-jsonl`은 successful-forward 진단 row만 쓰며 raw header/body와 hosted-savings claim을 저장하지 않습니다. `plan local-proxy-external-forwarding`은 threat model/allowlist/redaction/provider-evidence design metadata만 출력하고 DNS lookup, external service call, traffic forwarding, credential persistence, hosted savings claim을 하지 않습니다. |
|
|
@@ -431,7 +437,8 @@ local-proxy 예시는 side effect 기준으로 나뉩니다.
|
|
|
431
437
|
ContextGuard는 아직 다음 기능을 제공하지 않습니다.
|
|
432
438
|
|
|
433
439
|
- caller-supplied learned candidate emitter를 넘어서는 learned/synthetic compressor 실행 또는 생성형 replacement
|
|
434
|
-
- caller-supplied visual evidence-pack emitter를 넘어서는 생성형 crop/OCR
|
|
440
|
+
- caller-supplied visual evidence-pack emitter와 plan-only image-context-pack dry-run gate를 넘어서는 생성형 crop/OCR, visual-token pruning runtime, image-context-pack rendering/runtime
|
|
441
|
+
- plan-only semantic-checkpoint gate를 넘어서는 emit/record/serve runtime, replacement context, file-writing checkpoint store, transcript/prompt edit, provider/model/network-backed checkpointing, 새 `context-guard-semantic-checkpoint` binary
|
|
435
442
|
- 명시적 local metrics 기록을 넘어서는 self-hosted KV/latent optimization
|
|
436
443
|
- one-shot literal-loopback local proxy MVP를 넘어서는 external/daemon/credential-bearing proxy forwarding runtime
|
|
437
444
|
|
package/README.md
CHANGED
|
@@ -80,7 +80,7 @@ ContextGuard complements provider and semantic caches, and works alongside promp
|
|
|
80
80
|
| Provider prompt/context caching | Reusing stable prompt prefixes. | Complementary; ContextGuard helps keep the changing tail of context smaller and cleaner, `context-guard-audit` can flag likely volatile prefix layouts, and `context-guard cost` can warn when an Anthropic request is likely to cache-write instead of cache-read. |
|
|
81
81
|
| Semantic response cache | Reusing answers to identical or similar requests. | Complementary; ContextGuard does not serve cached AI answers. |
|
|
82
82
|
| Prompt/context compression | Shortening text that is already selected for the model. | Adjacent; ContextGuard trims and summarizes local output, but does not promise lossless semantic compression. |
|
|
83
|
-
| Experimental planners and local runtimes | Default-off and explicit-command-only; covers local-proxy plans
|
|
83
|
+
| Experimental planners and local runtimes | Default-off and explicit-command-only; covers plan-only `image-context-pack` and `semantic-checkpoint` gates plus local-proxy plans/gate records and narrow local runtimes for caller-supplied context-diff, visual evidence-pack, learned-compression, and self-hosted metrics evidence. | `image-context-pack` and `semantic-checkpoint` are dry-run planning gates only: they do not emit replacements, call models/providers, proxy traffic, write files, or make hosted token/cost savings claims. `semantic-checkpoint` additionally requires exact context fallback/re-expand metadata, provenance review acknowledgement, provider-boundary acknowledgement, protected-zone denial, and missed-context notes before the JSON payload reports readiness. The local proxy `record` command starts no listener and forwards no traffic; `serve local-proxy` binds and forwards only literal loopback IPs for one bounded request; `--response-sandbox` can replace a safe UTF-8 upstream body with a compact local artifact rehydration envelope. Compressor/model execution, OCR/crop services, external forwarding, credential persistence, runtime checkpoint replacement, and hosted-savings claims stay out of scope until a separate evidence gate and future PR allow them. |
|
|
84
84
|
| ContextGuard | Avoiding unnecessary files, logs, repeated failures, and noisy output before they enter agent context. | Local guardrails, reversible artifacts, and measurement. |
|
|
85
85
|
|
|
86
86
|
Related patterns that informed the design:
|
|
@@ -119,7 +119,7 @@ If you need a savings claim, measure it on your own tasks:
|
|
|
119
119
|
- It does not execute command manifests as code or trust arbitrary `PATH`/current-working-directory helpers during setup or packaged smoke checks.
|
|
120
120
|
- It does not replace real before/after measurement when you need a savings claim.
|
|
121
121
|
- Local RAM/disk receipts can help reduce what you send next, but they do **not** replace Anthropic's provider prompt cache or guarantee cache hits. Recheck Anthropic prompt-caching and pricing docs before release or billing claims: https://docs.anthropic.com/en/build-with-claude/prompt-caching and https://platform.claude.com/docs/en/about-claude/pricing.
|
|
122
|
-
- Experimental helpers are mostly dry-run checker/planner surfaces, including a design-only external-forwarding opt-in gate. Explicit local runtimes exist only for caller-supplied context-diff replacement payloads, caller-supplied visual crop/OCR evidence packs, caller-supplied learned-compression prose candidates, self-hosted metrics JSONL sidecar records, local-proxy runtime-gate JSONL records, and one-shot `serve local-proxy` loopback forwarding with a private ready-file nonce, optional `--response-sandbox` compact artifact envelopes for safe UTF-8 responses, plus optional shifted-cost diagnostic JSONL rows for successful forwarded requests.
|
|
122
|
+
- Experimental helpers are mostly dry-run checker/planner surfaces, including plan-only `image-context-pack` and `semantic-checkpoint` evaluation gates and a design-only external-forwarding opt-in gate. Explicit local runtimes exist only for caller-supplied context-diff replacement payloads, caller-supplied visual crop/OCR evidence packs, caller-supplied learned-compression prose candidates, self-hosted metrics JSONL sidecar records, local-proxy runtime-gate JSONL records, and one-shot `serve local-proxy` loopback forwarding with a private ready-file nonce, optional `--response-sandbox` compact artifact envelopes for safe UTF-8 responses, plus optional shifted-cost diagnostic JSONL rows for successful forwarded requests.
|
|
123
123
|
- ContextGuard does not ship learned/synthetic compressor execution, embeddings, rerankers, model calls, generated replacement text, screenshot capture, image cropping, OCR execution, image parsing, external OCR/image services, self-hosted KV/latent inference optimization beyond explicit local metrics recording, or broader proxy forwarding beyond literal-loopback, one-request HTTP forwarding with credential material blocked.
|
|
124
124
|
- It does not alias the old `/claude-token-optimizer:*` Claude Code slash-command namespace. Use `/context-guard:*` after installing this plugin.
|
|
125
125
|
|
|
@@ -441,6 +441,8 @@ context-guard experiments plan context-diff-compaction --json < change.diff
|
|
|
441
441
|
context-guard experiments emit context-diff-compaction --receipt-id <artifact-id> --reexpand-command "context-guard-artifact get <artifact-id> --full" --replacement-file compact-diff.txt --json < change.diff
|
|
442
442
|
context-guard experiments plan visual-crop-ocr --json --full-evidence-receipt <id> --crop-label <label> --crop-bounds 0,0,100,100 --image-size 800,600 --missed-context-note "outside crop omitted"
|
|
443
443
|
context-guard experiments emit visual-crop-ocr --json --full-evidence-receipt <id> --crop-label <label> --crop-bounds 0,0,100,100 --image-size 800,600 --ocr-text "visible text" --ocr-confidence 0.9 --ocr-error-note "glyph may be uncertain" --missed-context-note "outside crop omitted"
|
|
444
|
+
context-guard experiments plan image-context-pack --json --exact-text-fallback-receipt <id> --reexpand-command "context-guard-artifact get <id> --full" --provider-boundary-ack --protected-zone-policy deny --missed-context-note "omitted text remains retrievable before any future image pack is used" --image-size 800,600 --packed-image-size 400,300
|
|
445
|
+
context-guard experiments plan semantic-checkpoint --json --goal "preserve current task state for review" --constraint "do not rewrite protected evidence" --decision "ship plan-only semantic-checkpoint gate first" --open-task "verify exact fallback before any checkpoint is used" --evidence-handle "roadmap=contextguard-artifact:0123456789abcdef" --missing-provenance-note "none known after review" --unresolved-question "which provenance handle fields become mandatory later" --exact-context-fallback-receipt 0123456789abcdef --reexpand-command "context-guard-artifact get 0123456789abcdef --full" --provider-boundary-ack --protected-zone-policy deny --missed-context-note "raw transcript remains retrievable before checkpoint metadata is used"
|
|
444
446
|
context-guard experiments plan learned-compression --json --sanitized --trusted-source --exact-fallback-receipt <id> --reexpand-command "context-guard-artifact get <id> --full" < sanitized-prose.txt
|
|
445
447
|
context-guard experiments emit learned-compression --json --sanitized --trusted-source --exact-fallback-receipt <id> --reexpand-command "context-guard-artifact get <id> --full" --replacement-file compact-prose.txt < sanitized-prose.txt
|
|
446
448
|
context-guard experiments plan self-hosted-metrics-ledger --json --latency-ms 123.5 --peak-memory-mb 2048 --quality-score 0.98
|
|
@@ -453,6 +455,10 @@ context-guard experiments enable output-receipt-trim --root .
|
|
|
453
455
|
context-guard experiments disable output-receipt-trim --root .
|
|
454
456
|
```
|
|
455
457
|
|
|
458
|
+
`plan image-context-pack` is intentionally plan-only and side-effect free: it emits deterministic JSON metadata, does not render or parse images, does not run OCR, does not store binary image artifacts, does not call providers or proxy traffic, and does not duplicate `visual-crop-ocr`. Any future omission of exact text must keep a verified exact text fallback, deny protected zones, record missed-context guardrails, and treat image/request byte reductions as proxy evidence until provider-measured matched tasks prove token/cost deltas.
|
|
459
|
+
|
|
460
|
+
`plan semantic-checkpoint` is also plan-only/eval-only. Its CLI flags are optional so incomplete plans can produce reviewer JSON, but missing readiness fields block the JSON payload until exact context fallback is present. Ready plans require a goal, exact fallback receipt, a local re-expand command shaped as `context-guard-artifact get <id> --full` or `context-guard artifact get <id> --full`, provider-boundary acknowledgement, protected-zone policy `deny`, missed-context notes, and provenance review notes. `--missing-provenance-note` may be a review acknowledgement such as `none known after review`. The gate has no `emit`, `record`, or `serve` runtime, no `context-guard-semantic-checkpoint` binary, no file writes, transcript or prompt edits, model/provider/network calls, replacement context, or hosted token/cost savings claim.
|
|
461
|
+
|
|
456
462
|
The local-proxy examples are intentionally split by side effect:
|
|
457
463
|
|
|
458
464
|
- `plan local-proxy` produces advisory metadata only; it does not enable forwarding.
|
|
@@ -463,12 +469,14 @@ The local-proxy examples are intentionally split by side effect:
|
|
|
463
469
|
|
|
464
470
|
By default, project settings are stored in `.context-guard/experiments.json`. Use `--config <path>` only for an explicit project-local override. Experiment metadata includes risk level, gate requirements, explicit command/flag surfaces, and claim boundaries so hosted API token/cost savings are not claimed without provider-measured matched-task evidence. `experiments enable` records intent only; it does not run helpers, remove the need for their explicit flags, or permit replacing content without exact receipt/re-expand evidence.
|
|
465
471
|
|
|
466
|
-
Shipped experimental checker/planner surfaces, plus explicit local context-diff, visual evidence, learned-candidate, metrics,
|
|
472
|
+
Shipped experimental checker/planner surfaces, plus explicit local context-diff, visual evidence, learned-candidate, metrics, proxy-gate record runtimes, and the plan-only image-context-pack and semantic-checkpoint gates, are intentionally narrow:
|
|
467
473
|
|
|
468
474
|
| Planner/checker/runtime | What it emits | Hard boundary |
|
|
469
475
|
| --- | --- | --- |
|
|
470
476
|
| `context-diff-compaction` | Dry-run diff advice plus an explicit `emit ... --receipt-id ... --reexpand-command ...` runtime for caller-supplied compact replacements. | `plan` emits no replacement. `emit` requires reviewable hunks, exact local artifact re-expand metadata whose stored content matches the input diff, and a smaller caller-supplied replacement; ContextGuard does not generate semantic compression or support hosted token/cost savings claims. |
|
|
471
477
|
| `visual-crop-ocr` | Dry-run visual evidence advice plus an explicit `emit visual-crop-ocr` runtime for caller-supplied evidence packs. | `emit` requires a full visual evidence receipt, missed-context note, and complete user-supplied crop and/or OCR evidence; ContextGuard does not capture screenshots, crop images, run OCR, parse images, call external services, write files, or support hosted token/cost savings claims. |
|
|
478
|
+
| `image-context-pack` | Pxpipe-inspired dry-run plan metadata only for future image/context packing evaluation. | `plan` emits no image, replacement, evidence pack, binary artifact, ledger, listener, or proxy. It requires exact text fallback receipt/re-expand metadata before omitted text is used, protected-zone denial, missed-context notes, and an explicit provider boundary acknowledgement for provider/model measured matched-task evidence. `visual-crop-ocr` remains the caller-supplied visual evidence-pack surface; `image-context-pack` is not a duplicate emitter or verified exact binary/image fallback. |
|
|
479
|
+
| `semantic-checkpoint` | Plan-only/eval-only checkpoint readiness metadata for preserving task state during review. | `plan` emits deterministic JSON metadata only. CLI flags are optional, but readiness is blocked in JSON until exact context fallback, local re-expand metadata, provider-boundary acknowledgement, protected-zone denial, missed-context note, and provenance review note are present. `--missing-provenance-note` may be a review acknowledgement such as `none known after review`. It writes no files, edits no transcript or prompt, calls no model/provider/network, emits no replacement context, has no `emit`/`record`/`serve` runtime or new binary, and makes no hosted token/cost savings claim. |
|
|
472
480
|
| `learned-compression` | Deny-by-default policy checks plus an explicit `emit learned-compression` runtime for caller-supplied compact prose candidates with verified exact fallback content. | `emit` requires sanitized trusted prose, protected-signal denial, a verified local fallback artifact matching the input, and a smaller caller-supplied prose candidate; ContextGuard does not run compressors, embeddings, rerankers, model calls, subprocesses, external services, generated replacement text, or hosted savings claims. |
|
|
473
481
|
| `self-hosted-metrics-ledger` | Dry-run preview plus an explicit `record ... --ledger-jsonl` runtime for local/model-server latency, memory, quality, energy, throughput, and local-cost metrics. | The dry-run preview does not write a ledger; the explicit record command writes only local JSONL sidecars and still does not support hosted API token/cost savings claims. |
|
|
474
482
|
| `local-proxy` | Localhost-only advisory metadata, design-only `plan local-proxy-external-forwarding` review for future external forwarding, an explicit `record local-proxy-runtime-gate --ledger-jsonl` runtime for one local gate row, an explicit one-shot `serve local-proxy` loopback forwarding MVP, optional `--response-sandbox` compact artifact envelopes, and optional `--diagnostic-ledger-jsonl` shifted-cost diagnostics for successful forwarded requests. | `plan` writes no ledger. `record` writes only after localhost-only metadata and `--runtime-gate-ack`; it starts no listener, forwards no traffic, and performs no DNS lookup. `serve` additionally requires `--forwarding-gate-ack --once`, a private `--ready-file` nonce handoff, literal loopback bind/target IPs, nonzero ports, bounded bytes/timeouts, and credential-free requests; it performs no external forwarding, no CONNECT/TLS proxying, no API-key persistence, and no hosted-savings claim. `--response-sandbox` can store safe UTF-8 response text as a sanitized local artifact receipt and return a compact envelope with redacted rehydration command templates; it does not claim hosted token/cost savings. `--diagnostic-ledger-jsonl` writes only successful-forward diagnostics with no raw headers/bodies and no hosted-savings claim. `plan local-proxy-external-forwarding` emits threat-model/allowlist/redaction/provider-evidence design metadata only and still performs no DNS lookup, external service call, traffic forwarding, credential persistence, or hosted-savings claim. |
|
|
@@ -481,6 +489,8 @@ ContextGuard does not yet ship:
|
|
|
481
489
|
|
|
482
490
|
- learned/synthetic compressor execution or generated replacement text beyond the caller-supplied learned candidate emitter
|
|
483
491
|
- generated crop/OCR or visual-token pruning runtime beyond the caller-supplied visual evidence-pack emitter
|
|
492
|
+
- generated image-context-pack renderers, binary/image artifact fallback, or pxpipe-style proxy/runtime beyond the plan-only evaluation gate
|
|
493
|
+
- semantic-checkpoint emit/record/serve runtime, replacement context, file-writing checkpoint store, transcript/prompt editing, provider/model/network-backed checkpointing, or a new `context-guard-semantic-checkpoint` binary
|
|
484
494
|
- self-hosted KV/latent optimization beyond explicit local metrics recording
|
|
485
495
|
- external, daemon, or credential-bearing proxy forwarding beyond the one-shot literal-loopback local proxy MVP
|
|
486
496
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ictechgy/context-guard",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.14",
|
|
4
4
|
"description": "ContextGuard CLI helpers for keeping AI coding agent context focused and local-first.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://github.com/ictechgy/context-guard#readme",
|
|
@@ -119,7 +119,11 @@ brief 모드는 코딩 에이전트가 군더더기를 줄이도록 요청하되
|
|
|
119
119
|
|
|
120
120
|
ContextGuard는 모델 토큰을 줄이기 위해 작업을 외부 AI 서비스로 전송하지 않습니다. 모든 헬퍼 명령은 로컬에서 동작합니다. 로컬 RAM/디스크 보관본은 다음에 보낼 컨텍스트를 줄이는 데 도움될 수 있지만 provider prompt cache를 대체하지 않습니다. Anthropic 배포나 청구 설명 전에는 공식 prompt caching/pricing 문서를 다시 확인하세요: https://docs.anthropic.com/en/build-with-claude/prompt-caching 및 https://platform.claude.com/docs/en/about-claude/pricing.
|
|
121
121
|
|
|
122
|
-
미래 learned, self-hosted 최적화 아이디어는 [`research/experimental-token-reduction-radar.md`](https://github.com/ictechgy/context-guard/blob/main/research/experimental-token-reduction-radar.md)에 gated experiment로 기록하며, fixture-only 시작 예시는 [`docs/experimental-benchmark-fixtures.md`](https://github.com/ictechgy/context-guard/blob/main/docs/experimental-benchmark-fixtures.md)에 둡니다. learned compression은 `context-guard experiments plan learned-compression` dry-run checker와 명시적 `context-guard experiments emit learned-compression` caller-supplied candidate emitter만 shipped 상태이고, self-hosted-metrics-ledger는 dry-run preview와 명시적 `context-guard experiments record self-hosted-metrics-ledger` local JSONL record를 제공하며, dry-run preview는 ledger 파일을 쓰지 않습니다. visual crop/OCR은 caller-supplied evidence-pack emit, context-diff는 verified-receipt caller-supplied replacement emit만 제공합니다. local proxy는 `context-guard experiments plan local-proxy` localhost-only dry-run advisory plan, design-only `context-guard experiments plan local-proxy-external-forwarding` gate, 명시적 `context-guard experiments record local-proxy-runtime-gate --ledger-jsonl ...` gate row record, private ready-file nonce가 필요한 one-shot `context-guard experiments serve local-proxy` loopback forwarding MVP와 successful forwarded request용 optional shifted-cost diagnostic JSONL row만 shipped 상태입니다. record는 no listener/no traffic forwarding/no DNS lookup/no external service/no API-key persistence boundary를 유지하고, serve는 private ready-file nonce, literal loopback IP, `--once`, credential-free request만 허용하고 CONNECT/TLS proxying도 지원하지 않습니다. `--response-sandbox`는 safe UTF-8 response text만 local artifact receipt로 저장하고 raw body 대신 redacted rehydration command template가 담긴 compact envelope를 돌려주며 hosted token/cost savings claim은 아닙니다. `--diagnostic-ledger-jsonl`은 successful forwarded request 뒤에만 진단 row를 쓰며 raw header/body나 hosted-savings evidence를 저장하지 않습니다. `plan local-proxy-external-forwarding`은 threat model, HTTPS allowlist, credential redaction, provider-evidence boundary를 점검하는 dry-run design gate이고 listener, DNS lookup, external service call, traffic forwarding, credential persistence, external proxy forwarding runtime, hosted savings claim을 제공하지 않습니다. learned/synthetic compressor 실행·embedding·reranker·model call·생성형 replacement, generated OCR/crop
|
|
122
|
+
미래 learned, self-hosted 최적화 아이디어는 [`research/experimental-token-reduction-radar.md`](https://github.com/ictechgy/context-guard/blob/main/research/experimental-token-reduction-radar.md)에 gated experiment로 기록하며, fixture-only 시작 예시는 [`docs/experimental-benchmark-fixtures.md`](https://github.com/ictechgy/context-guard/blob/main/docs/experimental-benchmark-fixtures.md)에 둡니다. learned compression은 `context-guard experiments plan learned-compression` dry-run checker와 명시적 `context-guard experiments emit learned-compression` caller-supplied candidate emitter만 shipped 상태이고, self-hosted-metrics-ledger는 dry-run preview와 명시적 `context-guard experiments record self-hosted-metrics-ledger` local JSONL record를 제공하며, dry-run preview는 ledger 파일을 쓰지 않습니다. visual crop/OCR은 caller-supplied evidence-pack emit, image-context-pack은 pxpipe-inspired image/context packing 평가를 위한 plan-only dry-run gate, semantic-checkpoint는 review용 task-state checkpoint 계획을 위한 plan-only/eval-only gate, context-diff는 verified-receipt caller-supplied replacement emit만 제공합니다. image-context-pack은 exact text artifact fallback, protected-zone denial, provider-boundary acknowledgement for provider-measured matched tasks, missed-context guardrail, 그리고 visual-crop-ocr이 기존 caller-supplied visual evidence-pack surface라는 plan output 확인이 필요하며, image rendering, OCR 실행, image parsing, model/provider call, proxy traffic, binary artifact 저장, replacement evidence 출력, hosted token/cost savings claim을 하지 않습니다. semantic-checkpoint는 CLI flag가 optional이지만 JSON readiness에서 exact context fallback/re-expand, provider-boundary ack, protected-zone policy `deny`, missed-context note, provenance review note가 없으면 blocked이며, `--missing-provenance-note`는 `none known after review` 같은 검토 확인 문구일 수 있습니다. 허용되는 re-expand command는 `context-guard-artifact get <id> --full` 또는 `context-guard artifact get <id> --full` 형태이고, emit/record/serve runtime, 새 `context-guard-semantic-checkpoint` binary, file write, transcript/prompt edit, model/provider/network call, replacement context, hosted token/cost savings claim은 없습니다. local proxy는 `context-guard experiments plan local-proxy` localhost-only dry-run advisory plan, design-only `context-guard experiments plan local-proxy-external-forwarding` gate, 명시적 `context-guard experiments record local-proxy-runtime-gate --ledger-jsonl ...` gate row record, private ready-file nonce가 필요한 one-shot `context-guard experiments serve local-proxy` loopback forwarding MVP와 successful forwarded request용 optional shifted-cost diagnostic JSONL row만 shipped 상태입니다. record는 no listener/no traffic forwarding/no DNS lookup/no external service/no API-key persistence boundary를 유지하고, serve는 private ready-file nonce, literal loopback IP, `--once`, credential-free request만 허용하고 CONNECT/TLS proxying도 지원하지 않습니다. `--response-sandbox`는 safe UTF-8 response text만 local artifact receipt로 저장하고 raw body 대신 redacted rehydration command template가 담긴 compact envelope를 돌려주며 hosted token/cost savings claim은 아닙니다. `--diagnostic-ledger-jsonl`은 successful forwarded request 뒤에만 진단 row를 쓰며 raw header/body나 hosted-savings evidence를 저장하지 않습니다. `plan local-proxy-external-forwarding`은 threat model, HTTPS allowlist, credential redaction, provider-evidence boundary를 점검하는 dry-run design gate이고 listener, DNS lookup, external service call, traffic forwarding, credential persistence, external proxy forwarding runtime, hosted savings claim을 제공하지 않습니다. learned/synthetic compressor 실행·embedding·reranker·model call·생성형 replacement, generated OCR/crop, visual-token pruning, plan-only image-context-pack dry-run gate를 넘어선 image-context-pack rendering/runtime, plan-only semantic-checkpoint gate를 넘어선 emit/record/serve runtime이나 replacement context/file-writing checkpoint store/transcript-prompt edit/provider-backed checkpointing, self-hosted KV/latent runtime 최적화, one-shot literal-loopback local proxy MVP를 넘어선 external/daemon/credential-bearing proxy forwarding runtime은 shipped가 아닙니다. 이 radar와 fixture는 provider가 측정한 matched-task 근거 없이 hosted API 절감을 주장하지 않습니다. Radar의 later-roadmap gate는 neural/semantic compression, trust-tiered injection-aware compression, generated visual-token reduction, broader local proxy forwarding constraint도 별도 미래 PR이 gate를 통과하기 전까지 experimental/non-shipped로 묶습니다.
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
context-guard experiments plan semantic-checkpoint --json --goal "preserve current task state for review" --constraint "do not rewrite protected evidence" --decision "ship plan-only semantic-checkpoint gate first" --open-task "verify exact fallback before any checkpoint is used" --evidence-handle "roadmap=contextguard-artifact:0123456789abcdef" --missing-provenance-note "none known after review" --unresolved-question "which provenance handle fields become mandatory later" --exact-context-fallback-receipt 0123456789abcdef --reexpand-command "context-guard-artifact get 0123456789abcdef --full" --provider-boundary-ack --protected-zone-policy deny --missed-context-note "raw transcript remains retrievable before checkpoint metadata is used"
|
|
126
|
+
```
|
|
123
127
|
|
|
124
128
|
교차 에이전트 규칙 스니펫은 안내용입니다. 대상 에이전트가 반드시 따른다고 보장할 수 없으므로, 절감 주장이 필요하면 실제 전후 동작을 직접 측정하세요.
|
|
125
129
|
|
|
@@ -128,7 +128,7 @@ These helpers reduce common sources of context bloat, but they do not guarantee
|
|
|
128
128
|
|
|
129
129
|
ContextGuard also does not send work to external AI providers to save model tokens. All helper commands run locally. Local RAM/disk receipts can reduce what you choose to send, but they do not replace a provider prompt cache. Before release or billing claims for Anthropic, recheck the official prompt-caching and pricing docs: https://docs.anthropic.com/en/build-with-claude/prompt-caching and https://platform.claude.com/docs/en/about-claude/pricing.
|
|
130
130
|
|
|
131
|
-
Future learned, multimodal, and self-hosted optimization ideas are tracked in [`research/experimental-token-reduction-radar.md`](https://github.com/ictechgy/context-guard/blob/main/research/experimental-token-reduction-radar.md), with fixture-only starters in [`docs/experimental-benchmark-fixtures.md`](https://github.com/ictechgy/context-guard/blob/main/docs/experimental-benchmark-fixtures.md). ContextGuard ships dry-run planners/checkers for local-proxy advisory plans and design-only external-forwarding gates, plus narrow explicit local runtimes for caller-supplied context-diff replacement payloads, caller-supplied visual crop/OCR evidence packs, caller-supplied learned-compression prose candidates, self-hosted metrics JSONL sidecar records, local-proxy runtime-gate JSONL records, one-shot `serve local-proxy` loopback forwarding with a private ready-file nonce, optional `--response-sandbox` compact artifact envelopes for safe UTF-8 responses, and optional shifted-cost diagnostic JSONL rows for successful forwarded requests. Learned/synthetic compressor execution beyond the caller-supplied candidate emitter, embeddings, rerankers, model calls, generated replacement text, screenshot capture, image cropping, OCR execution, image parsing, external OCR/image services, output-file evidence writes, self-hosted KV/latent runtime optimization beyond explicit local metrics recording, and external/daemon/hostname-DNS, credential-bearing, or external proxy forwarding beyond literal-loopback one-request HTTP forwarding are not shipped. That radar and the fixtures do not claim hosted API savings without provider-measured matched-task evidence. The radar's later-roadmap gates also keep neural/semantic compression, trust-tiered injection-aware compression, generated visual-token reduction, and broader local proxy forwarding constraints experimental/non-shipped until a separate future PR satisfies those gates.
|
|
131
|
+
Future learned, multimodal, and self-hosted optimization ideas are tracked in [`research/experimental-token-reduction-radar.md`](https://github.com/ictechgy/context-guard/blob/main/research/experimental-token-reduction-radar.md), with fixture-only starters in [`docs/experimental-benchmark-fixtures.md`](https://github.com/ictechgy/context-guard/blob/main/docs/experimental-benchmark-fixtures.md). ContextGuard ships dry-run planners/checkers for a plan-only `image-context-pack` evaluation gate, local-proxy advisory plans, and design-only external-forwarding gates, plus narrow explicit local runtimes for caller-supplied context-diff replacement payloads, caller-supplied visual crop/OCR evidence packs, caller-supplied learned-compression prose candidates, self-hosted metrics JSONL sidecar records, local-proxy runtime-gate JSONL records, one-shot `serve local-proxy` loopback forwarding with a private ready-file nonce, optional `--response-sandbox` compact artifact envelopes for safe UTF-8 responses, and optional shifted-cost diagnostic JSONL rows for successful forwarded requests. Learned/synthetic compressor execution beyond the caller-supplied candidate emitter, embeddings, rerankers, model calls, generated replacement text, screenshot capture, image cropping, OCR execution, image parsing, external OCR/image services, output-file evidence writes, generated image-context-pack renderers, binary/image artifact fallback, pxpipe-style proxy/runtime, self-hosted KV/latent runtime optimization beyond explicit local metrics recording, and external/daemon/hostname-DNS, credential-bearing, or external proxy forwarding beyond literal-loopback one-request HTTP forwarding are not shipped. That radar and the fixtures do not claim hosted API savings without provider-measured matched-task evidence. The radar's later-roadmap gates also keep neural/semantic compression, trust-tiered injection-aware compression, generated visual-token reduction, and broader local proxy forwarding constraints experimental/non-shipped until a separate future PR satisfies those gates.
|
|
132
132
|
|
|
133
133
|
## Experimental opt-ins
|
|
134
134
|
|
|
@@ -141,6 +141,8 @@ context-guard experiments plan context-diff-compaction --json < change.diff
|
|
|
141
141
|
context-guard experiments emit context-diff-compaction --receipt-id <artifact-id> --reexpand-command "context-guard-artifact get <artifact-id> --full" --replacement-file compact-diff.txt --json < change.diff
|
|
142
142
|
context-guard experiments plan visual-crop-ocr --json --full-evidence-receipt <id> --crop-label <label> --crop-bounds 0,0,100,100 --image-size 800,600 --missed-context-note "outside crop omitted"
|
|
143
143
|
context-guard experiments emit visual-crop-ocr --json --full-evidence-receipt <id> --crop-label <label> --crop-bounds 0,0,100,100 --image-size 800,600 --ocr-text "visible text" --ocr-confidence 0.9 --ocr-error-note "glyph may be uncertain" --missed-context-note "outside crop omitted"
|
|
144
|
+
context-guard experiments plan image-context-pack --json --exact-text-fallback-receipt <id> --reexpand-command "context-guard-artifact get <id> --full" --provider-boundary-ack --protected-zone-policy deny --missed-context-note "omitted text remains retrievable before any future image pack is used" --image-size 800,600 --packed-image-size 400,300
|
|
145
|
+
context-guard experiments plan semantic-checkpoint --json --goal "preserve current task state for review" --constraint "do not rewrite protected evidence" --decision "ship plan-only semantic-checkpoint gate first" --open-task "verify exact fallback before any checkpoint is used" --evidence-handle "roadmap=contextguard-artifact:0123456789abcdef" --missing-provenance-note "none known after review" --unresolved-question "which provenance handle fields become mandatory later" --exact-context-fallback-receipt 0123456789abcdef --reexpand-command "context-guard-artifact get 0123456789abcdef --full" --provider-boundary-ack --protected-zone-policy deny --missed-context-note "raw transcript remains retrievable before checkpoint metadata is used"
|
|
144
146
|
context-guard experiments plan learned-compression --json --sanitized --trusted-source --exact-fallback-receipt <id> --reexpand-command "context-guard-artifact get <id> --full" < sanitized-prose.txt
|
|
145
147
|
context-guard experiments emit learned-compression --json --sanitized --trusted-source --exact-fallback-receipt <id> --reexpand-command "context-guard-artifact get <id> --full" --replacement-file compact-prose.txt < sanitized-prose.txt
|
|
146
148
|
context-guard experiments plan self-hosted-metrics-ledger --json --latency-ms 123.5 --peak-memory-mb 2048 --quality-score 0.98
|
|
@@ -153,7 +155,11 @@ context-guard experiments enable output-receipt-trim --root .
|
|
|
153
155
|
context-guard experiments disable output-receipt-trim --root .
|
|
154
156
|
```
|
|
155
157
|
|
|
156
|
-
|
|
158
|
+
`image-context-pack` is a plan-only/dry-run gate for pxpipe-inspired image/context packing evaluation. It requires exact text artifact fallback, protected-zone denial, provider-boundary acknowledgement for provider-measured matched tasks, missed-context guardrails, and acknowledgement in the plan output that `visual-crop-ocr` is the existing caller-supplied visual evidence-pack surface. It does not render images, run OCR, call models/providers, proxy traffic, store binary artifacts, emit replacement evidence, or support hosted token/cost savings.
|
|
159
|
+
|
|
160
|
+
`semantic-checkpoint` is a plan-only/eval-only gate for reviewable task-state checkpoint planning. Its flags are optional at the CLI so incomplete dry runs can return JSON, but readiness remains blocked in the JSON payload until the plan includes a goal, exact fallback receipt, local re-expand command, provider-boundary acknowledgement, protected-zone policy `deny`, missed-context note, and provenance review note. `--missing-provenance-note` can be a review acknowledgement such as `none known after review`; allowed local re-expand shapes are `context-guard-artifact get <id> --full` and `context-guard artifact get <id> --full`. It has no `emit`, `record`, or `serve` runtime, no new `context-guard-semantic-checkpoint` binary, writes no files, edits no transcript or prompt, calls no model/provider/network, emits no replacement context, and makes no hosted token/cost savings claim.
|
|
161
|
+
|
|
162
|
+
Use `--config <path>` only for an explicit project-local override. Registry entries include risk, gate requirements, explicit command/flag surfaces, and claim boundaries; hosted API token/cost savings still require provider-measured matched-task evidence. The registry can discover existing explicit-flag experiments such as `context-guard-trim-output --digest ... --artifact-receipt` and `context-guard-compress --protected-policy`, run dry-run advisory planners such as `context-guard experiments plan context-diff-compaction`, `context-guard experiments plan visual-crop-ocr`, `context-guard experiments plan learned-compression`, `context-guard experiments plan semantic-checkpoint`, `context-guard experiments plan self-hosted-metrics-ledger`, `context-guard experiments plan local-proxy`, and design-only `context-guard experiments plan local-proxy-external-forwarding`, and run explicit local runtimes such as `context-guard experiments emit context-diff-compaction ...`, `context-guard experiments emit visual-crop-ocr ...`, `context-guard experiments emit learned-compression ...`, `context-guard experiments record self-hosted-metrics-ledger ...`, `context-guard experiments record local-proxy-runtime-gate ...`, `context-guard experiments serve local-proxy ...`, and successful-forward `context-guard experiments serve local-proxy --diagnostic-ledger-jsonl ...` diagnostics. The context-diff emit runtime only emits caller-supplied compact replacements when reviewable hunks, exact local artifact re-expand metadata whose stored content matches the input diff, and a smaller replacement are present; it does not generate semantic compression or permit hosted savings claims. The visual lane ships a dry-run planner plus an explicit local evidence-pack emitter: both use only caller-supplied full-evidence receipts, crop metadata, OCR text, confidence/error notes, and missed-context notes; screenshot capture, image cropping, OCR execution, image parsing, external OCR/image services, output-file writes, and hosted savings claims are not shipped. The learned-compression lane ships a deny-by-default dry-run policy check plus an explicit local candidate emitter for caller-supplied compact prose with verified exact fallback content: learned/synthetic compressor execution, embeddings, rerankers, model calls, subprocesses, external services, generated replacement text, and hosted savings claims are not shipped. The semantic-checkpoint lane ships only the plan/eval gate above: no runtime emit/record/serve surface, file-writing checkpoint store, transcript/prompt edit, provider/model/network-backed checkpointing, replacement context, new binary, or hosted savings claim is shipped. The self-hosted metrics planner emits a dry-run ledger-compatible preview for explicit local/model-server latency, memory, quality, energy, throughput, and local-cost metrics; the dry-run preview does not write a ledger, while `context-guard experiments record self-hosted-metrics-ledger --ledger-jsonl ...` writes only local JSONL sidecars and still does not permit hosted API token/cost savings claims. The local-proxy planner emits localhost-only advisory metadata only, while `context-guard experiments record local-proxy-runtime-gate --ledger-jsonl ...` appends one local gate row only after localhost-only metadata and `--runtime-gate-ack`: it starts no listener, forwards no traffic, and performs no DNS lookup. `context-guard experiments serve local-proxy ...` is the separate forwarding MVP: it requires `--forwarding-gate-ack --once`, a private `--ready-file` nonce handoff, literal loopback bind/target IPs, no hostname DNS targets, nonzero ports, byte/time limits, and credential-free requests; it performs no external forwarding, no CONNECT/TLS proxying, no API-key persistence, and no hosted-savings claim. `--response-sandbox` can store safe UTF-8 response text as a sanitized local artifact receipt and return a compact envelope with redacted rehydration command templates; it does not claim hosted token/cost savings. `--diagnostic-ledger-jsonl` writes one shifted-cost diagnostic row only after a successful forwarded request, with no raw headers/bodies and no hosted-savings evidence. `plan local-proxy-external-forwarding` emits threat-model/allowlist/redaction/provider-evidence design metadata only and still starts no listener, performs no DNS lookup, calls no external service, forwards no traffic, persists no credentials, and does not ship an external proxy forwarding runtime. `experiments enable` records intent only; it does not run those helpers, remove the need for their explicit flags, or permit replacing content without exact receipt/re-expand evidence.
|
|
157
163
|
|
|
158
164
|
Cross-agent rule snippets are advisory: the target agent may ignore them, so measure actual before/after behavior when you need a savings claim.
|
|
159
165
|
|
|
@@ -46,6 +46,7 @@ MAX_VISUAL_OCR_TEXT_BYTES = 64_000
|
|
|
46
46
|
MAX_LEARNED_COMPRESSION_INPUT_BYTES = 128_000
|
|
47
47
|
MAX_LEARNED_COMPRESSION_REPLACEMENT_BYTES = 64_000
|
|
48
48
|
MAX_LEARNED_COMPRESSION_ARTIFACT_METADATA_BYTES = 64_000
|
|
49
|
+
IMAGE_CONTEXT_PACK_MAX_DIMENSION = 16_384
|
|
49
50
|
MAX_SELF_HOSTED_METRICS_INPUT_BYTES = 64_000
|
|
50
51
|
SELF_HOSTED_METRICS_SCHEMA_VERSION = "contextguard.bench.self-hosted-metrics.v1"
|
|
51
52
|
SELF_HOSTED_METRICS_KEY = "self_hosted_metrics"
|
|
@@ -67,6 +68,9 @@ LOCAL_PROXY_DIAGNOSTIC_SCHEMA_VERSION = "contextguard.experiments.local-proxy-fo
|
|
|
67
68
|
LOCAL_PROXY_READY_SCHEMA_VERSION = "contextguard.experiments.local-proxy-ready.v1"
|
|
68
69
|
LOCAL_PROXY_EXTERNAL_DESIGN_SCHEMA_VERSION = "contextguard.experiments.local-proxy-external-forwarding-design.v1"
|
|
69
70
|
LOCAL_PROXY_RESPONSE_SANDBOX_SCHEMA_VERSION = "contextguard.experiments.local-proxy-response-sandbox.v1"
|
|
71
|
+
IMAGE_CONTEXT_PACK_PLAN_SCHEMA_VERSION = "contextguard.experiments.image-context-pack-plan.v1"
|
|
72
|
+
SEMANTIC_CHECKPOINT_PLAN_SCHEMA_VERSION = "contextguard.experiments.semantic-checkpoint-plan.v1"
|
|
73
|
+
IMAGE_CONTEXT_PACK_PROVIDER_BOUNDARY = "provider-measured-matched-tasks-required"
|
|
70
74
|
LOCAL_PROXY_DEFAULT_BIND_HOST = "127.0.0.1"
|
|
71
75
|
LOCAL_PROXY_DEFAULT_BIND_PORT = 0
|
|
72
76
|
LOCAL_PROXY_DEFAULT_TARGET_HOST = "127.0.0.1"
|
|
@@ -259,6 +263,103 @@ EXPERIMENTS: tuple[Experiment, ...] = (
|
|
|
259
263
|
"OCR confidence/error notes when OCR is present, and missed-context guardrails before human review."
|
|
260
264
|
),
|
|
261
265
|
),
|
|
266
|
+
Experiment(
|
|
267
|
+
id="image-context-pack",
|
|
268
|
+
name="Pxpipe-inspired image context pack planning gate",
|
|
269
|
+
summary=(
|
|
270
|
+
"Plan-only evaluation gate for pxpipe-inspired image/context packing without rendering images, "
|
|
271
|
+
"emitting visual artifacts, or changing runtime behavior."
|
|
272
|
+
),
|
|
273
|
+
stability="experimental",
|
|
274
|
+
default_enabled=False,
|
|
275
|
+
risk_level="high",
|
|
276
|
+
claim_boundary=(
|
|
277
|
+
"Image/request byte reductions are proxy evidence only; hosted token/cost savings require "
|
|
278
|
+
"provider-measured matched successful tasks."
|
|
279
|
+
),
|
|
280
|
+
gate_requirements=(
|
|
281
|
+
"explicit opt-in",
|
|
282
|
+
"verified exact text artifact fallback before omitted text is used",
|
|
283
|
+
"protected-zone denial",
|
|
284
|
+
"provider/model measurement boundary",
|
|
285
|
+
"missed-context guardrails",
|
|
286
|
+
"relation to visual-crop-ocr",
|
|
287
|
+
),
|
|
288
|
+
runtime_status="available-plan-only",
|
|
289
|
+
commands=("context-guard experiments plan image-context-pack",),
|
|
290
|
+
opt_in_flags=(
|
|
291
|
+
"plan image-context-pack",
|
|
292
|
+
"--exact-text-fallback-receipt",
|
|
293
|
+
"--reexpand-command",
|
|
294
|
+
"--provider-boundary-ack",
|
|
295
|
+
"--protected-zone-policy deny",
|
|
296
|
+
"--missed-context-note",
|
|
297
|
+
"--image-size",
|
|
298
|
+
"--packed-image-size",
|
|
299
|
+
),
|
|
300
|
+
config_effect=(
|
|
301
|
+
"Registry enablement records project-local intent only; image-context-pack exposes only a deterministic "
|
|
302
|
+
"plan command. It does not add an emit/record/serve runtime, render images, run OCR, call models, proxy "
|
|
303
|
+
"traffic, write binary artifacts, or duplicate the caller-supplied visual-crop-ocr evidence-pack emitter."
|
|
304
|
+
),
|
|
305
|
+
evidence_contract=(
|
|
306
|
+
"The planner requires acknowledgements for explicit evaluation intent, verified exact text artifact fallback, "
|
|
307
|
+
"protected-zone denial, provider/model measured matched-task boundaries, missed-context review, and the fact that "
|
|
308
|
+
"visual-crop-ocr is the existing caller-supplied visual evidence-pack surface, not a verified "
|
|
309
|
+
"exact binary/image fallback."
|
|
310
|
+
),
|
|
311
|
+
),
|
|
312
|
+
|
|
313
|
+
Experiment(
|
|
314
|
+
id="semantic-checkpoint",
|
|
315
|
+
name="Semantic checkpoint planning gate",
|
|
316
|
+
summary=(
|
|
317
|
+
"Plan-only evaluation gate for semantic checkpoint metadata and provenance readiness without "
|
|
318
|
+
"emitting replacement context or changing runtime behavior."
|
|
319
|
+
),
|
|
320
|
+
stability="experimental",
|
|
321
|
+
default_enabled=False,
|
|
322
|
+
risk_level="high",
|
|
323
|
+
claim_boundary=(
|
|
324
|
+
"Semantic checkpoint metadata is dry-run planning evidence only; it cannot replace raw context or "
|
|
325
|
+
"claim hosted token/cost savings without future provider-measured matched successful tasks."
|
|
326
|
+
),
|
|
327
|
+
gate_requirements=(
|
|
328
|
+
"explicit planning goal",
|
|
329
|
+
"verified exact context fallback before checkpoint metadata is used",
|
|
330
|
+
"provider/model measurement boundary",
|
|
331
|
+
"protected-zone denial",
|
|
332
|
+
"missed-context guardrails",
|
|
333
|
+
"provenance review acknowledgement",
|
|
334
|
+
),
|
|
335
|
+
runtime_status="available-plan-only",
|
|
336
|
+
commands=("context-guard experiments plan semantic-checkpoint",),
|
|
337
|
+
opt_in_flags=(
|
|
338
|
+
"plan semantic-checkpoint",
|
|
339
|
+
"--goal",
|
|
340
|
+
"--constraint",
|
|
341
|
+
"--decision",
|
|
342
|
+
"--open-task",
|
|
343
|
+
"--evidence-handle",
|
|
344
|
+
"--missing-provenance-note",
|
|
345
|
+
"--unresolved-question",
|
|
346
|
+
"--exact-context-fallback-receipt",
|
|
347
|
+
"--reexpand-command",
|
|
348
|
+
"--provider-boundary-ack",
|
|
349
|
+
"--protected-zone-policy deny",
|
|
350
|
+
"--missed-context-note",
|
|
351
|
+
),
|
|
352
|
+
config_effect=(
|
|
353
|
+
"Registry enablement records project-local intent only; semantic-checkpoint exposes only a deterministic "
|
|
354
|
+
"plan command. It does not add an emit/record/serve runtime, call models/providers, proxy traffic, write "
|
|
355
|
+
"files, edit prompts/transcripts, replace context, or emit checkpoint candidates."
|
|
356
|
+
),
|
|
357
|
+
evidence_contract=(
|
|
358
|
+
"The planner requires a goal, exact context artifact fallback, protected-zone denial, provider/model "
|
|
359
|
+
"measured matched-task boundary, missed-context notes, and provenance review notes before checkpoint metadata "
|
|
360
|
+
"is ready for plan review; raw context remains authoritative."
|
|
361
|
+
),
|
|
362
|
+
),
|
|
262
363
|
Experiment(
|
|
263
364
|
id="learned-compression",
|
|
264
365
|
name="Learned/synthetic compression candidate gate",
|
|
@@ -1735,6 +1836,308 @@ def command_plan_visual_crop_ocr(args: argparse.Namespace) -> int:
|
|
|
1735
1836
|
return 0
|
|
1736
1837
|
|
|
1737
1838
|
|
|
1839
|
+
def image_context_pack_size_payload(raw: str | None) -> tuple[dict[str, Any] | None, bool]:
|
|
1840
|
+
size = parse_int_tuple(raw, count=2)
|
|
1841
|
+
if raw is None or not str(raw).strip():
|
|
1842
|
+
return None, True
|
|
1843
|
+
if size is None:
|
|
1844
|
+
return None, False
|
|
1845
|
+
width, height = size
|
|
1846
|
+
if width <= 0 or height <= 0:
|
|
1847
|
+
return {"width": width, "height": height}, False
|
|
1848
|
+
return {"width": width, "height": height}, True
|
|
1849
|
+
|
|
1850
|
+
|
|
1851
|
+
def image_context_pack_plan_payload(args: argparse.Namespace) -> dict[str, Any]:
|
|
1852
|
+
receipt_id = args.exact_text_fallback_receipt.strip() if args.exact_text_fallback_receipt else None
|
|
1853
|
+
reexpand_command = args.reexpand_command.strip() if args.reexpand_command else None
|
|
1854
|
+
reexpand_valid, fallback_blocker = valid_learned_reexpand_command(receipt_id, reexpand_command)
|
|
1855
|
+
fallback_blocker_map = {
|
|
1856
|
+
"missing_exact_fallback": "missing_exact_text_fallback",
|
|
1857
|
+
"invalid_reexpand_command": "invalid_exact_text_reexpand_command",
|
|
1858
|
+
}
|
|
1859
|
+
source_size, source_size_valid = image_context_pack_size_payload(args.image_size)
|
|
1860
|
+
packed_size, packed_size_valid = image_context_pack_size_payload(args.packed_image_size)
|
|
1861
|
+
missed_context_notes = clean_values(args.missed_context_note)
|
|
1862
|
+
protected_policy = (args.protected_zone_policy or "deny").strip().lower()
|
|
1863
|
+
|
|
1864
|
+
blockers: list[str] = []
|
|
1865
|
+
if fallback_blocker:
|
|
1866
|
+
blockers.append(fallback_blocker_map.get(fallback_blocker, fallback_blocker))
|
|
1867
|
+
if not args.provider_boundary_ack:
|
|
1868
|
+
blockers.append("missing_provider_measurement_boundary")
|
|
1869
|
+
if not missed_context_notes:
|
|
1870
|
+
blockers.append("missing_missed_context_note")
|
|
1871
|
+
if protected_policy != "deny":
|
|
1872
|
+
blockers.append("protected_zone_denial_required")
|
|
1873
|
+
if not source_size_valid:
|
|
1874
|
+
blockers.append("invalid_image_size")
|
|
1875
|
+
if not packed_size_valid:
|
|
1876
|
+
blockers.append("invalid_packed_image_size")
|
|
1877
|
+
blockers = list(dict.fromkeys(blockers))
|
|
1878
|
+
|
|
1879
|
+
source_area = source_size["width"] * source_size["height"] if source_size and source_size_valid else None
|
|
1880
|
+
packed_area = packed_size["width"] * packed_size["height"] if packed_size and packed_size_valid else None
|
|
1881
|
+
area_delta = source_area - packed_area if source_area is not None and packed_area is not None else None
|
|
1882
|
+
ready = not blockers
|
|
1883
|
+
|
|
1884
|
+
return {
|
|
1885
|
+
"tool": TOOL_NAME,
|
|
1886
|
+
"schema_version": CONFIG_SCHEMA_VERSION,
|
|
1887
|
+
"plan_schema_version": IMAGE_CONTEXT_PACK_PLAN_SCHEMA_VERSION,
|
|
1888
|
+
"experiment_id": "image-context-pack",
|
|
1889
|
+
"mode": "dry_run",
|
|
1890
|
+
"status": "ready_for_plan_review" if ready else "blocked_until_image_context_pack_gate_ready",
|
|
1891
|
+
"plan_only": {
|
|
1892
|
+
"command_advertised": True,
|
|
1893
|
+
"emit_command_available": False,
|
|
1894
|
+
"record_command_available": False,
|
|
1895
|
+
"serve_command_available": False,
|
|
1896
|
+
"runtime_behavior_changed": False,
|
|
1897
|
+
"replacement_or_visual_evidence_emitted": False,
|
|
1898
|
+
},
|
|
1899
|
+
"external_services": {
|
|
1900
|
+
"called": False,
|
|
1901
|
+
"network": False,
|
|
1902
|
+
"model_calls": False,
|
|
1903
|
+
"ocr_service": None,
|
|
1904
|
+
"image_service": None,
|
|
1905
|
+
"proxy_forwarding": False,
|
|
1906
|
+
},
|
|
1907
|
+
"runtime_side_effects": {
|
|
1908
|
+
"files_written": False,
|
|
1909
|
+
"image_rendering": False,
|
|
1910
|
+
"ocr_execution": False,
|
|
1911
|
+
"image_parsing": False,
|
|
1912
|
+
"binary_artifacts_written": False,
|
|
1913
|
+
"proxy_forwarding": False,
|
|
1914
|
+
"stable_runtime_behavior_changed": False,
|
|
1915
|
+
},
|
|
1916
|
+
"text_fallback": {
|
|
1917
|
+
"required": True,
|
|
1918
|
+
"available": bool(reexpand_valid),
|
|
1919
|
+
"receipt_id": receipt_id,
|
|
1920
|
+
"reexpand_command": reexpand_command,
|
|
1921
|
+
"verified": False,
|
|
1922
|
+
"must_be_verified_before_omitted_text_is_used": True,
|
|
1923
|
+
"note": (
|
|
1924
|
+
"This dry-run validates only local receipt/re-expand shape. A future runtime must verify exact "
|
|
1925
|
+
"text artifact content before relying on omitted exact text."
|
|
1926
|
+
),
|
|
1927
|
+
},
|
|
1928
|
+
"protected_zones": {
|
|
1929
|
+
"policy": protected_policy,
|
|
1930
|
+
"override_allowed": False,
|
|
1931
|
+
"denied_classes": [
|
|
1932
|
+
"code",
|
|
1933
|
+
"diffs",
|
|
1934
|
+
"identifiers",
|
|
1935
|
+
"hashes",
|
|
1936
|
+
"paths",
|
|
1937
|
+
"numeric_constants",
|
|
1938
|
+
"json_keys",
|
|
1939
|
+
"stack_frames",
|
|
1940
|
+
"secrets",
|
|
1941
|
+
"prompt_like_instructions",
|
|
1942
|
+
],
|
|
1943
|
+
},
|
|
1944
|
+
"image_pack_plan": {
|
|
1945
|
+
"source_label": sanitize_self_hosted_text(args.source_label) if args.source_label else "manual-plan",
|
|
1946
|
+
"source_image_size": source_size,
|
|
1947
|
+
"packed_image_size": packed_size,
|
|
1948
|
+
"source_area": source_area,
|
|
1949
|
+
"packed_area": packed_area,
|
|
1950
|
+
"area_delta": area_delta,
|
|
1951
|
+
"area_reduction_is_proxy_only": area_delta is not None,
|
|
1952
|
+
"image_or_request_byte_reductions_are_proxy_evidence_only": True,
|
|
1953
|
+
},
|
|
1954
|
+
"measurement_boundary": {
|
|
1955
|
+
"provider_boundary_acknowledged": bool(args.provider_boundary_ack),
|
|
1956
|
+
"provider_boundary_policy": IMAGE_CONTEXT_PACK_PROVIDER_BOUNDARY,
|
|
1957
|
+
"provider_measured_matched_tasks_required_for_hosted_claims": True,
|
|
1958
|
+
"provider_model_specific": True,
|
|
1959
|
+
"hosted_api_token_savings_claim_allowed": False,
|
|
1960
|
+
"hosted_api_cost_savings_claim_allowed": False,
|
|
1961
|
+
},
|
|
1962
|
+
"relation_to_visual_crop_ocr": {
|
|
1963
|
+
"visual_crop_ocr_is_existing_surface": True,
|
|
1964
|
+
"visual_crop_ocr_remains_caller_supplied_visual_evidence_pack": True,
|
|
1965
|
+
"image_context_pack_is_planning_gate_not_duplicate_emitter": True,
|
|
1966
|
+
"verified_exact_binary_or_image_fallback_claimed": False,
|
|
1967
|
+
},
|
|
1968
|
+
"review_plan": {
|
|
1969
|
+
"readiness_blockers": blockers,
|
|
1970
|
+
"missed_context_notes": missed_context_notes,
|
|
1971
|
+
"next_steps": [
|
|
1972
|
+
"Keep exact text artifact fallback verified before any future image/context packing omits source text.",
|
|
1973
|
+
"Deny protected evidence zones before any future lossy visual packing is considered.",
|
|
1974
|
+
"Measure provider/model token and cost fields on matched successful tasks before any hosted savings claim.",
|
|
1975
|
+
"Use visual-crop-ocr only for caller-supplied visual evidence packs; this gate emits no images or evidence.",
|
|
1976
|
+
],
|
|
1977
|
+
},
|
|
1978
|
+
"claim_boundary": (
|
|
1979
|
+
"Dry-run image-context-pack planning only; image/request byte reductions are proxy evidence and no hosted "
|
|
1980
|
+
"token/cost savings claim is allowed without provider-measured matched successful tasks."
|
|
1981
|
+
),
|
|
1982
|
+
"candidate_replacement": None,
|
|
1983
|
+
}
|
|
1984
|
+
|
|
1985
|
+
|
|
1986
|
+
def command_plan_image_context_pack(args: argparse.Namespace) -> int:
|
|
1987
|
+
payload = image_context_pack_plan_payload(args)
|
|
1988
|
+
if args.json:
|
|
1989
|
+
emit_json(payload)
|
|
1990
|
+
else:
|
|
1991
|
+
print("ContextGuard image-context-pack plan (dry-run only)")
|
|
1992
|
+
print("No image rendering, OCR/image service, model call, proxy forwarding, binary artifact, or replacement was emitted.")
|
|
1993
|
+
print(f"Status: {payload['status']}")
|
|
1994
|
+
if payload["review_plan"]["readiness_blockers"]:
|
|
1995
|
+
print(f"Readiness blockers: {', '.join(payload['review_plan']['readiness_blockers'])}")
|
|
1996
|
+
print(payload["claim_boundary"])
|
|
1997
|
+
return 0
|
|
1998
|
+
|
|
1999
|
+
|
|
2000
|
+
def semantic_checkpoint_plan_payload(args: argparse.Namespace) -> dict[str, Any]:
|
|
2001
|
+
goal = args.goal.strip() if args.goal else None
|
|
2002
|
+
receipt_id = args.exact_context_fallback_receipt.strip() if args.exact_context_fallback_receipt else None
|
|
2003
|
+
reexpand_command = args.reexpand_command.strip() if args.reexpand_command else None
|
|
2004
|
+
reexpand_valid, fallback_blocker = valid_learned_reexpand_command(receipt_id, reexpand_command)
|
|
2005
|
+
fallback_blocker_map = {
|
|
2006
|
+
"missing_exact_fallback": "missing_exact_context_fallback",
|
|
2007
|
+
"invalid_reexpand_command": "invalid_exact_context_reexpand_command",
|
|
2008
|
+
}
|
|
2009
|
+
protected_policy = (args.protected_zone_policy or "deny").strip().lower()
|
|
2010
|
+
missed_context_notes = clean_values(args.missed_context_note)
|
|
2011
|
+
missing_provenance_notes = clean_values(args.missing_provenance_note)
|
|
2012
|
+
|
|
2013
|
+
blockers: list[str] = []
|
|
2014
|
+
if not goal:
|
|
2015
|
+
blockers.append("missing_goal")
|
|
2016
|
+
if fallback_blocker:
|
|
2017
|
+
blockers.append(fallback_blocker_map.get(fallback_blocker, fallback_blocker))
|
|
2018
|
+
if not args.provider_boundary_ack:
|
|
2019
|
+
blockers.append("missing_provider_measurement_boundary")
|
|
2020
|
+
if protected_policy != "deny":
|
|
2021
|
+
blockers.append("protected_zone_denial_required")
|
|
2022
|
+
if not missed_context_notes:
|
|
2023
|
+
blockers.append("missing_missed_context_note")
|
|
2024
|
+
if not missing_provenance_notes:
|
|
2025
|
+
blockers.append("missing_provenance_review")
|
|
2026
|
+
blockers = list(dict.fromkeys(blockers))
|
|
2027
|
+
ready = not blockers
|
|
2028
|
+
|
|
2029
|
+
return {
|
|
2030
|
+
"tool": TOOL_NAME,
|
|
2031
|
+
"schema_version": CONFIG_SCHEMA_VERSION,
|
|
2032
|
+
"plan_schema_version": SEMANTIC_CHECKPOINT_PLAN_SCHEMA_VERSION,
|
|
2033
|
+
"experiment_id": "semantic-checkpoint",
|
|
2034
|
+
"mode": "dry_run",
|
|
2035
|
+
"status": "ready_for_plan_review" if ready else "blocked_until_semantic_checkpoint_gate_ready",
|
|
2036
|
+
"plan_only": {
|
|
2037
|
+
"command_advertised": True,
|
|
2038
|
+
"emit_command_available": False,
|
|
2039
|
+
"record_command_available": False,
|
|
2040
|
+
"serve_command_available": False,
|
|
2041
|
+
"runtime_behavior_changed": False,
|
|
2042
|
+
"replacement_context_emitted": False,
|
|
2043
|
+
},
|
|
2044
|
+
"external_services": {
|
|
2045
|
+
"called": False,
|
|
2046
|
+
"network": False,
|
|
2047
|
+
"model_calls": False,
|
|
2048
|
+
"provider_calls": False,
|
|
2049
|
+
"proxy_forwarding": False,
|
|
2050
|
+
},
|
|
2051
|
+
"runtime_side_effects": {
|
|
2052
|
+
"files_written": False,
|
|
2053
|
+
"transcript_edited": False,
|
|
2054
|
+
"prompt_edited": False,
|
|
2055
|
+
"context_replaced": False,
|
|
2056
|
+
"stable_runtime_behavior_changed": False,
|
|
2057
|
+
},
|
|
2058
|
+
"checkpoint_metadata": {
|
|
2059
|
+
"goal": goal,
|
|
2060
|
+
"constraints": clean_values(args.constraint),
|
|
2061
|
+
"decisions": clean_values(args.decision),
|
|
2062
|
+
"open_tasks": clean_values(args.open_task),
|
|
2063
|
+
"evidence_provenance_handles": clean_values(args.evidence_handle),
|
|
2064
|
+
"unresolved_questions": clean_values(args.unresolved_question),
|
|
2065
|
+
},
|
|
2066
|
+
"exact_context_fallback": {
|
|
2067
|
+
"required": True,
|
|
2068
|
+
"available": bool(reexpand_valid),
|
|
2069
|
+
"receipt_id": receipt_id,
|
|
2070
|
+
"reexpand_command": reexpand_command,
|
|
2071
|
+
"verified": False,
|
|
2072
|
+
"must_be_verified_before_checkpoint_metadata_is_used": True,
|
|
2073
|
+
"allowed_reexpand_shapes": [
|
|
2074
|
+
"context-guard-artifact get RECEIPT --full",
|
|
2075
|
+
"context-guard artifact get RECEIPT --full",
|
|
2076
|
+
],
|
|
2077
|
+
},
|
|
2078
|
+
"protected_zones": {
|
|
2079
|
+
"policy": protected_policy,
|
|
2080
|
+
"override_allowed": False,
|
|
2081
|
+
"denied_classes": [
|
|
2082
|
+
"code",
|
|
2083
|
+
"diffs",
|
|
2084
|
+
"identifiers",
|
|
2085
|
+
"hashes",
|
|
2086
|
+
"paths",
|
|
2087
|
+
"numeric_constants",
|
|
2088
|
+
"json_keys",
|
|
2089
|
+
"stack_frames",
|
|
2090
|
+
"secrets",
|
|
2091
|
+
"prompt_like_instructions",
|
|
2092
|
+
],
|
|
2093
|
+
},
|
|
2094
|
+
"measurement_boundary": {
|
|
2095
|
+
"provider_boundary_acknowledged": bool(args.provider_boundary_ack),
|
|
2096
|
+
"provider_boundary_policy": IMAGE_CONTEXT_PACK_PROVIDER_BOUNDARY,
|
|
2097
|
+
"provider_measured_matched_tasks_required_for_hosted_claims": True,
|
|
2098
|
+
"provider_model_specific": True,
|
|
2099
|
+
"hosted_api_token_savings_claim_allowed": False,
|
|
2100
|
+
"hosted_api_cost_savings_claim_allowed": False,
|
|
2101
|
+
},
|
|
2102
|
+
"provenance_review": {
|
|
2103
|
+
"required": True,
|
|
2104
|
+
"reviewed": bool(missing_provenance_notes),
|
|
2105
|
+
"missing_provenance_notes": missing_provenance_notes,
|
|
2106
|
+
"missing_provenance_warnings": [] if missing_provenance_notes else ["missing_provenance_review"],
|
|
2107
|
+
"checkpoint_cannot_replace_raw_context_without_complete_provenance": True,
|
|
2108
|
+
},
|
|
2109
|
+
"review_plan": {
|
|
2110
|
+
"readiness_blockers": blockers,
|
|
2111
|
+
"missed_context_notes": missed_context_notes,
|
|
2112
|
+
"next_steps": [
|
|
2113
|
+
"Keep exact raw context fallback verified before checkpoint metadata is used.",
|
|
2114
|
+
"Deny protected evidence zones before any semantic checkpoint summary is considered.",
|
|
2115
|
+
"Keep provenance handles and missing-provenance review notes attached to checkpoint metadata.",
|
|
2116
|
+
"Measure provider/model token and cost fields on matched successful tasks before any hosted savings claim.",
|
|
2117
|
+
],
|
|
2118
|
+
},
|
|
2119
|
+
"claim_boundary": (
|
|
2120
|
+
"Dry-run semantic-checkpoint planning only; checkpoint metadata is not replacement context and no hosted "
|
|
2121
|
+
"token/cost savings claim is allowed without provider-measured matched successful tasks."
|
|
2122
|
+
),
|
|
2123
|
+
"candidate_replacement": None,
|
|
2124
|
+
}
|
|
2125
|
+
|
|
2126
|
+
|
|
2127
|
+
def command_plan_semantic_checkpoint(args: argparse.Namespace) -> int:
|
|
2128
|
+
payload = semantic_checkpoint_plan_payload(args)
|
|
2129
|
+
if args.json:
|
|
2130
|
+
emit_json(payload)
|
|
2131
|
+
else:
|
|
2132
|
+
print("ContextGuard semantic-checkpoint plan (dry-run only)")
|
|
2133
|
+
print("No files, prompts, transcripts, model/provider calls, proxy forwarding, or replacement context were emitted.")
|
|
2134
|
+
print(f"Status: {payload['status']}")
|
|
2135
|
+
if payload["review_plan"]["readiness_blockers"]:
|
|
2136
|
+
print(f"Readiness blockers: {', '.join(payload['review_plan']['readiness_blockers'])}")
|
|
2137
|
+
print(payload["claim_boundary"])
|
|
2138
|
+
return 0
|
|
2139
|
+
|
|
2140
|
+
|
|
1738
2141
|
def visual_crop_ocr_evidence_pack_payload(args: argparse.Namespace) -> dict[str, Any]:
|
|
1739
2142
|
payload = visual_crop_ocr_plan_payload(args)
|
|
1740
2143
|
blockers = list(payload["review_plan"]["readiness_blockers"])
|
|
@@ -4467,6 +4870,58 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
4467
4870
|
visual_ocr.add_argument("--json", action="store_true", help="Emit JSON output.")
|
|
4468
4871
|
visual_ocr.set_defaults(func=command_plan_visual_crop_ocr)
|
|
4469
4872
|
|
|
4873
|
+
image_context_pack = plan_sub.add_parser(
|
|
4874
|
+
"image-context-pack",
|
|
4875
|
+
help="Dry-run a plan-only pxpipe-inspired image/context packing gate without rendering images.",
|
|
4876
|
+
)
|
|
4877
|
+
image_context_pack.add_argument("--source-label", help="Safe label for this image/context packing plan.")
|
|
4878
|
+
image_context_pack.add_argument("--image-size", help="Optional source image/context canvas size as width,height integers.")
|
|
4879
|
+
image_context_pack.add_argument("--packed-image-size", help="Optional planned packed image size as width,height integers.")
|
|
4880
|
+
image_context_pack.add_argument("--exact-text-fallback-receipt", help="Local exact text artifact receipt id for omitted source text.")
|
|
4881
|
+
image_context_pack.add_argument("--reexpand-command", help="Local exact text re-expand command bound to the receipt id.")
|
|
4882
|
+
image_context_pack.add_argument(
|
|
4883
|
+
"--provider-boundary-ack",
|
|
4884
|
+
action="store_true",
|
|
4885
|
+
help="Acknowledge hosted claims require provider-measured matched successful tasks for the target model.",
|
|
4886
|
+
)
|
|
4887
|
+
image_context_pack.add_argument(
|
|
4888
|
+
"--protected-zone-policy",
|
|
4889
|
+
default="deny",
|
|
4890
|
+
choices=("deny", "allow"),
|
|
4891
|
+
help="Protected evidence handling; only deny can pass the plan gate.",
|
|
4892
|
+
)
|
|
4893
|
+
image_context_pack.add_argument("--missed-context-note", action="append", help="Potential context omitted by a future pack. Repeatable.")
|
|
4894
|
+
image_context_pack.add_argument("--json", action="store_true", help="Emit JSON output.")
|
|
4895
|
+
image_context_pack.set_defaults(func=command_plan_image_context_pack)
|
|
4896
|
+
|
|
4897
|
+
semantic_checkpoint = plan_sub.add_parser(
|
|
4898
|
+
"semantic-checkpoint",
|
|
4899
|
+
help="Dry-run a plan-only semantic checkpoint metadata gate without replacing raw context.",
|
|
4900
|
+
)
|
|
4901
|
+
semantic_checkpoint.add_argument("--goal", help="Planning goal for the semantic checkpoint metadata.")
|
|
4902
|
+
semantic_checkpoint.add_argument("--constraint", action="append", help="Constraint the checkpoint metadata must preserve. Repeatable.")
|
|
4903
|
+
semantic_checkpoint.add_argument("--decision", action="append", help="Decision captured by the checkpoint metadata. Repeatable.")
|
|
4904
|
+
semantic_checkpoint.add_argument("--open-task", action="append", help="Open task captured by the checkpoint metadata. Repeatable.")
|
|
4905
|
+
semantic_checkpoint.add_argument("--evidence-handle", action="append", help="Evidence/provenance handle supporting the checkpoint. Repeatable.")
|
|
4906
|
+
semantic_checkpoint.add_argument("--missing-provenance-note", action="append", help="Missing provenance review note or 'none known after review'. Repeatable.")
|
|
4907
|
+
semantic_checkpoint.add_argument("--unresolved-question", action="append", help="Unresolved question for checkpoint review. Repeatable.")
|
|
4908
|
+
semantic_checkpoint.add_argument("--exact-context-fallback-receipt", help="Local exact raw context artifact receipt id.")
|
|
4909
|
+
semantic_checkpoint.add_argument("--reexpand-command", help="Local exact context re-expand command bound to the receipt id.")
|
|
4910
|
+
semantic_checkpoint.add_argument(
|
|
4911
|
+
"--provider-boundary-ack",
|
|
4912
|
+
action="store_true",
|
|
4913
|
+
help="Acknowledge hosted claims require provider-measured matched successful tasks for the target model.",
|
|
4914
|
+
)
|
|
4915
|
+
semantic_checkpoint.add_argument(
|
|
4916
|
+
"--protected-zone-policy",
|
|
4917
|
+
default="deny",
|
|
4918
|
+
choices=("deny", "allow"),
|
|
4919
|
+
help="Protected evidence handling; only deny can pass the plan gate.",
|
|
4920
|
+
)
|
|
4921
|
+
semantic_checkpoint.add_argument("--missed-context-note", action="append", help="Potential context missed by checkpoint metadata. Repeatable.")
|
|
4922
|
+
semantic_checkpoint.add_argument("--json", action="store_true", help="Emit JSON output.")
|
|
4923
|
+
semantic_checkpoint.set_defaults(func=command_plan_semantic_checkpoint)
|
|
4924
|
+
|
|
4470
4925
|
self_hosted = plan_sub.add_parser(
|
|
4471
4926
|
"self-hosted-metrics-ledger",
|
|
4472
4927
|
help="Dry-run self-hosted/local metrics ledger sidecar evidence without writing a ledger.",
|
|
@@ -4757,7 +5212,7 @@ def normalize_negative_csv_option_values(argv: list[str] | None) -> list[str] |
|
|
|
4757
5212
|
argv = sys.argv[1:]
|
|
4758
5213
|
normalized: list[str] = []
|
|
4759
5214
|
pending_csv_option: str | None = None
|
|
4760
|
-
csv_options = {"--crop-bounds"}
|
|
5215
|
+
csv_options = {"--crop-bounds", "--image-size", "--packed-image-size"}
|
|
4761
5216
|
for token in argv:
|
|
4762
5217
|
if pending_csv_option is not None:
|
|
4763
5218
|
normalized.append(f"{pending_csv_option}={token}")
|
|
@@ -19,6 +19,7 @@ import sys
|
|
|
19
19
|
SHELL_OPERATOR_TOKENS = {";", ";;", ";&", ";;&", "&", "&&", "|", "||", "<", ">", "<<", ">>", "<>", "(", ")"}
|
|
20
20
|
SHELL_OPERATOR_CHARS = frozenset(";&|<>()")
|
|
21
21
|
ENV_ASSIGNMENT_RE = re.compile(r"^[A-Za-z_][A-Za-z0-9_]*=.*")
|
|
22
|
+
SAFE_PIPE_FILTER_BASENAMES = frozenset({"cat", "head", "tail", "wc", "sort", "uniq"})
|
|
22
23
|
WRAPPER_BASENAMES = frozenset({
|
|
23
24
|
"trim_command_output.py",
|
|
24
25
|
"context-guard-trim-output",
|
|
@@ -164,6 +165,59 @@ def split_single_safe_command(command: str) -> list[str] | None:
|
|
|
164
165
|
return argv
|
|
165
166
|
|
|
166
167
|
|
|
168
|
+
def split_safe_sanitizer_pipeline(command: str) -> list[list[str]] | None:
|
|
169
|
+
"""Return argv segments for a narrow read-only pipeline safe to sanitizer-wrap.
|
|
170
|
+
|
|
171
|
+
Compound search/diff/log commands are useful in practice (`git diff | cat`,
|
|
172
|
+
`rg token . | head`), but arbitrary shell operators can branch output to
|
|
173
|
+
files/network or change control flow before the sanitizer sees it. This
|
|
174
|
+
helper therefore allows only plain `|` pipelines where the first segment is
|
|
175
|
+
sanitizer-worthy and every later segment is a simple stdout filter. It
|
|
176
|
+
intentionally rejects redirection, here-doc/string, `tee`, `curl`, `&&`,
|
|
177
|
+
command substitution, and other shell syntax.
|
|
178
|
+
"""
|
|
179
|
+
if not command.strip():
|
|
180
|
+
return None
|
|
181
|
+
if any(char in command for char in "\n\r\t`"):
|
|
182
|
+
return None
|
|
183
|
+
if "$(" in command or "${" in command:
|
|
184
|
+
return None
|
|
185
|
+
try:
|
|
186
|
+
lexer = shlex.shlex(command, posix=True, punctuation_chars=True)
|
|
187
|
+
lexer.whitespace_split = True
|
|
188
|
+
tokens = list(lexer)
|
|
189
|
+
except ValueError:
|
|
190
|
+
return None
|
|
191
|
+
if "|" not in tokens:
|
|
192
|
+
return None
|
|
193
|
+
|
|
194
|
+
segments: list[list[str]] = [[]]
|
|
195
|
+
for token in tokens:
|
|
196
|
+
is_operator = token in SHELL_OPERATOR_TOKENS or (
|
|
197
|
+
any(char in SHELL_OPERATOR_CHARS for char in token)
|
|
198
|
+
and all(char in SHELL_OPERATOR_CHARS for char in token)
|
|
199
|
+
)
|
|
200
|
+
if is_operator:
|
|
201
|
+
if token != "|":
|
|
202
|
+
return None
|
|
203
|
+
if not segments[-1]:
|
|
204
|
+
return None
|
|
205
|
+
segments.append([])
|
|
206
|
+
continue
|
|
207
|
+
if any(char in token for char in "`\n\r\t"):
|
|
208
|
+
return None
|
|
209
|
+
if "$(" in token or "${" in token:
|
|
210
|
+
return None
|
|
211
|
+
segments[-1].append(token)
|
|
212
|
+
if not segments or not segments[-1] or len(segments) < 2:
|
|
213
|
+
return None
|
|
214
|
+
if not (is_sanitizable_output_command(segments[0]) or is_log_streaming_command(segments[0])):
|
|
215
|
+
return None
|
|
216
|
+
if not all(is_safe_pipe_filter(segment) for segment in segments[1:]):
|
|
217
|
+
return None
|
|
218
|
+
return segments
|
|
219
|
+
|
|
220
|
+
|
|
167
221
|
def command_basename(command: str) -> str:
|
|
168
222
|
return os.path.basename(command)
|
|
169
223
|
|
|
@@ -214,6 +268,70 @@ def npm_script_args(rest: list[str]) -> list[str]:
|
|
|
214
268
|
return rest[i:]
|
|
215
269
|
|
|
216
270
|
|
|
271
|
+
def _filter_args_are_stdin_only(first: str, args: list[str]) -> bool:
|
|
272
|
+
"""Accept small, option-only filter argv forms that do not name files."""
|
|
273
|
+
if first == "cat":
|
|
274
|
+
return not args
|
|
275
|
+
long_no_value_options = {
|
|
276
|
+
"head": set(),
|
|
277
|
+
"tail": set(),
|
|
278
|
+
"wc": {"--bytes", "--chars", "--lines", "--words"},
|
|
279
|
+
"sort": {"--ignore-leading-blanks", "--dictionary-order", "--ignore-case", "--general-numeric-sort", "--human-numeric-sort", "--numeric-sort", "--reverse", "--unique"},
|
|
280
|
+
"uniq": {"--count", "--repeated", "--unique", "--ignore-case"},
|
|
281
|
+
}.get(first, set())
|
|
282
|
+
short_no_value_chars = {
|
|
283
|
+
"head": set(),
|
|
284
|
+
"tail": {"f", "F", "r"},
|
|
285
|
+
"wc": {"c", "m", "l", "w"},
|
|
286
|
+
"sort": {"b", "d", "f", "g", "h", "n", "r", "u"},
|
|
287
|
+
"uniq": {"c", "d", "u", "i"},
|
|
288
|
+
}.get(first, set())
|
|
289
|
+
value_options = {"-n", "--lines", "-c", "--bytes"} if first in {"head", "tail"} else set()
|
|
290
|
+
i = 0
|
|
291
|
+
while i < len(args):
|
|
292
|
+
arg = args[i]
|
|
293
|
+
if arg == "--":
|
|
294
|
+
return i == len(args) - 1
|
|
295
|
+
if arg.startswith("--") and "=" in arg:
|
|
296
|
+
name, value = arg.split("=", 1)
|
|
297
|
+
if name not in value_options:
|
|
298
|
+
return False
|
|
299
|
+
if not re.fullmatch(r"[+-]?\d+[KkMmGg]?", value):
|
|
300
|
+
return False
|
|
301
|
+
i += 1
|
|
302
|
+
continue
|
|
303
|
+
if arg in value_options:
|
|
304
|
+
if i + 1 >= len(args):
|
|
305
|
+
return False
|
|
306
|
+
if not re.fullmatch(r"[+-]?\d+[KkMmGg]?", args[i + 1]):
|
|
307
|
+
return False
|
|
308
|
+
i += 2
|
|
309
|
+
continue
|
|
310
|
+
if arg in long_no_value_options:
|
|
311
|
+
i += 1
|
|
312
|
+
continue
|
|
313
|
+
if arg.startswith("--"):
|
|
314
|
+
return False
|
|
315
|
+
if arg.startswith("-") and arg != "-":
|
|
316
|
+
if not set(arg[1:]).issubset(short_no_value_chars):
|
|
317
|
+
return False
|
|
318
|
+
i += 1
|
|
319
|
+
continue
|
|
320
|
+
if arg.startswith("-"):
|
|
321
|
+
return False
|
|
322
|
+
return False
|
|
323
|
+
return True
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
def is_safe_pipe_filter(argv: list[str]) -> bool:
|
|
327
|
+
if not argv:
|
|
328
|
+
return False
|
|
329
|
+
first = command_basename(argv[0])
|
|
330
|
+
if first not in SAFE_PIPE_FILTER_BASENAMES:
|
|
331
|
+
return False
|
|
332
|
+
return _filter_args_are_stdin_only(first, argv[1:])
|
|
333
|
+
|
|
334
|
+
|
|
217
335
|
def is_noisy_command(argv: list[str]) -> bool:
|
|
218
336
|
argv = strip_env_prefix(argv)
|
|
219
337
|
if not argv:
|
|
@@ -423,6 +541,16 @@ def build_sanitized_command(wrapper: str, command: str) -> str:
|
|
|
423
541
|
return shlex.join(wrapped_argv)
|
|
424
542
|
|
|
425
543
|
|
|
544
|
+
def print_updated_command(wrapped: str) -> None:
|
|
545
|
+
response = {
|
|
546
|
+
"hookSpecificOutput": {
|
|
547
|
+
"hookEventName": "PreToolUse",
|
|
548
|
+
"updatedInput": {"command": wrapped},
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
print(json.dumps(response, ensure_ascii=False))
|
|
552
|
+
|
|
553
|
+
|
|
426
554
|
def main() -> int:
|
|
427
555
|
if any(arg in {"-h", "--help"} for arg in sys.argv[1:]):
|
|
428
556
|
print("ContextGuard helper: context-guard-rewrite-bash")
|
|
@@ -450,11 +578,25 @@ def main() -> int:
|
|
|
450
578
|
argv = split_single_safe_command(command)
|
|
451
579
|
if not argv:
|
|
452
580
|
if unparseable_command_needs_sanitizer(command):
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
581
|
+
safe_pipeline = split_safe_sanitizer_pipeline(command)
|
|
582
|
+
if safe_pipeline is None:
|
|
583
|
+
deny(
|
|
584
|
+
"Search/diff/log command contains shell operators that are not in ContextGuard's "
|
|
585
|
+
"read-only pipe allowlist. Simplify to a plain pipeline ending in cat/head/tail/wc/sort/uniq, "
|
|
586
|
+
"run context-guard-sanitize-output explicitly after review, or set "
|
|
587
|
+
f"{FAIL_OPEN_ENV}=1 to run unsanitized intentionally."
|
|
588
|
+
)
|
|
589
|
+
return 0
|
|
590
|
+
wrapper = find_wrapper("sanitize")
|
|
591
|
+
if wrapper is None:
|
|
592
|
+
deny(
|
|
593
|
+
"Search/diff/log command blocked because it contains shell operators and "
|
|
594
|
+
"context-guard-sanitize-output is not installed next to context-guard-rewrite-bash. "
|
|
595
|
+
"Install the sanitizer or set "
|
|
596
|
+
f"{FAIL_OPEN_ENV}=1 to run unsanitized intentionally."
|
|
597
|
+
)
|
|
598
|
+
return 0
|
|
599
|
+
print_updated_command(build_sanitized_command(wrapper, command))
|
|
458
600
|
return 0
|
|
459
601
|
print_noop()
|
|
460
602
|
return 0
|
|
@@ -490,13 +632,7 @@ def main() -> int:
|
|
|
490
632
|
print("{}")
|
|
491
633
|
return 0
|
|
492
634
|
|
|
493
|
-
|
|
494
|
-
"hookSpecificOutput": {
|
|
495
|
-
"hookEventName": "PreToolUse",
|
|
496
|
-
"updatedInput": {"command": wrapped},
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
print(json.dumps(response, ensure_ascii=False))
|
|
635
|
+
print_updated_command(wrapped)
|
|
500
636
|
return 0
|
|
501
637
|
|
|
502
638
|
|