Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 0 additions & 9 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -239,15 +239,6 @@ jobs:
- name: Smoke test repository composition with the compiled binary
run: deno run --allow-all --frozen scripts/smoke-run-composition.ts

# A retained REPL entry's repository host is assembled at a runtime-named
# entrypoint too, and reaches further than the ordinary run's: the Git
# host, the credential helper the binary re-enters as a subprocess of
# itself, and the records an interrupted entry is read back from. This
# drives the binary's own `xmd repl` on a pty, publishes out of an ambient
# checkout into a bare remote, leaves, and reopens the location it printed.
- name: Smoke test a REPL entry's repository work with the compiled binary
run: deno test --allow-all --frozen scripts/tests/repl-repositories-compiled.test.ts

# `<Fetch>` resolves from core's registry, requests through the contextual
# Fetch adapter, and detaches the response before binding it. All three
# live in the module graph, so only the binary shows they survived
Expand Down
245 changes: 5 additions & 240 deletions architecture.md

Large diffs are not rendered by default.

18 changes: 1 addition & 17 deletions packages/cli/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,6 @@ import { testingExecutionHost } from "./testing-host.ts";
import type { ChildPlanDeclaration } from "./testing-host.ts";
import { unsupportedRepositories } from "./run-repositories.ts";
import type { RepositoryInstaller } from "./run-repositories.ts";
import type { ReplEntryHostFactory } from "./repl-repositories.ts";
import { EVAL_ALIAS, EVAL_OPTION, evalGrammarError, readEvalFlags } from "./eval-source.ts";
import type { EvalFlags } from "./eval-source.ts";
import { STANDARD_INPUT_FAILURE, STANDARD_INPUT_PATH } from "./standard-input.ts";
Expand Down Expand Up @@ -2678,11 +2677,6 @@ function* dispatch(
workflowHost: WorkflowHost | undefined,
sessions: MachineSessionAssembly | undefined,
installRepl: ReplHostInstaller | undefined,
// What a REPL entry of this host obtains repository operations through, or
// nothing on a runtime that offers none. Carried rather than called: the
// `repl` command retains it in its profile, and the entry task builds the
// host.
replEntryHost: ReplEntryHostFactory | undefined,
/**
* What this invocation's Plugins installed.
*
Expand Down Expand Up @@ -2929,7 +2923,7 @@ function* dispatch(
// vocabulary and the ceiling a generated fragment runs under. Nothing is
// assembled again per entry, so two entries of one session cannot run
// under different rules.
const profile = yield* assembleReplProfile(replStack, plugins, {}, replEntryHost);
const profile = yield* assembleReplProfile(replStack, plugins);
yield* installRepl();
const ran = yield* runReplProgram({
profile,
Expand Down Expand Up @@ -3336,13 +3330,6 @@ export function* runXmd(
// names none has no REPL, and says so rather than opening a terminal it cannot
// restore.
installRepl?: ReplHostInstaller,
// How a REPL entry of this host obtains repository operations. A factory, so
// the host belongs to the executing entry's own task rather than to the
// command: two entries of one session are two owners, and a cold view builds
// none at all. Deno and the compiled binary supply the retained one; Node and
// Bun supply none, so an entry there refuses repository work before a lock, a
// credential, a subprocess or a request exists.
replEntryHost?: ReplEntryHostFactory,
): Operation<void> {
// Before every scanner and before anything reads a path: what a command line
// selects is read from the argv the caller wrote, and the tokens that
Expand Down Expand Up @@ -3377,7 +3364,6 @@ export function* runXmd(
installWorkflowHost,
sessions,
installRepl,
replEntryHost,
);
}

Expand Down Expand Up @@ -3440,7 +3426,6 @@ function* runCommand(
installWorkflowHost: HostWorkflowInstaller,
sessions: MachineSessionAssembly | undefined,
installRepl: ReplHostInstaller | undefined,
replEntryHost: ReplEntryHostFactory | undefined,
): Operation<void> {
// First, so that no later scanner — help, properties, agent flags — can
// mistake the inline document's own text for an option.
Expand Down Expand Up @@ -3506,7 +3491,6 @@ function* runCommand(
workflowHost,
sessions,
installRepl,
replEntryHost,
plugins,
);

Expand Down
5 changes: 1 addition & 4 deletions packages/cli/src/compiled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { importPluginModule } from "./host-plugin-modules.ts";
import { compiledUpgradeAssembly } from "./compiled-upgrade.ts";
import { useMachineSessions } from "./session-coordinator.ts";
import { useDenoWorkflowHost } from "./deno-workflow.ts";
import { denoReplEntryHost, denoRunRepositories } from "./deno-repositories.ts";
import { denoRunRepositories } from "./deno-repositories.ts";
import { isCredentialHelperMode, runCredentialHelper } from "@executablemd/git/credential-helper";
import type { HelperAssembly } from "@executablemd/git/credential-helper";
import { useCompiledService } from "./compiled-service.ts";
Expand Down Expand Up @@ -94,9 +94,6 @@ if (isCredentialHelperMode(process.argv.slice(2))) {
() => useDenoWorkflowHost(HELPER),
useMachineSessions(),
useCompiledRepl,
// The same retained host the source entrypoint supplies: a compiled
// binary is the same program, and an entry it runs resumes the same way.
denoReplEntryHost(HELPER),
);
});
}
48 changes: 2 additions & 46 deletions packages/cli/src/deno-repositories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,11 @@
*/

import type { Operation } from "effection";
import { cwd, hostFilesHandler } from "@executablemd/runtime";
import {
denoRepositoryHost,
useRetainedRepositoryEntry,
useRunComposition,
} from "@executablemd/git/deno";
import { cwd } from "@executablemd/runtime";
import { useRunComposition } from "@executablemd/git/deno";
import type { HelperAssembly } from "@executablemd/git/credential-helper";
import { DEFAULT_REPOSITORY_ROOT } from "./run-repositories.ts";
import type { RepositoryInstaller } from "./run-repositories.ts";
import type { ReplEntryHost, ReplEntryHostFactory } from "./repl-repositories.ts";

/**
* The live provider Deno and the compiled binary install.
Expand Down Expand Up @@ -52,42 +47,3 @@ export function denoRunRepositories(
});
};
}

/**
* The retained host one REPL entry runs its repository work through.
*
* Built per entry, inside that entry's own task, which is what the factory is
* for: the owner it retains under is this execution and this admitted entry,
* and everything it acquires — a lease, a credential session, a scratch
* directory — belongs to the task that asked for it and ends with it. A cold
* view calls none of this, because nothing executes there to ask.
*
* Managed checkouts live under the same root an ordinary run uses, for the same
* reason: what is in one is somebody's work, and which entry wrote it does not
* change where it lives.
*/
export function denoReplEntryHost(
helper: HelperAssembly,
root: string = DEFAULT_REPOSITORY_ROOT,
): ReplEntryHostFactory {
return function* (request): Operation<ReplEntryHost> {
const entry = yield* useRetainedRepositoryEntry({
executionId: request.executionId,
entryKey: request.entryKey,
source: request.source,
// Where this entry started, which is where its ambient checkout is
// looked for. Read through the contextual Api rather than from the
// process, and read once: a resume takes the root its own history
// recorded instead of looking again.
cwd: yield* cwd(),
managedRoot: root,
host: denoRepositoryHost({ helper }),
// Ordinary file behavior, for everything outside a selected checkout. The
// entry's own handlers perform it directly rather than routing back
// through the public chain, which is what keeps a write beside the
// document ordinary and a write inside a checkout retained.
files: hostFilesHandler(),
});
return { installation: entry.installation, files: entry.files };
};
}
7 changes: 1 addition & 6 deletions packages/cli/src/deno.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { importPluginModule } from "./host-plugin-modules.ts";
import type { UpgradeAssembly } from "./upgrade.ts";
import { useMachineSessions } from "./session-coordinator.ts";
import { useDenoWorkflowHost } from "./deno-workflow.ts";
import { denoReplEntryHost, denoRunRepositories } from "./deno-repositories.ts";
import { denoRunRepositories } from "./deno-repositories.ts";
import { isCredentialHelperMode, runCredentialHelper } from "@executablemd/git/credential-helper";
import type { HelperAssembly } from "@executablemd/git/credential-helper";
import { useDenoService } from "./deno-service.ts";
Expand Down Expand Up @@ -113,11 +113,6 @@ if (isCredentialHelperMode(process.argv.slice(2))) {
() => useDenoWorkflowHost(HELPER),
useMachineSessions(),
useDenoRepl,
// One retained repository host per REPL entry, under the same managed
// root and the same credential-helper assembly the ordinary provider
// uses. A factory, so nothing is built until an entry is actually
// executing.
denoReplEntryHost(HELPER),
);
});
}
31 changes: 0 additions & 31 deletions packages/cli/src/evaluation-profile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,37 +103,6 @@ export function ordinaryEvaluationProfile(): FragmentEvaluationInput {
};
}

