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.
@@ -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":"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"}
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