@assethub/cli 0.1.6 → 0.1.8

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.
Files changed (47) hide show
  1. package/README.md +289 -5
  2. package/dist/canvas.d.ts +27 -0
  3. package/dist/canvas.d.ts.map +1 -0
  4. package/dist/canvas.js +82 -0
  5. package/dist/canvasAssetImport.d.ts +45 -0
  6. package/dist/canvasAssetImport.d.ts.map +1 -0
  7. package/dist/canvasAssetImport.js +154 -0
  8. package/dist/canvasComparison.d.ts +21 -0
  9. package/dist/canvasComparison.d.ts.map +1 -0
  10. package/dist/canvasComparison.js +58 -0
  11. package/dist/execution.d.ts +175 -0
  12. package/dist/execution.d.ts.map +1 -0
  13. package/dist/execution.js +234 -0
  14. package/dist/index.d.ts +94 -0
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +1567 -189
  17. package/dist/projectSources.d.ts +65 -0
  18. package/dist/projectSources.d.ts.map +1 -0
  19. package/dist/projectSources.js +369 -0
  20. package/dist/projectSourcesWorkbook.d.ts +3 -0
  21. package/dist/projectSourcesWorkbook.d.ts.map +1 -0
  22. package/dist/projectSourcesWorkbook.js +143 -0
  23. package/dist/runsUpload/artifactGraphModel.d.ts +48 -0
  24. package/dist/runsUpload/artifactGraphModel.d.ts.map +1 -0
  25. package/dist/runsUpload/artifactGraphModel.js +127 -0
  26. package/dist/runsUpload/blobRefs.d.ts +13 -0
  27. package/dist/runsUpload/blobRefs.d.ts.map +1 -0
  28. package/dist/runsUpload/blobRefs.js +73 -0
  29. package/dist/runsUpload/buildRunUpload.d.ts +63 -0
  30. package/dist/runsUpload/buildRunUpload.d.ts.map +1 -0
  31. package/dist/runsUpload/buildRunUpload.js +428 -0
  32. package/dist/runsUpload/canonicalJson.d.ts +5 -0
  33. package/dist/runsUpload/canonicalJson.d.ts.map +1 -0
  34. package/dist/runsUpload/canonicalJson.js +108 -0
  35. package/dist/runsUpload/controlEndpoints.d.ts +63 -0
  36. package/dist/runsUpload/controlEndpoints.d.ts.map +1 -0
  37. package/dist/runsUpload/controlEndpoints.js +64 -0
  38. package/dist/runsUpload/graphFolder.d.ts +25 -0
  39. package/dist/runsUpload/graphFolder.d.ts.map +1 -0
  40. package/dist/runsUpload/graphFolder.js +147 -0
  41. package/dist/runsUpload/runUploadError.d.ts +23 -0
  42. package/dist/runsUpload/runUploadError.d.ts.map +1 -0
  43. package/dist/runsUpload/runUploadError.js +24 -0
  44. package/dist/runsUpload/uploadRun.d.ts +43 -0
  45. package/dist/runsUpload/uploadRun.d.ts.map +1 -0
  46. package/dist/runsUpload/uploadRun.js +217 -0
  47. package/package.json +11 -5
