opensocrates 1.1.2 → 1.1.4
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 +137 -0
- package/README.ko.md +78 -35
- package/README.md +84 -36
- package/SECURITY.md +24 -3
- package/VERSION +1 -1
- package/installer/opensocrates.mjs +133 -28
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,141 @@
|
|
|
3
3
|
All notable changes to OpenSocrates are documented here. This project follows
|
|
4
4
|
[Semantic Versioning](https://semver.org/).
|
|
5
5
|
|
|
6
|
+
## [Unreleased]
|
|
7
|
+
|
|
8
|
+
## [1.1.4] - 2026-08-12
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- A privacy-safe Claude selector aggregate records only bounded counts under a
|
|
13
|
+
closed outcome vocabulary. `diagnose` exposes those counts without prompts,
|
|
14
|
+
transcripts, session identifiers, paths, model output, credentials, or
|
|
15
|
+
selector reasoning ([#4](https://github.com/ParkerHwang/OpenSocrates/issues/4)).
|
|
16
|
+
- A sanitized Cowork receipt validates local plugin upload and the native
|
|
17
|
+
`UserPromptSubmit` → `PostToolUse(Read)` → `Stop` lifecycle, including the
|
|
18
|
+
authenticated grounding receipt and final cleanup
|
|
19
|
+
([#4](https://github.com/ParkerHwang/OpenSocrates/issues/4)).
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
|
|
23
|
+
- Native runtime builds are split by host profile. The Claude package excludes
|
|
24
|
+
the Codex SDK and CLI while the Codex package preserves its existing runtime
|
|
25
|
+
surface ([#4](https://github.com/ParkerHwang/OpenSocrates/issues/4)).
|
|
26
|
+
- Release tooling derives artifact paths from the detected native target,
|
|
27
|
+
defaults plugin generation to `dist/runtime/<host>`, and interprets Cowork's
|
|
28
|
+
50 MB and 200 MB limits conservatively as decimal bytes
|
|
29
|
+
([#4](https://github.com/ParkerHwang/OpenSocrates/issues/4)).
|
|
30
|
+
|
|
31
|
+
### Fixed
|
|
32
|
+
|
|
33
|
+
- The Claude runtime now uses PyInstaller's no-archive mode, and release checks
|
|
34
|
+
reject nested ZIP entries before a Cowork package can be published
|
|
35
|
+
([#4](https://github.com/ParkerHwang/OpenSocrates/issues/4)).
|
|
36
|
+
- Unreadable selector aggregates report `unavailable` instead of zero attempts.
|
|
37
|
+
Malformed current-schema documents self-heal on the next valid outcome while
|
|
38
|
+
unknown future schemas are preserved
|
|
39
|
+
([#4](https://github.com/ParkerHwang/OpenSocrates/issues/4)).
|
|
40
|
+
|
|
41
|
+
## [1.1.3] - 2026-08-11
|
|
42
|
+
|
|
43
|
+
### Added
|
|
44
|
+
|
|
45
|
+
- Bounded semantic packaged-README checks now reject novel universal-support,
|
|
46
|
+
vendor-endorsement, and managed-environment safety overclaims, with mutation
|
|
47
|
+
coverage that also protects accurate limitation wording from false positives
|
|
48
|
+
([#27](https://github.com/ParkerHwang/OpenSocrates/issues/27)).
|
|
49
|
+
- Native plugin packages now expose one honest `darwin-arm64` boundary: the
|
|
50
|
+
unvalidated PowerShell launcher is removed, the POSIX launcher rejects every
|
|
51
|
+
other target, and package manifests and docs distinguish unshipped build
|
|
52
|
+
candidates from the released platform
|
|
53
|
+
([#12](https://github.com/ParkerHwang/OpenSocrates/issues/12)).
|
|
54
|
+
- A Claude Chat upload probe records the exact verified v1.1.2 skills ZIP
|
|
55
|
+
shape and hash, live uploader acceptance, single visible skill entry,
|
|
56
|
+
catalog routing, representative method loading, and grounding audit without
|
|
57
|
+
retaining prompt or conversation content
|
|
58
|
+
([#5](https://github.com/ParkerHwang/OpenSocrates/issues/5)).
|
|
59
|
+
- A privacy-safe Cowork probe validates the separately uploaded
|
|
60
|
+
`/opensocrates` skill and corrects the installation boundary: Claude Code CLI
|
|
61
|
+
marketplace registration is not a Cowork-native plugin install. The exact
|
|
62
|
+
published v1.1.2 plugin archive is rejected by Cowork's upload-size limits,
|
|
63
|
+
and repository sync is unavailable without a marketplace manifest, so native
|
|
64
|
+
hooks remain blocked
|
|
65
|
+
([#4](https://github.com/ParkerHwang/OpenSocrates/issues/4)).
|
|
66
|
+
- A privacy-safe Claude Code desktop live probe now validates a complete
|
|
67
|
+
authenticated UserPromptSubmit → PostToolUse(Read) → Stop lifecycle. It
|
|
68
|
+
observes the owner-only instruction artifact, authenticated grounding
|
|
69
|
+
receipt, and final cleanup without retaining prompts, transcripts, paths,
|
|
70
|
+
credentials, payloads, or selector reasoning
|
|
71
|
+
([#3](https://github.com/ParkerHwang/OpenSocrates/issues/3)).
|
|
72
|
+
- A reproducible packaged `darwin-arm64` timing harness verifies PostToolUse
|
|
73
|
+
receipt creation and Stop cleanup across fresh-path and warm runs. All 80
|
|
74
|
+
measured operations completed, the worst p95 was 1,333.067 ms against the
|
|
75
|
+
3-second budget, and no timeout change is recommended
|
|
76
|
+
([#6](https://github.com/ParkerHwang/OpenSocrates/issues/6)).
|
|
77
|
+
- An opt-in Claude structured-output matrix runs 20–50 bounded attempts per
|
|
78
|
+
explicitly requested model, requires 95% valid envelopes, and stores only
|
|
79
|
+
aggregate fixed outcome counts. The authenticated Claude Code 2.1.226
|
|
80
|
+
`host-default` row passed 20/20 attempts with every failure outcome at zero;
|
|
81
|
+
no unobserved named model is claimed
|
|
82
|
+
([#8](https://github.com/ParkerHwang/OpenSocrates/issues/8)).
|
|
83
|
+
- An opt-in, privacy-safe real Claude selector contract verifies the exact
|
|
84
|
+
isolation command, environment allowlist, temporary workspace, and real
|
|
85
|
+
subprocess failure categories. An authenticated, non-sensitive live call on
|
|
86
|
+
Claude Code 2.1.226 returned `selected`, removed its temporary workspace, and
|
|
87
|
+
retained no prompt, raw output, credential, or selector reasoning
|
|
88
|
+
([#7](https://github.com/ParkerHwang/OpenSocrates/issues/7)).
|
|
89
|
+
- Sanitized Claude Code payload receipts for the complete v1.1.2 hook
|
|
90
|
+
lifecycle — `SessionStart`, `UserPromptSubmit`, `PostToolUse`, `Stop`, and
|
|
91
|
+
`SessionEnd` — captured from a supported runtime and compared field by field
|
|
92
|
+
with the shared adapter mapping. The checks assert that `prompt_id` is
|
|
93
|
+
projected into turn identity, that `last_assistant_message` reaches the Stop
|
|
94
|
+
decision, that two consecutive turns of one session stay artifact-isolated,
|
|
95
|
+
and that Stop and `SessionEnd` clean up
|
|
96
|
+
([#9](https://github.com/ParkerHwang/OpenSocrates/issues/9)).
|
|
97
|
+
|
|
98
|
+
### Fixed
|
|
99
|
+
|
|
100
|
+
- The Claude Chat skills ZIP now uses the uploader's required single top-level
|
|
101
|
+
`opensocrates/` folder with `SKILL.md` directly inside; the prior plugin-shaped
|
|
102
|
+
archive was rejected by the real Customize → Skills upload UI
|
|
103
|
+
([#5](https://github.com/ParkerHwang/OpenSocrates/issues/5)).
|
|
104
|
+
- The installer now accepts only explicit Claude list JSON variants, rejects
|
|
105
|
+
malformed, duplicate, or conflicting managed entries, surfaces disabled
|
|
106
|
+
plugins as drift, re-enables them on install/update, preserves their state on
|
|
107
|
+
rollback, and emits executable recovery commands after a secondary root
|
|
108
|
+
removal failure ([#11](https://github.com/ParkerHwang/OpenSocrates/issues/11)).
|
|
109
|
+
- POSIX and PowerShell launchers now enforce the single generated `bin/`
|
|
110
|
+
package layout and never probe a competing `bin/runtime/` tree
|
|
111
|
+
([#26](https://github.com/ParkerHwang/OpenSocrates/issues/26)).
|
|
112
|
+
- Packaged-launcher checks now derive each host's runtime root from canonical
|
|
113
|
+
`generator.json` metadata and include a mismatch probe that remains
|
|
114
|
+
discriminating when no native runtime targets were built
|
|
115
|
+
([#25](https://github.com/ParkerHwang/OpenSocrates/issues/25)).
|
|
116
|
+
- Claude sessions now supersede private instruction artifacts by `prompt_id`.
|
|
117
|
+
When `Stop` is absent, the next `UserPromptSubmit` removes prior turn trees in
|
|
118
|
+
that session while preserving the new active turn; `SessionEnd` and the
|
|
119
|
+
24-hour `SessionStart` sweep remain backstops
|
|
120
|
+
([#13](https://github.com/ParkerHwang/OpenSocrates/issues/13)).
|
|
121
|
+
- The Claude selector now enforces its 512 KiB stdout ceiling while reading the
|
|
122
|
+
child process stream. Output that crosses the limit terminates and reaps the
|
|
123
|
+
process immediately, fails open with a content-free diagnostic, and is never
|
|
124
|
+
retained or logged ([#10](https://github.com/ParkerHwang/OpenSocrates/issues/10)).
|
|
125
|
+
- An ordinary Claude payload no longer reports an unknown field. `effort` was
|
|
126
|
+
present in the captured `PostToolUse` and `Stop` receipts, while
|
|
127
|
+
`background_tasks` and `session_crons` were present in the captured `Stop`
|
|
128
|
+
receipt. They were missing from the parser's known-field sets, so the
|
|
129
|
+
`native_unknown_field_ignored` diagnostic fired on healthy turns. The parser
|
|
130
|
+
still never reads those fields, and no parsing, projection, or gating
|
|
131
|
+
behavior changed.
|
|
132
|
+
|
|
133
|
+
### Security and privacy
|
|
134
|
+
|
|
135
|
+
- The committed receipts contain no prompt, transcript, path, credential, or
|
|
136
|
+
user-identifying content. Field names, value types, and container shapes are
|
|
137
|
+
preserved as captured; every sensitive value is a fixed synthetic marker, and
|
|
138
|
+
a check refuses every native-payload string outside a closed vocabulary so a
|
|
139
|
+
future re-capture cannot commit real payload content by accident.
|
|
140
|
+
|
|
6
141
|
## [1.1.2] - 2026-08-11
|
|
7
142
|
|
|
8
143
|
### Added
|
|
@@ -168,3 +303,5 @@ All notable changes to OpenSocrates are documented here. This project follows
|
|
|
168
303
|
[1.1.0]: https://github.com/ParkerHwang/OpenSocrates/compare/v1.0.0...v1.1.0
|
|
169
304
|
[1.1.1]: https://github.com/ParkerHwang/OpenSocrates/compare/v1.1.0...v1.1.1
|
|
170
305
|
[1.1.2]: https://github.com/ParkerHwang/OpenSocrates/compare/v1.1.1...v1.1.2
|
|
306
|
+
[1.1.3]: https://github.com/ParkerHwang/OpenSocrates/compare/v1.1.2...v1.1.3
|
|
307
|
+
[1.1.4]: https://github.com/ParkerHwang/OpenSocrates/compare/v1.1.3...v1.1.4
|
package/README.ko.md
CHANGED
|
@@ -16,16 +16,21 @@ OpenSocrates는 Claude와 Codex를 위한 로컬 연동 및 저작 추론 프레
|
|
|
16
16
|
추론 시스템을 고른 뒤, 이론과 예제 전체를 활성 작업에 추가합니다. 단순한 사실
|
|
17
17
|
확인과 기계적인 작업은 그대로 통과할 수 있습니다.
|
|
18
18
|
|
|
19
|
-
버전 `1.1.
|
|
19
|
+
버전 `1.1.4`에는 48개의 추론 시스템, Claude의 단일 사용자 진입점, 선택된 절차를
|
|
20
20
|
실제로 읽었는지 확인하는 Claude 접지 게이트, Claude/Codex 통합 라이프사이클,
|
|
21
21
|
선택형 자동 업데이트가 들어 있습니다. 현재 릴리스 플랫폼은 Apple Silicon
|
|
22
22
|
macOS(`darwin-arm64`)입니다. 기존 호스트 로그인을 사용하므로 API 키나
|
|
23
23
|
OpenSocrates 백엔드가 필요하지 않습니다.
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
네이티브 플러그인 아카이브에는 의도적으로 `bin/launch.sh`만 포함됩니다. 이
|
|
26
|
+
런처는 `darwin-arm64`만 허용하며, Intel Mac·Linux·Windows용 런처와 런타임은
|
|
27
|
+
이번 릴리스에 포함되거나 지원되지 않습니다.
|
|
28
|
+
|
|
29
|
+
> **최신 릴리스: [OpenSocrates 1.1.4](https://github.com/ParkerHwang/OpenSocrates/releases/tag/v1.1.4).**
|
|
30
|
+
> Cowork에 업로드할 수 있는 Claude 네이티브 패키지, 호스트별 런타임 분리, 사용할 수
|
|
31
|
+
> 없는 집계와 0회를 구분하는 내용 없는 셀렉터 진단을 추가했습니다.
|
|
32
|
+
> `npx --yes opensocrates@1.1.4 update --host all`로 관리 중인 두 호스트를 함께
|
|
33
|
+
> 업데이트할 수 있습니다.
|
|
29
34
|
|
|
30
35
|
## 호스트 지원 범위
|
|
31
36
|
|
|
@@ -33,9 +38,9 @@ OpenSocrates 백엔드가 필요하지 않습니다.
|
|
|
33
38
|
| --- | --- | --- | --- |
|
|
34
39
|
| Codex CLI 및 Desktop | 지원 | OpenSocrates 플러그인 | `darwin-arm64` 릴리스 검증 완료 |
|
|
35
40
|
| Claude Code CLI | `UserPromptSubmit` 훅으로 지원 | `/opensocrates` | `darwin-arm64` 로컬 검증 완료 |
|
|
36
|
-
| Claude Code 데스크톱 앱 | Claude Code 플러그인이 실행되는 곳에서
|
|
37
|
-
| Claude Cowork | 로컬 플러그인
|
|
38
|
-
| Claude 웹 및 Desktop Chat | 훅 미지원 | `/opensocrates` |
|
|
41
|
+
| Claude Code 데스크톱 앱 | Claude Code 플러그인이 실행되는 곳에서 지원 | `/opensocrates` | [인증된 훅 생명주기 로컬 검증 완료](docs/claude-desktop-live-probe.md) |
|
|
42
|
+
| Claude Cowork | 실측 로컬 플러그인 업로드에서 지원 | `/opensocrates` | [네이티브 훅 생명주기 로컬 검증 완료, 릴리스 직접 업로드 지원, 마켓플레이스 동기화 없음](docs/claude-cowork-live-probe.md) |
|
|
43
|
+
| Claude 웹 및 Desktop Chat | 훅 미지원 | `/opensocrates` | [실제 업로드 및 호출 검증 완료](docs/claude-chat-upload-probe.md) |
|
|
39
44
|
|
|
40
45
|
상태 열은 서로 다른 네 단계를 뜻하며 같은 의미로 읽으면 안 됩니다.
|
|
41
46
|
|
|
@@ -52,11 +57,13 @@ Claude Chat 화면은 플러그인 훅을 실행하지 않습니다. 생성된
|
|
|
52
57
|
Code와 Cowork 화면에서만 작동합니다. 훅이나 셀렉터를 사용할 수 없으면
|
|
53
58
|
OpenSocrates는 작업을 막지 않고 통과합니다.
|
|
54
59
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
+
공개된 v1.1.2 Claude 플러그인 아카이브는 Cowork의 문서화된 압축 크기 제한과
|
|
61
|
+
실측 압축 해제 크기 제한을 모두 초과했습니다. 출시 전 v1.1.3 후보는 압축
|
|
62
|
+
13.8MB, 비압축 34.1MB이며 Codex 런타임과 중첩 ZIP을 포함하지 않고 Cowork 로컬
|
|
63
|
+
업로드를 통과했습니다. UserPromptSubmit, PostToolUse(Read), 인증된 grounding
|
|
64
|
+
receipt, Stop, 정리 생명주기도 로컬 검증을 마쳤습니다. 버전 1.1.4는 검토를 마친
|
|
65
|
+
이 패키지 경계를 처음 배포합니다. 저장소에는 아직 Cowork 마켓플레이스
|
|
66
|
+
매니페스트가 없으므로 저장소 동기화 대신 로컬 플러그인 업로드 경로를 사용합니다.
|
|
60
67
|
|
|
61
68
|
## 설치
|
|
62
69
|
|
|
@@ -73,7 +80,7 @@ Node.js 20 이상이 필요합니다. npm에 게시된 `opensocrates` 패키지
|
|
|
73
80
|
### 준비된 모든 호스트에 설치
|
|
74
81
|
|
|
75
82
|
```bash
|
|
76
|
-
npx --yes opensocrates@1.1.
|
|
83
|
+
npx --yes opensocrates@1.1.4 install --host all
|
|
77
84
|
```
|
|
78
85
|
|
|
79
86
|
모든 호스트 경로는 지원되는 인증 완료 CLI를 찾고, 어느 호스트도 바꾸기 전에
|
|
@@ -84,9 +91,9 @@ npx --yes opensocrates@1.1.2 install --host all
|
|
|
84
91
|
전체 라이프사이클에서 같은 호스트 값을 사용할 수 있습니다.
|
|
85
92
|
|
|
86
93
|
```bash
|
|
87
|
-
npx --yes opensocrates@1.1.
|
|
88
|
-
npx --yes opensocrates@1.1.
|
|
89
|
-
npx --yes opensocrates@1.1.
|
|
94
|
+
npx --yes opensocrates@1.1.4 status --host all
|
|
95
|
+
npx --yes opensocrates@1.1.4 update --host all
|
|
96
|
+
npx --yes opensocrates@1.1.4 remove --host all
|
|
90
97
|
```
|
|
91
98
|
|
|
92
99
|
소유자 전용 `~/.opensocrates/desired-state.json`에는 선택 채널, 설치된 호스트,
|
|
@@ -98,21 +105,28 @@ npx --yes opensocrates@1.1.2 remove --host all
|
|
|
98
105
|
기존 사용자와의 호환성을 위해 기본 호스트는 계속 Codex입니다.
|
|
99
106
|
|
|
100
107
|
```bash
|
|
101
|
-
npx --yes opensocrates@1.1.
|
|
102
|
-
# 같은 명령: npx --yes opensocrates@1.1.
|
|
103
|
-
npx --yes opensocrates@1.1.
|
|
108
|
+
npx --yes opensocrates@1.1.4 install
|
|
109
|
+
# 같은 명령: npx --yes opensocrates@1.1.4 install --host codex
|
|
110
|
+
npx --yes opensocrates@1.1.4 install --host claude
|
|
104
111
|
```
|
|
105
112
|
|
|
106
113
|
기존 `--host codex` 및 `--host claude` 라이프사이클은 그대로 지원합니다. 호스트별
|
|
107
114
|
업데이트는 의도적으로 버전 차이를 만들 수 있고, 이후 `update --host all` 또는
|
|
108
115
|
성공한 자동 조정이 desired state에 기록된 모든 호스트를 다시 한 버전으로 맞춥니다.
|
|
109
116
|
|
|
117
|
+
Claude 상태는 활성 설치와 설치됐지만 비활성화된 플러그인을 구분합니다. 원하는
|
|
118
|
+
설치가 비활성 상태라면 drift로 보고합니다. `install` 또는 `update`를 실행하면 검증된
|
|
119
|
+
패키지를 의도적으로 다시 활성화하며, 활성화가 실패하면 롤백이 이전의 활성·비활성
|
|
120
|
+
상태를 복원합니다. 설치 프로그램은 Claude 목록 명령에서 실측한 직접 JSON 배열과
|
|
121
|
+
명시적인 `marketplaces`/`plugins` 래퍼만 허용합니다. 개인정보를 제거한 2.1.226
|
|
122
|
+
픽스처는 `installer/fixtures/claude-cli/`에 있습니다.
|
|
123
|
+
|
|
110
124
|
### 선택형 자동 업데이트
|
|
111
125
|
|
|
112
126
|
```bash
|
|
113
|
-
npx --yes opensocrates@1.1.
|
|
114
|
-
npx --yes opensocrates@1.1.
|
|
115
|
-
npx --yes opensocrates@1.1.
|
|
127
|
+
npx --yes opensocrates@1.1.4 auto-update enable --host all
|
|
128
|
+
npx --yes opensocrates@1.1.4 auto-update status
|
|
129
|
+
npx --yes opensocrates@1.1.4 auto-update disable
|
|
116
130
|
```
|
|
117
131
|
|
|
118
132
|
자동 업데이트는 명시적으로 켜기 전까지 비활성화되어 있습니다. macOS LaunchAgent는
|
|
@@ -134,8 +148,10 @@ LaunchAgent를 언로드하고 삭제하며, `remove --host all`도 관리 호
|
|
|
134
148
|
### Claude 웹 및 Desktop Chat 스킬
|
|
135
149
|
|
|
136
150
|
이 화면들은 플러그인 스킬은 지원하지만 훅은 실행하지 않습니다. 릴리스에서
|
|
137
|
-
`opensocrates-1.1.
|
|
138
|
-
|
|
151
|
+
`opensocrates-1.1.4-claude-chat-skills.zip`을 내려받아 Claude의 **사용자 지정 →
|
|
152
|
+
스킬 → 스킬 업로드** 화면에서 업로드하세요. ZIP은 업로더 요구사항에 맞춰
|
|
153
|
+
최상위 `opensocrates/` 폴더 바로 아래에 `SKILL.md`를 둡니다. 패키지는
|
|
154
|
+
`/opensocrates` 스킬 하나만 노출하고, 48개
|
|
139
155
|
방법 절차와 엄격도·근거·추적 제어는 내부 참조로 둡니다. Chat은 플러그인 훅을
|
|
140
156
|
실행하지 않으므로 자동 선택은 없습니다. Anthropic의
|
|
141
157
|
[플러그인 화면 안내](https://support.claude.com/en/articles/13837440-use-plugins-in-claude)를
|
|
@@ -146,21 +162,21 @@ LaunchAgent를 언로드하고 삭제하며, `remove --host all`도 관리 호
|
|
|
146
162
|
npm 레지스트리를 거치지 않을 때도 같은 호스트 옵션을 사용합니다.
|
|
147
163
|
|
|
148
164
|
```bash
|
|
149
|
-
npx --yes github:ParkerHwang/OpenSocrates#v1.1.
|
|
150
|
-
npx --yes github:ParkerHwang/OpenSocrates#v1.1.
|
|
151
|
-
npx --yes github:ParkerHwang/OpenSocrates#v1.1.
|
|
165
|
+
npx --yes github:ParkerHwang/OpenSocrates#v1.1.4 install --host all
|
|
166
|
+
npx --yes github:ParkerHwang/OpenSocrates#v1.1.4 install --host claude
|
|
167
|
+
npx --yes github:ParkerHwang/OpenSocrates#v1.1.4 install --host codex
|
|
152
168
|
```
|
|
153
169
|
|
|
154
170
|
### 릴리스 파일 직접 검증
|
|
155
171
|
|
|
156
|
-
[v1.1.
|
|
172
|
+
[v1.1.4 릴리스](https://github.com/ParkerHwang/OpenSocrates/releases/tag/v1.1.4)에서
|
|
157
173
|
`opensocrates.mjs`, 호스트 패키지, `.sha256` 파일을 내려받습니다. Claude의 예:
|
|
158
174
|
|
|
159
175
|
```bash
|
|
160
|
-
shasum -a 256 -c opensocrates-1.1.
|
|
176
|
+
shasum -a 256 -c opensocrates-1.1.4-claude-plugin.zip.sha256
|
|
161
177
|
node opensocrates.mjs install --host claude \
|
|
162
|
-
--asset opensocrates-1.1.
|
|
163
|
-
--checksum opensocrates-1.1.
|
|
178
|
+
--asset opensocrates-1.1.4-claude-plugin.zip \
|
|
179
|
+
--checksum opensocrates-1.1.4-claude-plugin.zip.sha256
|
|
164
180
|
```
|
|
165
181
|
|
|
166
182
|
Codex 패키지는 `claude`를 `codex`로 바꾸면 됩니다.
|
|
@@ -175,7 +191,7 @@ Codex 패키지는 `claude`를 `codex`로 바꾸면 됩니다.
|
|
|
175
191
|
```bash
|
|
176
192
|
claude plugin uninstall opensocrates@OpenSocrates --scope user
|
|
177
193
|
claude plugin marketplace remove OpenSocrates --scope user
|
|
178
|
-
npx --yes opensocrates@1.1.
|
|
194
|
+
npx --yes opensocrates@1.1.4 install --host claude
|
|
179
195
|
```
|
|
180
196
|
|
|
181
197
|
관리형 v1.1.0 Claude 설치를 업데이트하면 패키지 트리 전체가 교체됩니다. 따라서
|
|
@@ -262,8 +278,21 @@ OpenSocrates 기록, 로그, 메트릭, 진단 또는 instruction 파일에 쓰
|
|
|
262
278
|
전체 Read 응답은 메모리에서 종료 표식만 확인하고 보관하지 않습니다. 소유자 전용
|
|
263
279
|
접지 영수증에는 artifact 해시, 콘텐츠 리비전, 선택한 방법 ID, 키 기반 인증 및
|
|
264
280
|
도구 사용 태그만 저장하며 프롬프트, 도구 출력, 워크스페이스 경로와 artifact 경로는
|
|
265
|
-
저장하지 않습니다. `Stop`에서 현재 turn 파일과
|
|
266
|
-
|
|
281
|
+
저장하지 않습니다. `Stop`에서 현재 turn 파일과 영수증을 삭제합니다. `Stop`이 오지
|
|
282
|
+
않으면 같은 세션의 다음 `UserPromptSubmit`이 새 turn을 선택하기 전에 이전
|
|
283
|
+
`prompt_id` 트리를 모두 삭제하되 새 활성 트리는 보존합니다. `SessionEnd`는 세션에
|
|
284
|
+
남은 파일을 삭제하고, 다음 `SessionStart`는 24시간이 지난 비정상 종료 잔여 파일을
|
|
285
|
+
삭제합니다.
|
|
286
|
+
|
|
287
|
+
Claude 셀렉터 시도는 `executable_missing`, `request_rejected`, `spawn_failed`,
|
|
288
|
+
`timeout`, `nonzero_exit`, `invalid_output`, `selector_closed`,
|
|
289
|
+
`no_intervention`, `selected`라는 고정 라벨만 사용해 소유자 전용 로컬 집계에
|
|
290
|
+
누적됩니다. `diagnose`는 이 누적 횟수를 표시합니다. 집계에는 시각, 프롬프트,
|
|
291
|
+
대화 기록, 세션·turn ID, 경로, 모델 출력, 자격 증명 또는 추론이 없으며 외부로
|
|
292
|
+
업로드되지 않습니다.
|
|
293
|
+
집계를 읽을 수 없으면 `diagnose`는 시도 0회라고 단정하지 않고 `unavailable`로
|
|
294
|
+
표시합니다. 다음 유효한 셀렉터 결과가 현재 스키마의 손상된 집계를 새로운 제한된
|
|
295
|
+
카운트 문서로 교체하며, 알 수 없는 미래 스키마는 해당 새 런타임을 위해 보존합니다.
|
|
267
296
|
|
|
268
297
|
자동 업데이트를 켜면 앞서 설명한 desired state와 간결한 영수증만 소유자 전용
|
|
269
298
|
권한으로 저장합니다. 실행 중인 Claude나 Codex 세션을 검사하거나 종료하지 않습니다.
|
|
@@ -283,6 +312,20 @@ OpenSocrates 기록, 로그, 메트릭, 진단 또는 instruction 파일에 쓰
|
|
|
283
312
|
인증된 실제 Claude Code 및 Codex 홈에서 검증하고 개인정보를 뺀 근거 묶음을
|
|
284
313
|
확보하세요.
|
|
285
314
|
|
|
315
|
+
셀렉터의 인증된 Claude 하위 프로세스 계약은 별도의
|
|
316
|
+
[선택형 검사](docs/real-claude-selector.md)로 검증합니다. 인증된 v1.1.2 영수증은 실제
|
|
317
|
+
하위 프로세스 격리 및 구조화 출력 계약을 통과했으며, 일반 오프라인 테스트는 이
|
|
318
|
+
실제 호출을 다시 실행하지 않습니다.
|
|
319
|
+
|
|
320
|
+
`--max-turns 1` 구조화 출력의 반복 동작은 별도의
|
|
321
|
+
[집계 신뢰성 매트릭스](docs/claude-structured-output-reliability.md)로 검증합니다. 인증된
|
|
322
|
+
Claude Code 2.1.226의 `host-default` 행은 20/20회를 통과했으며, 관측하지 않은
|
|
323
|
+
명시적 모델은 지원된다고 주장하지 않습니다.
|
|
324
|
+
|
|
325
|
+
패키지 Claude PostToolUse 영수증과 Stop 정리 지연 시간에는 재현 가능한
|
|
326
|
+
[Apple Silicon 측정 영수증](docs/claude-hook-timing.md)이 있습니다. v1.1.2에서 관측한
|
|
327
|
+
p95는 3초 훅 예산의 절반 이상을 여유로 남겨 타임아웃을 변경하지 않았습니다.
|
|
328
|
+
|
|
286
329
|
```bash
|
|
287
330
|
make bootstrap
|
|
288
331
|
make format-check
|
package/README.md
CHANGED
|
@@ -17,16 +17,21 @@ uses a fresh host-native selector to choose relevant systems, and adds their
|
|
|
17
17
|
complete theory and examples to the active task. Straightforward factual and
|
|
18
18
|
mechanical work can pass through unchanged.
|
|
19
19
|
|
|
20
|
-
Version `1.1.
|
|
20
|
+
Version `1.1.4` includes 48 reasoning systems, one user-facing Claude entry, a
|
|
21
21
|
Claude grounding gate that verifies selected procedures were read, coordinated
|
|
22
22
|
Claude/Codex lifecycle management, and opt-in automatic updates on
|
|
23
23
|
Apple-silicon macOS (`darwin-arm64`). It uses your existing host login and does
|
|
24
24
|
not require an API key or an OpenSocrates backend.
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
The native plugin archives intentionally ship only `bin/launch.sh`. That
|
|
27
|
+
launcher accepts `darwin-arm64` only; macOS Intel, Linux, and Windows launchers
|
|
28
|
+
and runtimes are not shipped or supported in this release.
|
|
29
|
+
|
|
30
|
+
> **Latest release: [OpenSocrates 1.1.4](https://github.com/ParkerHwang/OpenSocrates/releases/tag/v1.1.4).**
|
|
31
|
+
> It adds a Cowork-uploadable native Claude package, host-split runtimes, and
|
|
32
|
+
> content-free selector diagnostics that distinguish unavailable data from zero.
|
|
33
|
+
> Upgrade both managed hosts together with
|
|
34
|
+
> `npx --yes opensocrates@1.1.4 update --host all`.
|
|
30
35
|
|
|
31
36
|
## Host support
|
|
32
37
|
|
|
@@ -34,9 +39,9 @@ not require an API key or an OpenSocrates backend.
|
|
|
34
39
|
| --- | --- | --- | --- |
|
|
35
40
|
| Codex CLI and Desktop | Yes | OpenSocrates plugin | Release-validated on `darwin-arm64` |
|
|
36
41
|
| Claude Code CLI | Yes, through `UserPromptSubmit` | `/opensocrates` | Locally validated on `darwin-arm64` |
|
|
37
|
-
| Claude Code desktop app |
|
|
38
|
-
| Claude Cowork |
|
|
39
|
-
| Claude web and Desktop Chat | No hooks | `/opensocrates` |
|
|
42
|
+
| Claude Code desktop app | Yes, where Claude Code plugins run | `/opensocrates` | [Authenticated hook lifecycle locally validated](docs/claude-desktop-live-probe.md) |
|
|
43
|
+
| Claude Cowork | Yes, in the tested local plugin upload | `/opensocrates` | [Native hook lifecycle locally validated; direct release upload, no marketplace sync](docs/claude-cowork-live-probe.md) |
|
|
44
|
+
| Claude web and Desktop Chat | No hooks | `/opensocrates` | [Live upload and invocation validated](docs/claude-chat-upload-probe.md) |
|
|
40
45
|
|
|
41
46
|
The status column uses four distinct levels. Do not read them as
|
|
42
47
|
interchangeable:
|
|
@@ -54,11 +59,15 @@ skills, but automatic per-prompt selection is available only on Claude Code
|
|
|
54
59
|
and Cowork surfaces that execute the plugin runtime. OpenSocrates fails open
|
|
55
60
|
if a hook or selector is unavailable.
|
|
56
61
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
+
The published v1.1.2 Claude plugin archive exceeded Cowork's documented
|
|
63
|
+
compressed limit and observed uncompressed limit. A pre-release v1.1.3
|
|
64
|
+
candidate was 13.8 MB compressed and 34.1 MB uncompressed, contained neither
|
|
65
|
+
the Codex runtime nor a nested ZIP, and passed Cowork's local upload. Its
|
|
66
|
+
UserPromptSubmit, PostToolUse(Read), authenticated grounding receipt, Stop, and
|
|
67
|
+
cleanup lifecycle is locally validated. Version 1.1.4 is the first release to
|
|
68
|
+
ship that reviewed package boundary. The repository still has no Cowork
|
|
69
|
+
marketplace manifest, so Cowork installation uses the local plugin upload path
|
|
70
|
+
rather than repository sync.
|
|
62
71
|
|
|
63
72
|
## Install
|
|
64
73
|
|
|
@@ -75,7 +84,7 @@ before registering an owner-marked managed marketplace.
|
|
|
75
84
|
### Install every ready host
|
|
76
85
|
|
|
77
86
|
```bash
|
|
78
|
-
npx --yes opensocrates@1.1.
|
|
87
|
+
npx --yes opensocrates@1.1.4 install --host all
|
|
79
88
|
```
|
|
80
89
|
|
|
81
90
|
The all-host path detects supported, authenticated host CLIs, completes every
|
|
@@ -87,9 +96,9 @@ registration.
|
|
|
87
96
|
Use the same host value for the complete lifecycle:
|
|
88
97
|
|
|
89
98
|
```bash
|
|
90
|
-
npx --yes opensocrates@1.1.
|
|
91
|
-
npx --yes opensocrates@1.1.
|
|
92
|
-
npx --yes opensocrates@1.1.
|
|
99
|
+
npx --yes opensocrates@1.1.4 status --host all
|
|
100
|
+
npx --yes opensocrates@1.1.4 update --host all
|
|
101
|
+
npx --yes opensocrates@1.1.4 remove --host all
|
|
93
102
|
```
|
|
94
103
|
|
|
95
104
|
A private `~/.opensocrates/desired-state.json` manifest records the selected
|
|
@@ -102,9 +111,9 @@ automatic update, and per-host drift.
|
|
|
102
111
|
Codex remains the default host for backward compatibility:
|
|
103
112
|
|
|
104
113
|
```bash
|
|
105
|
-
npx --yes opensocrates@1.1.
|
|
106
|
-
# Equivalent: npx --yes opensocrates@1.1.
|
|
107
|
-
npx --yes opensocrates@1.1.
|
|
114
|
+
npx --yes opensocrates@1.1.4 install
|
|
115
|
+
# Equivalent: npx --yes opensocrates@1.1.4 install --host codex
|
|
116
|
+
npx --yes opensocrates@1.1.4 install --host claude
|
|
108
117
|
```
|
|
109
118
|
|
|
110
119
|
Existing `--host codex` and `--host claude` lifecycle commands remain
|
|
@@ -112,12 +121,21 @@ supported. A host-specific update can intentionally create drift; a later
|
|
|
112
121
|
`update --host all` or successful automatic reconciliation brings every host
|
|
113
122
|
recorded in desired state back to one version.
|
|
114
123
|
|
|
124
|
+
For Claude, status distinguishes an enabled installation from an
|
|
125
|
+
installed-but-disabled plugin. A disabled desired installation is reported as
|
|
126
|
+
drift. Running `install` or `update` intentionally installs the verified
|
|
127
|
+
package enabled again; if activation fails, rollback restores the previous
|
|
128
|
+
enabled or disabled state. The installer accepts only the observed direct JSON
|
|
129
|
+
arrays and explicit `marketplaces`/`plugins` wrappers from Claude's list
|
|
130
|
+
commands. The privacy-safe 2.1.226 fixture is under
|
|
131
|
+
`installer/fixtures/claude-cli/`.
|
|
132
|
+
|
|
115
133
|
### Opt-in automatic updates
|
|
116
134
|
|
|
117
135
|
```bash
|
|
118
|
-
npx --yes opensocrates@1.1.
|
|
119
|
-
npx --yes opensocrates@1.1.
|
|
120
|
-
npx --yes opensocrates@1.1.
|
|
136
|
+
npx --yes opensocrates@1.1.4 auto-update enable --host all
|
|
137
|
+
npx --yes opensocrates@1.1.4 auto-update status
|
|
138
|
+
npx --yes opensocrates@1.1.4 auto-update disable
|
|
121
139
|
```
|
|
122
140
|
|
|
123
141
|
Automatic updates are disabled until explicitly enabled. The macOS LaunchAgent
|
|
@@ -140,8 +158,10 @@ workspace paths. `auto-update disable` unloads and removes the LaunchAgent;
|
|
|
140
158
|
### Claude web and Desktop Chat skills
|
|
141
159
|
|
|
142
160
|
These surfaces support plugin skills but not hooks. Download
|
|
143
|
-
`opensocrates-1.1.
|
|
144
|
-
Claude's
|
|
161
|
+
`opensocrates-1.1.4-claude-chat-skills.zip` from the release and upload it from
|
|
162
|
+
Claude's **Customize → Skills → Upload skill** UI. The ZIP contains one
|
|
163
|
+
top-level `opensocrates/` folder with `SKILL.md` directly inside, as required by
|
|
164
|
+
the skill uploader. The package exposes exactly one
|
|
145
165
|
`/opensocrates` skill; its 48 method procedures, rigor, evidence, and trace
|
|
146
166
|
controls are internal supporting references. Automatic selection is absent
|
|
147
167
|
because Chat does not execute plugin hooks. See Anthropic's
|
|
@@ -152,22 +172,22 @@ because Chat does not execute plugin hooks. See Anthropic's
|
|
|
152
172
|
The same host option works without the npm registry:
|
|
153
173
|
|
|
154
174
|
```bash
|
|
155
|
-
npx --yes github:ParkerHwang/OpenSocrates#v1.1.
|
|
156
|
-
npx --yes github:ParkerHwang/OpenSocrates#v1.1.
|
|
157
|
-
npx --yes github:ParkerHwang/OpenSocrates#v1.1.
|
|
175
|
+
npx --yes github:ParkerHwang/OpenSocrates#v1.1.4 install --host all
|
|
176
|
+
npx --yes github:ParkerHwang/OpenSocrates#v1.1.4 install --host claude
|
|
177
|
+
npx --yes github:ParkerHwang/OpenSocrates#v1.1.4 install --host codex
|
|
158
178
|
```
|
|
159
179
|
|
|
160
180
|
### Manual release verification
|
|
161
181
|
|
|
162
182
|
Download `opensocrates.mjs`, the host package, and its `.sha256` file from the
|
|
163
|
-
[v1.1.
|
|
183
|
+
[v1.1.4 release](https://github.com/ParkerHwang/OpenSocrates/releases/tag/v1.1.4).
|
|
164
184
|
For Claude, for example:
|
|
165
185
|
|
|
166
186
|
```bash
|
|
167
|
-
shasum -a 256 -c opensocrates-1.1.
|
|
187
|
+
shasum -a 256 -c opensocrates-1.1.4-claude-plugin.zip.sha256
|
|
168
188
|
node opensocrates.mjs install --host claude \
|
|
169
|
-
--asset opensocrates-1.1.
|
|
170
|
-
--checksum opensocrates-1.1.
|
|
189
|
+
--asset opensocrates-1.1.4-claude-plugin.zip \
|
|
190
|
+
--checksum opensocrates-1.1.4-claude-plugin.zip.sha256
|
|
171
191
|
```
|
|
172
192
|
|
|
173
193
|
Replace `claude` with `codex` for the Codex package.
|
|
@@ -182,7 +202,7 @@ what is installed, remove it explicitly:
|
|
|
182
202
|
```bash
|
|
183
203
|
claude plugin uninstall opensocrates@OpenSocrates --scope user
|
|
184
204
|
claude plugin marketplace remove OpenSocrates --scope user
|
|
185
|
-
npx --yes opensocrates@1.1.
|
|
205
|
+
npx --yes opensocrates@1.1.4 install --host claude
|
|
186
206
|
```
|
|
187
207
|
|
|
188
208
|
Updating a managed v1.1.0 Claude installation replaces the complete package
|
|
@@ -276,9 +296,22 @@ or instruction files. The complete Read response is inspected only in memory
|
|
|
276
296
|
for its terminal marker and is not retained. The owner-only grounding receipt
|
|
277
297
|
stores only an artifact digest, content revision, selected method IDs, and
|
|
278
298
|
keyed authentication/tool-use tags—never a prompt, tool output, workspace path,
|
|
279
|
-
or artifact path. Turn files and receipts are removed on `Stop
|
|
280
|
-
|
|
281
|
-
`
|
|
299
|
+
or artifact path. Turn files and receipts are removed on `Stop`. If `Stop` never
|
|
300
|
+
arrives, the next `UserPromptSubmit` in the same session removes every prior
|
|
301
|
+
`prompt_id` tree before selecting for the new turn while preserving the new
|
|
302
|
+
active tree. `SessionEnd` removes anything still left in the session, and the
|
|
303
|
+
next `SessionStart` removes crash leftovers older than 24 hours.
|
|
304
|
+
|
|
305
|
+
Claude selector attempts increment one owner-only local aggregate using only
|
|
306
|
+
the fixed labels `executable_missing`, `request_rejected`, `spawn_failed`,
|
|
307
|
+
`timeout`, `nonzero_exit`, `invalid_output`, `selector_closed`,
|
|
308
|
+
`no_intervention`, and `selected`. `diagnose` reports those cumulative counts.
|
|
309
|
+
The aggregate contains no timestamp, prompt, transcript, session or turn ID,
|
|
310
|
+
path, model output, credential, or reasoning, and is never uploaded.
|
|
311
|
+
If the aggregate is unreadable, `diagnose` reports it as `unavailable` instead
|
|
312
|
+
of asserting zero attempts. The next valid selector outcome replaces a
|
|
313
|
+
malformed current-schema aggregate with a fresh bounded count document; an
|
|
314
|
+
unknown future schema is preserved for the newer runtime that owns it.
|
|
282
315
|
|
|
283
316
|
When enabled, the updater stores only desired lifecycle state and the concise
|
|
284
317
|
receipt described above, under owner-only permissions. It does not inspect or
|
|
@@ -299,6 +332,21 @@ Before merging a release candidate, follow the
|
|
|
299
332
|
to exercise the real authenticated Claude Code and Codex homes and return a
|
|
300
333
|
privacy-safe evidence bundle.
|
|
301
334
|
|
|
335
|
+
The selector's authenticated Claude subprocess contract has a separate
|
|
336
|
+
[opt-in check](docs/real-claude-selector.md). The authenticated v1.1.2 receipt
|
|
337
|
+
passes the real subprocess isolation and structured-output contract; the live
|
|
338
|
+
call is never rerun by the ordinary offline suite.
|
|
339
|
+
|
|
340
|
+
Repeated `--max-turns 1` structured-output behavior has a separate
|
|
341
|
+
[aggregate reliability matrix](docs/claude-structured-output-reliability.md).
|
|
342
|
+
The authenticated Claude Code 2.1.226 `host-default` row passed 20/20 attempts;
|
|
343
|
+
no unobserved named model is claimed supported.
|
|
344
|
+
|
|
345
|
+
Packaged Claude PostToolUse receipt and Stop cleanup latency has a reproducible
|
|
346
|
+
[Apple-silicon timing receipt](docs/claude-hook-timing.md). The observed v1.1.2
|
|
347
|
+
p95 results retain more than half of the 3-second hook budget, so the timeout is
|
|
348
|
+
unchanged.
|
|
349
|
+
|
|
302
350
|
```bash
|
|
303
351
|
make bootstrap
|
|
304
352
|
make format-check
|
package/SECURITY.md
CHANGED
|
@@ -62,6 +62,17 @@ small set of allowed path variables because the child needs it to locate the
|
|
|
62
62
|
user's existing Claude login when a non-default config directory is in use.
|
|
63
63
|
OpenSocrates does not copy, inspect, or log credentials from that directory.
|
|
64
64
|
|
|
65
|
+
For fail-open diagnosis, each Claude selector attempt increments one
|
|
66
|
+
owner-only local aggregate under a closed nine-label vocabulary. The aggregate
|
|
67
|
+
stores counts only: it has no timestamp, prompt, transcript, session or turn
|
|
68
|
+
identifier, path, model output, credential, or reasoning. It is shown by the
|
|
69
|
+
local `diagnose` command and is never transmitted.
|
|
70
|
+
An unreadable aggregate is reported as `unavailable`, never as zero observed
|
|
71
|
+
attempts. The next valid selector outcome atomically replaces only a malformed
|
|
72
|
+
current-schema aggregate with a fresh bounded count document; an unknown future
|
|
73
|
+
schema is preserved. Rejected malformed bytes are never copied into another
|
|
74
|
+
file.
|
|
75
|
+
|
|
65
76
|
Managed policy settings are part of the host trust boundary and are not disabled.
|
|
66
77
|
Anthropic's [CLI reference](https://code.claude.com/docs/en/cli-reference) states
|
|
67
78
|
that under `--safe-mode` "managed settings policy still applies, including
|
|
@@ -86,7 +97,10 @@ does not retain the response. The owner-only authenticated receipt stores only
|
|
|
86
97
|
the artifact digest, content revision, selected method IDs, and keyed
|
|
87
98
|
authentication/tool-use tags; prompts, transcripts, raw tool output,
|
|
88
99
|
credentials, workspace paths, and artifact paths are excluded. `Stop` removes
|
|
89
|
-
the receipt with the turn artifact
|
|
100
|
+
the receipt with the turn artifact. If `Stop` is absent, the next
|
|
101
|
+
`UserPromptSubmit` in that session removes prior prompt trees without touching
|
|
102
|
+
the new active tree. `SessionEnd` remains the session backstop, and the
|
|
103
|
+
24-hour `SessionStart` sweep covers crash leftovers when neither event arrives.
|
|
90
104
|
|
|
91
105
|
The gate's scope is deliberate and worth stating plainly. It establishes that a
|
|
92
106
|
successful `Read` callback naming the exact current-turn artifact returned
|
|
@@ -107,7 +121,14 @@ transcripts, workspace paths, credentials, and raw error output are excluded.
|
|
|
107
121
|
Automatic major-version upgrades are disabled unless the user explicitly
|
|
108
122
|
changes that policy.
|
|
109
123
|
|
|
124
|
+
Installer rollback mutates only its owner-marked managed marketplace root. If
|
|
125
|
+
the failed root cannot be removed and the previous backup therefore cannot be
|
|
126
|
+
renamed into place, the installer preserves that backup and prints quoted,
|
|
127
|
+
executable recovery commands naming only those two managed paths.
|
|
128
|
+
|
|
110
129
|
Signing, notarization, clean-machine installation, platforms other than
|
|
111
130
|
`darwin-arm64`, Claude Chat automatic hooks, and live delivery on every host
|
|
112
|
-
surface are not claimed as validated.
|
|
113
|
-
|
|
131
|
+
surface are not claimed as validated. Native plugin archives ship only
|
|
132
|
+
`bin/launch.sh`; it rejects macOS Intel, Linux, Windows, and every other target,
|
|
133
|
+
and no PowerShell launcher is included. See the release limitations file for
|
|
134
|
+
the complete measured boundary.
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.1.
|
|
1
|
+
1.1.4
|
|
@@ -24,7 +24,7 @@ import { Readable } from "node:stream";
|
|
|
24
24
|
import { pipeline } from "node:stream/promises";
|
|
25
25
|
import { fileURLToPath } from "node:url";
|
|
26
26
|
|
|
27
|
-
export const PRODUCT_VERSION = "1.1.
|
|
27
|
+
export const PRODUCT_VERSION = "1.1.4";
|
|
28
28
|
export const REPOSITORY = "ParkerHwang/OpenSocrates";
|
|
29
29
|
export const MARKETPLACE_NAME = "opensocrates";
|
|
30
30
|
export const PLUGIN_NAME = "opensocrates";
|
|
@@ -83,6 +83,10 @@ function fail(message) {
|
|
|
83
83
|
throw new InstallerError(message);
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
+
function shellQuote(value) {
|
|
87
|
+
return `'${String(value).replaceAll("'", `'"'"'`)}'`;
|
|
88
|
+
}
|
|
89
|
+
|
|
86
90
|
async function exists(target) {
|
|
87
91
|
try {
|
|
88
92
|
await access(target);
|
|
@@ -703,6 +707,58 @@ function runClaudeJson(args) {
|
|
|
703
707
|
return runJson(claudeBinary(), args, "Claude Code");
|
|
704
708
|
}
|
|
705
709
|
|
|
710
|
+
function claudeListEntries(payload, wrapper, label) {
|
|
711
|
+
if (Array.isArray(payload)) {
|
|
712
|
+
return payload;
|
|
713
|
+
}
|
|
714
|
+
if (
|
|
715
|
+
payload !== null &&
|
|
716
|
+
typeof payload === "object" &&
|
|
717
|
+
!Array.isArray(payload) &&
|
|
718
|
+
Object.keys(payload).length === 1 &&
|
|
719
|
+
Array.isArray(payload[wrapper])
|
|
720
|
+
) {
|
|
721
|
+
return payload[wrapper];
|
|
722
|
+
}
|
|
723
|
+
fail(`Claude Code ${label} returned an unexpected schema`);
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
function requireUniqueClaudeEntries(entries, identity, label) {
|
|
727
|
+
const seen = new Set();
|
|
728
|
+
for (const entry of entries) {
|
|
729
|
+
if (
|
|
730
|
+
entry === null ||
|
|
731
|
+
typeof entry !== "object" ||
|
|
732
|
+
Array.isArray(entry) ||
|
|
733
|
+
typeof entry[identity] !== "string" ||
|
|
734
|
+
entry[identity].trim().length === 0
|
|
735
|
+
) {
|
|
736
|
+
fail(`Claude Code ${label} returned a malformed entry`);
|
|
737
|
+
}
|
|
738
|
+
if (seen.has(entry[identity])) {
|
|
739
|
+
fail(`Claude Code ${label} returned duplicate entries for ${entry[identity]}`);
|
|
740
|
+
}
|
|
741
|
+
seen.add(entry[identity]);
|
|
742
|
+
}
|
|
743
|
+
return entries;
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
function claudeMarketplaceEntries(payload) {
|
|
747
|
+
return requireUniqueClaudeEntries(
|
|
748
|
+
claudeListEntries(payload, "marketplaces", "marketplace list"),
|
|
749
|
+
"name",
|
|
750
|
+
"marketplace list",
|
|
751
|
+
);
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
function claudePluginEntries(payload) {
|
|
755
|
+
return requireUniqueClaudeEntries(
|
|
756
|
+
claudeListEntries(payload, "plugins", "plugin list"),
|
|
757
|
+
"id",
|
|
758
|
+
"plugin list",
|
|
759
|
+
);
|
|
760
|
+
}
|
|
761
|
+
|
|
706
762
|
function versionAtLeast(value, minimum) {
|
|
707
763
|
const match = String(value).match(/(\d+)\.(\d+)\.(\d+)/u);
|
|
708
764
|
if (!match) {
|
|
@@ -740,7 +796,7 @@ function marketplaceEntries(host) {
|
|
|
740
796
|
host === "claude"
|
|
741
797
|
? runClaudeJson(["plugin", "marketplace", "list", "--json"])
|
|
742
798
|
: runCodexJson(["plugin", "marketplace", "list", "--json"]).marketplaces;
|
|
743
|
-
const entries = payload;
|
|
799
|
+
const entries = host === "claude" ? claudeMarketplaceEntries(payload) : payload;
|
|
744
800
|
if (!Array.isArray(entries)) {
|
|
745
801
|
fail(`${host} marketplace list returned an unexpected schema`);
|
|
746
802
|
}
|
|
@@ -758,17 +814,22 @@ function marketplaceEntry(host) {
|
|
|
758
814
|
|
|
759
815
|
function pluginState(host) {
|
|
760
816
|
if (host === "claude") {
|
|
761
|
-
const installed = runClaudeJson(["plugin", "list", "--json"]);
|
|
762
|
-
if (!Array.isArray(installed)) {
|
|
763
|
-
fail("Claude Code plugin list returned an unexpected schema");
|
|
764
|
-
}
|
|
817
|
+
const installed = claudePluginEntries(runClaudeJson(["plugin", "list", "--json"]));
|
|
765
818
|
const matches = installed.filter((entry) => entry?.id === PLUGIN_ID);
|
|
766
|
-
if (matches.length
|
|
767
|
-
|
|
819
|
+
if (matches.length === 0) return { kind: "missing", version: null };
|
|
820
|
+
const entry = matches[0];
|
|
821
|
+
if (
|
|
822
|
+
(entry.version !== undefined &&
|
|
823
|
+
entry.version !== null &&
|
|
824
|
+
(typeof entry.version !== "string" || entry.version.trim().length === 0)) ||
|
|
825
|
+
typeof entry.enabled !== "boolean"
|
|
826
|
+
) {
|
|
827
|
+
fail(`Claude Code reported an invalid state for ${PLUGIN_ID}`);
|
|
768
828
|
}
|
|
769
|
-
return
|
|
770
|
-
|
|
771
|
-
:
|
|
829
|
+
return {
|
|
830
|
+
kind: entry.enabled ? "installed" : "disabled",
|
|
831
|
+
version: entry.version ?? null,
|
|
832
|
+
};
|
|
772
833
|
}
|
|
773
834
|
const payload = runCodexJson([
|
|
774
835
|
"plugin", "list", "--marketplace", MARKETPLACE_NAME, "--available", "--json",
|
|
@@ -799,15 +860,12 @@ function detectLegacyClaudeInstallation() {
|
|
|
799
860
|
entry.name !== MARKETPLACE_NAME &&
|
|
800
861
|
entry.name.toLowerCase() === MARKETPLACE_NAME,
|
|
801
862
|
);
|
|
802
|
-
const plugins = runClaudeJson(["plugin", "list", "--json"]);
|
|
803
|
-
const legacyPlugins =
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
entry.id.toLowerCase() === PLUGIN_ID,
|
|
809
|
-
)
|
|
810
|
-
: [];
|
|
863
|
+
const plugins = claudePluginEntries(runClaudeJson(["plugin", "list", "--json"]));
|
|
864
|
+
const legacyPlugins = plugins.filter(
|
|
865
|
+
(entry) =>
|
|
866
|
+
entry.id !== PLUGIN_ID &&
|
|
867
|
+
entry.id.toLowerCase() === PLUGIN_ID,
|
|
868
|
+
);
|
|
811
869
|
const names = marketplaces.map((entry) => entry.name).join(", ") || "OpenSocrates";
|
|
812
870
|
return { found: marketplaces.length > 0 || legacyPlugins.length > 0, names };
|
|
813
871
|
}
|
|
@@ -1148,7 +1206,34 @@ function entryRoot(entry, host) {
|
|
|
1148
1206
|
if (entry === null) {
|
|
1149
1207
|
return null;
|
|
1150
1208
|
}
|
|
1151
|
-
|
|
1209
|
+
let value;
|
|
1210
|
+
if (host === "claude") {
|
|
1211
|
+
const fields = ["path", "installLocation"].filter(
|
|
1212
|
+
(field) => entry[field] !== undefined && entry[field] !== null,
|
|
1213
|
+
);
|
|
1214
|
+
if (
|
|
1215
|
+
fields.length === 0 ||
|
|
1216
|
+
fields.some(
|
|
1217
|
+
(field) => typeof entry[field] !== "string" || entry[field].trim().length === 0,
|
|
1218
|
+
)
|
|
1219
|
+
) {
|
|
1220
|
+
fail(`${host} marketplace ${MARKETPLACE_NAME} has no usable root`);
|
|
1221
|
+
}
|
|
1222
|
+
const roots = fields.map((field) => {
|
|
1223
|
+
const candidate = resolve(entry[field]);
|
|
1224
|
+
try {
|
|
1225
|
+
return realpathSync(candidate);
|
|
1226
|
+
} catch {
|
|
1227
|
+
return candidate;
|
|
1228
|
+
}
|
|
1229
|
+
});
|
|
1230
|
+
if (new Set(roots).size !== 1) {
|
|
1231
|
+
fail(`${host} marketplace ${MARKETPLACE_NAME} reported conflicting roots`);
|
|
1232
|
+
}
|
|
1233
|
+
[value] = roots;
|
|
1234
|
+
} else {
|
|
1235
|
+
value = entry.root;
|
|
1236
|
+
}
|
|
1152
1237
|
if (typeof value !== "string" || value.trim().length === 0) {
|
|
1153
1238
|
fail(`${host} marketplace ${MARKETPLACE_NAME} has no usable root`);
|
|
1154
1239
|
}
|
|
@@ -1166,7 +1251,7 @@ function entryRoot(entry, host) {
|
|
|
1166
1251
|
|
|
1167
1252
|
function removeRegistration(host, entry, state) {
|
|
1168
1253
|
if (host === "claude") {
|
|
1169
|
-
if (state.kind
|
|
1254
|
+
if (["installed", "disabled"].includes(state.kind)) {
|
|
1170
1255
|
run(claudeBinary(), ["plugin", "uninstall", PLUGIN_ID, "--scope", "user"]);
|
|
1171
1256
|
}
|
|
1172
1257
|
if (entry !== null) {
|
|
@@ -1184,11 +1269,14 @@ function removeRegistration(host, entry, state) {
|
|
|
1184
1269
|
}
|
|
1185
1270
|
}
|
|
1186
1271
|
|
|
1187
|
-
function addRegistration(host, root, installPlugin) {
|
|
1272
|
+
function addRegistration(host, root, installPlugin, { enabled = true } = {}) {
|
|
1188
1273
|
if (host === "claude") {
|
|
1189
1274
|
run(claudeBinary(), ["plugin", "marketplace", "add", root, "--scope", "user"]);
|
|
1190
1275
|
if (installPlugin) {
|
|
1191
1276
|
run(claudeBinary(), ["plugin", "install", PLUGIN_ID, "--scope", "user"]);
|
|
1277
|
+
if (!enabled) {
|
|
1278
|
+
run(claudeBinary(), ["plugin", "disable", PLUGIN_ID, "--scope", "user"]);
|
|
1279
|
+
}
|
|
1192
1280
|
}
|
|
1193
1281
|
return null;
|
|
1194
1282
|
}
|
|
@@ -1212,7 +1300,7 @@ function removeRegistrationBestEffort(host) {
|
|
|
1212
1300
|
}
|
|
1213
1301
|
try {
|
|
1214
1302
|
const state = pluginState(host);
|
|
1215
|
-
if (state.kind
|
|
1303
|
+
if (["installed", "disabled"].includes(state.kind)) {
|
|
1216
1304
|
const binary = host === "claude" ? claudeBinary() : codexBinary();
|
|
1217
1305
|
const args =
|
|
1218
1306
|
host === "claude"
|
|
@@ -1403,7 +1491,12 @@ async function rollbackInstallation(transaction) {
|
|
|
1403
1491
|
(restored || !transaction.backupCreated)
|
|
1404
1492
|
) {
|
|
1405
1493
|
await recoveryStep(`re-register the previous ${host} installation`, async () => {
|
|
1406
|
-
addRegistration(
|
|
1494
|
+
addRegistration(
|
|
1495
|
+
host,
|
|
1496
|
+
paths.root,
|
|
1497
|
+
["installed", "disabled"].includes(previousState.kind),
|
|
1498
|
+
{ enabled: previousState.kind !== "disabled" },
|
|
1499
|
+
);
|
|
1407
1500
|
});
|
|
1408
1501
|
}
|
|
1409
1502
|
if (transaction.backupCreated && !restored) {
|
|
@@ -1411,10 +1504,11 @@ async function rollbackInstallation(transaction) {
|
|
|
1411
1504
|
`error: the previous ${host} OpenSocrates installation could not be restored automatically.`,
|
|
1412
1505
|
);
|
|
1413
1506
|
console.error(`error: your previous files are preserved at: ${transaction.backup}`);
|
|
1507
|
+
console.error(`error: recovery command: /bin/rm -rf -- ${shellQuote(paths.root)}`);
|
|
1414
1508
|
console.error(
|
|
1415
|
-
`error:
|
|
1416
|
-
`to ${paths.root}, then rerun \`opensocrates install --host ${host}\`.`,
|
|
1509
|
+
`error: recovery command: /bin/mv -- ${shellQuote(transaction.backup)} ${shellQuote(paths.root)}`,
|
|
1417
1510
|
);
|
|
1511
|
+
console.error(`error: recovery command: opensocrates install --host ${host}`);
|
|
1418
1512
|
}
|
|
1419
1513
|
}
|
|
1420
1514
|
|
|
@@ -1537,6 +1631,11 @@ async function showStatus(host) {
|
|
|
1537
1631
|
: " (in sync)"
|
|
1538
1632
|
: " (not in desired state)"),
|
|
1539
1633
|
);
|
|
1634
|
+
} else if (status.kind === "disabled") {
|
|
1635
|
+
console.log(
|
|
1636
|
+
`${candidate}: installed but disabled (${status.version ?? "unknown"})` +
|
|
1637
|
+
(expected ? " (drift: desired host is not active)" : " (not in desired state)"),
|
|
1638
|
+
);
|
|
1540
1639
|
} else if (status.kind === "available") {
|
|
1541
1640
|
console.log(
|
|
1542
1641
|
`${candidate}: available but not installed (${status.version ?? "unknown"})` +
|
|
@@ -1563,6 +1662,11 @@ async function showStatus(host) {
|
|
|
1563
1662
|
const status = await inspectHostStatus(host);
|
|
1564
1663
|
if (status.kind === "installed") {
|
|
1565
1664
|
console.log(`OpenSocrates ${status.version ?? "unknown"} is installed.`);
|
|
1665
|
+
} else if (status.kind === "disabled") {
|
|
1666
|
+
console.log(
|
|
1667
|
+
`OpenSocrates ${status.version ?? "unknown"} is installed but disabled. ` +
|
|
1668
|
+
"Run install or update to re-enable it.",
|
|
1669
|
+
);
|
|
1566
1670
|
} else if (status.kind === "available") {
|
|
1567
1671
|
console.log(`OpenSocrates ${status.version ?? "unknown"} is available but not installed.`);
|
|
1568
1672
|
} else if (status.kind === "files-only") {
|
|
@@ -1606,7 +1710,8 @@ async function rollbackRemoval(transaction) {
|
|
|
1606
1710
|
addRegistration(
|
|
1607
1711
|
transaction.host,
|
|
1608
1712
|
transaction.paths.root,
|
|
1609
|
-
transaction.previousState.kind
|
|
1713
|
+
["installed", "disabled"].includes(transaction.previousState.kind),
|
|
1714
|
+
{ enabled: transaction.previousState.kind !== "disabled" },
|
|
1610
1715
|
);
|
|
1611
1716
|
});
|
|
1612
1717
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opensocrates",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.4",
|
|
4
4
|
"description": "Install and manage OpenSocrates for Claude Code, Cowork, and Codex.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"VERSION"
|
|
14
14
|
],
|
|
15
15
|
"scripts": {
|
|
16
|
-
"test": "node --test installer/opensocrates.test.mjs installer/lifecycle.test.mjs tools/clean_machine_acceptance.test.mjs && npm run test:npx",
|
|
16
|
+
"test": "node --test installer/opensocrates.test.mjs installer/lifecycle.test.mjs tools/clean_machine_acceptance.test.mjs tools/release_gate.test.mjs && npm run test:npx",
|
|
17
17
|
"test:npx": "node installer/package-smoke.mjs",
|
|
18
18
|
"pack:check": "npm pack --dry-run",
|
|
19
19
|
"prepublishOnly": "npm test"
|