@procedures/lib 0.0.0-stage → 0.1.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.
Files changed (114) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/LICENSE +21 -0
  3. package/README.md +119 -2
  4. package/dist/.tsbuildinfo +1 -0
  5. package/dist/cli-flags.d.ts +27 -0
  6. package/dist/cli-flags.d.ts.map +1 -0
  7. package/dist/cli-flags.js +33 -0
  8. package/dist/cli-flags.js.map +1 -0
  9. package/dist/dag/builder.d.ts +18 -0
  10. package/dist/dag/builder.d.ts.map +1 -0
  11. package/dist/dag/builder.js +35 -0
  12. package/dist/dag/builder.js.map +1 -0
  13. package/dist/dag/index.d.ts +12 -0
  14. package/dist/dag/index.d.ts.map +1 -0
  15. package/dist/dag/index.js +12 -0
  16. package/dist/dag/index.js.map +1 -0
  17. package/dist/git/index.d.ts +5 -0
  18. package/dist/git/index.d.ts.map +1 -0
  19. package/dist/git/index.js +5 -0
  20. package/dist/git/index.js.map +1 -0
  21. package/dist/git/ref-parser.d.ts +34 -0
  22. package/dist/git/ref-parser.d.ts.map +1 -0
  23. package/dist/git/ref-parser.js +70 -0
  24. package/dist/git/ref-parser.js.map +1 -0
  25. package/dist/index.d.ts +14 -0
  26. package/dist/index.d.ts.map +1 -0
  27. package/dist/index.js +20 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/module.d.ts +16 -0
  30. package/dist/module.d.ts.map +1 -0
  31. package/dist/module.js +156 -0
  32. package/dist/module.js.map +1 -0
  33. package/dist/procedures/core/catch.d.ts +33 -0
  34. package/dist/procedures/core/catch.d.ts.map +1 -0
  35. package/dist/procedures/core/catch.js +118 -0
  36. package/dist/procedures/core/catch.js.map +1 -0
  37. package/dist/procedures/core/index.d.ts +9 -0
  38. package/dist/procedures/core/index.d.ts.map +1 -0
  39. package/dist/procedures/core/index.js +8 -0
  40. package/dist/procedures/core/index.js.map +1 -0
  41. package/dist/procedures/dag/index.d.ts +5 -0
  42. package/dist/procedures/dag/index.d.ts.map +1 -0
  43. package/dist/procedures/dag/index.js +5 -0
  44. package/dist/procedures/dag/index.js.map +1 -0
  45. package/dist/procedures/dag/traverse.d.ts +54 -0
  46. package/dist/procedures/dag/traverse.d.ts.map +1 -0
  47. package/dist/procedures/dag/traverse.js +252 -0
  48. package/dist/procedures/dag/traverse.js.map +1 -0
  49. package/dist/procedures/ecosystem/index.d.ts +7 -0
  50. package/dist/procedures/ecosystem/index.d.ts.map +1 -0
  51. package/dist/procedures/ecosystem/index.js +6 -0
  52. package/dist/procedures/ecosystem/index.js.map +1 -0
  53. package/dist/procedures/ecosystem/procedures.d.ts +63 -0
  54. package/dist/procedures/ecosystem/procedures.d.ts.map +1 -0
  55. package/dist/procedures/ecosystem/procedures.js +215 -0
  56. package/dist/procedures/ecosystem/procedures.js.map +1 -0
  57. package/dist/procedures/lib/audit.d.ts +29 -0
  58. package/dist/procedures/lib/audit.d.ts.map +1 -0
  59. package/dist/procedures/lib/audit.js +236 -0
  60. package/dist/procedures/lib/audit.js.map +1 -0
  61. package/dist/procedures/lib/index.d.ts +8 -0
  62. package/dist/procedures/lib/index.d.ts.map +1 -0
  63. package/dist/procedures/lib/index.js +8 -0
  64. package/dist/procedures/lib/index.js.map +1 -0
  65. package/dist/procedures/lib/new.d.ts +18 -0
  66. package/dist/procedures/lib/new.d.ts.map +1 -0
  67. package/dist/procedures/lib/new.js +170 -0
  68. package/dist/procedures/lib/new.js.map +1 -0
  69. package/dist/procedures/lib/rename.d.ts +28 -0
  70. package/dist/procedures/lib/rename.d.ts.map +1 -0
  71. package/dist/procedures/lib/rename.js +267 -0
  72. package/dist/procedures/lib/rename.js.map +1 -0
  73. package/dist/procedures/lib/scan.d.ts +14 -0
  74. package/dist/procedures/lib/scan.d.ts.map +1 -0
  75. package/dist/procedures/lib/scan.js +102 -0
  76. package/dist/procedures/lib/scan.js.map +1 -0
  77. package/dist/register.d.ts +10 -0
  78. package/dist/register.d.ts.map +1 -0
  79. package/dist/register.js +19 -0
  80. package/dist/register.js.map +1 -0
  81. package/dist/scoped-input.d.ts +17 -0
  82. package/dist/scoped-input.d.ts.map +1 -0
  83. package/dist/scoped-input.js +23 -0
  84. package/dist/scoped-input.js.map +1 -0
  85. package/dist/types.d.ts +248 -0
  86. package/dist/types.d.ts.map +1 -0
  87. package/dist/types.js +231 -0
  88. package/dist/types.js.map +1 -0
  89. package/dist/workspace.d.ts +46 -0
  90. package/dist/workspace.d.ts.map +1 -0
  91. package/dist/workspace.js +98 -0
  92. package/dist/workspace.js.map +1 -0
  93. package/package.json +84 -3
  94. package/src/cli-flags.ts +49 -0
  95. package/src/dag/builder.ts +44 -0
  96. package/src/dag/index.ts +23 -0
  97. package/src/git/index.ts +11 -0
  98. package/src/git/ref-parser.ts +83 -0
  99. package/src/index.ts +57 -0
  100. package/src/module.ts +207 -0
  101. package/src/procedures/core/catch.ts +142 -0
  102. package/src/procedures/core/index.ts +9 -0
  103. package/src/procedures/dag/index.ts +5 -0
  104. package/src/procedures/dag/traverse.ts +281 -0
  105. package/src/procedures/ecosystem/index.ts +12 -0
  106. package/src/procedures/ecosystem/procedures.ts +317 -0
  107. package/src/procedures/lib/audit.ts +307 -0
  108. package/src/procedures/lib/index.ts +8 -0
  109. package/src/procedures/lib/new.ts +216 -0
  110. package/src/procedures/lib/rename.ts +355 -0
  111. package/src/procedures/lib/scan.ts +143 -0
  112. package/src/register.ts +23 -0
  113. package/src/types.ts +526 -0
  114. package/src/workspace.ts +110 -0
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Workspace helpers
3
+ *
4
+ * The client packages live in one pnpm workspace (the client monorepo). These helpers
5
+ * find the workspace root and decide which dependencies link two ecosystem packages,
6
+ * so the lib.* procedures work on the monorepo instead of one git repository per package.
7
+ */
8
+ import { existsSync } from "node:fs";
9
+ import { homedir } from "node:os";
10
+ import { dirname, join, resolve } from "node:path";
11
+ import { fileURLToPath } from "node:url";
12
+ import { isMark1Russell7Ref } from "./git/index.js";
13
+ /**
14
+ * Expand a leading `~/` to the home directory
15
+ */
16
+ export function expandHome(p) {
17
+ if (p === "~") {
18
+ return homedir();
19
+ }
20
+ if (p.startsWith("~/") || p.startsWith("~\\")) {
21
+ return join(homedir(), p.slice(2));
22
+ }
23
+ return p;
24
+ }
25
+ /**
26
+ * Find the nearest folder at or above `start` that holds pnpm-workspace.yaml
27
+ */
28
+ export function findWorkspaceRoot(start) {
29
+ let dir = resolve(start);
30
+ for (;;) {
31
+ if (existsSync(join(dir, "pnpm-workspace.yaml"))) {
32
+ return dir;
33
+ }
34
+ const parent = dirname(dir);
35
+ if (parent === dir) {
36
+ return null;
37
+ }
38
+ dir = parent;
39
+ }
40
+ }
41
+ /**
42
+ * Resolve the workspace root for a procedure call: the explicit `rootPath` if given,
43
+ * else the workspace that contains this package.
44
+ */
45
+ export function resolveWorkspaceRoot(rootPath) {
46
+ if (rootPath) {
47
+ // Only a real workspace root: lib.new runs that workspace's cue CLI, and lib.rename rewrites
48
+ // its files, so a rootPath elsewhere ran a script from any folder (deep dive DATA-18)
49
+ const root = resolve(expandHome(rootPath));
50
+ if (!existsSync(join(root, "pnpm-workspace.yaml"))) {
51
+ throw new Error(`Not a workspace root (no pnpm-workspace.yaml): ${root}`);
52
+ }
53
+ return root;
54
+ }
55
+ const own = findWorkspaceRoot(dirname(fileURLToPath(import.meta.url)));
56
+ if (!own) {
57
+ throw new Error("Could not find the workspace root (no pnpm-workspace.yaml above client-lib). Pass rootPath.");
58
+ }
59
+ return own;
60
+ }
61
+ /**
62
+ * The folder that holds the workspace packages
63
+ */
64
+ export function packagesDir(root) {
65
+ return join(root, "packages");
66
+ }
67
+ /**
68
+ * Return true if a dependency spec links to another ecosystem package:
69
+ * a workspace link (`workspace:*`) or a `github:mark1russell7/...` reference.
70
+ */
71
+ export function isEcosystemDependencySpec(spec) {
72
+ return spec.startsWith("workspace:") || isMark1Russell7Ref(spec);
73
+ }
74
+ /**
75
+ * The npm scopes of the ecosystem: `@procedures` for the packages of this workspace, and
76
+ * `@mark1russell7` for the general packages (cue, splay, docker-sqlite and the others).
77
+ */
78
+ export const ECOSYSTEM_SCOPES = ["@procedures/", "@mark1russell7/"];
79
+ /** True for the name of a package of the ecosystem scopes. */
80
+ export function isEcosystemPackageName(name) {
81
+ return ECOSYSTEM_SCOPES.some((scope) => name.startsWith(scope));
82
+ }
83
+ /**
84
+ * Collect the names of the ecosystem packages (`@procedures/*` and `@mark1russell7/*`) that a
85
+ * package.json depends on (dependencies, devDependencies and peerDependencies), without duplicates.
86
+ */
87
+ export function extractEcosystemDeps(pkg) {
88
+ const names = new Set();
89
+ for (const deps of [pkg.dependencies, pkg.devDependencies, pkg.peerDependencies]) {
90
+ for (const [name, spec] of Object.entries(deps ?? {})) {
91
+ if (isEcosystemPackageName(name) && isEcosystemDependencySpec(spec)) {
92
+ names.add(name);
93
+ }
94
+ }
95
+ }
96
+ return [...names];
97
+ }
98
+ //# sourceMappingURL=workspace.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace.js","sourceRoot":"","sources":["../src/workspace.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,87 @@
1
1
  {
2
+ "$schema": "https://json.schemastore.org/package",
2
3
  "name": "@procedures/lib",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
4
+ "version": "0.1.0",
5
+ "description": "Workspace procedures for pnpm monorepos: scan the packages, scaffold a new package, audit packages against a template, rename across the workspace, and program runners.",
6
+ "keywords": [
7
+ "monorepo",
8
+ "pnpm",
9
+ "workspace",
10
+ "scaffold",
11
+ "audit",
12
+ "procedures"
13
+ ],
14
+ "homepage": "https://mark1russell7.github.io/client/",
15
+ "bugs": {
16
+ "url": "https://github.com/mark1russell7/client/issues"
17
+ },
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git+https://github.com/mark1russell7/client.git",
21
+ "directory": "packages/client-lib"
22
+ },
23
+ "license": "MIT",
24
+ "author": "Mark Russell (https://github.com/mark1russell7)",
25
+ "type": "module",
26
+ "main": "./dist/index.js",
27
+ "types": "./dist/index.d.ts",
28
+ "exports": {
29
+ ".": {
30
+ "types": "./dist/index.d.ts",
31
+ "import": "./dist/index.js"
32
+ },
33
+ "./module": {
34
+ "types": "./dist/module.d.ts",
35
+ "import": "./dist/module.js"
36
+ },
37
+ "./cli-flags": {
38
+ "types": "./dist/cli-flags.d.ts",
39
+ "import": "./dist/cli-flags.js"
40
+ }
41
+ },
42
+ "files": [
43
+ "dist",
44
+ "src",
45
+ "!src/**/*.test.ts",
46
+ "!src/**/*.test.tsx",
47
+ "!src/**/__tests__",
48
+ "CHANGELOG.md"
49
+ ],
50
+ "sideEffects": [
51
+ "./dist/index.js",
52
+ "./dist/register.js"
53
+ ],
54
+ "engines": {
55
+ "node": ">=22"
56
+ },
57
+ "publishConfig": {
58
+ "access": "public",
59
+ "provenance": true
60
+ },
61
+ "devDependencies": {
62
+ "typescript": "^7.0.2",
63
+ "@types/node": "^22.0.0",
64
+ "@mark1russell7/cue": "^1.0.0",
65
+ "vitest": "^5.0.3"
66
+ },
67
+ "dependencies": {
68
+ "@procedures/client": "0.1.0",
69
+ "@procedures/dag": "0.1.0",
70
+ "@procedures/fs": "0.1.0",
71
+ "@procedures/git": "0.1.0",
72
+ "@procedures/pnpm": "0.1.0",
73
+ "@procedures/shell": "0.1.0",
74
+ "ts-morph": "^24.0.0",
75
+ "zod": "^4.6.5"
76
+ },
77
+ "client": {
78
+ "procedures": "./dist/register.js"
79
+ },
80
+ "scripts": {
81
+ "build": "tsc -b",
82
+ "typecheck": "tsc --noEmit",
83
+ "clean": "rm -rf dist .tsbuildinfo",
84
+ "test": "vitest run --passWithNoTests",
85
+ "test:watch": "vitest"
86
+ }
6
87
  }
