@kbediako/codex-orchestrator 0.1.38 → 0.2.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/.agents/plugins/marketplace.json +20 -0
- package/README.md +70 -301
- package/bin/codex-orchestrator.js +161 -0
- package/codex.orchestrator.json +149 -13
- package/dist/bin/codex-orchestrator.js +795 -1154
- package/dist/orchestrator/src/cli/adapters/CommandPlanner.js +22 -4
- package/dist/orchestrator/src/cli/adapters/CommandReviewer.js +3 -3
- package/dist/orchestrator/src/cli/adapters/CommandTester.js +2 -2
- package/dist/orchestrator/src/cli/adapters/cloudFailureDiagnostics.js +183 -11
- package/dist/orchestrator/src/cli/coStatusAttachCliShell.js +402 -0
- package/dist/orchestrator/src/cli/coStatusCliShell.js +429 -0
- package/dist/orchestrator/src/cli/coStatusOperatorAutopilotCliShell.js +120 -0
- package/dist/orchestrator/src/cli/codexCliShell.js +72 -0
- package/dist/orchestrator/src/cli/codexDefaultsSetup.js +49 -11
- package/dist/orchestrator/src/cli/config/delegationConfig.js +317 -5
- package/dist/orchestrator/src/cli/config/repoConfigPolicy.js +2 -3
- package/dist/orchestrator/src/cli/config/userConfig.js +28 -13
- package/dist/orchestrator/src/cli/control/authenticatedControlRouteGate.js +69 -0
- package/dist/orchestrator/src/cli/control/authenticatedRouteComposition.js +267 -0
- package/dist/orchestrator/src/cli/control/authenticatedRouteController.js +5 -0
- package/dist/orchestrator/src/cli/control/authenticatedRouteDispatcher.js +41 -0
- package/dist/orchestrator/src/cli/control/compatibilityIssuePresenter.js +1035 -0
- package/dist/orchestrator/src/cli/control/confirmationApproveController.js +62 -0
- package/dist/orchestrator/src/cli/control/confirmationCreateController.js +69 -0
- package/dist/orchestrator/src/cli/control/confirmationIssueConsumeController.js +43 -0
- package/dist/orchestrator/src/cli/control/confirmationListController.js +22 -0
- package/dist/orchestrator/src/cli/control/confirmationValidateController.js +58 -0
- package/dist/orchestrator/src/cli/control/confirmations.js +25 -3
- package/dist/orchestrator/src/cli/control/controlActionCancelConfirmation.js +65 -0
- package/dist/orchestrator/src/cli/control/controlActionController.js +77 -0
- package/dist/orchestrator/src/cli/control/controlActionControllerSequencing.js +161 -0
- package/dist/orchestrator/src/cli/control/controlActionExecution.js +142 -0
- package/dist/orchestrator/src/cli/control/controlActionFinalization.js +43 -0
- package/dist/orchestrator/src/cli/control/controlActionOutcome.js +60 -0
- package/dist/orchestrator/src/cli/control/controlActionPreflight.js +476 -0
- package/dist/orchestrator/src/cli/control/controlAuthenticatedRouteHandoff.js +57 -0
- package/dist/orchestrator/src/cli/control/controlBootstrapAssembly.js +39 -0
- package/dist/orchestrator/src/cli/control/controlBootstrapMetadataPersistence.js +16 -0
- package/dist/orchestrator/src/cli/control/controlEventTransport.js +49 -0
- package/dist/orchestrator/src/cli/control/controlExpiryLifecycle.js +102 -0
- package/dist/orchestrator/src/cli/control/controlHostOwnership.js +480 -0
- package/dist/orchestrator/src/cli/control/controlHostSupervision.js +608 -0
- package/dist/orchestrator/src/cli/control/controlOversightFacade.js +8 -0
- package/dist/orchestrator/src/cli/control/controlOversightReadContract.js +1 -0
- package/dist/orchestrator/src/cli/control/controlOversightReadService.js +16 -0
- package/dist/orchestrator/src/cli/control/controlOversightUpdateContract.js +1 -0
- package/dist/orchestrator/src/cli/control/controlPersistenceFiles.js +6 -0
- package/dist/orchestrator/src/cli/control/controlQuestionChildResolution.js +18 -0
- package/dist/orchestrator/src/cli/control/controlRequestContext.js +42 -0
- package/dist/orchestrator/src/cli/control/controlRequestController.js +9 -0
- package/dist/orchestrator/src/cli/control/controlRequestPredispatch.js +17 -0
- package/dist/orchestrator/src/cli/control/controlRequestRouteDispatch.js +44 -0
- package/dist/orchestrator/src/cli/control/controlRuntime.js +992 -0
- package/dist/orchestrator/src/cli/control/controlServer.js +23 -1456
- package/dist/orchestrator/src/cli/control/controlServerAuditAndErrorHelpers.js +115 -0
- package/dist/orchestrator/src/cli/control/controlServerAuthenticatedRouteBranch.js +29 -0
- package/dist/orchestrator/src/cli/control/controlServerBootstrapLifecycle.js +30 -0
- package/dist/orchestrator/src/cli/control/controlServerBootstrapStartSequence.js +21 -0
- package/dist/orchestrator/src/cli/control/controlServerOwnedRuntimeLifecycle.js +67 -0
- package/dist/orchestrator/src/cli/control/controlServerPublicLifecycle.js +756 -0
- package/dist/orchestrator/src/cli/control/controlServerPublicRouteHelpers.js +86 -0
- package/dist/orchestrator/src/cli/control/controlServerReadyInstanceLifecycle.js +25 -0
- package/dist/orchestrator/src/cli/control/controlServerReadyInstanceStartup.js +18 -0
- package/dist/orchestrator/src/cli/control/controlServerRequestBodyHelpers.js +37 -0
- package/dist/orchestrator/src/cli/control/controlServerRequestShell.js +40 -0
- package/dist/orchestrator/src/cli/control/controlServerRequestShellBinding.js +17 -0
- package/dist/orchestrator/src/cli/control/controlServerSeedLoading.js +27 -0
- package/dist/orchestrator/src/cli/control/controlServerSeededRuntimeAssembly.js +186 -0
- package/dist/orchestrator/src/cli/control/controlServerStartupInputPreparation.js +31 -0
- package/dist/orchestrator/src/cli/control/controlServerStartupSequence.js +49 -0
- package/dist/orchestrator/src/cli/control/controlState.js +233 -2
- package/dist/orchestrator/src/cli/control/controlStatusDashboard.js +1899 -0
- package/dist/orchestrator/src/cli/control/controlTelegramBridgeBootstrapLifecycle.js +22 -0
- package/dist/orchestrator/src/cli/control/controlTelegramBridgeLifecycle.js +67 -0
- package/dist/orchestrator/src/cli/control/controlTelegramBridgeOversightFacadeFactory.js +8 -0
- package/dist/orchestrator/src/cli/control/controlTelegramCommandController.js +49 -0
- package/dist/orchestrator/src/cli/control/controlTelegramDispatchRead.js +40 -0
- package/dist/orchestrator/src/cli/control/controlTelegramPollingController.js +89 -0
- package/dist/orchestrator/src/cli/control/controlTelegramProjectionNotificationController.js +29 -0
- package/dist/orchestrator/src/cli/control/controlTelegramPushState.js +63 -0
- package/dist/orchestrator/src/cli/control/controlTelegramQuestionRead.js +13 -0
- package/dist/orchestrator/src/cli/control/controlTelegramReadController.js +216 -0
- package/dist/orchestrator/src/cli/control/controlTelegramUpdateHandler.js +63 -0
- package/dist/orchestrator/src/cli/control/controlWatcher.js +73 -5
- package/dist/orchestrator/src/cli/control/delegationRegisterController.js +35 -0
- package/dist/orchestrator/src/cli/control/dynamicToolBridgePolicy.js +139 -0
- package/dist/orchestrator/src/cli/control/eventsSseController.js +12 -0
- package/dist/orchestrator/src/cli/control/linearBudgetState.js +1789 -0
- package/dist/orchestrator/src/cli/control/linearDispatchSource.js +1137 -0
- package/dist/orchestrator/src/cli/control/linearGraphqlClient.js +150 -0
- package/dist/orchestrator/src/cli/control/linearRateLimit.js +102 -0
- package/dist/orchestrator/src/cli/control/linearWebhookController.js +499 -0
- package/dist/orchestrator/src/cli/control/liveLinearAdvisoryRuntime.js +70 -0
- package/dist/orchestrator/src/cli/control/observabilityApiController.js +173 -0
- package/dist/orchestrator/src/cli/control/observabilityReadModel.js +500 -0
- package/dist/orchestrator/src/cli/control/observabilitySurface.js +284 -0
- package/dist/orchestrator/src/cli/control/observabilityUpdateNotifier.js +22 -0
- package/dist/orchestrator/src/cli/control/operatorDashboardPresenter.js +252 -0
- package/dist/orchestrator/src/cli/control/providerAgentCapacity.js +70 -0
- package/dist/orchestrator/src/cli/control/providerControlHostFreshnessGauge.js +1068 -0
- package/dist/orchestrator/src/cli/control/providerIntakeState.js +473 -0
- package/dist/orchestrator/src/cli/control/providerIssueHandoff.js +6811 -0
- package/dist/orchestrator/src/cli/control/providerIssueObservability.js +1348 -0
- package/dist/orchestrator/src/cli/control/providerIssueRetryQueue.js +84 -0
- package/dist/orchestrator/src/cli/control/providerLinearRuntimeProof.js +588 -0
- package/dist/orchestrator/src/cli/control/providerLinearScreenshotProof.js +473 -0
- package/dist/orchestrator/src/cli/control/providerLinearWorkerTruth.js +383 -0
- package/dist/orchestrator/src/cli/control/providerLinearWorkflowAudit.js +254 -0
- package/dist/orchestrator/src/cli/control/providerLinearWorkflowFacade.js +5573 -0
- package/dist/orchestrator/src/cli/control/providerLinearWorkflowStates.js +115 -0
- package/dist/orchestrator/src/cli/control/providerMergeCloseout.js +1868 -0
- package/dist/orchestrator/src/cli/control/providerOperatorAutopilot.js +1580 -0
- package/dist/orchestrator/src/cli/control/providerOperatorAutopilotLifecycle.js +154 -0
- package/dist/orchestrator/src/cli/control/providerOperatorAutopilotLocalRolloutExecution.js +1006 -0
- package/dist/orchestrator/src/cli/control/providerPollingHealth.js +435 -0
- package/dist/orchestrator/src/cli/control/providerTerminalCleanup.js +516 -0
- package/dist/orchestrator/src/cli/control/providerWorkerHosts.js +191 -0
- package/dist/orchestrator/src/cli/control/providerWorkflowConfigStore.js +515 -0
- package/dist/orchestrator/src/cli/control/questionChildResolutionAdapter.js +361 -0
- package/dist/orchestrator/src/cli/control/questionQueueController.js +181 -0
- package/dist/orchestrator/src/cli/control/questionReadRetryDeduplication.js +9 -0
- package/dist/orchestrator/src/cli/control/questionReadSequence.js +10 -0
- package/dist/orchestrator/src/cli/control/securityViolationController.js +27 -0
- package/dist/orchestrator/src/cli/control/selectedRunProjection.js +1838 -0
- package/dist/orchestrator/src/cli/control/telegramOversightApiClient.js +48 -0
- package/dist/orchestrator/src/cli/control/telegramOversightBridge.js +180 -0
- package/dist/orchestrator/src/cli/control/telegramOversightBridgeProjectionDeliveryQueue.js +25 -0
- package/dist/orchestrator/src/cli/control/telegramOversightBridgeRuntimeLifecycle.js +45 -0
- package/dist/orchestrator/src/cli/control/telegramOversightBridgeStateStore.js +77 -0
- package/dist/orchestrator/src/cli/control/telegramOversightControlActionApiClient.js +45 -0
- package/dist/orchestrator/src/cli/control/trackerDispatchPilot.js +439 -0
- package/dist/orchestrator/src/cli/control/uiDataController.js +34 -0
- package/dist/orchestrator/src/cli/control/uiSessionController.js +100 -0
- package/dist/orchestrator/src/cli/controlHostCliShell.js +860 -0
- package/dist/orchestrator/src/cli/controlHostFreshnessGaugeCliShell.js +129 -0
- package/dist/orchestrator/src/cli/controlHostSupervisionCliShell.js +2127 -0
- package/dist/orchestrator/src/cli/delegationCliShell.js +62 -0
- package/dist/orchestrator/src/cli/delegationServer.js +567 -678
- package/dist/orchestrator/src/cli/delegationServerCliShell.js +52 -0
- package/dist/orchestrator/src/cli/delegationServerQuestionFlowShell.js +228 -0
- package/dist/orchestrator/src/cli/delegationServerToolDispatchShell.js +411 -0
- package/dist/orchestrator/src/cli/delegationServerTransport.js +274 -0
- package/dist/orchestrator/src/cli/delegationSetup.js +51 -171
- package/dist/orchestrator/src/cli/devtoolsCliShell.js +34 -0
- package/dist/orchestrator/src/cli/doctor.js +542 -122
- package/dist/orchestrator/src/cli/doctorCliRequestShell.js +72 -0
- package/dist/orchestrator/src/cli/doctorCliShell.js +138 -0
- package/dist/orchestrator/src/cli/doctorUsage.js +119 -15
- package/dist/orchestrator/src/cli/exec/experience.js +16 -2
- package/dist/orchestrator/src/cli/exec/summary.js +3 -0
- package/dist/orchestrator/src/cli/execCliShell.js +51 -0
- package/dist/orchestrator/src/cli/flowCliRequestShell.js +44 -0
- package/dist/orchestrator/src/cli/flowCliShell.js +239 -0
- package/dist/orchestrator/src/cli/frontendTestCliRequestShell.js +80 -0
- package/dist/orchestrator/src/cli/frontendTestCliShell.js +41 -0
- package/dist/orchestrator/src/cli/init.js +1 -0
- package/dist/orchestrator/src/cli/initCliShell.js +50 -0
- package/dist/orchestrator/src/cli/linearCliShell.js +1200 -0
- package/dist/orchestrator/src/cli/mcpEnableCliShell.js +132 -0
- package/dist/orchestrator/src/cli/metrics/metricsAggregator.js +3 -2
- package/dist/orchestrator/src/cli/metrics/metricsRecorder.js +56 -0
- package/dist/orchestrator/src/cli/orchestrator.js +66 -1376
- package/dist/orchestrator/src/cli/planCliShell.js +19 -0
- package/dist/orchestrator/src/cli/prCliShell.js +41 -0
- package/dist/orchestrator/src/cli/providerLinearChildLanePhaseContract.js +204 -0
- package/dist/orchestrator/src/cli/providerLinearChildLaneRunner.js +1772 -0
- package/dist/orchestrator/src/cli/providerLinearChildLaneShell.js +2420 -0
- package/dist/orchestrator/src/cli/providerLinearChildStreamShell.js +385 -0
- package/dist/orchestrator/src/cli/providerLinearWorkerRunner.js +5738 -0
- package/dist/orchestrator/src/cli/resumeCliShell.js +14 -0
- package/dist/orchestrator/src/cli/reviewCliLaunchShell.js +72 -0
- package/dist/orchestrator/src/cli/rlm/alignment.js +3 -3
- package/dist/orchestrator/src/cli/rlm/context.js +94 -7
- package/dist/orchestrator/src/cli/rlm/rlmCodexRuntimeShell.js +546 -0
- package/dist/orchestrator/src/cli/rlm/symbolic.js +4 -2
- package/dist/orchestrator/src/cli/rlmCliRequestShell.js +42 -0
- package/dist/orchestrator/src/cli/rlmCompletionCliShell.js +46 -0
- package/dist/orchestrator/src/cli/rlmLaunchCliShell.js +51 -0
- package/dist/orchestrator/src/cli/rlmRunner.js +83 -523
- package/dist/orchestrator/src/cli/run/blockMemory.js +500 -0
- package/dist/orchestrator/src/cli/run/manifest.js +410 -73
- package/dist/orchestrator/src/cli/run/manifestPersister.js +45 -14
- package/dist/orchestrator/src/cli/run/runMemoryController.js +216 -0
- package/dist/orchestrator/src/cli/run/source0.js +690 -0
- package/dist/orchestrator/src/cli/run/workspacePath.js +101 -0
- package/dist/orchestrator/src/cli/runtime/mode.js +2 -1
- package/dist/orchestrator/src/cli/runtime/provider.js +39 -2
- package/dist/orchestrator/src/cli/selfCheckCliShell.js +12 -0
- package/dist/orchestrator/src/cli/services/commandRunner.js +667 -18
- package/dist/orchestrator/src/cli/services/execRuntime.js +66 -1
- package/dist/orchestrator/src/cli/services/orchestratorAutoScoutEvidenceRecorder.js +71 -0
- package/dist/orchestrator/src/cli/services/orchestratorCloudBranchResolution.js +8 -0
- package/dist/orchestrator/src/cli/services/orchestratorCloudEnvironmentResolution.js +22 -0
- package/dist/orchestrator/src/cli/services/orchestratorCloudExecutionLifecycleShell.js +39 -0
- package/dist/orchestrator/src/cli/services/orchestratorCloudPromptBuilder.js +37 -0
- package/dist/orchestrator/src/cli/services/orchestratorCloudRouteFallbackContract.js +45 -0
- package/dist/orchestrator/src/cli/services/orchestratorCloudRouteShell.js +36 -0
- package/dist/orchestrator/src/cli/services/orchestratorCloudTargetExecutor.js +277 -0
- package/dist/orchestrator/src/cli/services/orchestratorControlPlaneLifecycle.js +98 -0
- package/dist/orchestrator/src/cli/services/orchestratorControlPlaneLifecycleShell.js +54 -0
- package/dist/orchestrator/src/cli/services/orchestratorExecutionLifecycle.js +112 -0
- package/dist/orchestrator/src/cli/services/orchestratorExecutionModePolicy.js +27 -0
- package/dist/orchestrator/src/cli/services/orchestratorExecutionRouteAdapterShell.js +59 -0
- package/dist/orchestrator/src/cli/services/orchestratorExecutionRouteDecisionShell.js +57 -0
- package/dist/orchestrator/src/cli/services/orchestratorExecutionRouteState.js +21 -0
- package/dist/orchestrator/src/cli/services/orchestratorExecutionRouter.js +2 -0
- package/dist/orchestrator/src/cli/services/orchestratorLocalPipelineExecutor.js +149 -0
- package/dist/orchestrator/src/cli/services/orchestratorLocalRouteShell.js +63 -0
- package/dist/orchestrator/src/cli/services/orchestratorPlanShell.js +54 -0
- package/dist/orchestrator/src/cli/services/orchestratorPlanTargetTracker.js +16 -0
- package/dist/orchestrator/src/cli/services/orchestratorResumePreparationShell.js +84 -0
- package/dist/orchestrator/src/cli/services/orchestratorResumeTokenValidation.js +15 -0
- package/dist/orchestrator/src/cli/services/orchestratorRunLifecycleCompletion.js +31 -0
- package/dist/orchestrator/src/cli/services/orchestratorRunLifecycleExecutionRegistration.js +37 -0
- package/dist/orchestrator/src/cli/services/orchestratorRunLifecycleOrchestrationShell.js +83 -0
- package/dist/orchestrator/src/cli/services/orchestratorRunLifecycleTaskManagerShell.js +37 -0
- package/dist/orchestrator/src/cli/services/orchestratorRuntimeManifestMutation.js +20 -0
- package/dist/orchestrator/src/cli/services/orchestratorStartPreparationShell.js +56 -0
- package/dist/orchestrator/src/cli/services/orchestratorStatusShell.js +70 -0
- package/dist/orchestrator/src/cli/services/pipelineResolver.js +7 -3
- package/dist/orchestrator/src/cli/services/plannerMemory.js +119 -0
- package/dist/orchestrator/src/cli/services/runPreparation.js +7 -3
- package/dist/orchestrator/src/cli/services/runSummaryWriter.js +9 -0
- package/dist/orchestrator/src/cli/setupBootstrapShell.js +114 -0
- package/dist/orchestrator/src/cli/setupCliShell.js +51 -0
- package/dist/orchestrator/src/cli/skillsCliShell.js +56 -0
- package/dist/orchestrator/src/cli/startCliRequestShell.js +53 -0
- package/dist/orchestrator/src/cli/startCliShell.js +68 -0
- package/dist/orchestrator/src/cli/statusCliShell.js +22 -0
- package/dist/orchestrator/src/cli/utils/authProvenanceFingerprint.js +27 -0
- package/dist/orchestrator/src/cli/utils/cloudPreflight.js +83 -1
- package/dist/orchestrator/src/cli/utils/delegationConfigParser.js +250 -0
- package/dist/orchestrator/src/cli/utils/delegationMcpHealth.js +1382 -0
- package/dist/orchestrator/src/cli/utils/devtools.js +2 -54
- package/dist/orchestrator/src/cli/utils/mcpServerEntry.js +53 -0
- package/dist/orchestrator/src/cli/utils/packageProgramResolver.js +151 -0
- package/dist/orchestrator/src/cli/utils/providerOverrideEnv.js +71 -0
- package/dist/orchestrator/src/cli/utils/trailingJsonObject.js +59 -0
- package/dist/orchestrator/src/learning/crystalizer.js +2 -2
- package/dist/orchestrator/src/persistence/ExperienceStore.js +233 -49
- package/dist/orchestrator/src/persistence/TaskStateStore.js +6 -6
- package/dist/orchestrator/src/persistence/lockFile.js +70 -4
- package/dist/orchestrator/src/persistence/sanitizeIdentifier.js +39 -0
- package/dist/orchestrator/src/sync/createCloudSyncWorker.js +3 -2
- package/dist/orchestrator/src/utils/atomicWrite.js +17 -2
- package/dist/packages/orchestrator/src/exec/unified-exec.js +99 -6
- package/dist/packages/orchestrator/src/instructions/promptPacks.js +150 -19
- package/dist/packages/sdk-node/src/orchestrator.js +137 -13
- package/dist/packages/shared/config/designConfig.js +8 -1
- package/dist/packages/shared/streams/stdio.js +1 -1
- package/dist/scripts/design/pipeline/permit.js +15 -0
- package/dist/scripts/lib/docs-catalog.js +365 -0
- package/dist/scripts/lib/docs-helpers.js +87 -5
- package/dist/scripts/lib/pr-watch-merge.js +1088 -80
- package/dist/scripts/lib/provider-run-contract.js +26 -0
- package/dist/scripts/lib/review-command-intent-classification.js +532 -0
- package/dist/scripts/lib/review-command-probe-classification.js +385 -0
- package/dist/scripts/lib/review-execution-boundary-preflight.js +279 -0
- package/dist/scripts/lib/review-execution-runtime.js +753 -0
- package/dist/scripts/lib/review-execution-state.js +1144 -0
- package/dist/scripts/lib/review-execution-telemetry.js +215 -0
- package/dist/scripts/lib/review-inspection-target-parsing.js +78 -0
- package/dist/scripts/lib/review-launch-attempt.js +601 -0
- package/dist/scripts/lib/review-meta-surface-boundary-analysis.js +300 -0
- package/dist/scripts/lib/review-meta-surface-normalization.js +746 -0
- package/dist/scripts/lib/review-non-interactive-handoff.js +61 -0
- package/dist/scripts/lib/review-prompt-context.js +376 -0
- package/dist/scripts/lib/review-scope-advisory.js +286 -0
- package/dist/scripts/lib/review-scope-paths.js +123 -0
- package/dist/scripts/lib/review-shell-command-parser.js +389 -0
- package/dist/scripts/lib/review-shell-env-interpreter.js +340 -0
- package/dist/scripts/lib/run-manifests.js +192 -36
- package/dist/scripts/lib/spark-policy-classifier.js +593 -0
- package/dist/scripts/run-review.js +507 -1777
- package/docs/public/downstream-setup.md +106 -0
- package/docs/public/provider-onboarding.md +173 -0
- package/package.json +20 -10
- package/plugins/codex-orchestrator/.codex-plugin/plugin.json +30 -0
- package/plugins/codex-orchestrator/.mcp.json +13 -0
- package/plugins/codex-orchestrator/launcher.mjs +359 -0
- package/schemas/manifest.json +394 -0
- package/skills/collab-subagents-first/SKILL.md +1 -1
- package/skills/delegation-usage/DELEGATION_GUIDE.md +24 -11
- package/skills/delegation-usage/SKILL.md +19 -13
- package/skills/land/SKILL.md +77 -0
- package/skills/linear/SKILL.md +255 -0
- package/skills/release/SKILL.md +47 -3
- package/skills/standalone-review/SKILL.md +6 -1
- package/templates/README.md +4 -2
- package/templates/codex/.codex/agents/awaiter-high.toml +2 -2
- package/templates/codex/.codex/agents/worker-complex.toml +1 -1
- package/templates/codex/.codex/config.toml +3 -4
- package/templates/codex/.codex/providers/README.md +13 -0
- package/templates/codex/.codex/providers/control.example.json +18 -0
- package/templates/codex/.codex/providers/provider.env.example +15 -0
- package/templates/codex/AGENTS.md +12 -7
- package/templates/codex/mcp-client.json +5 -1
- package/docs/README.md +0 -310
- package/docs/assets/setup.gif +0 -0
|
@@ -0,0 +1,593 @@
|
|
|
1
|
+
const SPARK_POLICY_MUST_BE_FILE_CODEBASE_REASON = 'spark role must be file/codebase search only';
|
|
2
|
+
const SPARK_POLICY_MISSING_FILE_CODEBASE_REASON = 'spark role missing file/codebase search-only scope';
|
|
3
|
+
const SPARK_POLICY_FILE_SEARCH_PATTERN = /(?:file[-/ ]search|codebase[-/ ]search|file\/codebase search|file search|codebase search)/i;
|
|
4
|
+
const SPARK_POLICY_LIMITING_APPOSITIVE_PATTERN = /^\s*(?:and\s+)?(?:(?:confin(?:e|ed|es|ing)|constrain(?:ed|s|ing)?|limit(?:ed|s|ing)?|reserv(?:e|ed|es|ing)|restrict(?:ed|s|ing)?|scop(?:e|ed|es|ing))\b|only[- ](?:as|for|to|search)\b|\bsearch[- ]only\b)/i;
|
|
5
|
+
const SPARK_POLICY_NEXT_ASSERTION_BOUNDARY_PATTERN = /\s+\b(?:and|but|or|while|whereas)\b\s+(?:(?:(?:can|could|may|might|must|should)\s+)?(?:allow(?:ed|s|ing)?|choos(?:e|es|ing)|confin(?:e|ed|es|ing)|constrain(?:ed|s|ing)?|keep(?:s|ing)?|leav(?:e|es|ing)|limit(?:ed|s|ing)?|mak(?:e|es|ing)|permit(?:s|ted|ting)?|prefer(?:s|ring)?|reserv(?:e|ed|es|ing)|restrict(?:ed|s|ing)?|rout(?:e|ed|es|ing)|run(?:s|ning)?|scop(?:e|ed|es|ing)|select(?:s|ing)?|support(?:ed|s|ing)?|us(?:e|ed|es|ing))\s+(?:(?:the|a|an)\s+)?[`*_]*(?:spark(?:\s+roles?)?|explorer_fast|gpt-5\.3-codex-spark)[`*_]*(?:\s+(?:roles?|agents?|models?))?\b|(?:(?:the|a|an)\s+)?[`*_]*(?:spark(?:\s+roles?)?|explorer_fast|gpt-5\.3-codex-spark)[`*_]*(?:\s+(?:roles?|agents?|models?))?\s+(?:are|is|can|could|should|must|may|might|remain(?:s|ing)?|stay(?:s|ing)?|be(?:ing)?|become(?:s|ing)?|confin(?:e|ed|es|ing)|constrain(?:ed|s|ing)?|limit(?:ed|s|ing)?|reserv(?:e|ed|es|ing)|restrict(?:ed|s|ing)?|scop(?:e|ed|es|ing)|support(?:ed|s|ing)?)\b)/i;
|
|
6
|
+
const SPARK_POLICY_SCOPE_REQUIRED_PATTERN = /\b(?:allow(?:ed|s|ing)?|choos(?:e|es|ing)|confin(?:e|ed|es|ing)|constrain(?:ed|s|ing)?|except(?:ion|ions)?|keep(?:s|ing)?|leav(?:e|es|ing)|limit(?:ed|s|ing)?|mak(?:e|es|ing)|only|permitted?|permits?|prefer(?:s|ring)?|remain(?:s|ing)?|reserv(?:e|ed|es|ing)|restrict(?:ed|s|ing)?|rout(?:e|ed|es|ing)|run(?:s|ning)?|scop(?:e|ed|es|ing)|select(?:s|ing)?|should|support(?:ed|s|ing)?|us(?:e|ed|es|ing)|must)\b/i;
|
|
7
|
+
const SPARK_POLICY_ACTIVE_CAPABILITY_PATTERN = /^(?:(?:can|could|may|might|should|must)\s+(?:(?:be|being)\s+)?(?:available|helpful|useful|suitable|appropriate|valid|help(?:s|ed|ing)?|assist(?:s|ed|ing)?|aid(?:s|ed|ing)?|debug(?:s|ged|ging)?|diagnos(?:e|es|ed|ing)|triag(?:e|es|ed|ing)|troubleshoot(?:s|ed|ing)?|investigat(?:e|es|ed|ing)|analyz(?:e|es|ed|ing)|inspect(?:s|ed|ing)?|handle(?:s|d|ing)?|cover(?:s|ed|ing)?|serve(?:s|d|ing)?|work(?:s|ed|ing)?|process(?:es|ed|ing)?)|(?:are|is|be(?:ing)?|become(?:s|ing)?|remain(?:s|ing)?|stay(?:s|ing)?)\s+(?:available|helpful|useful|suitable|appropriate|valid)\s+(?:for|with|to)|(?:help(?:s|ed|ing)?|assist(?:s|ed|ing)?|aid(?:s|ed|ing)?)\s+(?:with|for|to))\b/i;
|
|
8
|
+
const SPARK_POLICY_GENERIC_SCOPE_ASSERTION_PATTERN = /\b(?:allow(?:ed|s|ing)?|choos(?:e|es|ing)|confin(?:e|ed|es|ing)|constrain(?:ed|s|ing)?|except(?:ion|ions)?|file[-/ ]?search|codebase[-/ ]?search|(?:image|visual)\s+(?:inputs?|tasks?)|limit(?:ed|s|ing)?|only|only[- ]search|permitted?|permits?|prefer(?:s|ring)?|remain(?:s|ing)?|reserv(?:e|ed|es|ing)|restrict(?:ed|s|ing)?|rout(?:e|ed|es|ing)|run(?:s|ning)?|scop(?:ed|es|ing)|search[- ]only|select(?:s|ing)?|stay(?:s|ing)?|support(?:ed|s|ing)?|text[- ]only|us(?:e|ed|es|ing))\b/i;
|
|
9
|
+
const SPARK_POLICY_GENERIC_SEARCH_SCOPE_PATTERN = /\b(?:search(?![- ]?polic(?:y|ies)\b)(?:\s+lanes?)?|search[- ]only|only[- ]search)\b/i;
|
|
10
|
+
const SPARK_POLICY_NEUTRAL_ASSERTION_LEAD_PATTERN = /^(?:(?:can|could|may|might|must|should)\s+)?(?:allow(?:ed|s|ing)?|are|available|be(?:ing)?|become(?:s|ing)?|choos(?:e|es|ing)|confin(?:e|ed|es|ing)|constrain(?:ed|s|ing)?|enabl(?:e|ed|es|ing)|intended|is|limit(?:ed|s|ing)?|only\b|permit(?:s|ted|ting)?|remain(?:s|ing)?|reserv(?:e|ed|es|ing)|restrict(?:ed|s|ing)?|rout(?:e|ed|es|ing)|run(?:s|ning)?|scop(?:e|ed|es|ing)|search[- ]only\b|select(?:s|ing)?|stay(?:s|ing)?|support(?:ed|s|ing)?|text[- ]only\b|us(?:e|ed|es|ing))\b/i;
|
|
11
|
+
const SPARK_POLICY_FORBIDDEN_USAGE_PATTERN = /(?:search\/synthesis|\bbroad exploration\b|\bsynthesis\b|\bplanning\b|\bimplementation\b|\breview\b|\bexploration\b)/gi;
|
|
12
|
+
const SPARK_POLICY_NEUTRAL_MAINTENANCE_PHRASE_PATTERN = /\b(?:planning|review)\s+(?:comments?|context|docs?|documentation|feedback|guidance|notes?|records?|references?|summar(?:y|ies)|updates?)\b/gi;
|
|
13
|
+
const SPARK_POLICY_SUPPORT_MAINTENANCE_REFERENCE_PATTERN = /^\s*(?:role\s+)?support\s+(?:comments?|context|docs?|documentation|feedback|guidance|notes?|records?|references?|summar(?:y|ies)|updates?)\b/i;
|
|
14
|
+
const SPARK_POLICY_SUPPORT_MAINTENANCE_TAIL_PATTERN = /^(?:\s*(?:[.;,!?]|$)|\s+(?:(?:can|could|may|might|must|should)\s+)?(?:(?:be|remain|stay)\s+)?(?:changed?|edited|kept|locked|maintained|moved|recorded|renamed|updated?)\b|\s+(?:exist|exists|link|links|live|lives|living|point|points|record|records|reference|references|reside|resides)\b|\s+(?:are|be|been|being|is|was|were)\s+(?:available|changed?|edited|kept|locked|maintained|moved|present|recorded|renamed|updated?)\b)/i;
|
|
15
|
+
const SPARK_POLICY_MARKER_AT_START_PATTERN = /^(?:[`*_]*(?:spark(?:\s+roles?)?|explorer_fast|gpt-5\.3-codex-spark)[`*_]*(?:\s+(?:roles?|agents?|models?))?)/i;
|
|
16
|
+
const SPARK_POLICY_SUFFIX_RESTRICTION_PATTERN = /(?:,\s*)?\b(?:do not|don't|must not|should not|cannot|can't|never)\s+(?:(?:route)\s+(?:to\s+)?|(?:use|run|select|choose|prefer)\s+)(?:it\b|(?:(?:the|a|an)\s+)?[`*_]*(?:spark|spark roles?|explorer_fast|gpt-5\.3-codex-spark)[`*_]*(?=\W|$))/;
|
|
17
|
+
const SPARK_POLICY_WITHOUT_FORBIDDEN_SCOPE_PATTERN = /\bwithout\s+(?:broad\s+exploration|exploration|implementation|planning|review|search\/synthesis|synthesis)\b/i;
|
|
18
|
+
const SPARK_POLICY_DISABLED_NON_USE_PATTERN = /(?:\b(?:keep(?:s|ing)?|leav(?:e|es|ing)|set(?:s|ting)?|mark(?:s|ing)?|configur(?:e|es|ed|ing))\s+(?:(?:the|a|an)\s+)?[`*_]*(?:spark(?:\s+roles?)?|explorer_fast|gpt-5\.3-codex-spark)[`*_]*(?:\s+(?:roles?|agents?|models?))?\s+(?:disabled|inactive|off|unset|unconfigured|unavailable)\b|(?:(?:the|a|an)\s+)?[`*_]*(?:spark(?:\s+roles?)?|explorer_fast|gpt-5\.3-codex-spark)[`*_]*(?:\s+(?:roles?|agents?|models?))?\s+(?:are|is|remain(?:s|ing)?|stay(?:s|ing)?|be(?:ing)?|become(?:s|ing)?)\s+(?:disabled|inactive|off|unset|unconfigured|unavailable)\b)/i;
|
|
19
|
+
const SPARK_POLICY_DISABLED_GENERIC_SEARCH_SCOPE_PATTERN = /\b(?:(?:only\s+)?(?:allow(?:ed|s|ing)?|available|confin(?:e|ed|es|ing)|constrain(?:ed|s|ing)?|intended|limit(?:ed|s|ing)?|permitted?|reserv(?:e|ed|es|ing)|restrict(?:ed|s|ing)?|scop(?:e|ed|es|ing))\s+(?:as|for|to)\s+search(?:\s+lanes?)?|(?:are|is|be(?:ing)?|remain(?:s|ing)?|stay(?:s|ing)?)\s+(?:only\s+)?(?:for\s+)?search(?:\s+lanes?)?|only\s+for\s+search(?:\s+lanes?)?|(?:search[- ]only|only[- ]search)(?:\s+lanes?)?|(?:unless|until|except\s+(?:when|if)|when|if|where)\s+(?:(?:a|an|the)\s+)?search(?:\s+lanes?)?\s+(?:opts?\s+in|opt\s+in|needs?\b|is\s+(?:needed|required|requested)))\b/i;
|
|
20
|
+
const SPARK_POLICY_NON_SPARK_REDIRECT_PATTERN = /\b(?:use|prefer|choose|select|route|run)\s+(?:to\s+)?(?:a\s+|an\s+)?(?:non-spark|non\s+spark|alternate|alternative|different|other)\s+(?:roles?|agents?|models?)\s+(?:instead\s+of|over|rather\s+than|before)\s+(?:(?:the|a|an)\s+)?[`*_]*(?:spark(?:\s+roles?)?|explorer_fast|gpt-5\.3-codex-spark)[`*_]*(?:\s+(?:roles?|agents?|models?))?\b/i;
|
|
21
|
+
const SPARK_POLICY_DISABLED_ACTIVE_USE_PATTERN = /\b(?:(?:and|but|or|then|when|while)\s+)?(?:(?:can|could|may|might|must|should)\s+)?(?:(?:be|being)\s+)?(?:allow(?:ed|s|ing)?|choos(?:e|es|ing)|confin(?:e|ed|es|ing)|constrain(?:ed|s|ing)?|enabl(?:e|ed|es|ing)|keep(?:s|ing)?|leav(?:e|es|ing)|limit(?:ed|s|ing)?|mak(?:e|es|ing)|permit(?:s|ted|ting)?|prefer(?:s|red|ring)?|remain(?:s|ing)?|reserv(?:e|ed|es|ing)|restrict(?:ed|s|ing)?|rout(?:e|ed|es|ing)|run(?:s|ning)?|scop(?:e|ed|es|ing)|select(?:ed|s|ing)?|stay(?:s|ing)?|support(?:ed|s|ing)?|us(?:e|ed|es|ing))\b/gi;
|
|
22
|
+
export function getSparkPolicyViolations(content) {
|
|
23
|
+
const violations = [];
|
|
24
|
+
const reportedLines = new Set();
|
|
25
|
+
for (const result of evaluateSparkPolicyContent(content)) {
|
|
26
|
+
if (result.verdict !== 'forbidden' || reportedLines.has(result.line)) {
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
violations.push(result);
|
|
30
|
+
reportedLines.add(result.line);
|
|
31
|
+
}
|
|
32
|
+
return violations;
|
|
33
|
+
}
|
|
34
|
+
export function evaluateSparkPolicyContent(content) {
|
|
35
|
+
const results = [];
|
|
36
|
+
const lines = content.split('\n');
|
|
37
|
+
for (const [index, line] of lines.entries()) {
|
|
38
|
+
const markerIndexes = findSparkPolicyMarkerIndexes(line);
|
|
39
|
+
if (markerIndexes.length === 0) {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
for (const markerIndex of markerIndexes) {
|
|
43
|
+
const lineContext = buildSparkPolicyLineContext(lines, index, markerIndex);
|
|
44
|
+
results.push({
|
|
45
|
+
line: index + 1,
|
|
46
|
+
...classifySparkPolicyLineContext(lineContext.text, lineContext.markerIndex)
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return results;
|
|
51
|
+
}
|
|
52
|
+
export function classifySparkPolicyLineContext(text, markerIndex) {
|
|
53
|
+
const parsed = parseSparkPolicyLineContext(text, markerIndex);
|
|
54
|
+
if (parsed.neutralReference && !parsed.neutralContinuationAssertion) {
|
|
55
|
+
return {
|
|
56
|
+
marker: parsed.marker,
|
|
57
|
+
markerIndex,
|
|
58
|
+
verdict: 'neutral',
|
|
59
|
+
reason: 'neutral spark policy reference',
|
|
60
|
+
context: text,
|
|
61
|
+
relevantText: parsed.relevantText
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
if (parsed.neutralSupportMaintenanceReference) {
|
|
65
|
+
return {
|
|
66
|
+
marker: parsed.marker,
|
|
67
|
+
markerIndex,
|
|
68
|
+
verdict: 'neutral',
|
|
69
|
+
reason: 'neutral spark support maintenance reference',
|
|
70
|
+
context: text,
|
|
71
|
+
relevantText: parsed.relevantText
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
if (hasOverbroadSparkUsage(parsed.relevantText) || hasNegatedSparkFileSearchScope(parsed.relevantText)) {
|
|
75
|
+
return {
|
|
76
|
+
marker: parsed.marker,
|
|
77
|
+
markerIndex,
|
|
78
|
+
verdict: 'forbidden',
|
|
79
|
+
reason: SPARK_POLICY_MUST_BE_FILE_CODEBASE_REASON,
|
|
80
|
+
context: text,
|
|
81
|
+
relevantText: parsed.relevantText
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
if (hasMissingSparkFileSearchScope(parsed.relevantText)) {
|
|
85
|
+
return {
|
|
86
|
+
marker: parsed.marker,
|
|
87
|
+
markerIndex,
|
|
88
|
+
verdict: 'forbidden',
|
|
89
|
+
reason: SPARK_POLICY_MISSING_FILE_CODEBASE_REASON,
|
|
90
|
+
context: text,
|
|
91
|
+
relevantText: parsed.relevantText
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
95
|
+
marker: parsed.marker,
|
|
96
|
+
markerIndex,
|
|
97
|
+
verdict: 'allowed',
|
|
98
|
+
reason: 'spark policy scope is file/codebase search only or restrictive non-use',
|
|
99
|
+
context: text,
|
|
100
|
+
relevantText: parsed.relevantText
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
function parseSparkPolicyLineContext(text, markerIndex) {
|
|
104
|
+
const marker = readSparkPolicyMarker(text, markerIndex);
|
|
105
|
+
return {
|
|
106
|
+
marker,
|
|
107
|
+
markerIndex,
|
|
108
|
+
text,
|
|
109
|
+
relevantText: text.slice(findLastClauseBoundary(text, markerIndex)),
|
|
110
|
+
neutralReference: isNeutralSparkPolicyReference(text, markerIndex),
|
|
111
|
+
neutralContinuationAssertion: hasNeutralSparkPolicyContinuationAssertion(text, markerIndex),
|
|
112
|
+
neutralSupportMaintenanceReference: isNeutralSparkSupportMaintenanceReference(text, markerIndex)
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
function readSparkPolicyMarker(text, markerIndex) {
|
|
116
|
+
const markerText = text.slice(markerIndex);
|
|
117
|
+
const markerMatch = SPARK_POLICY_MARKER_AT_START_PATTERN.exec(markerText);
|
|
118
|
+
if (markerMatch) {
|
|
119
|
+
return markerMatch[0].replace(/[`*_]/g, '').trim();
|
|
120
|
+
}
|
|
121
|
+
return text.slice(markerIndex, markerIndex + 'spark'.length);
|
|
122
|
+
}
|
|
123
|
+
function hasMissingSparkFileSearchScope(relevantText) {
|
|
124
|
+
if (hasUnqualifiedActiveUseAfterDisabledNonUse(relevantText)) {
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
const scopeAssertionWindows = getSparkScopeAssertionWindows(relevantText).filter((markerWindow) => hasSparkPolicyScopeRequiredAssertion(markerWindow));
|
|
128
|
+
if (scopeAssertionWindows.length > 0) {
|
|
129
|
+
return scopeAssertionWindows.some((markerWindow) => !isRestrictiveSparkPolicyStatement(markerWindow) &&
|
|
130
|
+
(hasNonFileSparkScopeAssertion(markerWindow) ||
|
|
131
|
+
!SPARK_POLICY_FILE_SEARCH_PATTERN.test(markerWindow) ||
|
|
132
|
+
hasUnqualifiedLaterSparkScopeAssertion(markerWindow)));
|
|
133
|
+
}
|
|
134
|
+
if (isRestrictiveSparkPolicyStatement(relevantText)) {
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
return hasSparkPolicyScopeRequiredAssertion(relevantText) && !SPARK_POLICY_FILE_SEARCH_PATTERN.test(relevantText);
|
|
138
|
+
}
|
|
139
|
+
function hasSparkPolicyScopeRequiredAssertion(text) {
|
|
140
|
+
return SPARK_POLICY_SCOPE_REQUIRED_PATTERN.test(text) || hasSparkPolicyActiveCapabilityAssertion(text);
|
|
141
|
+
}
|
|
142
|
+
function hasSparkPolicyActiveCapabilityAssertion(text) {
|
|
143
|
+
for (const markerIndex of findSparkPolicyMarkerIndexes(text)) {
|
|
144
|
+
if (isNeutralSparkPolicyReference(text, markerIndex) ||
|
|
145
|
+
isNeutralSparkSupportMaintenanceReference(text, markerIndex)) {
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
const clauseEnd = findNextClauseBoundary(text, markerIndex);
|
|
149
|
+
const predicate = sliceAfterSparkPolicyMarker(text, markerIndex, clauseEnd).trimStart();
|
|
150
|
+
if (SPARK_POLICY_ACTIVE_CAPABILITY_PATTERN.test(predicate)) {
|
|
151
|
+
return true;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
function getSparkScopeAssertionWindows(relevantText) {
|
|
157
|
+
return findSparkPolicyMarkerIndexes(relevantText)
|
|
158
|
+
.filter((markerIndex) => !isNeutralSparkPolicyReference(relevantText, markerIndex) &&
|
|
159
|
+
!isNeutralSparkSupportMaintenanceReference(relevantText, markerIndex))
|
|
160
|
+
.map((markerIndex) => {
|
|
161
|
+
const clauseStart = findLastClauseBoundary(relevantText, markerIndex);
|
|
162
|
+
const clauseEnd = findNextClauseBoundary(relevantText, markerIndex);
|
|
163
|
+
const markerClause = relevantText.slice(clauseStart, clauseEnd);
|
|
164
|
+
return buildSparkPolicyMarkerWindow(markerClause, markerIndex - clauseStart);
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
function buildSparkPolicyMarkerWindow(markerClause, markerIndex) {
|
|
168
|
+
const prefix = markerClause.slice(0, markerIndex);
|
|
169
|
+
const suffix = markerClause.slice(markerIndex);
|
|
170
|
+
const frontedQualifierStart = findSparkPolicyFrontedFileSearchQualifierStart(prefix);
|
|
171
|
+
const prefixStart = frontedQualifierStart ?? Math.max(prefix.lastIndexOf(',') + 1, findSparkPolicyPreviousAssertionPrefixEnd(prefix));
|
|
172
|
+
const suffixEnd = findSparkPolicyMarkerWindowSuffixEnd(suffix);
|
|
173
|
+
const localPrefix = prefix.slice(prefixStart);
|
|
174
|
+
const localSuffix = suffix.slice(0, suffixEnd);
|
|
175
|
+
return `${localPrefix}${localSuffix}`;
|
|
176
|
+
}
|
|
177
|
+
function findSparkPolicyFrontedFileSearchQualifierStart(prefix) {
|
|
178
|
+
const fileSearchPattern = new RegExp(SPARK_POLICY_FILE_SEARCH_PATTERN.source, 'gi');
|
|
179
|
+
let qualifierStart = null;
|
|
180
|
+
for (const match of prefix.matchAll(fileSearchPattern)) {
|
|
181
|
+
const fileSearchIndex = match.index ?? -1;
|
|
182
|
+
if (fileSearchIndex === -1) {
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
const segmentEnd = prefix.indexOf(',', fileSearchIndex);
|
|
186
|
+
if (segmentEnd === -1) {
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
const segmentStart = prefix.lastIndexOf(',', fileSearchIndex) + 1;
|
|
190
|
+
const candidate = prefix.slice(segmentStart, segmentEnd + 1);
|
|
191
|
+
if (/^\s*(?:[-*+]\s+|\d+\.\s+)?(?:only\s+)?(?:for|when|while|during|in|as)\b/i.test(candidate)) {
|
|
192
|
+
qualifierStart = segmentStart;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return qualifierStart;
|
|
196
|
+
}
|
|
197
|
+
function findSparkPolicyMarkerWindowSuffixEnd(suffix) {
|
|
198
|
+
const firstComma = suffix.indexOf(',');
|
|
199
|
+
const assertionBoundary = findSparkPolicyNextAssertionBoundary(suffix);
|
|
200
|
+
if (firstComma === -1) {
|
|
201
|
+
return assertionBoundary === -1 ? suffix.length : assertionBoundary;
|
|
202
|
+
}
|
|
203
|
+
if (assertionBoundary !== -1 && assertionBoundary < firstComma) {
|
|
204
|
+
return assertionBoundary;
|
|
205
|
+
}
|
|
206
|
+
const localSuffix = suffix.slice(0, firstComma);
|
|
207
|
+
const followingText = suffix.slice(firstComma + 1);
|
|
208
|
+
const trailingQualifierEnd = findSparkPolicyTrailingFileSearchQualifierEnd(followingText);
|
|
209
|
+
if (trailingQualifierEnd !== -1) {
|
|
210
|
+
return firstComma + 1 + trailingQualifierEnd;
|
|
211
|
+
}
|
|
212
|
+
if (isBareSparkPolicyMarkerWindow(localSuffix) && SPARK_POLICY_LIMITING_APPOSITIVE_PATTERN.test(followingText)) {
|
|
213
|
+
const nextComma = followingText.indexOf(',');
|
|
214
|
+
const followingAssertionBoundary = findSparkPolicyNextAssertionBoundary(followingText);
|
|
215
|
+
const followingSuffixEnd = minPositiveIndex(followingText.length, nextComma, followingAssertionBoundary);
|
|
216
|
+
return firstComma + 1 + followingSuffixEnd;
|
|
217
|
+
}
|
|
218
|
+
const sharedMarkerListQualifierEnd = findSparkPolicySharedMarkerListQualifierEnd(suffix);
|
|
219
|
+
if (sharedMarkerListQualifierEnd !== -1) {
|
|
220
|
+
return sharedMarkerListQualifierEnd;
|
|
221
|
+
}
|
|
222
|
+
const continuedGenericSearchAssertionEnd = findSparkPolicyContinuedGenericSearchAssertionEnd(followingText);
|
|
223
|
+
if (continuedGenericSearchAssertionEnd !== -1) {
|
|
224
|
+
return firstComma + 1 + continuedGenericSearchAssertionEnd;
|
|
225
|
+
}
|
|
226
|
+
return firstComma;
|
|
227
|
+
}
|
|
228
|
+
function findSparkPolicyNextAssertionBoundary(text) {
|
|
229
|
+
const match = SPARK_POLICY_NEXT_ASSERTION_BOUNDARY_PATTERN.exec(text);
|
|
230
|
+
return match?.index ?? -1;
|
|
231
|
+
}
|
|
232
|
+
function findSparkPolicyTrailingFileSearchQualifierEnd(text) {
|
|
233
|
+
const nextComma = text.indexOf(',');
|
|
234
|
+
const assertionBoundary = findSparkPolicyNextAssertionBoundary(text);
|
|
235
|
+
const qualifierEnd = minPositiveIndex(text.length, nextComma, assertionBoundary);
|
|
236
|
+
const qualifier = text.slice(0, qualifierEnd);
|
|
237
|
+
if (/^\s*(?:and\s+)?(?:only\s+)?(?:as|during|for|in|when|while)\b/i.test(qualifier) &&
|
|
238
|
+
SPARK_POLICY_FILE_SEARCH_PATTERN.test(qualifier)) {
|
|
239
|
+
return qualifierEnd;
|
|
240
|
+
}
|
|
241
|
+
return -1;
|
|
242
|
+
}
|
|
243
|
+
function findSparkPolicySharedMarkerListQualifierEnd(text) {
|
|
244
|
+
const fileSearchMatch = SPARK_POLICY_FILE_SEARCH_PATTERN.exec(text);
|
|
245
|
+
if (!fileSearchMatch) {
|
|
246
|
+
return -1;
|
|
247
|
+
}
|
|
248
|
+
const qualifierStart = fileSearchMatch.index;
|
|
249
|
+
const markerListPrefix = text
|
|
250
|
+
.slice(0, qualifierStart)
|
|
251
|
+
.replace(/\s+(?:only\s+)?(?:as|during|for|in|when|while)\s*$/i, '');
|
|
252
|
+
if (!isSparkPolicyMarkerList(markerListPrefix)) {
|
|
253
|
+
return -1;
|
|
254
|
+
}
|
|
255
|
+
const qualifierText = text.slice(qualifierStart);
|
|
256
|
+
const nextComma = qualifierText.indexOf(',');
|
|
257
|
+
const assertionBoundary = findSparkPolicyNextAssertionBoundary(qualifierText);
|
|
258
|
+
return qualifierStart + minPositiveIndex(qualifierText.length, nextComma, assertionBoundary);
|
|
259
|
+
}
|
|
260
|
+
function findSparkPolicyContinuedGenericSearchAssertionEnd(text) {
|
|
261
|
+
const clauseEnd = findNextClauseBoundary(text, 0);
|
|
262
|
+
const nextComma = text.indexOf(',');
|
|
263
|
+
const assertionEnd = minPositiveIndex(clauseEnd, nextComma);
|
|
264
|
+
const assertion = text.slice(0, assertionEnd);
|
|
265
|
+
if (SPARK_POLICY_GENERIC_SCOPE_ASSERTION_PATTERN.test(assertion) &&
|
|
266
|
+
SPARK_POLICY_GENERIC_SEARCH_SCOPE_PATTERN.test(assertion) &&
|
|
267
|
+
!SPARK_POLICY_FILE_SEARCH_PATTERN.test(assertion) &&
|
|
268
|
+
!isRestrictiveSparkPolicyStatement(assertion)) {
|
|
269
|
+
return assertionEnd;
|
|
270
|
+
}
|
|
271
|
+
return -1;
|
|
272
|
+
}
|
|
273
|
+
function isSparkPolicyMarkerList(text) {
|
|
274
|
+
const markers = text
|
|
275
|
+
.trim()
|
|
276
|
+
.replace(/\s*,\s*(?:and|or)\s+/gi, ',')
|
|
277
|
+
.replace(/\s+(?:and|or)\s+/gi, ',')
|
|
278
|
+
.split(/\s*,\s*/)
|
|
279
|
+
.filter((marker) => marker.length > 0);
|
|
280
|
+
return markers.length > 1 && markers.every((marker) => isBareSparkPolicyMarkerWindow(marker));
|
|
281
|
+
}
|
|
282
|
+
function findSparkPolicyPreviousAssertionPrefixEnd(text) {
|
|
283
|
+
const policyVerbMatch = /\s+\b(?:and|but|or|while|whereas)\b\s+((?:(?:can|could|may|might|must|should)\s+)?(?:allow(?:ed|s|ing)?|choos(?:e|es|ing)|confin(?:e|ed|es|ing)|constrain(?:ed|s|ing)?|keep(?:s|ing)?|leav(?:e|es|ing)|limit(?:ed|s|ing)?|mak(?:e|es|ing)|permit(?:s|ted|ting)?|prefer(?:s|ring)?|reserv(?:e|ed|es|ing)|restrict(?:ed|s|ing)?|rout(?:e|ed|es|ing)|run(?:s|ning)?|scop(?:e|ed|es|ing)|select(?:s|ing)?|support(?:ed|s|ing)?|us(?:e|ed|es|ing))\s+(?:(?:the|a|an)\s+)?[`*_]*)$/i.exec(text);
|
|
284
|
+
if (policyVerbMatch) {
|
|
285
|
+
return policyVerbMatch.index + policyVerbMatch[0].length - policyVerbMatch[1].length;
|
|
286
|
+
}
|
|
287
|
+
const match = /\s+\b(?:and|but|or|while|whereas)\b\s+(?:(?:the|a|an)\s+)?[`*_]*$/i.exec(text);
|
|
288
|
+
return match ? match.index + match[0].length : 0;
|
|
289
|
+
}
|
|
290
|
+
function minPositiveIndex(fallback, ...indexes) {
|
|
291
|
+
return indexes.filter((index) => index >= 0).reduce((min, index) => Math.min(min, index), fallback);
|
|
292
|
+
}
|
|
293
|
+
function isBareSparkPolicyMarkerWindow(text) {
|
|
294
|
+
const normalized = text
|
|
295
|
+
.replace(/[`*]/g, '')
|
|
296
|
+
.replace(/(^|[^A-Za-z0-9])_+(?=[A-Za-z0-9])/g, '$1')
|
|
297
|
+
.replace(/([A-Za-z0-9])_+(?=$|[^A-Za-z0-9])/g, '$1')
|
|
298
|
+
.replace(/\s+/g, ' ')
|
|
299
|
+
.trim()
|
|
300
|
+
.toLowerCase();
|
|
301
|
+
return /^(?:(?:the|a|an)\s+)?(?:spark(?:\s+roles?)?|explorer_fast(?:\s+(?:roles?|agents?|models?))?|gpt-5\.3-codex-spark(?:\s+(?:roles?|agents?|models?))?)$/.test(normalized);
|
|
302
|
+
}
|
|
303
|
+
function isRestrictiveSparkPolicyStatement(relevantText) {
|
|
304
|
+
return (/\b(?:do not|don't|must not|should not|cannot|can't|never)\b/i.test(relevantText) ||
|
|
305
|
+
/\bnot\s+(?:available\s+for|for|intended\s+for|to\s+be\s+used\s+for|used\s+for)\b/i.test(relevantText) ||
|
|
306
|
+
SPARK_POLICY_NON_SPARK_REDIRECT_PATTERN.test(relevantText) ||
|
|
307
|
+
SPARK_POLICY_DISABLED_NON_USE_PATTERN.test(relevantText) ||
|
|
308
|
+
SPARK_POLICY_WITHOUT_FORBIDDEN_SCOPE_PATTERN.test(relevantText) ||
|
|
309
|
+
/\bno\s+(?:broad\s+exploration|exploration|implementation|planning|review|search\/synthesis|synthesis)\b/i.test(relevantText));
|
|
310
|
+
}
|
|
311
|
+
function hasUnqualifiedActiveUseAfterDisabledNonUse(relevantText) {
|
|
312
|
+
const disabledPattern = new RegExp(SPARK_POLICY_DISABLED_NON_USE_PATTERN.source, 'gi');
|
|
313
|
+
for (const disabledMatch of relevantText.matchAll(disabledPattern)) {
|
|
314
|
+
const tail = relevantText.slice((disabledMatch.index ?? 0) + disabledMatch[0].length);
|
|
315
|
+
const disabledTailClause = tail.slice(0, findNextClauseBoundary(tail, 0));
|
|
316
|
+
const disabledTailSearchScopeMatch = SPARK_POLICY_DISABLED_GENERIC_SEARCH_SCOPE_PATTERN.exec(disabledTailClause);
|
|
317
|
+
if (disabledTailSearchScopeMatch &&
|
|
318
|
+
!isNegatedSparkGenericSearchScope(disabledTailClause, disabledTailSearchScopeMatch.index ?? 0) &&
|
|
319
|
+
!SPARK_POLICY_FILE_SEARCH_PATTERN.test(disabledTailClause)) {
|
|
320
|
+
return true;
|
|
321
|
+
}
|
|
322
|
+
for (const activeUseMatch of tail.matchAll(SPARK_POLICY_DISABLED_ACTIVE_USE_PATTERN)) {
|
|
323
|
+
if (isNegatedSparkActiveUse(tail, activeUseMatch)) {
|
|
324
|
+
continue;
|
|
325
|
+
}
|
|
326
|
+
const activeText = tail.slice(activeUseMatch.index ?? 0);
|
|
327
|
+
const activeClause = activeText.slice(0, findNextClauseBoundary(activeText, 0));
|
|
328
|
+
if (SPARK_POLICY_NON_SPARK_REDIRECT_PATTERN.test(activeClause)) {
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
331
|
+
if ((SPARK_POLICY_GENERIC_SEARCH_SCOPE_PATTERN.test(activeClause) ||
|
|
332
|
+
hasNonFileSparkScopeAssertion(activeClause)) &&
|
|
333
|
+
!SPARK_POLICY_FILE_SEARCH_PATTERN.test(activeClause)) {
|
|
334
|
+
return true;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
return false;
|
|
339
|
+
}
|
|
340
|
+
function isNegatedSparkGenericSearchScope(text, matchIndex) {
|
|
341
|
+
const immediatePrefix = text.slice(Math.max(0, matchIndex - 40), matchIndex);
|
|
342
|
+
return /\b(?:do not|don't|must not|should not|can(?:not|'t| not)|never|not|no|without)\s+(?:(?:be|being)\s+)?$/i.test(immediatePrefix);
|
|
343
|
+
}
|
|
344
|
+
function hasNonFileSparkScopeAssertion(text) {
|
|
345
|
+
return (/\b(?:(?:image|visual)\s+(?:analysis|generation|inputs?|inspection|outputs?|processing|reasoning|review|tasks?|understanding|work)|text[- ]only)\b/i.test(text) ||
|
|
346
|
+
new RegExp(SPARK_POLICY_FORBIDDEN_USAGE_PATTERN.source, 'i').test(text));
|
|
347
|
+
}
|
|
348
|
+
function isNegatedSparkActiveUse(text, activeUseMatch) {
|
|
349
|
+
const activeStart = activeUseMatch.index ?? 0;
|
|
350
|
+
const immediatePrefix = text.slice(Math.max(0, activeStart - 40), activeStart);
|
|
351
|
+
return /\b(?:do not|don't|must not|should not|can(?:not|'t| not)|never|not|no)\s+(?:(?:be|being)\s+)?$/i.test(immediatePrefix);
|
|
352
|
+
}
|
|
353
|
+
function hasUnqualifiedLaterSparkScopeAssertion(markerWindow) {
|
|
354
|
+
const fileSearchMatch = SPARK_POLICY_FILE_SEARCH_PATTERN.exec(markerWindow);
|
|
355
|
+
if (!fileSearchMatch) {
|
|
356
|
+
return false;
|
|
357
|
+
}
|
|
358
|
+
const separatorPattern = /\s+\b(?:and|or|but|while|whereas)\b\s+/gi;
|
|
359
|
+
const separators = [...markerWindow.matchAll(separatorPattern)];
|
|
360
|
+
const assertionRanges = [
|
|
361
|
+
{ start: 0, end: separators[0]?.index ?? markerWindow.length },
|
|
362
|
+
...separators.map((separator, index) => ({
|
|
363
|
+
start: separator.index ?? 0,
|
|
364
|
+
end: separators[index + 1]?.index ?? markerWindow.length
|
|
365
|
+
}))
|
|
366
|
+
];
|
|
367
|
+
for (const { start, end } of assertionRanges) {
|
|
368
|
+
const assertion = markerWindow.slice(start, end);
|
|
369
|
+
if (SPARK_POLICY_GENERIC_SCOPE_ASSERTION_PATTERN.test(assertion) &&
|
|
370
|
+
(SPARK_POLICY_GENERIC_SEARCH_SCOPE_PATTERN.test(assertion) || hasNonFileSparkScopeAssertion(assertion)) &&
|
|
371
|
+
!SPARK_POLICY_FILE_SEARCH_PATTERN.test(assertion) &&
|
|
372
|
+
!isRestrictiveSparkPolicyStatement(assertion)) {
|
|
373
|
+
return true;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
return false;
|
|
377
|
+
}
|
|
378
|
+
function hasOverbroadSparkUsage(relevantText) {
|
|
379
|
+
for (const match of relevantText.matchAll(SPARK_POLICY_FORBIDDEN_USAGE_PATTERN)) {
|
|
380
|
+
if (!isRestrictiveSparkUsageMention(relevantText, match.index ?? 0)) {
|
|
381
|
+
return true;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
return false;
|
|
385
|
+
}
|
|
386
|
+
function hasNegatedSparkFileSearchScope(relevantText) {
|
|
387
|
+
return (/\bnot\s+(?:exclusively|just|limited(?:\s+to)?|only|solely)\b/i.test(relevantText) &&
|
|
388
|
+
SPARK_POLICY_FILE_SEARCH_PATTERN.test(relevantText));
|
|
389
|
+
}
|
|
390
|
+
function isRestrictiveSparkUsageMention(relevantText, mentionIndex) {
|
|
391
|
+
const clauseStart = findLastClauseBoundary(relevantText, mentionIndex);
|
|
392
|
+
const clauseEnd = findNextClauseBoundary(relevantText, mentionIndex);
|
|
393
|
+
const clausePrefix = relevantText.slice(clauseStart, mentionIndex).toLowerCase();
|
|
394
|
+
const clauseSuffix = relevantText.slice(mentionIndex, clauseEnd).toLowerCase();
|
|
395
|
+
const localClausePrefix = sliceAfterLastContrast(clausePrefix);
|
|
396
|
+
const localClause = `${localClausePrefix}${clauseSuffix}`;
|
|
397
|
+
if (/\b(?:use|prefer|choose|select|route|run)\s+(?:a\s+|an\s+)?(?:non-spark|non\s+spark|alternate|alternative|different|other)\s+(?:roles?|agents?|models?)\b/.test(localClausePrefix)) {
|
|
398
|
+
return true;
|
|
399
|
+
}
|
|
400
|
+
if (/\bnot\s+(?:exclusively|just|limited\b|limited\s+to|only|solely)\b/.test(localClausePrefix)) {
|
|
401
|
+
return false;
|
|
402
|
+
}
|
|
403
|
+
if (/\b(?:do not|don't|must not|should not|cannot|can't|never|not|no)\b/.test(localClausePrefix) ||
|
|
404
|
+
SPARK_POLICY_WITHOUT_FORBIDDEN_SCOPE_PATTERN.test(localClause)) {
|
|
405
|
+
return true;
|
|
406
|
+
}
|
|
407
|
+
return hasSuffixRestrictionForSparkUsage(localClausePrefix, clauseSuffix);
|
|
408
|
+
}
|
|
409
|
+
function buildSparkPolicyLineContext(lines, lineIndex, markerIndex) {
|
|
410
|
+
const currentLine = lines[lineIndex] ?? '';
|
|
411
|
+
const startLine = findSparkPolicyContextStartLine(lines, lineIndex);
|
|
412
|
+
const parts = [];
|
|
413
|
+
let adjustedMarkerIndex = markerIndex;
|
|
414
|
+
for (let index = startLine; index < lineIndex; index += 1) {
|
|
415
|
+
const previousPart = (lines[index] ?? '').trim();
|
|
416
|
+
parts.push(previousPart);
|
|
417
|
+
adjustedMarkerIndex += previousPart.length + 1;
|
|
418
|
+
}
|
|
419
|
+
parts.push(currentLine.trimEnd());
|
|
420
|
+
for (let index = lineIndex + 1; index < lines.length; index += 1) {
|
|
421
|
+
const nextLine = lines[index] ?? '';
|
|
422
|
+
if (isSparkPolicyLineContextBoundary(nextLine)) {
|
|
423
|
+
break;
|
|
424
|
+
}
|
|
425
|
+
parts.push(nextLine.trim());
|
|
426
|
+
}
|
|
427
|
+
return {
|
|
428
|
+
text: parts.join(' '),
|
|
429
|
+
markerIndex: adjustedMarkerIndex
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
function isSparkPolicyLineContextBoundary(line) {
|
|
433
|
+
return isSparkPolicyHardContextBoundary(line) || isSparkPolicyListItemLine(line);
|
|
434
|
+
}
|
|
435
|
+
function findSparkPolicyContextStartLine(lines, lineIndex) {
|
|
436
|
+
let startLine = lineIndex;
|
|
437
|
+
while (startLine > 0) {
|
|
438
|
+
const previousLine = lines[startLine - 1] ?? '';
|
|
439
|
+
const currentLine = lines[startLine] ?? '';
|
|
440
|
+
if (isSparkPolicyHardContextBoundary(previousLine) || isSparkPolicyListItemLine(currentLine)) {
|
|
441
|
+
break;
|
|
442
|
+
}
|
|
443
|
+
startLine -= 1;
|
|
444
|
+
if (isSparkPolicyListItemLine(previousLine)) {
|
|
445
|
+
break;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
return startLine;
|
|
449
|
+
}
|
|
450
|
+
function isSparkPolicyHardContextBoundary(line) {
|
|
451
|
+
const trimmed = line.trim();
|
|
452
|
+
return trimmed.length === 0 || /^(?:#{1,6}\s+|>\s+|```|~~~|\|)/.test(trimmed);
|
|
453
|
+
}
|
|
454
|
+
function isSparkPolicyListItemLine(line) {
|
|
455
|
+
return /^\s*(?:[-*+]\s+|\d+\.\s+)/.test(line);
|
|
456
|
+
}
|
|
457
|
+
function sliceAfterLastContrast(text) {
|
|
458
|
+
let lastContrastEnd = 0;
|
|
459
|
+
for (const match of text.matchAll(/\b(?:but|except|unless)\b/gi)) {
|
|
460
|
+
lastContrastEnd = (match.index ?? 0) + match[0].length;
|
|
461
|
+
}
|
|
462
|
+
return lastContrastEnd === 0 ? text : text.slice(lastContrastEnd);
|
|
463
|
+
}
|
|
464
|
+
function hasSuffixRestrictionForSparkUsage(clausePrefix, clauseSuffix) {
|
|
465
|
+
const restrictionMatch = SPARK_POLICY_SUFFIX_RESTRICTION_PATTERN.exec(clauseSuffix);
|
|
466
|
+
if (!restrictionMatch) {
|
|
467
|
+
return false;
|
|
468
|
+
}
|
|
469
|
+
const prefixBeforeRestriction = clauseSuffix.slice(0, restrictionMatch.index);
|
|
470
|
+
if (/\b(?:but|except|unless)\b/.test(prefixBeforeRestriction)) {
|
|
471
|
+
return false;
|
|
472
|
+
}
|
|
473
|
+
return isFrontedSparkRestrictionScope(`${clausePrefix}${prefixBeforeRestriction}`);
|
|
474
|
+
}
|
|
475
|
+
function isFrontedSparkRestrictionScope(prefixBeforeRestriction) {
|
|
476
|
+
const normalized = prefixBeforeRestriction
|
|
477
|
+
.replace(/[`*_]/g, '')
|
|
478
|
+
.replace(/^\s*[-+]\s+/, '')
|
|
479
|
+
.replace(/\s+/g, ' ')
|
|
480
|
+
.trim()
|
|
481
|
+
.toLowerCase();
|
|
482
|
+
const frontedScope = normalized.replace(/^(?:for|when|while|during)\s+/, '');
|
|
483
|
+
return isSparkForbiddenScopeList(frontedScope);
|
|
484
|
+
}
|
|
485
|
+
function isSparkForbiddenScopeList(scopeText) {
|
|
486
|
+
return /^(?:(?:broad exploration|exploration|implementation|planning|review|search\/synthesis|synthesis)(?:\s+tasks?)?\s*(?:,|\/|and|or)?\s*)+$/.test(scopeText);
|
|
487
|
+
}
|
|
488
|
+
function findLastClauseBoundary(text, beforeIndex) {
|
|
489
|
+
const boundary = Math.max(text.lastIndexOf('.', beforeIndex), text.lastIndexOf(';', beforeIndex), text.lastIndexOf('!', beforeIndex), text.lastIndexOf('?', beforeIndex));
|
|
490
|
+
return boundary === -1 ? 0 : boundary + 1;
|
|
491
|
+
}
|
|
492
|
+
function findNextClauseBoundary(text, afterIndex) {
|
|
493
|
+
for (let index = afterIndex; index < text.length; index += 1) {
|
|
494
|
+
const char = text[index];
|
|
495
|
+
if (char === ';' || char === '!' || char === '?') {
|
|
496
|
+
return index;
|
|
497
|
+
}
|
|
498
|
+
if (char === '.' && !isInternalClausePeriod(text, index)) {
|
|
499
|
+
return index;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
return text.length;
|
|
503
|
+
}
|
|
504
|
+
function isInternalClausePeriod(text, index) {
|
|
505
|
+
const previous = text[index - 1] ?? '';
|
|
506
|
+
const next = text[index + 1] ?? '';
|
|
507
|
+
return /[A-Za-z0-9]/.test(previous) && /[A-Za-z0-9]/.test(next);
|
|
508
|
+
}
|
|
509
|
+
function findSparkPolicyMarkerIndexes(line) {
|
|
510
|
+
const markers = [/explorer_fast/i, /gpt-5\.3-codex-spark/i];
|
|
511
|
+
const indexes = markers
|
|
512
|
+
.flatMap((marker) => [...line.matchAll(new RegExp(marker.source, `${marker.flags}g`))].map((match) => match.index ?? -1))
|
|
513
|
+
.filter((index) => index >= 0);
|
|
514
|
+
indexes.push(...findSparkWordPolicyMarkerIndexes(line));
|
|
515
|
+
return [...new Set(indexes)].sort((a, b) => a - b);
|
|
516
|
+
}
|
|
517
|
+
function findSparkWordPolicyMarkerIndexes(line) {
|
|
518
|
+
const indexes = [];
|
|
519
|
+
for (const match of line.matchAll(/\bspark\b/gi)) {
|
|
520
|
+
const index = match.index ?? -1;
|
|
521
|
+
const prefix = line.slice(Math.max(0, index - 4), index).toLowerCase();
|
|
522
|
+
if (prefix === 'non-' || prefix === 'non ') {
|
|
523
|
+
continue;
|
|
524
|
+
}
|
|
525
|
+
indexes.push(index);
|
|
526
|
+
}
|
|
527
|
+
return indexes;
|
|
528
|
+
}
|
|
529
|
+
function isNeutralSparkPolicyReference(text, markerIndex) {
|
|
530
|
+
const clauseEnd = findNextClauseBoundary(text, markerIndex);
|
|
531
|
+
const afterSpark = sliceAfterSparkPolicyMarker(text, markerIndex, clauseEnd);
|
|
532
|
+
const policyMatch = /^\s*[- ]?polic(?:y|ies)\b/i.exec(afterSpark);
|
|
533
|
+
if (!policyMatch) {
|
|
534
|
+
return false;
|
|
535
|
+
}
|
|
536
|
+
const afterPolicy = afterSpark.slice(policyMatch[0].length);
|
|
537
|
+
const localAfterPolicy = afterPolicy.slice(0, minPositiveIndex(afterPolicy.length, afterPolicy.indexOf(','), findSparkPolicyNextAssertionBoundary(afterPolicy)));
|
|
538
|
+
const assertionText = localAfterPolicy.replace(SPARK_POLICY_NEUTRAL_MAINTENANCE_PHRASE_PATTERN, '');
|
|
539
|
+
return (!new RegExp(SPARK_POLICY_FORBIDDEN_USAGE_PATTERN.source, 'i').test(assertionText) &&
|
|
540
|
+
!SPARK_POLICY_GENERIC_SEARCH_SCOPE_PATTERN.test(assertionText) &&
|
|
541
|
+
!hasNonFileSparkScopeAssertion(assertionText) &&
|
|
542
|
+
!/\benabl(?:e|ed|es|ing)\b/i.test(assertionText));
|
|
543
|
+
}
|
|
544
|
+
function isNeutralSparkSupportMaintenanceReference(text, markerIndex) {
|
|
545
|
+
const clauseEnd = findNextClauseBoundary(text, markerIndex);
|
|
546
|
+
const afterSpark = sliceAfterSparkPolicyMarker(text, markerIndex, clauseEnd);
|
|
547
|
+
const supportMaintenanceMatch = SPARK_POLICY_SUPPORT_MAINTENANCE_REFERENCE_PATTERN.exec(afterSpark);
|
|
548
|
+
if (!supportMaintenanceMatch) {
|
|
549
|
+
return false;
|
|
550
|
+
}
|
|
551
|
+
const afterSupportMaintenance = afterSpark.slice(supportMaintenanceMatch[0].length);
|
|
552
|
+
return (SPARK_POLICY_SUPPORT_MAINTENANCE_TAIL_PATTERN.test(afterSupportMaintenance) &&
|
|
553
|
+
!hasSparkPolicyAssertionText(afterSupportMaintenance));
|
|
554
|
+
}
|
|
555
|
+
function sliceAfterSparkPolicyMarker(text, markerIndex, clauseEnd) {
|
|
556
|
+
const markerText = text.slice(markerIndex, clauseEnd);
|
|
557
|
+
const markerMatch = SPARK_POLICY_MARKER_AT_START_PATTERN.exec(markerText);
|
|
558
|
+
if (!markerMatch) {
|
|
559
|
+
return text.slice(markerIndex + 'spark'.length, clauseEnd);
|
|
560
|
+
}
|
|
561
|
+
return markerText.slice(markerMatch[0].length);
|
|
562
|
+
}
|
|
563
|
+
function hasNeutralSparkPolicyContinuationAssertion(text, markerIndex) {
|
|
564
|
+
const clauseEnd = findNextClauseBoundary(text, markerIndex);
|
|
565
|
+
const afterSpark = sliceAfterSparkPolicyMarker(text, markerIndex, clauseEnd);
|
|
566
|
+
const policyMatch = /^\s*[- ]?polic(?:y|ies)\b/i.exec(afterSpark);
|
|
567
|
+
if (!policyMatch) {
|
|
568
|
+
return false;
|
|
569
|
+
}
|
|
570
|
+
const afterPolicy = afterSpark.slice(policyMatch[0].length);
|
|
571
|
+
const localEnd = minPositiveIndex(afterPolicy.length, afterPolicy.indexOf(','), findSparkPolicyNextAssertionBoundary(afterPolicy));
|
|
572
|
+
const continuation = afterPolicy.slice(localEnd);
|
|
573
|
+
return (hasSparkPolicyAssertionText(continuation) ||
|
|
574
|
+
hasNeutralSparkPolicyPostClauseAssertion(text.slice(clauseEnd)));
|
|
575
|
+
}
|
|
576
|
+
function hasSparkPolicyAssertionText(text) {
|
|
577
|
+
return (new RegExp(SPARK_POLICY_FORBIDDEN_USAGE_PATTERN.source, 'i').test(text) ||
|
|
578
|
+
SPARK_POLICY_GENERIC_SEARCH_SCOPE_PATTERN.test(text) ||
|
|
579
|
+
hasNonFileSparkScopeAssertion(text) ||
|
|
580
|
+
/\benabl(?:e|ed|es|ing)\b/i.test(text));
|
|
581
|
+
}
|
|
582
|
+
function hasNeutralSparkPolicyPostClauseAssertion(text) {
|
|
583
|
+
const tail = text.replace(/^\s*[;.!?]\s*/, '').trim();
|
|
584
|
+
if (tail.length === 0) {
|
|
585
|
+
return false;
|
|
586
|
+
}
|
|
587
|
+
const firstClause = tail.slice(0, findNextClauseBoundary(tail, 0)).trim();
|
|
588
|
+
const assertionCandidate = firstClause
|
|
589
|
+
.replace(/^(?:and|but|or|then)\s+/i, '')
|
|
590
|
+
.replace(/^(?:(?:it|this|that|the\s+(?:spark\s+)?polic(?:y|ies))\s+)/i, '');
|
|
591
|
+
return (SPARK_POLICY_NEUTRAL_ASSERTION_LEAD_PATTERN.test(assertionCandidate) &&
|
|
592
|
+
hasSparkPolicyAssertionText(assertionCandidate));
|
|
593
|
+
}
|