@stage-labs/metro 0.1.0-beta.298 → 0.1.0-beta.299
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/package.json +1 -1
- package/runtime/marketplace/plugin/.claude-plugin/plugin.json +1 -1
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/org-runtime.ts +20 -8
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/org-sync.ts +14 -3
- package/runtime/runtime.json +1 -1
- package/runtime/sdk-runner/runner.json +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "metro",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.299",
|
|
4
4
|
"description": "Metro for Claude Code, installed by the metro daemon on this machine: every connector the agent holds as its own MCP server relayed through the daemon, the orchestrator-only guard on the main thread, and the standing rules loaded at each session start. No vendor credential ever sits in a config file.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Bonustrack",
|
|
@@ -3,7 +3,7 @@ import { agentsDir } from '../agents/files.js';
|
|
|
3
3
|
import { assertMigrationOutcomeKnown, beginMigrationOperation, migrationRequestEffectful, type MigrationOperation } from './migration-operations.js';
|
|
4
4
|
import type { FetchLike } from '@metro-labs/core/stations/oauth';
|
|
5
5
|
import type { ToolGroup } from '@metro-labs/core/stations/types';
|
|
6
|
-
import { effectiveConnectorPolicy, type DeliveredConnector } from '@metro-labs/http/connector-delivery';
|
|
6
|
+
import { effectiveConnectorPolicy, type DeliveredConnector, type DeliverySnapshot } from '@metro-labs/http/connector-delivery';
|
|
7
7
|
import type { ApiError } from '@metro-labs/http/api-error';
|
|
8
8
|
import { requestConnectorBlocker, type GateRow } from './gates.js';
|
|
9
9
|
import { publishOrgConnectors } from './publication.js';
|
|
@@ -92,7 +92,7 @@ export class OrgConnectorRuntime {
|
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
private publish(rows: RuntimeRow[]): void {
|
|
95
|
-
const metadata: GateRow[] = rows.
|
|
95
|
+
const metadata: GateRow[] = rows.map((row) => ({
|
|
96
96
|
id: row.relayId, name: row.relayName,
|
|
97
97
|
config: { policy: effectiveConnectorPolicy(row, this.entries.get(row.id)?.groups ?? {}), toolGroups: { ...this.entries.get(row.id)?.groups } },
|
|
98
98
|
}));
|
|
@@ -145,14 +145,13 @@ export class OrgConnectorRuntime {
|
|
|
145
145
|
private update(): RuntimeRow[] | null {
|
|
146
146
|
try {
|
|
147
147
|
const mapping = this.mapping();
|
|
148
|
-
const
|
|
149
|
-
const
|
|
148
|
+
const wanted = this.enabled() || mapping.aliases.length > 0;
|
|
149
|
+
const snapshot = wanted ? this.sync.read() : null;
|
|
150
150
|
const epoch = this.sync.epoch();
|
|
151
|
+
if (this.held(snapshot, wanted, epoch)) return null;
|
|
152
|
+
const rows = this.mappedRows(snapshot?.connectors ?? [], mapping);
|
|
151
153
|
this.invalidateEntries(rows, epoch, snapshot !== null);
|
|
152
|
-
|
|
153
|
-
if (row.state !== 'ready' || this.entries.has(row.id)) continue;
|
|
154
|
-
this.entries.set(row.id, { id: row.id, relayId: row.relayId, epoch, stamp: stampOf(row), controller: new AbortController(), groups: {}, scan: null, nextScan: 0, error: null });
|
|
155
|
-
}
|
|
154
|
+
this.track(rows, epoch);
|
|
156
155
|
this.publish(rows);
|
|
157
156
|
return snapshot === null ? null : rows;
|
|
158
157
|
} catch {
|
|
@@ -162,6 +161,19 @@ export class OrgConnectorRuntime {
|
|
|
162
161
|
}
|
|
163
162
|
}
|
|
164
163
|
|
|
164
|
+
private track(rows: RuntimeRow[], epoch: number): void {
|
|
165
|
+
for (const row of rows) {
|
|
166
|
+
if (row.state !== 'ready' || this.entries.has(row.id)) continue;
|
|
167
|
+
this.entries.set(row.id, { id: row.id, relayId: row.relayId, epoch, stamp: stampOf(row), controller: new AbortController(), groups: {}, scan: null, nextScan: 0, error: null });
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
private held(snapshot: DeliverySnapshot | null, wanted: boolean, epoch: number): boolean {
|
|
172
|
+
if (snapshot !== null || !wanted || !this.sync.lapsed()) return false;
|
|
173
|
+
this.invalidateEntries([], epoch, false);
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
|
|
165
177
|
refresh(): void {
|
|
166
178
|
this.update();
|
|
167
179
|
}
|
|
@@ -5,7 +5,7 @@ import { ApiError } from '@metro-labs/http/api-error';
|
|
|
5
5
|
import { AGENT_CLOCK_SKEW_MS } from '@metro-labs/http/agent-signature';
|
|
6
6
|
import { CONNECTOR_DELIVERY_LEASE_MS, CONNECTOR_DELIVERY_MAX_BYTES, openConnectorDelivery, type DeliveryContext, type DeliverySnapshot } from '@metro-labs/http/connector-delivery';
|
|
7
7
|
import type { AgentKey } from './agent-key.js';
|
|
8
|
-
import { agentCall, type MetroApi } from './metro-api.js';
|
|
8
|
+
import { agentCall, MetroApiRefusal, type MetroApi } from './metro-api.js';
|
|
9
9
|
|
|
10
10
|
interface Identity {
|
|
11
11
|
key: AgentKey;
|
|
@@ -93,6 +93,12 @@ export class OrgConnectorSync {
|
|
|
93
93
|
this.expiry = null;
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
+
private refused = false;
|
|
97
|
+
|
|
98
|
+
lapsed(): boolean {
|
|
99
|
+
return !this.refused && (this.receipt.state === 'expired' || this.receipt.state === 'unavailable');
|
|
100
|
+
}
|
|
101
|
+
|
|
96
102
|
invalidate(reason: 'waiting' | 'expired' | 'unavailable' = 'waiting'): void {
|
|
97
103
|
this.generation += 1;
|
|
98
104
|
this.controller?.abort();
|
|
@@ -147,8 +153,13 @@ export class OrgConnectorSync {
|
|
|
147
153
|
this.token = identity.token;
|
|
148
154
|
const generation = this.generation;
|
|
149
155
|
this.controller = new AbortController();
|
|
150
|
-
this.running = this.fetch(identity, refresh, generation, this.controller.signal).
|
|
151
|
-
|
|
156
|
+
this.running = this.fetch(identity, refresh, generation, this.controller.signal).then(() => {
|
|
157
|
+
this.refused = false;
|
|
158
|
+
}, (err: unknown) => {
|
|
159
|
+
if (generation === this.generation) {
|
|
160
|
+
this.refused = err instanceof MetroApiRefusal && err.upstreamStatus < 500;
|
|
161
|
+
this.invalidate('unavailable');
|
|
162
|
+
}
|
|
152
163
|
throw err;
|
|
153
164
|
}).finally(() => { this.running = null; });
|
|
154
165
|
return this.running;
|
package/runtime/runtime.json
CHANGED