skein-js 0.5.0 → 0.7.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 (3) hide show
  1. package/README.md +10 -6
  2. package/dist/index.js +53 -14
  3. package/package.json +8 -8
package/README.md CHANGED
@@ -52,15 +52,19 @@ LangGraph Studio — any Agent Protocol client works with only a URL change. See
52
52
 
53
53
  ## Commands
54
54
 
55
- | Command | What it does | LangGraph CLI equivalent | Key flags |
56
- | ------------------ | -------------------------------------------------------------- | ------------------------ | ---------------------------------------------- |
57
- | `skein dev` | In-process dev server, hot reload, `.skein/` state, no Docker. | `langgraph dev` | see [`skein dev` flags](#skein-dev-flags) |
58
- | `skein up` | Self-hosted stack via Docker Compose (app + Postgres + Redis). | `langgraph up` | `-p, --port` (8123) · `--host` (0.0.0.0) |
59
- | `skein build` | Build a deployable Docker image from the config. | `langgraph build` | `-t, --tag` (defaults to the project dir name) |
60
- | `skein dockerfile` | Emit a standalone Dockerfile (stdout by default). | `langgraph dockerfile` | `-o, --output <path>` |
55
+ | Command | What it does | LangGraph CLI equivalent | Key flags |
56
+ | ------------------ | -------------------------------------------------------------- | ------------------------ | --------------------------------------------------------------------- |
57
+ | `skein dev` | In-process dev server, hot reload, `.skein/` state, no Docker. | `langgraph dev` | see [`skein dev` flags](#skein-dev-flags) |
58
+ | `skein up` | Self-hosted stack via Docker Compose (app + Postgres + Redis). | `langgraph up` | `-p, --port` (8123) · `--host` (0.0.0.0) · `-n, --npmrc <path>` |
59
+ | `skein build` | Build a deployable Docker image from the config. | `langgraph build` | `-t, --tag` (defaults to the project dir name) · `-n, --npmrc <path>` |
60
+ | `skein dockerfile` | Emit a standalone Dockerfile (stdout by default). | `langgraph dockerfile` | `-o, --output <path>` |
61
61
 
62
62
  All commands take `-c, --config <path>` (default `langgraph.json`).
63
63
 
64
+ `--npmrc <path>` (on `build`/`up`) mounts an `.npmrc` as a BuildKit secret so the image's dependency
65
+ install can authenticate against a **private/authenticated npm registry** without baking a token into
66
+ any layer. Public-registry builds don't need it.
67
+
64
68
  ## `skein dev` flags
65
69
 
66
70
  | Flag | Values | Default | Notes |
package/dist/index.js CHANGED
@@ -359,7 +359,7 @@ async function runDev(options) {
359
359
 
360
360
  // src/docker/commands.ts
361
361
  import { spawn, spawnSync } from "child_process";
362
- import { writeFileSync as writeFileSync2 } from "fs";
362
+ import { existsSync as existsSync4, writeFileSync as writeFileSync2 } from "fs";
363
363
  import { createRequire as createRequire2 } from "module";
364
364
  import path5 from "path";
365
365
  import { loadConfig as loadConfig3 } from "@skein-js/config";
@@ -370,7 +370,7 @@ import { mkdir, writeFile } from "fs/promises";
370
370
  import { createRequire, isBuiltin } from "module";
371
371
  import path4 from "path";
372
372
  import { loadConfig as loadConfig2, parseGraphSpec } from "@skein-js/config";
373
- import { embedRuntimePackage, isCustomFunctionPath } from "@skein-js/runtime";
373
+ import { providerEmbedPackage, isCustomFunctionPath } from "@skein-js/runtime";
374
374
 
375
375
  // src/bundle/precompute-schemas.ts
376
376
  async function precomputeSchemas(graphs) {
@@ -535,7 +535,7 @@ async function bundleProject(options) {
535
535
  for (const peer of SKEIN_RUNTIME_PEERS) {
536
536
  dependencies[peer] = resolveInstalledVersion(peer, workspaceRoot);
537
537
  }
538
- const embedPkg = config.store?.index?.embed && embedRuntimePackage(config.store.index.embed);
538
+ const embedPkg = config.store?.index?.embed && providerEmbedPackage(config.store.index.embed);
539
539
  if (embedPkg) dependencies[embedPkg] = resolveInstalledVersion(embedPkg, workspaceRoot);
540
540
  for (const dep of config.dependencies ?? []) {
541
541
  if (dep.startsWith(".") || dep.startsWith("/")) continue;
@@ -568,10 +568,19 @@ function portMapping(options) {
568
568
  }
569
569
  function generateCompose(options) {
570
570
  const ports = portMapping(options);
571
+ const appBuild = options.npmrcPath ? `build:
572
+ context: .
573
+ secrets:
574
+ - npmrc` : `build: .`;
575
+ const secretsBlock = options.npmrcPath ? `
576
+ secrets:
577
+ npmrc:
578
+ file: ${JSON.stringify(options.npmrcPath)}
579
+ ` : "";
571
580
  return `# Generated by skein \u2014 regenerated by \`skein up\`. Edit with care.
572
581
  services:
573
582
  app:
574
- build: .
583
+ ${appBuild}
575
584
  # Reap zombies + forward signals with an init process (PID 1), so graph-spawned children don't
576
585
  # accumulate; the app itself still handles SIGTERM for graceful shutdown.
577
586
  init: true
@@ -616,7 +625,7 @@ services:
616
625
 
617
626
  volumes:
618
627
  skein-pgdata:
619
- `;
628
+ ${secretsBlock}`;
620
629
  }
621
630
 
622
631
  // src/docker/dockerfile.ts
@@ -631,6 +640,9 @@ function generateDockerignore() {
631
640
  "node_modules",
632
641
  ".env",
633
642
  ".env.*",
643
+ // Never bake a registry credential into a layer — it's supplied via a BuildKit secret at install.
644
+ ".npmrc",
645
+ ".npmrc.*",
634
646
  "Dockerfile",
635
647
  "compose.yaml",
636
648
  ".dockerignore",
@@ -653,10 +665,15 @@ function generateDockerfile(options) {
653
665
  ``,
654
666
  // Install prod deps first for layer caching: the artifact's pinned package.json changes rarely,
655
667
  // so this layer is reused across rebuilds while only the bundle layer below re-runs. The BuildKit
656
- // cache mount keeps the npm cache out of the committed layer.
668
+ // cache mount keeps the npm cache out of the committed layer. The `npmrc` secret mount lets private
669
+ // scoped deps authenticate against a private/authenticated registry without baking a token into any
670
+ // layer; it is optional (BuildKit secrets are not required by default), so a public-registry build
671
+ // that passes no secret is unaffected. Supply it via `skein build --npmrc <path>` or, for the
672
+ // standalone Dockerfile, `docker build --secret id=npmrc,src=<path>`.
657
673
  `# Install the artifact's pinned production dependencies (exact versions \u2014 deterministic).`,
658
674
  `COPY package.json ./`,
659
675
  `RUN --mount=type=cache,target=/root/.npm \\`,
676
+ ` --mount=type=secret,id=npmrc,target=/app/.npmrc \\`,
660
677
  ` npm install --omit=dev --omit=optional --no-audit --no-fund`,
661
678
  ``,
662
679
  `# Copy the pre-built artifact (bundled JS graphs, production langgraph.json, baked schemas).`,
@@ -723,6 +740,16 @@ function defaultImageTag(configDir) {
723
740
  const trimmed = base.replace(/^[-.]+|[-.]+$/g, "");
724
741
  return trimmed.length > 0 ? trimmed : "skein-app";
725
742
  }
743
+ function resolveNpmrcSecret(npmrc) {
744
+ if (npmrc === void 0) return void 0;
745
+ const resolved = path5.resolve(process.cwd(), npmrc);
746
+ if (!existsSync4(resolved)) {
747
+ console.error(`skein: --npmrc file not found: ${resolved}`);
748
+ process.exitCode = 1;
749
+ return null;
750
+ }
751
+ return resolved;
752
+ }
726
753
  function dockerAvailable() {
727
754
  const probe = spawnSync("docker", ["--version"], { stdio: "ignore" });
728
755
  return probe.status === 0;
@@ -768,6 +795,8 @@ async function runDockerfile(options) {
768
795
  }
769
796
  async function runBuild(options) {
770
797
  const context = await loadConfigContext(options.config);
798
+ const npmrcPath = resolveNpmrcSecret(options.npmrc);
799
+ if (npmrcPath === null) return;
771
800
  if (!requireDocker()) return;
772
801
  let artifactDir;
773
802
  try {
@@ -778,10 +807,11 @@ async function runBuild(options) {
778
807
  return;
779
808
  }
780
809
  const tag = options.tag ?? defaultImageTag(context.configDir);
810
+ const secretArgs = npmrcPath !== void 0 ? ["--secret", `id=npmrc,src=${npmrcPath}`] : [];
781
811
  console.log(`skein: building image "${tag}"\u2026`);
782
812
  const result = await runToCompletion(
783
813
  "docker",
784
- ["build", "-t", tag, "-f", path5.join(artifactDir, DOCKERFILE_NAME), "."],
814
+ ["build", "-t", tag, "-f", path5.join(artifactDir, DOCKERFILE_NAME), ...secretArgs, "."],
785
815
  artifactDir
786
816
  );
787
817
  if (!succeeded(result)) {
@@ -793,6 +823,8 @@ async function runBuild(options) {
793
823
  }
794
824
  async function runUp(options) {
795
825
  const context = await loadConfigContext(options.config);
826
+ const npmrcPath = resolveNpmrcSecret(options.npmrc);
827
+ if (npmrcPath === null) return;
796
828
  if (!requireDocker()) return;
797
829
  let artifactDir;
798
830
  try {
@@ -802,7 +834,8 @@ async function runUp(options) {
802
834
  contents: generateCompose({
803
835
  hostPort: options.port,
804
836
  host: options.host,
805
- containerPort: CONTAINER_PORT
837
+ containerPort: CONTAINER_PORT,
838
+ npmrcPath
806
839
  })
807
840
  }
808
841
  ]);
@@ -826,7 +859,7 @@ async function runUp(options) {
826
859
  }
827
860
 
828
861
  // src/import-command.ts
829
- import { existsSync as existsSync4 } from "fs";
862
+ import { existsSync as existsSync5 } from "fs";
830
863
  import path6 from "path";
831
864
  import { loadConfig as loadConfig4 } from "@skein-js/config";
832
865
  import {
@@ -850,7 +883,7 @@ async function runImportLanggraph(options) {
850
883
  const counts = describeSnapshot2(snapshot);
851
884
  if (options.store === "memory") {
852
885
  const stateFile = devStateFile(configDir);
853
- if (existsSync4(stateFile) && !options.force) {
886
+ if (existsSync5(stateFile) && !options.force) {
854
887
  console.error(
855
888
  `skein: ${path6.relative(process.cwd(), stateFile)} already exists. Re-run with --force to overwrite it (or delete it first).`
856
889
  );
@@ -885,7 +918,7 @@ async function runImportLanggraph(options) {
885
918
  }
886
919
 
887
920
  // src/start-command.ts
888
- import { existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
921
+ import { existsSync as existsSync6, readFileSync as readFileSync4 } from "fs";
889
922
  import path7 from "path";
890
923
  import { loadConfig as loadConfig5 } from "@skein-js/config";
891
924
  import { createExpressServer as createExpressServer2 } from "@skein-js/express";
@@ -896,7 +929,7 @@ var FORCE_EXIT_MS2 = 5e3;
896
929
  var logger = createDevLogger();
897
930
  function readBakedSchemas(configDir) {
898
931
  const schemasFile = path7.join(configDir, "schemas.json");
899
- if (!existsSync5(schemasFile)) {
932
+ if (!existsSync6(schemasFile)) {
900
933
  throw new Error(
901
934
  `no schemas.json next to the config \u2014 \`skein start\` expects a built artifact. Run \`skein build\` (or \`skein up\`), or use \`skein dev\` for a source project.`
902
935
  );
@@ -1000,8 +1033,14 @@ program.command("start").description("Serve a pre-built .skein/build artifact (t
1000
1033
  hostExplicit: command.getOptionValueSource("host") === "cli"
1001
1034
  })
1002
1035
  );
1003
- program.command("up").description("Bring up the production stack (Docker Compose: app + Postgres + Redis).").option("-c, --config <path>", "Path to langgraph.json", "langgraph.json").option("-p, --port <port>", "Port to expose", parsePort, 8123).option("--host <host>", "Host to bind", "0.0.0.0").action((options) => runUp(options));
1004
- program.command("build").description("Build a deployable Docker image from the config.").option("-c, --config <path>", "Path to langgraph.json", "langgraph.json").option("-t, --tag <tag>", "Image tag (defaults to the project directory name)").action((options) => runBuild(options));
1036
+ program.command("up").description("Bring up the production stack (Docker Compose: app + Postgres + Redis).").option("-c, --config <path>", "Path to langgraph.json", "langgraph.json").option("-p, --port <port>", "Port to expose", parsePort, 8123).option("--host <host>", "Host to bind", "0.0.0.0").option(
1037
+ "-n, --npmrc <path>",
1038
+ "Path to an .npmrc for authenticating private-registry installs (wired in as a build secret)"
1039
+ ).action((options) => runUp(options));
1040
+ program.command("build").description("Build a deployable Docker image from the config.").option("-c, --config <path>", "Path to langgraph.json", "langgraph.json").option("-t, --tag <tag>", "Image tag (defaults to the project directory name)").option(
1041
+ "-n, --npmrc <path>",
1042
+ "Path to an .npmrc for authenticating private-registry installs (passed to docker build as a BuildKit secret)"
1043
+ ).action((options) => runBuild(options));
1005
1044
  program.command("dockerfile").description("Emit a standalone Dockerfile from the config.").option("-c, --config <path>", "Path to langgraph.json", "langgraph.json").option("-o, --output <path>", "Write the Dockerfile here instead of stdout").action((options) => runDockerfile(options));
1006
1045
  program.command("import-langgraph").description("Import an existing LangGraph in-memory dev state (.langgraph_api/) into skein.").option("-c, --config <path>", "Path to langgraph.json", "langgraph.json").option(
1007
1046
  "--store <driver>",
package/package.json CHANGED
@@ -1,17 +1,17 @@
1
1
  {
2
2
  "name": "skein-js",
3
- "version": "0.5.0",
3
+ "version": "0.7.0",
4
4
  "description": "The skein-js CLI — a drop-in replacement for the LangGraph CLI (dev/up/build/dockerfile).",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Maina Wycliffe <wmmaina7@gmail.com>",
7
- "homepage": "https://github.com/mainawycliffe/skein-js/tree/main/packages/cli#readme",
7
+ "homepage": "https://github.com/skein-js/skein-js/tree/main/packages/cli#readme",
8
8
  "repository": {
9
9
  "type": "git",
10
- "url": "git+https://github.com/mainawycliffe/skein-js.git",
10
+ "url": "git+https://github.com/skein-js/skein-js.git",
11
11
  "directory": "packages/cli"
12
12
  },
13
13
  "bugs": {
14
- "url": "https://github.com/mainawycliffe/skein-js/issues"
14
+ "url": "https://github.com/skein-js/skein-js/issues"
15
15
  },
16
16
  "keywords": [
17
17
  "typescript",
@@ -47,10 +47,10 @@
47
47
  "@commander-js/extra-typings": "~13.1.0",
48
48
  "@langchain/langgraph-checkpoint-postgres": "^1.0.4",
49
49
  "commander": "~13.1.0",
50
- "@skein-js/core": "0.5.0",
51
- "@skein-js/express": "0.5.0",
52
- "@skein-js/config": "0.5.0",
53
- "@skein-js/runtime": "0.5.0"
50
+ "@skein-js/config": "0.7.0",
51
+ "@skein-js/core": "0.7.0",
52
+ "@skein-js/runtime": "0.7.0",
53
+ "@skein-js/express": "0.7.0"
54
54
  },
55
55
  "optionalDependencies": {
56
56
  "vite": "^8.1.0"