@amalgm/shell 0.1.135 → 0.1.136

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.
@@ -0,0 +1,3 @@
1
+ /** Run `perform` over every item with at most `concurrency` in flight. The
2
+ * first failure stops admission and rejects the whole loop. */
3
+ export declare function boundedForEach<T>(items: readonly T[], concurrency: number, perform: (item: T) => Promise<void>): Promise<void>;
@@ -0,0 +1,26 @@
1
+ /** Run `perform` over every item with at most `concurrency` in flight. The
2
+ * first failure stops admission and rejects the whole loop. */
3
+ export async function boundedForEach(items, concurrency, perform) {
4
+ if (!Number.isSafeInteger(concurrency) || concurrency < 1) {
5
+ throw new Error("bounded loop concurrency must be a positive integer");
6
+ }
7
+ let next = 0;
8
+ let stopped = false;
9
+ const worker = async () => {
10
+ while (!stopped) {
11
+ const index = next;
12
+ next += 1;
13
+ if (index >= items.length)
14
+ return;
15
+ try {
16
+ await perform(items[index]);
17
+ }
18
+ catch (error) {
19
+ stopped = true;
20
+ throw error;
21
+ }
22
+ }
23
+ };
24
+ await Promise.all(Array.from({ length: Math.min(concurrency, items.length) }, () => worker()));
25
+ }
26
+ //# sourceMappingURL=bounded-for-each.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bounded-for-each.js","sourceRoot":"","sources":["../src/bounded-for-each.ts"],"names":[],"mappings":"AAAA;+DAC+D;AAC/D,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,KAAmB,EACnB,WAAmB,EACnB,OAAmC;IAEnC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,WAAW,CAAC,IAAI,WAAW,GAAG,CAAC,EAAE,CAAC;QAC1D,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;IACzE,CAAC;IACD,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,MAAM,MAAM,GAAG,KAAK,IAAI,EAAE;QACxB,OAAO,CAAC,OAAO,EAAE,CAAC;YAChB,MAAM,KAAK,GAAG,IAAI,CAAC;YACnB,IAAI,IAAI,CAAC,CAAC;YACV,IAAI,KAAK,IAAI,KAAK,CAAC,MAAM;gBAAE,OAAO;YAClC,IAAI,CAAC;gBACH,MAAM,OAAO,CAAC,KAAK,CAAC,KAAK,CAAM,CAAC,CAAC;YACnC,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,OAAO,GAAG,IAAI,CAAC;gBACf,MAAM,KAAK,CAAC;YACd,CAAC;QACH,CAAC;IACH,CAAC,CAAC;IACF,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAC1B,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE,EAC/C,GAAG,EAAE,CAAC,MAAM,EAAE,CACf,CAAC,CAAC;AACL,CAAC"}
@@ -3,6 +3,9 @@ export declare function ensurePrivateDir(directory: string): void;
3
3
  * gets 0755 — the same default a fresh mkdir gives the user — and an
4
4
  * existing directory keeps whatever mode the user chose. */
5
5
  export declare function ensureUserDir(directory: string): void;
6
+ /** The batch form of ensureUserDir: the same mode law for a whole directory
7
+ * skeleton, created ahead of the files it will hold and off the event loop. */
8
+ export declare function ensureUserDirs(directories: readonly string[], concurrency: number): Promise<void>;
6
9
  export declare function atomicWrite(file: string, bytes: string | Uint8Array, mode?: number): void;
7
10
  export declare function atomicCopy(source: string, destination: string, mode?: number): void;
8
11
  /** Assemble verified chunk files without holding the complete artifact in RAM. */
@@ -1,7 +1,9 @@
1
1
  import { createHash, randomUUID } from "node:crypto";
2
2
  import { constants, chmodSync, copyFileSync, createReadStream, createWriteStream, existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync, } from "node:fs";
3
+ import { chmod, mkdir } from "node:fs/promises";
3
4
  import { dirname } from "node:path";
4
5
  import { once } from "node:events";
6
+ import { boundedForEach } from "./bounded-for-each.js";
5
7
  export function ensurePrivateDir(directory) {
6
8
  mkdirSync(directory, { recursive: true, mode: 0o700 });
7
9
  chmodSync(directory, 0o700);
@@ -14,6 +16,15 @@ export function ensureUserDir(directory) {
14
16
  chmodSync(directory, 0o755);
15
17
  }
16
18
  }
