maesttro 0.4.2 → 0.4.3
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/README.md +1 -1
- package/dist/maesttro.js +40 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -189,7 +189,7 @@ Declining only skips it for that run; the next start asks again.
|
|
|
189
189
|
|---|---|---|
|
|
190
190
|
| `/home/agent` | `maesttro-home` named volume | Per-client session state. Survives across runs, lives only in Docker. Holds no GitHub credential. |
|
|
191
191
|
| `/home/agent/.config/gh-maesttro` (read-only) | per-session temp dir on host | The session's GitHub token (`hosts.yml`). The CLI refreshes it before its 1 h expiry and revokes it on exit. Not mounted in `--strict` sessions, or when GitHub access is unavailable. |
|
|
192
|
-
|
|
|
192
|
+
| `/opt/maesttro-objects` (read-only) | your repo's `.git/objects` | Base history, borrowed by the clone through its `alternates`, which is pinned to this fixed path so it resolves the same on every host OS. The real `.git` is never mounted. |
|
|
193
193
|
| `/workspace` | the session clone (`.worktrees/<id>`) | The working directory: a `git clone --shared` detached at the default branch. |
|
|
194
194
|
| `/opt/maesttro`, `/opt/maesttro-host` (read-only) | this package; your instruction files | Used by `maesttro configure` at container start. |
|
|
195
195
|
| `/home/agent/.claude/skills` (read-only) | `~/agent-shared/skills` on host, if present | Reusable skills/house-style files shared across sessions. Read-only. |
|
package/dist/maesttro.js
CHANGED
|
@@ -1611,7 +1611,10 @@ async function openGitHubSession({
|
|
|
1611
1611
|
...identityEnv(author, initial.committer)
|
|
1612
1612
|
};
|
|
1613
1613
|
return {
|
|
1614
|
-
dockerArgs: withEnvFlags([
|
|
1614
|
+
dockerArgs: withEnvFlags([
|
|
1615
|
+
"--mount",
|
|
1616
|
+
`type=bind,source=${dir.ghDir},target=${CONTAINER_GH_CONFIG_DIR},readonly`
|
|
1617
|
+
], env),
|
|
1615
1618
|
env,
|
|
1616
1619
|
close: async () => {
|
|
1617
1620
|
refresher.stop();
|
|
@@ -1642,7 +1645,8 @@ import {
|
|
|
1642
1645
|
lstatSync,
|
|
1643
1646
|
mkdirSync as mkdirSync9,
|
|
1644
1647
|
readdirSync as readdirSync3,
|
|
1645
|
-
readFileSync as readFileSync6
|
|
1648
|
+
readFileSync as readFileSync6,
|
|
1649
|
+
writeFileSync as writeFileSync7
|
|
1646
1650
|
} from "node:fs";
|
|
1647
1651
|
import { join as join9 } from "node:path";
|
|
1648
1652
|
|
|
@@ -1837,6 +1841,31 @@ function copyObjectFiles(fromDir, intoDir) {
|
|
|
1837
1841
|
copyFileSync(join9(fromDir, entry.name), dest);
|
|
1838
1842
|
}
|
|
1839
1843
|
}
|
|
1844
|
+
function pinAlternates(clonePath, containerObjects) {
|
|
1845
|
+
const gitDir = cloneGitDir(clonePath);
|
|
1846
|
+
if (!gitDir)
|
|
1847
|
+
return;
|
|
1848
|
+
const objects = join9(gitDir, "objects");
|
|
1849
|
+
const info = join9(objects, "info");
|
|
1850
|
+
if (!realDir(objects) || !realDir(info)) {
|
|
1851
|
+
throw new LaunchError(`Unsafe objects tree in the session clone: ${clonePath}`);
|
|
1852
|
+
}
|
|
1853
|
+
const alternates = join9(info, "alternates");
|
|
1854
|
+
let stat;
|
|
1855
|
+
try {
|
|
1856
|
+
stat = lstatSync(alternates);
|
|
1857
|
+
} catch {
|
|
1858
|
+
return;
|
|
1859
|
+
}
|
|
1860
|
+
if (!stat.isFile()) {
|
|
1861
|
+
throw new LaunchError(`Unsafe alternates file in the session clone: ${clonePath}`);
|
|
1862
|
+
}
|
|
1863
|
+
const desired = `${containerObjects}
|
|
1864
|
+
`;
|
|
1865
|
+
if (readFileSync6(alternates, "utf8") !== desired) {
|
|
1866
|
+
writeFileSync7(alternates, desired);
|
|
1867
|
+
}
|
|
1868
|
+
}
|
|
1840
1869
|
function importObjects(run, root, clonePath, tip) {
|
|
1841
1870
|
const gitDir = cloneGitDir(clonePath);
|
|
1842
1871
|
if (!gitDir)
|
|
@@ -1864,7 +1893,7 @@ import {
|
|
|
1864
1893
|
readFileSync as readFileSync7,
|
|
1865
1894
|
renameSync as renameSync4,
|
|
1866
1895
|
rmSync as rmSync5,
|
|
1867
|
-
writeFileSync as
|
|
1896
|
+
writeFileSync as writeFileSync8
|
|
1868
1897
|
} from "node:fs";
|
|
1869
1898
|
import { join as join10 } from "node:path";
|
|
1870
1899
|
function newSessionId() {
|
|
@@ -1876,7 +1905,7 @@ function sessionsDir(home = maesttroHome()) {
|
|
|
1876
1905
|
function saveSession(record, dir = sessionsDir()) {
|
|
1877
1906
|
mkdirSync10(dir, { recursive: true, mode: 448 });
|
|
1878
1907
|
const path = join10(dir, `${record.id}.json`);
|
|
1879
|
-
|
|
1908
|
+
writeFileSync8(`${path}.tmp`, `${JSON.stringify(record, null, 2)}
|
|
1880
1909
|
`);
|
|
1881
1910
|
renameSync4(`${path}.tmp`, path);
|
|
1882
1911
|
}
|
|
@@ -1929,6 +1958,7 @@ function workspaceAuthor(run, workspace) {
|
|
|
1929
1958
|
// src/launch.ts
|
|
1930
1959
|
var CONTAINER_REPO = "/workspace";
|
|
1931
1960
|
var CONTAINER_PACKAGE = "/opt/maesttro";
|
|
1961
|
+
var CONTAINER_GIT_OBJECTS = "/opt/maesttro-objects";
|
|
1932
1962
|
function resolveCommand(args) {
|
|
1933
1963
|
const [first, ...rest] = args;
|
|
1934
1964
|
if (first === undefined)
|
|
@@ -1951,8 +1981,8 @@ function sessionMounts({
|
|
|
1951
1981
|
}) {
|
|
1952
1982
|
const objects = join11(repoRoot, ".git", "objects");
|
|
1953
1983
|
const mounts = [
|
|
1954
|
-
{ host: VOLUME, container: "/home/agent" },
|
|
1955
|
-
{ host: objects, container:
|
|
1984
|
+
{ host: VOLUME, container: "/home/agent", type: "volume" },
|
|
1985
|
+
{ host: objects, container: CONTAINER_GIT_OBJECTS, readOnly: true },
|
|
1956
1986
|
{ host: sessionDir, container: CONTAINER_REPO },
|
|
1957
1987
|
{ host: packageRoot, container: CONTAINER_PACKAGE, readOnly: true },
|
|
1958
1988
|
...stagedPaths.map((path) => ({
|
|
@@ -1982,9 +2012,9 @@ function dockerRunArgs({
|
|
|
1982
2012
|
extra = [],
|
|
1983
2013
|
name
|
|
1984
2014
|
}) {
|
|
1985
|
-
const volumes = mounts.flatMap(({ host, container, readOnly }) => [
|
|
1986
|
-
"
|
|
1987
|
-
|
|
2015
|
+
const volumes = mounts.flatMap(({ host, container, readOnly, type = "bind" }) => [
|
|
2016
|
+
"--mount",
|
|
2017
|
+
`type=${type},source=${host},target=${container}${readOnly ? ",readonly" : ""}`
|
|
1988
2018
|
]);
|
|
1989
2019
|
return [
|
|
1990
2020
|
"run",
|
|
@@ -2222,6 +2252,7 @@ async function launch({
|
|
|
2222
2252
|
"MAESTTRO_HOST_GID"
|
|
2223
2253
|
].concat(repo ? ["MAESTTRO_REPO"] : []).flatMap((name) => ["-e", name]);
|
|
2224
2254
|
clearStaleContainer(saved.id);
|
|
2255
|
+
pinAlternates(saved.worktree, CONTAINER_GIT_OBJECTS);
|
|
2225
2256
|
const child = spawn("docker", dockerRunArgs({
|
|
2226
2257
|
command: containerCommand(resolveCommand(args)),
|
|
2227
2258
|
mounts,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "maesttro",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.3",
|
|
4
4
|
"description": "Isolated Docker runner for local coding agents (opencode, claude, ...) under a dedicated bot GitHub identity, with curated configs baked in per client.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|