forkit-connect 0.1.7 → 0.1.9

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 CHANGED
@@ -1427,6 +1427,11 @@ function formatSmartInboxActionValue(action, itemType, connectableModelName) {
1427
1427
  }
1428
1428
  }
1429
1429
  function formatSmartInboxActionLabel(item) {
1430
+ if (item.item_type === 'model'
1431
+ && item.recommended_action === 'create_passport_draft'
1432
+ && String(item.details_received_automatically.registration_flow_state || '').trim() === 'private_draft_required') {
1433
+ return 'Open Draft Path';
1434
+ }
1430
1435
  return formatSmartInboxActionValue(item.recommended_action, item.item_type, String(item.details_received_automatically.connectable_model_name || '').trim());
1431
1436
  }
1432
1437
  function printInboxGroup(label, items) {
@@ -1463,6 +1468,7 @@ function printConnectStatusOverview(status) {
1463
1468
  paused_session_count: status.paused_session_count,
1464
1469
  revoked_session_count: status.revoked_session_count,
1465
1470
  credential_reconnect_needed: status.credential_reconnect_needed,
1471
+ draft_first_count: status.draft_first_count,
1466
1472
  ready_to_connect_count: status.ready_to_connect_count,
1467
1473
  needs_confirmation_count: status.needs_confirmation_count,
1468
1474
  connected_count: status.connected_count,
@@ -1473,12 +1479,13 @@ function printConnectStatusOverview(status) {
1473
1479
  }, null, 2));
1474
1480
  }
1475
1481
  function printPublicStatusOverview(status) {
1482
+ const otherReadyCount = Math.max(0, status.ready_to_connect_count - status.draft_first_count);
1476
1483
  console.log('[forkit-connect] Status');
1477
1484
  console.log(`- device=${status.device_paired ? 'paired' : 'approval pending'}`);
1478
1485
  console.log(`- scope=${status.workspace_id && status.project_id ? `${status.workspace_id} / ${status.project_id}` : 'not selected'}`);
1479
1486
  console.log(`- daemon=${status.daemon_status}`);
1480
1487
  console.log(`- local inventory=models ${status.models_discovered} · agents ${status.agents_discovered} · runtimes ${status.runtimes_discovered}`);
1481
- console.log(`- review queue=ready ${status.ready_to_connect_count} · needs review ${status.needs_confirmation_count}`);
1488
+ console.log(`- review queue=draft first ${status.draft_first_count} · ready ${otherReadyCount} · needs review ${status.needs_confirmation_count}`);
1482
1489
  console.log(`- connected records=${status.connected_count}`);
1483
1490
  console.log(`- pending runtime sync=${status.c2_sync_pending}`);
1484
1491
  console.log(`- privacy=${status.privacy_mode}`);
@@ -1747,8 +1754,11 @@ async function run() {
1747
1754
  preferSnapshot: true,
1748
1755
  refreshInBackground: false,
1749
1756
  });