/**
* The same installations, with one entry's own file access bound into the
* ceiling.
*
* The tables are untouched: what a generated fragment may name, and in which
* spelling, is the command's single decision and is settled before any entry
* exists. What changes per entry is only *which* instance the admitted
* operations reach — this entry's retained one, so a fragment's write inside a
* checkout the entry has selected is retained exactly as an authored write is.
*
* Rebound rather than appended, because one execution offers one maximum
* permission: a second profile beside the first would be two ceilings for one
* fragment, and "whichever came last wins" is how permission stops being
* auditable.
*/
export function withEntryFileAccess(
installations: readonly ExecutionInstallation[],
files: FragmentFileAccess,
): readonly ExecutionInstallation[] {
return Object.freeze(
installations.map((installation) =>
installation.evaluation === undefined
? installation
: Object.freeze({
...installation,
evaluation: Object.freeze({ ...installation.evaluation, files }),
}),
),
);
}

/**
* Whether the host that attached this execution already stated a ceiling.
*
Expand Down
16 changes: 0 additions & 16 deletions packages/cli/src/repl-profile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import { ordinaryEvaluationProfile } from "./evaluation-profile.ts";
import { planComponentDeclaration } from "./plan-component.ts";
import { planAgentContext } from "./plan-writer-profile.ts";
import type { CommandPlugins } from "./plugin-host.ts";
import type { ReplEntryHostFactory } from "./repl-repositories.ts";

/**
* Where a REPL entry looks for components.
Expand Down Expand Up @@ -67,16 +66,6 @@ export interface ReplExecutionProfile {
readonly installations: readonly ExecutionInstallation[];
/** How this REPL answers an Agent permission request. */
readonly permissionMode: PermissionMode;
/**
* How each entry of this execution obtains repository operations.
*
* A factory, retained and never called here: the host belongs to the
* executing entry's own task, and building one at assembly would give every
* entry of the session one owner and make a cold view somebody is only
* reading acquire a checkout and a lease. Absent on a runtime that supplies
* none, which leaves repository work refusing before anything is touched.
*/
readonly entryHost?: ReplEntryHostFactory;
}

