@iaforged/context-code 2.1.5 → 2.1.7
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/src/Task.js +1 -1
- package/dist/src/commands/add-dir/add-dir.js +1 -1
- package/dist/src/commands/add-dir/validation.js +1 -1
- package/dist/src/constants/oauth.js +1 -1
- package/dist/src/context/mailbox.js +1 -1
- package/dist/src/context/voice.js +1 -1
- package/dist/src/hooks/useTerminalSize.js +1 -1
- package/dist/src/ink/Ansi.js +1 -1
- package/dist/src/ink/clearTerminal.js +1 -1
- package/dist/src/ink/colorize.js +1 -1
- package/dist/src/ink/components/App.js +1 -1
- package/dist/src/ink/components/Button.js +1 -1
- package/dist/src/ink/components/ClockContext.js +1 -1
- package/dist/src/ink/components/CursorDeclarationContext.js +1 -1
- package/dist/src/ink/components/Link.js +1 -1
- package/dist/src/ink/components/StdinContext.js +1 -1
- package/dist/src/ink/components/TerminalFocusContext.js +1 -1
- package/dist/src/ink/dom.js +1 -1
- package/dist/src/ink/events/keyboard-event.js +1 -1
- package/dist/src/ink/hit-test.js +1 -1
- package/dist/src/ink/hooks/use-animation-frame.js +1 -1
- package/dist/src/ink/hooks/use-app.js +1 -1
- package/dist/src/ink/hooks/use-input.js +1 -1
- package/dist/src/ink/hooks/use-interval.js +1 -1
- package/dist/src/ink/hooks/use-selection.js +1 -1
- package/dist/src/ink/hooks/use-tab-status.js +1 -1
- package/dist/src/ink/hooks/use-terminal-focus.js +1 -1
- package/dist/src/ink/hooks/use-terminal-title.js +1 -1
- package/dist/src/ink/hooks/use-terminal-viewport.js +1 -1
- package/dist/src/ink/ink.js +1 -1
- package/dist/src/ink/layout/yoga.js +1 -1
- package/dist/src/ink/line-width-cache.js +1 -1
- package/dist/src/ink/log-update.js +1 -1
- package/dist/src/ink/measure-text.js +1 -1
- package/dist/src/ink/output.js +1 -1
- package/dist/src/ink/parse-keypress.js +1 -1
- package/dist/src/ink/reconciler.js +1 -1
- package/dist/src/ink/render-border.js +1 -1
- package/dist/src/ink/render-node-to-output.js +1 -1
- package/dist/src/ink/render-to-screen.js +1 -1
- package/dist/src/ink/renderer.js +1 -1
- package/dist/src/ink/root.js +1 -1
- package/dist/src/ink/screen.js +1 -1
- package/dist/src/ink/searchHighlight.js +1 -1
- package/dist/src/ink/selection.js +1 -1
- package/dist/src/ink/squash-text-nodes.js +1 -1
- package/dist/src/ink/stringWidth.js +1 -1
- package/dist/src/ink/tabstops.js +1 -1
- package/dist/src/ink/terminal.js +1 -1
- package/dist/src/ink/termio/osc.js +1 -1
- package/dist/src/ink/termio/parser.js +1 -1
- package/dist/src/ink/termio/tokenize.js +1 -1
- package/dist/src/ink/useTerminalNotification.js +1 -1
- package/dist/src/ink/warn.js +1 -1
- package/dist/src/ink/widest-line.js +1 -1
- package/dist/src/ink/wrap-text.js +1 -1
- package/dist/src/ink/wrapAnsi.js +1 -1
- package/dist/src/native-ts/yoga-layout/index.js +1 -1
- package/dist/src/schemas/hooks.js +1 -1
- package/dist/src/services/SessionMemory/sessionMemoryUtils.js +1 -1
- package/dist/src/services/api/client.js +1 -1
- package/dist/src/services/api/dumpPrompts.js +1 -1
- package/dist/src/services/api/errorUtils.js +1 -1
- package/dist/src/services/api/promptCacheBreakDetection.js +1 -1
- package/dist/src/services/api/withRetry.js +1 -1
- package/dist/src/services/autoDream/consolidationLock.js +1 -1
- package/dist/src/services/mcp/elicitationHandler.js +1 -1
- package/dist/src/services/mcp/mcpStringUtils.js +1 -1
- package/dist/src/services/mcp/oauthPort.js +1 -1
- package/dist/src/services/mcp/vscodeSdkMcp.js +1 -1
- package/dist/src/services/oauth/client.js +1 -1
- package/dist/src/services/oauth/getOauthProfile.js +1 -1
- package/dist/src/services/objetivo/types.js +1 -1
- package/dist/src/services/rateLimitMocking.js +1 -1
- package/dist/src/services/remoteManagedSettings/syncCacheState.js +1 -1
- package/dist/src/skills/bundledSkills.js +1 -1
- package/dist/src/tasks/DreamTask/DreamTask.js +1 -1
- package/dist/src/tools/AgentTool/agentMemory.js +1 -1
- package/dist/src/tools/AgentTool/forkSubagent.js +1 -1
- package/dist/src/tools/BashTool/BashToolResultMessage.js +1 -1
- package/dist/src/tools/BashTool/UI.js +1 -1
- package/dist/src/tools/BashTool/sedEditParser.js +1 -1
- package/dist/src/tools/BashTool/utils.js +1 -1
- package/dist/src/tools/FileReadTool/imageProcessor.js +1 -1
- package/dist/src/tools/FileReadTool/prompt.js +1 -1
- package/dist/src/tools/ListMcpResourcesTool/ListMcpResourcesTool.js +1 -1
- package/dist/src/tools/ListMcpResourcesTool/UI.js +1 -1
- package/dist/src/tools/MCPTool/MCPTool.js +1 -1
- package/dist/src/tools/MCPTool/UI.js +1 -1
- package/dist/src/tools/McpAuthTool/McpAuthTool.js +1 -1
- package/dist/src/tools/NotebookEditTool/prompt.js +1 -1
- package/dist/src/tools/PowerShellTool/PowerShellTool.js +1 -1
- package/dist/src/tools/PowerShellTool/UI.js +1 -1
- package/dist/src/tools/PowerShellTool/gitSafety.js +1 -1
- package/dist/src/tools/PowerShellTool/modeValidation.js +1 -1
- package/dist/src/tools/PowerShellTool/pathValidation.js +1 -1
- package/dist/src/tools/PowerShellTool/powershellPermissions.js +1 -1
- package/dist/src/tools/PowerShellTool/powershellSecurity.js +1 -1
- package/dist/src/tools/PowerShellTool/prompt.js +1 -1
- package/dist/src/tools/PowerShellTool/readOnlyValidation.js +1 -1
- package/dist/src/tools/REPLTool/constants.js +1 -1
- package/dist/src/tools/REPLTool/primitiveTools.js +1 -1
- package/dist/src/tools/ReadMcpResourceTool/ReadMcpResourceTool.js +1 -1
- package/dist/src/tools/ReadMcpResourceTool/UI.js +1 -1
- package/dist/src/tools/ScheduleCronTool/prompt.js +1 -1
- package/dist/src/tools/SkillTool/prompt.js +1 -1
- package/dist/src/tools/TodoWriteTool/TodoWriteTool.js +1 -1
- package/dist/src/tools/ToolSearchTool/prompt.js +1 -1
- package/dist/src/tools/WebSearchTool/prompt.js +1 -1
- package/dist/src/tools/shared/gitOperationTracking.js +1 -1
- package/dist/src/types/permissions.js +1 -1
- package/dist/src/utils/Cursor.js +1 -1
- package/dist/src/utils/QueryGuard.js +1 -1
- package/dist/src/utils/Shell.js +1 -1
- package/dist/src/utils/ShellCommand.js +1 -1
- package/dist/src/utils/activityManager.js +1 -1
- package/dist/src/utils/advisor.js +1 -1
- package/dist/src/utils/appleTerminalBackup.js +1 -1
- package/dist/src/utils/argumentSubstitution.js +1 -1
- package/dist/src/utils/authFileDescriptor.js +1 -1
- package/dist/src/utils/autoUpdater.js +1 -1
- package/dist/src/utils/background/remote/preconditions.js +1 -1
- package/dist/src/utils/background/remote/remoteSession.js +1 -1
- package/dist/src/utils/bash/ShellSnapshot.js +1 -1
- package/dist/src/utils/bash/ast.js +1 -1
- package/dist/src/utils/bash/bashParser.js +1 -1
- package/dist/src/utils/bash/bashPipeCommand.js +1 -1
- package/dist/src/utils/bash/parser.js +1 -1
- package/dist/src/utils/bash/shellQuote.js +1 -1
- package/dist/src/utils/bash/shellQuoting.js +1 -1
- package/dist/src/utils/billing.js +1 -1
- package/dist/src/utils/caCerts.js +1 -1
- package/dist/src/utils/claudeInChrome/common.js +1 -1
- package/dist/src/utils/claudeInChrome/setupPortable.js +1 -1
- package/dist/src/utils/claudemd.js +1 -1
- package/dist/src/utils/collapseBackgroundBashNotifications.js +1 -1
- package/dist/src/utils/collapseReadSearch.js +1 -1
- package/dist/src/utils/completionCache.js +1 -1
- package/dist/src/utils/computerUse/common.js +1 -1
- package/dist/src/utils/concurrentSessions.js +1 -1
- package/dist/src/utils/context.js +1 -1
- package/dist/src/utils/cron.js +1 -1
- package/dist/src/utils/cronTasks.js +1 -1
- package/dist/src/utils/cwd.js +1 -1
- package/dist/src/utils/debug.js +1 -1
- package/dist/src/utils/debugFilter.js +1 -1
- package/dist/src/utils/detectRepository.js +1 -1
- package/dist/src/utils/diagLogs.js +1 -1
- package/dist/src/utils/diff.js +1 -1
- package/dist/src/utils/directMemberMessage.js +1 -1
- package/dist/src/utils/doctorDiagnostic.js +1 -1
- package/dist/src/utils/dxt/helpers.js +1 -1
- package/dist/src/utils/dxt/zip.js +1 -1
- package/dist/src/utils/earlyInput.js +1 -1
- package/dist/src/utils/editor.js +1 -1
- package/dist/src/utils/effort.js +1 -1
- package/dist/src/utils/embeddedTools.js +1 -1
- package/dist/src/utils/envDynamic.js +1 -1
- package/dist/src/utils/envUtils.js +1 -1
- package/dist/src/utils/execFileNoThrowPortable.js +1 -1
- package/dist/src/utils/execSyncWrapper.js +1 -1
- package/dist/src/utils/exportRenderer.js +1 -1
- package/dist/src/utils/extraUsage.js +1 -1
- package/dist/src/utils/fastMode.js +1 -1
- package/dist/src/utils/fileOperationAnalytics.js +1 -1
- package/dist/src/utils/fileRead.js +1 -1
- package/dist/src/utils/findExecutable.js +1 -1
- package/dist/src/utils/format.js +1 -1
- package/dist/src/utils/frontmatterParser.js +1 -1
- package/dist/src/utils/fsOperations.js +1 -1
- package/dist/src/utils/fullscreen.js +1 -1
- package/dist/src/utils/genericProcessUtils.js +1 -1
- package/dist/src/utils/getWorktreePaths.js +1 -1
- package/dist/src/utils/git/gitConfigParser.js +1 -1
- package/dist/src/utils/git/gitFilesystem.js +1 -1
- package/dist/src/utils/git/gitignore.js +1 -1
- package/dist/src/utils/gitDiff.js +1 -1
- package/dist/src/utils/gitSettings.js +1 -1
- package/dist/src/utils/glob.js +1 -1
- package/dist/src/utils/gracefulShutdown.js +1 -1
- package/dist/src/utils/groupToolUses.js +1 -1
- package/dist/src/utils/handlePromptSubmit.js +1 -1
- package/dist/src/utils/hash.js +1 -1
- package/dist/src/utils/hooks/fileChangedWatcher.js +1 -1
- package/dist/src/utils/hooks/hooksSettings.js +1 -1
- package/dist/src/utils/hooks/registerSkillHooks.js +1 -1
- package/dist/src/utils/hooks/sessionHooks.js +1 -1
- package/dist/src/utils/http.js +1 -1
- package/dist/src/utils/hyperlink.js +1 -1
- package/dist/src/utils/ide.js +1 -1
- package/dist/src/utils/idePathConversion.js +1 -1
- package/dist/src/utils/imagePaste.js +1 -1
- package/dist/src/utils/imageResizer.js +1 -1
- package/dist/src/utils/imageStore.js +1 -1
- package/dist/src/utils/inProcessTeammateHelpers.js +1 -1
- package/dist/src/utils/ink.js +1 -1
- package/dist/src/utils/jetbrains.js +1 -1
- package/dist/src/utils/json.js +1 -1
- package/dist/src/utils/listSessionsImpl.js +1 -1
- package/dist/src/utils/localInstaller.js +1 -1
- package/dist/src/utils/lockfile.js +1 -1
- package/dist/src/utils/logoV2Utils.js +1 -1
- package/dist/src/utils/markdown.js +1 -1
- package/dist/src/utils/mcp/dateTimeParser.js +1 -1
- package/dist/src/utils/mcpOutputStorage.js +1 -1
- package/dist/src/utils/mcpValidation.js +1 -1
- package/dist/src/utils/memoize.js +1 -1
- package/dist/src/utils/memory/types.js +1 -1
- package/dist/src/utils/memoryFileDetection.js +1 -1
- package/dist/src/utils/messageQueueManager.js +1 -1
- package/dist/src/utils/messages/mappers.js +1 -1
- package/dist/src/utils/messages/systemInit.js +1 -1
- package/dist/src/utils/model/antModels.js +1 -1
- package/dist/src/utils/model/check1mAccess.js +1 -1
- package/dist/src/utils/model/contextWindowUpgradeCheck.js +1 -1
- package/dist/src/utils/model/model.js +1 -1
- package/dist/src/utils/model/modelAllowlist.js +1 -1
- package/dist/src/utils/model/modelCapabilities.js +1 -1
- package/dist/src/utils/model/modelOptions.js +1 -1
- package/dist/src/utils/model/modelStrings.js +1 -1
- package/dist/src/utils/model/providerModels.js +1 -1
- package/dist/src/utils/model/providerProfiles.js +1 -1
- package/dist/src/utils/model/providerProfilesDb.js +1 -1
- package/dist/src/utils/model/providerSwitch.js +1 -1
- package/dist/src/utils/model/providers.js +1 -1
- package/dist/src/utils/modelCost.js +1 -1
- package/dist/src/utils/modifiers.js +1 -1
- package/dist/src/utils/mtls.js +1 -1
- package/dist/src/utils/nativeInstaller/download.js +1 -1
- package/dist/src/utils/nativeInstaller/installer.js +1 -1
- package/dist/src/utils/nativeInstaller/packageManagers.js +1 -1
- package/dist/src/utils/nativeInstaller/pidLock.js +1 -1
- package/dist/src/utils/notebook.js +1 -1
- package/dist/src/utils/pasteStore.js +1 -1
- package/dist/src/utils/path.js +1 -1
- package/dist/src/utils/permissions/PermissionMode.js +1 -1
- package/dist/src/utils/permissions/PermissionPromptToolResultSchema.js +1 -1
- package/dist/src/utils/permissions/PermissionUpdate.js +1 -1
- package/dist/src/utils/permissions/PermissionUpdateSchema.js +1 -1
- package/dist/src/utils/permissions/autoModeState.js +1 -1
- package/dist/src/utils/permissions/bypassPermissionsKillswitch.js +1 -1
- package/dist/src/utils/permissions/filesystem.js +1 -1
- package/dist/src/utils/permissions/getNextPermissionMode.js +1 -1
- package/dist/src/utils/permissions/pathValidation.js +1 -1
- package/dist/src/utils/permissions/permissionRuleParser.js +1 -1
- package/dist/src/utils/permissions/permissionsDb.js +1 -1
- package/dist/src/utils/permissions/permissionsLoader.js +1 -1
- package/dist/src/utils/permissions/shellRuleMatching.js +1 -1
- package/dist/src/utils/planModeV2.js +1 -1
- package/dist/src/utils/plans.js +1 -1
- package/dist/src/utils/platform.js +1 -1
- package/dist/src/utils/plugins/addDirPluginSettings.js +1 -1
- package/dist/src/utils/plugins/cacheUtils.js +1 -1
- package/dist/src/utils/plugins/dependencyResolver.js +1 -1
- package/dist/src/utils/plugins/fetchTelemetry.js +1 -1
- package/dist/src/utils/plugins/gitAvailability.js +1 -1
- package/dist/src/utils/plugins/hintRecommendation.js +1 -1
- package/dist/src/utils/plugins/installedPluginsManager.js +1 -1
- package/dist/src/utils/plugins/loadPluginAgents.js +1 -1
- package/dist/src/utils/plugins/loadPluginCommands.js +1 -1
- package/dist/src/utils/plugins/loadPluginHooks.js +1 -1
- package/dist/src/utils/plugins/loadPluginOutputStyles.js +1 -1
- package/dist/src/utils/plugins/lspPluginIntegration.js +1 -1
- package/dist/src/utils/plugins/lspRecommendation.js +1 -1
- package/dist/src/utils/plugins/managedPlugins.js +1 -1
- package/dist/src/utils/plugins/marketplaceHelpers.js +1 -1
- package/dist/src/utils/plugins/marketplaceManager.js +1 -1
- package/dist/src/utils/plugins/mcpPluginIntegration.js +1 -1
- package/dist/src/utils/plugins/mcpbHandler.js +1 -1
- package/dist/src/utils/plugins/officialMarketplaceGcs.js +1 -1
- package/dist/src/utils/plugins/officialMarketplaceStartupCheck.js +1 -1
- package/dist/src/utils/plugins/orphanedPluginFilter.js +1 -1
- package/dist/src/utils/plugins/performStartupChecks.js +1 -1
- package/dist/src/utils/plugins/pluginAutoupdate.js +1 -1
- package/dist/src/utils/plugins/pluginBlocklist.js +1 -1
- package/dist/src/utils/plugins/pluginDirectories.js +1 -1
- package/dist/src/utils/plugins/pluginFlagging.js +1 -1
- package/dist/src/utils/plugins/pluginInstallationHelpers.js +1 -1
- package/dist/src/utils/plugins/pluginLoader.js +1 -1
- package/dist/src/utils/plugins/pluginOptionsStorage.js +1 -1
- package/dist/src/utils/plugins/pluginPolicy.js +1 -1
- package/dist/src/utils/plugins/pluginStartupCheck.js +1 -1
- package/dist/src/utils/plugins/pluginVersioning.js +1 -1
- package/dist/src/utils/plugins/reconciler.js +1 -1
- package/dist/src/utils/plugins/refresh.js +1 -1
- package/dist/src/utils/plugins/schemas.js +1 -1
- package/dist/src/utils/plugins/walkPluginMarkdown.js +1 -1
- package/dist/src/utils/plugins/zipCache.js +1 -1
- package/dist/src/utils/powershell/parser.js +1 -1
- package/dist/src/utils/processUserInput/processBashCommand.js +1 -1
- package/dist/src/utils/processUserInput/processSlashCommand.js +1 -1
- package/dist/src/utils/processUserInput/processTextPrompt.js +1 -1
- package/dist/src/utils/processUserInput/processUserInput.js +1 -1
- package/dist/src/utils/profilerBase.js +1 -1
- package/dist/src/utils/promptCategory.js +1 -1
- package/dist/src/utils/promptEditor.js +1 -1
- package/dist/src/utils/promptShellExecution.js +1 -1
- package/dist/src/utils/proxy.js +1 -1
- package/dist/src/utils/queryHelpers.js +1 -1
- package/dist/src/utils/queryProfiler.js +1 -1
- package/dist/src/utils/queueProcessor.js +1 -1
- package/dist/src/utils/readFileInRange.js +1 -1
- package/dist/src/utils/releaseNotes.js +1 -1
- package/dist/src/utils/renderOptions.js +1 -1
- package/dist/src/utils/ripgrep.js +1 -1
- package/dist/src/utils/sandbox/sandbox-adapter.js +1 -1
- package/dist/src/utils/sdkEventQueue.js +1 -1
- package/dist/src/utils/secureStorage/index.js +1 -1
- package/dist/src/utils/secureStorage/macOsKeychainHelpers.js +1 -1
- package/dist/src/utils/secureStorage/macOsKeychainStorage.js +1 -1
- package/dist/src/utils/secureStorage/plainTextStorage.js +1 -1
- package/dist/src/utils/secureStorage/sqliteStorage.js +1 -1
- package/dist/src/utils/sessionEnvironment.js +1 -1
- package/dist/src/utils/sessionIngressAuth.js +1 -1
- package/dist/src/utils/sessionRestore.js +1 -1
- package/dist/src/utils/sessionStart.js +1 -1
- package/dist/src/utils/sessionTitle.js +1 -1
- package/dist/src/utils/settings/managedPath.js +1 -1
- package/dist/src/utils/settings/mdm/rawRead.js +1 -1
- package/dist/src/utils/settings/mdm/settings.js +1 -1
- package/dist/src/utils/settings/permissionValidation.js +1 -1
- package/dist/src/utils/settings/pluginOnlyPolicy.js +1 -1
- package/dist/src/utils/settings/schemaOutput.js +1 -1
- package/dist/src/utils/settings/settings.js +1 -1
- package/dist/src/utils/settings/types.js +1 -1
- package/dist/src/utils/settings/validateEditTool.js +1 -1
- package/dist/src/utils/settings/validation.js +1 -1
- package/dist/src/utils/shell/bashProvider.js +1 -1
- package/dist/src/utils/shell/powershellDetection.js +1 -1
- package/dist/src/utils/shell/powershellProvider.js +1 -1
- package/dist/src/utils/shell/readOnlyCommandValidation.js +1 -1
- package/dist/src/utils/shell/resolveDefaultShell.js +1 -1
- package/dist/src/utils/shell/shellToolUtils.js +1 -1
- package/dist/src/utils/shell/specPrefix.js +1 -1
- package/dist/src/utils/shellConfig.js +1 -1
- package/dist/src/utils/sideQuestion.js +1 -1
- package/dist/src/utils/skills/skillChangeDetector.js +1 -1
- package/dist/src/utils/slashCommandParsing.js +1 -1
- package/dist/src/utils/sliceAnsi.js +1 -1
- package/dist/src/utils/slowOperations.js +1 -1
- package/dist/src/utils/standaloneAgent.js +1 -1
- package/dist/src/utils/startupProfiler.js +1 -1
- package/dist/src/utils/staticRender.js +1 -1
- package/dist/src/utils/status.js +1 -1
- package/dist/src/utils/statusNoticeDefinitions.js +1 -1
- package/dist/src/utils/suggestions/commandSuggestions.js +1 -1
- package/dist/src/utils/suggestions/directoryCompletion.js +1 -1
- package/dist/src/utils/suggestions/shellHistoryCompletion.js +1 -1
- package/dist/src/utils/suggestions/skillUsageTracking.js +1 -1
- package/dist/src/utils/suggestions/slackChannelSuggestions.js +1 -1
- package/dist/src/utils/swarm/backends/detection.js +1 -1
- package/dist/src/utils/swarm/permissionSync.js +1 -1
- package/dist/src/utils/swarm/reconnection.js +1 -1
- package/dist/src/utils/swarm/spawnUtils.js +91 -1
- package/dist/src/utils/swarm/teammateInit.js +1 -1
- package/dist/src/utils/systemDirectories.js +1 -1
- package/dist/src/utils/systemPrompt.js +1 -1
- package/dist/src/utils/systemTheme.js +1 -1
- package/dist/src/utils/task/TaskOutput.js +1 -1
- package/dist/src/utils/task/diskOutput.js +1 -1
- package/dist/src/utils/tasks.js +1 -1
- package/dist/src/utils/teamDiscovery.js +1 -1
- package/dist/src/utils/teamMemoryOps.js +1 -1
- package/dist/src/utils/teammateMailbox.js +1 -1
- package/dist/src/utils/telemetry/betaSessionTracing.js +1 -1
- package/dist/src/utils/telemetry/bigqueryExporter.js +1 -1
- package/dist/src/utils/telemetry/events.js +1 -1
- package/dist/src/utils/telemetry/instrumentation.js +1 -1
- package/dist/src/utils/telemetry/logger.js +1 -1
- package/dist/src/utils/telemetry/perfettoTracing.js +1 -1
- package/dist/src/utils/telemetry/pluginTelemetry.js +1 -1
- package/dist/src/utils/telemetry/sessionTracing.js +1 -1
- package/dist/src/utils/telemetryAttributes.js +1 -1
- package/dist/src/utils/teleport/api.js +1 -1
- package/dist/src/utils/teleport/environments.js +1 -1
- package/dist/src/utils/teleport/gitBundle.js +1 -1
- package/dist/src/utils/teleport.js +1 -1
- package/dist/src/utils/tempfile.js +1 -1
- package/dist/src/utils/terminal.js +1 -1
- package/dist/src/utils/terminalPanel.js +1 -1
- package/dist/src/utils/textHighlighting.js +1 -1
- package/dist/src/utils/theme.js +1 -1
- package/dist/src/utils/themes/bootstrap.js +1 -1
- package/dist/src/utils/themes/loader.js +1 -1
- package/dist/src/utils/thinking.js +1 -1
- package/dist/src/utils/tmuxSocket.js +1 -1
- package/dist/src/utils/tokens.js +1 -1
- package/dist/src/utils/toolPool.js +1 -1
- package/dist/src/utils/toolResultStorage.js +1 -1
- package/dist/src/utils/transcriptSearch.js +1 -1
- package/dist/src/utils/truncate.js +1 -1
- package/dist/src/utils/ultraplan/keyword.js +1 -1
- package/dist/src/utils/unaryLogging.js +1 -1
- package/dist/src/utils/undercover.js +1 -1
- package/dist/src/utils/user.js +1 -1
- package/dist/src/utils/userPromptKeywords.js +1 -1
- package/dist/src/utils/which.js +1 -1
- package/dist/src/utils/windowsPaths.js +1 -1
- package/dist/src/utils/worktree.js +1 -1
- package/dist/src/utils/zodToJsonSchema.js +1 -1
- package/dist/src/vim/operators.js +1 -1
- package/dist/src/vim/textObjects.js +1 -1
- package/dist/src/vim/transitions.js +1 -1
- package/dist/src/voice/voiceModeEnabled.js +1 -1
- package/dist/src/webapp/auth.js +1 -1
- package/dist/src/webapp/tunnel.js +1 -1
- package/dist/src/whatsapp/bridge.js +1 -1
- package/dist/src/whatsapp/mirror.js +1 -1
- package/package.json +1 -1
package/dist/src/utils/Shell.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{execFileSync as
|
|
1
|
+
import{execFileSync as e,spawn as s}from"child_process";import{constants as t,readFileSync as o,unlinkSync as r}from"fs";import{mkdir as a,open as i,realpath as n}from"fs/promises";import c from"lodash-es/memoize.js";import{isAbsolute as l,resolve as d}from"path";import{join as h}from"path/posix";import{logEvent as m}from"src/services/analytics/index.js";import{getOriginalCwd as p,getSessionId as u,setCwdState as f}from"../bootstrap/state.js";import{generateTaskId as w}from"../Task.js";import{pwd as g}from"./cwd.js";import{logForDebugging as E}from"./debug.js";import{errorMessage as b,isENOENT as v}from"./errors.js";import{getFsImplementation as S}from"./fsOperations.js";import{logError as C}from"./log.js";import{createAbortedCommand as y,createFailedCommand as O,wrapSpawn as P}from"./ShellCommand.js";import{getTaskOutputDir as _}from"./task/diskOutput.js";import{TaskOutput as x}from"./task/TaskOutput.js";import{which as j}from"./which.js";import{accessSync as D}from"fs";import{onCwdChangedForHooks as L}from"./hooks/fileChangedWatcher.js";import{getClaudeTempDirName as T}from"./permissions/filesystem.js";import{getPlatform as k}from"./platform.js";import{SandboxManager as N}from"./sandbox/sandbox-adapter.js";import{invalidateSessionEnvCache as A}from"./sessionEnvironment.js";import{createBashShellProvider as I}from"./shell/bashProvider.js";import{getCachedPowerShellPath as $}from"./shell/powershellDetection.js";import{createPowerShellProvider as F}from"./shell/powershellProvider.js";import{subprocessEnv as z}from"./subprocessEnv.js";import{posixPathToWindowsPath as H}from"./windowsPaths.js";function isExecutable(s){try{return D(s,t.X_OK),!0}catch(t){try{return e(s,["--version"],{timeout:1e3,stdio:"ignore"}),!0}catch{return!1}}}export async function findSuitableShell(){const e=process.env.CONTEXT_CODE_SHELL??process.env.CLAUDE_CODE_SHELL;if(e){if((e.includes("bash")||e.includes("zsh"))&&isExecutable(e))return E(`Using shell override: ${e}`),e;E(`CLAUDE_CODE_SHELL="${e}" is not a valid bash/zsh path, falling back to detection`)}const s=process.env.SHELL,t=s&&(s.includes("bash")||s.includes("zsh")),o=s?.includes("bash"),[r,a]=await Promise.all([j("zsh"),j("bash")]),i=["/bin","/usr/bin","/usr/local/bin","/opt/homebrew/bin"],n=(o?["bash","zsh"]:["zsh","bash"]).flatMap(e=>i.map(s=>`${s}/${e}`));o?(a&&n.unshift(a),r&&n.push(r)):(r&&n.unshift(r),a&&n.push(a)),t&&isExecutable(s)&&n.unshift(s);const c=n.find(e=>e&&isExecutable(e));if(!c){const e="No suitable shell found. Claude CLI requires a Posix shell environment. Please ensure you have a valid shell installed and the SHELL environment variable set.";throw C(new Error(e)),new Error(e)}return c}export const getShellConfig=c(async function(){const e=await findSuitableShell();return{provider:await I(e)}});export const getPsProvider=c(async()=>{const e=await $();if(!e)throw new Error("PowerShell is not available");return F(e)});const U={bash:async()=>(await getShellConfig()).provider,powershell:getPsProvider};export async function exec(e,c,l,d){const{timeout:v,onProgress:C,preventCwdChanges:j,shouldUseSandbox:D,shouldAutoBackground:I,onStdout:$}=d??{},F=v||18e5,M=await U[l](),W=Math.floor(65536*Math.random()).toString(16).padStart(4,"0"),R=h(process.env.CONTEXT_CODE_TMPDIR||process.env.CLAUDE_CODE_TMPDIR||"/tmp",T()),{commandString:X,cwdFilePath:B}=await M.buildExecCommand(e,{id:W,sandboxTmpDir:D?R:void 0,useSandbox:D??!1});let Y=X,q=g();try{await n(q)}catch{const e=p();E(`Shell CWD "${q}" no longer exists, recovering to "${e}"`);try{await n(e),f(e),q=e}catch{return O(`Working directory "${q}" no longer exists. Please restart Claude from an existing directory.`)}}if(c.aborted)return y();const G=M.shellPath,K=D&&"powershell"===l,V=K?"/bin/sh":G;if(D){Y=await N.wrapWithSandbox(Y,V,void 0,c);try{const e=S();await e.mkdir(R,{mode:448})}catch(e){E(`Failed to create ${R} directory: ${e}`)}}const J=K?"/bin/sh":G,Q=K?["-c",Y]:M.getSpawnArgs(Y),Z=await M.getEnvironmentOverrides(e),ee=!!$,se=w("local_bash"),te=new x(se,C??null,!ee);let oe;if(await a(_(),{recursive:!0}),!ee){const e=t.O_NOFOLLOW??0;oe=await i(te.path,"win32"===process.platform?"w":t.O_WRONLY|t.O_CREAT|t.O_APPEND|e)}try{const e=s(J,Q,{env:{...z(),SHELL:"bash"===l?G:void 0,GIT_EDITOR:"true",CLAUDECODE:"1",...Z,..."ant"===process.env.USER_TYPE?{CLAUDE_CODE_SESSION_ID:u()}:{}},cwd:q,stdio:ee?["pipe","pipe","pipe"]:["pipe",oe?.fd,oe?.fd],detached:M.detached,windowsHide:!0}),t=P(e,c,F,te,I);if(void 0!==oe)try{await oe.close()}catch{}e.stdout&&$&&e.stdout.on("data",e=>{$("string"==typeof e?e:e.toString())});const a="windows"===k()?H(B):B;return t.result.then(async e=>{if(D&&N.cleanupAfterCommand(),e&&!j&&!e.backgroundTaskId)try{let e=o(a,{encoding:"utf8"}).trim();"windows"===k()&&(e=H(e)),e.normalize("NFC")!==q&&(setCwd(e,q),A(),L(q,e))}catch{m("tengu_shell_set_cwd",{success:!1})}try{r(a)}catch{}}),t}catch(e){if(void 0!==oe)try{await oe.close()}catch{}return te.clear(),E(`Shell exec error: ${b(e)}`),y(void 0,{code:126,stderr:b(e)})}}export function setCwd(e,s){const t=l(e)?e:d(s||S().cwd(),e);let o;try{o=S().realpathSync(t)}catch(e){if(v(e))throw new Error(`Path "${t}" does not exist`);throw e}if(f(o),"test"!==process.env.NODE_ENV)try{m("tengu_shell_set_cwd",{success:!0})}catch(e){}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var t;import{stat as
|
|
1
|
+
var t;import{stat as s}from"fs/promises";import i from"tree-kill";import{generateTaskId as e}from"../Task.js";import{formatDuration as r}from"./format.js";import{MAX_TASK_OUTPUT_BYTES as u,MAX_TASK_OUTPUT_BYTES_DISPLAY as n}from"./task/diskOutput.js";import{TaskOutput as h}from"./task/TaskOutput.js";function prependStderr(t,s){return s?`${t} ${s}`:t}class StreamWrapper{#t;#s=!1;#i;#e;#r=this.#u.bind(this);constructor(t,s,i){this.#t=t,this.#i=s,this.#e=i,t.setEncoding("utf-8"),t.on("data",this.#r)}#u(t){const s="string"==typeof t?t:t.toString();this.#e?this.#i.writeStderr(s):this.#i.writeStdout(s)}cleanup(){this.#s||(this.#s=!0,this.#t.removeListener("data",this.#r),this.#t=null,this.#i=null,this.#r=()=>{})}}class ShellCommandImpl{#n="running";#h;#a;#o;#l;#d=null;#p=null;#c=!1;#k;#m;#b;#S;#T;#O=null;#g=null;#f=null;taskOutput;static#I(t){t.#T&&t.#b?t.#b(t.background.bind(t)):t.#w(143)}result;onTimeout;constructor(t,s,i,e,r=!1,n=u){this.#l=t,this.#m=s,this.#S=i,this.#T=r,this.#k=n,this.taskOutput=e,this.#o=t.stderr?new StreamWrapper(t.stderr,e,!0):null,this.#a=t.stdout?new StreamWrapper(t.stdout,e,!1):null,r&&(this.onTimeout=t=>{this.#b=t}),this.result=this.#C()}get status(){return this.#n}#v(){"interrupt"!==this.#m.reason&&this.kill()}#P(t,s){const i=null!=t?t:"SIGTERM"===s?144:1;this.#x(i)}#A(){this.#x(1)}#x(t){this.#g&&(this.#g(t),this.#g=null)}#_(){this.#F();const t=this.#d;t&&(clearTimeout(t),this.#d=null);const s=this.#f;s&&(this.#m.removeEventListener("abort",s),this.#f=null)}#F(){this.#p&&(clearInterval(this.#p),this.#p=null)}#z(){this.#p=setInterval(()=>{s(this.taskOutput.path).then(t=>{t.size>this.#k&&"backgrounded"===this.#n&&null!==this.#p&&(this.#c=!0,this.#F(),this.#w(137))},()=>{})},5e3),this.#p.unref()}#C(){this.#f=this.#v.bind(this),this.#m.addEventListener("abort",this.#f,{once:!0}),this.#l.once("exit",this.#P.bind(this)),this.#l.once("error",this.#A.bind(this)),this.#d=setTimeout(t.#I,this.#S,this);const s=new Promise(t=>{this.#g=t});return new Promise(t=>{this.#O=t,s.then(this.#E.bind(this))})}async#E(t){this.#_(),"running"!==this.#n&&"backgrounded"!==this.#n||(this.#n="completed");const s={code:t,stdout:await this.taskOutput.getStdout(),stderr:this.taskOutput.getStderr(),interrupted:137===t,backgroundTaskId:this.#h};this.taskOutput.stdoutToFile&&!this.#h&&(this.taskOutput.outputFileRedundant?this.taskOutput.deleteOutputFile():(s.outputFilePath=this.taskOutput.path,s.outputFileSize=this.taskOutput.outputFileSize,s.outputTaskId=this.taskOutput.taskId)),this.#c?s.stderr=prependStderr(`Background command killed: output file exceeded ${n}`,s.stderr):143===t&&(s.stderr=prependStderr(`Command timed out after ${r(this.#S)}`,s.stderr));const i=this.#O;i&&(this.#O=null,i(s))}#w(t){this.#n="killed",this.#l.pid&&i(this.#l.pid,"SIGKILL"),this.#x(t??137)}kill(){this.#w()}background(t){return"running"===this.#n&&(this.#h=t,this.#n="backgrounded",this.#_(),this.taskOutput.stdoutToFile?this.#z():this.taskOutput.spillToDisk(),!0)}cleanup(){this.#a?.cleanup(),this.#o?.cleanup(),this.taskOutput.clear(),this.#_(),this.#l=null,this.#m=null,this.#b=void 0}}t=ShellCommandImpl;export function wrapSpawn(t,s,i,e,r=!1,n=u){return new ShellCommandImpl(t,s,i,e,r,n)}class AbortedShellCommand{status="killed";result;taskOutput;constructor(t){this.taskOutput=new h(e("local_bash"),null),this.result=Promise.resolve({code:t?.code??145,stdout:"",stderr:t?.stderr??"Command aborted before execution",interrupted:!0,backgroundTaskId:t?.backgroundTaskId})}background(){return!1}kill(){}cleanup(){}}export function createAbortedCommand(t,s){return new AbortedShellCommand({backgroundTaskId:t,...s})}export function createFailedCommand(t){const s=new h(e("local_bash"),null);return{status:"completed",result:Promise.resolve({code:1,stdout:"",stderr:t,interrupted:!1,preSpawnError:t}),taskOutput:s,background:()=>!1,kill(){},cleanup(){}}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{getActiveTimeCounter as t}from"../bootstrap/state.js";export class ActivityManager{activeOperations=new Set;lastUserActivityTime=0;lastCLIRecordedTime;isCLIActive=!1;USER_ACTIVITY_TIMEOUT_MS=5e3;getNow;getActiveTimeCounter;static instance=null;constructor(i){this.getNow=i?.getNow??(()=>Date.now()),this.getActiveTimeCounter=i?.getActiveTimeCounter??t,this.lastCLIRecordedTime=this.getNow()}static getInstance(){return ActivityManager.instance||(ActivityManager.instance=new ActivityManager),ActivityManager.instance}static resetInstance(){ActivityManager.instance=null}static createInstance(t){return ActivityManager.instance=new ActivityManager(t),ActivityManager.instance}recordUserActivity(){if(!this.isCLIActive&&0!==this.lastUserActivityTime){const t=(this.getNow()-this.lastUserActivityTime)/1e3;if(t>0){const i=this.getActiveTimeCounter();
|
|
1
|
+
import{getActiveTimeCounter as t}from"../bootstrap/state.js";export class ActivityManager{activeOperations=new Set;lastUserActivityTime=0;lastCLIRecordedTime;isCLIActive=!1;USER_ACTIVITY_TIMEOUT_MS=5e3;getNow;getActiveTimeCounter;static instance=null;constructor(i){this.getNow=i?.getNow??(()=>Date.now()),this.getActiveTimeCounter=i?.getActiveTimeCounter??t,this.lastCLIRecordedTime=this.getNow()}static getInstance(){return ActivityManager.instance||(ActivityManager.instance=new ActivityManager),ActivityManager.instance}static resetInstance(){ActivityManager.instance=null}static createInstance(t){return ActivityManager.instance=new ActivityManager(t),ActivityManager.instance}recordUserActivity(){if(!this.isCLIActive&&0!==this.lastUserActivityTime){const t=(this.getNow()-this.lastUserActivityTime)/1e3;if(t>0){const i=this.getActiveTimeCounter();i&&t<this.USER_ACTIVITY_TIMEOUT_MS/1e3&&i.add(t,{type:"user"})}}this.lastUserActivityTime=this.getNow()}startCLIActivity(t){this.activeOperations.has(t)&&this.endCLIActivity(t);const i=0===this.activeOperations.size;this.activeOperations.add(t),i&&(this.isCLIActive=!0,this.lastCLIRecordedTime=this.getNow())}endCLIActivity(t){if(this.activeOperations.delete(t),0===this.activeOperations.size){const t=this.getNow(),i=(t-this.lastCLIRecordedTime)/1e3;if(i>0){const t=this.getActiveTimeCounter();t&&t.add(i,{type:"cli"})}this.lastCLIRecordedTime=t,this.isCLIActive=!1}}async trackOperation(t,i){this.startCLIActivity(t);try{return await i()}finally{this.endCLIActivity(t)}}getActivityStates(){return{isUserActive:(this.getNow()-this.lastUserActivityTime)/1e3<this.USER_ACTIVITY_TIMEOUT_MS/1e3,isCLIActive:this.isCLIActive,activeOperationCount:this.activeOperations.size}}}export const activityManager=ActivityManager.getInstance();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{getFeatureValue_CACHED_MAY_BE_STALE as e}from"../services/analytics/growthbook.js";import{shouldIncludeFirstPartyOnlyBetas as t}from"./betas.js";import{isEnvTruthy as o}from"./envUtils.js";import{getInitialSettings as
|
|
1
|
+
import{getFeatureValue_CACHED_MAY_BE_STALE as e}from"../services/analytics/growthbook.js";import{shouldIncludeFirstPartyOnlyBetas as t}from"./betas.js";import{isEnvTruthy as o}from"./envUtils.js";import{getInitialSettings as s}from"./settings/settings.js";export function isAdvisorBlock(e){return"advisor_tool_result"===e.type||"server_tool_use"===e.type&&"advisor"===e.name}function getAdvisorConfig(){return e("tengu_sage_compass",{})}export function isAdvisorEnabled(){return!o(process.env.CONTEXT_CODE_DISABLE_ADVISOR_TOOL)&&!o(process.env.CLAUDE_CODE_DISABLE_ADVISOR_TOOL)&&!!t()&&(getAdvisorConfig().enabled??!1)}export function canUserConfigureAdvisor(){return isAdvisorEnabled()&&(getAdvisorConfig().canUserConfigure??!1)}export function getExperimentAdvisorModels(){const e=getAdvisorConfig();return isAdvisorEnabled()&&!canUserConfigureAdvisor()&&e.baseModel&&e.advisorModel?{baseModel:e.baseModel,advisorModel:e.advisorModel}:void 0}export function modelSupportsAdvisor(e){const t=e.toLowerCase();return t.includes("opus-4-6")||t.includes("sonnet-4-6")||"ant"===process.env.USER_TYPE}export function isValidAdvisorModel(e){const t=e.toLowerCase();return t.includes("opus-4-6")||t.includes("sonnet-4-6")||"ant"===process.env.USER_TYPE}export function getInitialAdvisorSetting(){if(isAdvisorEnabled())return s().advisorModel}export function getAdvisorUsage(e){const t=e.iterations;return t?t.filter(e=>"advisor_message"===e.type):[]}export const ADVISOR_TOOL_INSTRUCTIONS="# Advisor Tool\n\nYou have access to an `advisor` tool backed by a stronger reviewer model. It takes NO parameters -- when you call it, your entire conversation history is automatically forwarded. The advisor sees the task, every tool call you've made, every result you've seen.\n\nCall advisor BEFORE substantive work -- before writing code, before committing to an interpretation, before building on an assumption. If the task requires orientation first (finding files, reading code, seeing what's there), do that, then call advisor. Orientation is not substantive work. Writing, editing, and declaring an answer are.\n\nAlso call advisor:\n- When you believe the task is complete. BEFORE this call, make your deliverable durable: write the file, stage the change, save the result. The advisor call takes time; if the session ends during it, a durable result persists and an unwritten one doesn't.\n- When stuck -- errors recurring, approach not converging, results that don't fit.\n- When considering a change of approach.\n\nOn tasks longer than a few steps, call advisor at least once before committing to an approach and once before declaring done. On short reactive tasks where the next action is dictated by tool output you just read, you don't need to keep calling -- the advisor adds most of its value on the first call, before the approach crystallizes.\n\nGive the advice serious weight. If you follow a step and it fails empirically, or you have primary-source evidence that contradicts a specific claim (the file says X, the code does Y), adapt. A passing self-test is not evidence the advice is wrong -- it's evidence your test doesn't check what the advice is checking.\n\nIf you've already retrieved data pointing one way and the advisor points another: don't silently switch. Surface the conflict in one more advisor call -- \"I found X, you suggest Y, which constraint breaks the tie?\" The advisor saw your evidence but may have underweighted it; a reconcile call is cheaper than committing to the wrong branch.";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{stat as e}from"fs/promises";import{homedir as r}from"os";import{join as t}from"path";import{getGlobalConfig as a,saveGlobalConfig as n}from"./config.js";import{execFileNoThrow as
|
|
1
|
+
import{stat as e}from"fs/promises";import{homedir as r}from"os";import{join as t}from"path";import{getGlobalConfig as a,saveGlobalConfig as n}from"./config.js";import{execFileNoThrow as o}from"./execFileNoThrow.js";import{logError as l}from"./log.js";export function markTerminalSetupInProgress(e){n(r=>({...r,appleTerminalSetupInProgress:!0,appleTerminalBackupPath:e}))}export function markTerminalSetupComplete(){n(e=>({...e,appleTerminalSetupInProgress:!1}))}export function getTerminalPlistPath(){return t(r(),"Library","Preferences","com.apple.Terminal.plist")}export async function backupTerminalPreferences(){const r=getTerminalPlistPath(),t=`${r}.bak`;try{const{code:a}=await o("defaults",["export","com.apple.Terminal",r]);if(0!==a)return null;try{await e(r)}catch{return null}return await o("defaults",["export","com.apple.Terminal",t]),markTerminalSetupInProgress(t),t}catch(e){return l(e),null}}export async function checkAndRestoreTerminalBackup(){const{inProgress:r,backupPath:t}=function(){const e=a();return{inProgress:e.appleTerminalSetupInProgress??!1,backupPath:e.appleTerminalBackupPath||null}}();if(!r)return{status:"no_backup"};if(!t)return markTerminalSetupComplete(),{status:"no_backup"};try{await e(t)}catch{return markTerminalSetupComplete(),{status:"no_backup"}}try{const{code:e}=await o("defaults",["import","com.apple.Terminal",t]);return 0!==e?{status:"failed",backupPath:t}:(await o("killall",["cfprefsd"]),markTerminalSetupComplete(),{status:"restored"})}catch(e){return l(new Error(`Failed to restore Terminal.app settings with: ${e}`)),markTerminalSetupComplete(),{status:"failed",backupPath:t}}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{tryParseShellCommand as
|
|
1
|
+
import{tryParseShellCommand as e}from"./bash/shellQuote.js";export function parseArguments(t){if(!t||!t.trim())return[];const r=e(t,e=>`$${e}`);return r.success?r.tokens.filter(e=>"string"==typeof e):t.split(/\s+/).filter(Boolean)}export function parseArgumentNames(e){if(!e)return[];const isValidName=e=>"string"==typeof e&&""!==e.trim()&&!/^\d+$/.test(e);return Array.isArray(e)?e.filter(isValidName):"string"==typeof e?e.split(/\s+/).filter(isValidName):[]}export function generateProgressiveArgumentHint(e,t){const r=e.slice(t.length);if(0!==r.length)return r.map(e=>`[${e}]`).join(" ")}export function substituteArguments(e,t,r=!0,n=[]){if(null==t)return e;const s=parseArguments(t),o=e;for(let t=0;t<n.length;t++){const r=n[t];r&&(e=e.replace(new RegExp(`\\$${r}(?![\\[\\w])`,"g"),s[t]??""))}return(e=(e=(e=e.replace(/\$ARGUMENTS\[(\d+)\]/g,(e,t)=>{const r=parseInt(t,10);return s[r]??""})).replace(/\$(\d+)(?!\w)/g,(e,t)=>{const r=parseInt(t,10);return s[r]??""})).replaceAll("$ARGUMENTS",t))===o&&r&&t&&(e+=`\n\nARGUMENTS: ${t}`),e}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{mkdirSync as e,writeFileSync as r}from"fs";import{getApiKeyFromFd as o,getOauthTokenFromFd as t,setApiKeyFromFd as n,setOauthTokenFromFd as s}from"../bootstrap/state.js";import{logForDebugging as l}from"./debug.js";import{isEnvTruthy as i}from"./envUtils.js";import{errorMessage as
|
|
1
|
+
import{mkdirSync as e,writeFileSync as r}from"fs";import{getApiKeyFromFd as o,getOauthTokenFromFd as t,setApiKeyFromFd as n,setOauthTokenFromFd as s}from"../bootstrap/state.js";import{logForDebugging as l}from"./debug.js";import{isEnvTruthy as i}from"./envUtils.js";import{errorMessage as a,isENOENT as c}from"./errors.js";import{getFsImplementation as d}from"./fsOperations.js";const m="/home/claude/.claude/remote";export const CCR_OAUTH_TOKEN_PATH=`${m}/.oauth_token`;export const CCR_API_KEY_PATH=`${m}/.api_key`;export const CCR_SESSION_INGRESS_TOKEN_PATH=`${m}/.session_ingress_token`;export function maybePersistTokenForSubprocesses(o,t,n){if(i(process.env.CONTEXT_CODE_REMOTE)||i(process.env.CLAUDE_CODE_REMOTE))try{e(m,{recursive:!0,mode:448}),r(o,t,{encoding:"utf8",mode:384}),l(`Persisted ${n} to ${o} for subprocess access`)}catch(e){l(`Failed to persist ${n} to disk (non-fatal): ${a(e)}`,{level:"error"})}}export function readTokenFromWellKnownFile(e,r){try{const o=d().readFileSync(e,{encoding:"utf8"}).trim();return o?(l(`Read ${r} from well-known file ${e}`),o):null}catch(o){return c(o)||l(`Failed to read ${r} from ${e}: ${a(o)}`,{level:"debug"}),null}}function getCredentialFromFd({envVar:e,wellKnownPath:r,label:o,getCached:t,setCached:n}){const s=t();if(void 0!==s)return s;const i=process.env[e];if(!i){const e=readTokenFromWellKnownFile(r,o);return n(e),e}const c=parseInt(i,10);if(Number.isNaN(c))return l(`${e} must be a valid file descriptor number, got: ${i}`,{level:"error"}),n(null),null;try{const e=d(),t="darwin"===process.platform||"freebsd"===process.platform?`/dev/fd/${c}`:`/proc/self/fd/${c}`,s=e.readFileSync(t,{encoding:"utf8"}).trim();return s?(l(`Successfully read ${o} from file descriptor ${c}`),n(s),maybePersistTokenForSubprocesses(r,s,o),s):(l(`File descriptor contained empty ${o}`,{level:"error"}),n(null),null)}catch(e){l(`Failed to read ${o} from file descriptor ${c}: ${a(e)}`,{level:"error"});const t=readTokenFromWellKnownFile(r,o);return n(t),t}}export function getOAuthTokenFromFileDescriptor(){return getCredentialFromFd({envVar:"CLAUDE_CODE_OAUTH_TOKEN_FILE_DESCRIPTOR",wellKnownPath:CCR_OAUTH_TOKEN_PATH,label:"OAuth token",getCached:t,setCached:s})}export function getApiKeyFromFileDescriptor(){return getCredentialFromFd({envVar:"CLAUDE_CODE_API_KEY_FILE_DESCRIPTOR",wellKnownPath:CCR_API_KEY_PATH,label:"API key",getCached:o,setCached:n})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{MACRO as t}from"../recovery/bunBundleShim.js";import e from"axios";import{constants as n}from"fs";import{access as r,writeFile as
|
|
1
|
+
import{MACRO as t}from"../recovery/bunBundleShim.js";import e from"axios";import{constants as n}from"fs";import{access as r,writeFile as s}from"fs/promises";import{homedir as i}from"os";import{join as o}from"path";import{getDynamicConfig_BLOCKS_ON_INIT as a}from"src/services/analytics/growthbook.js";import{logEvent as c}from"src/services/analytics/index.js";import{saveGlobalConfig as l}from"./config.js";import{logForDebugging as u}from"./debug.js";import{env as m}from"./env.js";import{getClaudeConfigHomeDir as d}from"./envUtils.js";import{ClaudeError as f,getErrnoCode as p,isENOENT as g}from"./errors.js";import{execFileNoThrowWithCwd as w}from"./execFileNoThrow.js";import{getFsImplementation as h}from"./fsOperations.js";import{gracefulShutdownSync as y}from"./gracefulShutdown.js";import{logError as x}from"./log.js";import{gte as v,lt as E}from"./semver.js";import{getInitialSettings as _}from"./settings/settings.js";import{filterClaudeAliases as b,getShellConfigPaths as P,readFileLines as S,writeFileLines as $}from"./shellConfig.js";import{jsonParse as A}from"./slowOperations.js";class AutoUpdaterError extends f{}export async function assertMinVersion(){if("test"!==process.env.NODE_ENV&&"@iaforged/context-code"!==t.PACKAGE_URL)try{const e=await a("tengu_version_config",{minVersion:"0.0.0"});e.minVersion&&E(t.VERSION,e.minVersion)&&(console.error(`\nIt looks like your version of Context Code (${t.VERSION}) needs an update.\nA newer version (${e.minVersion} or higher) is required to continue.\n\nTo update, please run:\n context update\n\nThis will ensure you have access to the latest features and improvements.\n`),y(1))}catch(t){x(t)}}export async function getMaxVersion(){const t=await getMaxVersionConfig();return"ant"===process.env.USER_TYPE?t.ant||void 0:t.external||void 0}export async function getMaxVersionMessage(){const t=await getMaxVersionConfig();return"ant"===process.env.USER_TYPE?t.ant_message||void 0:t.external_message||void 0}async function getMaxVersionConfig(){try{return await a("tengu_max_version_config",{})}catch(t){return x(t),{}}}export function shouldSkipVersion(t){const e=_(),n=e?.minimumVersion;if(!n)return!1;const r=!v(t,n);return r&&u(`Skipping update to ${t} - below minimumVersion ${n}`),r}const C=3e5;export function getLockFilePath(){return o(d(),".update.lock")}export async function checkGlobalInstallPermissions(){try{const t=await async function(){const t=m.isRunningWithBun();let e=null;return e=t?await w("bun",["pm","bin","-g"],{cwd:i()}):await w("npm",["-g","config","get","prefix"],{cwd:i()}),0!==e.code?(x(new Error(`Failed to check ${t?"bun":"npm"} permissions`)),null):e.stdout.trim()}();if(!t)return{hasPermissions:!1,npmPrefix:null};try{return await r(t,n.W_OK),{hasPermissions:!0,npmPrefix:t}}catch{return x(new AutoUpdaterError("Insufficient permissions for global npm install.")),{hasPermissions:!1,npmPrefix:t}}}catch(t){return x(t),{hasPermissions:!1,npmPrefix:null}}}export async function getLatestVersion(e){const n="stable"===e?"stable":"latest",r=await w("npm",["view",`${t.PACKAGE_URL}@${n}`,"version","--prefer-online"],{abortSignal:AbortSignal.timeout(5e3),cwd:i()});return 0!==r.code?(u(`npm view failed with code ${r.code}`),r.stderr?u(`npm stderr: ${r.stderr.trim()}`):u("npm stderr: (empty)"),r.stdout&&u(`npm stdout: ${r.stdout.trim()}`),null):r.stdout.trim()}export async function getNpmDistTags(){const e=await w("npm",["view",t.PACKAGE_URL,"dist-tags","--json","--prefer-online"],{abortSignal:AbortSignal.timeout(5e3),cwd:i()});if(0!==e.code)return u(`npm view dist-tags failed with code ${e.code}`),{latest:null,stable:null};try{const t=A(e.stdout.trim());return{latest:"string"==typeof t.latest?t.latest:null,stable:"string"==typeof t.stable?t.stable:null}}catch(e){return u(`Failed to parse dist-tags: ${e}`),{latest:null,stable:null}}}export async function getLatestVersionFromGcs(t){try{return(await e.get(`https://storage.googleapis.com/claude-code-dist-86c565f3-f756-42ad-8dfa-d59b1c096819/claude-code-releases/${t}`,{timeout:5e3,responseType:"text"})).data.trim()}catch(e){return u(`Failed to fetch ${t} from GCS: ${e}`),null}}export async function getGcsDistTags(){const[t,e]=await Promise.all([getLatestVersionFromGcs("latest"),getLatestVersionFromGcs("stable")]);return{latest:t,stable:e}}export async function getVersionHistory(e){if("ant"!==process.env.USER_TYPE)return[];const n=t.NATIVE_PACKAGE_URL??t.PACKAGE_URL,r=await w("npm",["view",n,"versions","--json","--prefer-online"],{abortSignal:AbortSignal.timeout(3e4),cwd:i()});if(0!==r.code)return u(`npm view versions failed with code ${r.code}`),r.stderr&&u(`npm stderr: ${r.stderr.trim()}`),[];try{return A(r.stdout.trim()).slice(-e).reverse()}catch(e){return u(`Failed to parse version history: ${e}`),[]}}export async function installGlobalPackage(e){if(!await async function(){const t=h(),e=getLockFilePath();try{const n=await t.stat(e);if(Date.now()-n.mtimeMs<C)return!1;try{const n=await t.stat(e);if(Date.now()-n.mtimeMs<C)return!1;await t.unlink(e)}catch(t){if(!g(t))return x(t),!1}}catch(t){if(!g(t))return x(t),!1}try{return await s(e,`${process.pid}`,{encoding:"utf8",flag:"wx"}),!0}catch(n){const r=p(n);if("EEXIST"===r)return!1;if("ENOENT"===r)try{return await t.mkdir(d()),await s(e,`${process.pid}`,{encoding:"utf8",flag:"wx"}),!0}catch(t){return"EEXIST"===p(t)||x(t),!1}return x(n),!1}}())return x(new AutoUpdaterError("Another process is currently installing an update")),c("tengu_auto_updater_lock_contention",{pid:process.pid,currentVersion:t.VERSION}),"in_progress";try{if(await async function(){const t=P();for(const[,e]of Object.entries(t))try{const t=await S(e);if(!t)continue;const{filtered:n,hadAlias:r}=b(t);r&&(await $(e,n),u(`Removed claude alias from ${e}`))}catch(t){u(`Failed to remove alias from ${e}: ${t}`,{level:"error"})}}(),!m.isRunningWithBun()&&m.isNpmFromWindowsPath())return x(new Error("Windows NPM detected in WSL environment")),c("tengu_auto_updater_windows_npm_in_wsl",{currentVersion:t.VERSION}),console.error("\nError: Windows NPM detected in WSL\n\nYou're running Context Code in WSL but using the Windows NPM installation from /mnt/c/.\nThis configuration is not supported for updates.\n\nTo fix this issue:\n 1. Install Node.js within your Linux distribution: e.g. sudo apt install nodejs npm\n 2. Make sure Linux NPM is in your PATH before the Windows version\n 3. Try updating again with 'context update'\n"),"install_failed";const{hasPermissions:n}=await checkGlobalInstallPermissions();if(!n)return"no_permissions";const r=e?`${t.PACKAGE_URL}@${e}`:t.PACKAGE_URL,s=m.isRunningWithBun()?"bun":"npm",o=await w(s,["install","-g",r],{cwd:i()});if(0!==o.code){const t=new AutoUpdaterError(`Failed to install new version of context: ${o.stdout} ${o.stderr}`);return x(t),"install_failed"}return l(t=>({...t,installMethod:"global"})),"success"}finally{await async function(){const t=h(),e=getLockFilePath();try{await t.readFile(e,{encoding:"utf8"})===`${process.pid}`&&await t.unlink(e)}catch(t){if(g(t))return;x(t)}}()}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import t from"axios";import{getOauthConfig as e}from"
|
|
1
|
+
import t from"axios";import{getOauthConfig as e}from"src/constants/oauth.js";import{getOrganizationUUID as n}from"src/services/oauth/client.js";import{getFeatureValue_CACHED_MAY_BE_STALE as s}from"../../../services/analytics/growthbook.js";import{checkAndRefreshOAuthTokenIfNeeded as o,getClaudeAIOAuthTokens as a,isClaudeAISubscriber as r}from"../../auth.js";import{getCwd as i}from"../../cwd.js";import{logForDebugging as c}from"../../debug.js";import{detectCurrentRepository as u}from"../../detectRepository.js";import{errorMessage as p}from"../../errors.js";import{findGitRoot as h,getIsClean as d}from"../../git.js";import{getOAuthHeaders as l}from"../../teleport/api.js";import{fetchEnvironments as f}from"../../teleport/environments.js";export async function checkNeedsClaudeAiLogin(){return!!r()&&o()}export async function checkIsGitClean(){return await d({ignoreUntracked:!0})}export async function checkHasRemoteEnvironment(){try{return(await f()).length>0}catch(t){return c(`checkHasRemoteEnvironment failed: ${p(t)}`),!1}}export function checkIsInGitRepo(){return null!==h(i())}export async function checkHasGitRemote(){return null!==await u()}export async function checkGithubAppInstalled(s,o,r){try{const i=a()?.accessToken;if(!i)return c("checkGithubAppInstalled: No access token found, assuming app not installed"),!1;const u=await n();if(!u)return c("checkGithubAppInstalled: No org UUID found, assuming app not installed"),!1;const p=`${e().BASE_API_URL}/api/oauth/organizations/${u}/code/repos/${s}/${o}`,h={...l(i),"x-organization-uuid":u};c(`Checking GitHub app installation for ${s}/${o}`);const d=await t.get(p,{headers:h,timeout:15e3,signal:r});if(200===d.status){if(d.data.status){const t=d.data.status.app_installed;return c(`GitHub app ${t?"is":"is not"} installed on ${s}/${o}`),t}return c(`GitHub app is not installed on ${s}/${o} (status is null)`),!1}return c(`checkGithubAppInstalled: Unexpected response status ${d.status}`),!1}catch(e){if(t.isAxiosError(e)){const t=e.response?.status;if(t&&t>=400&&t<500)return c(`checkGithubAppInstalled: Got ${t} error, app likely not installed on ${s}/${o}`),!1}return c(`checkGithubAppInstalled error: ${p(e)}`),!1}}export async function checkGithubTokenSynced(){try{const s=a()?.accessToken;if(!s)return c("checkGithubTokenSynced: No access token found"),!1;const o=await n();if(!o)return c("checkGithubTokenSynced: No org UUID found"),!1;const r=`${e().BASE_API_URL}/api/oauth/organizations/${o}/sync/github/auth`,i={...l(s),"x-organization-uuid":o};c("Checking if GitHub token is synced via web-setup");const u=await t.get(r,{headers:i,timeout:15e3}),p=200===u.status&&!0===u.data?.is_authenticated;return c(`GitHub token synced: ${p} (status=${u.status}, data=${JSON.stringify(u.data)})`),p}catch(e){if(t.isAxiosError(e)){const t=e.response?.status;if(t&&t>=400&&t<500)return c(`checkGithubTokenSynced: Got ${t}, token not synced`),!1}return c(`checkGithubTokenSynced error: ${p(e)}`),!1}}export async function checkRepoForRemoteAccess(t,e){return await checkGithubAppInstalled(t,e)?{hasAccess:!0,method:"github-app"}:s("tengu_cobalt_lantern",!1)&&await checkGithubTokenSynced()?{hasAccess:!0,method:"token-sync"}:{hasAccess:!1,method:"none"}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{checkGate_CACHED_OR_BLOCKING as e}from"../../../services/analytics/growthbook.js";import{isPolicyAllowed as
|
|
1
|
+
import{checkGate_CACHED_OR_BLOCKING as e}from"../../../services/analytics/growthbook.js";import{isPolicyAllowed as t}from"../../../services/policyLimits/index.js";import{detectCurrentRepositoryWithHost as o}from"../../detectRepository.js";import{isEnvTruthy as s}from"../../envUtils.js";import{checkGithubAppInstalled as i,checkHasRemoteEnvironment as n,checkIsInGitRepo as r,checkNeedsClaudeAiLogin as c}from"./preconditions.js";export async function checkBackgroundRemoteSessionEligibility({skipBundle:p=!1}={}){const a=[];if(!t("allow_remote_sessions"))return a.push({type:"policy_blocked"}),a;const[_,l,m]=await Promise.all([c(),n(),o()]);_&&a.push({type:"not_logged_in"}),l||a.push({type:"no_remote_environment"});const u=!p&&(s(process.env.CCR_FORCE_BUNDLE)||s(process.env.CCR_ENABLE_BUNDLE)||await e("tengu_ccr_bundle_seed_enabled"));return r()?u||(null===m?a.push({type:"no_git_remote"}):"github.com"===m.host&&(await i(m.owner,m.name)||a.push({type:"github_app_not_installed"}))):a.push({type:"not_in_git_repo"}),a}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{execFile as e}from"child_process";import{execa as n}from"execa";import{mkdir as t,stat as s}from"fs/promises";import*as o from"os";import{join as i}from"path";import{logEvent as r}from"
|
|
1
|
+
import{execFile as e}from"child_process";import{execa as n}from"execa";import{mkdir as t,stat as s}from"fs/promises";import*as o from"os";import{join as i}from"path";import{logEvent as r}from"src/services/analytics/index.js";import{registerCleanup as a}from"../cleanupRegistry.js";import{getCwd as l}from"../cwd.js";import{logForDebugging as c}from"../debug.js";import{embeddedSearchToolsBinaryPath as h,hasEmbeddedSearchTools as d}from"../embeddedTools.js";import{getClaudeConfigHomeDir as u}from"../envUtils.js";import{pathExists as p}from"../file.js";import{getFsImplementation as f}from"../fsOperations.js";import{logError as g}from"../log.js";import{getPlatform as $}from"../platform.js";import{ripgrepCommand as S}from"../ripgrep.js";import{subprocessEnv as _}from"../subprocessEnv.js";import{quote as m}from"./shellQuote.js";function createArgv0ShellFunction(e,n,t,s=[]){const o=m([t]),i=s.length>0?`${s.join(" ")} "$@"`:'"$@"';return[`function ${e} {`," if [[ -n $ZSH_VERSION ]]; then",` ARGV0=${n} ${o} ${i}`,' elif [[ "$OSTYPE" == "msys" ]] || [[ "$OSTYPE" == "cygwin" ]] || [[ "$OSTYPE" == "win32" ]]; then',` ARGV0=${n} ${o} ${i}`," elif [[ $BASHPID != $$ ]]; then",` exec -a ${n} ${o} ${i}`," else",` (exec -a ${n} ${o} ${i})`," fi","}"].join("\n")}export function createRipgrepShellIntegration(){const e=S();if(e.argv0)return{type:"function",snippet:createArgv0ShellFunction("rg",e.argv0,e.rgPath)};const n=m([e.rgPath]),t=e.rgArgs.map(e=>m([e]));return{type:"alias",snippet:e.rgArgs.length>0?`${n} ${t.join(" ")}`:n}}const E=[".git",".svn",".hg",".bzr",".jj",".sl"];export function createFindGrepShellIntegration(){if(!d())return null;const e=h();return["unalias find 2>/dev/null || true","unalias grep 2>/dev/null || true",createArgv0ShellFunction("find","bfs",e,["-regextype","findutils-default"]),createArgv0ShellFunction("grep","ugrep",e,["-G","--ignore-files","--hidden","-I",...E.map(e=>`--exclude-dir=${e}`)])].join("\n")}function getConfigFile(e){const n=e.includes("zsh")?".zshrc":e.includes("bash")?".bashrc":".profile";return i(o.homedir(),n)}async function getSnapshotScript(e,t,s){const o=getConfigFile(e),i=o.endsWith(".zshrc"),r=s?function(e){const n=e.endsWith(".zshrc");let t="";return t+=n?'\n echo "# Functions" >> "$SNAPSHOT_FILE"\n\n # Force autoload all functions first\n typeset -f > /dev/null 2>&1\n\n # Now get user function names - filter completion functions (single underscore prefix)\n # but keep double-underscore helpers (e.g. __zsh_like_cd from mise, __pyenv_init)\n typeset +f | grep -vE \'^_[^_]\' | while read func; do\n typeset -f "$func" >> "$SNAPSHOT_FILE"\n done\n ':'\n echo "# Functions" >> "$SNAPSHOT_FILE"\n\n # Force autoload all functions first\n declare -f > /dev/null 2>&1\n\n # Now get user function names - filter completion functions (single underscore prefix)\n # but keep double-underscore helpers (e.g. __zsh_like_cd from mise, __pyenv_init)\n declare -F | cut -d\' \' -f3 | grep -vE \'^_[^_]\' | while read func; do\n # Encode the function to base64, preserving all special characters\n encoded_func=$(declare -f "$func" | base64 )\n # Write the function definition to the snapshot\n echo "eval \\"\\$(echo \'$encoded_func\' | base64 -d)\\" > /dev/null 2>&1" >> "$SNAPSHOT_FILE"\n done\n ',t+=n?'\n echo "# Shell Options" >> "$SNAPSHOT_FILE"\n setopt | sed \'s/^/setopt /\' | head -n 1000 >> "$SNAPSHOT_FILE"\n ':'\n echo "# Shell Options" >> "$SNAPSHOT_FILE"\n shopt -p | head -n 1000 >> "$SNAPSHOT_FILE"\n set -o | grep "on" | awk \'{print "set -o " $1}\' | head -n 1000 >> "$SNAPSHOT_FILE"\n echo "shopt -s expand_aliases" >> "$SNAPSHOT_FILE"\n ',t+='\n echo "# Aliases" >> "$SNAPSHOT_FILE"\n # Filter out winpty aliases on Windows to avoid "stdin is not a tty" errors\n # Git Bash automatically creates aliases like "alias node=\'winpty node.exe\'" for\n # programs that need Win32 Console in mintty, but winpty fails when there\'s no TTY\n if [[ "$OSTYPE" == "msys" ]] || [[ "$OSTYPE" == "cygwin" ]]; then\n alias | grep -v "=\'winpty " | sed \'s/^alias //g\' | sed \'s/^/alias -- /\' | head -n 1000 >> "$SNAPSHOT_FILE"\n else\n alias | sed \'s/^alias //g\' | sed \'s/^/alias -- /\' | head -n 1000 >> "$SNAPSHOT_FILE"\n fi\n ',t}(o):i?"":'echo "shopt -s expand_aliases" >> "$SNAPSHOT_FILE"',a=await async function(){let e=process.env.PATH;if("windows"===$()){const t=await n("echo $PATH",{shell:!0,reject:!1});0===t.exitCode&&t.stdout&&(e=t.stdout.trim())}const t=createRipgrepShellIntegration();let s="";s+='\n # Check for rg availability\n echo "# Check for rg availability" >> "$SNAPSHOT_FILE"\n echo "if ! (unalias rg 2>/dev/null; command -v rg) >/dev/null 2>&1; then" >> "$SNAPSHOT_FILE"\n ',"function"===t.type?s+=`\n cat >> "$SNAPSHOT_FILE" << 'RIPGREP_FUNC_END'\n ${t.snippet}\nRIPGREP_FUNC_END\n `:s+=`\n echo ' alias rg='"'${t.snippet.replace(/'/g,"'\\''")}'" >> "$SNAPSHOT_FILE"\n `,s+='\n echo "fi" >> "$SNAPSHOT_FILE"\n ';const o=createFindGrepShellIntegration();return null!==o&&(s+=`\n # Shadow find/grep with embedded bfs/ugrep (ant-native only)\n echo "# Shadow find/grep with embedded bfs/ugrep" >> "$SNAPSHOT_FILE"\n cat >> "$SNAPSHOT_FILE" << 'FIND_GREP_FUNC_END'\n${o}\nFIND_GREP_FUNC_END\n `),s+=`\n\n # Add PATH to the file\n echo "export PATH=${m([e||""])}" >> "$SNAPSHOT_FILE"\n `,s}();return`SNAPSHOT_FILE=${m([t])}\n ${s?`source "${o}" < /dev/null`:"# No user config file to source"}\n\n # First, create/clear the snapshot file\n echo "# Snapshot file" >| "$SNAPSHOT_FILE"\n\n # When this file is sourced, we first unalias to avoid conflicts\n # This is necessary because aliases get "frozen" inside function definitions at definition time,\n # which can cause unexpected behavior when functions use commands that conflict with aliases\n echo "# Unset all aliases to avoid conflicts with functions" >> "$SNAPSHOT_FILE"\n echo "unalias -a 2>/dev/null || true" >> "$SNAPSHOT_FILE"\n\n ${r}\n\n ${a}\n\n # Exit silently on success, only report errors\n if [ ! -f "$SNAPSHOT_FILE" ]; then\n echo "Error: Snapshot file was not created at $SNAPSHOT_FILE" >&2\n exit 1\n fi\n `}export const createAndSaveSnapshot=async n=>{const h=n.includes("zsh")?"zsh":n.includes("bash")?"bash":"sh";return c(`Creating shell snapshot for ${h} (${n})`),new Promise(async d=>{try{const $=getConfigFile(n);c(`Looking for shell config file: ${$}`);const S=await p($);S||c(`Shell config file not found: ${$}, creating snapshot with Context Code defaults only`);const m=Date.now(),E=Math.random().toString(36).substring(2,8),F=i(u(),"shell-snapshots");c(`Snapshots directory: ${F}`);const N=i(F,`snapshot-${h}-${m}-${E}.sh`);await t(F,{recursive:!0});const T=await getSnapshotScript(n,N,S);c(`Creating snapshot at: ${N}`),c("Execution timeout: 10000ms"),e(n,["-c","-l",T],{env:{...process.env.CONTEXT_CODE_DONT_INHERIT_ENV??process.env.CLAUDE_CODE_DONT_INHERIT_ENV?{}:_(),SHELL:n,GIT_EDITOR:"true",CLAUDECODE:"1"},timeout:1e4,maxBuffer:1048576,encoding:"utf8"},async(e,t,i)=>{if(e){const s=e;c(`Shell snapshot creation failed: ${e.message}`),c("Error details:"),c(` - Error code: ${s?.code}`),c(` - Error signal: ${s?.signal}`),c(` - Error killed: ${s?.killed}`),c(` - Shell path: ${n}`),c(` - Config file: ${getConfigFile(n)}`),c(` - Config file exists: ${S}`),c(` - Working directory: ${l()}`),c(` - Claude home: ${u()}`),c(`Full snapshot script:\n${T}`),c(t?`stdout output (${t.length} chars):\n${t}`:"No stdout output captured"),c(i?`stderr output (${i.length} chars): ${i}`:"No stderr output captured"),g(new Error(`Failed to create shell snapshot: ${e.message}`));const a=s?.signal?o.constants.signals[s.signal]:void 0;r("tengu_shell_snapshot_failed",{stderr_length:i?.length||0,has_error_code:!!s?.code,error_signal_number:a,error_killed:s?.killed}),d(void 0)}else{let e;try{e=(await s(N)).size}catch{}if(void 0!==e)c(`Shell snapshot created successfully (${e} bytes)`),a(async()=>{try{await f().unlink(N),c(`Cleaned up session snapshot: ${N}`)}catch(e){c(`Error cleaning up session snapshot: ${e}`)}}),d(N);else{c(`Shell snapshot file not found after creation: ${N}`),c(`Checking if parent directory still exists: ${F}`);try{const e=await f().readdir(F);c(`Directory contains ${e.length} files`)}catch{c(`Parent directory does not exist or is not accessible: ${F}`)}r("tengu_shell_unknown_error",{}),d(void 0)}}})}catch(e){c(`Unexpected error during snapshot creation: ${e}`),e instanceof Error&&c(`Error stack trace: ${e.stack}`),g(e),r("tengu_shell_snapshot_error",{}),d(void 0)}})};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{SHELL_KEYWORDS as e}from"./bashParser.js";import{PARSE_ABORTED as t,parseCommandRaw as n}from"./parser.js";const r=new Set(["program","list","pipeline","redirected_statement"]),o=new Set(["&&","||","|",";","&","|&","\n"]),s="__CMDSUB_OUTPUT__",i="__TRACKED_VAR__";function containsAnyPlaceholder(e){return e.includes(s)||e.includes(i)}const a=/[ \t\n*?[]/,c=/^-[ioe]$/,l=/^-[ioe]./,u=/^--(input|output|error)=/,f=new Set(["HOME","PWD","OLDPWD","USER","LOGNAME","SHELL","PATH","HOSTNAME","UID","EUID","PPID","RANDOM","SECONDS","LINENO","TMPDIR","BASH_VERSION","BASHPID","SHLVL","HISTFILE","IFS"]),p=new Set(["?","$","!","#","0","-"]),d=new Set(["command_substitution","process_substitution","expansion","simple_expansion","brace_expression","subshell","compound_statement","for_statement","while_statement","until_statement","if_statement","case_statement","function_definition","test_command","ansi_c_string","translated_string","herestring_redirect","heredoc_redirect"]),m=[...d];export function nodeTypeId(e){if(!e)return-2;if("ERROR"===e)return-1;const t=m.indexOf(e);return t>=0?t+1:0}const y={">":">",">>":">>","<":"<",">&":">&","<&":"<&",">|":">|","&>":"&>","&>>":"&>>","<<<":"<<<"},h=/\{[^{}\s]*(,|\.\.)[^{}\s]*\}/,g=/[\x00-\x08\x0B-\x1F\x7F]/,x=/[\u00A0\u1680\u2000-\u200B\u2028\u2029\u202F\u205F\u3000\uFEFF]/,b=/\\[ \t]|[^ \t\n\\]\\\n/,k=/~\[/,_=/(?:^|[\s;&|])=[a-zA-Z_]/,w=/\{[^}]*['"]/;const v=String.fromCharCode(36);export async function parseForSecurity(e){if(""===e)return{kind:"simple",commands:[]};const t=await n(e);return null===t?{kind:"parse-unavailable"}:parseForSecurityFromAst(e,t)}export function parseForSecurityFromAst(e,n){if(g.test(e))return{kind:"too-complex",reason:"Contains control characters"};if(x.test(e))return{kind:"too-complex",reason:"Contains Unicode whitespace"};if(b.test(e))return{kind:"too-complex",reason:"Contains backslash-escaped whitespace"};if(k.test(e))return{kind:"too-complex",reason:"Contains zsh ~[ dynamic directory syntax"};if(_.test(e))return{kind:"too-complex",reason:"Contains zsh =cmd equals expansion"};if(w.test(function(e){if(!e.includes("{"))return e;const t=[];let n=!1,r=!1,o=0;for(;o<e.length;){const s=e[o];n?("'"===s&&(n=!1),t.push("{"===s?" ":s),o++):r?"\\"!==s||'"'!==e[o+1]&&"\\"!==e[o+1]?('"'===s&&(r=!1),t.push("{"===s?" ":s),o++):(t.push(s,e[o+1]),o+=2):"\\"===s&&o+1<e.length?(t.push(s,e[o+1]),o+=2):("'"===s?n=!0:'"'===s&&(r=!0),t.push(s),o++)}return t.join("")}(e)))return{kind:"too-complex",reason:"Contains brace with quote character (expansion obfuscation)"};return""===e.trim()?{kind:"simple",commands:[]}:n===t?{kind:"too-complex",reason:"Parser aborted (timeout or resource limit) — possible adversarial input",nodeType:"PARSE_ABORT"}:function(e){const t=[],n=new Map,r=collectCommands(e,t,n);return r||{kind:"simple",commands:t}}(n)}function collectCommands(e,t,n){if("command"===e.type){const r=function(e,t,n,r){const o=[],s=[],i=[...t];for(const t of e.children)if(t)switch(t.type){case"variable_assignment":{const e=walkVariableAssignment(t,n,r);if("kind"in e)return e;s.push({name:e.name,value:e.value});break}case"command_name":{const e=walkArgument(t.children[0]??t,n,r);if("string"!=typeof e)return e;o.push(e);break}case"word":case"number":case"raw_string":case"string":case"concatenation":case"arithmetic_expansion":{const e=walkArgument(t,n,r);if("string"!=typeof e)return e;o.push(e);break}case"simple_expansion":{const e=resolveSimpleExpansion(t,r,!1);if("string"!=typeof e)return e;o.push(e);break}case"file_redirect":{const e=walkFileRedirect(t,n,r);if("kind"in e)return e;i.push(e);break}case"herestring_redirect":{const e=walkHerestringRedirect(t,n,r);if(e)return e;break}default:return tooComplex(t)}const a=/\$[A-Za-z_]/.test(e.text)||e.text.includes("\n")?o.map(e=>""===e||/["'\\ \t\n$`;|&<>(){}*?[\]~#]/.test(e)?`'${e.replace(/'/g,"'\\''")}'`:e).join(" "):e.text;return{kind:"simple",commands:[{argv:o,envVars:s,redirects:i,text:a}]}}(e,[],t,n);return"simple"!==r.kind?r:(t.push(...r.commands),null)}if("redirected_statement"===e.type)return function(e,t,n){const r=[];let o=null;for(const s of e.children)if(s)if("file_redirect"===s.type){const e=walkFileRedirect(s,t,n);if("kind"in e)return e;r.push(e)}else if("heredoc_redirect"===s.type){const e=walkHeredocRedirect(s);if(e)return e}else{if("command"!==s.type&&"pipeline"!==s.type&&"list"!==s.type&&"negated_command"!==s.type&&"declaration_command"!==s.type&&"unset_command"!==s.type)return tooComplex(s);o=s}if(!o)return t.push({argv:[],envVars:[],redirects:r,text:e.text}),null;const s=t.length,i=collectCommands(o,t,n);if(i)return i;if(t.length>s&&r.length>0){const e=t[t.length-1];e&&e.redirects.push(...r)}return null}(e,t,n);if("comment"===e.type)return null;if(r.has(e.type)){const r="pipeline"===e.type;let s=!1;if(!r)for(const t of e.children)if(t&&("||"===t.type||"&"===t.type)){s=!0;break}const i=s?new Map(n):null;let a=r?new Map(n):n;for(const r of e.children){if(!r)continue;if(o.has(r.type)){"||"!==r.type&&"|"!==r.type&&"|&"!==r.type&&"&"!==r.type||(a=new Map(i??n));continue}const e=collectCommands(r,t,a);if(e)return e}return null}if("negated_command"===e.type){for(const r of e.children)if(r&&"!"!==r.type)return collectCommands(r,t,n);return null}if("declaration_command"===e.type){const r=[];for(const o of e.children)if(o)switch(o.type){case"export":case"local":case"readonly":case"declare":case"typeset":case"variable_name":r.push(o.text);break;case"word":case"number":case"raw_string":case"string":case"concatenation":{const e=walkArgument(o,t,n);if("string"!=typeof e)return e;if(("declare"===r[0]||"typeset"===r[0]||"local"===r[0])&&/^-[a-zA-Z]*[niaA]/.test(e))return{kind:"too-complex",reason:`declare flag ${e} changes assignment semantics (nameref/integer/array)`,nodeType:"declaration_command"};if(("declare"===r[0]||"typeset"===r[0]||"local"===r[0])&&"-"!==e[0]&&/^[^=]*\[/.test(e))return{kind:"too-complex",reason:`declare positional '${e}' contains array subscript — bash evaluates $(cmd) in subscripts`,nodeType:"declaration_command"};r.push(e);break}case"variable_assignment":{const e=walkVariableAssignment(o,t,n);if("kind"in e)return e;applyVarToScope(n,e),r.push(`${e.name}=${e.value}`);break}default:return tooComplex(o)}return t.push({argv:r,envVars:[],redirects:[],text:e.text}),null}if("variable_assignment"===e.type){const r=walkVariableAssignment(e,t,n);return"kind"in r?r:(applyVarToScope(n,r),null)}if("for_statement"===e.type){let r=null,o=null;for(const s of e.children)if(s)if("variable_name"===s.type)r=s.text;else if("do_group"===s.type)o=s;else{if("for"===s.type||"in"===s.type||"select"===s.type||";"===s.type)continue;if("command_substitution"===s.type){const e=collectCommandSubstitution(s,t,n);if(e)return e}else{const e=walkArgument(s,t,n);if("string"!=typeof e)return e}}if(null===r||null===o)return tooComplex(e);if("PS4"===r||"IFS"===r)return{kind:"too-complex",reason:`${r} as loop variable bypasses assignment validation`,nodeType:"for_statement"};n.set(r,i);const s=new Map(n);for(const e of o.children){if(!e)continue;if("do"===e.type||"done"===e.type||";"===e.type)continue;const n=collectCommands(e,t,s);if(n)return n}return null}if("if_statement"===e.type||"while_statement"===e.type){let r=!1;for(const o of e.children){if(!o)continue;if("if"===o.type||"fi"===o.type||"else"===o.type||"elif"===o.type||"while"===o.type||"until"===o.type||";"===o.type)continue;if("then"===o.type){r=!0;continue}if("do_group"===o.type){const e=new Map(n);for(const n of o.children){if(!n)continue;if("do"===n.type||"done"===n.type||";"===n.type)continue;const r=collectCommands(n,t,e);if(r)return r}continue}if("elif_clause"===o.type||"else_clause"===o.type){const e=new Map(n);for(const n of o.children){if(!n)continue;if("elif"===n.type||"else"===n.type||"then"===n.type||";"===n.type)continue;const r=collectCommands(n,t,e);if(r)return r}continue}const e=r?new Map(n):n,s=t.length,a=collectCommands(o,t,e);if(a)return a;if(!r)for(let e=s;e<t.length;e++){const r=t[e];if("read"===r?.argv[0])for(const e of r.argv.slice(1))if(!e.startsWith("-")&&/^[A-Za-z_][A-Za-z0-9_]*$/.test(e)){const t=n.get(e);if(void 0!==t&&!containsAnyPlaceholder(t))return{kind:"too-complex",reason:`'read ${e}' in condition may not execute (||/pipeline/subshell); cannot prove it overwrites tracked literal '${t}'`,nodeType:"if_statement"};n.set(e,i)}}}return null}if("subshell"===e.type){const r=new Map(n);for(const n of e.children){if(!n)continue;if("("===n.type||")"===n.type)continue;const e=collectCommands(n,t,r);if(e)return e}return null}if("test_command"===e.type){const r=["[["];for(const o of e.children){if(!o)continue;if("[["===o.type||"]]"===o.type)continue;if("["===o.type||"]"===o.type)continue;const e=walkTestExpr(o,r,t,n);if(e)return e}return t.push({argv:r,envVars:[],redirects:[],text:e.text}),null}if("unset_command"===e.type){const r=[];for(const o of e.children)if(o)switch(o.type){case"unset":r.push(o.text);break;case"variable_name":r.push(o.text),n.delete(o.text);break;case"word":{const e=walkArgument(o,t,n);if("string"!=typeof e)return e;r.push(e);break}default:return tooComplex(o)}return t.push({argv:r,envVars:[],redirects:[],text:e.text}),null}return tooComplex(e)}function walkTestExpr(e,t,n,r){switch(e.type){case"unary_expression":case"binary_expression":case"negated_expression":case"parenthesized_expression":for(const o of e.children){if(!o)continue;const e=walkTestExpr(o,t,n,r);if(e)return e}return null;case"test_operator":case"!":case"(":case")":case"&&":case"||":case"==":case"=":case"!=":case"<":case">":case"=~":case"regex":case"extglob_pattern":return t.push(e.text),null;default:{const o=walkArgument(e,n,r);return"string"!=typeof o?o:(t.push(o),null)}}}function walkFileRedirect(e,t,n){let r,o=null,s=null;for(const i of e.children)if(i)if("file_descriptor"===i.type)r=Number(i.text);else if(i.type in y)o=y[i.type]??null;else if("word"===i.type||"number"===i.type){if(i.children.length>0)return tooComplex(i);if(h.test(i.text))return tooComplex(i);s=i.text.replace(/\\(.)/g,"$1")}else if("raw_string"===i.type)s=stripRawString(i.text);else if("string"===i.type){const e=walkString(i,t,n);if("string"!=typeof e)return e;s=e}else{if("concatenation"!==i.type)return tooComplex(i);{const e=walkArgument(i,t,n);if("string"!=typeof e)return e;s=e}}return o&&null!==s?{op:o,target:s,fd:r}:{kind:"too-complex",reason:"Unrecognized redirect shape",nodeType:e.type}}function walkHeredocRedirect(e){let t=null,n=null;for(const r of e.children)if(r)if("heredoc_start"===r.type)t=r.text;else if("heredoc_body"===r.type)n=r;else if("<<"!==r.type&&"<<-"!==r.type&&"heredoc_end"!==r.type&&"file_descriptor"!==r.type)return tooComplex(r);if(!(null!==t&&(t.startsWith("'")&&t.endsWith("'")||t.startsWith('"')&&t.endsWith('"')||t.startsWith("\\"))))return{kind:"too-complex",reason:"Heredoc with unquoted delimiter undergoes shell expansion",nodeType:"heredoc_redirect"};if(n)for(const e of n.children)if(e&&"heredoc_content"!==e.type)return tooComplex(e);return null}function walkHerestringRedirect(e,t,n){for(const r of e.children){if(!r)continue;if("<<<"===r.type)continue;const e=walkArgument(r,t,n);if("string"!=typeof e)return e;if(P.test(e))return tooComplex(r)}return null}function collectCommandSubstitution(e,t,n){const r=new Map(n);for(const n of e.children){if(!n)continue;if("$("===n.type||"`"===n.type||")"===n.type)continue;const e=collectCommands(n,t,r);if(e)return e}return null}function walkArgument(e,t,n){if(!e)return{kind:"too-complex",reason:"Null argument node"};switch(e.type){case"word":return h.test(e.text)?{kind:"too-complex",reason:"Word contains brace expansion syntax",nodeType:"word"}:e.text.replace(/\\(.)/g,"$1");case"number":return e.children.length>0?{kind:"too-complex",reason:"Number node contains expansion (NN# arithmetic base syntax)",nodeType:e.children[0]?.type}:e.text;case"raw_string":return stripRawString(e.text);case"string":return walkString(e,t,n);case"concatenation":{if(h.test(e.text))return{kind:"too-complex",reason:"Brace expansion",nodeType:"concatenation"};let r="";for(const o of e.children){if(!o)continue;const e=walkArgument(o,t,n);if("string"!=typeof e)return e;r+=e}return r}case"arithmetic_expansion":{const t=walkArithmetic(e);return t||e.text}case"simple_expansion":return resolveSimpleExpansion(e,n,!1);default:return tooComplex(e)}}function walkString(e,t,n){let r="",o=-1,a=!1,c=!1;for(const l of e.children)if(l)switch(-1!==o&&l.startIndex>o&&'"'!==l.type&&(r+="\n".repeat(l.startIndex-o),c=!0),o=l.endIndex,l.type){case'"':o=l.endIndex;break;case"string_content":r+=l.text.replace(/\\([$`"\\])/g,"$1"),c=!0;break;case v:r+=v,c=!0;break;case"command_substitution":{const e=extractSafeCatHeredoc(l);if("DANGEROUS"===e)return tooComplex(l);if(null!==e){const t=e.replace(/\n+$/,"");if(t.includes("\n")){c=!0;break}r+=t,c=!0;break}const o=collectCommandSubstitution(l,t,n);if(o)return o;r+=s,a=!0;break}case"simple_expansion":{const e=resolveSimpleExpansion(l,n,!0);if("string"!=typeof e)return e;e===i?a=!0:c=!0,r+=e;break}case"arithmetic_expansion":{const e=walkArithmetic(l);if(e)return e;r+=l.text,c=!0;break}default:return tooComplex(l)}return a&&!c||!c&&!a&&e.text.length>2?tooComplex(e):r}const S=/^(?:[0-9]+|0[xX][0-9a-fA-F]+|[0-9]+#[0-9a-zA-Z]+|[-+*/%^&|~!<>=?:(),]+|<<|>>|\*\*|&&|\|\||[<>=!]=|\$\(\(|\)\))$/;function walkArithmetic(e){for(const t of e.children)if(t)if(0!==t.children.length)switch(t.type){case"binary_expression":case"unary_expression":case"ternary_expression":case"parenthesized_expression":{const e=walkArithmetic(t);if(e)return e;break}default:return tooComplex(t)}else if(!S.test(t.text))return{kind:"too-complex",reason:`Arithmetic expansion references variable or non-literal: ${t.text}`,nodeType:"arithmetic_expansion"};return null}function extractSafeCatHeredoc(e){let t=null;for(const n of e.children)if(n&&"$("!==n.type&&")"!==n.type){if("redirected_statement"!==n.type||null!==t)return null;t=n}if(!t)return null;let n=!1,r=null;for(const e of t.children)if(e)if("command"===e.type){const t=e.children.filter(e=>e);if(1!==t.length)return null;const r=t[0];if("command_name"!==r?.type||"cat"!==r.text)return null;n=!0}else{if("heredoc_redirect"!==e.type)return null;if(null!==walkHeredocRedirect(e))return null;for(const t of e.children)"heredoc_body"===t?.type&&(r=t.text)}return n&&null!==r?E.test(r)||/\bsystem\s*\(/.test(r)?"DANGEROUS":r:null}function walkVariableAssignment(e,t,n){let r=null,o="",i=!1;for(const a of e.children)if(a)if("variable_name"===a.type)r=a.text;else{if("="===a.type||"+="===a.type){i="+="===a.type;continue}if("command_substitution"===a.type){const e=collectCommandSubstitution(a,t,n);if(e)return e;o=s}else if("simple_expansion"===a.type){const e=resolveSimpleExpansion(a,n,!0);if("string"!=typeof e)return e;o=e}else{const e=walkArgument(a,t,n);if("string"!=typeof e)return e;o=e}}if(null===r)return{kind:"too-complex",reason:"Variable assignment without name",nodeType:"variable_assignment"};if(!/^[A-Za-z_][A-Za-z0-9_]*$/.test(r))return{kind:"too-complex",reason:`Invalid variable name (bash treats as command): ${r}`,nodeType:"variable_assignment"};if("IFS"===r)return{kind:"too-complex",reason:"IFS assignment changes word-splitting — cannot model statically",nodeType:"variable_assignment"};if("PS4"===r){if(i)return{kind:"too-complex",reason:"PS4 += cannot be statically verified — combine into a single PS4= assignment",nodeType:"variable_assignment"};if(containsAnyPlaceholder(o))return{kind:"too-complex",reason:"PS4 value derived from cmdsub/variable — runtime unknowable",nodeType:"variable_assignment"};if(!/^[A-Za-z0-9 _+:./=[\]-]*$/.test(o.replace(/\$\{[A-Za-z_][A-Za-z0-9_]*\}/g,"")))return{kind:"too-complex",reason:"PS4 value outside safe charset — only ${VAR} refs and [A-Za-z0-9 _+:.=/[]-] allowed",nodeType:"variable_assignment"}}return o.includes("~")?{kind:"too-complex",reason:"Tilde in assignment value — bash may expand at assignment time",nodeType:"variable_assignment"}:{name:r,value:o,isAppend:i}}function resolveSimpleExpansion(e,t,n){let r=null,o=!1;for(const t of e.children){if("variable_name"===t?.type){r=t.text;break}if("special_variable_name"===t?.type){r=t.text,o=!0;break}}if(null===r)return tooComplex(e);const s=t.get(r);if(void 0!==s){if(containsAnyPlaceholder(s))return n?i:tooComplex(e);if(!n){if(""===s)return tooComplex(e);if(a.test(s))return tooComplex(e)}return s}if(n){if(f.has(r))return i;if(o&&(p.has(r)||/^[0-9]+$/.test(r)))return i}return tooComplex(e)}function applyVarToScope(e,t){const n=e.get(t.name)??"",r=t.isAppend?n+t.value:t.value;e.set(t.name,containsAnyPlaceholder(r)?i:r)}function stripRawString(e){return e.slice(1,-1)}function tooComplex(e){return{kind:"too-complex",reason:"ERROR"===e.type?"Parse error":d.has(e.type)?`Contains ${e.type}`:`Unhandled node type: ${e.type}`,nodeType:e.type}}const $=new Set(["zmodload","emulate","sysopen","sysread","syswrite","sysseek","zpty","ztcp","zsocket","zf_rm","zf_mv","zf_ln","zf_chmod","zf_chown","zf_mkdir","zf_rmdir","zf_chgrp"]),A=new Set(["eval","source",".","exec","command","builtin","fc","coproc","noglob","nocorrect","trap","enable","mapfile","readarray","hash","bind","complete","compgen","alias","let"]),C={test:new Set(["-v","-R"]),"[":new Set(["-v","-R"]),"[[":new Set(["-v","-R"]),printf:new Set(["-v"]),read:new Set(["-a"]),unset:new Set(["-v"]),wait:new Set(["-p"])},z=new Set(["-eq","-ne","-lt","-le","-gt","-ge"]),T=new Set(["read","unset"]),R=new Set(["-p","-d","-n","-N","-t","-u","-i"]),E=/\/proc\/.*\/environ/,P=/\n[ \t]*#/;export function checkSemantics(t){for(const n of t){let t=n.argv;for(;;)if("time"===t[0]||"nohup"===t[0])t=t.slice(1);else if("timeout"===t[0]){let e=1;for(;e<t.length;){const n=t[e];if("--foreground"===n||"--preserve-status"===n||"--verbose"===n)e++;else if(/^--(?:kill-after|signal)=[A-Za-z0-9_.+-]+$/.test(n))e++;else if(("--kill-after"===n||"--signal"===n)&&t[e+1]&&/^[A-Za-z0-9_.+-]+$/.test(t[e+1]))e+=2;else{if(n.startsWith("--"))return{ok:!1,reason:`timeout with ${n} flag cannot be statically analyzed`};if("-v"===n)e++;else if(("-k"===n||"-s"===n)&&t[e+1]&&/^[A-Za-z0-9_.+-]+$/.test(t[e+1]))e+=2;else{if(!/^-[ks][A-Za-z0-9_.+-]+$/.test(n)){if(n.startsWith("-"))return{ok:!1,reason:`timeout with ${n} flag cannot be statically analyzed`};break}e++}}}if(!t[e]||!/^\d+(?:\.\d+)?[smhd]?$/.test(t[e])){if(t[e])return{ok:!1,reason:`timeout duration '${t[e]}' cannot be statically analyzed`};break}t=t.slice(e+1)}else if("nice"===t[0])if("-n"===t[1]&&t[2]&&/^-?\d+$/.test(t[2]))t=t.slice(3);else if(t[1]&&/^-\d+$/.test(t[1]))t=t.slice(2);else{if(t[1]&&/[$(`]/.test(t[1]))return{ok:!1,reason:`nice argument '${t[1]}' contains expansion — cannot statically determine wrapped command`};t=t.slice(1)}else if("env"===t[0]){let e=1;for(;e<t.length;){const n=t[e];if(n.includes("=")&&!n.startsWith("-"))e++;else if("-i"===n||"-0"===n||"-v"===n)e++;else{if("-u"!==n||!t[e+1]){if(n.startsWith("-"))return{ok:!1,reason:`env with ${n} flag cannot be statically analyzed`};break}e+=2}}if(!(e<t.length))break;t=t.slice(e)}else{if("stdbuf"!==t[0])break;{let e=1;for(;e<t.length;){const n=t[e];if(c.test(n)&&t[e+1])e+=2;else if(l.test(n))e++;else{if(!u.test(n)){if(n.startsWith("-"))return{ok:!1,reason:`stdbuf with ${n} flag cannot be statically analyzed`};break}e++}}if(!(e>1&&e<t.length))break;t=t.slice(e)}}const r=t[0];if(void 0===r)continue;if(""===r)return{ok:!1,reason:"Empty command name — argv[0] may not reflect what bash runs"};if(r.includes(s)||r.includes(i))return{ok:!1,reason:"Command name is runtime-determined (placeholder argv[0])"};if(r.startsWith("-")||r.startsWith("|")||r.startsWith("&"))return{ok:!1,reason:"Command appears to be an incomplete fragment"};const o=C[r];if(void 0!==o)for(let e=1;e<t.length;e++){const n=t[e];if(o.has(n)&&t[e+1]?.includes("["))return{ok:!1,reason:`'${r} ${n}' operand contains array subscript — bash evaluates $(cmd) in subscripts`};if(n.length>2&&"-"===n[0]&&"-"!==n[1]&&!n.includes("["))for(const s of o)if(2===s.length&&n.includes(s[1])&&t[e+1]?.includes("["))return{ok:!1,reason:`'${r} ${s}' (combined in '${n}') operand contains array subscript — bash evaluates $(cmd) in subscripts`};for(const e of o)if(2===e.length&&n.startsWith(e)&&n.length>2&&n.includes("["))return{ok:!1,reason:`'${r} ${e}' (fused) operand contains array subscript — bash evaluates $(cmd) in subscripts`}}if("[["===r)for(let e=2;e<t.length;e++)if(z.has(t[e])&&(t[e-1]?.includes("[")||t[e+1]?.includes("[")))return{ok:!1,reason:`'[[ ... ${t[e]} ... ]]' operand contains array subscript — bash arithmetically evaluates $(cmd) in subscripts`};if(T.has(r)){let e=!1;for(let n=1;n<t.length;n++){const o=t[n];if(e)e=!1;else if("-"!==o[0]){if(o.includes("["))return{ok:!1,reason:`'${r}' positional NAME '${o}' contains array subscript — bash evaluates $(cmd) in subscripts`}}else if("read"===r)if(R.has(o))e=!0;else if(o.length>2&&"-"!==o[1])for(let t=1;t<o.length;t++)if(R.has("-"+o[t])){t===o.length-1&&(e=!0);break}}}if(e.has(r))return{ok:!1,reason:`Shell keyword '${r}' as command name — tree-sitter mis-parse`};for(const e of n.argv)if(e.includes("\n")&&P.test(e))return{ok:!1,reason:"Newline followed by # inside a quoted argument can hide arguments from path validation"};for(const e of n.envVars)if(e.value.includes("\n")&&P.test(e.value))return{ok:!1,reason:"Newline followed by # inside an env var value can hide arguments from path validation"};for(const e of n.redirects)if(e.target.includes("\n")&&P.test(e.target))return{ok:!1,reason:"Newline followed by # inside a redirect target can hide arguments from path validation"};if("jq"===r){for(const e of t)if(/\bsystem\s*\(/.test(e))return{ok:!1,reason:"jq command contains system() function which executes arbitrary commands"};if(t.some(e=>/^(?:-[fL](?:$|[^A-Za-z])|--(?:from-file|rawfile|slurpfile|library-path)(?:$|=))/.test(e)))return{ok:!1,reason:"jq command contains dangerous flags that could execute code or read arbitrary files"}}if($.has(r))return{ok:!1,reason:`Zsh builtin '${r}' can bypass security checks`};if(A.has(r))if("command"!==r||"-v"!==t[1]&&"-V"!==t[1])if("fc"!==r||t.slice(1).some(e=>/^-[^-]*[es]/.test(e))){if("compgen"!==r||t.slice(1).some(e=>/^-[^-]*[CFW]/.test(e)))return{ok:!1,reason:`'${r}' evaluates arguments as shell code`}}else;else;for(const e of n.argv)if(e.includes("/proc/")&&E.test(e))return{ok:!1,reason:"Accesses /proc/*/environ which may expose secrets"};for(const e of n.redirects)if(e.target.includes("/proc/")&&E.test(e.target))return{ok:!1,reason:"Accesses /proc/*/environ which may expose secrets"}}return{ok:!0}}
|
|
1
|
+
import{SHELL_KEYWORDS as e}from"./bashParser.js";import{PARSE_ABORTED as t,parseCommandRaw as n}from"./parser.js";const r=new Set(["program","list","pipeline","redirected_statement"]),o=new Set(["&&","||","|",";","&","|&","\n"]),s="__CMDSUB_OUTPUT__",i="__TRACKED_VAR__";function containsAnyPlaceholder(e){return e.includes(s)||e.includes(i)}const a=/[ \t\n*?[]/,c=/^-[ioe]$/,l=/^-[ioe]./,u=/^--(input|output|error)=/,f=new Set(["HOME","PWD","OLDPWD","USER","LOGNAME","SHELL","PATH","HOSTNAME","UID","EUID","PPID","RANDOM","SECONDS","LINENO","TMPDIR","BASH_VERSION","BASHPID","SHLVL","HISTFILE","IFS"]),p=new Set(["?","$","!","#","0","-"]),d=new Set(["command_substitution","process_substitution","expansion","simple_expansion","brace_expression","subshell","compound_statement","for_statement","while_statement","until_statement","if_statement","case_statement","function_definition","test_command","ansi_c_string","translated_string","herestring_redirect","heredoc_redirect"]),m=[...d];export function nodeTypeId(e){if(!e)return-2;if("ERROR"===e)return-1;const t=m.indexOf(e);return t>=0?t+1:0}const y={">":">",">>":">>","<":"<",">&":">&","<&":"<&",">|":">|","&>":"&>","&>>":"&>>","<<<":"<<<"},h=/\{[^{}\s]*(,|\.\.)[^{}\s]*\}/,g=/[\x00-\x08\x0B-\x1F\x7F]/,x=/[\u00A0\u1680\u2000-\u200B\u2028\u2029\u202F\u205F\u3000\uFEFF]/,b=/\\[ \t]|[^ \t\n\\]\\\n/,k=/~\[/,_=/(?:^|[\s;&|])=[a-zA-Z_]/,w=/\{[^}]*['"]/,v=String.fromCharCode(36);export async function parseForSecurity(e){if(""===e)return{kind:"simple",commands:[]};const t=await n(e);return null===t?{kind:"parse-unavailable"}:parseForSecurityFromAst(e,t)}export function parseForSecurityFromAst(e,n){return g.test(e)?{kind:"too-complex",reason:"Contains control characters"}:x.test(e)?{kind:"too-complex",reason:"Contains Unicode whitespace"}:b.test(e)?{kind:"too-complex",reason:"Contains backslash-escaped whitespace"}:k.test(e)?{kind:"too-complex",reason:"Contains zsh ~[ dynamic directory syntax"}:_.test(e)?{kind:"too-complex",reason:"Contains zsh =cmd equals expansion"}:w.test(function(e){if(!e.includes("{"))return e;const t=[];let n=!1,r=!1,o=0;for(;o<e.length;){const s=e[o];n?("'"===s&&(n=!1),t.push("{"===s?" ":s),o++):r?"\\"!==s||'"'!==e[o+1]&&"\\"!==e[o+1]?('"'===s&&(r=!1),t.push("{"===s?" ":s),o++):(t.push(s,e[o+1]),o+=2):"\\"===s&&o+1<e.length?(t.push(s,e[o+1]),o+=2):("'"===s?n=!0:'"'===s&&(r=!0),t.push(s),o++)}return t.join("")}(e))?{kind:"too-complex",reason:"Contains brace with quote character (expansion obfuscation)"}:""===e.trim()?{kind:"simple",commands:[]}:n===t?{kind:"too-complex",reason:"Parser aborted (timeout or resource limit) — possible adversarial input",nodeType:"PARSE_ABORT"}:function(e){const t=[];return collectCommands(e,t,new Map)||{kind:"simple",commands:t}}(n)}function collectCommands(e,t,n){if("command"===e.type){const r=function(e,t,n,r){const o=[],s=[],i=[];for(const t of e.children)if(t)switch(t.type){case"variable_assignment":{const e=walkVariableAssignment(t,n,r);if("kind"in e)return e;s.push({name:e.name,value:e.value});break}case"command_name":{const e=walkArgument(t.children[0]??t,n,r);if("string"!=typeof e)return e;o.push(e);break}case"word":case"number":case"raw_string":case"string":case"concatenation":case"arithmetic_expansion":{const e=walkArgument(t,n,r);if("string"!=typeof e)return e;o.push(e);break}case"simple_expansion":{const e=resolveSimpleExpansion(t,r,!1);if("string"!=typeof e)return e;o.push(e);break}case"file_redirect":{const e=walkFileRedirect(t,n,r);if("kind"in e)return e;i.push(e);break}case"herestring_redirect":{const e=walkHerestringRedirect(t,n,r);if(e)return e;break}default:return tooComplex(t)}const a=/\$[A-Za-z_]/.test(e.text)||e.text.includes("\n")?o.map(e=>""===e||/["'\\ \t\n$`;|&<>(){}*?[\]~#]/.test(e)?`'${e.replace(/'/g,"'\\''")}'`:e).join(" "):e.text;return{kind:"simple",commands:[{argv:o,envVars:s,redirects:i,text:a}]}}(e,0,t,n);return"simple"!==r.kind?r:(t.push(...r.commands),null)}if("redirected_statement"===e.type)return function(e,t,n){const r=[];let o=null;for(const s of e.children)if(s)if("file_redirect"===s.type){const e=walkFileRedirect(s,t,n);if("kind"in e)return e;r.push(e)}else if("heredoc_redirect"===s.type){const e=walkHeredocRedirect(s);if(e)return e}else{if("command"!==s.type&&"pipeline"!==s.type&&"list"!==s.type&&"negated_command"!==s.type&&"declaration_command"!==s.type&&"unset_command"!==s.type)return tooComplex(s);o=s}if(!o)return t.push({argv:[],envVars:[],redirects:r,text:e.text}),null;const s=t.length,i=collectCommands(o,t,n);if(i)return i;if(t.length>s&&r.length>0){const e=t[t.length-1];e&&e.redirects.push(...r)}return null}(e,t,n);if("comment"===e.type)return null;if(r.has(e.type)){const r="pipeline"===e.type;let s=!1;if(!r)for(const t of e.children)if(t&&("||"===t.type||"&"===t.type)){s=!0;break}const i=s?new Map(n):null;let a=r?new Map(n):n;for(const r of e.children){if(!r)continue;if(o.has(r.type)){"||"!==r.type&&"|"!==r.type&&"|&"!==r.type&&"&"!==r.type||(a=new Map(i??n));continue}const e=collectCommands(r,t,a);if(e)return e}return null}if("negated_command"===e.type){for(const r of e.children)if(r&&"!"!==r.type)return collectCommands(r,t,n);return null}if("declaration_command"===e.type){const r=[];for(const o of e.children)if(o)switch(o.type){case"export":case"local":case"readonly":case"declare":case"typeset":case"variable_name":r.push(o.text);break;case"word":case"number":case"raw_string":case"string":case"concatenation":{const e=walkArgument(o,t,n);if("string"!=typeof e)return e;if(("declare"===r[0]||"typeset"===r[0]||"local"===r[0])&&/^-[a-zA-Z]*[niaA]/.test(e))return{kind:"too-complex",reason:`declare flag ${e} changes assignment semantics (nameref/integer/array)`,nodeType:"declaration_command"};if(("declare"===r[0]||"typeset"===r[0]||"local"===r[0])&&"-"!==e[0]&&/^[^=]*\[/.test(e))return{kind:"too-complex",reason:`declare positional '${e}' contains array subscript — bash evaluates $(cmd) in subscripts`,nodeType:"declaration_command"};r.push(e);break}case"variable_assignment":{const e=walkVariableAssignment(o,t,n);if("kind"in e)return e;applyVarToScope(n,e),r.push(`${e.name}=${e.value}`);break}default:return tooComplex(o)}return t.push({argv:r,envVars:[],redirects:[],text:e.text}),null}if("variable_assignment"===e.type){const r=walkVariableAssignment(e,t,n);return"kind"in r?r:(applyVarToScope(n,r),null)}if("for_statement"===e.type){let r=null,o=null;for(const s of e.children)if(s)if("variable_name"===s.type)r=s.text;else if("do_group"===s.type)o=s;else{if("for"===s.type||"in"===s.type||"select"===s.type||";"===s.type)continue;if("command_substitution"===s.type){const e=collectCommandSubstitution(s,t,n);if(e)return e}else{const e=walkArgument(s,t,n);if("string"!=typeof e)return e}}if(null===r||null===o)return tooComplex(e);if("PS4"===r||"IFS"===r)return{kind:"too-complex",reason:`${r} as loop variable bypasses assignment validation`,nodeType:"for_statement"};n.set(r,i);const s=new Map(n);for(const e of o.children){if(!e)continue;if("do"===e.type||"done"===e.type||";"===e.type)continue;const n=collectCommands(e,t,s);if(n)return n}return null}if("if_statement"===e.type||"while_statement"===e.type){let r=!1;for(const o of e.children){if(!o)continue;if("if"===o.type||"fi"===o.type||"else"===o.type||"elif"===o.type||"while"===o.type||"until"===o.type||";"===o.type)continue;if("then"===o.type){r=!0;continue}if("do_group"===o.type){const e=new Map(n);for(const n of o.children){if(!n)continue;if("do"===n.type||"done"===n.type||";"===n.type)continue;const r=collectCommands(n,t,e);if(r)return r}continue}if("elif_clause"===o.type||"else_clause"===o.type){const e=new Map(n);for(const n of o.children){if(!n)continue;if("elif"===n.type||"else"===n.type||"then"===n.type||";"===n.type)continue;const r=collectCommands(n,t,e);if(r)return r}continue}const e=r?new Map(n):n,s=t.length,a=collectCommands(o,t,e);if(a)return a;if(!r)for(let e=s;e<t.length;e++){const r=t[e];if("read"===r?.argv[0])for(const e of r.argv.slice(1))if(!e.startsWith("-")&&/^[A-Za-z_][A-Za-z0-9_]*$/.test(e)){const t=n.get(e);if(void 0!==t&&!containsAnyPlaceholder(t))return{kind:"too-complex",reason:`'read ${e}' in condition may not execute (||/pipeline/subshell); cannot prove it overwrites tracked literal '${t}'`,nodeType:"if_statement"};n.set(e,i)}}}return null}if("subshell"===e.type){const r=new Map(n);for(const n of e.children){if(!n)continue;if("("===n.type||")"===n.type)continue;const e=collectCommands(n,t,r);if(e)return e}return null}if("test_command"===e.type){const r=["[["];for(const o of e.children){if(!o)continue;if("[["===o.type||"]]"===o.type)continue;if("["===o.type||"]"===o.type)continue;const e=walkTestExpr(o,r,t,n);if(e)return e}return t.push({argv:r,envVars:[],redirects:[],text:e.text}),null}if("unset_command"===e.type){const r=[];for(const o of e.children)if(o)switch(o.type){case"unset":r.push(o.text);break;case"variable_name":r.push(o.text),n.delete(o.text);break;case"word":{const e=walkArgument(o,t,n);if("string"!=typeof e)return e;r.push(e);break}default:return tooComplex(o)}return t.push({argv:r,envVars:[],redirects:[],text:e.text}),null}return tooComplex(e)}function walkTestExpr(e,t,n,r){switch(e.type){case"unary_expression":case"binary_expression":case"negated_expression":case"parenthesized_expression":for(const o of e.children){if(!o)continue;const e=walkTestExpr(o,t,n,r);if(e)return e}return null;case"test_operator":case"!":case"(":case")":case"&&":case"||":case"==":case"=":case"!=":case"<":case">":case"=~":case"regex":case"extglob_pattern":return t.push(e.text),null;default:{const o=walkArgument(e,n,r);return"string"!=typeof o?o:(t.push(o),null)}}}function walkFileRedirect(e,t,n){let r,o=null,s=null;for(const i of e.children)if(i)if("file_descriptor"===i.type)r=Number(i.text);else if(i.type in y)o=y[i.type]??null;else if("word"===i.type||"number"===i.type){if(i.children.length>0)return tooComplex(i);if(h.test(i.text))return tooComplex(i);s=i.text.replace(/\\(.)/g,"$1")}else if("raw_string"===i.type)s=stripRawString(i.text);else if("string"===i.type){const e=walkString(i,t,n);if("string"!=typeof e)return e;s=e}else{if("concatenation"!==i.type)return tooComplex(i);{const e=walkArgument(i,t,n);if("string"!=typeof e)return e;s=e}}return o&&null!==s?{op:o,target:s,fd:r}:{kind:"too-complex",reason:"Unrecognized redirect shape",nodeType:e.type}}function walkHeredocRedirect(e){let t=null,n=null;for(const r of e.children)if(r)if("heredoc_start"===r.type)t=r.text;else if("heredoc_body"===r.type)n=r;else if("<<"!==r.type&&"<<-"!==r.type&&"heredoc_end"!==r.type&&"file_descriptor"!==r.type)return tooComplex(r);if(null===t||!(t.startsWith("'")&&t.endsWith("'")||t.startsWith('"')&&t.endsWith('"')||t.startsWith("\\")))return{kind:"too-complex",reason:"Heredoc with unquoted delimiter undergoes shell expansion",nodeType:"heredoc_redirect"};if(n)for(const e of n.children)if(e&&"heredoc_content"!==e.type)return tooComplex(e);return null}function walkHerestringRedirect(e,t,n){for(const r of e.children){if(!r)continue;if("<<<"===r.type)continue;const e=walkArgument(r,t,n);if("string"!=typeof e)return e;if(P.test(e))return tooComplex(r)}return null}function collectCommandSubstitution(e,t,n){const r=new Map(n);for(const n of e.children){if(!n)continue;if("$("===n.type||"`"===n.type||")"===n.type)continue;const e=collectCommands(n,t,r);if(e)return e}return null}function walkArgument(e,t,n){if(!e)return{kind:"too-complex",reason:"Null argument node"};switch(e.type){case"word":return h.test(e.text)?{kind:"too-complex",reason:"Word contains brace expansion syntax",nodeType:"word"}:e.text.replace(/\\(.)/g,"$1");case"number":return e.children.length>0?{kind:"too-complex",reason:"Number node contains expansion (NN# arithmetic base syntax)",nodeType:e.children[0]?.type}:e.text;case"raw_string":return stripRawString(e.text);case"string":return walkString(e,t,n);case"concatenation":{if(h.test(e.text))return{kind:"too-complex",reason:"Brace expansion",nodeType:"concatenation"};let r="";for(const o of e.children){if(!o)continue;const e=walkArgument(o,t,n);if("string"!=typeof e)return e;r+=e}return r}case"arithmetic_expansion":return walkArithmetic(e)||e.text;case"simple_expansion":return resolveSimpleExpansion(e,n,!1);default:return tooComplex(e)}}function walkString(e,t,n){let r="",o=-1,a=!1,c=!1;for(const l of e.children)if(l)switch(-1!==o&&l.startIndex>o&&'"'!==l.type&&(r+="\n".repeat(l.startIndex-o),c=!0),o=l.endIndex,l.type){case'"':o=l.endIndex;break;case"string_content":r+=l.text.replace(/\\([$`"\\])/g,"$1"),c=!0;break;case v:r+=v,c=!0;break;case"command_substitution":{const e=extractSafeCatHeredoc(l);if("DANGEROUS"===e)return tooComplex(l);if(null!==e){const t=e.replace(/\n+$/,"");if(t.includes("\n")){c=!0;break}r+=t,c=!0;break}const o=collectCommandSubstitution(l,t,n);if(o)return o;r+=s,a=!0;break}case"simple_expansion":{const e=resolveSimpleExpansion(l,n,!0);if("string"!=typeof e)return e;e===i?a=!0:c=!0,r+=e;break}case"arithmetic_expansion":{const e=walkArithmetic(l);if(e)return e;r+=l.text,c=!0;break}default:return tooComplex(l)}return a&&!c||!c&&!a&&e.text.length>2?tooComplex(e):r}const S=/^(?:[0-9]+|0[xX][0-9a-fA-F]+|[0-9]+#[0-9a-zA-Z]+|[-+*/%^&|~!<>=?:(),]+|<<|>>|\*\*|&&|\|\||[<>=!]=|\$\(\(|\)\))$/;function walkArithmetic(e){for(const t of e.children)if(t)if(0!==t.children.length)switch(t.type){case"binary_expression":case"unary_expression":case"ternary_expression":case"parenthesized_expression":{const e=walkArithmetic(t);if(e)return e;break}default:return tooComplex(t)}else if(!S.test(t.text))return{kind:"too-complex",reason:`Arithmetic expansion references variable or non-literal: ${t.text}`,nodeType:"arithmetic_expansion"};return null}function extractSafeCatHeredoc(e){let t=null;for(const n of e.children)if(n&&"$("!==n.type&&")"!==n.type){if("redirected_statement"!==n.type||null!==t)return null;t=n}if(!t)return null;let n=!1,r=null;for(const e of t.children)if(e)if("command"===e.type){const t=e.children.filter(e=>e);if(1!==t.length)return null;const r=t[0];if("command_name"!==r?.type||"cat"!==r.text)return null;n=!0}else{if("heredoc_redirect"!==e.type)return null;if(null!==walkHeredocRedirect(e))return null;for(const t of e.children)"heredoc_body"===t?.type&&(r=t.text)}return n&&null!==r?E.test(r)||/\bsystem\s*\(/.test(r)?"DANGEROUS":r:null}function walkVariableAssignment(e,t,n){let r=null,o="",i=!1;for(const a of e.children)if(a)if("variable_name"===a.type)r=a.text;else{if("="===a.type||"+="===a.type){i="+="===a.type;continue}if("command_substitution"===a.type){const e=collectCommandSubstitution(a,t,n);if(e)return e;o=s}else if("simple_expansion"===a.type){const e=resolveSimpleExpansion(a,n,!0);if("string"!=typeof e)return e;o=e}else{const e=walkArgument(a,t,n);if("string"!=typeof e)return e;o=e}}if(null===r)return{kind:"too-complex",reason:"Variable assignment without name",nodeType:"variable_assignment"};if(!/^[A-Za-z_][A-Za-z0-9_]*$/.test(r))return{kind:"too-complex",reason:`Invalid variable name (bash treats as command): ${r}`,nodeType:"variable_assignment"};if("IFS"===r)return{kind:"too-complex",reason:"IFS assignment changes word-splitting — cannot model statically",nodeType:"variable_assignment"};if("PS4"===r){if(i)return{kind:"too-complex",reason:"PS4 += cannot be statically verified — combine into a single PS4= assignment",nodeType:"variable_assignment"};if(containsAnyPlaceholder(o))return{kind:"too-complex",reason:"PS4 value derived from cmdsub/variable — runtime unknowable",nodeType:"variable_assignment"};if(!/^[A-Za-z0-9 _+:./=[\]-]*$/.test(o.replace(/\$\{[A-Za-z_][A-Za-z0-9_]*\}/g,"")))return{kind:"too-complex",reason:"PS4 value outside safe charset — only ${VAR} refs and [A-Za-z0-9 _+:.=/[]-] allowed",nodeType:"variable_assignment"}}return o.includes("~")?{kind:"too-complex",reason:"Tilde in assignment value — bash may expand at assignment time",nodeType:"variable_assignment"}:{name:r,value:o,isAppend:i}}function resolveSimpleExpansion(e,t,n){let r=null,o=!1;for(const t of e.children){if("variable_name"===t?.type){r=t.text;break}if("special_variable_name"===t?.type){r=t.text,o=!0;break}}if(null===r)return tooComplex(e);const s=t.get(r);if(void 0!==s){if(containsAnyPlaceholder(s))return n?i:tooComplex(e);if(!n){if(""===s)return tooComplex(e);if(a.test(s))return tooComplex(e)}return s}if(n){if(f.has(r))return i;if(o&&(p.has(r)||/^[0-9]+$/.test(r)))return i}return tooComplex(e)}function applyVarToScope(e,t){const n=e.get(t.name)??"",r=t.isAppend?n+t.value:t.value;e.set(t.name,containsAnyPlaceholder(r)?i:r)}function stripRawString(e){return e.slice(1,-1)}function tooComplex(e){return{kind:"too-complex",reason:"ERROR"===e.type?"Parse error":d.has(e.type)?`Contains ${e.type}`:`Unhandled node type: ${e.type}`,nodeType:e.type}}const A=new Set(["zmodload","emulate","sysopen","sysread","syswrite","sysseek","zpty","ztcp","zsocket","zf_rm","zf_mv","zf_ln","zf_chmod","zf_chown","zf_mkdir","zf_rmdir","zf_chgrp"]),$=new Set(["eval","source",".","exec","command","builtin","fc","coproc","noglob","nocorrect","trap","enable","mapfile","readarray","hash","bind","complete","compgen","alias","let"]),C={test:new Set(["-v","-R"]),"[":new Set(["-v","-R"]),"[[":new Set(["-v","-R"]),printf:new Set(["-v"]),read:new Set(["-a"]),unset:new Set(["-v"]),wait:new Set(["-p"])},z=new Set(["-eq","-ne","-lt","-le","-gt","-ge"]),T=new Set(["read","unset"]),R=new Set(["-p","-d","-n","-N","-t","-u","-i"]),E=/\/proc\/.*\/environ/,P=/\n[ \t]*#/;export function checkSemantics(t){for(const n of t){let t=n.argv;for(;;)if("time"===t[0]||"nohup"===t[0])t=t.slice(1);else if("timeout"===t[0]){let e=1;for(;e<t.length;){const n=t[e];if("--foreground"===n||"--preserve-status"===n||"--verbose"===n)e++;else if(/^--(?:kill-after|signal)=[A-Za-z0-9_.+-]+$/.test(n))e++;else if(("--kill-after"===n||"--signal"===n)&&t[e+1]&&/^[A-Za-z0-9_.+-]+$/.test(t[e+1]))e+=2;else{if(n.startsWith("--"))return{ok:!1,reason:`timeout with ${n} flag cannot be statically analyzed`};if("-v"===n)e++;else if(("-k"===n||"-s"===n)&&t[e+1]&&/^[A-Za-z0-9_.+-]+$/.test(t[e+1]))e+=2;else{if(!/^-[ks][A-Za-z0-9_.+-]+$/.test(n)){if(n.startsWith("-"))return{ok:!1,reason:`timeout with ${n} flag cannot be statically analyzed`};break}e++}}}if(!t[e]||!/^\d+(?:\.\d+)?[smhd]?$/.test(t[e])){if(t[e])return{ok:!1,reason:`timeout duration '${t[e]}' cannot be statically analyzed`};break}t=t.slice(e+1)}else if("nice"===t[0])if("-n"===t[1]&&t[2]&&/^-?\d+$/.test(t[2]))t=t.slice(3);else if(t[1]&&/^-\d+$/.test(t[1]))t=t.slice(2);else{if(t[1]&&/[$(`]/.test(t[1]))return{ok:!1,reason:`nice argument '${t[1]}' contains expansion — cannot statically determine wrapped command`};t=t.slice(1)}else if("env"===t[0]){let e=1;for(;e<t.length;){const n=t[e];if(n.includes("=")&&!n.startsWith("-"))e++;else if("-i"===n||"-0"===n||"-v"===n)e++;else{if("-u"!==n||!t[e+1]){if(n.startsWith("-"))return{ok:!1,reason:`env with ${n} flag cannot be statically analyzed`};break}e+=2}}if(!(e<t.length))break;t=t.slice(e)}else{if("stdbuf"!==t[0])break;{let e=1;for(;e<t.length;){const n=t[e];if(c.test(n)&&t[e+1])e+=2;else if(l.test(n))e++;else{if(!u.test(n)){if(n.startsWith("-"))return{ok:!1,reason:`stdbuf with ${n} flag cannot be statically analyzed`};break}e++}}if(!(e>1&&e<t.length))break;t=t.slice(e)}}const r=t[0];if(void 0===r)continue;if(""===r)return{ok:!1,reason:"Empty command name — argv[0] may not reflect what bash runs"};if(r.includes(s)||r.includes(i))return{ok:!1,reason:"Command name is runtime-determined (placeholder argv[0])"};if(r.startsWith("-")||r.startsWith("|")||r.startsWith("&"))return{ok:!1,reason:"Command appears to be an incomplete fragment"};const o=C[r];if(void 0!==o)for(let e=1;e<t.length;e++){const n=t[e];if(o.has(n)&&t[e+1]?.includes("["))return{ok:!1,reason:`'${r} ${n}' operand contains array subscript — bash evaluates $(cmd) in subscripts`};if(n.length>2&&"-"===n[0]&&"-"!==n[1]&&!n.includes("["))for(const s of o)if(2===s.length&&n.includes(s[1])&&t[e+1]?.includes("["))return{ok:!1,reason:`'${r} ${s}' (combined in '${n}') operand contains array subscript — bash evaluates $(cmd) in subscripts`};for(const e of o)if(2===e.length&&n.startsWith(e)&&n.length>2&&n.includes("["))return{ok:!1,reason:`'${r} ${e}' (fused) operand contains array subscript — bash evaluates $(cmd) in subscripts`}}if("[["===r)for(let e=2;e<t.length;e++)if(z.has(t[e])&&(t[e-1]?.includes("[")||t[e+1]?.includes("[")))return{ok:!1,reason:`'[[ ... ${t[e]} ... ]]' operand contains array subscript — bash arithmetically evaluates $(cmd) in subscripts`};if(T.has(r)){let e=!1;for(let n=1;n<t.length;n++){const o=t[n];if(e)e=!1;else if("-"!==o[0]){if(o.includes("["))return{ok:!1,reason:`'${r}' positional NAME '${o}' contains array subscript — bash evaluates $(cmd) in subscripts`}}else if("read"===r)if(R.has(o))e=!0;else if(o.length>2&&"-"!==o[1])for(let t=1;t<o.length;t++)if(R.has("-"+o[t])){t===o.length-1&&(e=!0);break}}}if(e.has(r))return{ok:!1,reason:`Shell keyword '${r}' as command name — tree-sitter mis-parse`};for(const e of n.argv)if(e.includes("\n")&&P.test(e))return{ok:!1,reason:"Newline followed by # inside a quoted argument can hide arguments from path validation"};for(const e of n.envVars)if(e.value.includes("\n")&&P.test(e.value))return{ok:!1,reason:"Newline followed by # inside an env var value can hide arguments from path validation"};for(const e of n.redirects)if(e.target.includes("\n")&&P.test(e.target))return{ok:!1,reason:"Newline followed by # inside a redirect target can hide arguments from path validation"};if("jq"===r){for(const e of t)if(/\bsystem\s*\(/.test(e))return{ok:!1,reason:"jq command contains system() function which executes arbitrary commands"};if(t.some(e=>/^(?:-[fL](?:$|[^A-Za-z])|--(?:from-file|rawfile|slurpfile|library-path)(?:$|=))/.test(e)))return{ok:!1,reason:"jq command contains dangerous flags that could execute code or read arbitrary files"}}if(A.has(r))return{ok:!1,reason:`Zsh builtin '${r}' can bypass security checks`};if($.has(r)&&("command"!==r||"-v"!==t[1]&&"-V"!==t[1])&&("fc"!==r||t.slice(1).some(e=>/^-[^-]*[es]/.test(e)))&&("compgen"!==r||t.slice(1).some(e=>/^-[^-]*[CFW]/.test(e))))return{ok:!1,reason:`'${r}' evaluates arguments as shell code`};for(const e of n.argv)if(e.includes("/proc/")&&E.test(e))return{ok:!1,reason:"Accesses /proc/*/environ which may expose secrets"};for(const e of n.redirects)if(e.target.includes("/proc/")&&E.test(e.target))return{ok:!1,reason:"Accesses /proc/*/environ which may expose secrets"}}return{ok:!0}}
|