1757
+ const draftFirstCount = inbox.groups.ready_to_connect.filter((item) => (item.item_type === 'model'
1758
+ && String(item.details_received_automatically.registration_flow_state || '').trim() === 'private_draft_required')).length;
1750
1759
  return {
1751
1760
  ...overview,
1761
+ draft_first_count: draftFirstCount,
1752
1762
  ready_to_connect_count: inbox.summary.ready_to_connect_count,
1753
1763
  needs_confirmation_count: inbox.summary.needs_confirmation_count,
1754
1764
  connected_count: inbox.summary.connected_count,
@@ -2070,6 +2080,7 @@ async function run() {
2070
2080
  ? 'Local workspace/project scope is cached on this device, but account login is required before governed actions can continue.'
2071
2081
  : 'Account login is required before governed workspace/project actions can continue.',
2072
2082
  daemon_status: overview.daemon_status,
2083
+ draft_first_count: overview.draft_first_count,
2073
2084
  ready_to_connect_count: overview.ready_to_connect_count,
2074
2085
  needs_confirmation_count: overview.needs_confirmation_count,
2075
2086
  connected_count: overview.connected_count,
@@ -2113,6 +2124,7 @@ async function run() {
2113
2124
  {
2114
2125
  title: 'Queue',
2115
2126
  lines: [
2127
+ shellLine('Draft-first review', payload.draft_first_count),
2116
2128
  shellLine('Ready to connect', payload.ready_to_connect_count),
2117
2129
  shellLine('Needs confirmation', payload.needs_confirmation_count),
2118
2130
  shellLine('Connected', payload.connected_count),
@@ -2850,6 +2862,8 @@ async function run() {
2850
2862
  const detailKeys = [
2851
2863
  'verification_summary',
2852
2864
  'limitations_summary',
2865
+ 'registration_guidance',
2866
+ 'registration_error_message',
2853
2867
  'scope_suggestion',
2854
2868
  'scope_mismatch_reason',
2855
2869
  'connectable_model_name',
package/dist/launcher.js CHANGED
@@ -676,6 +676,9 @@ function buildDiscovery(service) {
676
676
  const registeredPassportName = getInboxDetailText(entry, 'registered_passport_name');
677
677
  const scopeSuggestion = getInboxDetailText(entry, 'scope_suggestion');
678
678
  const verificationSummary = getInboxDetailText(entry, 'verification_summary');
679
+ const registrationState = getInboxDetailText(entry, 'registration_flow_state');
680
+ const registrationGuidance = getInboxDetailText(entry, 'registration_guidance')
681
+ ?? getInboxDetailText(entry, 'registration_error_message');
679
682
  const matchReason = entry.match_reason;
680
683
  const draftPending = binding?.status === 'pending';
681
684
  let statusLabel = 'Ready to register';
@@ -697,6 +700,13 @@ function buildDiscovery(service) {
697
700
  actionLabel = 'Review';
698
701
  actionTone = 'accent';
699
702
  }
703
+ else if (registrationState === 'private_draft_required') {
704
+ statusLabel = 'Draft first';
705
+ statusMeta = registrationGuidance ?? 'This model needs to go through the private draft path before publishing.';
706
+ statusTone = 'warn';
707
+ actionLabel = 'Review';
708
+ actionTone = 'accent';
709
+ }
700
710
  else if (group === 'connected') {
701
711
  statusLabel = 'Registered';
702
712
  statusMeta = registeredPassportName
@@ -902,6 +912,9 @@ function buildDiscovery(service) {
902
912
  const modelItems = items.filter((item) => item.kind === 'model');
903
913
  const agentItems = items.filter((item) => item.kind === 'agent');
904
914
  const runtimeItems = items.filter((item) => item.kind === 'runtime');
915
+ const draftFirstCount = inbox.groups.ready_to_connect.filter((item) => (item.item_type === 'model'
916
+ && String(item.details_received_automatically.registration_flow_state || '').trim() === 'private_draft_required')).length;
917
+ const otherReadyCount = Math.max(0, inbox.summary.ready_to_connect_count - draftFirstCount);
905
918
  return {
906
919
  ok: true,
907
920
  generatedAt: new Date().toISOString(),
@@ -916,7 +929,7 @@ function buildDiscovery(service) {
916
929
  localDetection: state.detected_runtimes.length > 0 || state.detected_models.length > 0 ? 'active' : 'attention',
917
930
  metadataExtraction: state.detected_models.length > 0 ? 'active' : 'attention',
918
931
  duplicateMatching: inbox.existing_passport_match_candidates.length > 0 || state.model_bindings.length > 0 ? 'active' : 'attention',
919
- passportReadiness: `${inbox.summary.ready_to_connect_count} ready · ${inbox.summary.needs_confirmation_count} review · ${inbox.summary.connected_count} linked`,
932
+ passportReadiness: `${draftFirstCount} draft-first · ${otherReadyCount} ready · ${inbox.summary.needs_confirmation_count} review · ${inbox.summary.connected_count} linked`,
920
933
  },
921
934
  groups: {
922
935
  ready_to_connect: inbox.groups.ready_to_connect.length,
@@ -253,6 +253,7 @@ export interface ConnectStatusOverview {
253
253
  paused_session_count: number;
254
254
  revoked_session_count: number;
255
255
  credential_reconnect_needed: boolean;
256
+ draft_first_count: number;
256
257
  ready_to_connect_count: number;
257
258
  needs_confirmation_count: number;
258
259
  connected_count: number;
@@ -408,6 +409,7 @@ export declare class ConnectV1Service {
408
409
  private hasExactBoundPassportForModel;
409
410
  private runtimeHasExactBoundModelDuplicate;
410
411
  private clearModelReviewDeferral;
412
+ private updateDetectedModelRegistrationHint;
411
413
  private buildPassportMatchSuggestionForModel;
412
414
  private normalizeRemotePassportList;
413
415
  private loadRemoteWorkspaceNameMaps;
@@ -2287,6 +2287,33 @@ class ConnectV1Service {
2287
2287
  : item);
2288
2288
  this.stateStore.replaceDetectedModels(nextModels);
2289
2289
  }
2290
+ updateDetectedModelRegistrationHint(model, input) {
2291
+ const nextModels = this.stateStore.readState().detected_models.map((item) => {
2292
+ if (item.discoveryHash !== model.discoveryHash) {
2293
+ return item;
2294
+ }
2295
+ const nextMetadata = {
2296
+ ...(item.metadata && typeof item.metadata === 'object' ? item.metadata : {}),
2297
+ };
2298
+ const assignOrDelete = (key, value) => {
2299
+ if (value === null || value === undefined || value === '') {
2300
+ delete nextMetadata[key];
2301
+ return;
2302
+ }
2303
+ nextMetadata[key] = value;
2304
+ };
2305
+ assignOrDelete('tracking_status', input.trackingStatus ?? null);
2306
+ assignOrDelete('registration_error_code', input.errorCode ?? null);
2307
+ assignOrDelete('registration_error_message', input.errorMessage ?? null);
2308
+ assignOrDelete('registration_error_status', typeof input.errorStatus === 'number' ? input.errorStatus : null);
2309
+ assignOrDelete('registration_guidance', input.guidance ?? null);
2310
+ return {
2311
+ ...item,
2312
+ metadata: nextMetadata,
2313
+ };
2314
+ });
2315
+ this.stateStore.replaceDetectedModels(nextModels);
2316
+ }
2290
2317
  buildPassportMatchSuggestionForModel(state, model, runtimePassport) {
2291
2318
  const registrationKey = (0, discovery_1.buildModelRegistrationKey)(model, state.runtime_identity.runtimeId);
2292
2319
  const candidates = state.model_bindings
@@ -4305,6 +4332,10 @@ class ConnectV1Service {
4305
4332
  const observedProjectId = normalizeDisplayText(modelMetadata.projectId ?? modelMetadata.project_id);
4306
4333
  const scopeSuggestion = this.resolveScopeSuggestion(refreshedState, observedWorkspaceId, observedProjectId);
4307
4334
  const itemId = this.buildInboxItemId('model', model.discoveryHash);
4335
+ const registrationTrackingStatus = normalizeDisplayText(modelMetadata.tracking_status);
4336
+ const registrationErrorMessage = normalizeDisplayText(modelMetadata.registration_error_message);
4337
+ const registrationErrorCode = normalizeDisplayText(modelMetadata.registration_error_code);
4338
+ const registrationGuidance = normalizeDisplayText(modelMetadata.registration_guidance);
4308
4339
  const recommendedAction = binding?.status === 'bound'
4309
4340
  ? 'open_on_forkit'
4310
4341
  : suggestion.match_confidence === 'medium'
@@ -4371,6 +4402,10 @@ class ConnectV1Service {
4371
4402
  registered_workspace_name: binding?.workspaceName ?? null,
4372
4403
  registered_project_name: binding?.projectName ?? null,
4373
4404
  remote_match_source: binding?.remoteMatchSource ?? null,
4405
+ registration_flow_state: registrationTrackingStatus,
4406
+ registration_error_message: registrationErrorMessage,
4407
+ registration_error_code: registrationErrorCode,
4408
+ registration_guidance: registrationGuidance,
4374
4409
  verification_summary: verification.verification,
4375
4410
  limitations_summary: verification.limitations,
4376
4411
  review_disposition: reviewDisposition,
@@ -4690,6 +4725,11 @@ class ConnectV1Service {
4690
4725
  const state = this.stateStore.readState();
4691
4726
  const includeInbox = options?.includeInbox !== false;
4692
4727
  const inbox = includeInbox ? this.buildSmartRegistrationInbox() : null;
4728
+ const draftFirstCount = inbox
4729
+ ? inbox.groups.ready_to_connect.filter((item) => (item.item_type === 'model'
4730
+ && String(item.details_received_automatically.registration_flow_state || '').trim() === 'private_draft_required')).length
4731
+ : state.detected_models.filter((item) => (item.status !== 'ignored'
4732
+ && String((item.metadata && typeof item.metadata === 'object' ? item.metadata : {}).tracking_status || '').trim() === 'private_draft_required')).length;
4693
4733
  const sessionSummary = this.getC2SessionSummary();
4694
4734
  const binding = this.getEffectiveBindingState(state);
4695
4735
  const bindingReconnectRequired = this.bindingRequiresReconnect(state);
@@ -4709,6 +4749,7 @@ class ConnectV1Service {
4709
4749
  paused_session_count: sessionSummary.paused_session_count,
4710
4750
  revoked_session_count: sessionSummary.revoked_session_count,
4711
4751
  credential_reconnect_needed: bindingReconnectRequired || sessionSummary.credential_reconnect_needed,
4752
+ draft_first_count: draftFirstCount,
4712
4753
  ready_to_connect_count: inbox?.summary.ready_to_connect_count ?? discoveredModels,
4713
4754
  needs_confirmation_count: inbox?.summary.needs_confirmation_count ?? 0,
4714
4755
  connected_count: inbox?.summary.connected_count ?? connectedCount,
@@ -7798,6 +7839,13 @@ class ConnectV1Service {
7798
7839
  ? 'public'
7799
7840
  : 'private';
7800
7841
  this.clearModelReviewDeferral(model);
7842
+ this.updateDetectedModelRegistrationHint(model, {
7843
+ trackingStatus: null,
7844
+ errorCode: null,
7845
+ errorMessage: null,
7846
+ errorStatus: null,
7847
+ guidance: null,
7848
+ });
7801
7849
  const { payload, registrationKey } = this.buildConnectDraftPayload(model, state, draftScope, {
7802
7850
  visibility: requestedVisibility,
7803
7851
  });
@@ -7939,6 +7987,16 @@ class ConnectV1Service {
7939
7987
  const api = this.getApiClient(state);
7940
7988
  const result = await api.createPassportDraft(payload);
7941
7989
  if (!result.ok) {
7990
+ const backendCode = extractApiErrorCode(result.body) || `DRAFT_CREATE_FAILED:${result.status}`;
7991
+ if (backendCode === 'INVALID_DRAFT_VISIBILITY') {
7992
+ this.updateDetectedModelRegistrationHint(model, {
7993
+ trackingStatus: 'private_draft_required',
7994
+ errorCode: backendCode,
7995
+ errorMessage: 'This registration must start as a private draft before it can be published.',
7996
+ errorStatus: result.status,
7997
+ guidance: 'Open the review flow and continue through the private draft path first.',
7998
+ });
7999
+ }
7942
8000
  this.observeBackendCommunicationState({
7943
8001
  passportGaid: bindingWithRuntime?.gaid ?? null,
7944
8002
  runtimeGaid: runtimePassport?.runtime_gaid ?? null,
@@ -7947,7 +8005,7 @@ class ConnectV1Service {
7947
8005
  body: result.body,
7948
8006
  source: 'draft_sync',
7949
8007
  });
7950
- throw new Error(result.status === 409 ? 'DRAFT_ALREADY_EXISTS' : (extractApiErrorCode(result.body) || `DRAFT_CREATE_FAILED:${result.status}`));
8008
+ throw new Error(result.status === 409 ? 'DRAFT_ALREADY_EXISTS' : backendCode);
7951
8009
  }
7952
8010
  const parsed = this.parseDraftResponse(result);
7953
8011
  let finalGaid = parsed.gaid;
package/dist/v1/state.js CHANGED
@@ -938,8 +938,30 @@ class LocalStateStore {
938
938
  const seen = new Map();
939
939
  for (const model of models) {
940
940
  const existing = state.detected_models.find((item) => item.discoveryHash === model.discoveryHash);
941
+ const nextMetadata = model.metadata && typeof model.metadata === 'object'
942
+ ? { ...model.metadata }
943
+ : {};
944
+ const existingMetadata = existing?.metadata && typeof existing.metadata === 'object'
945
+ ? existing.metadata
946
+ : null;
947
+ if (existingMetadata) {
948
+ for (const key of [
949
+ 'draft_id',
950
+ 'passport_gaid',
951
+ 'tracking_status',
952
+ 'registration_error_code',
953
+ 'registration_error_message',
954
+ 'registration_error_status',
955
+ 'registration_guidance',
956
+ ]) {
957
+ if (!Object.prototype.hasOwnProperty.call(nextMetadata, key) && Object.prototype.hasOwnProperty.call(existingMetadata, key)) {
958
+ nextMetadata[key] = existingMetadata[key];
959
+ }
960
+ }
961
+ }
941
962
  seen.set(model.discoveryHash, {
942
963
  ...model,
964
+ metadata: nextMetadata,
943
965
  status: model.status === 'ignored' || model.status === 'bound'
944
966
  ? model.status
945
967
  : existing?.status === 'ignored' || existing?.status === 'bound'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "forkit-connect",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "description": "Forkit Connect Local Engine - The Global AI Governance Fabric",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",