/**
Expand All @@ -96,10 +85,6 @@ export function* assembleReplProfile(
stack: AgentStack,
plugins: CommandPlugins,
seams: ReplProfileSeams = {},
// What this runtime offers an entry for repository work, from the entrypoint
// that knows whether it has one. Retained as given: it is called by the entry
// task, not here.
entryHost?: ReplEntryHostFactory,
): Operation<ReplExecutionProfile> {
yield* installAgentProviderStack(stack, seams.acp);

Expand Down Expand Up @@ -134,7 +119,6 @@ export function* assembleReplProfile(
}),
]),
permissionMode: stack.permissionMode,
...(entryHost === undefined ? {} : { entryHost }),
});
}

Expand Down
83 changes: 0 additions & 83 deletions packages/cli/src/repl-repositories.ts

This file was deleted.

11 changes: 0 additions & 11 deletions packages/cli/src/repl/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,8 +207,6 @@ export function* runReplProgram(options: ReplProgramOptions): Operation<Result<R
includes: options.profile.includes,
installations: options.profile.installations,
permissionMode: options.profile.permissionMode,
// Carried, not called: the session hands it to each entry's own task.
...(options.profile.entryHost === undefined ? {} : { entryHost: options.profile.entryHost }),
...(state.route.at === undefined ? {} : { selection: state.route.at }),
});

Expand Down Expand Up @@ -741,15 +739,6 @@ function* drive(
} else if (built !== undefined && built.ok) {
state = adopting;
reading = candidate;
// Standing at the head means the unfinished entry below is this
// process's to continue. Said here rather than at the open, because a
// location may name a frozen position: that view continues nothing, and
// the control that comes back to the head is what asks for the work.
// Idempotent, so a frame that merely redrew the head starts nothing and
// an entry already running is left exactly as it is.
if (state.route.at === undefined) {
yield* current.resume();
}
// The readiness may have moved while that refusal was on the screen: the
// entry it named has finished, or the teardown it named has completed.
// A refusal that is no longer true is worse than no refusal, because it
Expand Down
Loading
Loading