@superblocksteam/vite-plugin-file-sync 2.0.140 → 2.0.141-next.0
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/ai-service/agent/prompts/build-base-system-prompt.js +1 -0
- package/dist/ai-service/agent/prompts/build-base-system-prompt.js.map +1 -1
- package/dist/ai-service/agent/tools/apis/api-testing-state.d.ts +1 -0
- package/dist/ai-service/agent/tools/apis/api-testing-state.d.ts.map +1 -1
- package/dist/ai-service/agent/tools/apis/api-testing-state.js +16 -0
- package/dist/ai-service/agent/tools/apis/api-testing-state.js.map +1 -1
- package/dist/ai-service/agent/tools/apis/get-api-docs.d.ts +1 -1
- package/dist/ai-service/agent/tools/apis/test-api.d.ts +1 -1
- package/dist/ai-service/agent/tools/apis/test-api.d.ts.map +1 -1
- package/dist/ai-service/agent/tools/apis/test-api.js +13 -7
- package/dist/ai-service/agent/tools/apis/test-api.js.map +1 -1
- package/dist/ai-service/agent/tools/build-copy-directory.d.ts +1 -1
- package/dist/ai-service/agent/tools/build-copy-file.d.ts +1 -1
- package/dist/ai-service/agent/tools/build-copy-utils.d.ts +8 -8
- package/dist/ai-service/agent/tools/build-delete-file.d.ts +1 -1
- package/dist/ai-service/agent/tools/build-finalize.d.ts.map +1 -1
- package/dist/ai-service/agent/tools/build-finalize.js +1 -2
- package/dist/ai-service/agent/tools/build-finalize.js.map +1 -1
- package/dist/ai-service/agent/tools/build-manage-checklist.d.ts +4 -4
- package/dist/ai-service/agent/tools/databases/dev-database-tasks.d.ts +4 -4
- package/dist/ai-service/agent/tools/get-logs.d.ts +3 -3
- package/dist/ai-service/agent/tools/integrations/execute-request.d.ts +9 -9
- package/dist/ai-service/agent/tools2/tools/end-test-run.d.ts +2 -2
- package/dist/ai-service/agent/tools2/tools/exit-plan-mode.d.ts.map +1 -1
- package/dist/ai-service/agent/tools2/tools/exit-plan-mode.js +93 -6
- package/dist/ai-service/agent/tools2/tools/exit-plan-mode.js.map +1 -1
- package/dist/ai-service/agent/tools2/tools/git.d.ts +1 -1
- package/dist/ai-service/agent/tools2/tools/grep-metadata.d.ts +1 -1
- package/dist/ai-service/agent/tools2/tools/grep.d.ts +1 -1
- package/dist/ai-service/agent/tools2/tools/list-attachments.d.ts +1 -1
- package/dist/ai-service/app-interface/npm-package-lookup.d.ts +3 -2
- package/dist/ai-service/app-interface/npm-package-lookup.d.ts.map +1 -1
- package/dist/ai-service/app-interface/npm-package-lookup.js +21 -13
- package/dist/ai-service/app-interface/npm-package-lookup.js.map +1 -1
- package/dist/ai-service/app-interface/shell.d.ts.map +1 -1
- package/dist/ai-service/app-interface/shell.js +119 -0
- package/dist/ai-service/app-interface/shell.js.map +1 -1
- package/dist/ai-service/checklist/api-migration-checklist-gate.js +1 -1
- package/dist/ai-service/checklist/api-migration-checklist-gate.js.map +1 -1
- package/dist/ai-service/features.d.ts +11 -0
- package/dist/ai-service/features.d.ts.map +1 -1
- package/dist/ai-service/features.js +24 -0
- package/dist/ai-service/features.js.map +1 -1
- package/dist/ai-service/index.d.ts +38 -4
- package/dist/ai-service/index.d.ts.map +1 -1
- package/dist/ai-service/index.js +210 -13
- package/dist/ai-service/index.js.map +1 -1
- package/dist/ai-service/llm/client.d.ts.map +1 -1
- package/dist/ai-service/llm/client.js +23 -0
- package/dist/ai-service/llm/client.js.map +1 -1
- package/dist/ai-service/llm/context-v2/context.d.ts +31 -2
- package/dist/ai-service/llm/context-v2/context.d.ts.map +1 -1
- package/dist/ai-service/llm/context-v2/context.js +81 -8
- package/dist/ai-service/llm/context-v2/context.js.map +1 -1
- package/dist/ai-service/llm/context-v2/turns.d.ts.map +1 -1
- package/dist/ai-service/llm/context-v2/turns.js +25 -1
- package/dist/ai-service/llm/context-v2/turns.js.map +1 -1
- package/dist/ai-service/llm/context-v2/types.d.ts +9 -0
- package/dist/ai-service/llm/context-v2/types.d.ts.map +1 -1
- package/dist/ai-service/llm/context-v2/types.js.map +1 -1
- package/dist/ai-service/llm/stream/config.d.ts +15 -0
- package/dist/ai-service/llm/stream/config.d.ts.map +1 -1
- package/dist/ai-service/llm/stream/config.js +9 -0
- package/dist/ai-service/llm/stream/config.js.map +1 -1
- package/dist/ai-service/llm/stream/errors.d.ts +1 -1
- package/dist/ai-service/llm/stream/errors.d.ts.map +1 -1
- package/dist/ai-service/llm/stream/errors.js.map +1 -1
- package/dist/ai-service/llm/stream/idle-monitor.d.ts +8 -0
- package/dist/ai-service/llm/stream/idle-monitor.d.ts.map +1 -1
- package/dist/ai-service/llm/stream/idle-monitor.js +51 -0
- package/dist/ai-service/llm/stream/idle-monitor.js.map +1 -1
- package/dist/ai-service/llm/stream/index.d.ts +1 -1
- package/dist/ai-service/llm/stream/index.d.ts.map +1 -1
- package/dist/ai-service/llm/stream/index.js.map +1 -1
- package/dist/ai-service/llm/stream/managed-stream.d.ts.map +1 -1
- package/dist/ai-service/llm/stream/managed-stream.js +2 -5
- package/dist/ai-service/llm/stream/managed-stream.js.map +1 -1
- package/dist/ai-service/llm/stream/orchestrator.d.ts +2 -0
- package/dist/ai-service/llm/stream/orchestrator.d.ts.map +1 -1
- package/dist/ai-service/llm/stream/orchestrator.js +67 -3
- package/dist/ai-service/llm/stream/orchestrator.js.map +1 -1
- package/dist/ai-service/llm/stream/structured-output-chunk.d.ts +16 -0
- package/dist/ai-service/llm/stream/structured-output-chunk.d.ts.map +1 -0
- package/dist/ai-service/llm/stream/structured-output-chunk.js +26 -0
- package/dist/ai-service/llm/stream/structured-output-chunk.js.map +1 -0
- package/dist/ai-service/migration-auto-dispatch-readiness.d.ts +18 -0
- package/dist/ai-service/migration-auto-dispatch-readiness.d.ts.map +1 -0
- package/dist/ai-service/migration-auto-dispatch-readiness.js +17 -0
- package/dist/ai-service/migration-auto-dispatch-readiness.js.map +1 -0
- package/dist/ai-service/migration-autodispatch-metrics.d.ts +3 -0
- package/dist/ai-service/migration-autodispatch-metrics.d.ts.map +1 -0
- package/dist/ai-service/migration-autodispatch-metrics.js +51 -0
- package/dist/ai-service/migration-autodispatch-metrics.js.map +1 -0
- package/dist/ai-service/migration-llm-config.d.ts +12 -0
- package/dist/ai-service/migration-llm-config.d.ts.map +1 -0
- package/dist/ai-service/migration-llm-config.js +130 -0
- package/dist/ai-service/migration-llm-config.js.map +1 -0
- package/dist/ai-service/migration-session-active.d.ts +14 -0
- package/dist/ai-service/migration-session-active.d.ts.map +1 -0
- package/dist/ai-service/migration-session-active.js +29 -0
- package/dist/ai-service/migration-session-active.js.map +1 -0
- package/dist/ai-service/resolve-generation-state-for-ui.d.ts +8 -0
- package/dist/ai-service/resolve-generation-state-for-ui.d.ts.map +1 -0
- package/dist/ai-service/resolve-generation-state-for-ui.js +25 -0
- package/dist/ai-service/resolve-generation-state-for-ui.js.map +1 -0
- package/dist/ai-service/skills/system/superblocks-migration/skill.generated.d.ts +1 -1
- package/dist/ai-service/skills/system/superblocks-migration/skill.generated.d.ts.map +1 -1
- package/dist/ai-service/skills/system/superblocks-migration/skill.generated.js +5 -1
- package/dist/ai-service/skills/system/superblocks-migration/skill.generated.js.map +1 -1
- package/dist/ai-service/state-machine/helpers/peer.d.ts +19 -1
- package/dist/ai-service/state-machine/helpers/peer.d.ts.map +1 -1
- package/dist/ai-service/state-machine/helpers/peer.js +81 -7
- package/dist/ai-service/state-machine/helpers/peer.js.map +1 -1
- package/dist/ai-service/state-machine/mocks.d.ts.map +1 -1
- package/dist/ai-service/state-machine/mocks.js +1 -0
- package/dist/ai-service/state-machine/mocks.js.map +1 -1
- package/dist/ai-service/types.d.ts +6 -0
- package/dist/ai-service/types.d.ts.map +1 -1
- package/dist/ai-service/types.js.map +1 -1
- package/dist/ai-service/util/inference-jwt.d.ts +15 -0
- package/dist/ai-service/util/inference-jwt.d.ts.map +1 -0
- package/dist/ai-service/util/inference-jwt.js +56 -0
- package/dist/ai-service/util/inference-jwt.js.map +1 -0
- package/dist/file-sync-vite-plugin.d.ts.map +1 -1
- package/dist/file-sync-vite-plugin.js +3 -6
- package/dist/file-sync-vite-plugin.js.map +1 -1
- package/dist/file-system-helpers.d.ts +14 -0
- package/dist/file-system-helpers.d.ts.map +1 -1
- package/dist/file-system-helpers.js +30 -0
- package/dist/file-system-helpers.js.map +1 -1
- package/dist/migration/integration-write-policy.d.ts +12 -0
- package/dist/migration/integration-write-policy.d.ts.map +1 -0
- package/dist/migration/integration-write-policy.js +31 -0
- package/dist/migration/integration-write-policy.js.map +1 -0
- package/dist/migration/migration-metrics.d.ts +69 -0
- package/dist/migration/migration-metrics.d.ts.map +1 -0
- package/dist/migration/migration-metrics.js +98 -0
- package/dist/migration/migration-metrics.js.map +1 -0
- package/dist/migration/migration-routes.d.ts.map +1 -1
- package/dist/migration/migration-routes.js +53 -121
- package/dist/migration/migration-routes.js.map +1 -1
- package/dist/migration/migration-verification.d.ts +49 -7
- package/dist/migration/migration-verification.d.ts.map +1 -1
- package/dist/migration/migration-verification.js +92 -28
- package/dist/migration/migration-verification.js.map +1 -1
- package/dist/migration/restructure.d.ts +10 -4
- package/dist/migration/restructure.d.ts.map +1 -1
- package/dist/migration/restructure.js +3 -2
- package/dist/migration/restructure.js.map +1 -1
- package/dist/server-rpc/client.d.ts.map +1 -1
- package/dist/server-rpc/client.js +11 -2
- package/dist/server-rpc/client.js.map +1 -1
- package/dist/socket-manager.d.ts.map +1 -1
- package/dist/socket-manager.js +5 -0
- package/dist/socket-manager.js.map +1 -1
- package/package.json +10 -10
package/dist/ai-service/index.js
CHANGED
|
@@ -30,7 +30,7 @@ import { AppSkillsManager } from "./app-skills/manager.js";
|
|
|
30
30
|
import { isUploadedAttachment, toUploadedAttachmentContentPart, } from "./attachments/uploaded-content-part.js";
|
|
31
31
|
import { ChatSessionStore } from "./chat/chat-session-store.js";
|
|
32
32
|
import { normalizeTextAttachmentForModel } from "./chat/utils.js";
|
|
33
|
-
import { API_MIGRATION_ORIGINS, readPersistedChecklist, updateChecklistItem, } from "./checklist/persisted-checklist-store.js";
|
|
33
|
+
import { API_MIGRATION_ORIGINS, isApiMigrationOrigin, readPersistedChecklist, updateChecklistItem, } from "./checklist/persisted-checklist-store.js";
|
|
34
34
|
import { downloadContextFromBucketeer, downloadLatestContextFromBucketeer, restoreContextFromCheckpoint, } from "./context-download.js";
|
|
35
35
|
import { uploadContextToBucketeer } from "./context-upload.js";
|
|
36
36
|
import { AppContextStore } from "./context/app-context.js";
|
|
@@ -53,12 +53,17 @@ import { traceLLM } from "./llmobs/helpers.js";
|
|
|
53
53
|
import { getJwtTraceTags } from "./llmobs/helpers.js";
|
|
54
54
|
import llmobs from "./llmobs/index.js";
|
|
55
55
|
import { PlaywrightMcpServerManager } from "./mcp/playwright-server.js";
|
|
56
|
+
import { evaluateMigrationAutoDispatchReadiness } from "./migration-auto-dispatch-readiness.js";
|
|
57
|
+
import { recordMigrationAutoDispatchOutcome } from "./migration-autodispatch-metrics.js";
|
|
58
|
+
import { buildServerMigrationLlmConfig, isMigrationAutoDispatchEnabled, } from "./migration-llm-config.js";
|
|
59
|
+
import { isMigrationSessionActive } from "./migration-session-active.js";
|
|
56
60
|
import { policyGateStreamPartToAgentStep } from "./policy-gate-step.js";
|
|
57
61
|
import { ClarkProfiler } from "./profiler/clark-profiler.js";
|
|
58
62
|
import { buildSummarizeApiUsagePrompt } from "./prompts/summarize-api-usage.js";
|
|
59
63
|
import { checkAiQuota } from "./quota-client.js";
|
|
60
64
|
import { RecordingManager, createRecordingFetch } from "./recording/index.js";
|
|
61
65
|
import { RequestDeduplicator } from "./request-deduplicator.js";
|
|
66
|
+
import { resolveGenerationStateForUi } from "./resolve-generation-state-for-ui.js";
|
|
62
67
|
import { scanContentForSecrets } from "./security/secret-scanner-service.js";
|
|
63
68
|
import { SecretRedactor } from "./security/secret-scanner.js";
|
|
64
69
|
import { ClarkStateNames, Clark, SERVICE_STARTED_WITH_DRAFT, USER_ACCEPTED_DRAFT, USER_REJECTED_DRAFT, USER_SENT_PROMPT, USER_CANCELED, AGENT_CANCELED, } from "./state-machine/clark-fsm.js";
|
|
@@ -78,10 +83,22 @@ import { catchBackgroundPeerDisconnect, StablePeer, } from "./state-machine/help
|
|
|
78
83
|
import { transitionFrom } from "./state-machine/helpers/transition.js";
|
|
79
84
|
import { isTaskAccessibleTo, registerBackgroundTaskTypes, resyncActiveTaskStatusesToPeer, TaskStore, wireTaskStatusPushToPeer, } from "./tasks/index.js";
|
|
80
85
|
import { TemplateRenderer } from "./template-renderer.js";
|
|
86
|
+
import { describeMigrationInferenceJwt, isUsableMigrationInferenceJwt, } from "./util/inference-jwt.js";
|
|
81
87
|
import { processLLMConfig } from "./util/llm-config-utils.js";
|
|
82
88
|
import { parseJwt } from "./util/parse-jwt.js";
|
|
83
89
|
import { getToolCallSignature } from "./util/tool-signature.js";
|
|
84
90
|
export { AiServiceFeatureFlags } from "./features.js";
|
|
91
|
+
function streamRetryOptionsFromConfig(retryOptions, streamTimeoutBudgets) {
|
|
92
|
+
if (streamTimeoutBudgets === undefined ||
|
|
93
|
+
Object.keys(streamTimeoutBudgets).length === 0) {
|
|
94
|
+
return retryOptions;
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
...retryOptions,
|
|
98
|
+
streamTimeoutBudgets,
|
|
99
|
+
timeoutSource: "feature-flag",
|
|
100
|
+
};
|
|
101
|
+
}
|
|
85
102
|
export { stripResolvedFromLockfile } from "./app-interface/npm-registry.js";
|
|
86
103
|
export { SnapshotManager } from "./recording/index.js";
|
|
87
104
|
export { isSdkApiTemplate } from "./sdk-api-templates.js";
|
|
@@ -357,6 +374,9 @@ export class AiService extends TracedEventEmitter {
|
|
|
357
374
|
try {
|
|
358
375
|
this.tokenManagerJwt = event.token;
|
|
359
376
|
this.getLogger().info(`[ai-service] token updated via tokenManager`);
|
|
377
|
+
if (event.token && isUsableMigrationInferenceJwt(event.token)) {
|
|
378
|
+
this.updateClarkJwt(event.token);
|
|
379
|
+
}
|
|
360
380
|
}
|
|
361
381
|
catch (err) {
|
|
362
382
|
console.error("[ai-service] tokenUpdated listener threw", err);
|
|
@@ -456,9 +476,16 @@ export class AiService extends TracedEventEmitter {
|
|
|
456
476
|
* Updates the JWT in Clark context
|
|
457
477
|
*/
|
|
458
478
|
updateClarkJwt(jwt) {
|
|
459
|
-
|
|
460
|
-
|
|
479
|
+
const jwtDetails = describeMigrationInferenceJwt(jwt);
|
|
480
|
+
if (!jwt || !jwtDetails.usable) {
|
|
481
|
+
return;
|
|
461
482
|
}
|
|
483
|
+
this.clark.updateContext({ jwt });
|
|
484
|
+
const llmConfig = this.lastMigrationTurnCredentials?.llmConfig ??
|
|
485
|
+
this.clark.context.llmConfig ??
|
|
486
|
+
buildServerMigrationLlmConfig(this.config.flagBootstrap);
|
|
487
|
+
this.storeMigrationTurnCredentials(jwt, llmConfig);
|
|
488
|
+
this.tryAutoDispatchMigrationTurnIfReady();
|
|
462
489
|
}
|
|
463
490
|
// ===== Recording API =====
|
|
464
491
|
/**
|
|
@@ -771,7 +798,7 @@ export class AiService extends TracedEventEmitter {
|
|
|
771
798
|
this.llmClient = new LLMClient({
|
|
772
799
|
contextManagerV2: this.contextManagerV2,
|
|
773
800
|
appShell: this.appShell,
|
|
774
|
-
retryOptions: config.retryOptions,
|
|
801
|
+
retryOptions: streamRetryOptionsFromConfig(config.retryOptions, config.features.streamTimeoutBudgets),
|
|
775
802
|
unifiedProviderEnabled: config.features.unifiedProviderEnabled ?? false,
|
|
776
803
|
organizationId: config.organizationId,
|
|
777
804
|
applicationId: config.applicationId,
|
|
@@ -916,6 +943,142 @@ export class AiService extends TracedEventEmitter {
|
|
|
916
943
|
},
|
|
917
944
|
});
|
|
918
945
|
}
|
|
946
|
+
this.tryAutoDispatchMigrationTurnIfReady();
|
|
947
|
+
}
|
|
948
|
+
migrationAppArtifactsReady = false;
|
|
949
|
+
migrationAutoDispatchPending = false;
|
|
950
|
+
migrationAutoDispatchInFlight = false;
|
|
951
|
+
lastMigrationTurnCredentials;
|
|
952
|
+
hasInitialPendingMigrationWork(items) {
|
|
953
|
+
const pendingItems = items.filter((item) => isApiMigrationOrigin(item.origin) &&
|
|
954
|
+
(item.status === "pending" || item.status === "in_progress"));
|
|
955
|
+
if (pendingItems.length === 0) {
|
|
956
|
+
return false;
|
|
957
|
+
}
|
|
958
|
+
return !pendingItems.some((item) => item.lastFailureReason);
|
|
959
|
+
}
|
|
960
|
+
resolveMigrationTurnCredentials() {
|
|
961
|
+
const cachedJwt = this.lastMigrationTurnCredentials?.jwt;
|
|
962
|
+
const inferenceJwt = this.getInferenceJwt();
|
|
963
|
+
const jwt = (cachedJwt && isUsableMigrationInferenceJwt(cachedJwt)
|
|
964
|
+
? cachedJwt
|
|
965
|
+
: undefined) ??
|
|
966
|
+
(inferenceJwt && isUsableMigrationInferenceJwt(inferenceJwt)
|
|
967
|
+
? inferenceJwt
|
|
968
|
+
: undefined);
|
|
969
|
+
const llmConfig = this.lastMigrationTurnCredentials?.llmConfig ??
|
|
970
|
+
this.clark.context.llmConfig ??
|
|
971
|
+
buildServerMigrationLlmConfig(this.config.flagBootstrap);
|
|
972
|
+
return { jwt, llmConfig };
|
|
973
|
+
}
|
|
974
|
+
storeMigrationTurnCredentials(jwt, llmConfig) {
|
|
975
|
+
const nextJwt = jwt && jwt.length > 0 ? jwt : this.lastMigrationTurnCredentials?.jwt;
|
|
976
|
+
this.lastMigrationTurnCredentials = {
|
|
977
|
+
...(nextJwt ? { jwt: nextJwt } : {}),
|
|
978
|
+
llmConfig,
|
|
979
|
+
};
|
|
980
|
+
if (jwt && jwt.length > 0 && !this.getInferenceJwt()) {
|
|
981
|
+
this.clark.updateContext({ jwt });
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
isRetriableMigrationAutoDispatchFailure(reason) {
|
|
985
|
+
if (!reason) {
|
|
986
|
+
return false;
|
|
987
|
+
}
|
|
988
|
+
return (reason.startsWith("busy:") ||
|
|
989
|
+
reason === "pending-tool-permission" ||
|
|
990
|
+
reason === "awaiting-interactive-response");
|
|
991
|
+
}
|
|
992
|
+
/**
|
|
993
|
+
* Called by dev startup once DBFS download (or upload-first local tree)
|
|
994
|
+
* has finished so migration scratch/checklist files are on disk.
|
|
995
|
+
*/
|
|
996
|
+
notifyMigrationAppArtifactsReady() {
|
|
997
|
+
if (this.migrationAppArtifactsReady) {
|
|
998
|
+
return;
|
|
999
|
+
}
|
|
1000
|
+
this.migrationAppArtifactsReady = true;
|
|
1001
|
+
this.tryAutoDispatchMigrationTurnIfReady();
|
|
1002
|
+
}
|
|
1003
|
+
tryAutoDispatchMigrationTurnIfReady() {
|
|
1004
|
+
if (this.migrationAutoDispatchInFlight) {
|
|
1005
|
+
return;
|
|
1006
|
+
}
|
|
1007
|
+
if (!isMigrationAutoDispatchEnabled(this.config.flagBootstrap)) {
|
|
1008
|
+
return;
|
|
1009
|
+
}
|
|
1010
|
+
const { jwt } = this.resolveMigrationTurnCredentials();
|
|
1011
|
+
const readiness = evaluateMigrationAutoDispatchReadiness({
|
|
1012
|
+
appArtifactsReady: this.migrationAppArtifactsReady,
|
|
1013
|
+
hasConnectedPeer: this.hasConnectedPeer(),
|
|
1014
|
+
hasUsableJwt: Boolean(jwt),
|
|
1015
|
+
});
|
|
1016
|
+
if (!readiness.ready) {
|
|
1017
|
+
if (readiness.reason === "jwt-unavailable") {
|
|
1018
|
+
this.migrationAutoDispatchPending = true;
|
|
1019
|
+
}
|
|
1020
|
+
return;
|
|
1021
|
+
}
|
|
1022
|
+
void this.maybeAutoDispatchMigrationTurn().catch((error) => {
|
|
1023
|
+
this.getLogger().error("[ai-service] Migration auto-dispatch failed", getErrorMeta(error));
|
|
1024
|
+
});
|
|
1025
|
+
}
|
|
1026
|
+
/**
|
|
1027
|
+
* Attempts to start the initial post-flip migration turn without UI
|
|
1028
|
+
* involvement. Skips user-initiated focused-debug retries (items with
|
|
1029
|
+
* `lastFailureReason`) and defers when JWT is unavailable.
|
|
1030
|
+
*/
|
|
1031
|
+
async maybeAutoDispatchMigrationTurn() {
|
|
1032
|
+
if (this.migrationAutoDispatchInFlight) {
|
|
1033
|
+
return;
|
|
1034
|
+
}
|
|
1035
|
+
this.migrationAutoDispatchInFlight = true;
|
|
1036
|
+
try {
|
|
1037
|
+
// Positive migration-session gate. Only auto-dispatch while a migration
|
|
1038
|
+
// session is genuinely in flight on disk (scratch/migration-state.json).
|
|
1039
|
+
// Completion and abort both remove it, so a stale checklist on a
|
|
1040
|
+
// never-migrated or already-finished app can never arm auto-dispatch
|
|
1041
|
+
// during normal usage — bounding the blast radius to migrations.
|
|
1042
|
+
if (!(await isMigrationSessionActive(this.appRootDirPath))) {
|
|
1043
|
+
this.migrationAutoDispatchPending = false;
|
|
1044
|
+
return;
|
|
1045
|
+
}
|
|
1046
|
+
const checklist = await readPersistedChecklist(this.appRootDirPath);
|
|
1047
|
+
if (!checklist) {
|
|
1048
|
+
this.migrationAutoDispatchPending = false;
|
|
1049
|
+
return;
|
|
1050
|
+
}
|
|
1051
|
+
if (!this.hasInitialPendingMigrationWork(checklist.items)) {
|
|
1052
|
+
this.migrationAutoDispatchPending = false;
|
|
1053
|
+
return;
|
|
1054
|
+
}
|
|
1055
|
+
const { jwt, llmConfig } = this.resolveMigrationTurnCredentials();
|
|
1056
|
+
if (!jwt) {
|
|
1057
|
+
this.migrationAutoDispatchPending = true;
|
|
1058
|
+
return;
|
|
1059
|
+
}
|
|
1060
|
+
const result = await this.handleAiTriggerMigrationTurn({
|
|
1061
|
+
jwt,
|
|
1062
|
+
llmConfig,
|
|
1063
|
+
triggeredBy: "auto-dispatch",
|
|
1064
|
+
});
|
|
1065
|
+
if (result.dispatched) {
|
|
1066
|
+
this.migrationAutoDispatchPending = false;
|
|
1067
|
+
this.getLogger().info("[ai-service] Auto-dispatched post-flip migration turn");
|
|
1068
|
+
}
|
|
1069
|
+
else if (result.reason === "already-triggered") {
|
|
1070
|
+
this.migrationAutoDispatchPending = false;
|
|
1071
|
+
}
|
|
1072
|
+
else if (this.isRetriableMigrationAutoDispatchFailure(result.reason)) {
|
|
1073
|
+
this.migrationAutoDispatchPending = true;
|
|
1074
|
+
}
|
|
1075
|
+
else {
|
|
1076
|
+
this.migrationAutoDispatchPending = false;
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
finally {
|
|
1080
|
+
this.migrationAutoDispatchInFlight = false;
|
|
1081
|
+
}
|
|
919
1082
|
}
|
|
920
1083
|
/**
|
|
921
1084
|
* Remove the integration metadata cache for this session.
|
|
@@ -1317,12 +1480,22 @@ export class AiService extends TracedEventEmitter {
|
|
|
1317
1480
|
* per ai-service lifetime. The disk checklist is the recovery source of
|
|
1318
1481
|
* truth across process restarts.
|
|
1319
1482
|
*
|
|
1320
|
-
*
|
|
1321
|
-
*
|
|
1322
|
-
*
|
|
1323
|
-
*
|
|
1483
|
+
* Primary auto-trigger: readiness gate (`notifyMigrationAppArtifactsReady`,
|
|
1484
|
+
* `handleUserConnected`, `updateClarkJwt`) →
|
|
1485
|
+
* `tryAutoDispatchMigrationTurnIfReady` → `maybeAutoDispatchMigrationTurn`.
|
|
1486
|
+
* Backup caller: the UI RPC (see v1.ai.triggerMigrationTurn) once it
|
|
1487
|
+
* observes the post-flip state via /sb-migration-status.
|
|
1488
|
+
* User retry after unresolved failures: UI RPC with
|
|
1489
|
+
* `retryMode: "focused-debug"` after /sb-migration-retry-unresolved.
|
|
1324
1490
|
*/
|
|
1325
1491
|
async handleAiTriggerMigrationTurn(request) {
|
|
1492
|
+
this.storeMigrationTurnCredentials(request.jwt, request.llmConfig);
|
|
1493
|
+
const isAutoDispatch = request.triggeredBy === "auto-dispatch";
|
|
1494
|
+
const recordAutoDispatchOutcome = (reason) => {
|
|
1495
|
+
if (isAutoDispatch) {
|
|
1496
|
+
recordMigrationAutoDispatchOutcome(reason);
|
|
1497
|
+
}
|
|
1498
|
+
};
|
|
1326
1499
|
// User-initiated "Fix with Clark" retries bypass the one-shot
|
|
1327
1500
|
// guard. The HTTP route that flips the items has already landed,
|
|
1328
1501
|
// so if we refused here the user would be stuck.
|
|
@@ -1330,33 +1503,44 @@ export class AiService extends TracedEventEmitter {
|
|
|
1330
1503
|
this.migrationTurnTriggered = false;
|
|
1331
1504
|
}
|
|
1332
1505
|
if (this.migrationTurnTriggered) {
|
|
1506
|
+
recordAutoDispatchOutcome("already-triggered");
|
|
1333
1507
|
return { dispatched: false, reason: "already-triggered" };
|
|
1334
1508
|
}
|
|
1335
1509
|
if (this.clark.state === ClarkStateNames.Dead) {
|
|
1510
|
+
recordAutoDispatchOutcome("dead");
|
|
1336
1511
|
return { dispatched: false, reason: "dead" };
|
|
1337
1512
|
}
|
|
1338
1513
|
if (this.clark.state !== ClarkStateNames.Idle &&
|
|
1339
1514
|
this.clark.state !== ClarkStateNames.AwaitingUser) {
|
|
1340
|
-
|
|
1515
|
+
const reason = `busy:${this.clark.state}`;
|
|
1516
|
+
recordAutoDispatchOutcome(reason);
|
|
1517
|
+
return { dispatched: false, reason };
|
|
1341
1518
|
}
|
|
1342
1519
|
if (this.clark.context.pendingToolPermissionRequest) {
|
|
1520
|
+
recordAutoDispatchOutcome("pending-tool-permission");
|
|
1343
1521
|
return { dispatched: false, reason: "pending-tool-permission" };
|
|
1344
1522
|
}
|
|
1345
1523
|
if (this.clark.state === ClarkStateNames.AwaitingUser) {
|
|
1346
1524
|
if (this.clark.context.activeInteractiveMessage ||
|
|
1347
1525
|
this.clark.context.deferredInteractiveMessage) {
|
|
1526
|
+
recordAutoDispatchOutcome("awaiting-interactive-response");
|
|
1348
1527
|
return { dispatched: false, reason: "awaiting-interactive-response" };
|
|
1349
1528
|
}
|
|
1350
1529
|
}
|
|
1530
|
+
this.migrationTurnTriggered = true;
|
|
1351
1531
|
const checklist = await readPersistedChecklist(this.appRootDirPath);
|
|
1352
1532
|
if (!checklist) {
|
|
1533
|
+
this.migrationTurnTriggered = false;
|
|
1353
1534
|
this.getLogger().warn("[ai-service] Migration checklist not found or unreadable; skipping translation turn");
|
|
1535
|
+
recordAutoDispatchOutcome("checklist-unavailable");
|
|
1354
1536
|
return { dispatched: false, reason: "checklist-unavailable" };
|
|
1355
1537
|
}
|
|
1356
1538
|
const pendingSeedApiItems = checklist.items.filter((item) => API_MIGRATION_ORIGINS.has(item.origin) &&
|
|
1357
1539
|
(item.status === "pending" || item.status === "in_progress"));
|
|
1358
1540
|
const pendingSeedApiCount = pendingSeedApiItems.length;
|
|
1359
1541
|
if (pendingSeedApiCount === 0) {
|
|
1542
|
+
this.migrationTurnTriggered = false;
|
|
1543
|
+
recordAutoDispatchOutcome("no-pending-items");
|
|
1360
1544
|
return { dispatched: false, reason: "no-pending-items" };
|
|
1361
1545
|
}
|
|
1362
1546
|
// Pre-flight quota gate. The migration turn drives LLM inference (which
|
|
@@ -1368,10 +1552,11 @@ export class AiService extends TracedEventEmitter {
|
|
|
1368
1552
|
// same pre-flight check handleAiGenerate already runs.
|
|
1369
1553
|
const quota = await this.checkAiQuota(request.jwt);
|
|
1370
1554
|
if (!quota.allowed) {
|
|
1555
|
+
this.migrationTurnTriggered = false;
|
|
1371
1556
|
this.getLogger().warn("[ai-service] Skipping v2→v3 migration turn — AI quota exceeded", { reason: quota.reason });
|
|
1557
|
+
recordAutoDispatchOutcome("quota-exceeded");
|
|
1372
1558
|
return { dispatched: false, reason: "quota-exceeded" };
|
|
1373
1559
|
}
|
|
1374
|
-
this.migrationTurnTriggered = true;
|
|
1375
1560
|
this.appShell.setApiHandlerEnabled(false);
|
|
1376
1561
|
this.getLogger().info(`[ai-service] Dispatching internal v2→v3 migration turn for ${pendingSeedApiCount} API(s) (API VFS projection disabled, retryMode=${request.retryMode ?? "none"})`);
|
|
1377
1562
|
const prompt = buildTranslationPrompt({
|
|
@@ -1393,6 +1578,8 @@ export class AiService extends TracedEventEmitter {
|
|
|
1393
1578
|
origin: "app_migration",
|
|
1394
1579
|
pendingSeedApiCount,
|
|
1395
1580
|
retryMode: request.retryMode ?? "none",
|
|
1581
|
+
triggeredBy: request.triggeredBy ??
|
|
1582
|
+
(request.retryMode === "focused-debug" ? "focused-debug" : "ui-rpc"),
|
|
1396
1583
|
};
|
|
1397
1584
|
this.clark.updateContext((context) => ({
|
|
1398
1585
|
...context,
|
|
@@ -1419,6 +1606,7 @@ export class AiService extends TracedEventEmitter {
|
|
|
1419
1606
|
this.migrationTurnTriggered = false;
|
|
1420
1607
|
this.appShell.setApiHandlerEnabled(true);
|
|
1421
1608
|
});
|
|
1609
|
+
recordAutoDispatchOutcome("dispatched");
|
|
1422
1610
|
return { dispatched: true };
|
|
1423
1611
|
}
|
|
1424
1612
|
getMigrationSafeLlmConfig(llmConfig) {
|
|
@@ -1737,6 +1925,7 @@ export class AiService extends TracedEventEmitter {
|
|
|
1737
1925
|
}
|
|
1738
1926
|
async handleAiGenerate(request) {
|
|
1739
1927
|
this.getLogger().info(`[ai-service] handleAiGenerate: peerId=${this.stablePeer.peerId ?? "unknown"}`);
|
|
1928
|
+
this.storeMigrationTurnCredentials(request.jwt, request.llmConfig);
|
|
1740
1929
|
if (this.clark.state === ClarkStateNames.Dead) {
|
|
1741
1930
|
recordPromptEntryRejection({
|
|
1742
1931
|
dedupeKey: resolvePromptRequestDedupeKey(request),
|
|
@@ -2895,6 +3084,12 @@ export class AiService extends TracedEventEmitter {
|
|
|
2895
3084
|
}
|
|
2896
3085
|
return `Continue with the task using alternative approaches. The tool ${toolName} was denied permission.`;
|
|
2897
3086
|
}
|
|
3087
|
+
resolveGenerationStateForUi() {
|
|
3088
|
+
return resolveGenerationStateForUi({
|
|
3089
|
+
clarkState: this.clark.state,
|
|
3090
|
+
lastGenerationState: this.clark.context.lastGenerationState,
|
|
3091
|
+
});
|
|
3092
|
+
}
|
|
2898
3093
|
handleUserConnected(peer, peerId) {
|
|
2899
3094
|
const existingPeerId = this.stablePeer.peerId;
|
|
2900
3095
|
this.getLogger().info(`[ai-service] handleUserConnected: peerId=${peerId}`);
|
|
@@ -2926,9 +3121,10 @@ export class AiService extends TracedEventEmitter {
|
|
|
2926
3121
|
this.authenticatedPeerUserId = undefined;
|
|
2927
3122
|
}
|
|
2928
3123
|
// 1. Sync generation state if generation is in progress
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
3124
|
+
const generationState = this.resolveGenerationStateForUi();
|
|
3125
|
+
if (generationState) {
|
|
3126
|
+
this.getLogger().info(`[ai-service] Syncing generation state on reconnect: ${generationState.state}`);
|
|
3127
|
+
catchBackgroundPeerDisconnect(peer.call.aiSetGenerationState(generationState), "generation state reconnect push");
|
|
2932
3128
|
}
|
|
2933
3129
|
// 2. Sync tool permission state with the UI
|
|
2934
3130
|
if (this.clark.context.pendingToolPermissionRequest) {
|
|
@@ -2979,6 +3175,7 @@ export class AiService extends TracedEventEmitter {
|
|
|
2979
3175
|
if (this.taskStore) {
|
|
2980
3176
|
this.pendingTaskResyncPeerIds.add(peerId);
|
|
2981
3177
|
}
|
|
3178
|
+
this.tryAutoDispatchMigrationTurnIfReady();
|
|
2982
3179
|
}
|
|
2983
3180
|
/**
|
|
2984
3181
|
* Per-session set of peer IDs that connected since their last task
|