forkit-connect 0.1.0 → 0.1.3

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/v1/api.d.ts CHANGED
@@ -233,16 +233,77 @@ export interface DeploymentListResponse {
233
233
  } | null;
234
234
  sessions?: DeploymentSessionResponse[];
235
235
  }
236
+ export interface DeploymentScopeQuery {
237
+ workspaceId?: string | null;
238
+ projectId?: string | null;
239
+ }
240
+ export interface DeploymentSummaryResponse {
241
+ gaid?: string | null;
242
+ summary?: DeploymentListResponse['summary'] | null;
243
+ }
244
+ export interface DeploymentLivenessResponse {
245
+ gaid?: string | null;
246
+ checkinStatus?: string | null;
247
+ lastCheckinAt?: string | null;
248
+ metadata?: Record<string, unknown> | null;
249
+ }
250
+ export interface PassportLedgerEntry {
251
+ id?: string | null;
252
+ eventType?: string | null;
253
+ eventGroup?: string | null;
254
+ actorType?: string | null;
255
+ actorLabel?: string | null;
256
+ occurredAt?: string | null;
257
+ reasonRequired?: boolean | null;
258
+ approvalState?: string | null;
259
+ metadata?: Record<string, unknown> | null;
260
+ }
261
+ export interface PassportLedgerPolicy {
262
+ canExport?: boolean;
263
+ viewerRole?: string | null;
264
+ retentionDays?: number | null;
265
+ }
266
+ export interface PassportLedgerResponse {
267
+ gaid?: string | null;
268
+ ledger?: PassportLedgerEntry[];
269
+ total?: number | null;
270
+ hasMore?: boolean;
271
+ visibility?: 'full' | 'public_safe' | string;
272
+ policy?: PassportLedgerPolicy | null;
273
+ }
274
+ export interface PassportLedgerQuery {
275
+ limit?: number;
276
+ actorTypes?: string | string[];
277
+ eventGroups?: string | string[];
278
+ q?: string;
279
+ download?: 'json' | 'csv';
280
+ }
281
+ export type DeploymentSessionControlAction = 'pause' | 'resume' | 'revoke';
282
+ export interface DeploymentSessionControlRequest {
283
+ reason?: string;
284
+ }
236
285
  export declare class ConnectApiClient {
237
286
  private readonly config;
238
287
  constructor(config: ConnectApiConfig);
288
+ private buildApiUrl;
289
+ private buildPassportApiPath;
290
+ private appendScopeParams;
291
+ private appendCsvParam;
239
292
  private getHeaders;
240
293
  private parseContract;
241
294
  getPassportsMine(limit?: number): Promise<ApiCallResult>;
242
295
  getProductSummary(): Promise<ApiCallResult>;
243
296
  createPassportDraft(payload: Record<string, unknown>): Promise<ApiCallResult>;
244
297
  pushRuntimeSignalEvent(payload: Record<string, unknown>): Promise<ApiCallResult>;
245
- getDeployments(gaid: string): Promise<ApiCallResult>;
298
+ pushRuntimeRunLog(payload: Record<string, unknown>): Promise<ApiCallResult>;
299
+ getDeployments(gaid: string, scope?: DeploymentScopeQuery): Promise<ApiCallResult>;
300
+ getDeploymentSummary(gaid: string, scope?: DeploymentScopeQuery): Promise<ApiCallResult>;
301
+ getDeploymentLiveness(gaid: string, scope?: DeploymentScopeQuery): Promise<ApiCallResult>;
302
+ getPassportLedger(gaid: string, query?: PassportLedgerQuery, scope?: DeploymentScopeQuery): Promise<ApiCallResult>;
303
+ controlDeploymentSession(gaid: string, sessionId: string, action: DeploymentSessionControlAction, payload?: DeploymentSessionControlRequest, scope?: DeploymentScopeQuery): Promise<ApiCallResult>;
304
+ pauseDeploymentSession(gaid: string, sessionId: string, payload?: DeploymentSessionControlRequest, scope?: DeploymentScopeQuery): Promise<ApiCallResult>;
305
+ resumeDeploymentSession(gaid: string, sessionId: string, payload?: DeploymentSessionControlRequest, scope?: DeploymentScopeQuery): Promise<ApiCallResult>;
306
+ revokeDeploymentSession(gaid: string, sessionId: string, payload?: DeploymentSessionControlRequest, scope?: DeploymentScopeQuery): Promise<ApiCallResult>;
246
307
  sendDeploymentCheckin(gaid: string, payload: DeploymentCheckinRequest): Promise<ApiCallResult>;
247
308
  getProfileAccess(): Promise<ApiCallResult>;
248
309
  getWorkspaceProjects(workspaceId: string): Promise<ApiCallResult>;
package/dist/v1/api.js CHANGED
@@ -23,6 +23,36 @@ class ConnectApiClient {
23
23
  constructor(config) {
24
24
  this.config = config;
25
25
  }
26
+ buildApiUrl(path, params) {
27
+ const query = params && params.toString();
28
+ return `${this.config.baseUrl}${path}${query ? `?${query}` : ''}`;
29
+ }
30
+ buildPassportApiPath(gaid, suffix = '') {
31
+ return `/api/v1/passports/${encodeURIComponent(gaid)}${suffix}`;
32
+ }
33
+ appendScopeParams(params, scope) {
34
+ const workspaceId = String(scope?.workspaceId || '').trim();
35
+ const projectId = String(scope?.projectId || '').trim();
36
+ if (workspaceId) {
37
+ params.set('workspaceId', workspaceId);
38
+ }
39
+ if (projectId) {
40
+ params.set('projectId', projectId);
41
+ }
42
+ }
43
+ appendCsvParam(params, key, value) {
44
+ if (Array.isArray(value)) {
45
+ const normalized = value.map((entry) => String(entry || '').trim()).filter(Boolean);
46
+ if (normalized.length) {
47
+ params.set(key, normalized.join(','));
48
+ }
49
+ return;
50
+ }
51
+ const normalized = String(value || '').trim();
52
+ if (normalized) {
53
+ params.set(key, normalized);
54
+ }
55
+ }
26
56
  getHeaders(extra) {
27
57
  const headers = {
28
58
  'Content-Type': 'application/json',
@@ -122,8 +152,39 @@ class ConnectApiClient {
122
152
  contract: this.parseContract(res),
123
153
  };
124
154
  }
125
- async getDeployments(gaid) {
126
- const url = `${this.config.baseUrl}/api/v1/passports/${encodeURIComponent(gaid)}/deployments`;
155
+ async pushRuntimeRunLog(payload) {
156
+ const url = `${this.config.baseUrl}/api/v1/runtime-signals/runs`;
157
+ const res = await fetch(url, {
158
+ method: 'POST',
159
+ headers: this.getHeaders(),
160
+ body: JSON.stringify(payload),
161
+ });
162
+ return {
163
+ ok: res.ok,
164
+ status: res.status,
165
+ body: await this.parseBody(res),
166
+ contract: this.parseContract(res),
167
+ };
168
+ }
169
+ async getDeployments(gaid, scope) {
170
+ const params = new URLSearchParams();
171
+ this.appendScopeParams(params, scope);
172
+ const url = this.buildApiUrl(this.buildPassportApiPath(gaid, '/deployments'), params);
173
+ const res = await fetch(url, {
174
+ method: 'GET',
175
+ headers: this.getHeaders(),
176
+ });
177
+ return {
178
+ ok: res.ok,
179
+ status: res.status,
180
+ body: await this.parseBody(res),
181
+ contract: this.parseContract(res),
182
+ };
183
+ }
184
+ async getDeploymentSummary(gaid, scope) {
185
+ const params = new URLSearchParams();
186
+ this.appendScopeParams(params, scope);
187
+ const url = this.buildApiUrl(this.buildPassportApiPath(gaid, '/deployments/summary'), params);
127
188
  const res = await fetch(url, {
128
189
  method: 'GET',
129
190
  headers: this.getHeaders(),
@@ -135,6 +196,74 @@ class ConnectApiClient {
135
196
  contract: this.parseContract(res),
136
197
  };
137
198
  }
199
+ async getDeploymentLiveness(gaid, scope) {
200
+ const params = new URLSearchParams();
201
+ this.appendScopeParams(params, scope);
202
+ const url = this.buildApiUrl(this.buildPassportApiPath(gaid, '/liveness'), params);
203
+ const res = await fetch(url, {
204
+ method: 'GET',
205
+ headers: this.getHeaders(),
206
+ });
207
+ return {
208
+ ok: res.ok,
209
+ status: res.status,
210
+ body: await this.parseBody(res),
211
+ contract: this.parseContract(res),
212
+ };
213
+ }
214
+ async getPassportLedger(gaid, query = {}, scope) {
215
+ const params = new URLSearchParams();
216
+ if (Number.isFinite(query.limit) && Number(query.limit) > 0) {
217
+ params.set('limit', String(Math.floor(Number(query.limit))));
218
+ }
219
+ this.appendCsvParam(params, 'actorTypes', query.actorTypes);
220
+ this.appendCsvParam(params, 'eventGroups', query.eventGroups);
221
+ const textQuery = String(query.q || '').trim();
222
+ if (textQuery) {
223
+ params.set('q', textQuery);
224
+ }
225
+ if (query.download) {
226
+ params.set('download', query.download);
227
+ }
228
+ this.appendScopeParams(params, scope);
229
+ const url = this.buildApiUrl(this.buildPassportApiPath(gaid, '/ledger'), params);
230
+ const res = await fetch(url, {
231
+ method: 'GET',
232
+ headers: this.getHeaders(),
233
+ });
234
+ return {
235
+ ok: res.ok,
236
+ status: res.status,
237
+ body: await this.parseBody(res),
238
+ contract: this.parseContract(res),
239
+ };
240
+ }
241
+ async controlDeploymentSession(gaid, sessionId, action, payload = {}, scope) {
242
+ const params = new URLSearchParams();
243
+ this.appendScopeParams(params, scope);
244
+ const path = this.buildPassportApiPath(gaid, `/deployments/${encodeURIComponent(sessionId)}/${action}`);
245
+ const url = this.buildApiUrl(path, params);
246
+ const res = await fetch(url, {
247
+ method: 'POST',
248
+ headers: this.getHeaders(),
249
+ body: JSON.stringify(payload),
250
+ });
251
+ return {
252
+ ok: res.ok,
253
+ status: res.status,
254
+ body: await this.parseBody(res),
255
+ contract: this.parseContract(res),
256
+ };
257
+ }
258
+ async pauseDeploymentSession(gaid, sessionId, payload = {}, scope) {
259
+ return this.controlDeploymentSession(gaid, sessionId, 'pause', payload, scope);
260
+ }
261
+ async resumeDeploymentSession(gaid, sessionId, payload = {}, scope) {
262
+ return this.controlDeploymentSession(gaid, sessionId, 'resume', payload, scope);
263
+ }
264
+ async revokeDeploymentSession(gaid, sessionId, payload = {}, scope) {
265
+ return this.controlDeploymentSession(gaid, sessionId, 'revoke', payload, scope);
266
+ }
138
267
  async sendDeploymentCheckin(gaid, payload) {
139
268
  const url = `${this.config.baseUrl}/api/v1/passports/${encodeURIComponent(gaid)}/deployments/checkin`;
140
269
  const res = await fetch(url, {
@@ -20,6 +20,7 @@ export interface ConnectCredentialStoreStatus {
20
20
  available: boolean;
21
21
  detail: string;
22
22
  legacyPlaintextFilePresent: boolean;
23
+ plaintextFallbackActive: boolean;
23
24
  }
24
25
  type WindowsDpapiOperation = 'status' | 'read' | 'write' | 'delete';
25
26
  interface WindowsDpapiCommandOptions {
@@ -19,6 +19,7 @@ class ConnectCredentialStoreError extends Error {
19
19
  exports.ConnectCredentialStoreError = ConnectCredentialStoreError;
20
20
  const SERVICE_BASE_NAME = 'ForkitConnect';
21
21
  const LEGACY_SERVICE_NAME = SERVICE_BASE_NAME;
22
+ const LINUX_SECRET_TOOL_TIMEOUT_MS = 1200;
22
23
  function nowIso() {
23
24
  return new Date().toISOString();
24
25
  }
@@ -274,6 +275,7 @@ class LinuxSecretServiceBackend {
274
275
  ...this.baseArgs(account),
275
276
  ], {
276
277
  encoding: 'utf8',
278
+ timeout: LINUX_SECRET_TOOL_TIMEOUT_MS,
277
279
  });
278
280
  if (result.error) {
279
281
  const detail = errnoCode(result.error) === 'ENOENT'
@@ -298,6 +300,7 @@ class LinuxSecretServiceBackend {
298
300
  ], {
299
301
  encoding: 'utf8',
300
302
  input: `${value}\n`,
303
+ timeout: LINUX_SECRET_TOOL_TIMEOUT_MS,
301
304
  });
302
305
  if (result.error) {
303
306
  const detail = errnoCode(result.error) === 'ENOENT'
@@ -316,6 +319,7 @@ class LinuxSecretServiceBackend {
316
319
  ...this.baseArgs(account),
317
320
  ], {
318
321
  encoding: 'utf8',
322
+ timeout: LINUX_SECRET_TOOL_TIMEOUT_MS,
319
323
  });
320
324
  if (result.error) {
321
325
  const detail = errnoCode(result.error) === 'ENOENT'
@@ -338,6 +342,7 @@ class LinuxSecretServiceBackend {
338
342
  }
339
343
  const result = (0, node_child_process_1.spawnSync)('secret-tool', ['search', 'service', this.serviceName], {
340
344
  encoding: 'utf8',
345
+ timeout: LINUX_SECRET_TOOL_TIMEOUT_MS,
341
346
  });
342
347
  if (result.error) {
343
348
  return {
@@ -495,7 +500,7 @@ class ConnectCredentialStore {
495
500
  this.credentialFile = node_path_1.default.join(stateDir, 'credentials.v1.json');
496
501
  this.backend = backend ?? createDefaultSecureCredentialBackend(stateDir);
497
502
  this.legacyBackend = legacyBackend === undefined ? createLegacySecureCredentialBackend() : legacyBackend;
498
- this.allowPlaintextFallback = process.env.FORKIT_CONNECT_ALLOW_PLAINTEXT_FALLBACK !== '0';
503
+ this.allowPlaintextFallback = process.env.FORKIT_CONNECT_ALLOW_PLAINTEXT_FALLBACK === '1';
499
504
  }
500
505
  getCredentialFilePath() {
501
506
  return this.credentialFile;
@@ -504,14 +509,18 @@ class ConnectCredentialStore {
504
509
  const backendStatus = this.backend.getStatus();
505
510
  const legacyPlaintextFilePresent = node_fs_1.default.existsSync(this.credentialFile);
506
511
  const fallbackActive = this.allowPlaintextFallback && legacyPlaintextFilePresent;
512
+ const disabledFallbackDetail = !this.allowPlaintextFallback && legacyPlaintextFilePresent
513
+ ? ` Plaintext fallback is disabled by default; remove ${this.credentialFile} after migrating credentials into secure storage.`
514
+ : '';
507
515
  const detail = fallbackActive
508
516
  ? `${this.lastBackendError?.message ?? backendStatus.detail} Connect is using local plaintext credential fallback at ${this.credentialFile}.`
509
- : this.lastBackendError?.message ?? backendStatus.detail;
517
+ : `${this.lastBackendError?.message ?? backendStatus.detail}${disabledFallbackDetail}`;
510
518
  return {
511
519
  backend: backendStatus.backend,
512
520
  available: fallbackActive || (backendStatus.available && !this.lastBackendError),
513
521
  detail,
514
522
  legacyPlaintextFilePresent,
523
+ plaintextFallbackActive: fallbackActive,
515
524
  };
516
525
  }
517
526
  migrateLegacyPlaintextFile() {
@@ -603,6 +612,9 @@ class ConnectCredentialStore {
603
612
  return `runtimeSignal:${gaid}`;
604
613
  }
605
614
  readAccount(account) {
615
+ if (this.cache.has(account)) {
616
+ return this.cache.get(account) ?? null;
617
+ }
606
618
  try {
607
619
  const current = this.backend.read(account);
608
620
  if (current) {
@@ -631,7 +643,7 @@ class ConnectCredentialStore {
631
643
  }
632
644
  return legacy;
633
645
  }
634
- this.cache.delete(account);
646
+ this.cache.set(account, null);
635
647
  return null;
636
648
  }
637
649
  writeAccount(account, value) {
@@ -1,5 +1,6 @@
1
+ import { type ApiCallResult } from './api';
1
2
  import { type ObservedAgentToolCallInput, type ObservedAgentToolCallResult, type ObservedAgentToolName } from './agent-observation';
2
- import { type SecureCredentialBackend } from './credential-store';
3
+ import { type ConnectCredentialStoreStatus, type SecureCredentialBackend } from './credential-store';
3
4
  import { type AgentProcessMetadata, type ProcessListEntry } from './process-scout';
4
5
  import { LocalStateStore } from './state';
5
6
  import { type VitalityPulseDependencies } from './vitality-pulse';
@@ -141,7 +142,7 @@ interface RemotePassportReconcileResult {
141
142
  }
142
143
  export interface TrainInitResult {
143
144
  buildSession: BuildSession;
144
- draftAction: 'draft_created' | 'draft_queued';
145
+ draftAction: 'bound' | 'draft_created' | 'draft_queued';
145
146
  draftId: string | null;
146
147
  gaid: string | null;
147
148
  payload: Record<string, unknown>;
@@ -262,11 +263,23 @@ export interface ConnectStatusOverview {
262
263
  export declare class ConnectV1Service {
263
264
  private readonly stateStore;
264
265
  private readonly credentialStore;
266
+ private smartInboxBackgroundRefreshInFlight;
265
267
  constructor(stateDir?: string, options?: {
266
268
  credentialBackend?: SecureCredentialBackend;
267
269
  legacyCredentialBackend?: SecureCredentialBackend | null;
268
270
  });
269
271
  getStateStore(): LocalStateStore;
272
+ private cloneInboxSnapshot;
273
+ private withInboxFreshness;
274
+ private persistSmartInboxSnapshot;
275
+ getSmartRegistrationInbox(options?: {
276
+ forceRefresh?: boolean;
277
+ preferSnapshot?: boolean;
278
+ maxSnapshotAgeMs?: number;
279
+ refreshInBackground?: boolean;
280
+ }): SmartRegistrationInbox;
281
+ refreshSmartRegistrationInboxInBackground(): void;
282
+ prewarmSmartRegistrationInbox(): Promise<void>;
270
283
  private getStoredSessionRef;
271
284
  private getEnvironmentSessionRef;
272
285
  private getActiveSessionRef;
@@ -325,6 +338,7 @@ export declare class ConnectV1Service {
325
338
  private buildStandardBindingConsentProfile;
326
339
  bindWorkspaceProject(workspaceId: string | null, projectId: string | null): Promise<ConnectBindingScopeSelectionResult>;
327
340
  getStatus(): StatusResult;
341
+ getCredentialStoreStatus(): ConnectCredentialStoreStatus;
328
342
  getConfig(): ConnectConfig;
329
343
  getServiceEntitlements(): ServiceEntitlements;
330
344
  private getApiClient;
@@ -389,6 +403,8 @@ export declare class ConnectV1Service {
389
403
  private buildModelVerificationSummary;
390
404
  private buildRuntimeVerificationSummary;
391
405
  private findConnectableModelForRuntime;
406
+ private hasExactBoundPassportForModel;
407
+ private runtimeHasExactBoundModelDuplicate;
392
408
  private clearModelReviewDeferral;
393
409
  private buildPassportMatchSuggestionForModel;
394
410
  private normalizeRemotePassportList;
@@ -402,8 +418,12 @@ export declare class ConnectV1Service {
402
418
  private findAgentModelCandidate;
403
419
  private getDefaultRuntimeSignalApiKey;
404
420
  private findBindingByGaid;
421
+ private findTrainingAnchorBinding;
422
+ private anchorBuildSessionToBinding;
423
+ private resolveRuntimeRunScope;
405
424
  private getPrimaryBoundBinding;
406
425
  private setRuntimeSignalApiKeyForGaid;
426
+ private clearRuntimeSignalApiKeyForGaid;
407
427
  private resolveRuntimeSignalApiKeyForEvent;
408
428
  /**
409
429
  * Promote local-only events (no passport_gaid) by assigning the given gaid.
@@ -488,6 +508,27 @@ export declare class ConnectV1Service {
488
508
  metadata?: Record<string, unknown>;
489
509
  }): C2LifecycleEvent;
490
510
  getC2Status(): C2StatusResult;
511
+ emitRuntimeRunLog(input: {
512
+ gaid: string;
513
+ apiKey?: string | null;
514
+ provider: string;
515
+ model: string;
516
+ serviceName: string;
517
+ serviceKind?: string | null;
518
+ runId?: string | null;
519
+ externalRunId?: string | null;
520
+ status?: string | null;
521
+ startedAt?: string | null;
522
+ endedAt?: string | null;
523
+ promptTokens?: number | undefined;
524
+ completionTokens?: number | undefined;
525
+ cachedPromptTokens?: number | undefined;
526
+ reasoningTokens?: number | undefined;
527
+ latencyMs?: number | undefined;
528
+ estimatedCostCents?: number | undefined;
529
+ currency?: string | null;
530
+ summary?: string | null;
531
+ }): Promise<ApiCallResult>;
491
532
  private findAgentByIdOrName;
492
533
  private findAgentLink;
493
534
  private findLinkedModelForAgent;
@@ -540,7 +581,9 @@ export declare class ConnectV1Service {
540
581
  getAgentStatus(): AgentStatusResult;
541
582
  getAgentModelUsageLedger(selector?: string): AgentModelUsageLedgerSummary;
542
583
  buildSmartRegistrationInbox(): SmartRegistrationInbox;
543
- getConnectStatusOverview(): ConnectStatusOverview;
584
+ getConnectStatusOverview(options?: {
585
+ includeInbox?: boolean;
586
+ }): ConnectStatusOverview;
544
587
  private resolveRecommendedNextAction;
545
588
  getTrayStatus(): TrayStatusResult;
546
589
  private getInboxDetailText;
@@ -552,6 +595,15 @@ export declare class ConnectV1Service {
552
595
  private getNotificationRuntimeLabel;
553
596
  private getNotificationSourceSummary;
554
597
  getNotificationCandidates(): NotificationCandidate[];
598
+ private getNotificationMetadataNumber;
599
+ private getMaxNotificationMetadataNumber;
600
+ private pluralizeNotificationNoun;
601
+ private buildConnectInboxReviewNotification;
602
+ private buildRuntimeAttentionNotification;
603
+ private buildGovernanceControlNotification;
604
+ private buildSyncAttentionNotification;
605
+ private getNotificationDeliveryCandidates;
606
+ getNotificationDeliveryPreview(candidates?: NotificationCandidate[]): NotificationCandidate[];
555
607
  private getNotificationTargetId;
556
608
  private wasNotificationRecentlyDelivered;
557
609
  private markNotificationDelivered;
@@ -669,9 +721,11 @@ export declare class ConnectV1Service {
669
721
  queueConfiguredHeartbeatRuntimeSignal(gaid: string | null): string | null;
670
722
  runDoctorChecks(): Promise<DoctorCheck[]>;
671
723
  markModelIgnored(modelName: string, digest: string): boolean;
724
+ ignoreDetectedModel(selector: string): boolean;
672
725
  deferDetectedModel(selector: string, deferHours?: number): boolean;
673
726
  markRuntimeIgnored(selector: string): boolean;
674
727
  deferRuntimeSuggestion(selector: string, deferHours?: number): boolean;
728
+ ignoreRuntimeSuggestion(selector: string): boolean;
675
729
  notImplemented(feature: string): never;
676
730
  ensureNoProductionPolicyBypass(): void;
677
731
  createEvidenceId(): string;