planmode 0.1.0 → 0.1.2
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/dist/index.js +23 -8
- package/package.json +1 -1
- package/src/commands/install.ts +16 -1
- package/src/index.ts +1 -1
- package/src/lib/config.ts +1 -1
- package/src/lib/installer.ts +3 -2
- package/src/lib/registry.ts +4 -3
- package/src/types/index.ts +1 -0
package/dist/index.js
CHANGED
|
@@ -57,7 +57,7 @@ function setGitHubToken(token) {
|
|
|
57
57
|
function getRegistries() {
|
|
58
58
|
const config = readConfig();
|
|
59
59
|
return {
|
|
60
|
-
default: "github.com/planmode/registry",
|
|
60
|
+
default: "github.com/kaihannonen/planmode.org/registry",
|
|
61
61
|
...config.registries
|
|
62
62
|
};
|
|
63
63
|
}
|
|
@@ -76,11 +76,12 @@ function getHeaders() {
|
|
|
76
76
|
return headers;
|
|
77
77
|
}
|
|
78
78
|
function registryRawUrl(registryUrl, filePath) {
|
|
79
|
-
const match = registryUrl.match(/^github\.com\/([^/]+)\/([^/]+)
|
|
79
|
+
const match = registryUrl.match(/^github\.com\/([^/]+)\/([^/]+)(?:\/(.+))?$/);
|
|
80
80
|
if (!match) {
|
|
81
81
|
throw new Error(`Invalid registry URL: ${registryUrl}`);
|
|
82
82
|
}
|
|
83
|
-
|
|
83
|
+
const subpath = match[3] ? `${match[3]}/` : "";
|
|
84
|
+
return `https://raw.githubusercontent.com/${match[1]}/${match[2]}/main/${subpath}${filePath}`;
|
|
84
85
|
}
|
|
85
86
|
function resolveRegistry(packageName) {
|
|
86
87
|
const registries = getRegistries();
|
|
@@ -643,10 +644,11 @@ async function installPackage(packageName, options = {}) {
|
|
|
643
644
|
const { version, metadata } = await resolveVersion(packageName, options.version);
|
|
644
645
|
const versionMeta = await fetchVersionMetadata(packageName, version);
|
|
645
646
|
logger.info(`Fetching ${packageName}@${version}...`);
|
|
647
|
+
const basePath = versionMeta.source.path ? `${versionMeta.source.path}/` : "";
|
|
646
648
|
const manifestRaw = await fetchFileAtTag(
|
|
647
649
|
versionMeta.source.repository,
|
|
648
650
|
versionMeta.source.tag,
|
|
649
|
-
|
|
651
|
+
`${basePath}planmode.yaml`
|
|
650
652
|
);
|
|
651
653
|
const manifest = parseManifest(manifestRaw);
|
|
652
654
|
let content;
|
|
@@ -656,7 +658,7 @@ async function installPackage(packageName, options = {}) {
|
|
|
656
658
|
content = await fetchFileAtTag(
|
|
657
659
|
versionMeta.source.repository,
|
|
658
660
|
versionMeta.source.tag,
|
|
659
|
-
manifest.content_file
|
|
661
|
+
`${basePath}${manifest.content_file}`
|
|
660
662
|
);
|
|
661
663
|
} else {
|
|
662
664
|
throw new Error("Package has no content or content_file");
|
|
@@ -751,14 +753,27 @@ async function updatePackage(packageName, projectDir = process.cwd()) {
|
|
|
751
753
|
}
|
|
752
754
|
|
|
753
755
|
// src/commands/install.ts
|
|
754
|
-
|
|
756
|
+
function parseVariables(pairs) {
|
|
757
|
+
const vars = {};
|
|
758
|
+
for (const pair of pairs) {
|
|
759
|
+
const eq = pair.indexOf("=");
|
|
760
|
+
if (eq === -1) {
|
|
761
|
+
throw new Error(`Invalid variable format: "${pair}". Use --set key=value`);
|
|
762
|
+
}
|
|
763
|
+
vars[pair.slice(0, eq)] = pair.slice(eq + 1);
|
|
764
|
+
}
|
|
765
|
+
return vars;
|
|
766
|
+
}
|
|
767
|
+
var installCommand = new Command("install").description("Install a package into the current project").argument("<package>", "Package name (e.g., nextjs-tailwind-starter)").option("-v, --version <version>", "Install specific version").option("--rule", "Force install as a rule to .claude/rules/").option("--no-input", "Fail if any required variable is missing").option("--set <key=value...>", "Set template variables (e.g., --set project_name=myapp)").action(
|
|
755
768
|
async (packageName, options) => {
|
|
756
769
|
try {
|
|
757
770
|
logger.blank();
|
|
771
|
+
const variables = options.set ? parseVariables(options.set) : void 0;
|
|
758
772
|
await installPackage(packageName, {
|
|
759
773
|
version: options.version,
|
|
760
774
|
forceRule: options.rule,
|
|
761
|
-
noInput: options.input === false
|
|
775
|
+
noInput: options.input === false,
|
|
776
|
+
variables
|
|
762
777
|
});
|
|
763
778
|
logger.blank();
|
|
764
779
|
} catch (err) {
|
|
@@ -1279,7 +1294,7 @@ var loginCommand = new Command10("login").description("Configure GitHub authenti
|
|
|
1279
1294
|
|
|
1280
1295
|
// src/index.ts
|
|
1281
1296
|
var program = new Command11();
|
|
1282
|
-
program.name("planmode").description("The open source package manager for AI plans, rules, and prompts.").version("0.1.
|
|
1297
|
+
program.name("planmode").description("The open source package manager for AI plans, rules, and prompts.").version("0.1.1");
|
|
1283
1298
|
program.addCommand(installCommand);
|
|
1284
1299
|
program.addCommand(uninstallCommand);
|
|
1285
1300
|
program.addCommand(searchCommand);
|
package/package.json
CHANGED
package/src/commands/install.ts
CHANGED
|
@@ -2,23 +2,38 @@ import { Command } from "commander";
|
|
|
2
2
|
import { installPackage } from "../lib/installer.js";
|
|
3
3
|
import { logger } from "../lib/logger.js";
|
|
4
4
|
|
|
5
|
+
function parseVariables(pairs: string[]): Record<string, string> {
|
|
6
|
+
const vars: Record<string, string> = {};
|
|
7
|
+
for (const pair of pairs) {
|
|
8
|
+
const eq = pair.indexOf("=");
|
|
9
|
+
if (eq === -1) {
|
|
10
|
+
throw new Error(`Invalid variable format: "${pair}". Use --set key=value`);
|
|
11
|
+
}
|
|
12
|
+
vars[pair.slice(0, eq)] = pair.slice(eq + 1);
|
|
13
|
+
}
|
|
14
|
+
return vars;
|
|
15
|
+
}
|
|
16
|
+
|
|
5
17
|
export const installCommand = new Command("install")
|
|
6
18
|
.description("Install a package into the current project")
|
|
7
19
|
.argument("<package>", "Package name (e.g., nextjs-tailwind-starter)")
|
|
8
20
|
.option("-v, --version <version>", "Install specific version")
|
|
9
21
|
.option("--rule", "Force install as a rule to .claude/rules/")
|
|
10
22
|
.option("--no-input", "Fail if any required variable is missing")
|
|
23
|
+
.option("--set <key=value...>", "Set template variables (e.g., --set project_name=myapp)")
|
|
11
24
|
.action(
|
|
12
25
|
async (
|
|
13
26
|
packageName: string,
|
|
14
|
-
options: { version?: string; rule?: boolean; input?: boolean },
|
|
27
|
+
options: { version?: string; rule?: boolean; input?: boolean; set?: string[] },
|
|
15
28
|
) => {
|
|
16
29
|
try {
|
|
17
30
|
logger.blank();
|
|
31
|
+
const variables = options.set ? parseVariables(options.set) : undefined;
|
|
18
32
|
await installPackage(packageName, {
|
|
19
33
|
version: options.version,
|
|
20
34
|
forceRule: options.rule,
|
|
21
35
|
noInput: options.input === false,
|
|
36
|
+
variables,
|
|
22
37
|
});
|
|
23
38
|
logger.blank();
|
|
24
39
|
} catch (err) {
|
package/src/index.ts
CHANGED
|
@@ -15,7 +15,7 @@ const program = new Command();
|
|
|
15
15
|
program
|
|
16
16
|
.name("planmode")
|
|
17
17
|
.description("The open source package manager for AI plans, rules, and prompts.")
|
|
18
|
-
.version("0.1.
|
|
18
|
+
.version("0.1.1");
|
|
19
19
|
|
|
20
20
|
program.addCommand(installCommand);
|
|
21
21
|
program.addCommand(uninstallCommand);
|
package/src/lib/config.ts
CHANGED
|
@@ -52,7 +52,7 @@ export function setGitHubToken(token: string): void {
|
|
|
52
52
|
export function getRegistries(): Record<string, string> {
|
|
53
53
|
const config = readConfig();
|
|
54
54
|
return {
|
|
55
|
-
default: "github.com/planmode/registry",
|
|
55
|
+
default: "github.com/kaihannonen/planmode.org/registry",
|
|
56
56
|
...config.registries,
|
|
57
57
|
};
|
|
58
58
|
}
|
package/src/lib/installer.ts
CHANGED
|
@@ -60,10 +60,11 @@ export async function installPackage(
|
|
|
60
60
|
|
|
61
61
|
// Fetch manifest
|
|
62
62
|
logger.info(`Fetching ${packageName}@${version}...`);
|
|
63
|
+
const basePath = versionMeta.source.path ? `${versionMeta.source.path}/` : "";
|
|
63
64
|
const manifestRaw = await fetchFileAtTag(
|
|
64
65
|
versionMeta.source.repository,
|
|
65
66
|
versionMeta.source.tag,
|
|
66
|
-
|
|
67
|
+
`${basePath}planmode.yaml`,
|
|
67
68
|
);
|
|
68
69
|
const manifest = parseManifest(manifestRaw);
|
|
69
70
|
|
|
@@ -75,7 +76,7 @@ export async function installPackage(
|
|
|
75
76
|
content = await fetchFileAtTag(
|
|
76
77
|
versionMeta.source.repository,
|
|
77
78
|
versionMeta.source.tag,
|
|
78
|
-
manifest.content_file
|
|
79
|
+
`${basePath}${manifest.content_file}`,
|
|
79
80
|
);
|
|
80
81
|
} else {
|
|
81
82
|
throw new Error("Package has no content or content_file");
|
package/src/lib/registry.ts
CHANGED
|
@@ -18,12 +18,13 @@ function getHeaders(): Record<string, string> {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
function registryRawUrl(registryUrl: string, filePath: string): string {
|
|
21
|
-
// Convert github.com/org/repo to raw.githubusercontent.com URL
|
|
22
|
-
const match = registryUrl.match(/^github\.com\/([^/]+)\/([^/]+)
|
|
21
|
+
// Convert github.com/org/repo[/subpath] to raw.githubusercontent.com URL
|
|
22
|
+
const match = registryUrl.match(/^github\.com\/([^/]+)\/([^/]+)(?:\/(.+))?$/);
|
|
23
23
|
if (!match) {
|
|
24
24
|
throw new Error(`Invalid registry URL: ${registryUrl}`);
|
|
25
25
|
}
|
|
26
|
-
|
|
26
|
+
const subpath = match[3] ? `${match[3]}/` : "";
|
|
27
|
+
return `https://raw.githubusercontent.com/${match[1]}/${match[2]}/main/${subpath}${filePath}`;
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
function resolveRegistry(packageName: string): string {
|