@arjunkhera/atlas 0.3.45 → 0.3.48
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/.claude-plugin/plugin.json +1 -1
- package/door/cli.mjs +6 -4
- package/door/lib/install.mjs +47 -5
- package/door/lib/owner-only.mjs +778 -0
- package/door/lib/pull-request.mjs +3 -2
- package/door/lib/tooling.mjs +34 -10
- package/door/lib/upkeep.mjs +47 -6
- package/door/templates/pull_request_template.md +25 -0
- package/owner-only.yaml +238 -0
- package/package.json +3 -2
- package/shape/check.mjs +44 -3
- package/shape/releases.json +5 -0
- package/skills/lead/SKILL.md +23 -1
- package/work/lib/child-env.mjs +6 -0
- package/work/mcp.mjs +16 -8
package/work/mcp.mjs
CHANGED
|
@@ -24,8 +24,8 @@ import { createVerbs, STAGES, TIERS, DRIVERS, LINK_KINDS, REPO_KINDS, WAITS_ON,
|
|
|
24
24
|
import { COST_MEANING, DECISION_KINDS } from './lib/questions.mjs';
|
|
25
25
|
import { FATAL_CONCLUSIONS } from './lib/delivery.mjs';
|
|
26
26
|
import { createMcpServer } from './lib/mcp-stdio.mjs';
|
|
27
|
-
import { childEnvironment } from './lib/child-env.mjs';
|
|
28
|
-
import { upgrade } from '../door/lib/install.mjs';
|
|
27
|
+
import { childEnvironment, CLOUD_NODE_VARIABLES } from './lib/child-env.mjs';
|
|
28
|
+
import { upgrade, proveCopy } from '../door/lib/install.mjs';
|
|
29
29
|
export { childEnvironment };
|
|
30
30
|
|
|
31
31
|
const ATLAS_VERSION = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version;
|
|
@@ -74,7 +74,7 @@ export const TOOLS = [
|
|
|
74
74
|
{ name: 'where_are_we', description: 'Answer "where are we with X" in six parts: live support and known limits from the code read at question time, then in progress, delivered and proposed from the items, then the current priority decision. Every row carries a citation: a path and a line, an entity id, a pull request, or a decision date. The code half comes from the sub-agent digests, which are refused when they cite a never-read path or quote a never-quote path, and every string is scrubbed by pattern. Computed at read time and never stored. Scope: read, no owner flag needed.', inputSchema: { type: 'object', required: ['product', 'capability', 'code'], properties: { product: S('Product registry id.'), capability: S('The capability the question is about, the X.'), code: { type: 'array', description: 'One digest per repo, from the sub-agents briefed by code_read_brief. At least one is required: an answer with no code read says nothing about what the code does today.', items: CODE_DIGEST }, items: { type: 'array', description: 'Item ids the lead judges to answer this question.', items: { type: 'string' } }, match: { type: 'array', description: 'Terms to match against item titles, summaries and tags. Give items, match, or both.', items: { type: 'string' } }, movement_repos: { type: 'array', description: "Narrow the movement read to these registered repo ids. Default: every repo of the product. The digests' own repos are always read.", items: { type: 'string' } }, since: S('ISO date. Adds what changed since then.') }, additionalProperties: false } },
|
|
75
75
|
{ name: 'built_pending_possible', description: 'Answer "what are we building, what is built, what is pending and what can be done": delivered items by date, active items, paused items with their reason, proposed items with their age, and the decisions that set the order. Item records, delivery marks and decisions only; no code read and no GitHub read. Computed at read time and never stored. Scope: read, no owner flag needed.', inputSchema: { type: 'object', properties: { product: S('Limit the view to one product id.'), since: S('ISO date. Limits built and the decisions to what came after it.') }, additionalProperties: false } },
|
|
76
76
|
{ name: 'design_index', description: 'List every design: each work item with a design-doc link, in any lifecycle, newest change first, with its product, its state for the hub ("Waiting on the owner", "Building", "Paused", "Shipped", "Dropped"), its design docs and its pages. Also returns design_hub_url, the one hub page. When: before the lead rebuilds the "Design docs" hub, after each design publish, lock and done. Item records only; computed at read time and never stored. Scope: read, no owner flag needed.', inputSchema: { type: 'object', properties: { product: S('Limit the list to one product id.') }, additionalProperties: false } },
|
|
77
|
-
{ name: 'atlas_upgrade', description: 'Move Atlas on this Mac to the newest release: the same steps as the "atlas upgrade --yes" command. It checks that a master release run built the release, installs it and updates the plugin. When: the owner asks to upgrade Atlas. Use this tool and not the command: the Bash sandbox blocks the writes to ~/.npm, ~/.atlas and ~/.claude/plugins, and this server runs outside it. With check true it
|
|
77
|
+
{ name: 'atlas_upgrade', description: 'Move Atlas on this Mac to the newest release: the same steps as the "atlas upgrade --yes" command. It checks that a master release run built the release, installs it and updates the plugin. When: the owner asks to upgrade Atlas. Use this tool and not the command: the Bash sandbox blocks the writes to ~/.npm, ~/.atlas and ~/.claude/plugins, and this server runs outside it. With check true it writes no Atlas state: it reports the loaded and the newest version, and checks that the loaded files are the files of their master release commit (provenance: match, differs, unproven or not checked). The check runs from the copy it checks, so it finds stale or drifted files, not a package made to lie. The check runs anywhere, also in a Claude cloud session and with the owner flag off; the lead calls it at the first reply of a cloud session. Scope: this Mac, no tracker write. The upgrade itself is owner present only, and never in a Claude cloud session: a new cloud session installs the newest release.', inputSchema: { type: 'object', properties: { check: { type: 'boolean', description: 'True: report the versions and the provenance of the loaded copy, and install nothing.' } }, additionalProperties: false } },
|
|
78
78
|
];
|
|
79
79
|
|
|
80
80
|
// The Engram connection: the address and the key, in one setting, separated by
|
|
@@ -156,7 +156,7 @@ export const HOSTILE_NODE_VARIABLES = Object.freeze(['NODE_TLS_REJECT_UNAUTHORIZ
|
|
|
156
156
|
// that proxy. The owner accepted that proxy on 7 October 2026 ("Narrow
|
|
157
157
|
// exception"): the server accepts exactly these values, and only when the
|
|
158
158
|
// cloud's own marker is set. Any other value stays hostile, in the cloud too.
|
|
159
|
-
export
|
|
159
|
+
export { CLOUD_NODE_VARIABLES };
|
|
160
160
|
export const inClaudeCloud = (env) => env.CLAUDE_CODE_REMOTE === 'true';
|
|
161
161
|
export function hostileVariables(env) {
|
|
162
162
|
const cloud = inClaudeCloud(env);
|
|
@@ -246,16 +246,24 @@ const ATLAS_VERSION_OF = (root) => JSON.parse(readFileSync(join(root, 'package.j
|
|
|
246
246
|
function childExec(env) {
|
|
247
247
|
return (command, args) => execFileSync(command, args, { encoding: 'utf8', maxBuffer: 64 * 1024 * 1024, timeout: 600_000, stdio: ['pipe', 'pipe', 'pipe'], env: childEnvironment(env) });
|
|
248
248
|
}
|
|
249
|
-
|
|
249
|
+
const PROOFS = new WeakMap();
|
|
250
|
+
export async function runUpgrade({ args = {}, env = process.env, ownerPresent, packageRoot = PACKAGE_ROOT, exec = childExec(env), upgradeFn = upgrade, proveFn = proveCopy } = {}) {
|
|
250
251
|
const refuse = (message) => { const error = new Error(message); error.name = 'VerbError'; throw error; };
|
|
251
|
-
if (!ownerPresent) refuse('atlas_upgrade needs the owner-present flag on the server host (ATLAS_WORK_OWNER_PRESENT=1)');
|
|
252
|
-
if (inClaudeCloud(env)) refuse('atlas_upgrade does not run in a Claude cloud session. A new cloud session installs the newest release.');
|
|
253
252
|
const loaded = ATLAS_VERSION_OF(packageRoot);
|
|
253
|
+
// The check reads only, so it runs in a cloud session and with the owner
|
|
254
|
+
// flag off (item 92cfbba3): a cloud session states its lag at its first reply.
|
|
254
255
|
if (args.check) {
|
|
255
256
|
let newest;
|
|
256
257
|
try { newest = exec('npm', ['view', '@arjunkhera/atlas', 'version']).trim(); } catch (error) { refuse(`npm could not read the newest version: ${String(error.stderr || error.message).trim().split('\n').slice(0, 3).join(' ')}`); }
|
|
257
|
-
|
|
258
|
+
// The loaded copy cannot change within a server's life, so one proof per
|
|
259
|
+
// copy: a repeated check makes no new GitHub reads.
|
|
260
|
+
if (!PROOFS.has(proveFn)) PROOFS.set(proveFn, new Map());
|
|
261
|
+
const proofs = PROOFS.get(proveFn);
|
|
262
|
+
if (!proofs.has(packageRoot)) proofs.set(packageRoot, proveFn({ packageRoot, exec }));
|
|
263
|
+
return { loaded, newest, behind: newest !== loaded, provenance: proofs.get(packageRoot) };
|
|
258
264
|
}
|
|
265
|
+
if (!ownerPresent) refuse('atlas_upgrade needs the owner-present flag on the server host (ATLAS_WORK_OWNER_PRESENT=1)');
|
|
266
|
+
if (inClaudeCloud(env)) refuse('atlas_upgrade does not run in a Claude cloud session. A new cloud session installs the newest release.');
|
|
259
267
|
const lines = [];
|
|
260
268
|
let code;
|
|
261
269
|
try { code = await upgradeFn({ packageRoot, options: { yes: true }, line: (text) => lines.push(text), env, exec }); } catch (error) {
|