@ours.network/fleet 1.2.0-nightly.21 → 1.2.0-nightly.23
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/application/conversation-history.d.ts +19 -0
- package/dist/application/conversation-history.js +125 -1
- package/dist/application/session-control.d.ts +10 -0
- package/dist/application/session-control.js +35 -2
- package/dist/build-info.json +4 -4
- package/dist/isolation/policy.js +2 -0
- package/dist/isolation/types.d.ts +5 -0
- package/dist/runner.js +8 -1
- package/dist/session/acp.js +7 -0
- package/dist/session/control.js +1 -0
- package/dist/subscriptions/cli.d.ts +78 -0
- package/dist/subscriptions/cli.js +186 -0
- package/dist/subscriptions/launch.d.ts +37 -0
- package/dist/subscriptions/launch.js +93 -0
- package/dist/subscriptions/login.d.ts +75 -0
- package/dist/subscriptions/login.js +182 -0
- package/dist/subscriptions/observed.d.ts +7 -0
- package/dist/subscriptions/observed.js +44 -0
- package/dist/subscriptions/probe.d.ts +10 -0
- package/dist/subscriptions/probe.js +73 -0
- package/dist/subscriptions/service.d.ts +102 -0
- package/dist/subscriptions/service.js +364 -0
- package/dist/subscriptions/store.d.ts +71 -0
- package/dist/subscriptions/store.js +140 -0
- package/dist/web/runtime.js +7 -0
- package/dist/web/server.d.ts +2 -0
- package/dist/web/server.js +95 -5
- package/package.json +1 -1
package/dist/web/server.js
CHANGED
|
@@ -17,6 +17,7 @@ import { FleetEventBus } from './events.js';
|
|
|
17
17
|
import { ROLE_NAME_RE } from '../config.js';
|
|
18
18
|
import { TaskListError } from '../rooms-tasks/task-lists.js';
|
|
19
19
|
import { TaskStateError } from '../rooms-tasks/task-state.js';
|
|
20
|
+
import { isProvider } from '../subscriptions/store.js';
|
|
20
21
|
const statusFor = (code) => ({
|
|
21
22
|
role_not_found: 404, resource_not_found: 404, unauthorized: 401, forbidden: 403, conflict: 409,
|
|
22
23
|
idempotency_conflict: 409, stale_state: 409, rate_limited: 429,
|
|
@@ -433,6 +434,86 @@ export async function buildWebServer(services, boundary, options = {}) {
|
|
|
433
434
|
});
|
|
434
435
|
return result;
|
|
435
436
|
});
|
|
437
|
+
// Claude Code / Codex subscription profiles. Responses carry account metadata
|
|
438
|
+
// only; token values never leave the CLI-owned credential files.
|
|
439
|
+
const subscriptions = () => {
|
|
440
|
+
if (!services.subscriptions)
|
|
441
|
+
throw new FleetError('capability_unavailable', 'subscription management is unavailable');
|
|
442
|
+
return services.subscriptions;
|
|
443
|
+
};
|
|
444
|
+
const provider = (raw) => {
|
|
445
|
+
if (!isProvider(raw))
|
|
446
|
+
throw new FleetError('invalid_request', 'unknown subscription provider');
|
|
447
|
+
return raw;
|
|
448
|
+
};
|
|
449
|
+
const subscriptionsChanged = () => events.publish('subscription.changed', {});
|
|
450
|
+
app.get('/api/v1/subscriptions', async (request) => {
|
|
451
|
+
auth.authenticate(request);
|
|
452
|
+
return { providers: await subscriptions().list() };
|
|
453
|
+
});
|
|
454
|
+
app.post('/api/v1/subscriptions/:provider/logins', async (request, reply) => {
|
|
455
|
+
const session = auth.authenticate(request, true);
|
|
456
|
+
const login = await subscriptions().startLogin(provider(request.params.provider), session.id);
|
|
457
|
+
await audit.record({ requestId: request.id, browser: session.id, action: `subscription.login.${request.params.provider}`, result: login.state });
|
|
458
|
+
reply.code(201);
|
|
459
|
+
return login;
|
|
460
|
+
});
|
|
461
|
+
app.get('/api/v1/subscriptions/:provider/logins/:loginId', async (request) => {
|
|
462
|
+
const session = auth.authenticate(request);
|
|
463
|
+
return subscriptions().login(request.params.loginId, session.id).view();
|
|
464
|
+
});
|
|
465
|
+
app.post('/api/v1/subscriptions/:provider/logins/:loginId/code', async (request) => {
|
|
466
|
+
const session = auth.authenticate(request, true);
|
|
467
|
+
const code = request.body?.code;
|
|
468
|
+
if (typeof code !== 'string')
|
|
469
|
+
throw new FleetError('invalid_request', 'code is required');
|
|
470
|
+
const login = subscriptions().login(request.params.loginId, session.id);
|
|
471
|
+
login.submitCode(code.trim());
|
|
472
|
+
await audit.record({ requestId: request.id, browser: session.id, action: `subscription.login.code.${request.params.provider}`, result: 'submitted' });
|
|
473
|
+
return login.view();
|
|
474
|
+
});
|
|
475
|
+
app.delete('/api/v1/subscriptions/:provider/logins/:loginId', async (request) => {
|
|
476
|
+
const session = auth.authenticate(request, true);
|
|
477
|
+
const login = subscriptions().login(request.params.loginId, session.id);
|
|
478
|
+
login.cancel();
|
|
479
|
+
return login.view();
|
|
480
|
+
});
|
|
481
|
+
app.post('/api/v1/subscriptions/:provider/active', async (request) => {
|
|
482
|
+
const session = auth.authenticate(request, true);
|
|
483
|
+
const profileId = request.body?.profileId;
|
|
484
|
+
if (typeof profileId !== 'string')
|
|
485
|
+
throw new FleetError('invalid_request', 'profileId is required');
|
|
486
|
+
const view = await subscriptions().setActive(provider(request.params.provider), profileId);
|
|
487
|
+
subscriptionsChanged();
|
|
488
|
+
await audit.record({ requestId: request.id, browser: session.id, action: `subscription.activate.${request.params.provider}`, result: 'succeeded' });
|
|
489
|
+
return view;
|
|
490
|
+
});
|
|
491
|
+
app.post('/api/v1/subscriptions/:provider/profiles/:profileId/check', async (request) => {
|
|
492
|
+
auth.authenticate(request, true);
|
|
493
|
+
return subscriptions().check(provider(request.params.provider), request.params.profileId);
|
|
494
|
+
});
|
|
495
|
+
app.post('/api/v1/subscriptions/claude/profiles/:profileId/probe', async (request) => {
|
|
496
|
+
const session = auth.authenticate(request, true);
|
|
497
|
+
const usage = await subscriptions().probeClaudeUsage(request.params.profileId);
|
|
498
|
+
await audit.record({ requestId: request.id, browser: session.id, action: 'subscription.usage.probe.claude', result: usage.source });
|
|
499
|
+
return { usage };
|
|
500
|
+
});
|
|
501
|
+
app.patch('/api/v1/subscriptions/:provider/profiles/:profileId', async (request) => {
|
|
502
|
+
auth.authenticate(request, true);
|
|
503
|
+
const label = request.body?.label;
|
|
504
|
+
if (typeof label !== 'string')
|
|
505
|
+
throw new FleetError('invalid_request', 'label is required');
|
|
506
|
+
await subscriptions().rename(provider(request.params.provider), request.params.profileId, label);
|
|
507
|
+
subscriptionsChanged();
|
|
508
|
+
return { ok: true };
|
|
509
|
+
});
|
|
510
|
+
app.delete('/api/v1/subscriptions/:provider/profiles/:profileId', async (request) => {
|
|
511
|
+
const session = auth.authenticate(request, true);
|
|
512
|
+
await subscriptions().remove(provider(request.params.provider), request.params.profileId);
|
|
513
|
+
subscriptionsChanged();
|
|
514
|
+
await audit.record({ requestId: request.id, browser: session.id, action: `subscription.remove.${request.params.provider}`, result: 'succeeded' });
|
|
515
|
+
return { ok: true };
|
|
516
|
+
});
|
|
436
517
|
app.get('/api/v1/topology', async (request) => {
|
|
437
518
|
auth.authenticate(request);
|
|
438
519
|
if (!services.topology)
|
|
@@ -543,13 +624,22 @@ export async function buildWebServer(services, boundary, options = {}) {
|
|
|
543
624
|
const control = await services.session(request.params.id);
|
|
544
625
|
if (!control.conversationPage)
|
|
545
626
|
throw new FleetError('capability_unavailable', 'this role has no conversation ledger');
|
|
546
|
-
const
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
627
|
+
const limit = request.query.limit ? Number(request.query.limit) : undefined;
|
|
628
|
+
// `latest` / `before` page backwards from the newest event; `after` pages forward for live updates.
|
|
629
|
+
const backward = request.query.latest === '1' || request.query.before !== undefined;
|
|
630
|
+
if (backward && request.query.after !== undefined)
|
|
631
|
+
throw new FleetError('invalid_request', 'after cannot be combined with latest or before');
|
|
632
|
+
if (backward && !control.conversationTail)
|
|
633
|
+
throw new FleetError('capability_unavailable', 'this role cannot page its conversation backwards');
|
|
550
634
|
const role = await services.repository.get(request.params.id);
|
|
551
635
|
const stateDir = role ? services.repository.stateDir(role) : undefined;
|
|
552
|
-
|
|
636
|
+
const present = (event) => presentAttachmentEvent(stateDir, request.params.id, event);
|
|
637
|
+
if (backward) {
|
|
638
|
+
const page = await control.conversationTail({ before: request.query.before, limit });
|
|
639
|
+
return { ...page, events: page.events.map(present), context: page.context.map(present) };
|
|
640
|
+
}
|
|
641
|
+
const page = await control.conversationPage({ after: request.query.after, limit });
|
|
642
|
+
return { ...page, events: page.events.map(present) };
|
|
553
643
|
});
|
|
554
644
|
app.get('/api/v1/roles/:id/attachments/:attachmentId', async (request, reply) => {
|
|
555
645
|
auth.authenticate(request);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ours.network/fleet",
|
|
3
|
-
"version": "1.2.0-nightly.
|
|
3
|
+
"version": "1.2.0-nightly.23",
|
|
4
4
|
"description": "Harness-agnostic fleet of persistent, identity-bound AI agents. Declarative fleet.yaml, managed native/ACP sessions, supervision, and ours.network messaging.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "FSL-1.1-Apache-2.0",
|