@@ -0,0 +1,127 @@
1
+ // The `ag.commit.v1` artifact model plus the canonical normalize + hash that
2
+ // every ag.graph-folder.v1 reader recomputes.
3
+ //
4
+ // Line-faithful port of assethub-ml research/artifact-graph/artifact-graph-py/
5
+ // artifact_graph/graph/commit_reducer.py (`_normalize_tags`,
6
+ // `_canonical_value_copy`, `_normalize_artifact`, `_normalize_edge`,
7
+ // `normalize_graph_state`, `canonical_graph_hash`), taken from the identical
8
+ // port already shipping in
9
+ // apps/frontend/src/feature/artifactGraph/export/artifactGraphModel.ts.
10
+ //
11
+ // Do not "improve" ordering/trimming/defaults: byte parity with the Python
12
+ // normalize output is what makes a locally computed graphHash verifiable by the
13
+ // server that receives it.
14
+ import { canonicalJson, isPlainObject, sha256Hex } from './canonicalJson.js';
15
+ export { canonicalJson, isPlainObject, sha256Hex } from './canonicalJson.js';
16
+ const stringOrNull = (value) => typeof value === 'string' && value.length > 0 ? value : null;
17
+ /** Port of `_normalize_tags`: stringify+trim, drop empties, dedupe, sort
18
+ * (code-point order — Python `sorted`, NOT localeCompare). */
19
+ const normalizeTags = (value) => {
20
+ const raw = Array.isArray(value) ? value : [];
21
+ const seen = new Set();
22
+ for (const item of raw) {
23
+ const tag = String(item ?? '').trim();
24
+ if (tag)
25
+ seen.add(tag);
26
+ }
27
+ return [...seen].sort(codePointCompare);
28
+ };
29
+ export const codePointCompare = (a, b) => (a < b ? -1 : a > b ? 1 : 0);
30
+ /** Port of `_canonical_value_copy`: deep-copy JSON-shaped values. The Python
31
+ * side also coerces integral floats to ints here; JSON.parse already
32
+ * collapses 1.0 to 1 in JS, and canonicalJson renders integral doubles as
33
+ * plain digits, so a plain structural copy is the faithful equivalent. */
34
+ const canonicalValueCopy = (value) => {
35
+ if (Array.isArray(value))
36
+ return value.map(canonicalValueCopy);
37
+ if (isPlainObject(value)) {
38
+ const out = {};
39
+ for (const [key, item] of Object.entries(value)) {
40
+ if (item === undefined || typeof item === 'function' || typeof item === 'symbol')
41
+ continue;
42
+ out[key] = canonicalValueCopy(item);
43
+ }
44
+ return out;
45
+ }
46
+ return value;
47
+ };
48
+ /** Port of `_normalize_artifact`: returns null for anything that is not a
49
+ * valid `ag.commit.v1` artifact; keeps only the schema's fields. */
50
+ export const normalizeArtifact = (value) => {
51
+ if (!isPlainObject(value))
52
+ return null;
53
+ const id = stringOrNull(value.id);
54
+ const artifactKind = stringOrNull(value.artifactKind);
55
+ if (!id || !artifactKind || !isPlainObject(value.metadata))
56
+ return null;
57
+ const out = {
58
+ id,
59
+ artifactKind,
60
+ tags: normalizeTags(value.tags),
61
+ metadata: canonicalValueCopy(value.metadata),
62
+ };
63
+ assignOptionalString(out, 'semanticType', value.semanticType);
64
+ assignOptionalString(out, 'lifecycle', value.lifecycle);
65
+ if (isPlainObject(value.payload)) {
66
+ out.payload = canonicalValueCopy(value.payload);
67
+ }
68
+ assignOptionalString(out, 'schemaRef', value.schemaRef);
69
+ assignOptionalString(out, 'createdBy', value.createdBy);
70
+ assignOptionalString(out, 'createdAt', value.createdAt);
71
+ assignOptionalString(out, 'updatedAt', value.updatedAt);
72
+ return out;
73
+ };
74
+ /** Port of `_normalize_edge`. */
75
+ export const normalizeEdge = (value) => {
76
+ if (!isPlainObject(value))
77
+ return null;
78
+ const id = stringOrNull(value.id);
79
+ const from = stringOrNull(value.from);
80
+ const to = stringOrNull(value.to);
81
+ if (!id || !from || !to)
82
+ return null;
83
+ const out = {
84
+ id,
85
+ from,
86
+ to,
87
+ kind: stringOrNull(value.kind) ?? 'uses',
88
+ tags: normalizeTags(value.tags),
89
+ metadata: isPlainObject(value.metadata)
90
+ ? canonicalValueCopy(value.metadata)
91
+ : {},
92
+ };
93
+ assignOptionalString(out, 'createdBy', value.createdBy);
94
+ return out;
95
+ };
96
+ const assignOptionalString = (target, key, value) => {
97
+ const normalized = stringOrNull(value);
98
+ if (normalized)
99
+ target[key] = normalized;
100
+ };
101
+ /** Port of `normalize_graph_state`: dedupe by id (last wins), drop edges with
102
+ * missing endpoints, sort both arrays by id (code-point order). Idempotent —
103
+ * a reader normalizes our JSONL lines and must get them back byte-identical,
104
+ * or the manifest hash won't verify. */
105
+ export const normalizeArtifactGraph = (value) => {
106
+ const nodesById = new Map();
107
+ const edgesById = new Map();
108
+ for (const raw of Array.isArray(value?.nodes) ? value.nodes : []) {
109
+ const node = normalizeArtifact(raw);
110
+ if (node)
111
+ nodesById.set(node.id, node);
112
+ }
113
+ for (const raw of Array.isArray(value?.edges) ? value.edges : []) {
114
+ const edge = normalizeEdge(raw);
115
+ if (edge && nodesById.has(edge.from) && nodesById.has(edge.to)) {
116
+ edgesById.set(edge.id, edge);
117
+ }
118
+ }
119
+ return {
120
+ nodes: [...nodesById.keys()].sort(codePointCompare).map(key => nodesById.get(key)),
121
+ edges: [...edgesById.keys()].sort(codePointCompare).map(key => edgesById.get(key)),
122
+ };
123
+ };
124
+ /** Port of `canonical_graph_hash` — callers pass normalizeArtifactGraph output. */
125
+ export const canonicalGraphHash = (graph) => `sha256:${sha256Hex(canonicalJson(graph))}`;
126
+ /** Port of `canonical_json_line` (graph_folder/format.py) — one JSONL line. */
127
+ export const canonicalJsonLine = (value) => canonicalJson(value);
@@ -0,0 +1,13 @@
1
+ import { type ArtifactGraph } from './artifactGraphModel.js';
2
+ export type ReachableBlobRef = {
3
+ key: string;
4
+ blobKey: string;
5
+ artifactId?: string;
6
+ mime?: string;
7
+ name?: string;
8
+ sha256?: string;
9
+ size?: number;
10
+ };
11
+ /** Port of `reachable_blob_refs`. */
12
+ export declare const reachableBlobRefs: (graph: ArtifactGraph) => ReachableBlobRef[];
13
+ //# sourceMappingURL=blobRefs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blobRefs.d.ts","sourceRoot":"","sources":["../../src/runsUpload/blobRefs.ts"],"names":[],"mappings":"AAYA,OAAO,EAAmB,KAAK,aAAa,EAAC,MAAM,yBAAyB,CAAA;AAG5E,MAAM,MAAM,gBAAgB,GAAG;IAC7B,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;CACd,CAAA;AAED,qCAAqC;AACrC,eAAO,MAAM,iBAAiB,GAAI,OAAO,aAAa,KAAG,gBAAgB,EAMxE,CAAA"}
@@ -0,0 +1,73 @@
1
+ // Port of assethub-ml research/artifact-graph/artifact-graph-py/
2
+ // artifact_graph/graph/blob_refs.py — the walk that decides which blobs a graph
3
+ // can reach. The registry compares its own walk's output against the blobs a
4
+ // snapshot declares, so the qualification rules, the dedupe (first wins) and
5
+ // the sort-by-key order all have to stay identical.
6
+ //
7
+ // Taken from the identical port in
8
+ // apps/frontend/src/feature/artifactGraph/export/blobRefs.ts. Only
9
+ // `reachableBlobRefs` is carried over: the CLI reads a folder whose blobs are
10
+ // already content-addressed, so it never needs `mapBlobRefs` (the re-keying
11
+ // path the web publisher uses).
12
+ import { codePointCompare } from './artifactGraphModel.js';
13
+ import { isPlainObject } from './canonicalJson.js';
14
+ /** Port of `reachable_blob_refs`. */
15
+ export const reachableBlobRefs = (graph) => {
16
+ const byKey = new Map();
17
+ for (const node of graph.nodes ?? []) {
18
+ collectBlobRefs(node, byKey, typeof node?.id === 'string' ? node.id : '');
19
+ }
20
+ return [...byKey.keys()].sort(codePointCompare).map(key => byKey.get(key));
21
+ };
22
+ /** Port of `collect_blob_refs` — recursive walk; explicit `blobRef` fields and
23
+ * direct `{key|blobKey, ...}` dicts both qualify. */
24
+ const collectBlobRefs = (value, byKey, artifactId) => {
25
+ if (Array.isArray(value)) {
26
+ for (const item of value)
27
+ collectBlobRefs(item, byKey, artifactId);
28
+ return;
29
+ }
30
+ if (!isPlainObject(value))
31
+ return;
32
+ const explicitRef = reportBlobRef(value.blobRef, artifactId, true);
33
+ if (explicitRef && !byKey.has(explicitRef.key))
34
+ byKey.set(explicitRef.key, explicitRef);
35
+ const directRef = reportBlobRef(value, artifactId, false);
36
+ if (directRef && !byKey.has(directRef.key))
37
+ byKey.set(directRef.key, directRef);
38
+ for (const item of Object.values(value))
39
+ collectBlobRefs(item, byKey, artifactId);
40
+ };
41
+ /** Port of `report_blob_ref`. A non-explicit dict qualifies only when it has a
42
+ * `blobKey` field or one of mime/size/sha256 alongside `key` — a bare id-ish
43
+ * `key` alone is not a blob ref. */
44
+ const reportBlobRef = (value, artifactId, explicit) => {
45
+ if (!isPlainObject(value))
46
+ return null;
47
+ const key = String((typeof value.key === 'string' && value.key) ||
48
+ (typeof value.blobKey === 'string' && value.blobKey) ||
49
+ '').trim();
50
+ if (!key)
51
+ return null;
52
+ if (!explicit &&
53
+ !('blobKey' in value) &&
54
+ !('mime' in value) &&
55
+ !('size' in value) &&
56
+ !('sha256' in value)) {
57
+ return null;
58
+ }
59
+ const out = { key, blobKey: key };
60
+ if (artifactId)
61
+ out.artifactId = artifactId;
62
+ for (const field of ['mime', 'name', 'sha256']) {
63
+ const item = value[field];
64
+ if (item)
65
+ out[field] = String(item);
66
+ }
67
+ if (value.size !== null && value.size !== undefined) {
68
+ const size = Number(value.size);
69
+ if (Number.isFinite(size))
70
+ out.size = Math.trunc(size);
71
+ }
72
+ return out;
73
+ };
@@ -0,0 +1,63 @@
1
+ import { type GraphFolder } from './graphFolder.js';
2
+ export declare const PUSH_SCHEMA_VERSION = "ag.registry-push.v1";
3
+ export declare const SNAPSHOT_SCHEMA_VERSION = "ag.registry-snapshot.v1";
4
+ export declare const GRAPH_FOLDER_SCHEMA_VERSION = "ag.graph-folder.v1";
5
+ export declare const SHARED_BLOB_STORE = "shared-content-addressed";
6
+ export declare const DEFAULT_GENERATOR = "assethub-cli:runs.upload";
7
+ /** A blob the uploader has to send, with the on-disk file that holds its bytes. */
8
+ export type PlannedBlob = {
9
+ blobKey: string;
10
+ sha256: string;
11
+ mime: string;
12
+ name: string;
13
+ size: number;
14
+ /** Path inside the run folder. Never travels to the server. */
15
+ file: string;
16
+ };
17
+ export type RunUploadPlan = {
18
+ graphId: string;
19
+ streamId: string;
20
+ rev: number;
21
+ graphHash: string;
22
+ /** The `ag.registry-push.v1` document. */
23
+ push: Record<string, unknown>;
24
+ /** Pre-serialized request body, so the transport never re-stringifies it. */
25
+ pushBody: string;
26
+ blobs: PlannedBlob[];
27
+ counts: {
28
+ nodes: number;
29
+ edges: number;
30
+ blobs: number;
31
+ blobBytes: number;
32
+ };
33
+ sizes: {
34
+ manifestBytes: number;
35
+ nodesBytes: number;
36
+ edgesBytes: number;
37
+ pushBytes: number;
38
+ };
39
+ /** Registration payload for the graph, derived from the folder's manifest. */
40
+ registration: {
41
+ graphId: string;
42
+ description: string;
43
+ tags: string[];
44
+ metadata: Record<string, unknown>;
45
+ };
46
+ /** Non-fatal observations worth printing before an upload. */
47
+ warnings: string[];
48
+ };
49
+ export type BuildRunUploadPlanInput = {
50
+ folder: GraphFolder;
51
+ graphId?: string;
52
+ streamId?: string;
53
+ rev?: number;
54
+ description?: string;
55
+ tags?: string[];
56
+ now?: Date;
57
+ };
58
+ export declare const buildRunUploadPlan: ({ folder, graphId: graphIdInput, streamId: streamIdInput, rev: revInput, description, tags, now, }: BuildRunUploadPlanInput) => Promise<RunUploadPlan>;
59
+ /** `import_` rather than `graph_`: a local run folder is an import, not a graph
60
+ * this deployment owns the authority for. */
61
+ export declare const defaultGraphId: (folderName: string) => string;
62
+ export declare const formatBytes: (bytes: number) => string;
63
+ //# sourceMappingURL=buildRunUpload.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buildRunUpload.d.ts","sourceRoot":"","sources":["../../src/runsUpload/buildRunUpload.ts"],"names":[],"mappings":"AAiCA,OAAO,EAA4B,KAAK,WAAW,EAAC,MAAM,kBAAkB,CAAA;AAG5E,eAAO,MAAM,mBAAmB,wBAAwB,CAAA;AACxD,eAAO,MAAM,uBAAuB,4BAA4B,CAAA;AAChE,eAAO,MAAM,2BAA2B,uBAAuB,CAAA;AAC/D,eAAO,MAAM,iBAAiB,6BAA6B,CAAA;AAC3D,eAAO,MAAM,iBAAiB,6BAA6B,CAAA;AA0B3D,mFAAmF;AACnF,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,+DAA+D;IAC/D,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;IAChB,GAAG,EAAE,MAAM,CAAA;IACX,SAAS,EAAE,MAAM,CAAA;IACjB,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC7B,6EAA6E;IAC7E,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,WAAW,EAAE,CAAA;IACpB,MAAM,EAAE;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAC,CAAA;IACxE,KAAK,EAAE;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAC,CAAA;IACzF,8EAA8E;IAC9E,YAAY,EAAE;QACZ,OAAO,EAAE,MAAM,CAAA;QACf,WAAW,EAAE,MAAM,CAAA;QACnB,IAAI,EAAE,MAAM,EAAE,CAAA;QACd,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAClC,CAAA;IACD,8DAA8D;IAC9D,QAAQ,EAAE,MAAM,EAAE,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,uBAAuB,GAAG;IACpC,MAAM,EAAE,WAAW,CAAA;IACnB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;IACf,GAAG,CAAC,EAAE,IAAI,CAAA;CACX,CAAA;AAED,eAAO,MAAM,kBAAkB,GAAU,oGAQtC,uBAAuB,KAAG,OAAO,CAAC,aAAa,CA6JjD,CAAA;AAMD;8CAC8C;AAC9C,eAAO,MAAM,cAAc,GAAI,YAAY,MAAM,KAAG,MAanD,CAAA;AA0VD,eAAO,MAAM,WAAW,GAAI,OAAO,MAAM,KAAG,MAI3C,CAAA"}