forkit-connect 0.1.6 → 0.1.8

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) {
@@ -2709,6 +2714,9 @@ async function run() {
2709
2714
  else if (message === 'SIMILAR_PASSPORT_EXISTS') {
2710
2715
  console.error('A similar or existing passport already exists in your Forkit.dev account. Open inbox and review the connected/passport match before creating a new draft.');
2711
2716
  }
2717
+ else if (message === 'INVALID_DRAFT_VISIBILITY') {
2718
+ console.error('This registration must start as a private draft. Review it in inbox/start first, or choose publish only when Forkit is ready to finish the passport.');
2719
+ }
2712
2720
  else if (message.startsWith('DRAFT_CREATE_FAILED:')) {
2713
2721
  console.error(`[forkit-connect] Draft creation failed (${message.split(':')[1]}).`);
2714
2722
  }
@@ -2847,6 +2855,8 @@ async function run() {
2847
2855
  const detailKeys = [
2848
2856
  'verification_summary',
2849
2857
  'limitations_summary',
2858
+ 'registration_guidance',
2859
+ 'registration_error_message',
2850
2860
  'scope_suggestion',
2851
2861
  'scope_mismatch_reason',
2852
2862
  'connectable_model_name',
@@ -3871,6 +3881,8 @@ async function run() {
3871
3881
  return 'A backend draft already exists for this model. No duplicate draft created.';
3872
3882
  if (raw === 'SIMILAR_PASSPORT_EXISTS')
3873
3883
  return 'A similar or existing passport already exists in your Forkit.dev account. Review existing records before creating a new draft.';
3884
+ if (raw === 'INVALID_DRAFT_VISIBILITY')
3885
+ return 'This registration must start as a private draft. Review it in inbox/start first, or choose publish only when Forkit is ready to finish the passport.';
3874
3886
  if (raw === 'WORKSPACE_PROJECT_BINDING_REQUIRED')
3875
3887
  return 'No governed workspace/project scope is linked yet. Select or create scope first.';
3876
3888
  if (raw === 'DRAFT_CREATION_NOT_ALLOWED_BY_BINDING')
@@ -4538,6 +4550,11 @@ async function run() {
4538
4550
  process.exitCode = 2;
4539
4551
  return;
4540
4552
  }
4553
+ if (message === 'INVALID_DRAFT_VISIBILITY') {
4554
+ console.error('This registration must start as a private draft. Review it in inbox/start first, or choose publish only when Forkit is ready to finish the passport.');
4555
+ process.exitCode = 2;
4556
+ return;
4557
+ }
4541
4558
  if (message.startsWith('DRAFT_CREATE_FAILED:')) {
4542
4559
  console.error(`[forkit-connect] Draft creation failed (${message.split(':')[1]}).`);
4543
4560
  process.exitCode = 2;
package/dist/launcher.js CHANGED
@@ -535,6 +535,16 @@ function normalizeDiscoveryRegistrationFailure(message) {
535
535
  message: 'A similar passport already exists in Forkit. Review existing records before creating a new one.',
536
536
  };
537
537
  }
538
+ if (normalized === 'INVALID_DRAFT_VISIBILITY') {
539
+ return {
540
+ code: normalized,
541
+ message: 'This registration needs to start as a private draft before it can be published.',
542
+ nextActions: [
543
+ 'Keep the item in review or open the draft path first.',
544
+ 'Choose publish only when Forkit is ready to finish the passport.',
545
+ ],
546
+ };
547
+ }
538
548
  if (normalized === 'WORKSPACE_PROJECT_BINDING_REQUIRED') {
539
549
  return {
540
550
  code: normalized,
@@ -666,6 +676,9 @@ function buildDiscovery(service) {
666
676
  const registeredPassportName = getInboxDetailText(entry, 'registered_passport_name');
667
677
  const scopeSuggestion = getInboxDetailText(entry, 'scope_suggestion');
668
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');
669
682
  const matchReason = entry.match_reason;
670
683
  const draftPending = binding?.status === 'pending';
671
684
  let statusLabel = 'Ready to register';
@@ -687,6 +700,13 @@ function buildDiscovery(service) {
687
700
  actionLabel = 'Review';
688
701
  actionTone = 'accent';
689
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
+ }
690
710
  else if (group === 'connected') {
691
711
  statusLabel = 'Registered';
692
712
  statusMeta = registeredPassportName
@@ -7581,9 +7601,11 @@ function renderLauncherHtml(launcherToken) {
7581
7601
  actionSummary: result && result.code === 'GOVERNED_PASSPORT_CAPACITY_REACHED'
7582
7602
  ? 'Capacity full · use an existing passport or free space'
7583
7603
  : result && result.code === 'DRAFT_LIMIT_REACHED'
7584
- ? 'Draft capacity full · use an existing passport, clear a draft, or upgrade'
7604
+ ? 'Draft capacity full · use an existing passport, clear a draft, or upgrade'
7585
7605
  : result && result.code === 'SIMILAR_PASSPORT_EXISTS'
7586
7606
  ? 'Matching passport exists · reuse it instead of creating another'
7607
+ : result && result.code === 'INVALID_DRAFT_VISIBILITY'
7608
+ ? 'Draft first · keep this registration private until it is ready to publish'
7587
7609
  : result && (result.code === 'WORKSPACE_PROJECT_BINDING_REQUIRED' || result.code === 'DRAFT_CREATION_NOT_ALLOWED_BY_BINDING')
7588
7610
  ? 'Scope required · choose workspace and project'
7589
7611
  : null,
@@ -408,6 +408,7 @@ export declare class ConnectV1Service {
408
408
  private hasExactBoundPassportForModel;
409
409
  private runtimeHasExactBoundModelDuplicate;
410
410
  private clearModelReviewDeferral;
411
+ private updateDetectedModelRegistrationHint;
411
412
  private buildPassportMatchSuggestionForModel;
412
413
  private normalizeRemotePassportList;
413
414
  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,
@@ -7793,8 +7828,18 @@ class ConnectV1Service {
7793
7828
  const soloDraftAllowed = draftBindingStatus.allowed && draftBindingStatus.reasonCode === 'solo_passport_draft_allowed';
7794
7829
  const localScopedDraftAllowed = draftBindingStatus.allowed && draftBindingStatus.reasonCode === 'local_workspace_project_draft_allowed';
7795
7830
  const model = this.resolveModelSelection(selector, state);
7796
- const requestedVisibility = options?.visibility === 'private' ? 'private' : 'public';
7831
+ const requestedDestination = options?.destination === 'passport' ? 'passport' : 'draft';
7832
+ const requestedVisibility = options?.visibility === 'public' && requestedDestination === 'passport'
7833
+ ? 'public'
7834
+ : 'private';
7797
7835
  this.clearModelReviewDeferral(model);
7836
+ this.updateDetectedModelRegistrationHint(model, {
7837
+ trackingStatus: null,
7838
+ errorCode: null,
7839
+ errorMessage: null,
7840
+ errorStatus: null,
7841
+ guidance: null,
7842
+ });
7798
7843
  const { payload, registrationKey } = this.buildConnectDraftPayload(model, state, draftScope, {
7799
7844
  visibility: requestedVisibility,
7800
7845
  });
@@ -7802,7 +7847,7 @@ class ConnectV1Service {
7802
7847
  const binding = this.findBindingForModel(this.stateStore.readState(), model, registrationKey);
7803
7848
  const pendingQueue = this.findPendingQueueItem(state, model, registrationKey);
7804
7849
  const shouldPublishImmediately = requestedVisibility === 'public'
7805
- && (options?.destination === 'passport' || (soloDraftAllowed && options?.destination !== 'draft'));
7850
+ && (requestedDestination === 'passport' || (soloDraftAllowed && requestedDestination !== 'draft'));
7806
7851
  const bindingWithRuntime = binding ? {
7807
7852
  ...binding,
7808
7853
  runtimeGaid: binding.runtimeGaid ?? runtimePassport?.runtime_gaid ?? null,
@@ -7936,6 +7981,16 @@ class ConnectV1Service {
7936
7981
  const api = this.getApiClient(state);
7937
7982
  const result = await api.createPassportDraft(payload);
7938
7983
  if (!result.ok) {
7984
+ const backendCode = extractApiErrorCode(result.body) || `DRAFT_CREATE_FAILED:${result.status}`;
7985
+ if (backendCode === 'INVALID_DRAFT_VISIBILITY') {
7986
+ this.updateDetectedModelRegistrationHint(model, {
7987
+ trackingStatus: 'private_draft_required',
7988
+ errorCode: backendCode,
7989
+ errorMessage: 'This registration must start as a private draft before it can be published.',
7990
+ errorStatus: result.status,
7991
+ guidance: 'Open the review flow and continue through the private draft path first.',
7992
+ });
7993
+ }
7939
7994
  this.observeBackendCommunicationState({
7940
7995
  passportGaid: bindingWithRuntime?.gaid ?? null,
7941
7996
  runtimeGaid: runtimePassport?.runtime_gaid ?? null,
@@ -7944,7 +7999,7 @@ class ConnectV1Service {
7944
7999
  body: result.body,
7945
8000
  source: 'draft_sync',
7946
8001
  });
7947
- throw new Error(result.status === 409 ? 'DRAFT_ALREADY_EXISTS' : (extractApiErrorCode(result.body) || `DRAFT_CREATE_FAILED:${result.status}`));
8002
+ throw new Error(result.status === 409 ? 'DRAFT_ALREADY_EXISTS' : backendCode);
7948
8003
  }
7949
8004
  const parsed = this.parseDraftResponse(result);
7950
8005
  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.6",
3
+ "version": "0.1.8",
4
4
  "description": "Forkit Connect Local Engine - The Global AI Governance Fabric",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",