Vendor OpenClaw source as Adolf fork baseline
Some checks failed
ClawSweeper Dispatch / dispatch (push) Has been cancelled
CodeQL / Security High (actions) (push) Has been cancelled
CodeQL / Security High (channel-runtime-boundary) (push) Has been cancelled
CodeQL / Security High (core-auth-secrets) (push) Has been cancelled
CodeQL / Security High (mcp-process-tool-boundary) (push) Has been cancelled
CodeQL / Security High (network-ssrf-boundary) (push) Has been cancelled
CodeQL / Security High (plugin-trust-boundary) (push) Has been cancelled
CodeQL / Security High (process-exec-boundary) (push) Has been cancelled
Docs Sync Publish Repo / sync-publish-repo (push) Has been cancelled
Docs / docs (push) Has been cancelled
OpenClaw Stable Main Closeout / Resolve stable release closeout inputs (push) Has been cancelled
OpenClaw Stable Main Closeout / Verify stable main closeout (push) Has been cancelled
Workflow Sanity / no-tabs (push) Has been cancelled
Workflow Sanity / actionlint (push) Has been cancelled
Workflow Sanity / generated-doc-baselines (push) Has been cancelled
CI / runner-admission (push) Has been cancelled
CI / preflight (push) Has been cancelled
CI / security-fast (push) Has been cancelled
CI / pnpm-store-warmup (push) Has been cancelled
CI / build-artifacts (push) Has been cancelled
CI / native-i18n (push) Has been cancelled
CI / ${{ matrix.check_name }} (push) Has been cancelled
CI / ${{ matrix.checkName }} (push) Has been cancelled
CI / checks-node-compat-node22 (push) Has been cancelled
CI / check-bundled-channel-config-metadata (push) Has been cancelled
CI / check-dependencies (push) Has been cancelled
CI / check-guards (push) Has been cancelled
CI / check-lint (push) Has been cancelled
CI / check-prod-types (push) Has been cancelled
CI / check-shrinkwrap (push) Has been cancelled
CI / check-test-types (push) Has been cancelled
CI / check-additional-boundaries-a (push) Has been cancelled
CI / check-additional-boundaries-bcd (push) Has been cancelled
CI / check-additional-extension-bundled (push) Has been cancelled
CI / check-additional-extension-channels (push) Has been cancelled
CI / check-additional-extension-package-boundary (push) Has been cancelled
CI / check-additional-runtime-topology-architecture (push) Has been cancelled
CI / check-session-accessor-boundary (push) Has been cancelled
CI / check-session-transcript-reader-boundary (push) Has been cancelled
CI / check-docs (push) Has been cancelled
CI / skills-python (push) Has been cancelled
CI / macos-swift (push) Has been cancelled
CI / ios-build (push) Has been cancelled
CI / ci-timings-summary (push) Has been cancelled
Native App Locale Refresh / Refresh native fa (push) Has been cancelled
Native App Locale Refresh / Refresh native fr (push) Has been cancelled
Native App Locale Refresh / Refresh native hi (push) Has been cancelled
Native App Locale Refresh / Refresh native id (push) Has been cancelled
Native App Locale Refresh / Refresh native it (push) Has been cancelled
Native App Locale Refresh / Refresh native ja-JP (push) Has been cancelled
Control UI Locale Refresh / plan (push) Has been cancelled
Control UI Locale Refresh / Refresh ${{ matrix.locale }} (push) Has been cancelled
Control UI Locale Refresh / Commit control UI locale refresh (push) Has been cancelled
Live Media Runner Image / Build live media runner image (push) Has been cancelled
Native App Locale Refresh / Refresh native ar (push) Has been cancelled
Native App Locale Refresh / Refresh native de (push) Has been cancelled
Native App Locale Refresh / Refresh native es (push) Has been cancelled
Native App Locale Refresh / Refresh native ko (push) Has been cancelled
Native App Locale Refresh / Refresh native nl (push) Has been cancelled
Native App Locale Refresh / Refresh native pl (push) Has been cancelled
Native App Locale Refresh / Refresh native pt-BR (push) Has been cancelled
Native App Locale Refresh / Refresh native ru (push) Has been cancelled
Native App Locale Refresh / Refresh native sv (push) Has been cancelled
Native App Locale Refresh / Refresh native th (push) Has been cancelled
Native App Locale Refresh / Refresh native tr (push) Has been cancelled
Native App Locale Refresh / Refresh native uk (push) Has been cancelled
Native App Locale Refresh / Refresh native vi (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-CN (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-TW (push) Has been cancelled
Native App Locale Refresh / Commit native locale refresh (push) Has been cancelled
Plugin Init Scaffold Validation / Validate provider scaffold (push) Has been cancelled
Plugin NPM Release / preview_plugins_npm (push) Has been cancelled
Plugin NPM Release / Validate release publish approval (push) Has been cancelled
Plugin NPM Release / preview_plugin_pack (push) Has been cancelled
Plugin NPM Release / publish_plugins_npm (push) Has been cancelled
Sandbox Common Smoke / sandbox-common-smoke (push) Has been cancelled
Website Installer Sync / static (push) Has been cancelled
Website Installer Sync / linux-docker (push) Has been cancelled
Website Installer Sync / macos-installer (push) Has been cancelled
Website Installer Sync / windows-installer (push) Has been cancelled
Website Installer Sync / sync-website (push) Has been cancelled

Adolf is a fork/vendored clone of github.com/openclaw/openclaw (v2026.6.11),
free to diverge. Tree copied sans upstream .git; upstream remote added for
future syncs. Node pinned to 24 (.nvmrc); engines already require >=22.19.
Preserves docs/ARCHITECTURE.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LeqyaxJF2nbRXJtae2kNB2
This commit is contained in:
2026-07-05 09:36:54 +00:00
parent 3216769225
commit bedb527145
21108 changed files with 6010766 additions and 0 deletions

View File

@@ -0,0 +1,256 @@
// Copilot plugin module implements workspace bootstrap behavior.
import path from "node:path";
import type {
AgentHarnessAttemptParams,
EmbeddedContextFile,
} from "openclaw/plugin-sdk/agent-harness-runtime";
import {
resolveBootstrapContextForRun,
resolveUserPath,
} from "openclaw/plugin-sdk/agent-harness-runtime";
// Filenames the Copilot SDK already loads natively from the working
// directory / instructionDirectories (per
// `@github/copilot-sdk/dist/types.d.ts:1036,1155` —
// "custom instruction files (.github/copilot-instructions.md,
// AGENTS.md, etc.) are always loaded from the working directory").
// Filtering them out of the OpenClaw bootstrap injection avoids
// duplicating their content into `SessionConfig.systemMessage`, which
// would otherwise inflate every prompt with the same text the SDK
// already includes. Mirrors codex's CODEX_NATIVE_PROJECT_DOC_BASENAMES
// (extensions/codex/src/app-server/run-attempt.ts:160).
const COPILOT_NATIVE_PROJECT_DOC_BASENAMES = new Set(["agents.md"]);
// Persona/identity files get sorted to the top of the rendered block
// so they precede the freer-form context like USER.md / MEMORY.md.
// Mirrors codex's CODEX_BOOTSTRAP_CONTEXT_ORDER ordering (same files).
const COPILOT_BOOTSTRAP_CONTEXT_ORDER = new Map<string, number>([
["soul.md", 10],
["identity.md", 20],
["heartbeat.md", 30],
["bootstrap.md", 40],
["tools.md", 50],
["user.md", 60],
["memory.md", 70],
]);
export type CopilotWorkspaceBootstrapResult = {
bootstrapFiles: Awaited<ReturnType<typeof resolveBootstrapContextForRun>>["bootstrapFiles"];
contextFiles: EmbeddedContextFile[];
instructions?: string;
};
/**
* Loads OpenClaw workspace bootstrap files (IDENTITY.md, SOUL.md,
* HEARTBEAT.md, USER.md, TOOLS.md, BOOTSTRAP.md, MEMORY.md, ...) using
* the shared core helper PI and codex both use, then renders them as a
* single string suitable for `SessionConfig.systemMessage.content` on
* the Copilot SDK.
*
* Returns `instructions: undefined` when there are no relevant files
* (after filtering out SDK-native docs) so the caller can omit the
* `systemMessage` field entirely rather than passing an empty string.
*
* Mirrors codex's `buildCodexWorkspaceBootstrapContext` /
* `renderCodexWorkspaceBootstrapInstructions` pair
* (`extensions/codex/src/app-server/run-attempt.ts:2877,3047`). The
* shape divergence — codex returns instructions inside the same object
* as bootstrapFiles+contextFiles for its developerInstructions field;
* copilot exposes the rendered string for SDK `systemMessage` — is the
* intended difference between the two runtimes' system-prompt
* surfaces.
*/
export async function resolveCopilotWorkspaceBootstrapContext(params: {
attempt: AgentHarnessAttemptParams;
/**
* Sandbox-aware working directory the SDK session will run in.
* When this differs from the canonical `attempt.workspaceDir`
* (sandbox `ro` / `none` runs that redirect to a copy), bootstrap
* context file paths are remapped so the rendered `systemMessage`
* shows the model the same workspace the SDK's native loader and
* bridged tools operate on. Pass `undefined` only when no sandbox
* resolution has happened (e.g. tests not exercising sandbox
* redirection). Required so future callers cannot silently miss
* the remap. Mirrors PI's
* `remapInjectedContextFilesToWorkspace` call in
* `src/agents/pi-embedded-runner/run/attempt.ts:1595`.
*/
effectiveWorkspaceDir: string | undefined;
warn?: (message: string) => void;
}): Promise<CopilotWorkspaceBootstrapResult> {
const { attempt } = params;
const workspaceDir = readResolvedWorkspacePath(attempt.workspaceDir);
if (!workspaceDir) {
return { bootstrapFiles: [], contextFiles: [] };
}
try {
const bootstrapContext = await resolveBootstrapContextForRun({
workspaceDir,
config: attempt.config,
sessionKey: readNonEmptyString((attempt as { sessionKey?: unknown }).sessionKey),
sessionId: readNonEmptyString(attempt.sessionId),
agentId: readNonEmptyString(attempt.agentId),
warn: params.warn,
contextMode: attempt.bootstrapContextMode,
runKind: attempt.bootstrapContextRunKind,
});
// Remap context-file paths from the workspace we LOADED them
// from (`workspaceDir`, the canonical host workspace where
// SOUL.md / IDENTITY.md / .openclaw conventions live) onto the
// workspace the SDK session will actually OPERATE in
// (`effectiveWorkspaceDir`). When the two are identical (no
// sandbox, or sandbox `rw`), remap is a no-op. The render below
// and the returned `contextFiles` use the remapped array so the
// model never sees a host path while its native loader and
// bridged tools see only the sandbox copy.
const contextFiles = remapCopilotBootstrapContextFiles({
files: bootstrapContext.contextFiles,
sourceWorkspaceDir: workspaceDir,
targetWorkspaceDir: readResolvedWorkspacePath(params.effectiveWorkspaceDir) ?? workspaceDir,
});
return {
bootstrapFiles: bootstrapContext.bootstrapFiles,
contextFiles,
instructions: renderCopilotWorkspaceBootstrapInstructions(contextFiles),
};
} catch (error) {
params.warn?.(
`[copilot-attempt] failed to load workspace bootstrap instructions: ${
error instanceof Error ? error.message : String(error)
}`,
);
return { bootstrapFiles: [], contextFiles: [] };
}
}
/**
* Rewrites context-file paths from a source workspace root to a
* target workspace root, mirroring PI's
* `remapInjectedContextFilesToWorkspace`
* (`src/agents/pi-embedded-runner/run/attempt.ts:603`). Files whose
* resolved relative path escapes the source workspace (parent
* traversal or absolute) are left untouched so we never pretend a
* file lives inside the sandbox when it does not. Exported for unit
* tests; intentionally local to the Copilot extension (codex keeps
* similar helpers extension-local rather than importing from PI).
*/
export function remapCopilotBootstrapContextFiles(params: {
files: EmbeddedContextFile[];
sourceWorkspaceDir: string;
targetWorkspaceDir: string;
}): EmbeddedContextFile[] {
if (params.sourceWorkspaceDir === params.targetWorkspaceDir) {
return params.files;
}
return params.files.map((file) => {
const relative = path.relative(params.sourceWorkspaceDir, file.path);
if (!isRelativePathInsideOrEqual(relative)) {
return file;
}
return {
...file,
path:
relative === ""
? params.targetWorkspaceDir
: path.join(params.targetWorkspaceDir, relative),
};
});
}
function isRelativePathInsideOrEqual(relativePath: string): boolean {
return (
relativePath === "" ||
(relativePath !== ".." &&
!relativePath.startsWith(`..${path.sep}`) &&
!path.isAbsolute(relativePath))
);
}
/**
* Renders bootstrap context files into a single string for
* `SessionConfig.systemMessage.content` (append mode). Returns
* `undefined` when no relevant files remain after filtering, so the
* caller can skip setting `systemMessage` altogether.
*
* Files whose basename matches a doc the Copilot SDK already loads
* natively (see {@link COPILOT_NATIVE_PROJECT_DOC_BASENAMES}) are
* dropped to avoid duplication with SDK-managed sections.
*/
export function renderCopilotWorkspaceBootstrapInstructions(
contextFiles: EmbeddedContextFile[],
): string | undefined {
const files = contextFiles
.filter((file) => {
const baseName = getCopilotContextFileBasename(file.path);
return baseName.length > 0 && !COPILOT_NATIVE_PROJECT_DOC_BASENAMES.has(baseName);
})
.toSorted(compareCopilotContextFiles);
if (files.length === 0) {
return undefined;
}
const hasSoulFile = files.some((file) => getCopilotContextFileBasename(file.path) === "soul.md");
const lines: string[] = [
"OpenClaw loaded these user-editable workspace files. Treat them as project/user context. The Copilot SDK loads AGENTS.md natively from its instruction directories, so AGENTS.md is not repeated here.",
"",
"# Project Context",
"",
"The following project context files have been loaded:",
];
if (hasSoulFile) {
lines.push("SOUL.md: persona/tone. Follow it unless higher-priority instructions override.");
}
lines.push("");
for (const file of files) {
lines.push(`## ${file.path}`, "", file.content, "");
}
return lines.join("\n").trim();
}
function compareCopilotContextFiles(left: EmbeddedContextFile, right: EmbeddedContextFile): number {
const leftBase = getCopilotContextFileBasename(left.path);
const rightBase = getCopilotContextFileBasename(right.path);
const leftOrder = COPILOT_BOOTSTRAP_CONTEXT_ORDER.get(leftBase) ?? Number.MAX_SAFE_INTEGER;
const rightOrder = COPILOT_BOOTSTRAP_CONTEXT_ORDER.get(rightBase) ?? Number.MAX_SAFE_INTEGER;
if (leftOrder !== rightOrder) {
return leftOrder - rightOrder;
}
const leftPath = normalizeCopilotContextFilePath(left.path);
const rightPath = normalizeCopilotContextFilePath(right.path);
if (leftPath < rightPath) {
return -1;
}
if (leftPath > rightPath) {
return 1;
}
return 0;
}
function normalizeCopilotContextFilePath(filePath: string): string {
return filePath.trim().replaceAll("\\", "/").toLowerCase();
}
function getCopilotContextFileBasename(filePath: string): string {
return normalizeCopilotContextFilePath(filePath).split("/").pop() ?? "";
}
function readNonEmptyString(value: unknown): string | undefined {
return typeof value === "string" && value.trim().length > 0 ? value : undefined;
}
function readResolvedWorkspacePath(value: unknown): string | undefined {
const raw = readNonEmptyString(value);
if (!raw) {
return undefined;
}
if (process.platform !== "win32" && /^[A-Za-z]:[\\/]/.test(raw)) {
return raw.trim();
}
return resolveUserPath(raw);
}
export const TESTING_EXPORTS = {
COPILOT_NATIVE_PROJECT_DOC_BASENAMES,
COPILOT_BOOTSTRAP_CONTEXT_ORDER,
compareCopilotContextFiles,
getCopilotContextFileBasename,
};