clearotron 0.3.3 → 0.4.0-beta.0
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/INSTALL.md +1 -14
- package/bin/brandowner.mjs +5 -5
- package/bin/connect.mjs +4 -4
- package/bin/onboard.mjs +5 -7
- package/bin/start.mjs +20 -5
- package/build-info.json +2 -2
- package/driver/CHANGELOG.md +18 -0
- package/driver/company-bundle.mjs +11 -18
- package/driver/door-call-verdict.mjs +27 -0
- package/driver/driver.config.mjs +1 -2
- package/driver/package.json +1 -1
- package/driver/pipeline.mjs +14 -5
- package/driver/portal-mcp-client.mjs +1 -1
- package/driver/portal-request-origin.mjs +79 -0
- package/driver/portal-service.mjs +43 -15
- package/driver/profile-page.html +9 -13
- package/driver/profile-service.mjs +25 -13
- package/driver/profiles.mjs +17 -4
- package/driver/publish/index.mjs +13 -1
- package/driver/publish/render.mjs +13 -2
- package/driver/publish/search-depth.mjs +4 -2
- package/driver/run-economics.mjs +7 -18
- package/driver/stages.mjs +1 -1
- package/driver/suite-census.json +61 -31
- package/driver/tokens.mjs +18 -10
- package/mcp-server/CHANGELOG.md +4 -0
- package/mcp-server/lib/audit.mjs +9 -2
- package/mcp-server/lib/http-handler.mjs +7 -3
- package/mcp-server/mint-token.mjs +8 -6
- package/mcp-server/package.json +1 -1
- package/mcp-server/server.mjs +10 -0
- package/package.json +1 -1
- package/portal-ui/dist/assets/{index-GBbbyQxc.js → index-DVtz44vH.js} +57 -8
- package/portal-ui/dist/index.html +1 -1
- package/portal-ui/package.json +1 -1
- package/providers/oauth-mcp-bridge/CHANGELOG.md +4 -0
- package/providers/oauth-mcp-bridge/package.json +1 -1
- package/scripts/freeze-example-run.mjs +1 -1
- package/scripts/live-surface-check.mjs +11 -2
- package/scripts/release-entry-catch-up.mjs +142 -0
- package/shared/client-door.mjs +15 -8
- package/shared/scope.mjs +25 -10
- package/shared/store-in-repo.mjs +38 -17
package/shared/store-in-repo.mjs
CHANGED
|
@@ -282,6 +282,7 @@ export function commitWithAuditRow({ audit, gitCommit, files, message, by, row }
|
|
|
282
282
|
// That makes the failure resumable, and it makes "a concurrent editor's staged work survives" true by
|
|
283
283
|
// construction rather than by a careful reset that has to guess whose paths are whose.
|
|
284
284
|
import { execFileSync } from "node:child_process";
|
|
285
|
+
import { BRAND } from "./brand.mjs";
|
|
285
286
|
|
|
286
287
|
// Lock contention is TRANSIENT and worth retrying. A hook rejection and a full disk are not: retrying
|
|
287
288
|
// them turns one named failure into several and delays the report. The distinction is the reason this
|
|
@@ -289,17 +290,39 @@ import { execFileSync } from "node:child_process";
|
|
|
289
290
|
export const isTransientGitFault = (detail) =>
|
|
290
291
|
/index\.lock|another git process seems to be running|Unable to create/i.test(String(detail ?? ""));
|
|
291
292
|
|
|
293
|
+
// ── THE PRODUCT NAMES ITS OWN COMMITTER WHEN GIT HAS NONE ───────────────────────────────────────────
|
|
294
|
+
//
|
|
295
|
+
// A save names its author, the person who asked for it. Git also records a COMMITTER, taken from the
|
|
296
|
+
// repository's or the account's configuration, and refuses the commit when it finds none. That is the
|
|
297
|
+
// default state of a service account nobody ran `git config` for, and of a fresh Windows install: every
|
|
298
|
+
// company created in the portal was refused there, with a message telling the person to run git. The
|
|
299
|
+
// person creating a company cannot act on that, and nothing about the save needs them to.
|
|
300
|
+
//
|
|
301
|
+
// So a commit into the store is given the product's own committer whenever git cannot name one, on every
|
|
302
|
+
// commit rather than once: `-c` or an environment variable configures one invocation, not the repository.
|
|
303
|
+
// A store or account that already has an identity keeps it, so a configured install records exactly what
|
|
304
|
+
// it recorded before, signing included.
|
|
305
|
+
export const STORE_COMMITTER = Object.freeze({ name: BRAND.name, email: "store@localhost" });
|
|
306
|
+
|
|
307
|
+
/** The environment a commit into `repoRoot` runs with: `env` itself when git can name a committer, else `env` plus the product's. */
|
|
308
|
+
export function storeCommitEnv(repoRoot, { env = process.env } = {}) {
|
|
309
|
+
requireRepoRootPath(repoRoot, "storeCommitEnv");
|
|
310
|
+
try {
|
|
311
|
+
execFileSync("git", ["-C", repoRoot, "var", "GIT_COMMITTER_IDENT"], { stdio: ["ignore", "pipe", "pipe"], env });
|
|
312
|
+
return env;
|
|
313
|
+
} catch {
|
|
314
|
+
return { ...env, GIT_COMMITTER_NAME: STORE_COMMITTER.name, GIT_COMMITTER_EMAIL: STORE_COMMITTER.email };
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
292
318
|
/**
|
|
293
319
|
* Why a commit into `repoRoot` would be refused, asked BEFORE anything is written; null when it would not
|
|
294
|
-
* be. Read-only: `rev-parse`
|
|
295
|
-
*
|
|
320
|
+
* be. Read-only: `rev-parse` changes nothing. `{ code, detail, message }`, where `message` names the store
|
|
321
|
+
* and the command that clears it, in terms an operator acts on rather than git's own words:
|
|
296
322
|
*
|
|
297
|
-
* not-a-repository — the store is not inside a git repository this process can use
|
|
298
|
-
*
|
|
299
|
-
*
|
|
300
|
-
* its author; the COMMITTER is the machine's, and git refuses a commit it cannot name
|
|
301
|
-
* one for. `git -c user.email=…` on a one-off seed commit does not help: `-c` configures
|
|
302
|
-
* that invocation, not the repository, so every save after it fails the same way.
|
|
323
|
+
* not-a-repository — the store is not inside a git repository this process can use.
|
|
324
|
+
*
|
|
325
|
+
* A missing committer identity is not a refusal: every commit into the store supplies one (storeCommitEnv).
|
|
303
326
|
*/
|
|
304
327
|
export function storeCommitRefusal(repoRoot, { env = process.env } = {}) {
|
|
305
328
|
requireRepoRootPath(repoRoot, "storeCommitRefusal");
|
|
@@ -313,18 +336,13 @@ export function storeCommitRefusal(repoRoot, { env = process.env } = {}) {
|
|
|
313
336
|
: `run \`git init\` in ${repoRoot}, or point PROFILE_REPO_ROOT at the repository that holds the store`;
|
|
314
337
|
return { code: "not-a-repository", detail, message: `the store at ${repoRoot} is not a git repository this install can record into (${detail}) — ${fix}` };
|
|
315
338
|
}
|
|
316
|
-
try { ask("var", "GIT_COMMITTER_IDENT"); }
|
|
317
|
-
catch (e) {
|
|
318
|
-
return { code: "no-identity", detail: said(e).pop()?.slice(0, 200) ?? "",
|
|
319
|
-
message: `the store at ${repoRoot} has no git identity, so nothing saved to it can be recorded — run `
|
|
320
|
-
+ `\`git -C ${repoRoot} config user.email "you@example.com"\` and \`git -C ${repoRoot} config user.name "Your Name"\`` };
|
|
321
|
-
}
|
|
322
339
|
return null;
|
|
323
340
|
}
|
|
324
341
|
|
|
325
342
|
export function makeStoreCommit({ repoRoot, log = () => {}, what = "store", retries = 3, waitMs = 50 }) {
|
|
326
343
|
requireRepoRootPath(repoRoot, "makeStoreCommit");
|
|
327
|
-
const
|
|
344
|
+
const run = (env, args) => execFileSync("git", ["-C", repoRoot, ...args], { encoding: "utf8", ...(env ? { env } : {}) }).toString().trim();
|
|
345
|
+
const git = (...args) => run(null, args);
|
|
328
346
|
// ── IS THIS A REPOSITORY WE CAN USE? ASKED FIRST ─────────────────────────────
|
|
329
347
|
//
|
|
330
348
|
// Outside a repository git falls back to `--no-index` mode, which has no `--cached` — so the very
|
|
@@ -351,13 +369,16 @@ export function makeStoreCommit({ repoRoot, log = () => {}, what = "store", retr
|
|
|
351
369
|
log(`${what}: the store is not a usable git repository, so this save CANNOT be committed — ${refusal}`);
|
|
352
370
|
throw new Error(`the store at ${repoRoot} is not a usable git repository: ${refusal}`);
|
|
353
371
|
}
|
|
372
|
+
// Asked per commit, so an identity somebody configures while the service runs is used from then on.
|
|
373
|
+
const committing = storeCommitEnv(repoRoot);
|
|
374
|
+
const gitCommit = (...args) => run(committing, args);
|
|
354
375
|
// (1) Complete what an earlier failed save left staged. BEST EFFORT: if this fails too — the same
|
|
355
376
|
// hook is still rejecting, the disk is still full — it must not stop the save that is happening now,
|
|
356
377
|
// and it must not touch the index either. The paths simply stay staged for the next attempt.
|
|
357
378
|
try {
|
|
358
379
|
const found = git("diff", "--cached", "--name-only").split("\n").filter(Boolean);
|
|
359
380
|
if (found.length) {
|
|
360
|
-
|
|
381
|
+
gitCommit("commit", "-m", `Complete a store save left staged by an earlier failure (${found.length} path(s))`,
|
|
361
382
|
"--author", `${author} <${author}>`);
|
|
362
383
|
log(`${what}: completed a commit left staged by an earlier failed save — ${found.join(", ")}`);
|
|
363
384
|
}
|
|
@@ -369,7 +390,7 @@ export function makeStoreCommit({ repoRoot, log = () => {}, what = "store", retr
|
|
|
369
390
|
git("add", ...files);
|
|
370
391
|
for (let attempt = 1; ; attempt++) {
|
|
371
392
|
try {
|
|
372
|
-
|
|
393
|
+
gitCommit("commit", "-m", message, "--author", `${author} <${author}>`);
|
|
373
394
|
return git("rev-parse", "HEAD");
|
|
374
395
|
} catch (e) {
|
|
375
396
|
const detail = detailOf(e);
|