primitive-admin 1.1.0-alpha.3 → 1.1.0-alpha.31
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 +168 -21
- package/assets/skill/skills/primitive-platform/SKILL.md +226 -0
- package/dist/bin/primitive.js +198 -15
- package/dist/bin/primitive.js.map +1 -1
- package/dist/src/commands/admins.js +107 -0
- package/dist/src/commands/admins.js.map +1 -1
- package/dist/src/commands/analytics.js +464 -55
- package/dist/src/commands/analytics.js.map +1 -1
- package/dist/src/commands/apps.js +27 -13
- package/dist/src/commands/apps.js.map +1 -1
- package/dist/src/commands/auth.js +165 -5
- package/dist/src/commands/auth.js.map +1 -1
- package/dist/src/commands/blob-buckets.js +354 -0
- package/dist/src/commands/blob-buckets.js.map +1 -0
- package/dist/src/commands/catalog.js +17 -17
- package/dist/src/commands/catalog.js.map +1 -1
- package/dist/src/commands/collection-type-configs.js +178 -0
- package/dist/src/commands/collection-type-configs.js.map +1 -0
- package/dist/src/commands/collections.js +526 -0
- package/dist/src/commands/collections.js.map +1 -0
- package/dist/src/commands/comparisons.js +6 -6
- package/dist/src/commands/comparisons.js.map +1 -1
- package/dist/src/commands/cron-triggers.js +364 -0
- package/dist/src/commands/cron-triggers.js.map +1 -0
- package/dist/src/commands/database-types.js +462 -0
- package/dist/src/commands/database-types.js.map +1 -0
- package/dist/src/commands/databases.js +1067 -58
- package/dist/src/commands/databases.js.map +1 -1
- package/dist/src/commands/documents.js +510 -2
- package/dist/src/commands/documents.js.map +1 -1
- package/dist/src/commands/email-templates.js +281 -0
- package/dist/src/commands/email-templates.js.map +1 -0
- package/dist/src/commands/env.js +260 -0
- package/dist/src/commands/env.js.map +1 -0
- package/dist/src/commands/group-type-configs.js +189 -0
- package/dist/src/commands/group-type-configs.js.map +1 -0
- package/dist/src/commands/groups.js +28 -25
- package/dist/src/commands/groups.js.map +1 -1
- package/dist/src/commands/init.js +719 -188
- package/dist/src/commands/init.js.map +1 -1
- package/dist/src/commands/integrations.js +504 -33
- package/dist/src/commands/integrations.js.map +1 -1
- package/dist/src/commands/prompts.js +17 -16
- package/dist/src/commands/prompts.js.map +1 -1
- package/dist/src/commands/rule-sets.js +366 -0
- package/dist/src/commands/rule-sets.js.map +1 -0
- package/dist/src/commands/secrets.js +108 -0
- package/dist/src/commands/secrets.js.map +1 -0
- package/dist/src/commands/skill.js +29 -0
- package/dist/src/commands/skill.js.map +1 -0
- package/dist/src/commands/sync.js +2363 -182
- package/dist/src/commands/sync.js.map +1 -1
- package/dist/src/commands/tokens.js +9 -9
- package/dist/src/commands/tokens.js.map +1 -1
- package/dist/src/commands/users.js +426 -4
- package/dist/src/commands/users.js.map +1 -1
- package/dist/src/commands/webhooks.js +386 -0
- package/dist/src/commands/webhooks.js.map +1 -0
- package/dist/src/commands/workflows.js +614 -64
- package/dist/src/commands/workflows.js.map +1 -1
- package/dist/src/lib/api-client.js +942 -83
- package/dist/src/lib/api-client.js.map +1 -1
- package/dist/src/lib/config.js +51 -53
- package/dist/src/lib/config.js.map +1 -1
- package/dist/src/lib/constants.js +3 -0
- package/dist/src/lib/constants.js.map +1 -0
- package/dist/src/lib/credentials-store.js +307 -0
- package/dist/src/lib/credentials-store.js.map +1 -0
- package/dist/src/lib/env-resolver.js +121 -0
- package/dist/src/lib/env-resolver.js.map +1 -0
- package/dist/src/lib/init-config.js +87 -0
- package/dist/src/lib/init-config.js.map +1 -0
- package/dist/src/lib/migration-nag.js +163 -0
- package/dist/src/lib/migration-nag.js.map +1 -0
- package/dist/src/lib/output.js +58 -6
- package/dist/src/lib/output.js.map +1 -1
- package/dist/src/lib/paginate.js +42 -0
- package/dist/src/lib/paginate.js.map +1 -0
- package/dist/src/lib/project-config.js +209 -0
- package/dist/src/lib/project-config.js.map +1 -0
- package/dist/src/lib/refresh-admin-credentials.js +103 -0
- package/dist/src/lib/refresh-admin-credentials.js.map +1 -0
- package/dist/src/lib/skill-installer.js +135 -0
- package/dist/src/lib/skill-installer.js.map +1 -0
- package/dist/src/lib/sync-paths.js +102 -0
- package/dist/src/lib/sync-paths.js.map +1 -0
- package/dist/src/lib/template.js +279 -18
- package/dist/src/lib/template.js.map +1 -1
- package/dist/src/lib/toml-database-config.js +384 -0
- package/dist/src/lib/toml-database-config.js.map +1 -0
- package/dist/src/lib/toml-params-validator.js +183 -0
- package/dist/src/lib/toml-params-validator.js.map +1 -0
- package/dist/src/lib/version-check.js +172 -0
- package/dist/src/lib/version-check.js.map +1 -0
- package/dist/src/lib/workflow-fragments.js +121 -0
- package/dist/src/lib/workflow-fragments.js.map +1 -0
- package/dist/src/lib/workflow-toml-validator.js +328 -0
- package/dist/src/lib/workflow-toml-validator.js.map +1 -0
- package/package.json +7 -4
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared helper for refreshing the admin access token via the CLI auth API.
|
|
3
|
+
*
|
|
4
|
+
* Why this module exists:
|
|
5
|
+
*
|
|
6
|
+
* - `ApiClient.refreshToken()` already POSTs to /admin/api/auth/refresh
|
|
7
|
+
* before every API call when the access token is near expiry.
|
|
8
|
+
* - `primitive token` (issue #772) now needs the same exchange so it can
|
|
9
|
+
* auto-refresh a stale token before printing it.
|
|
10
|
+
* - `primitive login --token-stdin` does the same POST a third time to
|
|
11
|
+
* bootstrap credentials from a refresh token piped from another CLI.
|
|
12
|
+
*
|
|
13
|
+
* Putting the HTTP exchange + response parsing in one place keeps the
|
|
14
|
+
* response-shape contract in a single spot (server returns both `jwt` and
|
|
15
|
+
* `accessToken` — see `src/index.ts:2349-2356`) and means future server
|
|
16
|
+
* changes to that endpoint require touching exactly one CLI file.
|
|
17
|
+
*
|
|
18
|
+
* Design notes:
|
|
19
|
+
*
|
|
20
|
+
* - This module **does not** depend on `api-client.ts`. `ApiClient` imports
|
|
21
|
+
* it, not the other way around — that prevents the avoidable module cycle
|
|
22
|
+
* codex flagged in the design review.
|
|
23
|
+
* - It defines its own `RefreshError` so callers can map failures to
|
|
24
|
+
* whatever error type (or exit code) makes sense for their surface.
|
|
25
|
+
* `ApiClient` translates these to `ApiError`; the `token` command
|
|
26
|
+
* translates them to an `error()` + `process.exit(1)`.
|
|
27
|
+
* - It **does not save** the refreshed credentials. The caller decides
|
|
28
|
+
* whether to persist (the `token` command does; `ApiClient.refreshToken`
|
|
29
|
+
* does). Keeping persistence caller-owned matches the existing
|
|
30
|
+
* "storage is owned by `credentials-store.ts`" convention.
|
|
31
|
+
* - It **does not print anything**. Output (success/failure messaging) is
|
|
32
|
+
* the caller's responsibility — important because the `token` command
|
|
33
|
+
* must keep stdout clean for piping.
|
|
34
|
+
*/
|
|
35
|
+
import { fetchWithTLS } from "./fetch.js";
|
|
36
|
+
export class RefreshError extends Error {
|
|
37
|
+
kind;
|
|
38
|
+
statusCode;
|
|
39
|
+
cause;
|
|
40
|
+
constructor(message, kind, statusCode, cause) {
|
|
41
|
+
super(message);
|
|
42
|
+
this.kind = kind;
|
|
43
|
+
this.statusCode = statusCode;
|
|
44
|
+
this.cause = cause;
|
|
45
|
+
this.name = "RefreshError";
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Exchange the stored refresh token for a fresh `accessToken`. Returns a new
|
|
50
|
+
* `Credentials` object — the caller is responsible for persistence via
|
|
51
|
+
* `saveCredentials()` (or whatever storage the caller owns).
|
|
52
|
+
*
|
|
53
|
+
* Server contract: `POST {serverUrl}/admin/api/auth/refresh` with
|
|
54
|
+
* { refreshToken: string }
|
|
55
|
+
* Response (200):
|
|
56
|
+
* { jwt, accessToken, refreshToken, expiresAt }
|
|
57
|
+
*
|
|
58
|
+
* We accept `accessToken` as the canonical field and fall back to `jwt` for
|
|
59
|
+
* forward-compat (the server currently emits both — see issue #772 codex
|
|
60
|
+
* cleanup #3). Login's legacy `data.token` form is dropped — no server
|
|
61
|
+
* version that's still in support emits that field.
|
|
62
|
+
*/
|
|
63
|
+
export async function refreshAdminCredentials(credentials) {
|
|
64
|
+
if (!credentials.refreshToken) {
|
|
65
|
+
throw new RefreshError("No refresh token available. Please login again.", "missing-refresh-token");
|
|
66
|
+
}
|
|
67
|
+
const url = `${credentials.serverUrl}/admin/api/auth/refresh`;
|
|
68
|
+
const headers = {
|
|
69
|
+
"Content-Type": "application/json",
|
|
70
|
+
};
|
|
71
|
+
if (credentials.globalAdminAppId) {
|
|
72
|
+
headers["X-Global-Admin-App-Id"] = credentials.globalAdminAppId;
|
|
73
|
+
}
|
|
74
|
+
let response;
|
|
75
|
+
try {
|
|
76
|
+
response = await fetchWithTLS(url, {
|
|
77
|
+
method: "POST",
|
|
78
|
+
headers,
|
|
79
|
+
body: JSON.stringify({ refreshToken: credentials.refreshToken }),
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
catch (cause) {
|
|
83
|
+
const reason = cause instanceof Error && cause.message
|
|
84
|
+
? cause.message
|
|
85
|
+
: String(cause);
|
|
86
|
+
throw new RefreshError(`Network error refreshing token: ${reason}.`, "network", undefined, cause);
|
|
87
|
+
}
|
|
88
|
+
if (!response.ok) {
|
|
89
|
+
throw new RefreshError("Refresh token expired. Run 'primitive login'.", "unauthorized", response.status);
|
|
90
|
+
}
|
|
91
|
+
const data = (await response.json());
|
|
92
|
+
const accessToken = data?.accessToken || data?.jwt;
|
|
93
|
+
if (!accessToken) {
|
|
94
|
+
throw new RefreshError("Refresh response did not include an access token. Run 'primitive login'.", "unauthorized", response.status);
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
...credentials,
|
|
98
|
+
accessToken,
|
|
99
|
+
refreshToken: data.refreshToken || credentials.refreshToken,
|
|
100
|
+
expiresAt: data.expiresAt || new Date(Date.now() + 3600 * 1000).toISOString(),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=refresh-admin-credentials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refresh-admin-credentials.js","sourceRoot":"","sources":["../../../src/lib/refresh-admin-credentials.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAe1C,MAAM,OAAO,YAAa,SAAQ,KAAK;IAG5B;IACA;IACA;IAJT,YACE,OAAe,EACR,IAAwB,EACxB,UAAmB,EACnB,KAAe;QAEtB,KAAK,CAAC,OAAO,CAAC,CAAC;QAJR,SAAI,GAAJ,IAAI,CAAoB;QACxB,eAAU,GAAV,UAAU,CAAS;QACnB,UAAK,GAAL,KAAK,CAAU;QAGtB,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC;IAC7B,CAAC;CACF;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,WAAwB;IAExB,IAAI,CAAC,WAAW,CAAC,YAAY,EAAE,CAAC;QAC9B,MAAM,IAAI,YAAY,CACpB,iDAAiD,EACjD,uBAAuB,CACxB,CAAC;IACJ,CAAC;IAED,MAAM,GAAG,GAAG,GAAG,WAAW,CAAC,SAAS,yBAAyB,CAAC;IAC9D,MAAM,OAAO,GAA2B;QACtC,cAAc,EAAE,kBAAkB;KACnC,CAAC;IACF,IAAI,WAAW,CAAC,gBAAgB,EAAE,CAAC;QACjC,OAAO,CAAC,uBAAuB,CAAC,GAAG,WAAW,CAAC,gBAAgB,CAAC;IAClE,CAAC;IAED,IAAI,QAAkD,CAAC;IACvD,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,YAAY,CAAC,GAAG,EAAE;YACjC,MAAM,EAAE,MAAM;YACd,OAAO;YACP,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,YAAY,EAAE,WAAW,CAAC,YAAY,EAAE,CAAC;SACjE,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,MAAM,GACV,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,OAAO;YACrC,CAAC,CAAC,KAAK,CAAC,OAAO;YACf,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACpB,MAAM,IAAI,YAAY,CACpB,mCAAmC,MAAM,GAAG,EAC5C,SAAS,EACT,SAAS,EACT,KAAK,CACN,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,YAAY,CACpB,+CAA+C,EAC/C,cAAc,EACd,QAAQ,CAAC,MAAM,CAChB,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAQ,CAAC;IAC5C,MAAM,WAAW,GAAuB,IAAI,EAAE,WAAW,IAAI,IAAI,EAAE,GAAG,CAAC;IACvE,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,MAAM,IAAI,YAAY,CACpB,0EAA0E,EAC1E,cAAc,EACd,QAAQ,CAAC,MAAM,CAChB,CAAC;IACJ,CAAC;IAED,OAAO;QACL,GAAG,WAAW;QACd,WAAW;QACX,YAAY,EAAE,IAAI,CAAC,YAAY,IAAI,WAAW,CAAC,YAAY;QAC3D,SAAS,EACP,IAAI,CAAC,SAAS,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE;KACrE,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync, rmSync } from "fs";
|
|
2
|
+
import { readFile } from "fs/promises";
|
|
3
|
+
import { createHash } from "crypto";
|
|
4
|
+
import { homedir } from "os";
|
|
5
|
+
import { join, dirname } from "path";
|
|
6
|
+
import { fileURLToPath } from "url";
|
|
7
|
+
import chalk from "chalk";
|
|
8
|
+
const CLAUDE_DIR = join(homedir(), ".claude");
|
|
9
|
+
const SKILLS_DIR = join(CLAUDE_DIR, "skills");
|
|
10
|
+
const SKILL_DIR = join(SKILLS_DIR, "primitive-platform");
|
|
11
|
+
const SKILL_FILE = join(SKILL_DIR, "SKILL.md");
|
|
12
|
+
const HASH_FILE = join(SKILL_DIR, ".version");
|
|
13
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
14
|
+
function getBundledSkillPath() {
|
|
15
|
+
// In dist: dist/src/lib/skill-installer.js -> ../../../assets/...
|
|
16
|
+
// In source (tsx): src/lib/skill-installer.ts -> ../../assets/...
|
|
17
|
+
const distPath = fileURLToPath(new URL("../../../assets/skill/skills/primitive-platform/SKILL.md", import.meta.url));
|
|
18
|
+
if (existsSync(distPath))
|
|
19
|
+
return distPath;
|
|
20
|
+
return fileURLToPath(new URL("../../assets/skill/skills/primitive-platform/SKILL.md", import.meta.url));
|
|
21
|
+
}
|
|
22
|
+
function computeHash(content) {
|
|
23
|
+
return createHash("sha256").update(content).digest("hex").slice(0, 12);
|
|
24
|
+
}
|
|
25
|
+
function getInstalledHash() {
|
|
26
|
+
try {
|
|
27
|
+
if (!existsSync(HASH_FILE))
|
|
28
|
+
return null;
|
|
29
|
+
return readFileSync(HASH_FILE, "utf-8").trim();
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Returns true if the skill is currently installed.
|
|
37
|
+
*/
|
|
38
|
+
export function isSkillInstalled() {
|
|
39
|
+
return getInstalledHash() !== null;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Auto-update an already-installed skill if a newer version is bundled.
|
|
43
|
+
* Called after command execution for non-init, non-skill commands.
|
|
44
|
+
* If the skill is not installed, shows a non-blocking hint instead.
|
|
45
|
+
* Never throws — fails silently like version-check.
|
|
46
|
+
*/
|
|
47
|
+
export async function checkSkillStatus() {
|
|
48
|
+
try {
|
|
49
|
+
const bundledPath = getBundledSkillPath();
|
|
50
|
+
if (!existsSync(bundledPath))
|
|
51
|
+
return;
|
|
52
|
+
if (!existsSync(CLAUDE_DIR))
|
|
53
|
+
return;
|
|
54
|
+
const bundledContent = await readFile(bundledPath, "utf-8");
|
|
55
|
+
const bundledHash = computeHash(bundledContent);
|
|
56
|
+
const installedHash = getInstalledHash();
|
|
57
|
+
if (installedHash) {
|
|
58
|
+
// Already installed — silently auto-update if needed
|
|
59
|
+
if (installedHash === bundledHash)
|
|
60
|
+
return;
|
|
61
|
+
mkdirSync(SKILL_DIR, { recursive: true });
|
|
62
|
+
writeFileSync(SKILL_FILE, bundledContent);
|
|
63
|
+
writeFileSync(HASH_FILE, bundledHash);
|
|
64
|
+
console.log(chalk.dim("Updated Primitive platform skill for Claude Code"));
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
// Not installed — show a non-blocking hint
|
|
68
|
+
console.log(chalk.dim(`Claude Code skill available — run ${chalk.cyan("primitive skill install")} to set up`));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
// Never let skill check affect CLI operation
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Explicitly install or reinstall the skill. Shows output.
|
|
77
|
+
*/
|
|
78
|
+
export function installSkillExplicit() {
|
|
79
|
+
const bundledPath = getBundledSkillPath();
|
|
80
|
+
if (!existsSync(bundledPath)) {
|
|
81
|
+
console.error(chalk.red("Skill assets not found. Reinstall the CLI."));
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
if (!existsSync(CLAUDE_DIR)) {
|
|
85
|
+
console.error(chalk.red("Claude Code not found (~/.claude does not exist)."));
|
|
86
|
+
console.error(chalk.dim("Install Claude Code first: https://claude.ai/code"));
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
const bundledContent = readFileSync(bundledPath, "utf-8");
|
|
90
|
+
const bundledHash = computeHash(bundledContent);
|
|
91
|
+
mkdirSync(SKILL_DIR, { recursive: true });
|
|
92
|
+
writeFileSync(SKILL_FILE, bundledContent);
|
|
93
|
+
writeFileSync(HASH_FILE, bundledHash);
|
|
94
|
+
console.log(chalk.green("Primitive platform skill installed for Claude Code."));
|
|
95
|
+
console.log(chalk.dim(`Location: ${SKILL_FILE}`));
|
|
96
|
+
console.log(chalk.dim(`Version: ${bundledHash}`));
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Uninstall the skill.
|
|
101
|
+
*/
|
|
102
|
+
export function uninstallSkill() {
|
|
103
|
+
if (!existsSync(SKILL_DIR)) {
|
|
104
|
+
console.log(chalk.dim("Skill is not installed."));
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
107
|
+
rmSync(SKILL_DIR, { recursive: true });
|
|
108
|
+
console.log(chalk.green("Primitive platform skill uninstalled."));
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Show current skill installation status.
|
|
113
|
+
*/
|
|
114
|
+
export function skillStatus() {
|
|
115
|
+
const installedHash = getInstalledHash();
|
|
116
|
+
const bundledPath = getBundledSkillPath();
|
|
117
|
+
const bundledHash = existsSync(bundledPath)
|
|
118
|
+
? computeHash(readFileSync(bundledPath, "utf-8"))
|
|
119
|
+
: null;
|
|
120
|
+
if (!installedHash) {
|
|
121
|
+
console.log(chalk.yellow("Skill is not installed."));
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
console.log(chalk.green("Skill is installed."));
|
|
125
|
+
console.log(chalk.dim(` Location: ${SKILL_FILE}`));
|
|
126
|
+
console.log(chalk.dim(` Version: ${installedHash}`));
|
|
127
|
+
}
|
|
128
|
+
if (bundledHash) {
|
|
129
|
+
console.log(chalk.dim(` Bundled: ${bundledHash}`));
|
|
130
|
+
if (installedHash && installedHash !== bundledHash) {
|
|
131
|
+
console.log(chalk.yellow(" Update available — run: primitive skill install"));
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=skill-installer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-installer.js","sourceRoot":"","sources":["../../../src/lib/skill-installer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sync data path resolution.
|
|
3
|
+
*
|
|
4
|
+
* Per issue #373, sync state is scoped by environment AND by app:
|
|
5
|
+
*
|
|
6
|
+
* <projectRoot>/.primitive/sync/<env>/<appId>/
|
|
7
|
+
*
|
|
8
|
+
* This ensures that switching environments (dev -> prod) or apps never
|
|
9
|
+
* clobbers sync state from another slot. Push to dev and then to prod
|
|
10
|
+
* see independent "last synced" pointers, so prod won't falsely believe
|
|
11
|
+
* dev's changes are already in sync.
|
|
12
|
+
*
|
|
13
|
+
* When the user still passes `--dir <path>` (the legacy flag) we honor
|
|
14
|
+
* it and store sync state inside that directory, same as before. This
|
|
15
|
+
* keeps pre-project-config workflows working.
|
|
16
|
+
*/
|
|
17
|
+
import { existsSync, mkdirSync } from "fs";
|
|
18
|
+
import { join } from "path";
|
|
19
|
+
import { getCurrentEnvironment } from "./env-resolver.js";
|
|
20
|
+
/**
|
|
21
|
+
* Returns the directory that should hold TOML files + sync state for the
|
|
22
|
+
* current sync operation.
|
|
23
|
+
*
|
|
24
|
+
* Resolution order:
|
|
25
|
+
* 1. If userDir is set, return it as-is (legacy behavior).
|
|
26
|
+
* 2. If we're in project mode, return
|
|
27
|
+
* <projectRoot>/.primitive/sync/<env>/<appId>
|
|
28
|
+
* 3. Otherwise fall back to "./config" (the old default).
|
|
29
|
+
*/
|
|
30
|
+
export function resolveSyncDir(options) {
|
|
31
|
+
if (options.userDir)
|
|
32
|
+
return options.userDir;
|
|
33
|
+
const env = safeEnv();
|
|
34
|
+
if (env) {
|
|
35
|
+
// Defence-in-depth: appId is expected to be a ULID from the server, but
|
|
36
|
+
// we must never trust it blindly when building file-system paths. Reject
|
|
37
|
+
// anything that contains path separators or `..` sequences before
|
|
38
|
+
// joining it into <projectRoot>/.primitive/sync/...
|
|
39
|
+
assertSafePathComponent(options.appId, "appId");
|
|
40
|
+
return join(env.projectRoot, ".primitive", "sync", env.name, options.appId);
|
|
41
|
+
}
|
|
42
|
+
return "./config";
|
|
43
|
+
}
|
|
44
|
+
function assertSafePathComponent(value, label) {
|
|
45
|
+
if (typeof value !== "string" ||
|
|
46
|
+
value.length === 0 ||
|
|
47
|
+
/[\\/]/.test(value) ||
|
|
48
|
+
value.includes("..") ||
|
|
49
|
+
value === "." ||
|
|
50
|
+
value === "") {
|
|
51
|
+
throw new Error(`Invalid ${label} for file path: ${value}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Returns true if the path we'd use for sync data is the auto-resolved
|
|
56
|
+
* project-mode path (vs. a user-supplied --dir).
|
|
57
|
+
*/
|
|
58
|
+
export function isAutoResolvedSyncDir(userDir) {
|
|
59
|
+
if (userDir)
|
|
60
|
+
return false;
|
|
61
|
+
return safeEnv() !== null;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Ensures the sync directory exists, creating it (and parents) if
|
|
65
|
+
* necessary. Returns the path.
|
|
66
|
+
*/
|
|
67
|
+
export function ensureSyncDir(options) {
|
|
68
|
+
const dir = resolveSyncDir(options);
|
|
69
|
+
if (!existsSync(dir)) {
|
|
70
|
+
mkdirSync(dir, { recursive: true });
|
|
71
|
+
}
|
|
72
|
+
return dir;
|
|
73
|
+
}
|
|
74
|
+
function safeEnv() {
|
|
75
|
+
try {
|
|
76
|
+
return getCurrentEnvironment();
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Checks whether an old-style sync state file exists at `./config/.primitive-sync.json`
|
|
84
|
+
* (the pre-project-config default path). Returns a warning message if found and
|
|
85
|
+
* the current operation is using a different (project-mode) path, or null otherwise.
|
|
86
|
+
*
|
|
87
|
+
* Callers can display this once at the start of sync commands so users know
|
|
88
|
+
* their old sync data won't be picked up automatically.
|
|
89
|
+
*/
|
|
90
|
+
export function checkLegacySyncMigration(currentSyncDir) {
|
|
91
|
+
const legacySync = join(".", "config", ".primitive-sync.json");
|
|
92
|
+
if (!existsSync(legacySync))
|
|
93
|
+
return null;
|
|
94
|
+
// Only warn if the resolved dir is different from the legacy default.
|
|
95
|
+
const legacyDir = join(".", "config");
|
|
96
|
+
if (currentSyncDir === legacyDir)
|
|
97
|
+
return null;
|
|
98
|
+
return (`Detected old sync state at ./config/.primitive-sync.json. ` +
|
|
99
|
+
`Sync data now lives at ${currentSyncDir}. ` +
|
|
100
|
+
`Run 'primitive sync pull' to re-sync into the new location.`);
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=sync-paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-paths.js","sourceRoot":"","sources":["../../../src/lib/sync-paths.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAY1D;;;;;;;;;GASG;AACH,MAAM,UAAU,cAAc,CAAC,OAA8B;IAC3D,IAAI,OAAO,CAAC,OAAO;QAAE,OAAO,OAAO,CAAC,OAAO,CAAC;IAE5C,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC;IACtB,IAAI,GAAG,EAAE,CAAC;QACR,wEAAwE;QACxE,yEAAyE;QACzE,kEAAkE;QAClE,oDAAoD;QACpD,uBAAuB,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAChD,OAAO,IAAI,CACT,GAAG,CAAC,WAAW,EACf,YAAY,EACZ,MAAM,EACN,GAAG,CAAC,IAAI,EACR,OAAO,CAAC,KAAK,CACd,CAAC;IACJ,CAAC;IAED,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,SAAS,uBAAuB,CAAC,KAAa,EAAE,KAAa;IAC3D,IACE,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,CAAC,MAAM,KAAK,CAAC;QAClB,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC;QACnB,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC;QACpB,KAAK,KAAK,GAAG;QACb,KAAK,KAAK,EAAE,EACZ,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,WAAW,KAAK,mBAAmB,KAAK,EAAE,CAAC,CAAC;IAC9D,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,OAA2B;IAC/D,IAAI,OAAO;QAAE,OAAO,KAAK,CAAC;IAC1B,OAAO,OAAO,EAAE,KAAK,IAAI,CAAC;AAC5B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,OAA8B;IAC1D,MAAM,GAAG,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;IACpC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACrB,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACtC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,OAAO;IACd,IAAI,CAAC;QACH,OAAO,qBAAqB,EAAE,CAAC;IACjC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,wBAAwB,CAAC,cAAsB;IAC7D,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,QAAQ,EAAE,sBAAsB,CAAC,CAAC;IAC/D,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,OAAO,IAAI,CAAC;IACzC,sEAAsE;IACtE,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IACtC,IAAI,cAAc,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IAC9C,OAAO,CACL,4DAA4D;QAC5D,0BAA0B,cAAc,IAAI;QAC5C,6DAA6D,CAC9D,CAAC;AACJ,CAAC"}
|