19
+ /** The batch form of ensureUserDir: the same mode law for a whole directory
20
+ * skeleton, created ahead of the files it will hold and off the event loop. */
21
+ export async function ensureUserDirs(directories, concurrency) {
22
+ await boundedForEach(directories, concurrency, async (directory) => {
23
+ if (await mkdir(directory, { recursive: true, mode: 0o755 }) !== undefined) {
24
+ await chmod(directory, 0o755);
25
+ }
26
+ });
27
+ }
17
28
  /** File helpers own the file, never the parent's mode: an absent parent is
18
29
  * created private, an existing one — private or user-visible — keeps its
19
30
  * mode. */
@@ -1 +1 @@
1
- {"version":3,"file":"filesystem.js","sourceRoot":"","sources":["../src/filesystem.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"filesystem.js","sourceRoot":"","sources":["../src/filesystem.ts"],"names":[],"mappings":"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"}
@@ -26,3 +26,21 @@ export declare class TransferLegs {
26
26
  private enter;
27
27
  private exit;
28
28
  }
29
+ /** Partition one concurrent phase by three named activities. Counts preserve
30
+ * a bit until the last operation of that kind settles; the eight reported
31
+ * states therefore sum to wall time instead of double-counting overlap. */
32
+ export declare class ConcurrentActivityClock<Activity extends string> {
33
+ private readonly activities;
34
+ private readonly counts;
35
+ private readonly totals;
36
+ private state;
37
+ private changedAt;
38
+ constructor(activities: readonly [Activity, Activity, Activity]);
39
+ time<T>(activity: Activity, work: () => Promise<T>): Promise<T>;
40
+ timeSync<T>(activity: Activity, work: () => T): T;
41
+ /** Prefix + active activity names form stable ledger keys. */
42
+ report(prefix: string): Record<string, number>;
43
+ private index;
44
+ private transition;
45
+ private record;
46
+ }
@@ -65,4 +65,74 @@ export class TransferLegs {
65
65
  this.quietSince = now;
66
66
  }
67
67
  }
68
+ /** Partition one concurrent phase by three named activities. Counts preserve
69
+ * a bit until the last operation of that kind settles; the eight reported
70
+ * states therefore sum to wall time instead of double-counting overlap. */
71
+ export class ConcurrentActivityClock {
72
+ activities;
73
+ counts = [0, 0, 0];
74
+ totals = Array.from({ length: 8 }, () => 0);
75
+ state = 0;
76
+ changedAt = performance.now();
77
+ constructor(activities) {
78
+ this.activities = activities;
79
+ if (activities.some((activity) => activity.length === 0)
80
+ || new Set(activities).size !== activities.length) {
81
+ throw new Error("concurrent activity names must be distinct");
82
+ }
83
+ }
84
+ async time(activity, work) {
85
+ const index = this.index(activity);
86
+ this.transition(index, 1);
87
+ try {
88
+ return await work();
89
+ }
90
+ finally {
91
+ this.transition(index, -1);
92
+ }
93
+ }
94
+ timeSync(activity, work) {
95
+ const index = this.index(activity);
96
+ this.transition(index, 1);
97
+ try {
98
+ return work();
99
+ }
100
+ finally {
101
+ this.transition(index, -1);
102
+ }
103
+ }
104
+ /** Prefix + active activity names form stable ledger keys. */
105
+ report(prefix) {
106
+ if (!prefix)
107
+ throw new Error("concurrent activity report needs a prefix");
108
+ this.record(performance.now());
109
+ const key = (state) => {
110
+ if (state === 0)
111
+ return `${prefix}NeitherMs`;
112
+ const names = this.activities.filter((_activity, index) => (state & (1 << index)) !== 0);
113
+ const suffix = names.length === 1 ? "Only" : "";
114
+ return `${prefix}${names.map((name) => name.charAt(0).toUpperCase() + name.slice(1)).join("")}${suffix}Ms`;
115
+ };
116
+ return Object.fromEntries(this.totals.map((duration, state) => [key(state), Math.round(duration)]));
117
+ }
118
+ index(activity) {
119
+ const index = this.activities.indexOf(activity);
120
+ if (index < 0)
121
+ throw new Error(`unknown concurrent activity ${activity}`);
122
+ return index;
123
+ }
124
+ transition(index, delta) {
125
+ const now = performance.now();
126
+ this.record(now);
127
+ const next = (this.counts[index] ?? 0) + delta;
128
+ if (next < 0)
129
+ throw new Error("concurrent activity clock lost an operation");
130
+ this.counts[index] = next;
131
+ this.state = this.counts.reduce((mask, count, bit) => count > 0 ? mask | (1 << bit) : mask, 0);
132
+ }
133
+ record(now) {
134
+ this.totals[this.state] = (this.totals[this.state] ?? 0) + (now - this.changedAt);
135
+ this.changedAt = now;
136
+ }
137
+ }
68
138
  //# sourceMappingURL=transfer-instrumentation.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"transfer-instrumentation.js","sourceRoot":"","sources":["../src/transfer-instrumentation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,MAAM,OAAO,YAAY;IACN,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC5C,QAAQ,GAAG,CAAC,CAAC;IACb,UAAU,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;IAC/B,MAAM,GAAG,CAAC,CAAC;IAEnB;2EACuE;IACvE,GAAG,CAAC,GAAW,EAAE,EAAU;QACzB,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC;YAAE,OAAO;QAC5C,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;IACzD,CAAC;IAED,KAAK,CAAC,IAAI,CAAI,GAAW,EAAE,IAAsB;QAC/C,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;QAC/B,IAAI,CAAC;YACH,OAAO,MAAM,IAAI,EAAE,CAAC;QACtB,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;IAED,QAAQ,CAAI,GAAW,EAAE,IAAa;QACpC,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;QAC/B,IAAI,CAAC;YACH,OAAO,IAAI,EAAE,CAAC;QAChB,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;IAED;yCACqC;IACrC,MAAM;QACJ,MAAM,GAAG,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QAC9B,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;QACrE,OAAO;YACL,GAAG,MAAM,CAAC,WAAW,CACnB,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAC3D;YACD,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,YAAY,CAAC;SAC/C,CAAC;IACJ,CAAC;IAEO,KAAK;QACX,MAAM,GAAG,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QAC9B,IAAI,IAAI,CAAC,QAAQ,KAAK,CAAC;YAAE,IAAI,CAAC,MAAM,IAAI,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC;QAC9D,IAAI,CAAC,QAAQ,IAAI,CAAC,CAAC;QACnB,OAAO,GAAG,CAAC;IACb,CAAC;IAEO,IAAI,CAAC,GAAW,EAAE,SAAiB;QACzC,MAAM,GAAG,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QAC9B,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,GAAG,SAAS,CAAC,CAAC;QAC/B,IAAI,CAAC,QAAQ,IAAI,CAAC,CAAC;QACnB,IAAI,IAAI,CAAC,QAAQ,KAAK,CAAC;YAAE,IAAI,CAAC,UAAU,GAAG,GAAG,CAAC;IACjD,CAAC;CACF"}
1
+ {"version":3,"file":"transfer-instrumentation.js","sourceRoot":"","sources":["../src/transfer-instrumentation.ts"],"names":[],"mappings":"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"}
@@ -14,6 +14,7 @@ import { indexRowsByOutermostRoot } from "./ground-root-index.js";
14
14
  import { ContentCacheDownloadSet, captureContentFile, contentBlockCollector, hasSealedContent, hashContentFile, pruneSettledContentCache, sealCapturedArtifact, } from "./content-cache-host.js";
15
15
  import { RegisterUploadFusion } from "./register-upload-fusion.js";
16
16
  import { StagedContentSet, addStagingEvidenceDir, clearAddStagingEvidence, } from "./workspace-add-staging.js";
17
+ import { boundedForEach } from "./bounded-for-each.js";
17
18
  import { DirectContentPlane } from "./content-direct.js";
18
19
  import { encodeContentWireBytes } from "./content-wire-codec.js";
19
20
  import { TransferLegs } from "./transfer-instrumentation.js";
@@ -400,7 +401,7 @@ export class UserGroundHost {
400
401
  });
