@iamdevlinph/codex-kit 1.1.7 → 1.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.
package/README.md CHANGED
@@ -60,6 +60,12 @@ existing active guidance. During reconciliation, Codex merges only applicable
60
60
  rules into the project's `AGENTS.md` and preserves its local organization and
61
61
  adaptations.
62
62
 
63
+ Both `project init` and `project sync` contact the public npm registry before
64
+ writing project files. If the installed CLI is stale, or npm is unreachable or
65
+ returns invalid metadata, the command fails without changing the project. Rerun
66
+ with `pnpm dlx @iamdevlinph/codex-kit@latest` after the registry is available;
67
+ stale builds print the exact command.
68
+
63
69
  ## Commands
64
70
 
65
71
  | Action | Command |
@@ -179,7 +185,10 @@ codex-kit project sync --cwd /path/to/project
179
185
  - Codex with custom subagent and lifecycle-hook support
180
186
 
181
187
  The published package contains no credentials or runtime dependencies. Version
182
- checks contact the public npm registry only when `codex-kit version check` runs.
188
+ checks and project initialization/synchronization contact the public npm
189
+ registry; project operations fail closed before writing when that check cannot
190
+ verify the latest release. The CLI never auto-installs or executes downloaded
191
+ code.
183
192
 
184
193
  ## Security and license
185
194
 