@@ -0,0 +1,49 @@
1
+ /**
2
+ * The global flags of the `mark` CLI.
3
+ *
4
+ * `mark` reads a global flag before the command path. After the path, a flag is global only when
5
+ * the procedure does not declare a flag of that name: `mark docker compose down -v` gives `-v` to
6
+ * the procedure. `lib.audit` reports each procedure flag that hides a global flag in this way.
7
+ *
8
+ * This module has no side effects: `mark` imports it before it loads the procedures.
9
+ */
10
+
11
+ export interface CliGlobalFlag {
12
+ /** The long name, without "--" */
13
+ readonly long: string;
14
+ /** The short letter, without "-" */
15
+ readonly short?: string;
16
+ /** True when the flag takes a value */
17
+ readonly takesValue: boolean;
18
+ /** True when the flag starts a mode (the server or the REPL) and takes no command */
19
+ readonly mode?: boolean;
20
+ /** True when the flag is an option of `--server` */
21
+ readonly serverOption?: boolean;
22
+ /** The help text */
23
+ readonly description: string;
24
+ }
25
+
26
+ export const CLI_GLOBAL_FLAGS: readonly CliGlobalFlag[] = [
27
+ { long: "help", short: "h", takesValue: false, description: "Show the help" },
28
+ { long: "version", short: "v", takesValue: false, description: "Show the version" },
29
+ { long: "verbose", short: "V", takesValue: false, description: "Show more output" },
30
+ { long: "format", short: "f", takesValue: true, description: "The output format: text, json, table or streaming" },
31
+ { long: "local", takesValue: false, description: "Run the command in this process, not on the CLI server" },
32
+ { long: "json", takesValue: true, description: "Run a procedure reference that is given as JSON" },
33
+ { long: "no-input", takesValue: false, description: "Never ask for a missing argument (also when CI is set)" },
34
+ { long: "interactive", short: "i", takesValue: false, mode: true, description: "Start the REPL" },
35
+ { long: "server", takesValue: false, mode: true, description: "Start the CLI server" },
36
+ { long: "port", takesValue: true, serverOption: true, description: "The port of the CLI server (with --server)" },
37
+ { long: "host", takesValue: true, serverOption: true, description: "The host of the CLI server (with --server)" },
38
+ {
39
+ long: "transport",
40
+ takesValue: true,
41
+ serverOption: true,
42
+ description: "The transport of the CLI server: http, websocket or both (with --server)",
43
+ },
44
+ ];
45
+
46
+ /** The global flag with this long name or short letter */
47
+ export function findGlobalFlag(name: string, short: boolean): CliGlobalFlag | undefined {
48
+ return CLI_GLOBAL_FLAGS.find((flag) => (short ? flag.short === name : flag.long === name));
49
+ }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * DAG Builder
3
+ *
4
+ * Builds the ecosystem-specific dependency DAG from package scan results. This is the only
5
+ * domain-specific piece; the generic DAG algorithms (buildLeveledDAG, executeDAG, filterDAGFromRoot,
6
+ * getAncestors, getDescendants, ...) live in @procedures/dag. This package previously
7
+ * vendored a verbatim copy of those — see documentation/BUGS-2026-07.md (DAG de-dup).
8
+ */
9
+
10
+ import type { DAGNode, PackageInfo } from "../types.js";
11
+
12
+ /**
13
+ * Build DAG nodes from package info.
14
+ *
15
+ * Creates nodes only for packages that are mark1russell7 dependencies and exist in the scanned
16
+ * packages. `id` mirrors `name` so the nodes satisfy client-dag's DAGNode contract (which keys by
17
+ * id) while the ecosystem code keeps using the readable `name`.
18
+ */
19
+ export function buildDAGNodes(
20
+ packages: Record<string, PackageInfo>
21
+ ): Map<string, DAGNode> {
22
+ const nodes = new Map<string, DAGNode>();
23
+
24
+ for (const [name, info] of Object.entries(packages)) {
25
+ // Only include packages that have mark1russell7 dependencies or are dependencies of others.
26
+ const deps = info.mark1russell7Deps.filter((dep) => packages[dep] !== undefined);
27
+
28
+ const gitRef = info.gitRemote ?? `github:mark1russell7/${info.name}#${info.currentBranch ?? "main"}`;
29
+ const requiredBranch = info.currentBranch ?? "main";
30
+
31
+ const node: DAGNode = {
32
+ id: name,
33
+ name,
34
+ repoPath: info.repoPath,
35
+ gitRef,
36
+ requiredBranch,
37
+ dependencies: deps,
38
+ };
39
+
40
+ nodes.set(name, node);
41
+ }
42
+
43
+ return nodes;
44
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * DAG utilities.
3
+ *
4
+ * The generic DAG algorithms are re-exported from @procedures/dag; only buildDAGNodes
5
+ * (which builds the ecosystem package graph) is domain-specific and stays local. This package
6
+ * previously vendored a verbatim copy of the generic algorithms — deduplicated here. The nodes
7
+ * carry an `id` (mirroring `name`) so they satisfy client-dag's generic `DAGNode` contract.
8
+ * See documentation/BUGS-2026-07.md (DAG de-dup / H27).
9
+ */
10
+
11
+ export {
12
+ buildLeveledDAG,
13
+ getTopologicalOrder,
14
+ visualizeDAG,
15
+ executeDAG,
16
+ executeDAGSequential,
17
+ createProcessor,
18
+ filterDAGFromRoot,
19
+ getAncestors,
20
+ getDescendants,
21
+ } from "@procedures/dag";
22
+
23
+ export { buildDAGNodes } from "./builder.js";
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Git utilities
3
+ */
4
+
5
+ export {
6
+ parseGitRef,
7
+ isGitRef,
8
+ isMark1Russell7Ref,
9
+ extractMark1Russell7Deps,
10
+ getPackageNameFromRef,
11
+ } from "./ref-parser.js";
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Git reference parser
3
+ *
4
+ * Parses git references from package.json dependencies like:
5
+ * - github:mark1russell7/logger#main
6
+ * - github:mark1russell7/client#v1.0.0
7
+ */
8
+
9
+ import type { GitRef } from "../types.js";
10
+
11
+ /**
12
+ * Parse a git reference string into its components
13
+ *
14
+ * @example
15
+ * parseGitRef("github:mark1russell7/logger#main")
16
+ * // { raw: "...", host: "github", owner: "mark1russell7", repo: "logger", ref: "main" }
17
+ */
18
+ export function parseGitRef(refString: string): GitRef | null {
19
+ // Pattern: host:owner/repo#ref
20
+ // Examples:
21
+ // github:mark1russell7/logger#main
22
+ // gitlab:user/project#develop
23
+ const match = refString.match(/^(\w+):([^/]+)\/([^#]+)#(.+)$/);
24
+
25
+ if (!match) {
26
+ return null;
27
+ }
28
+
29
+ const [, host, owner, repo, ref] = match;
30
+
31
+ return {
32
+ raw: refString,
33
+ host: host!,
34
+ owner: owner!,
35
+ repo: repo!,
36
+ ref: ref!,
37
+ };
38
+ }
39
+
40
+ /**
41
+ * Check if a dependency string is a git reference
42
+ */
43
+ export function isGitRef(dep: string): boolean {
44
+ return /^\w+:[^/]+\/[^#]+#.+$/.test(dep);
45
+ }
46
+
47
+ /**
48
+ * Check if a dependency is a mark1russell7 git reference
49
+ */
50
+ export function isMark1Russell7Ref(dep: string): boolean {
51
+ return dep.includes("mark1russell7/");
52
+ }
53
+
54
+ /**
55
+ * Extract mark1russell7 git refs from package.json dependencies
56
+ */
57
+ export function extractMark1Russell7Deps(
58
+ dependencies: Record<string, string>
59
+ ): GitRef[] {
60
+ const refs: GitRef[] = [];
61
+
62
+ for (const [, version] of Object.entries(dependencies)) {
63
+ if (isMark1Russell7Ref(version)) {
64
+ const ref = parseGitRef(version);
65
+ if (ref) {
66
+ refs.push(ref);
67
+ }
68
+ }
69
+ }
70
+
71
+ return refs;
72
+ }
73
+
74
+ /**
75
+ * Get the package name from a git ref
76
+ * Uses the repo name, optionally scoped with @mark1russell7/
77
+ */
78
+ export function getPackageNameFromRef(ref: GitRef): string {
79
+ // For mark1russell7 repos, the package name is usually @mark1russell7/{repo}
80
+ // But some packages like "client" are unscoped
81
+ // We'll need to check the actual package.json to be sure
82
+ return ref.repo;
83
+ }
package/src/index.ts ADDED
@@ -0,0 +1,57 @@
1
+ /**
2
+ * @procedures/lib
3
+ *
4
+ * Library management procedures for the workspace - scan, new, audit, rename.
5
+ */
6
+
7
+ // Importing the package registers its procedures, as in the other client packages (BUGS-2026-07 H18)
8
+ import "./register.js";
9
+
10
+ // Re-export types
11
+ export * from "./types.js";
12
+
13
+ // Re-export procedures
14
+ export {
15
+ libScan,
16
+ libRename,
17
+ libNew,
18
+ libAudit,
19
+ } from "./procedures/lib/index.js";
20
+
21
+ // Re-export ecosystem procedures
22
+ export {
23
+ ecosystemProcedures,
24
+ EcosystemProceduresInputSchema,
25
+ } from "./procedures/ecosystem/index.js";
26
+ export type {
27
+ EcosystemProceduresInput,
28
+ EcosystemProceduresOutput,
29
+ ProcedureInfo,
30
+ PackageProcedures,
31
+ } from "./procedures/ecosystem/index.js";
32
+
33
+ // Re-export DAG utilities (ecosystem-specific)
34
+ export {
35
+ buildDAGNodes,
36
+ filterDAGFromRoot,
37
+ getAncestors,
38
+ getDescendants,
39
+ buildLeveledDAG,
40
+ getTopologicalOrder,
41
+ visualizeDAG,
42
+ executeDAG,
43
+ executeDAGSequential,
44
+ createProcessor,
45
+ } from "./dag/index.js";
46
+
47
+ // Re-export git utilities
48
+ export {
49
+ parseGitRef,
50
+ isGitRef,
51
+ isMark1Russell7Ref,
52
+ extractMark1Russell7Deps,
53
+ getPackageNameFromRef,
54
+ } from "./git/index.js";
55
+
56
+ // The global flags of the mark CLI (also at "@procedures/lib/cli-flags", with no side effects)
57
+ export { CLI_GLOBAL_FLAGS, findGlobalFlag, type CliGlobalFlag } from "./cli-flags.js";
package/src/module.ts ADDED
@@ -0,0 +1,207 @@
1
+ /**
2
+ * Module (no side effects): the procedures of this package as data, for `createRegistry()`.
3
+ *
4
+ * Procedure Registration for lib operations
5
+ *
6
+ * This is the canonical home for lib.* procedures.
7
+ * client-cli no longer registers these to avoid duplicates.
8
+ */
9
+
10
+ import { createProcedure, zodAdapter, RUNS_REFS_TAG, defineModule, type ProcedureModule } from "@procedures/client";
11
+ import gitModule from "@procedures/git/module";
12
+ import fsModule from "@procedures/fs/module";
13
+ import {
14
+ libScan,
15
+ libRename,
16
+ libNew,
17
+ libAudit,
18
+ } from "./procedures/lib/index.js";
19
+ import {
20
+ ecosystemProcedures,
21
+ EcosystemProceduresInputSchema,
22
+ EcosystemProceduresOutputSchema,
23
+ type EcosystemProceduresInput,
24
+ type EcosystemProceduresOutput,
25
+ } from "./procedures/ecosystem/index.js";
26
+ import { dagTraverse } from "./procedures/dag/index.js";
27
+ import { coreCatch } from "./procedures/core/index.js";
28
+ import {
29
+ LibScanInputSchema,
30
+ LibRenameInputSchema,
31
+ LibNewInputSchema,
32
+ LibAuditInputSchema,
33
+ DagTraverseInputSchema,
34
+ CoreCatchInputSchema,
35
+ type LibScanInput,
36
+ type LibScanOutput,
37
+ type LibRenameInput,
38
+ type LibRenameOutput,
39
+ type LibNewInput,
40
+ type LibNewOutput,
41
+ type LibAuditInput,
42
+ type LibAuditOutput,
43
+ type DagTraverseInput,
44
+ type DagTraverseOutput,
45
+ type CoreCatchInput,
46
+ type CoreCatchOutput,
47
+ LibScanOutputSchema,
48
+ LibRenameOutputSchema,
49
+ LibNewOutputSchema,
50
+ LibAuditOutputSchema,
51
+ DagTraverseOutputSchema,
52
+ CoreCatchOutputSchema,
53
+ } from "./types.js";
54
+ import type { ProcedureContext } from "@procedures/client";
55
+
56
+ // =============================================================================
57
+ // lib.* Procedures
58
+ // =============================================================================
59
+
60
+ const libScanProcedure = createProcedure()
61
+ .path(["lib", "scan"])
62
+ .input(zodAdapter<LibScanInput>(LibScanInputSchema))
63
+ .output(zodAdapter<LibScanOutput>(LibScanOutputSchema))
64
+ .meta({
65
+ description: "Scan for packages in the git directory",
66
+ calls: ["fs.readdir", "fs.read.json", "git.status", "git.remote"],
67
+ args: [],
68
+ shorts: {},
69
+ output: "json",
70
+ })
71
+ .handler(async (input: LibScanInput, ctx: ProcedureContext): Promise<LibScanOutput> => {
72
+ return libScan(input, ctx);
73
+ })
74
+ .build();
75
+
76
+ const libRenameProcedure = createProcedure()
77
+ .path(["lib", "rename"])
78
+ .input(zodAdapter<LibRenameInput>(LibRenameInputSchema))
79
+ .output(zodAdapter<LibRenameOutput>(LibRenameOutputSchema))
80
+ .meta({
81
+ description: "Rename a package across the ecosystem",
82
+ calls: ["fs.glob", "fs.read.json", "fs.write", "fs.exists"],
83
+ args: ["oldName", "newName"],
84
+ shorts: { dryRun: "n" },
85
+ output: "json",
86
+ })
87
+ .handler(async (input: LibRenameInput, ctx: ProcedureContext): Promise<LibRenameOutput> => {
88
+ return libRename(input, ctx);
89
+ })
90
+ .build();
91
+
92
+ const libNewProcedure = createProcedure()
93
+ .path(["lib", "new"])
94
+ .input(zodAdapter<LibNewInput>(LibNewInputSchema))
95
+ .output(zodAdapter<LibNewOutput>(LibNewOutputSchema))
96
+ .meta({
97
+ description: "Create a new package in the ecosystem",
98
+ calls: ["shell.run", "fs.exists", "fs.mkdir", "fs.write", "fs.read.json"],
99
+ args: ["name"],
100
+ shorts: { dryRun: "n" },
101
+ output: "json",
102
+ })
103
+ .handler(async (input: LibNewInput, ctx: ProcedureContext): Promise<LibNewOutput> => {
104
+ return libNew(input, ctx);
105
+ })
106
+ .build();
107
+
108
+ const libAuditProcedure = createProcedure()
109
+ .path(["lib", "audit"])
110
+ .input(zodAdapter<LibAuditInput>(LibAuditInputSchema))
111
+ .output(zodAdapter<LibAuditOutput>(LibAuditOutputSchema))
112
+ .meta({
113
+ description: "Audit ecosystem packages for issues",
114
+ calls: ["fs.readdir", "fs.read.json", "git.status", "git.remote", "fs.exists", "fs.mkdir", "fs.write"],
115
+ args: [],
116
+ shorts: { fix: "f" },
117
+ output: "json",
118
+ })
119
+ .handler(async (input: LibAuditInput, ctx: ProcedureContext): Promise<LibAuditOutput> => {
120
+ return libAudit(input, ctx);
121
+ })
122
+ .build();
123
+
124
+ // =============================================================================
125
+ // ecosystem.* Procedures
126
+ // =============================================================================
127
+
128
+ const ecosystemProceduresProcedure = createProcedure()
129
+ .path(["ecosystem", "procedures"])
130
+ .input(zodAdapter<EcosystemProceduresInput>(EcosystemProceduresInputSchema))
131
+ .output(zodAdapter<EcosystemProceduresOutput>(EcosystemProceduresOutputSchema))
132
+ .meta({
133
+ description: "List all procedures across the ecosystem",
134
+ args: [],
135
+ shorts: { namespace: "n" },
136
+ output: "json",
137
+ })
138
+ .handler(async (input: EcosystemProceduresInput, ctx: ProcedureContext): Promise<EcosystemProceduresOutput> => {
139
+ return ecosystemProcedures(input, ctx);
140
+ })
141
+ .build();
142
+
143
+ // =============================================================================
144
+ // dag.* Procedures
145
+ // =============================================================================
146
+
147
+ const dagTraverseProcedure = createProcedure()
148
+ .path(["dag", "traverse"])
149
+ .input(zodAdapter<DagTraverseInput>(DagTraverseInputSchema))
150
+ .output(zodAdapter<DagTraverseOutput>(DagTraverseOutputSchema))
151
+ .meta({
152
+ description: "Traverse ecosystem packages in dependency order, executing visit procedure for each",
153
+ // It runs the procedure refs of its input: a server with an expose rule limits what they call
154
+ tags: [RUNS_REFS_TAG],
155
+ args: [],
156
+ shorts: { root: "r", concurrency: "j", continueOnError: "c", dryRun: "d" },
157
+ output: "streaming",
158
+ })
159
+ .handler(async (input: DagTraverseInput, ctx: ProcedureContext): Promise<DagTraverseOutput> => {
160
+ return dagTraverse(input, ctx);
161
+ })
162
+ .build();
163
+
164
+ // =============================================================================
165
+ // core.* Procedures
166
+ // =============================================================================
167
+
168
+ const coreCatchProcedure = createProcedure()
169
+ .path(["core", "catch"])
170
+ .input(zodAdapter<CoreCatchInput>(CoreCatchInputSchema))
171
+ .output(zodAdapter<CoreCatchOutput>(CoreCatchOutputSchema))
172
+ .meta({
173
+ description: "Execute a procedure with error handling",
174
+ // It runs the procedure refs of its input: a server with an expose rule limits what they call
175
+ tags: [RUNS_REFS_TAG],
176
+ args: [],
177
+ shorts: {},
178
+ output: "json",
179
+ })
180
+ .handler(async (input: CoreCatchInput, ctx: ProcedureContext): Promise<CoreCatchOutput> => {
181
+ return coreCatch(input, ctx);
182
+ })
183
+ .build();
184
+
185
+ // =============================================================================
186
+ // Registration
187
+ // =============================================================================
188
+
189
+ /**
190
+ * The module of this package, for `createRegistry()`: its procedures as data. Importing this
191
+ * file registers nothing. (`register.ts` registers the same procedures in the global registry.)
192
+ */
193
+ export const libModule: ProcedureModule = defineModule("@procedures/lib", [
194
+ // lib.* procedures (canonical home)
195
+ libScanProcedure,
196
+ libRenameProcedure,
197
+ libNewProcedure,
198
+ libAuditProcedure,
199
+ // ecosystem.* procedures
200
+ ecosystemProceduresProcedure,
201
+ // dag.* procedures (canonical home)
202
+ dagTraverseProcedure,
203
+ // core.* procedures
204
+ coreCatchProcedure,
205
+ ], [fsModule, gitModule]);
206
+
207
+ export default libModule;