sneakoscope 8.0.0 → 8.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/crates/sks-core/Cargo.lock +1 -1
- package/crates/sks-core/Cargo.toml +1 -1
- package/dist/commands/doctor-profile.js +1 -0
- package/dist/commands/doctor.js +39 -0
- package/dist/config/skills-manifest.json +48 -48
- package/dist/core/codex-lb/codex-lb-env.js +28 -4
- package/dist/core/doctor/codex-config-syntax-repair.js +253 -0
- package/dist/core/update-check.js +59 -10
- package/dist/core/version.js +1 -1
- package/dist/native/sks-menubar/Sources/OperationCoordinator.swift +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -22,7 +22,7 @@ Proof-first orchestration for Codex CLI, ChatGPT Desktop, AI coding agents, mult
|
|
|
22
22
|
Sneakoscope Codex (`sks`) is an open-source trust layer for Codex CLI and ChatGPT Desktop. It coordinates bounded AI coding agents, records machine-verifiable evidence, preserves project memory, and blocks release claims that are not supported by current tests or artifacts. Search visibility outcomes are measured separately; SKS does not promise rankings or traffic.
|
|
23
23
|
<!-- END SKS SEARCH VISIBILITY MARKETING -->
|
|
24
24
|
|
|
25
|
-
This README documents package **SKS 8.0.
|
|
25
|
+
This README documents package **SKS 8.0.1** — its own identity, read from `package.json` and subject to release-gate verification, not advice about what to install.
|
|
26
26
|
|
|
27
27
|
Use the official latest stable SKS and Codex CLI releases. SKS stays version-agnostic: older hosts keep working where capabilities allow, while Menu Bar / Center induce updates to the latest stable build. Run `sks update-check` for what is installed and read the capability report for what is actually supported — feature availability is decided by capability probes, not by a version number printed in a document. It resolves managed SKS skills from the authoritative global install, preserves a runnable Naruto child slot when `max_threads=2`, and keeps Menu Bar repair transactional so stamped generations remain verifiable. Naruto uses stable opt-in multi-agent V2 when the host exposes it. Local code search is mode-separated (`sks search files|text|structure|symbol|context`); `context` is answered by the compiled TriWiki Context Graph with evidence paths rather than lexical guessing — see [docs/architecture/context-graph.md](docs/architecture/context-graph.md) and [docs/architecture/search-engine-target.md](docs/architecture/search-engine-target.md). See [CHANGELOG.md](CHANGELOG.md).
|
|
28
28
|
|
package/dist/commands/doctor.js
CHANGED
|
@@ -559,6 +559,20 @@ async function runDoctor(args = [], root, doctorFix) {
|
|
|
559
559
|
: null;
|
|
560
560
|
const codexDoctorDiff = compareCodexDoctorBridge(codexDoctorBefore, preRepairCodexDoctor);
|
|
561
561
|
codexStartupRepair = mergeObservedCodexStartupWarnings(codexStartupRepair, preRepairCodexDoctor);
|
|
562
|
+
const codexConfigSyntaxRepair = doctorPhaseIds.includes('codex_config_syntax_repair')
|
|
563
|
+
? await (await import('../core/doctor/codex-config-syntax-repair.js')).runCodexConfigSyntaxRepair({ root, fix: doctorFix }).catch((err) => ({
|
|
564
|
+
schema: 'sks.codex-config-syntax-repair.v1',
|
|
565
|
+
ok: false,
|
|
566
|
+
generated_at: new Date().toISOString(),
|
|
567
|
+
fix: doctorFix,
|
|
568
|
+
configs: [],
|
|
569
|
+
actions: [],
|
|
570
|
+
manual_actions: [],
|
|
571
|
+
blockers: [err?.message || String(err)],
|
|
572
|
+
warnings: [],
|
|
573
|
+
report_path: `${root}/.sneakoscope/reports/codex-config-syntax-repair.json`
|
|
574
|
+
}))
|
|
575
|
+
: null;
|
|
562
576
|
const codex = codexBin
|
|
563
577
|
? { bin: codexBin, version: 'fixture-or-explicit', available: true }
|
|
564
578
|
: await getCodexInfo().catch(() => ({ bin: null, version: null, available: false }));
|
|
@@ -858,6 +872,17 @@ async function runDoctor(args = [], root, doctorFix) {
|
|
|
858
872
|
rollback_evidence: startupConfigRepair?.backup_path || 'startup_config_repair_idempotent_report'
|
|
859
873
|
})
|
|
860
874
|
},
|
|
875
|
+
{
|
|
876
|
+
id: 'codex_config_syntax_repair',
|
|
877
|
+
run: async () => ({
|
|
878
|
+
id: 'codex_config_syntax_repair',
|
|
879
|
+
ok: codexConfigSyntaxRepair?.ok !== false,
|
|
880
|
+
repaired: doctorFix && (codexConfigSyntaxRepair?.configs || []).some((entry) => entry.changed),
|
|
881
|
+
blockers: codexConfigSyntaxRepair?.blockers || [],
|
|
882
|
+
warnings: codexConfigSyntaxRepair?.warnings || [],
|
|
883
|
+
rollback_evidence: codexConfigSyntaxRepair?.report_path || 'codex_config_syntax_repair_report'
|
|
884
|
+
})
|
|
885
|
+
},
|
|
861
886
|
{
|
|
862
887
|
id: 'context7_repair',
|
|
863
888
|
run: async () => ({
|
|
@@ -1232,6 +1257,7 @@ async function runDoctor(args = [], root, doctorFix) {
|
|
|
1232
1257
|
context7_repair: context7Repair,
|
|
1233
1258
|
codex_startup_repair: codexStartupRepair,
|
|
1234
1259
|
startup_config_repair: startupConfigRepair,
|
|
1260
|
+
codex_config_syntax_repair: codexConfigSyntaxRepair,
|
|
1235
1261
|
context7_mcp_repair: context7McpRepair,
|
|
1236
1262
|
supabase_mcp_repair: supabaseMcpRepair,
|
|
1237
1263
|
doctor_fix_transaction: doctorFixTransaction,
|
|
@@ -1254,6 +1280,7 @@ async function runDoctor(args = [], root, doctorFix) {
|
|
|
1254
1280
|
...(configRepair?.operator_actions || []),
|
|
1255
1281
|
...(zellijRepair && !zellijRepair.ok && zellijRepair.command ? [`Run: ${zellijRepair.command}`] : []),
|
|
1256
1282
|
...(codexStartupRepair.manual_actions || []),
|
|
1283
|
+
...(codexConfigSyntaxRepair?.manual_actions || []),
|
|
1257
1284
|
...(pluginPolicy?.doctor_warnings || [])
|
|
1258
1285
|
]
|
|
1259
1286
|
});
|
|
@@ -1310,6 +1337,7 @@ async function runDoctor(args = [], root, doctorFix) {
|
|
|
1310
1337
|
&& (!sksUpdate || sksUpdate.ok !== false)
|
|
1311
1338
|
&& commandAliasCleanup.ok !== false
|
|
1312
1339
|
&& codexStartupRepair.ok !== false
|
|
1340
|
+
&& codexConfigSyntaxRepair?.ok !== false
|
|
1313
1341
|
&& agentRoleConfigRepair.ok !== false
|
|
1314
1342
|
&& openRouterProviderRepair.ok !== false
|
|
1315
1343
|
&& (officialSubagentConfig.blockers || []).length === 0
|
|
@@ -1345,6 +1373,7 @@ async function runDoctor(args = [], root, doctorFix) {
|
|
|
1345
1373
|
context7_repair: context7Repair,
|
|
1346
1374
|
codex_startup_repair: codexStartupRepair,
|
|
1347
1375
|
startup_config_repair: startupConfigRepair,
|
|
1376
|
+
codex_config_syntax_repair: codexConfigSyntaxRepair,
|
|
1348
1377
|
context7_mcp_repair: context7McpRepair,
|
|
1349
1378
|
supabase_mcp_repair: supabaseMcpRepair,
|
|
1350
1379
|
doctor_fix_transaction: doctorFixTransaction,
|
|
@@ -1443,6 +1472,16 @@ async function runDoctor(args = [], root, doctorFix) {
|
|
|
1443
1472
|
console.log(` manual: ${action}`);
|
|
1444
1473
|
for (const warning of codexStartupRepair.warnings || [])
|
|
1445
1474
|
console.log(` warning: ${warning}`);
|
|
1475
|
+
if (codexConfigSyntaxRepair) {
|
|
1476
|
+
console.log('Codex config syntax:');
|
|
1477
|
+
console.log(` repair: ${codexConfigSyntaxRepair.ok ? 'ok' : 'blocked'}`);
|
|
1478
|
+
for (const action of codexConfigSyntaxRepair.actions || [])
|
|
1479
|
+
console.log(` - ${action}`);
|
|
1480
|
+
for (const action of codexConfigSyntaxRepair.manual_actions || [])
|
|
1481
|
+
console.log(` manual: ${action}`);
|
|
1482
|
+
for (const warning of codexConfigSyntaxRepair.warnings || [])
|
|
1483
|
+
console.log(` warning: ${warning}`);
|
|
1484
|
+
}
|
|
1446
1485
|
console.log(` codex doctor: ${formatCodexDoctorConsoleStatus(authoritativeCodexDoctor)}`);
|
|
1447
1486
|
console.log(`Rust acc.: ${rust.mode || (rust.available ? 'rust_accelerated' : 'js_fallback')} ${rust.version || rust.status || ''}`);
|
|
1448
1487
|
console.log(`Codex App: ${ready.codex_app_ready ? 'ok' : 'optional_missing'}`);
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema": "sks.skills-manifest.v1",
|
|
3
|
-
"package_version": "8.0.
|
|
3
|
+
"package_version": "8.0.1",
|
|
4
4
|
"skills": [
|
|
5
5
|
{
|
|
6
6
|
"canonical_name": "sks",
|
|
7
7
|
"type": "official",
|
|
8
|
-
"content_sha256": "
|
|
8
|
+
"content_sha256": "5b17aeb1484e9e2b3791bff6dcb175f30857f47e71b36eb0340e575385e8e82b",
|
|
9
9
|
"hash_history": [],
|
|
10
10
|
"deprecated_aliases": []
|
|
11
11
|
},
|
|
@@ -19,35 +19,35 @@
|
|
|
19
19
|
{
|
|
20
20
|
"canonical_name": "sks-answer",
|
|
21
21
|
"type": "official",
|
|
22
|
-
"content_sha256": "
|
|
22
|
+
"content_sha256": "bc8e2fc157b6c9819d32bb0a41bdf7f599a07693df18b0d80aa0ba103594f6eb",
|
|
23
23
|
"hash_history": [],
|
|
24
24
|
"deprecated_aliases": []
|
|
25
25
|
},
|
|
26
26
|
{
|
|
27
27
|
"canonical_name": "sks-autoresearch",
|
|
28
28
|
"type": "official",
|
|
29
|
-
"content_sha256": "
|
|
29
|
+
"content_sha256": "42602109bc1bf36b28a9acd0c458ab6c3b87f412c2710052e1c65a1f7b0cfeb8",
|
|
30
30
|
"hash_history": [],
|
|
31
31
|
"deprecated_aliases": []
|
|
32
32
|
},
|
|
33
33
|
{
|
|
34
34
|
"canonical_name": "sks-autoresearch-loop",
|
|
35
35
|
"type": "official",
|
|
36
|
-
"content_sha256": "
|
|
36
|
+
"content_sha256": "2bca681fef9a8ca29619c0ee70bc9d272a3d4c575bba0d12f5739e585eb1c0a5",
|
|
37
37
|
"hash_history": [],
|
|
38
38
|
"deprecated_aliases": []
|
|
39
39
|
},
|
|
40
40
|
{
|
|
41
41
|
"canonical_name": "sks-commit",
|
|
42
42
|
"type": "official",
|
|
43
|
-
"content_sha256": "
|
|
43
|
+
"content_sha256": "943c6dcf822df086b320140e74404d4c7bcfd531264e25ada6624b5009f26207",
|
|
44
44
|
"hash_history": [],
|
|
45
45
|
"deprecated_aliases": []
|
|
46
46
|
},
|
|
47
47
|
{
|
|
48
48
|
"canonical_name": "sks-commit-and-push",
|
|
49
49
|
"type": "official",
|
|
50
|
-
"content_sha256": "
|
|
50
|
+
"content_sha256": "b005b4a7456b80b95768ad358fe5950bf517483c6de71aec14ee3d1c600cc074",
|
|
51
51
|
"hash_history": [],
|
|
52
52
|
"deprecated_aliases": []
|
|
53
53
|
},
|
|
@@ -61,56 +61,56 @@
|
|
|
61
61
|
{
|
|
62
62
|
"canonical_name": "sks-computer-use-fast",
|
|
63
63
|
"type": "official",
|
|
64
|
-
"content_sha256": "
|
|
64
|
+
"content_sha256": "b8736b2621398dfc85f7a2ff35d7a2fc728db0dfc0e964de69aebff93b5ed897",
|
|
65
65
|
"hash_history": [],
|
|
66
66
|
"deprecated_aliases": []
|
|
67
67
|
},
|
|
68
68
|
{
|
|
69
69
|
"canonical_name": "sks-context7-docs",
|
|
70
70
|
"type": "official",
|
|
71
|
-
"content_sha256": "
|
|
71
|
+
"content_sha256": "f3618fa72800899ffbe1686bed6bc888997bfb007a14f0e17c9a26178d55262a",
|
|
72
72
|
"hash_history": [],
|
|
73
73
|
"deprecated_aliases": []
|
|
74
74
|
},
|
|
75
75
|
{
|
|
76
76
|
"canonical_name": "sks-cu",
|
|
77
77
|
"type": "official",
|
|
78
|
-
"content_sha256": "
|
|
78
|
+
"content_sha256": "da480ba03208d4888df1e97bbec6d80d608dafad0e33c2b1c72266e1860476a8",
|
|
79
79
|
"hash_history": [],
|
|
80
80
|
"deprecated_aliases": []
|
|
81
81
|
},
|
|
82
82
|
{
|
|
83
83
|
"canonical_name": "sks-db",
|
|
84
84
|
"type": "official",
|
|
85
|
-
"content_sha256": "
|
|
85
|
+
"content_sha256": "e3912adaf37f9be002b012c89c18ff987c9cd16ea2445600c834fa39a5bf865a",
|
|
86
86
|
"hash_history": [],
|
|
87
87
|
"deprecated_aliases": []
|
|
88
88
|
},
|
|
89
89
|
{
|
|
90
90
|
"canonical_name": "sks-db-safety-guard",
|
|
91
91
|
"type": "official",
|
|
92
|
-
"content_sha256": "
|
|
92
|
+
"content_sha256": "7978ca93f51540c838ae46aab9c2d88fde4932892cc7d75fc94e2071e6878a01",
|
|
93
93
|
"hash_history": [],
|
|
94
94
|
"deprecated_aliases": []
|
|
95
95
|
},
|
|
96
96
|
{
|
|
97
97
|
"canonical_name": "sks-design-artifact-expert",
|
|
98
98
|
"type": "official",
|
|
99
|
-
"content_sha256": "
|
|
99
|
+
"content_sha256": "4a28d166eaf0bc4477b566b056034f972a7034165e36d8186daa9947bf92e3cf",
|
|
100
100
|
"hash_history": [],
|
|
101
101
|
"deprecated_aliases": []
|
|
102
102
|
},
|
|
103
103
|
{
|
|
104
104
|
"canonical_name": "sks-design-system-builder",
|
|
105
105
|
"type": "official",
|
|
106
|
-
"content_sha256": "
|
|
106
|
+
"content_sha256": "c4f0007cad5774510bdc55e2815ce0911c220afa8d5dd4efc327ba1231c8f3da",
|
|
107
107
|
"hash_history": [],
|
|
108
108
|
"deprecated_aliases": []
|
|
109
109
|
},
|
|
110
110
|
{
|
|
111
111
|
"canonical_name": "sks-design-ui-editor",
|
|
112
112
|
"type": "official",
|
|
113
|
-
"content_sha256": "
|
|
113
|
+
"content_sha256": "1b65f0028a6dcb2f7eeab0b0df411a75546bc3aefa8a76067e1818da000c2249",
|
|
114
114
|
"hash_history": [],
|
|
115
115
|
"deprecated_aliases": []
|
|
116
116
|
},
|
|
@@ -124,98 +124,98 @@
|
|
|
124
124
|
{
|
|
125
125
|
"canonical_name": "sks-fast-mode",
|
|
126
126
|
"type": "official",
|
|
127
|
-
"content_sha256": "
|
|
127
|
+
"content_sha256": "257daa08de3807d47c0941ac21ef1f89af2f7f670b0c34059d3234a5a8bfb36b",
|
|
128
128
|
"hash_history": [],
|
|
129
129
|
"deprecated_aliases": []
|
|
130
130
|
},
|
|
131
131
|
{
|
|
132
132
|
"canonical_name": "sks-fast-off",
|
|
133
133
|
"type": "official",
|
|
134
|
-
"content_sha256": "
|
|
134
|
+
"content_sha256": "08b0b04df811d016d7f8018677dd9a25bd11de636daf1a11346e877d0466854e",
|
|
135
135
|
"hash_history": [],
|
|
136
136
|
"deprecated_aliases": []
|
|
137
137
|
},
|
|
138
138
|
{
|
|
139
139
|
"canonical_name": "sks-fast-on",
|
|
140
140
|
"type": "official",
|
|
141
|
-
"content_sha256": "
|
|
141
|
+
"content_sha256": "0355482a0baf32d8ac2131bdd88fb5fed5a3a9ea7ab82f12e26075bc8ea8c724",
|
|
142
142
|
"hash_history": [],
|
|
143
143
|
"deprecated_aliases": []
|
|
144
144
|
},
|
|
145
145
|
{
|
|
146
146
|
"canonical_name": "sks-from-chat-img",
|
|
147
147
|
"type": "official",
|
|
148
|
-
"content_sha256": "
|
|
148
|
+
"content_sha256": "583c41f46a7355d8c0c87472ea83573695d04341822eb9adcea822ed3311809f",
|
|
149
149
|
"hash_history": [],
|
|
150
150
|
"deprecated_aliases": []
|
|
151
151
|
},
|
|
152
152
|
{
|
|
153
153
|
"canonical_name": "sks-getdesign-reference",
|
|
154
154
|
"type": "official",
|
|
155
|
-
"content_sha256": "
|
|
155
|
+
"content_sha256": "688e10f29511c994ca24cdb16a160332bd79559bc03438cdcd43706420e34ad7",
|
|
156
156
|
"hash_history": [],
|
|
157
157
|
"deprecated_aliases": []
|
|
158
158
|
},
|
|
159
159
|
{
|
|
160
160
|
"canonical_name": "sks-goal",
|
|
161
161
|
"type": "official",
|
|
162
|
-
"content_sha256": "
|
|
162
|
+
"content_sha256": "0db0c58e72c0d58b24163371efe7a647c67d5d232020b2b4ed2557f19fe648d7",
|
|
163
163
|
"hash_history": [],
|
|
164
164
|
"deprecated_aliases": []
|
|
165
165
|
},
|
|
166
166
|
{
|
|
167
167
|
"canonical_name": "sks-gx",
|
|
168
168
|
"type": "official",
|
|
169
|
-
"content_sha256": "
|
|
169
|
+
"content_sha256": "55b7d535a5978077462eb4c71226b9fdc772094f91ca336830315de10666e85e",
|
|
170
170
|
"hash_history": [],
|
|
171
171
|
"deprecated_aliases": []
|
|
172
172
|
},
|
|
173
173
|
{
|
|
174
174
|
"canonical_name": "sks-gx-visual-generate",
|
|
175
175
|
"type": "official",
|
|
176
|
-
"content_sha256": "
|
|
176
|
+
"content_sha256": "390d2647735657aa8c248a5ab48ed4fa7981e8d5534e74e8f207779a1716af65",
|
|
177
177
|
"hash_history": [],
|
|
178
178
|
"deprecated_aliases": []
|
|
179
179
|
},
|
|
180
180
|
{
|
|
181
181
|
"canonical_name": "sks-gx-visual-read",
|
|
182
182
|
"type": "official",
|
|
183
|
-
"content_sha256": "
|
|
183
|
+
"content_sha256": "2175e76c4f4816d9c07f2f0ae02a0814d1489aaad78806a1ac27db1594282035",
|
|
184
184
|
"hash_history": [],
|
|
185
185
|
"deprecated_aliases": []
|
|
186
186
|
},
|
|
187
187
|
{
|
|
188
188
|
"canonical_name": "sks-gx-visual-validate",
|
|
189
189
|
"type": "official",
|
|
190
|
-
"content_sha256": "
|
|
190
|
+
"content_sha256": "f132066729e7f3e4a4287aa7be2146cd82df48730c38f51094f0174360c08d9d",
|
|
191
191
|
"hash_history": [],
|
|
192
192
|
"deprecated_aliases": []
|
|
193
193
|
},
|
|
194
194
|
{
|
|
195
195
|
"canonical_name": "sks-help",
|
|
196
196
|
"type": "official",
|
|
197
|
-
"content_sha256": "
|
|
197
|
+
"content_sha256": "0b67a2ed2eb1f3f80cf1645bee0c189ecc442d2ec84b1e0b218d800298487920",
|
|
198
198
|
"hash_history": [],
|
|
199
199
|
"deprecated_aliases": []
|
|
200
200
|
},
|
|
201
201
|
{
|
|
202
202
|
"canonical_name": "sks-honest-mode",
|
|
203
203
|
"type": "official",
|
|
204
|
-
"content_sha256": "
|
|
204
|
+
"content_sha256": "4543d942cac510b1a23e2e842f944d033087bbc761f6abc4a27d0a015bf22235",
|
|
205
205
|
"hash_history": [],
|
|
206
206
|
"deprecated_aliases": []
|
|
207
207
|
},
|
|
208
208
|
{
|
|
209
209
|
"canonical_name": "sks-hproof-claim-ledger",
|
|
210
210
|
"type": "official",
|
|
211
|
-
"content_sha256": "
|
|
211
|
+
"content_sha256": "dc04c5e6100c940a84e1dc52af5c84158e03f1d24935c3b4f814ce7f1f5f0f60",
|
|
212
212
|
"hash_history": [],
|
|
213
213
|
"deprecated_aliases": []
|
|
214
214
|
},
|
|
215
215
|
{
|
|
216
216
|
"canonical_name": "sks-hproof-evidence-bind",
|
|
217
217
|
"type": "official",
|
|
218
|
-
"content_sha256": "
|
|
218
|
+
"content_sha256": "fa20989183324964b5527742c0b1f593eacfcd3090b1707fb7c52258cdf62637",
|
|
219
219
|
"hash_history": [],
|
|
220
220
|
"deprecated_aliases": []
|
|
221
221
|
},
|
|
@@ -229,14 +229,14 @@
|
|
|
229
229
|
{
|
|
230
230
|
"canonical_name": "sks-imagegen",
|
|
231
231
|
"type": "official",
|
|
232
|
-
"content_sha256": "
|
|
232
|
+
"content_sha256": "7a1f9372b03975886233a623031f41e06fd782b1e7a3409517bb428d9c6b76dd",
|
|
233
233
|
"hash_history": [],
|
|
234
234
|
"deprecated_aliases": []
|
|
235
235
|
},
|
|
236
236
|
{
|
|
237
237
|
"canonical_name": "sks-imagegen-source-scout",
|
|
238
238
|
"type": "official",
|
|
239
|
-
"content_sha256": "
|
|
239
|
+
"content_sha256": "d648b571c674ed3be862bc0e8b2110f88c2bee54292bb009df0b0b2dbd6d400b",
|
|
240
240
|
"hash_history": [],
|
|
241
241
|
"deprecated_aliases": []
|
|
242
242
|
},
|
|
@@ -257,7 +257,7 @@
|
|
|
257
257
|
{
|
|
258
258
|
"canonical_name": "sks-mad-sks",
|
|
259
259
|
"type": "official",
|
|
260
|
-
"content_sha256": "
|
|
260
|
+
"content_sha256": "a3d0110ca97576130893311b3267621acb02c16ca9aea4b2da3e5300eea58158",
|
|
261
261
|
"hash_history": [],
|
|
262
262
|
"deprecated_aliases": []
|
|
263
263
|
},
|
|
@@ -271,35 +271,35 @@
|
|
|
271
271
|
{
|
|
272
272
|
"canonical_name": "sks-performance-evaluator",
|
|
273
273
|
"type": "official",
|
|
274
|
-
"content_sha256": "
|
|
274
|
+
"content_sha256": "c0bfd5a2e6c74813cb5dac9dadd4c7543ee768a48cf3e36b86b3d9306c2712c6",
|
|
275
275
|
"hash_history": [],
|
|
276
276
|
"deprecated_aliases": []
|
|
277
277
|
},
|
|
278
278
|
{
|
|
279
279
|
"canonical_name": "sks-pipeline-runner",
|
|
280
280
|
"type": "official",
|
|
281
|
-
"content_sha256": "
|
|
281
|
+
"content_sha256": "ffcbe0ea4b585e3d2886f1d9fa7a3b88706aaf42182fb177b2371b76beb0ddcd",
|
|
282
282
|
"hash_history": [],
|
|
283
283
|
"deprecated_aliases": []
|
|
284
284
|
},
|
|
285
285
|
{
|
|
286
286
|
"canonical_name": "sks-plan",
|
|
287
287
|
"type": "official",
|
|
288
|
-
"content_sha256": "
|
|
288
|
+
"content_sha256": "b6f3b09230e9809acf4e13df2de6af3c75a8534e8890d6560664ebfc2e4072f8",
|
|
289
289
|
"hash_history": [],
|
|
290
290
|
"deprecated_aliases": []
|
|
291
291
|
},
|
|
292
292
|
{
|
|
293
293
|
"canonical_name": "sks-ppt",
|
|
294
294
|
"type": "official",
|
|
295
|
-
"content_sha256": "
|
|
295
|
+
"content_sha256": "329fc6ee24bb04478b18fb6ccd3691cd7cbb50e1b77ca7b6136383d00b3b0bb4",
|
|
296
296
|
"hash_history": [],
|
|
297
297
|
"deprecated_aliases": []
|
|
298
298
|
},
|
|
299
299
|
{
|
|
300
300
|
"canonical_name": "sks-prompt-pipeline",
|
|
301
301
|
"type": "official",
|
|
302
|
-
"content_sha256": "
|
|
302
|
+
"content_sha256": "5dc8524de9bad66cef133ea5ff2a8052331bd12a7ec85695f727d0d2c8523145",
|
|
303
303
|
"hash_history": [],
|
|
304
304
|
"deprecated_aliases": []
|
|
305
305
|
},
|
|
@@ -313,21 +313,21 @@
|
|
|
313
313
|
{
|
|
314
314
|
"canonical_name": "sks-reasoning-router",
|
|
315
315
|
"type": "official",
|
|
316
|
-
"content_sha256": "
|
|
316
|
+
"content_sha256": "dc0b8c6a4093269c2c36b58432b25409704d06fea8ca558f43b598625ca0d9de",
|
|
317
317
|
"hash_history": [],
|
|
318
318
|
"deprecated_aliases": []
|
|
319
319
|
},
|
|
320
320
|
{
|
|
321
321
|
"canonical_name": "sks-reflection",
|
|
322
322
|
"type": "official",
|
|
323
|
-
"content_sha256": "
|
|
323
|
+
"content_sha256": "4ba8b2778d1d37c25c89f1a97ce3ce5602c39138425e1f4af4a91e840a961670",
|
|
324
324
|
"hash_history": [],
|
|
325
325
|
"deprecated_aliases": []
|
|
326
326
|
},
|
|
327
327
|
{
|
|
328
328
|
"canonical_name": "sks-release-review",
|
|
329
329
|
"type": "official",
|
|
330
|
-
"content_sha256": "
|
|
330
|
+
"content_sha256": "7cf879a2efd61822d3dccd4eb69fb704bfbab4b114b820b6dfa0d13b5f20e9fa",
|
|
331
331
|
"hash_history": [],
|
|
332
332
|
"deprecated_aliases": []
|
|
333
333
|
},
|
|
@@ -341,7 +341,7 @@
|
|
|
341
341
|
{
|
|
342
342
|
"canonical_name": "sks-review",
|
|
343
343
|
"type": "official",
|
|
344
|
-
"content_sha256": "
|
|
344
|
+
"content_sha256": "42ba1dbdc6b476d1c4a6e42467fdc86fda58bab3207c054550591ab5f6e94c37",
|
|
345
345
|
"hash_history": [],
|
|
346
346
|
"deprecated_aliases": []
|
|
347
347
|
},
|
|
@@ -362,49 +362,49 @@
|
|
|
362
362
|
{
|
|
363
363
|
"canonical_name": "sks-solution-scout",
|
|
364
364
|
"type": "official",
|
|
365
|
-
"content_sha256": "
|
|
365
|
+
"content_sha256": "a563554da2d69e69a4afebf914a7a2d3b7b0f25dcb5eb7f9248f3fc7576bc4c9",
|
|
366
366
|
"hash_history": [],
|
|
367
367
|
"deprecated_aliases": []
|
|
368
368
|
},
|
|
369
369
|
{
|
|
370
370
|
"canonical_name": "sks-super-search",
|
|
371
371
|
"type": "official",
|
|
372
|
-
"content_sha256": "
|
|
372
|
+
"content_sha256": "a0da7ec655bab7f40831de21b52691ac75b56fbc2fbfd1f053e1c5f2dd5ddb52",
|
|
373
373
|
"hash_history": [],
|
|
374
374
|
"deprecated_aliases": []
|
|
375
375
|
},
|
|
376
376
|
{
|
|
377
377
|
"canonical_name": "sks-turbo-context-pack",
|
|
378
378
|
"type": "official",
|
|
379
|
-
"content_sha256": "
|
|
379
|
+
"content_sha256": "d94bb85ea836e55c5b2b0df237821cf97b3d2ec6bfe697c97525f3fa5807b200",
|
|
380
380
|
"hash_history": [],
|
|
381
381
|
"deprecated_aliases": []
|
|
382
382
|
},
|
|
383
383
|
{
|
|
384
384
|
"canonical_name": "sks-wiki",
|
|
385
385
|
"type": "official",
|
|
386
|
-
"content_sha256": "
|
|
386
|
+
"content_sha256": "16b2b813d202ca51d2ea4fe0da918eddf9494db7ab1356352d4188a5da3496b1",
|
|
387
387
|
"hash_history": [],
|
|
388
388
|
"deprecated_aliases": []
|
|
389
389
|
},
|
|
390
390
|
{
|
|
391
391
|
"canonical_name": "sks-with-local-llm-off",
|
|
392
392
|
"type": "official",
|
|
393
|
-
"content_sha256": "
|
|
393
|
+
"content_sha256": "86d3a860b438c91c2a5b4cc8ac9c8e7477008f9b689602ddcf14a9e3b759923d",
|
|
394
394
|
"hash_history": [],
|
|
395
395
|
"deprecated_aliases": []
|
|
396
396
|
},
|
|
397
397
|
{
|
|
398
398
|
"canonical_name": "sks-with-local-llm-on",
|
|
399
399
|
"type": "official",
|
|
400
|
-
"content_sha256": "
|
|
400
|
+
"content_sha256": "27e1ff08b95428d6b623d06358d5d114ff02673a5c97d8f180dd75859682cd6c",
|
|
401
401
|
"hash_history": [],
|
|
402
402
|
"deprecated_aliases": []
|
|
403
403
|
},
|
|
404
404
|
{
|
|
405
405
|
"canonical_name": "sks-work",
|
|
406
406
|
"type": "official",
|
|
407
|
-
"content_sha256": "
|
|
407
|
+
"content_sha256": "7b4893af053caba27eab1b1d73ff375856522e433fb85dfabde50ea844c75639",
|
|
408
408
|
"hash_history": [],
|
|
409
409
|
"deprecated_aliases": []
|
|
410
410
|
}
|
|
@@ -6,10 +6,18 @@ const KEYCHAIN_WRITER_SWIFT = `import Foundation
|
|
|
6
6
|
import Security
|
|
7
7
|
let a=CommandLine.arguments[1],s=CommandLine.arguments[2]
|
|
8
8
|
guard let k=String(data:FileHandle.standardInput.readDataToEndOfFile(),encoding:.utf8)?.trimmingCharacters(in:.whitespacesAndNewlines),!k.isEmpty else{exit(64)}
|
|
9
|
+
var trusted:SecTrustedApplication?
|
|
10
|
+
var apps:[Any]=[]
|
|
11
|
+
if SecTrustedApplicationCreateFromPath("/usr/bin/security",&trusted)==errSecSuccess,let t=trusted{apps.append(t)}
|
|
12
|
+
var access:SecAccess?
|
|
13
|
+
_ = SecAccessCreate("sks-codex-lb" as CFString,apps as CFArray,&access)
|
|
9
14
|
let q:[String:Any]=[kSecClass as String:kSecClassGenericPassword,kSecAttrAccount as String:a,kSecAttrService as String:s]
|
|
10
|
-
|
|
11
|
-
var
|
|
12
|
-
|
|
15
|
+
SecItemDelete(q as CFDictionary)
|
|
16
|
+
var n=q
|
|
17
|
+
n[kSecValueData as String]=Data(k.utf8)
|
|
18
|
+
n[kSecAttrAccessible as String]=kSecAttrAccessibleAfterFirstUnlock
|
|
19
|
+
if let ac=access{n[kSecAttrAccess as String]=ac}
|
|
20
|
+
let r=SecItemAdd(n as CFDictionary,nil)
|
|
13
21
|
if r != errSecSuccess{FileHandle.standardError.write(Data("keychain_status=\\(r)\\n".utf8));exit(1)}`;
|
|
14
22
|
export function codexLbEnvPath(home = process.env.HOME || os.homedir()) {
|
|
15
23
|
return path.join(String(home || os.homedir()), '.codex', 'sks-codex-lb.env');
|
|
@@ -166,9 +174,11 @@ export async function loadCodexLbEnv(opts = {}) {
|
|
|
166
174
|
sourcePriority.push('project-local');
|
|
167
175
|
const processEnv = pickEnv(opts.processEnv || process.env);
|
|
168
176
|
const envFile = await readEnvFile(envPaths[0]);
|
|
169
|
-
const keychain = await readMacKeychain(opts);
|
|
170
177
|
const projectLocal = opts.allowProjectSecrets ? await readEnvFile(path.join(opts.root || process.cwd(), '.env')) : {};
|
|
171
178
|
const metadata = await readCodexLbCredentialMetadata(metadataPath);
|
|
179
|
+
const keychain = await keychainReadIsNeeded(opts, metadata, [envFile.apiKey, processEnv.apiKey, projectLocal.apiKey])
|
|
180
|
+
? await readMacKeychain(opts)
|
|
181
|
+
: { checked: false, available: false, status: 'skipped_not_needed', apiKey: '' };
|
|
172
182
|
const apiKeyCandidates = [
|
|
173
183
|
{ source: 'env-file', apiKey: envFile.apiKey },
|
|
174
184
|
{ source: 'keychain', apiKey: keychain.apiKey },
|
|
@@ -223,6 +233,20 @@ export async function loadCodexLbEnv(opts = {}) {
|
|
|
223
233
|
}
|
|
224
234
|
};
|
|
225
235
|
}
|
|
236
|
+
async function keychainReadIsNeeded(opts, metadata, nonKeychainKeys) {
|
|
237
|
+
if (opts.forceKeychainRead === true)
|
|
238
|
+
return true;
|
|
239
|
+
const candidates = nonKeychainKeys.map((key) => String(key || '').trim()).filter(Boolean);
|
|
240
|
+
if (candidates.length === 0)
|
|
241
|
+
return true;
|
|
242
|
+
if (!metadata.valid || !metadata.apiKeySha256)
|
|
243
|
+
return false;
|
|
244
|
+
for (const candidate of candidates) {
|
|
245
|
+
if ((await sha256Full(candidate)) === metadata.apiKeySha256)
|
|
246
|
+
return false;
|
|
247
|
+
}
|
|
248
|
+
return true;
|
|
249
|
+
}
|
|
226
250
|
async function readCodexLbCredentialMetadata(file) {
|
|
227
251
|
if (!(await exists(file)))
|
|
228
252
|
return { present: false, valid: false, baseUrl: '', apiKeySha256: '' };
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import { exists, nowIso, readText, writeJsonAtomic } from '../fsx.js';
|
|
4
|
+
import { validateCodexConfigRoundTrip } from '../codex/codex-config-toml.js';
|
|
5
|
+
import { isUnmanagedProjectCodexConfig, writeCodexConfigGuarded } from '../codex/codex-config-guard.js';
|
|
6
|
+
import { ALLOWED_REASONING_EFFORTS } from '../routes/constants.js';
|
|
7
|
+
import { escapeRegExp } from '../text/regex.js';
|
|
8
|
+
export const CODEX_CONFIG_SYNTAX_REPAIR_SCHEMA = 'sks.codex-config-syntax-repair.v1';
|
|
9
|
+
const RETIRED_TOP_LEVEL_KEYS = ['default_profile'];
|
|
10
|
+
const RETIRED_TABLES = ['user.fast_mode', 'profiles'];
|
|
11
|
+
const RETIRED_TABLE_KEYS = [
|
|
12
|
+
{ table: 'notice', key: 'fast_default_opt_out' },
|
|
13
|
+
{ table: 'features', key: 'codex_hooks' },
|
|
14
|
+
{ table: 'features', key: 'remote_control' },
|
|
15
|
+
{ table: 'features', key: 'fast_mode_ui' },
|
|
16
|
+
{ table: 'features', key: 'codex_git_commit' },
|
|
17
|
+
{ table: 'features', key: 'multi_agent' }
|
|
18
|
+
];
|
|
19
|
+
const ALLOWED_SERVICE_TIERS = new Set(['fast', 'priority', 'standard']);
|
|
20
|
+
export async function runCodexConfigSyntaxRepair(input) {
|
|
21
|
+
const root = path.resolve(input.root || process.cwd());
|
|
22
|
+
const codexHome = input.codexHome || process.env.CODEX_HOME || path.join(process.env.HOME || os.homedir(), '.codex');
|
|
23
|
+
const configs = [];
|
|
24
|
+
for (const candidate of [
|
|
25
|
+
{ scope: 'project', path: path.join(root, '.codex', 'config.toml') },
|
|
26
|
+
{ scope: 'global', path: path.join(codexHome, 'config.toml') }
|
|
27
|
+
]) {
|
|
28
|
+
configs.push(await inspectOrRepairScope(root, candidate, input.fix === true));
|
|
29
|
+
}
|
|
30
|
+
const blockers = configs.flatMap((entry) => entry.blockers.map((item) => `${entry.scope}:${item}`));
|
|
31
|
+
const warnings = configs.flatMap((entry) => entry.warnings.map((item) => `${entry.scope}:${item}`));
|
|
32
|
+
const actions = configs.flatMap((entry) => [
|
|
33
|
+
...entry.retired_syntax_removed.map((item) => `${entry.scope} retired codex syntax removed: ${item}`),
|
|
34
|
+
...entry.invalid_values_repaired.map((item) => `${entry.scope} invalid value repaired: ${item}`)
|
|
35
|
+
]);
|
|
36
|
+
const manualActions = configs.flatMap((entry) => entry.blockers.flatMap((item) => {
|
|
37
|
+
if (item.startsWith('toml_parse_failed')) {
|
|
38
|
+
return [`${entry.scope} config.toml does not parse as TOML; fix the syntax error manually (the file was preserved untouched).`];
|
|
39
|
+
}
|
|
40
|
+
if (item.startsWith('model_provider_auth_env_key_conflict')) {
|
|
41
|
+
return [`${entry.scope} config.toml has a model provider that sets both env_key and auth; keep exactly one authentication method.`];
|
|
42
|
+
}
|
|
43
|
+
return [];
|
|
44
|
+
}));
|
|
45
|
+
const reportPath = input.reportPath === null
|
|
46
|
+
? ''
|
|
47
|
+
: input.reportPath || path.join(root, '.sneakoscope', 'reports', 'codex-config-syntax-repair.json');
|
|
48
|
+
const report = {
|
|
49
|
+
schema: CODEX_CONFIG_SYNTAX_REPAIR_SCHEMA,
|
|
50
|
+
ok: blockers.length === 0,
|
|
51
|
+
generated_at: nowIso(),
|
|
52
|
+
fix: input.fix === true,
|
|
53
|
+
configs,
|
|
54
|
+
actions,
|
|
55
|
+
manual_actions: [...new Set(manualActions)],
|
|
56
|
+
blockers,
|
|
57
|
+
warnings,
|
|
58
|
+
report_path: reportPath
|
|
59
|
+
};
|
|
60
|
+
if (reportPath)
|
|
61
|
+
await writeJsonAtomic(reportPath, report);
|
|
62
|
+
return report;
|
|
63
|
+
}
|
|
64
|
+
async function inspectOrRepairScope(root, candidate, fix) {
|
|
65
|
+
const base = {
|
|
66
|
+
scope: candidate.scope,
|
|
67
|
+
path: candidate.path,
|
|
68
|
+
present: false,
|
|
69
|
+
changed: false,
|
|
70
|
+
backup_path: null,
|
|
71
|
+
retired_syntax_removed: [],
|
|
72
|
+
invalid_values_repaired: [],
|
|
73
|
+
blockers: [],
|
|
74
|
+
warnings: []
|
|
75
|
+
};
|
|
76
|
+
if (!await exists(candidate.path))
|
|
77
|
+
return base;
|
|
78
|
+
const text = await readText(candidate.path, '');
|
|
79
|
+
base.present = true;
|
|
80
|
+
const validation = validateCodexConfigRoundTrip(text);
|
|
81
|
+
if (!validation.ok) {
|
|
82
|
+
if (validation.blockers.includes('toml_parse_failed')) {
|
|
83
|
+
base.blockers.push('toml_parse_failed');
|
|
84
|
+
base.warnings.push('config_preserved:unparseable_toml_requires_manual_repair');
|
|
85
|
+
return base;
|
|
86
|
+
}
|
|
87
|
+
for (const blocker of validation.blockers)
|
|
88
|
+
base.blockers.push(blocker);
|
|
89
|
+
}
|
|
90
|
+
const retired = findRetiredSyntax(text);
|
|
91
|
+
const invalidValues = findInvalidValues(validation.parsed);
|
|
92
|
+
const repairableValues = invalidValues.filter((item) => item.repairable);
|
|
93
|
+
const detected = [...retired, ...repairableValues.map((item) => item.id)];
|
|
94
|
+
if (candidate.scope === 'project' && isUnmanagedProjectCodexConfig(root, candidate.path, text)) {
|
|
95
|
+
base.warnings.push('unmanaged_project_config_preserved');
|
|
96
|
+
if (detected.length)
|
|
97
|
+
base.warnings.push('user_owned_file_without_sks_marker');
|
|
98
|
+
return base;
|
|
99
|
+
}
|
|
100
|
+
if (!fix) {
|
|
101
|
+
for (const item of detected)
|
|
102
|
+
base.warnings.push(`codex_syntax_outdated:${item}`);
|
|
103
|
+
return base;
|
|
104
|
+
}
|
|
105
|
+
if (!detected.length)
|
|
106
|
+
return base;
|
|
107
|
+
base.retired_syntax_removed.push(...retired);
|
|
108
|
+
base.invalid_values_repaired.push(...repairableValues.map((item) => item.id));
|
|
109
|
+
let next = text;
|
|
110
|
+
for (const key of RETIRED_TOP_LEVEL_KEYS)
|
|
111
|
+
next = removeTopLevelTomlKey(next, key);
|
|
112
|
+
for (const table of RETIRED_TABLES)
|
|
113
|
+
next = removeTomlTable(next, table);
|
|
114
|
+
for (const entry of RETIRED_TABLE_KEYS)
|
|
115
|
+
next = removeTomlTableKey(next, entry.table, entry.key);
|
|
116
|
+
for (const item of repairableValues)
|
|
117
|
+
next = removeTopLevelTomlKey(next, item.key);
|
|
118
|
+
next = next.replace(/\n{3,}/g, '\n\n').replace(/\s*$/, next.trim() ? '\n' : '');
|
|
119
|
+
if (next === text)
|
|
120
|
+
return base;
|
|
121
|
+
const guarded = await writeCodexConfigGuarded({
|
|
122
|
+
root,
|
|
123
|
+
configPath: candidate.path,
|
|
124
|
+
before: text,
|
|
125
|
+
cause: 'codex-config-syntax-repair',
|
|
126
|
+
preserveFastUiKeys: false,
|
|
127
|
+
mutate: () => next
|
|
128
|
+
});
|
|
129
|
+
if (!guarded.ok) {
|
|
130
|
+
base.changed = false;
|
|
131
|
+
base.retired_syntax_removed.length = 0;
|
|
132
|
+
base.invalid_values_repaired.length = 0;
|
|
133
|
+
base.warnings.push(`config_preserved:${guarded.status}`);
|
|
134
|
+
return base;
|
|
135
|
+
}
|
|
136
|
+
base.changed = guarded.changed;
|
|
137
|
+
base.backup_path = guarded.backup_path;
|
|
138
|
+
return base;
|
|
139
|
+
}
|
|
140
|
+
function findRetiredSyntax(text) {
|
|
141
|
+
const found = [];
|
|
142
|
+
for (const key of RETIRED_TOP_LEVEL_KEYS) {
|
|
143
|
+
if (hasTopLevelTomlKey(text, key))
|
|
144
|
+
found.push(key);
|
|
145
|
+
}
|
|
146
|
+
for (const table of RETIRED_TABLES) {
|
|
147
|
+
if (hasTomlTable(text, table))
|
|
148
|
+
found.push(`[${table}]`);
|
|
149
|
+
}
|
|
150
|
+
for (const entry of RETIRED_TABLE_KEYS) {
|
|
151
|
+
if (hasTomlTableKey(text, entry.table, entry.key))
|
|
152
|
+
found.push(`${entry.table}.${entry.key}`);
|
|
153
|
+
}
|
|
154
|
+
return found;
|
|
155
|
+
}
|
|
156
|
+
function findInvalidValues(parsed) {
|
|
157
|
+
const findings = [];
|
|
158
|
+
if (parsed && Object.prototype.hasOwnProperty.call(parsed, 'service_tier')) {
|
|
159
|
+
const serviceTier = parsed.service_tier;
|
|
160
|
+
if (typeof serviceTier !== 'string') {
|
|
161
|
+
findings.push({ id: 'service_tier_non_string', key: 'service_tier', repairable: true });
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
const value = serviceTier.toLowerCase();
|
|
165
|
+
if (!ALLOWED_SERVICE_TIERS.has(value)) {
|
|
166
|
+
findings.push({ id: `service_tier_unknown:${value}`, key: 'service_tier', repairable: true });
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
if (parsed && Object.prototype.hasOwnProperty.call(parsed, 'model_reasoning_effort')) {
|
|
171
|
+
const effort = parsed.model_reasoning_effort;
|
|
172
|
+
if (typeof effort !== 'string') {
|
|
173
|
+
findings.push({ id: 'model_reasoning_effort_non_string', key: 'model_reasoning_effort', repairable: true });
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
const value = effort.toLowerCase();
|
|
177
|
+
if (!ALLOWED_REASONING_EFFORTS.has(value)) {
|
|
178
|
+
findings.push({ id: `model_reasoning_effort_unknown:${value}`, key: 'model_reasoning_effort', repairable: true });
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return findings;
|
|
183
|
+
}
|
|
184
|
+
function topLevelTomlValue(text, key) {
|
|
185
|
+
const lines = String(text || '').split('\n');
|
|
186
|
+
const firstTable = lines.findIndex((line) => /^\s*\[.+\]\s*(?:#.*)?$/.test(line));
|
|
187
|
+
const end = firstTable === -1 ? lines.length : firstTable;
|
|
188
|
+
const pattern = new RegExp(`^\\s*${escapeRegExp(key)}\\s*=\\s*(.+?)\\s*(?:#.*)?$`);
|
|
189
|
+
for (let index = 0; index < end; index += 1) {
|
|
190
|
+
const match = pattern.exec(lines[index] || '');
|
|
191
|
+
if (match)
|
|
192
|
+
return String(match[1] || '');
|
|
193
|
+
}
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
function hasTopLevelTomlKey(text, key) {
|
|
197
|
+
return topLevelTomlValue(text, key) !== null;
|
|
198
|
+
}
|
|
199
|
+
function removeTopLevelTomlKey(text, key) {
|
|
200
|
+
const lines = String(text || '').split('\n');
|
|
201
|
+
const firstTable = lines.findIndex((line) => /^\s*\[.+\]\s*(?:#.*)?$/.test(line));
|
|
202
|
+
const end = firstTable === -1 ? lines.length : firstTable;
|
|
203
|
+
const pattern = new RegExp(`^\\s*${escapeRegExp(key)}\\s*=`);
|
|
204
|
+
return lines.filter((line, index) => index >= end || !pattern.test(line)).join('\n').replace(/^\n+/, '');
|
|
205
|
+
}
|
|
206
|
+
function hasTomlTable(text, table) {
|
|
207
|
+
const header = new RegExp(`^\\s*\\[${escapeRegExp(table)}(?:\\.[^\\]]+)?\\]\\s*(?:#.*)?$`, 'm');
|
|
208
|
+
return header.test(String(text || ''));
|
|
209
|
+
}
|
|
210
|
+
function removeTomlTable(text, table) {
|
|
211
|
+
const lines = String(text || '').split('\n');
|
|
212
|
+
const header = new RegExp(`^\\s*\\[${escapeRegExp(table)}(?:\\.[^\\]]+)?\\]\\s*(?:#.*)?$`);
|
|
213
|
+
const anyHeader = /^\s*\[.+\]\s*(?:#.*)?$/;
|
|
214
|
+
const out = [];
|
|
215
|
+
let skipping = false;
|
|
216
|
+
for (const line of lines) {
|
|
217
|
+
if (anyHeader.test(line))
|
|
218
|
+
skipping = header.test(line);
|
|
219
|
+
if (!skipping)
|
|
220
|
+
out.push(line);
|
|
221
|
+
}
|
|
222
|
+
return out.join('\n').replace(/^\n+/, '');
|
|
223
|
+
}
|
|
224
|
+
function hasTomlTableKey(text, table, key) {
|
|
225
|
+
const lines = String(text || '').split('\n');
|
|
226
|
+
const header = new RegExp(`^\\s*\\[${escapeRegExp(table)}\\]\\s*(?:#.*)?$`);
|
|
227
|
+
const anyHeader = /^\s*\[.+\]\s*(?:#.*)?$/;
|
|
228
|
+
const pattern = new RegExp(`^\\s*${escapeRegExp(key)}\\s*=`);
|
|
229
|
+
let inside = false;
|
|
230
|
+
for (const line of lines) {
|
|
231
|
+
if (anyHeader.test(line))
|
|
232
|
+
inside = header.test(line);
|
|
233
|
+
else if (inside && pattern.test(line))
|
|
234
|
+
return true;
|
|
235
|
+
}
|
|
236
|
+
return false;
|
|
237
|
+
}
|
|
238
|
+
function removeTomlTableKey(text, table, key) {
|
|
239
|
+
const lines = String(text || '').split('\n');
|
|
240
|
+
const header = new RegExp(`^\\s*\\[${escapeRegExp(table)}\\]\\s*(?:#.*)?$`);
|
|
241
|
+
const anyHeader = /^\s*\[.+\]\s*(?:#.*)?$/;
|
|
242
|
+
const pattern = new RegExp(`^\\s*${escapeRegExp(key)}\\s*=`);
|
|
243
|
+
let inside = false;
|
|
244
|
+
const out = [];
|
|
245
|
+
for (const line of lines) {
|
|
246
|
+
if (anyHeader.test(line))
|
|
247
|
+
inside = header.test(line);
|
|
248
|
+
if (inside && pattern.test(line))
|
|
249
|
+
continue;
|
|
250
|
+
out.push(line);
|
|
251
|
+
}
|
|
252
|
+
return out.join('\n');
|
|
253
|
+
}
|
|
@@ -239,6 +239,7 @@ export const UPDATE_STAGE_ORDER = [
|
|
|
239
239
|
'native_capability_setup',
|
|
240
240
|
'menubar_rebuild',
|
|
241
241
|
'menubar_signature_verify',
|
|
242
|
+
'update_finalize_doctor',
|
|
242
243
|
'final_self_verification',
|
|
243
244
|
'snapshot_refresh'
|
|
244
245
|
];
|
|
@@ -268,7 +269,7 @@ export async function runSksUpdateReview(options = {}) {
|
|
|
268
269
|
global_root: globalRoot,
|
|
269
270
|
node_path: process.execPath,
|
|
270
271
|
expected_menubar_rebuild: process.platform === 'darwin' && env.SKS_UPDATE_SKIP_SKS_MENUBAR !== '1',
|
|
271
|
-
expected_migrations: ['hook_trust_repair', 'global_skills_reconcile', 'native_capability_setup'],
|
|
272
|
+
expected_migrations: ['hook_trust_repair', 'global_skills_reconcile', 'native_capability_setup', 'update_finalize_doctor'],
|
|
272
273
|
rollback_command: `sks update rollback --version ${check.current} --json`,
|
|
273
274
|
stages: [...UPDATE_STAGE_ORDER],
|
|
274
275
|
project_mutation: Boolean(options.projectRoot || env.SKS_MUTATION_LEDGER_ROOT || process.cwd()),
|
|
@@ -507,14 +508,25 @@ export async function runSksUpdateNow(options = {}) {
|
|
|
507
508
|
env
|
|
508
509
|
});
|
|
509
510
|
stage('menubar_signature_verify', menuVerification.ok, menuVerification.status, menuVerification.detail);
|
|
510
|
-
|
|
511
|
+
const currentFinalizeDoctor = await runUpdateFinalizeDoctor({
|
|
512
|
+
root: projectReceiptRoot,
|
|
513
|
+
env: nestedProcessEnv,
|
|
514
|
+
machineOutput
|
|
515
|
+
});
|
|
516
|
+
stage('update_finalize_doctor', currentFinalizeDoctor.ok, currentFinalizeDoctor.status, {
|
|
517
|
+
entrypoint: currentFinalizeDoctor.entrypoint,
|
|
518
|
+
args: currentFinalizeDoctor.args,
|
|
519
|
+
exit_code: currentFinalizeDoctor.exit_code,
|
|
520
|
+
timed_out: currentFinalizeDoctor.timed_out
|
|
521
|
+
});
|
|
522
|
+
stage('final_self_verification', migrationCurrent && menuVerification.ok && currentFinalizeDoctor.ok, migrationCurrent && menuVerification.ok && currentFinalizeDoctor.ok ? 'verified_current' : 'issues', {});
|
|
511
523
|
const currentSnapshot = await runSksUpdateStatus(updateStatusOptionsFromNow(options, check.current, { ...env, [versionOverrideEnvName(packageName)]: check.latest || check.current })).catch(() => null);
|
|
512
524
|
const snapshotOk = currentSnapshot?.schema === 'sks.update-status.v3' && currentSnapshot.source !== 'error';
|
|
513
525
|
stage('snapshot_refresh', snapshotOk, snapshotOk ? currentSnapshot.source : 'failed', {
|
|
514
526
|
update_count: currentSnapshot?.update_count ?? null
|
|
515
527
|
});
|
|
516
528
|
const currentMenuBarTerminalUncertain = menuBarInstallIsTerminalUncertain(sksMenuBar);
|
|
517
|
-
const currentOk = migrationCurrent && menuVerification.ok && snapshotOk && !currentMenuBarTerminalUncertain;
|
|
529
|
+
const currentOk = migrationCurrent && menuVerification.ok && currentFinalizeDoctor.ok && snapshotOk && !currentMenuBarTerminalUncertain;
|
|
518
530
|
return finalize(buildUpdateNowResult({
|
|
519
531
|
packageName,
|
|
520
532
|
from: check.current,
|
|
@@ -540,7 +552,9 @@ export async function runSksUpdateNow(options = {}) {
|
|
|
540
552
|
stages,
|
|
541
553
|
error: currentOk ? null : currentMenuBarTerminalUncertain
|
|
542
554
|
? 'Menu Bar launch or rollback completion could not be confirmed'
|
|
543
|
-
:
|
|
555
|
+
: currentFinalizeDoctor.ok
|
|
556
|
+
? 'current-version repair verification failed'
|
|
557
|
+
: 'current-version repair verification failed: update_finalize_doctor'
|
|
544
558
|
}));
|
|
545
559
|
}
|
|
546
560
|
const oldDoctorTimeoutOverride = Number.parseInt(env.SKS_UPDATE_OLD_DOCTOR_TIMEOUT_MS || '', 10);
|
|
@@ -733,11 +747,30 @@ export async function runSksUpdateNow(options = {}) {
|
|
|
733
747
|
}
|
|
734
748
|
}
|
|
735
749
|
}
|
|
750
|
+
const finalizeDoctor = installOk && newBinary
|
|
751
|
+
? await runUpdateFinalizeDoctor({
|
|
752
|
+
entrypoint: newBinary,
|
|
753
|
+
root: projectReceiptRoot,
|
|
754
|
+
env: nestedProcessEnv,
|
|
755
|
+
machineOutput
|
|
756
|
+
})
|
|
757
|
+
: null;
|
|
758
|
+
stage('update_finalize_doctor', finalizeDoctor?.ok === true, finalizeDoctor ? finalizeDoctor.status : 'skipped_install_failed', {
|
|
759
|
+
...(finalizeDoctor ? {
|
|
760
|
+
entrypoint: finalizeDoctor.entrypoint,
|
|
761
|
+
args: finalizeDoctor.args,
|
|
762
|
+
exit_code: finalizeDoctor.exit_code,
|
|
763
|
+
timed_out: finalizeDoctor.timed_out
|
|
764
|
+
} : {})
|
|
765
|
+
});
|
|
736
766
|
const verification = await runFinalUpdateVerification({ installOk, newBinary, installVersion, env, projectReceiptRoot });
|
|
737
|
-
const verifyOk = verification.length > 0 && verification.every((item) => item.ok);
|
|
767
|
+
const verifyOk = verification.length > 0 && verification.every((item) => item.ok) && finalizeDoctor?.ok === true;
|
|
738
768
|
if (verification.length) {
|
|
739
769
|
stage('final_self_verification', verifyOk, verifyOk ? 'verified' : 'issues', {
|
|
740
|
-
failed:
|
|
770
|
+
failed: [
|
|
771
|
+
...verification.filter((item) => !item.ok).map((item) => item.id),
|
|
772
|
+
...(finalizeDoctor?.ok === true ? [] : ['update_finalize_doctor'])
|
|
773
|
+
]
|
|
741
774
|
});
|
|
742
775
|
}
|
|
743
776
|
else
|
|
@@ -788,7 +821,7 @@ export async function runSksUpdateNow(options = {}) {
|
|
|
788
821
|
? menuBarTerminalUncertain
|
|
789
822
|
? 'Menu Bar launch or rollback completion could not be confirmed'
|
|
790
823
|
: 'global install timed out; package side-effect completion is uncertain'
|
|
791
|
-
: ok ? null : status === 'updated_with_issues' ? verificationError(verification) : updateNowError(install, newBinary, newVersionDoctor, migrationCurrent)
|
|
824
|
+
: ok ? null : status === 'updated_with_issues' ? verificationError(verification, finalizeDoctor) : updateNowError(install, newBinary, newVersionDoctor, migrationCurrent)
|
|
792
825
|
}));
|
|
793
826
|
}
|
|
794
827
|
export function menuBarInstallIsTerminalUncertain(result) {
|
|
@@ -796,6 +829,19 @@ export function menuBarInstallIsTerminalUncertain(result) {
|
|
|
796
829
|
|| result?.launch?.terminal_uncertain === true
|
|
797
830
|
|| result?.rollback?.status === 'terminal_uncertain';
|
|
798
831
|
}
|
|
832
|
+
async function runUpdateFinalizeDoctor(opts) {
|
|
833
|
+
const env = opts.env.SKS_TEST_FINALIZE_DOCTOR_FAIL === '1'
|
|
834
|
+
? { ...opts.env, SKS_TEST_DOCTOR_FAIL: '1' }
|
|
835
|
+
: opts.env;
|
|
836
|
+
return updateHeartbeat(opts.machineOutput, 'update finalize doctor', runPackageLocalDoctor({
|
|
837
|
+
root: opts.root,
|
|
838
|
+
...(opts.entrypoint ? { entrypoint: opts.entrypoint } : {}),
|
|
839
|
+
args: ['doctor', '--fix', '--yes', '--profile', 'migration', '--machine-only', '--report-file', path.join(opts.root, '.sneakoscope', 'update', 'update-finalize-doctor.json')],
|
|
840
|
+
env,
|
|
841
|
+
timeoutMs: updateDoctorTimeoutMs(env),
|
|
842
|
+
maxOutputBytes: 32 * 1024
|
|
843
|
+
}), 60_000);
|
|
844
|
+
}
|
|
799
845
|
async function runUpdateGlobalSkillsReconcile(stage, opts = {}) {
|
|
800
846
|
const targetDir = path.join(opts.env?.HOME || os.homedir(), '.agents', 'skills');
|
|
801
847
|
if (opts.newPackageRoot) {
|
|
@@ -1352,10 +1398,13 @@ async function runFinalUpdateVerification(input) {
|
|
|
1352
1398
|
}
|
|
1353
1399
|
return verification;
|
|
1354
1400
|
}
|
|
1355
|
-
function verificationError(verification) {
|
|
1356
|
-
const failed =
|
|
1401
|
+
function verificationError(verification, finalizeDoctor) {
|
|
1402
|
+
const failed = [
|
|
1403
|
+
...verification.filter((item) => !item.ok).map((item) => item.id),
|
|
1404
|
+
...(finalizeDoctor?.ok === true ? [] : ['update_finalize_doctor'])
|
|
1405
|
+
];
|
|
1357
1406
|
return failed.length
|
|
1358
|
-
? `update self-verification failed: ${failed.
|
|
1407
|
+
? `update self-verification failed: ${failed.join(', ')}`
|
|
1359
1408
|
: 'update self-verification did not run';
|
|
1360
1409
|
}
|
|
1361
1410
|
function updateNowError(install, newBinary, newVersionDoctor, migrationCurrent) {
|
package/dist/core/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const PACKAGE_VERSION = '8.0.
|
|
1
|
+
export const PACKAGE_VERSION = '8.0.1';
|
|
@@ -85,7 +85,7 @@ final class OperationCoordinator {
|
|
|
85
85
|
"preflight", "download_or_registry_check", "temporary_install_smoke", "global_install",
|
|
86
86
|
"resolve_new_binary", "version_probe", "new_version_doctor", "hook_trust_repair",
|
|
87
87
|
"project_receipt", "global_skills_reconcile", "native_capability_setup", "menubar_rebuild",
|
|
88
|
-
"menubar_signature_verify", "final_self_verification", "snapshot_refresh"
|
|
88
|
+
"menubar_signature_verify", "update_finalize_doctor", "final_self_verification", "snapshot_refresh"
|
|
89
89
|
]
|
|
90
90
|
private let directory: URL
|
|
91
91
|
private let queue = DispatchQueue(label: "com.sneakoscope.sks-menubar.operations")
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sneakoscope",
|
|
3
3
|
"displayName": "ㅅㅋㅅ",
|
|
4
|
-
"version": "8.0.
|
|
4
|
+
"version": "8.0.1",
|
|
5
5
|
"description": "Proof-first Codex CLI and ChatGPT Desktop orchestration for AI coding agents, release verification, and macOS menu bar control.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"homepage": "https://github.com/mandarange/Sneakoscope-Codex#readme",
|