401
402
  }
402
403
  },
403
- onStage: async (stage) => {
404
+ onStage: async (stage, measurements) => {
404
405
  const now = performance.now();
405
406
  this.stage({
406
407
  primitive: stage === "watching" ? "watch" : "download",
@@ -408,6 +409,7 @@ export class UserGroundHost {
408
409
  status: "completed",
409
410
  workspaceId: input.workspace.uuid,
410
411
  durationMs: now - milestoneAt,
412
+ ...(measurements ? { measurements } : {}),
411
413
  });
412
414
  milestoneAt = now;
413
415
  await this.options.onWorkspaceAddStage?.({
@@ -1870,7 +1872,7 @@ export class UserGroundHost {
1870
1872
  },
1871
1873
  });
1872
1874
  const downloads = new ContentCacheDownloadSet(cacheDir);
1873
- const stagedSet = staged ? new StagedContentSet(staged.evidenceDir) : null;
1875
+ let stagedSet = null;
1874
1876
  const targets = new Map();
1875
1877
  const target = (artifact) => {
1876
1878
  const found = targets.get(artifact.contentHash);
@@ -1883,16 +1885,22 @@ export class UserGroundHost {
1883
1885
  // which stays on the cache rail so a warm re-Add remains a local
1884
1886
  // clone instead of a fresh download.
1885
1887
  const route = (artifact, manifest) => {
1886
- const stagedPaths = stagedSet && staged?.destinations.get(artifact.contentHash);
1887
- if (stagedPaths && !hasSealedContent(cacheDir, artifact.contentHash, manifest.bytes)) {
1888
+ const set = stagedSet;
1889
+ const stagedPaths = set && staged?.destinations.get(artifact.contentHash);
1890
+ if (set && stagedPaths && !hasSealedContent(cacheDir, artifact.contentHash, manifest.bytes)) {
1888
1891
  stagedArtifacts += 1;
1889
- targets.set(artifact.contentHash, stagedSet.target(artifact, manifest, stagedPaths));
1892
+ targets.set(artifact.contentHash, set.target(artifact, manifest, stagedPaths));
1890
1893
  }
1891
1894
  else {
1892
1895
  targets.set(artifact.contentHash, downloads.target(artifact, manifest));
1893
1896
  }
1894
1897
  };
1895
1898
  try {
1899
+ // The staged rail's directory skeleton is the set's first act, so no
1900
+ // chunk's store path includes a mkdir.
1901
+ stagedSet = staged
1902
+ ? await StagedContentSet.open(staged.evidenceDir, staged.destinations)
1903
+ : null;
1896
1904
  // Every storage object — manifests and blocks alike — is fetched
1897
1905
  // straight from content storage over a presigned URL and opened
1898
1906
  // locally; the engine plans whole waves against these primitives, so
@@ -1983,9 +1991,9 @@ export class UserGroundHost {
1983
1991
  // plan (manifest cache + routing), fetch (storage waits, whose
1984
1992
  // decrypt share the plane delta names), hash (chunk verification),
1985
1993
  // reuse (retained-chunk re-proof), write (chunk placement), seal
1986
- // (whole-file proof + durability), and idle — wall time with
1987
- // nothing in flight. The staged rail decomposes its own write and
1988
- // seal internals below; `stagedArtifacts` counts its placements.
1994
+ // (whole-file proof assertion + duplicates), and idle — wall time
1995
+ // with nothing in flight. The staged rail decomposes its own
1996
+ // placement legs below; `stagedArtifacts` counts its placements.
1989
1997
  requests,
1990
1998
  // The engine's own geometry: how manifests were known (local vs
1991
1999
  // fetched, packed vs standalone) and how many planned pack spans
@@ -5726,9 +5734,11 @@ async function materializeRecords(input) {
5726
5734
  for (const list of stagedDestinations.values())
5727
5735
  list.sort();
5728
5736
  }
5737
+ const contentStarted = performance.now();
5729
5738
  const fileContent = await readContent([...wanted.values()], staged && stagedDestinations
5730
5739
  ? { evidenceDir: staged.evidenceDir, destinations: stagedDestinations }
5731
5740
  : undefined);
5741
+ const chainStarted = performance.now();
5732
5742
  const repositoryChains = new Map();
5733
5743
  const walking = repositoryHeads.map(({ record, artifact }) => {
5734
5744
  const local = fileContent.get(artifact.contentHash);
@@ -5773,11 +5783,15 @@ async function materializeRecords(input) {
5773
5783
  walk.parent = inspectRepositoryTransportFile(parent.file).parentTransportVersion;
5774
5784
  }
5775
5785
  }
5786
+ const walkStarted = performance.now();
5787
+ let repositoriesMs = 0;
5776
5788
  const materializeRepository = async (record, destination) => {
5777
5789
  const chain = repositoryChains.get(record.uuid);
5778
5790
  if (!chain)
5779
5791
  throw new Error(`cloud repository ${record.uuid} transport was not downloaded`);
5792
+ const started = performance.now();
5780
5793
  const applied = await applyRepositoryFiles(destination, chain);
5794
+ repositoriesMs += performance.now() - started;
5781
5795
  const repository = { record, state: applied };
5782
5796
  repositories.push(repository);
5783
5797
  repositoriesByUuid.set(record.uuid, repository);
@@ -5931,6 +5945,7 @@ async function materializeRecords(input) {
5931
5945
  throw new Error(`materialization for ${record.type} requires its dedicated adapter`);
5932
5946
  }
5933
5947
  }
5948
+ const rowsStarted = performance.now();
5934
5949
  const rows = records.map((record) => {
5935
5950
  const relativePath = paths.get(record.uuid);
5936
5951
  const absolutePath = relativePath ? join(rootPath, ...relativePath.split("/")) : rootPath;
@@ -5944,7 +5959,18 @@ async function materializeRecords(input) {
5944
5959
  ...statFingerprint(stats),
5945
5960
  };
5946
5961
  });
5947
- return { rows, repositories };
5962
+ const finished = performance.now();
5963
+ return {
5964
+ rows,
5965
+ repositories,
5966
+ timing: {
5967
+ contentMs: Math.round(chainStarted - contentStarted),
5968
+ transportChainMs: Math.round(walkStarted - chainStarted),
5969
+ repositoriesMs: Math.round(repositoriesMs),
5970
+ groundWalkMs: Math.round(rowsStarted - walkStarted - repositoriesMs),
5971
+ rowsMs: Math.round(finished - rowsStarted),
5972
+ },
5973
+ };
5948
5974
  }
5949
5975
  /** Refresh the always-materialized portable reference inventory selected by
5950
5976
  * Live. Paths and bindings are local; UUIDs, parents, names, and versions are
@@ -6193,6 +6219,7 @@ async function installCloudWorkspace(input) {
6193
6219
  staged: { evidenceDir: addStagingEvidenceDir(database, intent.workspaceId) },
6194
6220
  readContent,
6195
6221
  });
6222
+ const graphStarted = performance.now();
6196
6223
  const rows = projectMaterializedGraph(materialized.rows, materialized.repositories.map((repository) => ({
6197
6224
  record: repository.record,
6198
6225
  identity: repository.state.identity,
@@ -6202,7 +6229,13 @@ async function installCloudWorkspace(input) {
6202
6229
  ? join(intent.destinationPath, ...row.relativePath.split("/"))
6203
6230
  : intent.destinationPath,
6204
6231
  }));
6205
- await onStage?.("materialization-verified");
6232
+ // The milestone's duration spans the whole materialization; its legs say
6233
+ // where that wall time went after the content set itself.
6234
+ await onStage?.("materialization-verified", {
6235
+ ...materialized.timing,
6236
+ graphMs: Math.round(performance.now() - graphStarted),
6237
+ repositories: materialized.repositories.length,
6238
+ });
6206
6239
  persistRows(database, identity, intent.resourceId, intent.workspaceId, rows);
6207
6240
  input.adoptMaterialization(intent.workspaceId);
6208
6241
  await onStage?.("rows-committed");
@@ -6292,26 +6325,6 @@ async function retryContent(operation, eventualNotFound = false, attempts = 10)
6292
6325
  }
6293
6326
  throw last;
6294
6327
  }
6295
- async function boundedForEach(items, concurrency, perform) {
6296
- let next = 0;
6297
- let stopped = false;
6298
- const worker = async () => {
6299
- while (!stopped) {
6300
- const index = next;
6301
- next += 1;
6302
- if (index >= items.length)
6303
- return;
6304
- try {
6305
- await perform(items[index]);
6306
- }
6307
- catch (error) {
6308
- stopped = true;
6309
- throw error;
6310
- }
6311
- }
6312
- };
6313
- await Promise.all(Array.from({ length: Math.min(concurrency, items.length) }, () => worker()));
6314
- }
6315
6328
  /** Admit queued async tasks with at most `limit` in flight. Scheduling never
6316
6329
  * blocks the caller; each task's settlement is its returned promise. The
6317
6330
  * admitted task re-checks the bound because a released slot may be claimed