ascendant-skills 2.1.0 → 2.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/bin/cli.mjs +186 -133
- package/lib/plan.mjs +10 -59
- package/package.json +26 -21
package/bin/cli.mjs
CHANGED
|
@@ -2,165 +2,218 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* `npx ascendant-skills install`: detect coding tools, ask project or
|
|
4
4
|
* global, then install the ascendant plugin (Claude Code, Codex, OpenCode)
|
|
5
|
-
* or skill (everything else) into each.
|
|
5
|
+
* or skill (everything else) into each. Built on effect/cli; Node >= 18.
|
|
6
6
|
*
|
|
7
7
|
* The command matrix lives in ../lib/plan.mjs; this file only probes the
|
|
8
8
|
* machine, prompts, and runs the plan.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import { spawnSync } from "node:child_process";
|
|
12
11
|
import { existsSync, readFileSync } from "node:fs";
|
|
13
12
|
import { homedir } from "node:os";
|
|
14
13
|
import path from "node:path";
|
|
15
|
-
import { createInterface } from "node:readline/promises";
|
|
16
14
|
import { fileURLToPath } from "node:url";
|
|
17
|
-
import {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
15
|
+
import { Console, Effect, Option } from "effect";
|
|
16
|
+
import { CliError, Command, Flag, Prompt } from "effect/cli";
|
|
17
|
+
import { ChildProcess, ChildProcessSpawner } from "effect/process";
|
|
18
|
+
// Subpaths, not the barrel: the barrel also loads the socket and HTTP modules,
|
|
19
|
+
// which this CLI never uses. package.json pins @effect/platform-node-shared so
|
|
20
|
+
// a fresh install cannot pair it with a newer, incompatible shared release.
|
|
21
|
+
import * as NodeRuntime from "@effect/platform-node/NodeRuntime";
|
|
22
|
+
import * as NodeServices from "@effect/platform-node/NodeServices";
|
|
23
|
+
import { PROVIDERS, SCOPES, detectProviders, parseProviders, planInstall } from "../lib/plan.mjs";
|
|
24
24
|
|
|
25
25
|
const IS_WINDOWS = process.platform === "win32";
|
|
26
26
|
const PKG = JSON.parse(
|
|
27
27
|
readFileSync(fileURLToPath(new URL("../package.json", import.meta.url)), "utf-8"),
|
|
28
28
|
);
|
|
29
29
|
|
|
30
|
-
const
|
|
30
|
+
const BIN_NAMES = [...new Set([...PROVIDERS.flatMap((p) => p.bins), "npx"])];
|
|
31
|
+
const HOME_DIRS = [...new Set(PROVIDERS.flatMap((p) => p.homeDirs))];
|
|
31
32
|
|
|
32
|
-
|
|
33
|
+
/** Probe PATH and the home directory once; the plan reads the results synchronously. */
|
|
34
|
+
const detectMachine = Effect.sync(() => {
|
|
35
|
+
const exts = IS_WINDOWS ? (process.env.PATHEXT ?? ".EXE;.CMD;.BAT").split(";") : [""];
|
|
36
|
+
const dirs = (process.env.PATH ?? "").split(path.delimiter).filter(Boolean);
|
|
37
|
+
const bins = new Set(
|
|
38
|
+
BIN_NAMES.filter((name) =>
|
|
39
|
+
dirs.some((dir) => exts.some((ext) => existsSync(path.join(dir, name + ext)))),
|
|
40
|
+
),
|
|
41
|
+
);
|
|
42
|
+
const homeDirs = new Set(HOME_DIRS.filter((rel) => existsSync(path.join(homedir(), rel))));
|
|
43
|
+
return {
|
|
44
|
+
hasBin: (name) => bins.has(name),
|
|
45
|
+
hasHomeDir: (rel) => homeDirs.has(rel),
|
|
46
|
+
};
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const opencodeMajor = (machine) =>
|
|
50
|
+
Effect.gen(function* () {
|
|
51
|
+
if (!machine.hasBin("opencode")) return undefined;
|
|
52
|
+
const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
|
|
53
|
+
const out = yield* spawner
|
|
54
|
+
.string(ChildProcess.make("opencode", ["--version"], { shell: IS_WINDOWS }))
|
|
55
|
+
.pipe(Effect.orElseSucceed(() => ""));
|
|
56
|
+
const match = /(\d+)\.\d+/.exec(out);
|
|
57
|
+
return match ? Number(match[1]) : undefined;
|
|
58
|
+
});
|
|
33
59
|
|
|
34
|
-
|
|
35
|
-
|
|
60
|
+
/** Run one plan step with inherited stdio. A missing CLI counts as a failure. */
|
|
61
|
+
const runStep = (step) =>
|
|
62
|
+
Effect.gen(function* () {
|
|
63
|
+
const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
|
|
64
|
+
// Windows CLIs (claude, npx, ...) are .cmd shims that need a shell. Every
|
|
65
|
+
// argument comes from plan.mjs constants, so nothing user-supplied is
|
|
66
|
+
// interpolated into the shell line.
|
|
67
|
+
const code = yield* spawner.exitCode(
|
|
68
|
+
ChildProcess.make(step.command, step.args, {
|
|
69
|
+
shell: IS_WINDOWS,
|
|
70
|
+
stdin: "inherit",
|
|
71
|
+
stdout: "inherit",
|
|
72
|
+
stderr: "inherit",
|
|
73
|
+
}),
|
|
74
|
+
);
|
|
75
|
+
return code === 0;
|
|
76
|
+
}).pipe(Effect.orElseSucceed(() => false));
|
|
36
77
|
|
|
37
|
-
|
|
38
|
-
--providers=<ids> Comma-separated tools, or "all" (default: detected)
|
|
39
|
-
${PROVIDERS.map((p) => p.id).join(", ")}
|
|
40
|
-
--scope=<scope> project | global (default: asks; global with --yes)
|
|
41
|
-
-y, --yes Skip prompts and use the defaults
|
|
42
|
-
--dry-run Print the commands without running them
|
|
43
|
-
-h, --help Show this help
|
|
44
|
-
`;
|
|
78
|
+
const userError = (message) => new CliError.UserError({ cause: message });
|
|
45
79
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
async function choose(opts, detected) {
|
|
69
|
-
const interactive = !opts.yes && process.stdin.isTTY;
|
|
70
|
-
let { providers, scope } = opts;
|
|
71
|
-
|
|
72
|
-
if (!interactive) {
|
|
73
|
-
return { providers: providers ?? detected, scope: scope ?? "global" };
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
77
|
-
try {
|
|
78
|
-
if (!providers) {
|
|
80
|
+
const parseProvidersOrFail = (raw) =>
|
|
81
|
+
Effect.try({
|
|
82
|
+
try: () => parseProviders(raw),
|
|
83
|
+
catch: (error) => userError(error instanceof Error ? error.message : String(error)),
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Fill in providers and scope. Flags win; anything missing is asked for only
|
|
88
|
+
* on an interactive terminal without `--yes`, otherwise the defaults apply.
|
|
89
|
+
* `providersFlag` is the raw `--providers` value, parsed here.
|
|
90
|
+
*/
|
|
91
|
+
const choose = ({ providersFlag, scope, yes, detected }) =>
|
|
92
|
+
Effect.gen(function* () {
|
|
93
|
+
const interactive = !yes && process.stdin.isTTY;
|
|
94
|
+
if (!interactive) {
|
|
95
|
+
const providers =
|
|
96
|
+
providersFlag === undefined ? detected : yield* parseProvidersOrFail(providersFlag);
|
|
97
|
+
return { providers, scope: scope ?? "global" };
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
let providers;
|
|
101
|
+
if (providersFlag === undefined) {
|
|
79
102
|
const names = detected.map((id) => PROVIDERS.find((p) => p.id === id).name);
|
|
80
|
-
|
|
103
|
+
yield* Console.log(
|
|
81
104
|
detected.length > 0 ? `Detected: ${names.join(", ")}` : "No coding tools detected.",
|
|
82
105
|
);
|
|
83
|
-
const raw =
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
106
|
+
const raw = yield* Prompt.run(
|
|
107
|
+
Prompt.String({
|
|
108
|
+
message: `Install for which tools? [${detected.length > 0 ? detected.join(",") : "e.g. claude,cursor"}]`,
|
|
109
|
+
default: detected.join(","),
|
|
110
|
+
}),
|
|
87
111
|
);
|
|
88
|
-
providers = raw === "" ? [] :
|
|
112
|
+
providers = raw.trim() === "" ? [] : yield* parseProvidersOrFail(raw);
|
|
113
|
+
} else {
|
|
114
|
+
providers = yield* parseProvidersOrFail(providersFlag);
|
|
89
115
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
116
|
+
|
|
117
|
+
let chosenScope = scope;
|
|
118
|
+
if (chosenScope === undefined) {
|
|
119
|
+
chosenScope = yield* Prompt.run(
|
|
120
|
+
Prompt.Select({
|
|
121
|
+
message: "Install for this project or globally?",
|
|
122
|
+
choices: [
|
|
123
|
+
{ title: "Globally", value: "global" },
|
|
124
|
+
{ title: "This project", value: "project" },
|
|
125
|
+
],
|
|
126
|
+
}),
|
|
95
127
|
);
|
|
96
|
-
scope = raw.toLowerCase().startsWith("p") ? "project" : "global";
|
|
97
128
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
}
|
|
101
|
-
return { providers, scope };
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
function run(step) {
|
|
105
|
-
// Windows CLIs (claude, npx, ...) are .cmd shims that need a shell. Every
|
|
106
|
-
// argument comes from plan.mjs constants, so nothing user-supplied is
|
|
107
|
-
// interpolated into the shell line.
|
|
108
|
-
const result = spawnSync(step.command, step.args, { stdio: "inherit", shell: IS_WINDOWS });
|
|
109
|
-
return result.status === 0;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
async function main() {
|
|
113
|
-
const opts = parseArgs(process.argv.slice(2));
|
|
114
|
-
if (opts.help || opts.command === undefined) {
|
|
115
|
-
console.log(HELP);
|
|
116
|
-
return opts.help ? 0 : 1;
|
|
117
|
-
}
|
|
118
|
-
if (opts.command !== "install") {
|
|
119
|
-
console.error(`Unknown command: ${opts.command}\n\n${HELP}`);
|
|
120
|
-
return 1;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
const detected = detectProviders({ hasBin, hasHomeDir });
|
|
124
|
-
const { providers, scope } = await choose(opts, detected);
|
|
125
|
-
if (providers.length === 0) {
|
|
126
|
-
console.error(
|
|
127
|
-
"Nothing to install. Pass --providers=<ids>, for example --providers=claude,cursor.",
|
|
128
|
-
);
|
|
129
|
-
return 1;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
const { steps, notes } = planInstall({
|
|
133
|
-
providers,
|
|
134
|
-
scope,
|
|
135
|
-
hasBin,
|
|
136
|
-
opencodeMajor: opencodeMajor(),
|
|
129
|
+
|
|
130
|
+
return { providers, scope: chosenScope };
|
|
137
131
|
});
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
console.error(error instanceof Error ? error.message : error);
|
|
164
|
-
process.exit(1);
|
|
132
|
+
|
|
133
|
+
const install = Command.make(
|
|
134
|
+
"install",
|
|
135
|
+
{
|
|
136
|
+
providers: Flag.optional(
|
|
137
|
+
Flag.String("providers").pipe(
|
|
138
|
+
Flag.withDescription(
|
|
139
|
+
`Comma-separated tools, or "all" (default: detected). Ids: ${PROVIDERS.map((p) => p.id).join(", ")}`,
|
|
140
|
+
),
|
|
141
|
+
),
|
|
142
|
+
),
|
|
143
|
+
scope: Flag.optional(
|
|
144
|
+
Flag.Literals("scope", SCOPES).pipe(
|
|
145
|
+
Flag.withDescription("project | global (default: asks; global with --yes)"),
|
|
146
|
+
),
|
|
147
|
+
),
|
|
148
|
+
yes: Flag.Boolean("yes").pipe(
|
|
149
|
+
Flag.withAlias("y"),
|
|
150
|
+
Flag.withDefault(false),
|
|
151
|
+
Flag.withDescription("Skip prompts and use the defaults"),
|
|
152
|
+
),
|
|
153
|
+
dryRun: Flag.Boolean("dry-run").pipe(
|
|
154
|
+
Flag.withDefault(false),
|
|
155
|
+
Flag.withDescription("Print the commands without running them"),
|
|
156
|
+
),
|
|
165
157
|
},
|
|
158
|
+
({ providers, scope, yes, dryRun }) =>
|
|
159
|
+
Effect.gen(function* () {
|
|
160
|
+
const machine = yield* detectMachine;
|
|
161
|
+
const detected = detectProviders(machine);
|
|
162
|
+
const choice = yield* choose({
|
|
163
|
+
providersFlag: Option.getOrUndefined(providers),
|
|
164
|
+
scope: Option.getOrUndefined(scope),
|
|
165
|
+
yes,
|
|
166
|
+
detected,
|
|
167
|
+
});
|
|
168
|
+
if (choice.providers.length === 0) {
|
|
169
|
+
return yield* Effect.fail(
|
|
170
|
+
userError(
|
|
171
|
+
"Nothing to install. Pass --providers=<ids>, for example --providers=claude,cursor.",
|
|
172
|
+
),
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const { steps, notes } = planInstall({
|
|
177
|
+
providers: choice.providers,
|
|
178
|
+
scope: choice.scope,
|
|
179
|
+
hasBin: machine.hasBin,
|
|
180
|
+
opencodeMajor: yield* opencodeMajor(machine),
|
|
181
|
+
});
|
|
182
|
+
yield* Console.log(
|
|
183
|
+
`\nInstalling ascendant (${choice.scope}) for: ${choice.providers.join(", ")}\n`,
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
const failed = [];
|
|
187
|
+
for (const step of steps) {
|
|
188
|
+
yield* Console.log(`→ ${step.label}\n $ ${[step.command, ...step.args].join(" ")}`);
|
|
189
|
+
if (dryRun) continue;
|
|
190
|
+
if (!(yield* runStep(step))) failed.push(step.label);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
for (const note of notes) yield* Console.log(`\nNote: ${note}`);
|
|
194
|
+
if (failed.length > 0) {
|
|
195
|
+
return yield* Effect.fail(userError(`Failed: ${failed.join("; ")}`));
|
|
196
|
+
}
|
|
197
|
+
if (!dryRun) {
|
|
198
|
+
yield* Console.log(
|
|
199
|
+
"\nDone. Restart your tool, then run /ascendant (Codex: $ascendant) with your birth details.",
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
}),
|
|
203
|
+
).pipe(
|
|
204
|
+
Command.withDescription(
|
|
205
|
+
"Install the Ascendant Vedic astrology skill and plugins into your coding tools.",
|
|
206
|
+
),
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
const root = Command.make("ascendant-skills").pipe(
|
|
210
|
+
Command.withDescription(
|
|
211
|
+
"Install the Ascendant Vedic astrology skill and plugins into your coding tools.",
|
|
212
|
+
),
|
|
213
|
+
Command.withSubcommands([install]),
|
|
214
|
+
);
|
|
215
|
+
|
|
216
|
+
Command.runWith(root, { version: PKG.version })(process.argv.slice(2)).pipe(
|
|
217
|
+
Effect.provide(NodeServices.layer),
|
|
218
|
+
NodeRuntime.runMain,
|
|
166
219
|
);
|
package/lib/plan.mjs
CHANGED
|
@@ -77,60 +77,14 @@ export const PROVIDERS = [
|
|
|
77
77
|
},
|
|
78
78
|
];
|
|
79
79
|
|
|
80
|
-
const PROVIDER_IDS = PROVIDERS.map((p) => p.id);
|
|
81
|
-
const SCOPES = ["project", "global"];
|
|
80
|
+
export const PROVIDER_IDS = PROVIDERS.map((p) => p.id);
|
|
81
|
+
export const SCOPES = ["project", "global"];
|
|
82
82
|
|
|
83
83
|
/**
|
|
84
|
-
* Parse
|
|
85
|
-
*
|
|
86
|
-
*
|
|
84
|
+
* Parse a comma-separated `--providers` value. Throws on an empty value or an
|
|
85
|
+
* unknown id so a typo in a scripted install fails loudly instead of
|
|
86
|
+
* installing nothing. `all` expands to every provider.
|
|
87
87
|
*/
|
|
88
|
-
export function parseArgs(argv) {
|
|
89
|
-
const opts = {
|
|
90
|
-
command: undefined,
|
|
91
|
-
providers: undefined,
|
|
92
|
-
scope: undefined,
|
|
93
|
-
yes: false,
|
|
94
|
-
dryRun: false,
|
|
95
|
-
help: false,
|
|
96
|
-
};
|
|
97
|
-
const args = [...argv];
|
|
98
|
-
while (args.length > 0) {
|
|
99
|
-
const arg = args.shift();
|
|
100
|
-
const [flag, inline] = arg.startsWith("--") ? splitFlag(arg) : [arg, undefined];
|
|
101
|
-
const value = () => inline ?? args.shift();
|
|
102
|
-
switch (flag) {
|
|
103
|
-
case "-h":
|
|
104
|
-
case "--help":
|
|
105
|
-
opts.help = true;
|
|
106
|
-
break;
|
|
107
|
-
case "-y":
|
|
108
|
-
case "--yes":
|
|
109
|
-
opts.yes = true;
|
|
110
|
-
break;
|
|
111
|
-
case "--dry-run":
|
|
112
|
-
opts.dryRun = true;
|
|
113
|
-
break;
|
|
114
|
-
case "--providers":
|
|
115
|
-
opts.providers = parseProviders(value());
|
|
116
|
-
break;
|
|
117
|
-
case "--scope":
|
|
118
|
-
opts.scope = parseScope(value());
|
|
119
|
-
break;
|
|
120
|
-
default:
|
|
121
|
-
if (flag.startsWith("-")) throw new Error(`Unknown option: ${flag}`);
|
|
122
|
-
if (opts.command !== undefined) throw new Error(`Unexpected argument: ${flag}`);
|
|
123
|
-
opts.command = flag;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
return opts;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function splitFlag(arg) {
|
|
130
|
-
const eq = arg.indexOf("=");
|
|
131
|
-
return eq === -1 ? [arg, undefined] : [arg.slice(0, eq), arg.slice(eq + 1)];
|
|
132
|
-
}
|
|
133
|
-
|
|
134
88
|
export function parseProviders(raw) {
|
|
135
89
|
if (!raw) throw new Error(`--providers needs a value: ${PROVIDER_IDS.join(",")} or all`);
|
|
136
90
|
const ids = raw
|
|
@@ -147,12 +101,6 @@ export function parseProviders(raw) {
|
|
|
147
101
|
return [...new Set(ids)];
|
|
148
102
|
}
|
|
149
103
|
|
|
150
|
-
export function parseScope(raw) {
|
|
151
|
-
const scope = raw?.trim().toLowerCase();
|
|
152
|
-
if (!SCOPES.includes(scope)) throw new Error(`--scope must be one of: ${SCOPES.join(", ")}`);
|
|
153
|
-
return scope;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
104
|
/**
|
|
157
105
|
* Which providers are installed, given probes for binaries and home dirs.
|
|
158
106
|
* `hasBin(name)` and `hasHomeDir(relPath)` are injected by the CLI.
|
|
@@ -229,11 +177,14 @@ export function planInstall({ providers, scope, hasBin, opencodeMajor }) {
|
|
|
229
177
|
}
|
|
230
178
|
|
|
231
179
|
if (skillAgents.length > 0) {
|
|
180
|
+
// `npx ascendant-skills` implies npx, but `bunx ascendant-skills` works
|
|
181
|
+
// too and Bun-only machines have no npx to hand off to.
|
|
182
|
+
const [runner, ...runnerArgs] = hasBin("npx") ? ["npx", "-y"] : ["bunx"];
|
|
232
183
|
steps.push({
|
|
233
184
|
label: `Agent Skills: ${skillAgents.join(", ")}`,
|
|
234
|
-
command:
|
|
185
|
+
command: runner,
|
|
235
186
|
args: [
|
|
236
|
-
|
|
187
|
+
...runnerArgs,
|
|
237
188
|
"skills",
|
|
238
189
|
"add",
|
|
239
190
|
REPO,
|
package/package.json
CHANGED
|
@@ -1,37 +1,42 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ascendant-skills",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.2",
|
|
4
4
|
"description": "One command to install the Ascendant Vedic astrology skill and plugins into Claude Code, Codex, OpenCode, Cursor, Gemini CLI and more.",
|
|
5
|
-
"
|
|
6
|
-
|
|
7
|
-
"
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"README.md"
|
|
5
|
+
"keywords": [
|
|
6
|
+
"agent-skills",
|
|
7
|
+
"astrology",
|
|
8
|
+
"claude-code",
|
|
9
|
+
"codex",
|
|
10
|
+
"opencode",
|
|
11
|
+
"vedic astrology"
|
|
13
12
|
],
|
|
14
|
-
"
|
|
15
|
-
"node": ">=18"
|
|
16
|
-
},
|
|
13
|
+
"homepage": "https://astro-ascendant.vercel.app",
|
|
17
14
|
"license": "AGPL-3.0-or-later",
|
|
18
15
|
"author": {
|
|
19
16
|
"name": "Laxman K R",
|
|
20
17
|
"email": "krlaxman03@gmail.com",
|
|
21
18
|
"url": "https://thaletto.vercel.app"
|
|
22
19
|
},
|
|
23
|
-
"homepage": "https://astro-ascendant.vercel.app",
|
|
24
20
|
"repository": {
|
|
25
21
|
"type": "git",
|
|
26
22
|
"url": "https://github.com/astro-ascendant/skills.git",
|
|
27
23
|
"directory": "packages/ascendant-skills"
|
|
28
24
|
},
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
]
|
|
25
|
+
"bin": {
|
|
26
|
+
"ascendant-skills": "bin/cli.mjs"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"bin/",
|
|
30
|
+
"lib/",
|
|
31
|
+
"README.md"
|
|
32
|
+
],
|
|
33
|
+
"type": "module",
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@effect/platform-node": "4.0.5",
|
|
36
|
+
"@effect/platform-node-shared": "4.0.5",
|
|
37
|
+
"effect": "4.0.5"
|
|
38
|
+
},
|
|
39
|
+
"engines": {
|
|
40
|
+
"node": ">=18"
|
|
41
|
+
}
|
|
37
42
|
}
|