instar 0.28.121 → 0.28.123
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/dist/cli.js +1 -1
- package/dist/cli.js.map +1 -1
- package/dist/commands/server.js +1 -1
- package/dist/commands/server.js.map +1 -1
- package/dist/core/PostUpdateMigrator.d.ts +14 -0
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +206 -0
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/core/UpdateChecker.js +1 -1
- package/dist/core/UpdateChecker.js.map +1 -1
- package/dist/monitoring/FrameworkParitySentinel.d.ts +12 -0
- package/dist/monitoring/FrameworkParitySentinel.d.ts.map +1 -1
- package/dist/monitoring/FrameworkParitySentinel.js +11 -0
- package/dist/monitoring/FrameworkParitySentinel.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +46 -46
- package/upgrades/0.28.121.md +16 -17
- package/upgrades/0.28.122.md +38 -0
- package/upgrades/0.28.123.md +36 -0
- package/upgrades/1.0.8.md +40 -0
- package/upgrades/side-effects/feat-lessons-aware-reviewer.md +64 -0
- package/upgrades/side-effects/feat-parity-renderings-backfill.md +72 -0
- package/upgrades/side-effects/feat-parity-sentinel-trust-wiring.md +68 -0
|
@@ -72,6 +72,20 @@ export declare class PostUpdateMigrator {
|
|
|
72
72
|
* each migration is idempotent.
|
|
73
73
|
*/
|
|
74
74
|
migrate(): MigrationResult;
|
|
75
|
+
/**
|
|
76
|
+
* Async migration superset — runs the sync migrate() then performs the
|
|
77
|
+
* async parity-renderings backfill that needs rule.remediate() Promises.
|
|
78
|
+
* Callers in async contexts should prefer migrateAsync() to ensure all
|
|
79
|
+
* post-update side effects (including primitive-rendering backfill) are
|
|
80
|
+
* complete before returning.
|
|
81
|
+
*
|
|
82
|
+
* Sync callers can still use migrate() and rely on the next async pass to
|
|
83
|
+
* pick up the parity backfill. The marker in _instar_migrations ensures
|
|
84
|
+
* the backfill runs exactly once even across mixed sync/async callers.
|
|
85
|
+
*/
|
|
86
|
+
migrateAsync(): Promise<MigrationResult>;
|
|
87
|
+
private migrateParityRenderings;
|
|
88
|
+
private migrateParitySentinelTrust;
|
|
75
89
|
private migrateProviderPortability;
|
|
76
90
|
private migrateFleetWatchdog;
|
|
77
91
|
private migrateContextDeathAntiPattern;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PostUpdateMigrator.d.ts","sourceRoot":"","sources":["../../src/core/PostUpdateMigrator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AA8BH,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,qBAAqB,EAC3B,MAAM,yBAAyB,CAAC;AAIjC,MAAM,WAAW,eAAe;IAC9B,wBAAwB;IACxB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,kCAAkC;IAClC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,2CAA2C;IAC3C,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,MAAM,CAAiB;IAC/B;;;;;;OAMG;IACH,OAAO,CAAC,UAAU,CAAiC;gBAEvC,MAAM,EAAE,cAAc;IAIlC;;;;;;;;;;;OAWG;IACH,YAAY,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI;IAItC;;;;;;OAMG;IACG,eAAe,CACnB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,qBAAqB,CAAC;IAIjC,OAAO,CAAC,aAAa;IAOrB;;;OAGG;IACH,OAAO,IAAI,eAAe;
|
|
1
|
+
{"version":3,"file":"PostUpdateMigrator.d.ts","sourceRoot":"","sources":["../../src/core/PostUpdateMigrator.ts"],"names":[],"mappings":"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"}
|
|
@@ -111,8 +111,214 @@ export class PostUpdateMigrator {
|
|
|
111
111
|
this.migrateContextDeathAntiPattern(result);
|
|
112
112
|
this.migrateProviderPortability(result);
|
|
113
113
|
this.migrateFleetWatchdog(result);
|
|
114
|
+
this.migrateParitySentinelTrust(result);
|
|
114
115
|
return result;
|
|
115
116
|
}
|
|
117
|
+
/**
|
|
118
|
+
* Async migration superset — runs the sync migrate() then performs the
|
|
119
|
+
* async parity-renderings backfill that needs rule.remediate() Promises.
|
|
120
|
+
* Callers in async contexts should prefer migrateAsync() to ensure all
|
|
121
|
+
* post-update side effects (including primitive-rendering backfill) are
|
|
122
|
+
* complete before returning.
|
|
123
|
+
*
|
|
124
|
+
* Sync callers can still use migrate() and rely on the next async pass to
|
|
125
|
+
* pick up the parity backfill. The marker in _instar_migrations ensures
|
|
126
|
+
* the backfill runs exactly once even across mixed sync/async callers.
|
|
127
|
+
*/
|
|
128
|
+
async migrateAsync() {
|
|
129
|
+
const result = this.migrate();
|
|
130
|
+
try {
|
|
131
|
+
await this.migrateParityRenderings(result);
|
|
132
|
+
}
|
|
133
|
+
catch (err) {
|
|
134
|
+
result.errors.push(`parity-renderings: backfill failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
135
|
+
}
|
|
136
|
+
return result;
|
|
137
|
+
}
|
|
138
|
+
// ── Parity Rule Rendering Backfill ─────────────────────────────────
|
|
139
|
+
//
|
|
140
|
+
// For every registered parity rule (Layer-3 functional primitive), iterate
|
|
141
|
+
// its canonical instances and call remediate() for each enabled framework.
|
|
142
|
+
// This is the Migration Parity §5-style backfill for primitive-renderings
|
|
143
|
+
// that PRs #252 (Skill), #253 (Hook), #254 (Memory) deferred — existing
|
|
144
|
+
// deployed agents pick up the canonical→framework rendering on update.
|
|
145
|
+
//
|
|
146
|
+
// skillParityRule: refuse-on-conflict (per §5). User-edited skill files
|
|
147
|
+
// are preserved with operator-action requirement.
|
|
148
|
+
// hookParityRule: alwaysOverwrite=true (per §4). Built-in hooks ALWAYS
|
|
149
|
+
// re-render from canonical; user edits captured in audit event for
|
|
150
|
+
// git-recovery.
|
|
151
|
+
// memoryParityRule: refuse-on-conflict (per §5). Memory canonical content
|
|
152
|
+
// is operator-managed; system never clobbers.
|
|
153
|
+
//
|
|
154
|
+
// Idempotent via _instar_migrations marker AND each rule's verify-first
|
|
155
|
+
// pattern (no-op when rendering matches canonical).
|
|
156
|
+
async migrateParityRenderings(result) {
|
|
157
|
+
const configPath = path.join(this.config.stateDir, 'config.json');
|
|
158
|
+
if (!fs.existsSync(configPath)) {
|
|
159
|
+
result.skipped.push('parity-renderings: config.json not found');
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
let config;
|
|
163
|
+
try {
|
|
164
|
+
config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
165
|
+
}
|
|
166
|
+
catch (err) {
|
|
167
|
+
result.errors.push(`parity-renderings: config.json read failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
const migrations = (config._instar_migrations ?? []);
|
|
171
|
+
const marker = 'parity-renderings-backfill-v1';
|
|
172
|
+
if (migrations.some(m => m.startsWith(marker))) {
|
|
173
|
+
result.skipped.push('parity-renderings: already migrated');
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
// Lazy-import registry so PostUpdateMigrator doesn't pull the entire
|
|
177
|
+
// parity graph at startup for agents that never invoke migrate().
|
|
178
|
+
const { listParityRules } = await import('../providers/parity/registry.js');
|
|
179
|
+
// Determine enabled frameworks from config — default to claude-code+codex-cli
|
|
180
|
+
// for portable agents, claude-code-only as a safe fallback.
|
|
181
|
+
const frameworks = (() => {
|
|
182
|
+
const enabled = config.enabledFrameworks;
|
|
183
|
+
if (Array.isArray(enabled) && enabled.length > 0) {
|
|
184
|
+
return enabled.filter(f => f === 'claude-code' || f === 'codex-cli');
|
|
185
|
+
}
|
|
186
|
+
return ['claude-code'];
|
|
187
|
+
})();
|
|
188
|
+
const rules = listParityRules();
|
|
189
|
+
let renderedCount = 0;
|
|
190
|
+
let skippedCount = 0;
|
|
191
|
+
for (const rule of rules) {
|
|
192
|
+
let instances;
|
|
193
|
+
try {
|
|
194
|
+
instances = await rule.listInstances(this.config.projectDir);
|
|
195
|
+
}
|
|
196
|
+
catch (err) {
|
|
197
|
+
result.errors.push(`parity-renderings: ${rule.primitive} listInstances failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
for (const instance of instances) {
|
|
201
|
+
for (const framework of frameworks) {
|
|
202
|
+
if (!rule.frameworks.includes(framework))
|
|
203
|
+
continue;
|
|
204
|
+
try {
|
|
205
|
+
await rule.remediate(this.config.projectDir, instance, framework);
|
|
206
|
+
renderedCount += 1;
|
|
207
|
+
result.upgraded.push(`parity-renderings: ${rule.primitive}/${instance} → ${framework}`);
|
|
208
|
+
}
|
|
209
|
+
catch (err) {
|
|
210
|
+
// refuse-on-conflict (mirror-trust without alwaysOverwrite) is
|
|
211
|
+
// expected for user-edited renderings — not an error, just a
|
|
212
|
+
// skip. Capture for visibility.
|
|
213
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
214
|
+
if (msg.includes('user-edit-conflict')) {
|
|
215
|
+
skippedCount += 1;
|
|
216
|
+
result.skipped.push(`parity-renderings: ${rule.primitive}/${instance} on ${framework} — ${msg}`);
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
result.errors.push(`parity-renderings: ${rule.primitive}/${instance} on ${framework} — ${msg}`);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
// Mark migration complete regardless of per-instance skips — the marker
|
|
226
|
+
// means "this backfill pass ran successfully," not "every rendering
|
|
227
|
+
// succeeded." Operators resolve user-edit-conflicts via /spec-converge.
|
|
228
|
+
migrations.push(`${marker}-${new Date().toISOString()}`);
|
|
229
|
+
config._instar_migrations = migrations;
|
|
230
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
231
|
+
if (renderedCount === 0 && skippedCount === 0) {
|
|
232
|
+
result.skipped.push('parity-renderings: no canonical instances found (new agent or no primitives shipped yet)');
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
// ── Parity Sentinel trust profile seed ─────────────────────────────
|
|
236
|
+
//
|
|
237
|
+
// FrameworkParitySentinel.shouldRemediate now consults AdaptiveTrust on
|
|
238
|
+
// mirror-trust rules: trust level 'log' or 'autonomous' allows remediation,
|
|
239
|
+
// 'approve-*' or 'blocked' downgrades to flag-only. AdaptiveTrust's
|
|
240
|
+
// DEFAULT_TRUST for 'modify' is 'approve-always', which would silently turn
|
|
241
|
+
// every mirror-trust rule into flag-only for existing agents on update.
|
|
242
|
+
//
|
|
243
|
+
// This migration seeds state/trust-profile.json with a parity-sentinel
|
|
244
|
+
// service entry at level 'log' (auto-elevatable, never blocking by default)
|
|
245
|
+
// so existing agents preserve the v0.1 remediate-by-default behavior. New
|
|
246
|
+
// agents get the same seed via the natural AdaptiveTrust flow once the
|
|
247
|
+
// sentinel first calls getTrustLevel.
|
|
248
|
+
//
|
|
249
|
+
// Idempotent: re-runs are no-ops via the _instar_migrations marker AND a
|
|
250
|
+
// content-sniff (skip if parity-sentinel service entry already exists).
|
|
251
|
+
migrateParitySentinelTrust(result) {
|
|
252
|
+
const configPath = path.join(this.config.stateDir, 'config.json');
|
|
253
|
+
const trustProfilePath = path.join(this.config.stateDir, 'state', 'trust-profile.json');
|
|
254
|
+
if (!fs.existsSync(configPath)) {
|
|
255
|
+
result.skipped.push('parity-sentinel-trust: config.json not found');
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
let config;
|
|
259
|
+
try {
|
|
260
|
+
config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
261
|
+
}
|
|
262
|
+
catch (err) {
|
|
263
|
+
result.errors.push(`parity-sentinel-trust: config.json read failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
const migrations = (config._instar_migrations ?? []);
|
|
267
|
+
const marker = 'parity-sentinel-trust-seed';
|
|
268
|
+
if (migrations.some(m => m.startsWith(marker))) {
|
|
269
|
+
result.skipped.push('parity-sentinel-trust: already migrated');
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
// Load existing trust profile (or create skeleton). Content-sniff: skip
|
|
273
|
+
// if a parity-sentinel service entry already exists (operator-set).
|
|
274
|
+
let profile;
|
|
275
|
+
try {
|
|
276
|
+
if (fs.existsSync(trustProfilePath)) {
|
|
277
|
+
profile = JSON.parse(fs.readFileSync(trustProfilePath, 'utf-8'));
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
profile = {
|
|
281
|
+
services: {},
|
|
282
|
+
global: {
|
|
283
|
+
maturity: 0,
|
|
284
|
+
lastEvent: 'Profile created by parity-sentinel-trust-seed migration',
|
|
285
|
+
lastEventAt: new Date().toISOString(),
|
|
286
|
+
floor: 'collaborative',
|
|
287
|
+
},
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
catch (err) {
|
|
292
|
+
result.errors.push(`parity-sentinel-trust: trust-profile.json read failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
if (profile.services['parity-sentinel']) {
|
|
296
|
+
// Operator already configured it — never overwrite. Mark migration done.
|
|
297
|
+
migrations.push(`${marker}-${new Date().toISOString()}-existing-entry-preserved`);
|
|
298
|
+
config._instar_migrations = migrations;
|
|
299
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
300
|
+
result.skipped.push('parity-sentinel-trust: existing entry preserved');
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
const now = new Date().toISOString();
|
|
304
|
+
profile.services['parity-sentinel'] = {
|
|
305
|
+
service: 'parity-sentinel',
|
|
306
|
+
operations: {
|
|
307
|
+
modify: { level: 'log', source: 'default', changedAt: now },
|
|
308
|
+
},
|
|
309
|
+
history: { successCount: 0, incidentCount: 0, streakSinceIncident: 0 },
|
|
310
|
+
};
|
|
311
|
+
// Ensure state dir exists before writing the profile.
|
|
312
|
+
const stateDir = path.dirname(trustProfilePath);
|
|
313
|
+
if (!fs.existsSync(stateDir)) {
|
|
314
|
+
fs.mkdirSync(stateDir, { recursive: true });
|
|
315
|
+
}
|
|
316
|
+
fs.writeFileSync(trustProfilePath, JSON.stringify(profile, null, 2));
|
|
317
|
+
migrations.push(`${marker}-${now}`);
|
|
318
|
+
config._instar_migrations = migrations;
|
|
319
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
320
|
+
result.upgraded.push('parity-sentinel-trust: seeded trust profile entry at level=log');
|
|
321
|
+
}
|
|
116
322
|
// ── Provider portability v1.0.0 — Phase 7 migration entry ──────────
|
|
117
323
|
//
|
|
118
324
|
// Idempotent migrator that runs on every `instar update`. Confirms the
|