package/bin/codex-kit.js CHANGED
@@ -575,6 +575,87 @@ function uninstallGlobal(options) {
575
575
  // src/project/commands.ts
576
576
  import { existsSync as existsSync6, statSync as statSync2 } from "node:fs";
577
577
  import { join as join6 } from "node:path";
578
+
579
+ // src/version.ts
580
+ function parseVersion(value) {
581
+ const match = /^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/.exec(value);
582
+ if (!match) throw new Error(`Invalid package version: ${value}`);
583
+ return {
584
+ numbers: [Number(match[1]), Number(match[2]), Number(match[3])],
585
+ prerelease: match[4] ?? null
586
+ };
587
+ }
588
+ function compareVersions(left, right) {
589
+ const a = parseVersion(left);
590
+ const b = parseVersion(right);
591
+ for (const [leftNumber, rightNumber] of [
592
+ [a.numbers[0], b.numbers[0]],
593
+ [a.numbers[1], b.numbers[1]],
594
+ [a.numbers[2], b.numbers[2]]
595
+ ])
596
+ if (leftNumber !== rightNumber) return Math.sign(leftNumber - rightNumber);
597
+ if (a.prerelease === b.prerelease) return 0;
598
+ if (!a.prerelease) return 1;
599
+ if (!b.prerelease) return -1;
600
+ return Math.sign(
601
+ a.prerelease.localeCompare(b.prerelease, "en", { numeric: true })
602
+ );
603
+ }
604
+ async function fetchLatestVersion() {
605
+ const url = `${REGISTRY}/${encodeURIComponent(PACKAGE.name)}/latest`;
606
+ let response;
607
+ try {
608
+ response = await fetch(url, { signal: AbortSignal.timeout(15e3) });
609
+ } catch (error) {
610
+ throw new Error(
611
+ `Unable to check ${REGISTRY}: ${error instanceof Error ? error.message : String(error)}`
612
+ );
613
+ }
614
+ if (!response.ok)
615
+ throw new Error(
616
+ `Unable to check ${REGISTRY}: ${response.status} ${response.statusText}`
617
+ );
618
+ let value;
619
+ try {
620
+ value = await response.json();
621
+ } catch {
622
+ throw new Error("Registry returned no package version.");
623
+ }
624
+ if (!value || typeof value !== "object" || Array.isArray(value) || typeof value.version !== "string")
625
+ throw new Error("Registry returned no package version.");
626
+ const latest = value.version;
627
+ parseVersion(latest);
628
+ return latest;
629
+ }
630
+ async function getLatestVersion() {
631
+ const override = process.env.CODEX_KIT_LATEST_VERSION;
632
+ if (override) {
633
+ parseVersion(override);
634
+ return override;
635
+ }
636
+ return fetchLatestVersion();
637
+ }
638
+ async function checkVersion() {
639
+ const latest = await getLatestVersion();
640
+ console.log(`Installed: ${PACKAGE.version}`);
641
+ console.log(`Latest: ${latest}`);
642
+ const comparison = compareVersions(PACKAGE.version, latest);
643
+ if (comparison === 0) {
644
+ console.log("codex-kit is up to date.");
645
+ return;
646
+ }
647
+ if (comparison > 0) {
648
+ console.log("This local build is newer than the published package.");
649
+ return;
650
+ }
651
+ console.log(
652
+ `Update available. Run:
653
+ pnpm add --global ${PACKAGE.name}@latest
654
+ codex-kit global install`
655
+ );
656
+ }
657
+
658
+ // src/project/commands.ts
578
659
  var STATE_FILE2 = ".codex-kit-state.json";
579
660
  var PROJECT_BEGIN = "<!-- BEGIN codex-kit:shared-template -->";
580
661
  var PROJECT_END = "<!-- END codex-kit:shared-template -->";
@@ -644,9 +725,17 @@ and validation succeed, confirm codex-kit project status is up to date, then
644
725
  report any template-worthy generalized promotion.
645
726
  ===== END CODEX RECONCILIATION PROMPT =====`;
646
727
  }
647
- function syncProject(options) {
728
+ async function syncProject(options, action = "sync") {
648
729
  const { cwd } = options;
649
730
  requireDirectory(cwd);
731
+ const latest = await getLatestVersion();
732
+ if (compareVersions(PACKAGE.version, latest) < 0)
733
+ throw new Error(
734
+ `Installed: ${PACKAGE.version}
735
+ Latest: ${latest}
736
+ Published guidelines are newer than this local build. Rerun with:
737
+ pnpm dlx ${PACKAGE.name}@latest project ${action} --cwd '${cwd.replaceAll("'", "'\\''")}'`
738
+ );
650
739
  const agentsFile = join6(cwd, "AGENTS.md");
651
740
  const stagedTemplate = join6(cwd, "TEMPLATE_AGENTS.md");
652
741
  const desired = Buffer.from(readText(TEMPLATE_FILE));
@@ -744,79 +833,6 @@ function markApplied(options) {
744
833
  console.log(`recorded template reconciliation: ${stagedTemplate}`);
745
834
  }
746
835
 
747
- // src/version.ts
748
- function parseVersion(value) {
749
- const match = /^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/.exec(value);
750
- if (!match) throw new Error(`Invalid package version: ${value}`);
751
- return {
752
- numbers: [Number(match[1]), Number(match[2]), Number(match[3])],
753
- prerelease: match[4] ?? null
754
- };
755
- }
756
- function compareVersions(left, right) {
757
- const a = parseVersion(left);
758
- const b = parseVersion(right);
759
- for (const [leftNumber, rightNumber] of [
760
- [a.numbers[0], b.numbers[0]],
761
- [a.numbers[1], b.numbers[1]],
762
- [a.numbers[2], b.numbers[2]]
763
- ])
764
- if (leftNumber !== rightNumber) return Math.sign(leftNumber - rightNumber);
765
- if (a.prerelease === b.prerelease) return 0;
766
- if (!a.prerelease) return 1;
767
- if (!b.prerelease) return -1;
768
- return Math.sign(
769
- a.prerelease.localeCompare(b.prerelease, "en", { numeric: true })
770
- );
771
- }
772
- async function fetchLatestVersion() {
773
- const url = `${REGISTRY}/${encodeURIComponent(PACKAGE.name)}/latest`;
774
- let response;
775
- try {
776
- response = await fetch(url, { signal: AbortSignal.timeout(15e3) });
777
- } catch (error) {
778
- throw new Error(
779
- `Unable to check ${REGISTRY}: ${error instanceof Error ? error.message : String(error)}`
780
- );
781
- }
782
- if (!response.ok)
783
- throw new Error(
784
- `Unable to check ${REGISTRY}: ${response.status} ${response.statusText}`
785
- );
786
- let value;
787
- try {
788
- value = await response.json();
789
- } catch {
790
- throw new Error("Registry returned no package version.");
791
- }
792
- if (!value || typeof value !== "object" || Array.isArray(value) || typeof value.version !== "string")
793
- throw new Error("Registry returned no package version.");
794
- const latest = value.version;
795
- parseVersion(latest);
796
- return latest;
797
- }
798
- async function checkVersion() {
799
- let latest = process.env.CODEX_KIT_LATEST_VERSION;
800
- if (!latest) latest = await fetchLatestVersion();
801
- if (!latest) throw new Error("Registry returned no package version.");
802
- console.log(`Installed: ${PACKAGE.version}`);
803
- console.log(`Latest: ${latest}`);
804
- const comparison = compareVersions(PACKAGE.version, latest);
805
- if (comparison === 0) {
806
- console.log("codex-kit is up to date.");
807
- return;
808
- }
809
- if (comparison > 0) {
810
- console.log("This local build is newer than the published package.");
811
- return;
812
- }
813
- console.log(
814
- `Update available. Run:
815
- pnpm add --global ${PACKAGE.name}@latest
816
- codex-kit global install`
817
- );
818
- }
819
-
820
836
  // src/cli/options.ts
821
837
  import { homedir } from "node:os";
822
838
  import { join as join7, resolve as resolve2 } from "node:path";
@@ -865,8 +881,8 @@ Commands:
865
881
  global configure Set the orchestrator and normal/Plan reasoning defaults.
866
882
  global list Show model settings, routing status, and custom agents.
867
883
  global uninstall Restore managed config values and remove package-owned files.
868
- project init Initialize AGENTS.md, TEMPLATE_AGENTS.md, and project state.
869
- project sync Refresh TEMPLATE_AGENTS.md without editing AGENTS.md.
884
+ project init Initialize project files after checking the latest npm release.
885
+ project sync Refresh the template after checking the latest npm release.
870
886
  project status Show whether template changes still need reconciliation.
871
887
  project mark-applied Record the current template as reconciled with AGENTS.md.
872
888
  version check Compare the installed version with the latest npm release.
@@ -891,6 +907,7 @@ Options by command:
891
907
 
892
908
  project init, project sync
893
909
  --cwd PATH Use a project directory other than the current directory.
910
+ npm access is required; stale or unverifiable builds fail before writes.
894
911
 
895
912
  project status, project mark-applied
896
913
  --cwd PATH Use a project directory other than the current directory.
@@ -919,7 +936,7 @@ async function main(argv = process.argv.slice(2)) {
919
936
  else if (scope === "global" && action === "uninstall")
920
937
  uninstallGlobal(options);
921
938
  else if (scope === "project" && (action === "init" || action === "sync"))
922
- syncProject(options);
939
+ await syncProject(options, action);
923
940
  else if (scope === "project" && action === "status") projectStatus(options);
924
941
  else if (scope === "project" && action === "mark-applied")
925
942
  markApplied(options);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iamdevlinph/codex-kit",
3
- "version": "1.1.7",
3
+ "version": "1.1.8",
4
4
  "description": "Portable Codex subagents and project AGENTS.md defaults.",
5
5
  "type": "module",
6
6
  "bin": {