@profoundlogic/coderflow-server 0.2.1
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/LICENSE.txt +322 -0
- package/README.md +158 -0
- package/dist/LICENSE.txt +322 -0
- package/dist/README.md +158 -0
- package/dist/base-image/Dockerfile +184 -0
- package/dist/base-image/agent-wrapper.sh +143 -0
- package/dist/base-image/apply-local-state.sh +357 -0
- package/dist/base-image/coder-git-credential-helper +307 -0
- package/dist/base-image/entrypoint.sh +942 -0
- package/dist/base-image/ssh_config_template +41 -0
- package/dist/base-image/start-code-server.sh +76 -0
- package/dist/base-image/sync-repos.sh +170 -0
- package/dist/base-image/vscode-extensions.txt +10 -0
- package/dist/base-image/vscode-settings.json +41 -0
- package/dist/coder-server.js +2 -0
- package/dist/config/cli-models.json +45 -0
- package/dist/config/imported-skills.schema.json +83 -0
- package/dist/config/skill-catalog.json +18 -0
- package/dist/config/skill-catalog.schema.json +140 -0
- package/dist/config.js +1 -0
- package/dist/examples/oidc.json.example +11 -0
- package/dist/lib/agent-keepalive.js +1 -0
- package/dist/lib/api-keys.js +1 -0
- package/dist/lib/apiKeys.js +1 -0
- package/dist/lib/auto-judge.js +1 -0
- package/dist/lib/basic-auth.js +1 -0
- package/dist/lib/build-history.js +1 -0
- package/dist/lib/build-output-service.js +1 -0
- package/dist/lib/build-scheduler.js +1 -0
- package/dist/lib/build-service.js +1 -0
- package/dist/lib/claude-oauth-refresh.js +1 -0
- package/dist/lib/cli/build.js +1 -0
- package/dist/lib/cli/config-command.js +1 -0
- package/dist/lib/cli/config.js +1 -0
- package/dist/lib/cli/create-user.js +1 -0
- package/dist/lib/cli/init.js +1 -0
- package/dist/lib/cli/jira.js +1 -0
- package/dist/lib/cli/license.js +1 -0
- package/dist/lib/cli/server-manager.js +1 -0
- package/dist/lib/container-tokens.js +1 -0
- package/dist/lib/data-dir.js +1 -0
- package/dist/lib/deployment-history.js +1 -0
- package/dist/lib/deployment-service.js +1 -0
- package/dist/lib/docker-utils.js +1 -0
- package/dist/lib/email.js +1 -0
- package/dist/lib/emailTemplates.js +1 -0
- package/dist/lib/entitlement.js +1 -0
- package/dist/lib/fetch-utils.js +1 -0
- package/dist/lib/git-provider-service.js +1 -0
- package/dist/lib/git-provider-setup/assets/coderflow_github_app.png +0 -0
- package/dist/lib/git-provider-setup/github-setup-handler.js +1 -0
- package/dist/lib/git-provider-setup/index.js +1 -0
- package/dist/lib/git-provider-setup/setup-factory.js +1 -0
- package/dist/lib/git-provider-setup/setup-interface.js +1 -0
- package/dist/lib/git-providers/azure-devops-provider.js +1 -0
- package/dist/lib/git-providers/github-app-provider.js +1 -0
- package/dist/lib/git-providers/index.js +1 -0
- package/dist/lib/git-providers/provider-factory.js +1 -0
- package/dist/lib/git-providers/provider-interface.js +1 -0
- package/dist/lib/jira-client.js +1 -0
- package/dist/lib/logger.js +1 -0
- package/dist/lib/model-fetcher.js +1 -0
- package/dist/lib/notifications.js +1 -0
- package/dist/lib/oidc-auth.js +1 -0
- package/dist/lib/oidc-device-flow.js +1 -0
- package/dist/lib/passwordTokens.js +1 -0
- package/dist/lib/pin-cascade.js +1 -0
- package/dist/lib/provider-accounts.js +1 -0
- package/dist/lib/provider-oauth.js +1 -0
- package/dist/lib/provider-profile.js +1 -0
- package/dist/lib/provider-token-refresh.js +1 -0
- package/dist/lib/roles.js +1 -0
- package/dist/lib/secrets.js +1 -0
- package/dist/lib/state-capture.js +1 -0
- package/dist/lib/static-files.js +1 -0
- package/dist/lib/task-name-generator.js +1 -0
- package/dist/lib/users.js +1 -0
- package/dist/middleware/requireAuth.js +1 -0
- package/dist/middleware/requireInit.js +1 -0
- package/dist/middleware/requirePermission.js +1 -0
- package/dist/package-lock.json +4151 -0
- package/dist/package.json +50 -0
- package/dist/routes/apiKeys.js +1 -0
- package/dist/routes/auth-oidc.js +1 -0
- package/dist/routes/auth.js +1 -0
- package/dist/routes/build.js +1 -0
- package/dist/routes/containers.js +1 -0
- package/dist/routes/deploy-task.js +1 -0
- package/dist/routes/environment-management.js +1 -0
- package/dist/routes/environments.js +1 -0
- package/dist/routes/external-skills.js +1 -0
- package/dist/routes/git-credentials.js +1 -0
- package/dist/routes/git-provider-setup.js +1 -0
- package/dist/routes/health.js +1 -0
- package/dist/routes/jira.js +1 -0
- package/dist/routes/objective-management.js +1 -0
- package/dist/routes/password.js +1 -0
- package/dist/routes/prompt.js +1 -0
- package/dist/routes/provider-auth.js +1 -0
- package/dist/routes/qa.js +1 -0
- package/dist/routes/settings.js +1 -0
- package/dist/routes/skill-management.js +1 -0
- package/dist/routes/skills.js +1 -0
- package/dist/routes/tasks.js +2 -0
- package/dist/routes/templates.js +1 -0
- package/dist/routes/test-task.js +1 -0
- package/dist/routes/test.js +1 -0
- package/dist/routes/users.js +1 -0
- package/dist/routes/visualizations.js +1 -0
- package/dist/schemas/template-metadata.schema.json +178 -0
- package/dist/scripts/create-user.js +2 -0
- package/dist/shipped-skills/environment-instructions/SKILL.md +154 -0
- package/dist/shipped-skills/environment-templates/SKILL.md +282 -0
- package/dist/shipped-skills/objective-management/SKILL.md +238 -0
- package/dist/shipped-skills/skill-editor/SKILL.md +326 -0
- package/dist/start.js +2 -0
- package/dist/web-ui/public/activity-detail-modal.js +1 -0
- package/dist/web-ui/public/activity-feed.js +1 -0
- package/dist/web-ui/public/activity-formatters.js +1 -0
- package/dist/web-ui/public/agent-event-parser.js +1 -0
- package/dist/web-ui/public/app.js +1 -0
- package/dist/web-ui/public/approve-dialog.js +1 -0
- package/dist/web-ui/public/coderflow-logo-reversed.svg +46 -0
- package/dist/web-ui/public/coderflow-logo.svg +46 -0
- package/dist/web-ui/public/comments-widget.js +1 -0
- package/dist/web-ui/public/docs/.nojekyll +0 -0
- package/dist/web-ui/public/docs/README.md +26 -0
- package/dist/web-ui/public/docs/_sidebar.md +47 -0
- package/dist/web-ui/public/docs/admin/ai-providers.md +132 -0
- package/dist/web-ui/public/docs/admin/email-notifications.md +69 -0
- package/dist/web-ui/public/docs/admin/environments.md +215 -0
- package/dist/web-ui/public/docs/admin/git-providers.md +147 -0
- package/dist/web-ui/public/docs/admin/installation.md +313 -0
- package/dist/web-ui/public/docs/admin/skills.md +35 -0
- package/dist/web-ui/public/docs/admin/sso.md +241 -0
- package/dist/web-ui/public/docs/admin/users-and-roles.md +57 -0
- package/dist/web-ui/public/docs/code/cli.md +102 -0
- package/dist/web-ui/public/docs/code/files-and-editing.md +86 -0
- package/dist/web-ui/public/docs/code/terminal-access.md +110 -0
- package/dist/web-ui/public/docs/code/vscode-extension.md +58 -0
- package/dist/web-ui/public/docs/getting-started/core-concepts.md +129 -0
- package/dist/web-ui/public/docs/getting-started/overview.md +46 -0
- package/dist/web-ui/public/docs/index.html +151 -0
- package/dist/web-ui/public/docs/integrations/custom.md +58 -0
- package/dist/web-ui/public/docs/integrations/ibmi/overview.md +58 -0
- package/dist/web-ui/public/docs/integrations/overview.md +48 -0
- package/dist/web-ui/public/docs/objectives/qa-mode.md +90 -0
- package/dist/web-ui/public/docs/objectives/staged-tasks.md +60 -0
- package/dist/web-ui/public/docs/objectives/working-with-objectives.md +102 -0
- package/dist/web-ui/public/docs/tasks/approval-and-deployment.md +83 -0
- package/dist/web-ui/public/docs/tasks/creating-tasks.md +111 -0
- package/dist/web-ui/public/docs/tasks/judging.md +114 -0
- package/dist/web-ui/public/docs/tasks/providing-feedback.md +41 -0
- package/dist/web-ui/public/docs/tasks/task-groups.md +73 -0
- package/dist/web-ui/public/docs/tasks/winner-selection.md +75 -0
- package/dist/web-ui/public/docs/templates/batch-processing.md +152 -0
- package/dist/web-ui/public/docs/templates/task-templates.md +44 -0
- package/dist/web-ui/public/docs/templates/template-examples.md +93 -0
- package/dist/web-ui/public/docs/testing/profound-automated-testing.md +77 -0
- package/dist/web-ui/public/docs/testing/task-visualizations.md +42 -0
- package/dist/web-ui/public/docs/testing/testing-menu.md +118 -0
- package/dist/web-ui/public/environments.css +3942 -0
- package/dist/web-ui/public/environments.html +1791 -0
- package/dist/web-ui/public/environments.js +1 -0
- package/dist/web-ui/public/favicon-16.png +0 -0
- package/dist/web-ui/public/favicon-32.png +0 -0
- package/dist/web-ui/public/favicon.ico +0 -0
- package/dist/web-ui/public/feedback-widget.css +3133 -0
- package/dist/web-ui/public/feedback-widget.js +1 -0
- package/dist/web-ui/public/git-history.css +2663 -0
- package/dist/web-ui/public/git-history.html +272 -0
- package/dist/web-ui/public/git-history.js +1 -0
- package/dist/web-ui/public/git-status.js +1 -0
- package/dist/web-ui/public/index.html +1459 -0
- package/dist/web-ui/public/index.js +1 -0
- package/dist/web-ui/public/login.html +346 -0
- package/dist/web-ui/public/login.js +1 -0
- package/dist/web-ui/public/markdown-editor.js +1 -0
- package/dist/web-ui/public/markdown-file-editor.js +1 -0
- package/dist/web-ui/public/modal-maximize.js +1 -0
- package/dist/web-ui/public/notifications.js +1 -0
- package/dist/web-ui/public/server-health.js +1 -0
- package/dist/web-ui/public/settings.css +761 -0
- package/dist/web-ui/public/settings.html +1044 -0
- package/dist/web-ui/public/settings.js +1 -0
- package/dist/web-ui/public/setup-password.html +355 -0
- package/dist/web-ui/public/setup-password.js +1 -0
- package/dist/web-ui/public/skills.css +1949 -0
- package/dist/web-ui/public/skills.html +820 -0
- package/dist/web-ui/public/skills.js +1 -0
- package/dist/web-ui/public/sse-client.js +1 -0
- package/dist/web-ui/public/sse-shared-worker.js +1 -0
- package/dist/web-ui/public/styles.css +18614 -0
- package/dist/web-ui/public/task.html +1779 -0
- package/dist/web-ui/public/task.js +1 -0
- package/dist/web-ui/public/terminal.html +45 -0
- package/dist/web-ui/public/terminal.js +1 -0
- package/dist/web-ui/public/theme.js +1 -0
- package/dist/web-ui/public/users.html +298 -0
- package/dist/web-ui/public/users.js +1 -0
- package/dist/web-ui/public/variant-grouping.js +1 -0
- package/package.json +63 -0
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
# CoderFlow Base Image
|
|
2
|
+
# Minimal image with Node.js, Python, and Git for AI agent execution
|
|
3
|
+
|
|
4
|
+
FROM node:24-slim
|
|
5
|
+
|
|
6
|
+
# Set timezone to Eastern Time to match idev
|
|
7
|
+
ENV TZ=America/New_York
|
|
8
|
+
|
|
9
|
+
# Build arguments for user UID/GID (auto-detected from host, defaults to 1000)
|
|
10
|
+
ARG USER_UID=1000
|
|
11
|
+
ARG USER_GID=1000
|
|
12
|
+
|
|
13
|
+
# Install essential tools for development and troubleshooting
|
|
14
|
+
# Includes Playwright/Chromium dependencies for browser automation
|
|
15
|
+
RUN apt-get update && \
|
|
16
|
+
apt-get install -y \
|
|
17
|
+
expect \
|
|
18
|
+
tzdata \
|
|
19
|
+
git \
|
|
20
|
+
jq \
|
|
21
|
+
procps \
|
|
22
|
+
curl \
|
|
23
|
+
wget \
|
|
24
|
+
netcat-openbsd \
|
|
25
|
+
dnsutils \
|
|
26
|
+
iputils-ping \
|
|
27
|
+
telnet \
|
|
28
|
+
vim \
|
|
29
|
+
nano \
|
|
30
|
+
openssh-client \
|
|
31
|
+
make \
|
|
32
|
+
uuid-runtime \
|
|
33
|
+
lsof \
|
|
34
|
+
python3 \
|
|
35
|
+
python3-pip \
|
|
36
|
+
python3-venv \
|
|
37
|
+
ripgrep \
|
|
38
|
+
# Document handling tools
|
|
39
|
+
unzip \
|
|
40
|
+
poppler-utils \
|
|
41
|
+
# Playwright/Chromium dependencies (prebaked to avoid needing sudo at runtime)
|
|
42
|
+
libasound2 \
|
|
43
|
+
libatk-bridge2.0-0 \
|
|
44
|
+
libatk1.0-0 \
|
|
45
|
+
libatspi2.0-0 \
|
|
46
|
+
libcairo2 \
|
|
47
|
+
libcups2 \
|
|
48
|
+
libdbus-1-3 \
|
|
49
|
+
libdrm2 \
|
|
50
|
+
libgbm1 \
|
|
51
|
+
libglib2.0-0 \
|
|
52
|
+
libnspr4 \
|
|
53
|
+
libnss3 \
|
|
54
|
+
libpango-1.0-0 \
|
|
55
|
+
libx11-6 \
|
|
56
|
+
libxcb1 \
|
|
57
|
+
libxcomposite1 \
|
|
58
|
+
libxdamage1 \
|
|
59
|
+
libxext6 \
|
|
60
|
+
libxfixes3 \
|
|
61
|
+
libxkbcommon0 \
|
|
62
|
+
libxrandr2 \
|
|
63
|
+
xvfb && \
|
|
64
|
+
ln -sf /usr/share/zoneinfo/America/New_York /etc/localtime && \
|
|
65
|
+
echo "America/New_York" > /etc/timezone && \
|
|
66
|
+
apt-get clean && \
|
|
67
|
+
rm -rf /var/lib/apt/lists/* && \
|
|
68
|
+
ln -s /usr/bin/python3 /usr/bin/python
|
|
69
|
+
|
|
70
|
+
# Install Python libraries for document handling (docx, pdf)
|
|
71
|
+
RUN pip install --break-system-packages python-docx pypdf pdfplumber
|
|
72
|
+
|
|
73
|
+
# Remove the default 'node' user that comes with node:24-slim (typically UID 1000)
|
|
74
|
+
# This prevents conflicts when we create our own user with specified UID
|
|
75
|
+
RUN userdel -r node 2>/dev/null || true
|
|
76
|
+
|
|
77
|
+
# Create 'coder' user and group with UID/GID from build args
|
|
78
|
+
# This matches the host user's UID/GID, eliminating permission issues
|
|
79
|
+
RUN groupadd -g ${USER_GID} coder && \
|
|
80
|
+
useradd -m -u ${USER_UID} -g ${USER_GID} -s /bin/bash coder && \
|
|
81
|
+
mkdir -p /home/coder/.ssh /home/coder/.claude /home/coder/.codex \
|
|
82
|
+
/home/coder/.config/google-generative-ai /home/coder/.gemini && \
|
|
83
|
+
chown -R coder:coder /home/coder
|
|
84
|
+
|
|
85
|
+
# Configure git for root user (used during docker builds with BuildKit secrets)
|
|
86
|
+
RUN git config --global credential.helper store && \
|
|
87
|
+
git config --global --add safe.directory '*' && \
|
|
88
|
+
git config --global core.autocrlf false
|
|
89
|
+
|
|
90
|
+
# Configure git for coder user (used at runtime in containers)
|
|
91
|
+
# Credential helper chain: our custom helper first, then store as fallback
|
|
92
|
+
# Our helper only responds for managed repos (in CODER_MANAGED_REPOS); others fall through to store
|
|
93
|
+
# useHttpPath ensures Git sends the full repo path to credential helpers (needed for per-repo matching)
|
|
94
|
+
RUN su - coder -c "git config --global credential.helper '/usr/local/bin/coder-git-credential-helper' && \
|
|
95
|
+
git config --global --add credential.helper store && \
|
|
96
|
+
git config --global credential.useHttpPath true && \
|
|
97
|
+
git config --global --add safe.directory '*' && \
|
|
98
|
+
git config --global core.autocrlf false"
|
|
99
|
+
|
|
100
|
+
# Pre-populate SSH known_hosts with GitHub host keys at build time
|
|
101
|
+
# This eliminates the need for ssh-keyscan at runtime, preventing connection storms
|
|
102
|
+
# when multiple containers start simultaneously
|
|
103
|
+
RUN mkdir -p /etc/ssh && \
|
|
104
|
+
ssh-keyscan github.com >> /etc/ssh/ssh_known_hosts 2>/dev/null && \
|
|
105
|
+
chmod 644 /etc/ssh/ssh_known_hosts
|
|
106
|
+
|
|
107
|
+
# Configure SSH connection multiplexing for GitHub
|
|
108
|
+
# This enables connection reuse across multiple git operations, reducing overhead
|
|
109
|
+
COPY ssh_config_template /etc/ssh/ssh_config.d/10-github-multiplexing.conf
|
|
110
|
+
RUN chmod 644 /etc/ssh/ssh_config.d/10-github-multiplexing.conf
|
|
111
|
+
|
|
112
|
+
# Configure shell to source ~/.bash_env for environment variables
|
|
113
|
+
# This allows setup.sh to write env vars that persist in all shells (login and non-login)
|
|
114
|
+
RUN sed -i '/^# If not running interactively/i # Source environment variables from setup.sh\nif [ -f ~/.bash_env ]; then\n . ~/.bash_env\nfi\n' /home/coder/.bashrc && \
|
|
115
|
+
printf '\n# Source environment variables from setup.sh\nif [ -f ~/.bash_env ]; then\n . ~/.bash_env\nfi\n' >> /home/coder/.profile
|
|
116
|
+
|
|
117
|
+
# Install Claude Code, Codex, and Gemini CLI globally
|
|
118
|
+
RUN npm install -g @openai/codex @google/gemini-cli && \
|
|
119
|
+
su - coder -c "curl -fsSL https://claude.ai/install.sh | bash"
|
|
120
|
+
|
|
121
|
+
# Pre-install Playwright browser binaries (not the skill itself)
|
|
122
|
+
# This caches ~165MB of Chromium so skills that need browser automation don't have to download at runtime
|
|
123
|
+
# System dependencies are already installed above (libasound2, libatk*, etc.)
|
|
124
|
+
RUN su - coder -c "npx playwright install chromium"
|
|
125
|
+
|
|
126
|
+
# Install code-server for web-based VS Code
|
|
127
|
+
RUN curl -fsSL https://code-server.dev/install.sh | sh && \
|
|
128
|
+
mkdir -p /home/coder/.local/share/code-server && \
|
|
129
|
+
mkdir -p /home/coder/.config/code-server && \
|
|
130
|
+
chown -R coder:coder /home/coder/.local /home/coder/.config
|
|
131
|
+
|
|
132
|
+
# Pre-install VS Code extensions from configurable list
|
|
133
|
+
COPY vscode-extensions.txt /tmp/vscode-extensions.txt
|
|
134
|
+
RUN while IFS= read -r extension || [ -n "$extension" ]; do \
|
|
135
|
+
# Skip comments and empty lines
|
|
136
|
+
case "$extension" in \
|
|
137
|
+
\#*|'') continue ;; \
|
|
138
|
+
esac; \
|
|
139
|
+
echo "Installing extension: $extension"; \
|
|
140
|
+
su - coder -c "code-server --install-extension $extension" || echo "Failed to install $extension"; \
|
|
141
|
+
done < /tmp/vscode-extensions.txt && \
|
|
142
|
+
rm /tmp/vscode-extensions.txt
|
|
143
|
+
|
|
144
|
+
# Configure default VS Code settings for minimal layout
|
|
145
|
+
COPY vscode-settings.json /tmp/vscode-settings.json
|
|
146
|
+
RUN mkdir -p /home/coder/.local/share/code-server/User && \
|
|
147
|
+
cp /tmp/vscode-settings.json /home/coder/.local/share/code-server/User/settings.json && \
|
|
148
|
+
rm /tmp/vscode-settings.json && \
|
|
149
|
+
chown -R coder:coder /home/coder/.local
|
|
150
|
+
|
|
151
|
+
# Disable built-in chat/AI extensions that may show unwanted panels
|
|
152
|
+
RUN if [ -d "/usr/lib/code-server/lib/vscode/extensions/mermaid-chat-features" ]; then \
|
|
153
|
+
mv /usr/lib/code-server/lib/vscode/extensions/mermaid-chat-features \
|
|
154
|
+
/usr/lib/code-server/lib/vscode/extensions/mermaid-chat-features.disabled || true; \
|
|
155
|
+
fi
|
|
156
|
+
|
|
157
|
+
# Create workspace directory for repositories
|
|
158
|
+
RUN mkdir -p /workspace && \
|
|
159
|
+
chown coder:coder /workspace
|
|
160
|
+
|
|
161
|
+
# Create task-output directory for results
|
|
162
|
+
RUN mkdir -p /task-output && \
|
|
163
|
+
chown coder:coder /task-output
|
|
164
|
+
|
|
165
|
+
# Set working directory
|
|
166
|
+
WORKDIR /workspace
|
|
167
|
+
|
|
168
|
+
# Copy entrypoint script and AI agent wrapper
|
|
169
|
+
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
|
|
170
|
+
COPY sync-repos.sh /usr/local/bin/sync-repos.sh
|
|
171
|
+
COPY agent-wrapper.sh /usr/local/bin/agent-wrapper.sh
|
|
172
|
+
COPY start-code-server.sh /usr/local/bin/start-code-server.sh
|
|
173
|
+
COPY apply-local-state.sh /usr/local/bin/apply-local-state.sh
|
|
174
|
+
COPY coder-git-credential-helper /usr/local/bin/coder-git-credential-helper
|
|
175
|
+
RUN chmod +x /usr/local/bin/entrypoint.sh /usr/local/bin/sync-repos.sh /usr/local/bin/agent-wrapper.sh /usr/local/bin/start-code-server.sh /usr/local/bin/apply-local-state.sh /usr/local/bin/coder-git-credential-helper
|
|
176
|
+
|
|
177
|
+
# Expose code-server port
|
|
178
|
+
EXPOSE 8080
|
|
179
|
+
|
|
180
|
+
# Set entrypoint
|
|
181
|
+
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
|
|
182
|
+
|
|
183
|
+
# Default command: none (entrypoint will run default task)
|
|
184
|
+
CMD []
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Wrapper script to run AI agents (Claude/Codex/Gemini) and output JSON statistics
|
|
3
|
+
#
|
|
4
|
+
# Model selection via environment variables:
|
|
5
|
+
# CLAUDE_MODEL - Model for Claude (e.g., opus, sonnet, haiku)
|
|
6
|
+
# OPENAI_MODEL - Model for Codex/OpenAI (e.g., gpt-5.2-codex)
|
|
7
|
+
# GEMINI_MODEL - Model for Gemini (e.g., gemini-2.5-pro)
|
|
8
|
+
# CODEX_REASONING_LEVEL - Reasoning level for Codex (low, medium, high, xhigh)
|
|
9
|
+
#
|
|
10
|
+
# If model env vars are not set, agents use their default models.
|
|
11
|
+
|
|
12
|
+
# First argument is the agent command, rest are passed to the agent
|
|
13
|
+
AGENT_CMD="$1"
|
|
14
|
+
shift
|
|
15
|
+
|
|
16
|
+
echo "[$(date +'%Y-%m-%d %H:%M:%S')] Starting agent: $AGENT_CMD" >&2
|
|
17
|
+
|
|
18
|
+
# Log model configuration if set
|
|
19
|
+
if [[ -n "$CLAUDE_MODEL" ]] || [[ -n "$OPENAI_MODEL" ]] || [[ -n "$GEMINI_MODEL" ]]; then
|
|
20
|
+
echo "[$(date +'%Y-%m-%d %H:%M:%S')] Model configuration: CLAUDE_MODEL=${CLAUDE_MODEL:-default} OPENAI_MODEL=${OPENAI_MODEL:-default} GEMINI_MODEL=${GEMINI_MODEL:-default}" >&2
|
|
21
|
+
fi
|
|
22
|
+
|
|
23
|
+
START_TIME=$(date +%s%3N)
|
|
24
|
+
|
|
25
|
+
# Save stdin to temp file
|
|
26
|
+
TEMP_INPUT=$(mktemp)
|
|
27
|
+
cat > "$TEMP_INPUT"
|
|
28
|
+
|
|
29
|
+
mkdir -p /task-output
|
|
30
|
+
|
|
31
|
+
# UNIFIED APPROACH FOR ALL AGENTS:
|
|
32
|
+
# - Run agent once, stream output to debug-stream.jsonl
|
|
33
|
+
# - Capture exit code
|
|
34
|
+
# - Generate a simple success/failure result
|
|
35
|
+
# - Let the UI parse debug-stream.jsonl for detailed activity
|
|
36
|
+
|
|
37
|
+
# Codex requires exec subcommand for non-interactive use (or resume for continuing)
|
|
38
|
+
# Claude accepts stdin directly with --print --output-format stream-json
|
|
39
|
+
# Gemini uses -p flag for prompt with --yolo for auto-approval and --resume for continuing
|
|
40
|
+
if [[ "$AGENT_CMD" == *"codex"* ]]; then
|
|
41
|
+
INSTRUCTION=$(cat "$TEMP_INPUT")
|
|
42
|
+
|
|
43
|
+
# Build model argument if OPENAI_MODEL is set
|
|
44
|
+
MODEL_ARG=""
|
|
45
|
+
if [[ -n "$OPENAI_MODEL" ]]; then
|
|
46
|
+
MODEL_ARG="-m $OPENAI_MODEL"
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
# Build reasoning level argument if CODEX_REASONING_LEVEL is set
|
|
50
|
+
REASONING_ARG=""
|
|
51
|
+
if [[ -n "$CODEX_REASONING_LEVEL" ]]; then
|
|
52
|
+
echo "[$(date +'%Y-%m-%d %H:%M:%S')] Codex reasoning level: $CODEX_REASONING_LEVEL" >&2
|
|
53
|
+
REASONING_ARG="-c model_reasoning_effort=$CODEX_REASONING_LEVEL"
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
# Check if this is a resume operation (first arg is 'exec', second is 'resume')
|
|
57
|
+
if [[ "$1" == "exec" ]] && [[ "$2" == "resume" ]]; then
|
|
58
|
+
shift 2 # Remove 'exec' and 'resume' from $@
|
|
59
|
+
echo "$INSTRUCTION" | "$AGENT_CMD" $MODEL_ARG $REASONING_ARG -a never -s danger-full-access -c approval_policy=never -c sandbox_mode=danger-full-access exec --skip-git-repo-check --json resume "$@" >> /task-output/debug-stream.jsonl 2>&1
|
|
60
|
+
EXIT_CODE=$?
|
|
61
|
+
else
|
|
62
|
+
"$AGENT_CMD" $MODEL_ARG $REASONING_ARG -a never -s danger-full-access exec --skip-git-repo-check --json "$@" "$INSTRUCTION" >> /task-output/debug-stream.jsonl 2>&1
|
|
63
|
+
EXIT_CODE=$?
|
|
64
|
+
fi
|
|
65
|
+
|
|
66
|
+
elif [[ "$AGENT_CMD" == *"gemini"* ]]; then
|
|
67
|
+
INSTRUCTION=$(cat "$TEMP_INPUT")
|
|
68
|
+
|
|
69
|
+
# Use GEMINI_MODEL if set, otherwise default to "pro"
|
|
70
|
+
GEMINI_MODEL_TO_USE="${GEMINI_MODEL:-pro}"
|
|
71
|
+
|
|
72
|
+
# Check if this is a resume operation (--resume flag in args)
|
|
73
|
+
if [[ "$*" == *"--resume"* ]]; then
|
|
74
|
+
"$AGENT_CMD" --model "$GEMINI_MODEL_TO_USE" --resume latest -p "$INSTRUCTION" --yolo --include-directories /task-output --output-format stream-json >> /task-output/debug-stream.jsonl 2>&1
|
|
75
|
+
EXIT_CODE=$?
|
|
76
|
+
else
|
|
77
|
+
"$AGENT_CMD" --model "$GEMINI_MODEL_TO_USE" -p "$INSTRUCTION" --yolo --include-directories /task-output --output-format stream-json "$@" >> /task-output/debug-stream.jsonl 2>&1
|
|
78
|
+
EXIT_CODE=$?
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
else
|
|
82
|
+
# Claude - uses CLAUDE_MODEL env var if set (claude-code reads it automatically)
|
|
83
|
+
# The claude-code CLI respects the CLAUDE_MODEL environment variable
|
|
84
|
+
cat "$TEMP_INPUT" | "$AGENT_CMD" --print --output-format stream-json --verbose "$@" >> /task-output/debug-stream.jsonl 2>&1
|
|
85
|
+
EXIT_CODE=$?
|
|
86
|
+
fi
|
|
87
|
+
|
|
88
|
+
# Clean up temp file
|
|
89
|
+
rm -f "$TEMP_INPUT"
|
|
90
|
+
|
|
91
|
+
END_TIME=$(date +%s%3N)
|
|
92
|
+
DURATION=$((END_TIME - START_TIME))
|
|
93
|
+
|
|
94
|
+
# Extract final response from stream for activity feed
|
|
95
|
+
# This ensures the conversation shows the agent's reply
|
|
96
|
+
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%S.%3NZ")
|
|
97
|
+
|
|
98
|
+
if [ -f /task-output/debug-stream.jsonl ] && [ $EXIT_CODE -eq 0 ]; then
|
|
99
|
+
# Try to extract final response based on agent type
|
|
100
|
+
if [[ "$AGENT_CMD" == *"claude"* ]]; then
|
|
101
|
+
# Claude: Look for last text block in assistant message
|
|
102
|
+
RESPONSE=$(grep -a '"type":"assistant"' /task-output/debug-stream.jsonl | tail -1 | jq -r '.message.content[] | select(.type=="text") | .text' 2>/dev/null | head -20 || echo "")
|
|
103
|
+
elif [[ "$AGENT_CMD" == *"gemini"* ]]; then
|
|
104
|
+
# Gemini: Extract last assistant message content (the actual response)
|
|
105
|
+
# Gemini format: {"type":"message","role":"assistant","content":"...","delta":true}
|
|
106
|
+
RESPONSE=$(grep -a '"type":"message"' /task-output/debug-stream.jsonl | grep -a '"role":"assistant"' | tail -1 | jq -r '.content' 2>/dev/null || echo "")
|
|
107
|
+
elif [[ "$AGENT_CMD" == *"codex"* ]]; then
|
|
108
|
+
# Codex: Look for last agent_message or reasoning item
|
|
109
|
+
RESPONSE=$(grep -a '"type":"item.completed"' /task-output/debug-stream.jsonl | tail -1 | jq -r 'select(.item.type=="agent_message") | .item.text' 2>/dev/null || \
|
|
110
|
+
grep -a '"type":"item.completed"' /task-output/debug-stream.jsonl | tail -1 | jq -r 'select(.item.type=="reasoning") | .item.text' 2>/dev/null | head -20 || echo "")
|
|
111
|
+
fi
|
|
112
|
+
|
|
113
|
+
# Clean up response (limit length for summary)
|
|
114
|
+
if [ -n "$RESPONSE" ] && [ "$RESPONSE" != "null" ]; then
|
|
115
|
+
RESULT_TEXT="$RESPONSE"
|
|
116
|
+
else
|
|
117
|
+
RESULT_TEXT="Task completed successfully"
|
|
118
|
+
fi
|
|
119
|
+
else
|
|
120
|
+
RESULT_TEXT="Task failed with exit code $EXIT_CODE"
|
|
121
|
+
fi
|
|
122
|
+
|
|
123
|
+
# Estimate tokens from debug stream size
|
|
124
|
+
if [ -f /task-output/debug-stream.jsonl ]; then
|
|
125
|
+
TOKEN_EST=$(wc -c < /task-output/debug-stream.jsonl | awk '{print int($1/4)}')
|
|
126
|
+
else
|
|
127
|
+
TOKEN_EST=0
|
|
128
|
+
fi
|
|
129
|
+
|
|
130
|
+
# Escape result text for JSON
|
|
131
|
+
ESCAPED_RESULT=$(echo "$RESULT_TEXT" | jq -Rs . 2>/dev/null || echo '"Task completed"')
|
|
132
|
+
|
|
133
|
+
# Output result JSON with actual agent response
|
|
134
|
+
# The server and UI will also read debug-stream.jsonl for detailed events
|
|
135
|
+
cat <<EOF
|
|
136
|
+
{"type":"result","result":$ESCAPED_RESULT,"duration_ms":${DURATION},"num_turns":1,"usage":{"output_tokens":${TOKEN_EST},"cache_read_input_tokens":0},"timestamp":"${TIMESTAMP}","exit_code":${EXIT_CODE}}
|
|
137
|
+
EOF
|
|
138
|
+
|
|
139
|
+
# Write exit code and finished time marker files for server monitoring
|
|
140
|
+
echo "$EXIT_CODE" > /task-output/.exit_code
|
|
141
|
+
date -Iseconds > /task-output/.finished_at
|
|
142
|
+
|
|
143
|
+
exit $EXIT_CODE
|
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Apply Local Repository State
|
|
3
|
+
# Applies captured git state including local branches, staged/unstaged changes, untracked files
|
|
4
|
+
|
|
5
|
+
set -o pipefail
|
|
6
|
+
|
|
7
|
+
STATE_FILE="${LOCAL_STATE_FILE:-/task-output/local-state.json}"
|
|
8
|
+
WORKSPACE_DIR="${WORKSPACE_DIR:-/workspace}"
|
|
9
|
+
|
|
10
|
+
# Track warnings and errors
|
|
11
|
+
HAS_WARNINGS=false
|
|
12
|
+
WARNING_MESSAGES=()
|
|
13
|
+
|
|
14
|
+
# Logging functions
|
|
15
|
+
log() {
|
|
16
|
+
echo "[$(date +'%Y-%m-%d %H:%M:%S')] $*" >&2
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
log_error() {
|
|
20
|
+
echo "[$(date +'%Y-%m-%d %H:%M:%S')] ERROR: $*" >&2
|
|
21
|
+
HAS_WARNINGS=true
|
|
22
|
+
WARNING_MESSAGES+=("ERROR: $*")
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
log_warning() {
|
|
26
|
+
echo "[$(date +'%Y-%m-%d %H:%M:%S')] WARNING: $*" >&2
|
|
27
|
+
HAS_WARNINGS=true
|
|
28
|
+
WARNING_MESSAGES+=("WARNING: $*")
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
log_success() {
|
|
32
|
+
echo "[$(date +'%Y-%m-%d %H:%M:%S')] SUCCESS: $*" >&2
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
# Check if state file exists
|
|
36
|
+
if [ ! -f "$STATE_FILE" ]; then
|
|
37
|
+
log "No local state file found at $STATE_FILE, skipping state application"
|
|
38
|
+
exit 0
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
log "════════════════════════════════════════════════════════════════"
|
|
42
|
+
log " Applying Local Repository State"
|
|
43
|
+
log "════════════════════════════════════════════════════════════════"
|
|
44
|
+
log ""
|
|
45
|
+
|
|
46
|
+
# Validate JSON
|
|
47
|
+
if ! jq empty "$STATE_FILE" 2>/dev/null; then
|
|
48
|
+
log_error "Invalid JSON in state file: $STATE_FILE"
|
|
49
|
+
exit 1
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
# Show capture info
|
|
53
|
+
CAPTURED_AT=$(jq -r '.captured_at' "$STATE_FILE")
|
|
54
|
+
REPOS_FOUND=$(jq -r '.repos_found | join(", ")' "$STATE_FILE")
|
|
55
|
+
REPOS_MISSING=$(jq -r '.repos_missing | join(", ")' "$STATE_FILE")
|
|
56
|
+
|
|
57
|
+
log "📋 State Information:"
|
|
58
|
+
log " Captured at: $CAPTURED_AT"
|
|
59
|
+
log " Repositories: $REPOS_FOUND"
|
|
60
|
+
if [ -n "$REPOS_MISSING" ] && [ "$REPOS_MISSING" != "" ]; then
|
|
61
|
+
log " Missing (will use defaults): $REPOS_MISSING"
|
|
62
|
+
fi
|
|
63
|
+
log ""
|
|
64
|
+
|
|
65
|
+
# Process each repository
|
|
66
|
+
jq -r '.repositories | keys[]' "$STATE_FILE" | while read -r repo_name; do
|
|
67
|
+
# Look up the path for this repo from REPOS_CONFIG
|
|
68
|
+
repo_path_from_json=""
|
|
69
|
+
if [ -n "$REPOS_CONFIG" ]; then
|
|
70
|
+
repo_path_from_json=$(echo "$REPOS_CONFIG" | jq -r --arg name "$repo_name" '.[] | select(.name == $name) | .path')
|
|
71
|
+
fi
|
|
72
|
+
|
|
73
|
+
# Use path field from JSON if available, otherwise default to repo_name
|
|
74
|
+
if [ -n "$repo_path_from_json" ] && [ "$repo_path_from_json" != "null" ] && [ "$repo_path_from_json" != "" ]; then
|
|
75
|
+
REPO_PATH="$WORKSPACE_DIR/$repo_path_from_json"
|
|
76
|
+
else
|
|
77
|
+
REPO_PATH="$WORKSPACE_DIR/$repo_name"
|
|
78
|
+
fi
|
|
79
|
+
|
|
80
|
+
log "────────────────────────────────────────────────────────────────"
|
|
81
|
+
log "📁 Repository: $repo_name"
|
|
82
|
+
log " Path: $REPO_PATH"
|
|
83
|
+
log "────────────────────────────────────────────────────────────────"
|
|
84
|
+
|
|
85
|
+
# Check if repo exists in workspace
|
|
86
|
+
if [ ! -d "$REPO_PATH" ]; then
|
|
87
|
+
log_error "Repository not found in workspace: $REPO_PATH"
|
|
88
|
+
log " Skipping..."
|
|
89
|
+
log ""
|
|
90
|
+
continue
|
|
91
|
+
fi
|
|
92
|
+
|
|
93
|
+
if [ ! -d "$REPO_PATH/.git" ]; then
|
|
94
|
+
log_error "Not a git repository: $REPO_PATH"
|
|
95
|
+
log " Skipping..."
|
|
96
|
+
log ""
|
|
97
|
+
continue
|
|
98
|
+
fi
|
|
99
|
+
|
|
100
|
+
cd "$REPO_PATH" || {
|
|
101
|
+
log_error "Failed to cd into $REPO_PATH"
|
|
102
|
+
continue
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
# Extract repo state from JSON
|
|
106
|
+
CURRENT_BRANCH=$(jq -r ".repositories.\"$repo_name\".current_branch" "$STATE_FILE")
|
|
107
|
+
IS_REMOTE_TRACKING=$(jq -r ".repositories.\"$repo_name\".is_remote_tracking" "$STATE_FILE")
|
|
108
|
+
BASE_BRANCH=$(jq -r ".repositories.\"$repo_name\".base_branch" "$STATE_FILE")
|
|
109
|
+
COMMITS_AHEAD=$(jq -r ".repositories.\"$repo_name\".commits_ahead" "$STATE_FILE")
|
|
110
|
+
|
|
111
|
+
log " Current branch in container: $(git rev-parse --abbrev-ref HEAD)"
|
|
112
|
+
log " Target branch: $CURRENT_BRANCH"
|
|
113
|
+
log " Remote tracking: $IS_REMOTE_TRACKING"
|
|
114
|
+
|
|
115
|
+
# Step 1: Handle branch setup
|
|
116
|
+
if [ "$IS_REMOTE_TRACKING" = "true" ]; then
|
|
117
|
+
# Branch exists on remote, checkout first
|
|
118
|
+
log " Checking out remote-tracking branch: $CURRENT_BRANCH"
|
|
119
|
+
|
|
120
|
+
if git rev-parse --verify "origin/$CURRENT_BRANCH" >/dev/null 2>&1; then
|
|
121
|
+
git checkout "$CURRENT_BRANCH" 2>&1 | sed 's/^/ /' || {
|
|
122
|
+
log_error "Failed to checkout branch $CURRENT_BRANCH"
|
|
123
|
+
continue
|
|
124
|
+
}
|
|
125
|
+
else
|
|
126
|
+
log_error "Remote branch origin/$CURRENT_BRANCH not found"
|
|
127
|
+
log " Attempting to checkout local branch..."
|
|
128
|
+
git checkout "$CURRENT_BRANCH" 2>&1 | sed 's/^/ /' || {
|
|
129
|
+
log_error "Failed to checkout branch $CURRENT_BRANCH"
|
|
130
|
+
continue
|
|
131
|
+
}
|
|
132
|
+
fi
|
|
133
|
+
|
|
134
|
+
# Check for unpushed commits on remote-tracking branch
|
|
135
|
+
if [ -n "$COMMITS_AHEAD" ] && [ "$COMMITS_AHEAD" != "null" ] && [ "$COMMITS_AHEAD" -gt 0 ]; then
|
|
136
|
+
log " 📤 Unpushed commits detected: $COMMITS_AHEAD commit(s)"
|
|
137
|
+
COMMIT_PATCH=$(jq -r ".repositories.\"$repo_name\".commit_patch" "$STATE_FILE")
|
|
138
|
+
|
|
139
|
+
if [ -n "$COMMIT_PATCH" ] && [ "$COMMIT_PATCH" != "null" ]; then
|
|
140
|
+
log " Applying unpushed commits..."
|
|
141
|
+
|
|
142
|
+
# Save patch to temp file
|
|
143
|
+
TEMP_PATCH=$(mktemp)
|
|
144
|
+
echo "$COMMIT_PATCH" > "$TEMP_PATCH"
|
|
145
|
+
|
|
146
|
+
# Apply patches using git am
|
|
147
|
+
if git am --3way < "$TEMP_PATCH" 2>&1 | sed 's/^/ /'; then
|
|
148
|
+
log_success "Successfully applied unpushed commits"
|
|
149
|
+
else
|
|
150
|
+
log_error "Failed to apply commit patches, trying format-patch method..."
|
|
151
|
+
git am --abort 2>/dev/null || true
|
|
152
|
+
|
|
153
|
+
# Fallback: try applying as a single diff
|
|
154
|
+
if git apply < "$TEMP_PATCH" 2>&1 | sed 's/^/ /'; then
|
|
155
|
+
log_success "Applied changes as diff (commits not preserved)"
|
|
156
|
+
else
|
|
157
|
+
log_error "Failed to apply commit patches"
|
|
158
|
+
fi
|
|
159
|
+
fi
|
|
160
|
+
|
|
161
|
+
rm -f "$TEMP_PATCH"
|
|
162
|
+
fi
|
|
163
|
+
fi
|
|
164
|
+
else
|
|
165
|
+
# Local-only branch, need to recreate it
|
|
166
|
+
log " ⚠️ Local-only branch detected: $CURRENT_BRANCH"
|
|
167
|
+
|
|
168
|
+
if [ -n "$BASE_BRANCH" ] && [ "$BASE_BRANCH" != "null" ]; then
|
|
169
|
+
log " Base branch: $BASE_BRANCH"
|
|
170
|
+
log " Commits ahead: $COMMITS_AHEAD"
|
|
171
|
+
|
|
172
|
+
# Checkout base branch first
|
|
173
|
+
if git rev-parse --verify "$BASE_BRANCH" >/dev/null 2>&1; then
|
|
174
|
+
log " Checking out base branch: $BASE_BRANCH"
|
|
175
|
+
git checkout "$BASE_BRANCH" 2>&1 | sed 's/^/ /' || {
|
|
176
|
+
log_error "Failed to checkout base branch $BASE_BRANCH"
|
|
177
|
+
continue
|
|
178
|
+
}
|
|
179
|
+
else
|
|
180
|
+
log_error "Base branch $BASE_BRANCH not found"
|
|
181
|
+
continue
|
|
182
|
+
fi
|
|
183
|
+
|
|
184
|
+
# Create new branch
|
|
185
|
+
log " Creating local branch: $CURRENT_BRANCH"
|
|
186
|
+
git checkout -b "$CURRENT_BRANCH" 2>&1 | sed 's/^/ /' || {
|
|
187
|
+
# Branch might already exist
|
|
188
|
+
git checkout "$CURRENT_BRANCH" 2>&1 | sed 's/^/ /' || {
|
|
189
|
+
log_error "Failed to create/checkout branch $CURRENT_BRANCH"
|
|
190
|
+
continue
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
# Apply commit patches if available
|
|
195
|
+
if [ "$COMMITS_AHEAD" != "null" ] && [ "$COMMITS_AHEAD" -gt 0 ]; then
|
|
196
|
+
COMMIT_PATCH=$(jq -r ".repositories.\"$repo_name\".commit_patch" "$STATE_FILE")
|
|
197
|
+
|
|
198
|
+
if [ -n "$COMMIT_PATCH" ] && [ "$COMMIT_PATCH" != "null" ]; then
|
|
199
|
+
log " Applying $COMMITS_AHEAD commit(s)..."
|
|
200
|
+
|
|
201
|
+
# Save patch to temp file
|
|
202
|
+
TEMP_PATCH=$(mktemp)
|
|
203
|
+
echo "$COMMIT_PATCH" > "$TEMP_PATCH"
|
|
204
|
+
|
|
205
|
+
# Apply patches using git am
|
|
206
|
+
if git am --3way < "$TEMP_PATCH" 2>&1 | sed 's/^/ /'; then
|
|
207
|
+
log_success "Successfully applied commit patches"
|
|
208
|
+
else
|
|
209
|
+
log_error "Failed to apply commit patches, trying format-patch method..."
|
|
210
|
+
git am --abort 2>/dev/null || true
|
|
211
|
+
|
|
212
|
+
# Fallback: try applying as a single diff
|
|
213
|
+
if git apply < "$TEMP_PATCH" 2>&1 | sed 's/^/ /'; then
|
|
214
|
+
log_success "Applied changes as diff (commits not preserved)"
|
|
215
|
+
else
|
|
216
|
+
log_error "Failed to apply commit patches"
|
|
217
|
+
fi
|
|
218
|
+
fi
|
|
219
|
+
|
|
220
|
+
rm -f "$TEMP_PATCH"
|
|
221
|
+
fi
|
|
222
|
+
fi
|
|
223
|
+
else
|
|
224
|
+
log " No base branch info, checking out branch as-is..."
|
|
225
|
+
git checkout "$CURRENT_BRANCH" 2>&1 | sed 's/^/ /' || {
|
|
226
|
+
log_error "Failed to checkout branch $CURRENT_BRANCH"
|
|
227
|
+
continue
|
|
228
|
+
}
|
|
229
|
+
fi
|
|
230
|
+
fi
|
|
231
|
+
|
|
232
|
+
log_success "Branch setup complete"
|
|
233
|
+
|
|
234
|
+
# Step 2: Apply unstaged changes (working directory changes)
|
|
235
|
+
UNSTAGED=$(jq -r ".repositories.\"$repo_name\".unstaged" "$STATE_FILE")
|
|
236
|
+
if [ -n "$UNSTAGED" ] && [ "$UNSTAGED" != "null" ] && [ "$UNSTAGED" != "" ]; then
|
|
237
|
+
UNSTAGED_FILE_COUNT=$(echo "$UNSTAGED" | grep -c '^diff --git' || echo "0")
|
|
238
|
+
log " Applying unstaged changes ($UNSTAGED_FILE_COUNT files)..."
|
|
239
|
+
|
|
240
|
+
TEMP_DIFF=$(mktemp)
|
|
241
|
+
echo "$UNSTAGED" > "$TEMP_DIFF"
|
|
242
|
+
|
|
243
|
+
if git apply --verbose < "$TEMP_DIFF" 2>&1 | sed 's/^/ /'; then
|
|
244
|
+
log_success "Unstaged changes applied"
|
|
245
|
+
else
|
|
246
|
+
log_error "Failed to apply unstaged changes for $repo_name"
|
|
247
|
+
log_warning "$repo_name: Unstaged changes had conflicts - check git status in container"
|
|
248
|
+
log " Attempting with --reject to show conflicts..."
|
|
249
|
+
git apply --reject < "$TEMP_DIFF" 2>&1 | sed 's/^/ /' || true
|
|
250
|
+
fi
|
|
251
|
+
|
|
252
|
+
rm -f "$TEMP_DIFF"
|
|
253
|
+
fi
|
|
254
|
+
|
|
255
|
+
# Step 3: Apply staged changes (index)
|
|
256
|
+
STAGED=$(jq -r ".repositories.\"$repo_name\".staged" "$STATE_FILE")
|
|
257
|
+
if [ -n "$STAGED" ] && [ "$STAGED" != "null" ] && [ "$STAGED" != "" ]; then
|
|
258
|
+
STAGED_FILE_COUNT=$(echo "$STAGED" | grep -c '^diff --git' || echo "0")
|
|
259
|
+
log " Applying staged changes ($STAGED_FILE_COUNT files)..."
|
|
260
|
+
|
|
261
|
+
TEMP_STAGED=$(mktemp)
|
|
262
|
+
echo "$STAGED" > "$TEMP_STAGED"
|
|
263
|
+
|
|
264
|
+
if git apply --cached --verbose < "$TEMP_STAGED" 2>&1 | sed 's/^/ /'; then
|
|
265
|
+
log_success "Staged changes applied"
|
|
266
|
+
else
|
|
267
|
+
log_error "Failed to apply staged changes for $repo_name"
|
|
268
|
+
log_warning "$repo_name: Staged changes had conflicts - check git status in container"
|
|
269
|
+
log " Attempting with --reject to show conflicts..."
|
|
270
|
+
git apply --cached --reject < "$TEMP_STAGED" 2>&1 | sed 's/^/ /' || true
|
|
271
|
+
fi
|
|
272
|
+
|
|
273
|
+
rm -f "$TEMP_STAGED"
|
|
274
|
+
fi
|
|
275
|
+
|
|
276
|
+
# Step 4: Create untracked files
|
|
277
|
+
UNTRACKED_FILES=$(jq -r ".repositories.\"$repo_name\".untracked_files | keys[]" "$STATE_FILE" 2>/dev/null)
|
|
278
|
+
if [ -n "$UNTRACKED_FILES" ]; then
|
|
279
|
+
UNTRACKED_COUNT=$(echo "$UNTRACKED_FILES" | wc -l)
|
|
280
|
+
log " Creating $UNTRACKED_COUNT untracked file(s)..."
|
|
281
|
+
|
|
282
|
+
echo "$UNTRACKED_FILES" | while read -r file_path; do
|
|
283
|
+
if [ -z "$file_path" ]; then
|
|
284
|
+
continue
|
|
285
|
+
fi
|
|
286
|
+
|
|
287
|
+
# Get file content from JSON (properly escaped)
|
|
288
|
+
FILE_CONTENT=$(jq -r ".repositories.\"$repo_name\".untracked_files.\"$file_path\"" "$STATE_FILE")
|
|
289
|
+
|
|
290
|
+
if [ -n "$FILE_CONTENT" ] && [ "$FILE_CONTENT" != "null" ]; then
|
|
291
|
+
# Create parent directories if needed
|
|
292
|
+
mkdir -p "$(dirname "$file_path")"
|
|
293
|
+
|
|
294
|
+
# Write content to file
|
|
295
|
+
echo "$FILE_CONTENT" > "$file_path"
|
|
296
|
+
log " + $file_path"
|
|
297
|
+
fi
|
|
298
|
+
done
|
|
299
|
+
|
|
300
|
+
log_success "Untracked files created"
|
|
301
|
+
fi
|
|
302
|
+
|
|
303
|
+
# Step 5: Show final git status
|
|
304
|
+
log ""
|
|
305
|
+
log " 📊 Final repository state:"
|
|
306
|
+
git status --short 2>&1 | sed 's/^/ /' || true
|
|
307
|
+
log " Current branch: $(git rev-parse --abbrev-ref HEAD)"
|
|
308
|
+
log ""
|
|
309
|
+
log_success "State application complete for $repo_name"
|
|
310
|
+
log ""
|
|
311
|
+
done
|
|
312
|
+
|
|
313
|
+
log "════════════════════════════════════════════════════════════════"
|
|
314
|
+
log_success "Local state application complete!"
|
|
315
|
+
log "════════════════════════════════════════════════════════════════"
|
|
316
|
+
log ""
|
|
317
|
+
|
|
318
|
+
# Write summary for CLI to check
|
|
319
|
+
SUMMARY_FILE="/task-output/.local-state-summary"
|
|
320
|
+
|
|
321
|
+
if [ "$HAS_WARNINGS" = "true" ]; then
|
|
322
|
+
# Build warnings JSON array
|
|
323
|
+
WARNINGS_JSON="["
|
|
324
|
+
first=true
|
|
325
|
+
for msg in "${WARNING_MESSAGES[@]}"; do
|
|
326
|
+
if [ "$first" = "true" ]; then
|
|
327
|
+
first=false
|
|
328
|
+
else
|
|
329
|
+
WARNINGS_JSON+=","
|
|
330
|
+
fi
|
|
331
|
+
# Escape quotes in message
|
|
332
|
+
escaped_msg=$(echo "$msg" | sed 's/"/\\"/g')
|
|
333
|
+
WARNINGS_JSON+="\"$escaped_msg\""
|
|
334
|
+
done
|
|
335
|
+
WARNINGS_JSON+="]"
|
|
336
|
+
|
|
337
|
+
cat > "$SUMMARY_FILE" <<EOF
|
|
338
|
+
{
|
|
339
|
+
"status": "completed_with_warnings",
|
|
340
|
+
"applied_at": "$(date -Iseconds)",
|
|
341
|
+
"has_warnings": true,
|
|
342
|
+
"warnings": $WARNINGS_JSON,
|
|
343
|
+
"message": "Local state applied with ${#WARNING_MESSAGES[@]} warning(s) - check git status in container"
|
|
344
|
+
}
|
|
345
|
+
EOF
|
|
346
|
+
else
|
|
347
|
+
cat > "$SUMMARY_FILE" <<EOF
|
|
348
|
+
{
|
|
349
|
+
"status": "success",
|
|
350
|
+
"applied_at": "$(date -Iseconds)",
|
|
351
|
+
"has_warnings": false,
|
|
352
|
+
"message": "Local state applied successfully"
|
|
353
|
+
}
|
|
354
|
+
EOF
|
|
355
|
+
fi
|
|
356
|
+
|
|
357
|
+
exit 0
|