@urateam/cli 0.1.39 → 0.1.40
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/__tests__/init.test.d.ts +2 -0
- package/dist/__tests__/init.test.d.ts.map +1 -0
- package/dist/__tests__/init.test.js +65 -0
- package/dist/__tests__/init.test.js.map +1 -0
- package/dist/__tests__/repo.test.d.ts +2 -0
- package/dist/__tests__/repo.test.d.ts.map +1 -0
- package/dist/__tests__/repo.test.js +191 -0
- package/dist/__tests__/repo.test.js.map +1 -0
- package/dist/__tests__/start-user-level-fallback.test.d.ts +2 -0
- package/dist/__tests__/start-user-level-fallback.test.d.ts.map +1 -0
- package/dist/__tests__/start-user-level-fallback.test.js +191 -0
- package/dist/__tests__/start-user-level-fallback.test.js.map +1 -0
- package/dist/__tests__/uninstall.test.d.ts +2 -0
- package/dist/__tests__/uninstall.test.d.ts.map +1 -0
- package/dist/__tests__/uninstall.test.js +51 -0
- package/dist/__tests__/uninstall.test.js.map +1 -0
- package/dist/__tests__/user-level-config.test.d.ts +2 -0
- package/dist/__tests__/user-level-config.test.d.ts.map +1 -0
- package/dist/__tests__/user-level-config.test.js +92 -0
- package/dist/__tests__/user-level-config.test.js.map +1 -0
- package/dist/commands/init.d.ts +11 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +27 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/repo.d.ts +7 -0
- package/dist/commands/repo.d.ts.map +1 -0
- package/dist/commands/repo.js +126 -0
- package/dist/commands/repo.js.map +1 -0
- package/dist/commands/start.d.ts.map +1 -1
- package/dist/commands/start.js +25 -0
- package/dist/commands/start.js.map +1 -1
- package/dist/commands/uninstall.d.ts +17 -0
- package/dist/commands/uninstall.d.ts.map +1 -0
- package/dist/commands/uninstall.js +38 -0
- package/dist/commands/uninstall.js.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/build-repo-configs.d.ts.map +1 -1
- package/dist/lib/build-repo-configs.js +85 -27
- package/dist/lib/build-repo-configs.js.map +1 -1
- package/dist/lib/user-level-config.d.ts +70 -0
- package/dist/lib/user-level-config.d.ts.map +1 -0
- package/dist/lib/user-level-config.js +91 -0
- package/dist/lib/user-level-config.js.map +1 -0
- package/package.json +4 -3
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { repoPluginsFromEnv } from "./repo-plugins-from-env.js";
|
|
2
|
+
import { readUserLevelConfig } from "./user-level-config.js";
|
|
2
3
|
function parseCsv(raw) {
|
|
3
4
|
return raw.split(",").filter(Boolean);
|
|
4
5
|
}
|
|
@@ -24,32 +25,69 @@ function parseCsv(raw) {
|
|
|
24
25
|
*/
|
|
25
26
|
export function buildRepoConfigsFromEnv() {
|
|
26
27
|
const repoConfigs = {};
|
|
27
|
-
if (
|
|
28
|
+
if (process.env.REPO_TEAM_ID && process.env.REPO_URL) {
|
|
29
|
+
const repoEntry = {
|
|
30
|
+
url: process.env.REPO_URL,
|
|
31
|
+
defaultBranch: process.env.REPO_DEFAULT_BRANCH ?? "main",
|
|
32
|
+
testCommand: process.env.REPO_TEST_CMD ?? "pnpm test",
|
|
33
|
+
buildCommand: process.env.REPO_BUILD_CMD ?? "pnpm build",
|
|
34
|
+
};
|
|
35
|
+
if (process.env.GITHUB_WEBHOOK_SECRET) {
|
|
36
|
+
repoEntry.githubFeedback = {
|
|
37
|
+
autoTrigger: process.env.GITHUB_FEEDBACK_AUTO_TRIGGER !== "false",
|
|
38
|
+
triggerKeyword: process.env.GITHUB_FEEDBACK_TRIGGER_KEYWORD,
|
|
39
|
+
allowedReviewers: process.env.GITHUB_FEEDBACK_ALLOWED_REVIEWERS
|
|
40
|
+
? parseCsv(process.env.GITHUB_FEEDBACK_ALLOWED_REVIEWERS)
|
|
41
|
+
: undefined,
|
|
42
|
+
botLogins: process.env.GITHUB_FEEDBACK_BOT_LOGINS
|
|
43
|
+
? parseCsv(process.env.GITHUB_FEEDBACK_BOT_LOGINS)
|
|
44
|
+
: undefined,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
const pluginCfg = repoPluginsFromEnv();
|
|
48
|
+
if (pluginCfg)
|
|
49
|
+
repoEntry.plugins = pluginCfg;
|
|
50
|
+
repoConfigs[process.env.REPO_TEAM_ID] = repoEntry;
|
|
51
|
+
return repoConfigs;
|
|
52
|
+
}
|
|
53
|
+
// User-level fallback: when no REPO_* env vars produced anything, try
|
|
54
|
+
// ~/.urateam/config.json (or $URATEAM_HOME/config.json). This is what
|
|
55
|
+
// makes the `ura init` + `ura repo add` path usable end-to-end without
|
|
56
|
+
// operators having to hand-craft env vars.
|
|
57
|
+
//
|
|
58
|
+
// Read failures (malformed JSON, schema-validation error) bubble up —
|
|
59
|
+
// the operator should see the error explicitly rather than silently get
|
|
60
|
+
// an unconfigured daemon.
|
|
61
|
+
const userConfig = readUserLevelConfig();
|
|
62
|
+
if (!userConfig || userConfig.repos.length === 0)
|
|
28
63
|
return repoConfigs;
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
repoEntry.githubFeedback = {
|
|
37
|
-
autoTrigger: process.env.GITHUB_FEEDBACK_AUTO_TRIGGER !== "false",
|
|
38
|
-
triggerKeyword: process.env.GITHUB_FEEDBACK_TRIGGER_KEYWORD,
|
|
39
|
-
allowedReviewers: process.env.GITHUB_FEEDBACK_ALLOWED_REVIEWERS
|
|
40
|
-
? parseCsv(process.env.GITHUB_FEEDBACK_ALLOWED_REVIEWERS)
|
|
41
|
-
: undefined,
|
|
42
|
-
botLogins: process.env.GITHUB_FEEDBACK_BOT_LOGINS
|
|
43
|
-
? parseCsv(process.env.GITHUB_FEEDBACK_BOT_LOGINS)
|
|
44
|
-
: undefined,
|
|
64
|
+
for (const repo of userConfig.repos) {
|
|
65
|
+
const entry = {
|
|
66
|
+
url: repo.url,
|
|
67
|
+
defaultBranch: repo.defaultBranch,
|
|
68
|
+
testCommand: repo.testCommand,
|
|
69
|
+
buildCommand: repo.buildCommand,
|
|
70
|
+
...(repo.labelPattern && { labelPattern: repo.labelPattern }),
|
|
45
71
|
};
|
|
72
|
+
// Key by teamId when present (matches the existing env-var schema);
|
|
73
|
+
// fall back to a slug derived from the URL so config.json entries
|
|
74
|
+
// without a teamId still get a stable key.
|
|
75
|
+
const key = repo.teamId ?? deriveKeyFromUrl(repo.url);
|
|
76
|
+
repoConfigs[key] = entry;
|
|
46
77
|
}
|
|
47
|
-
const pluginCfg = repoPluginsFromEnv();
|
|
48
|
-
if (pluginCfg)
|
|
49
|
-
repoEntry.plugins = pluginCfg;
|
|
50
|
-
repoConfigs[process.env.REPO_TEAM_ID] = repoEntry;
|
|
51
78
|
return repoConfigs;
|
|
52
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* Derive a synthetic Record key from a repo URL when the user-level config
|
|
82
|
+
* entry omits `teamId`. Mirrors the slug logic in `commands/repo.ts` but
|
|
83
|
+
* lives here too so this file doesn't import from a sibling that pulls in
|
|
84
|
+
* commander.
|
|
85
|
+
*/
|
|
86
|
+
function deriveKeyFromUrl(url) {
|
|
87
|
+
const stripped = url.replace(/\.git$/, "");
|
|
88
|
+
const last = stripped.split(/[/:]/).filter(Boolean).pop() ?? "repo";
|
|
89
|
+
return last.replace(/[^A-Za-z0-9._-]/g, "-");
|
|
90
|
+
}
|
|
53
91
|
/**
|
|
54
92
|
* Fail-fast guard: exits 1 with a clear operator-actionable error if
|
|
55
93
|
* `repoConfigs` is empty.
|
|
@@ -62,12 +100,32 @@ export function buildRepoConfigsFromEnv() {
|
|
|
62
100
|
export function requireRepoConfigs(repoConfigs, command) {
|
|
63
101
|
if (Object.keys(repoConfigs).length > 0)
|
|
64
102
|
return;
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
103
|
+
// Branch the error message based on whether `ura init` has been run.
|
|
104
|
+
// Users on the user-level install path who forgot `ura repo add` need
|
|
105
|
+
// very different advice than project-level operators who forgot the
|
|
106
|
+
// env vars.
|
|
107
|
+
const userConfig = readUserLevelConfig();
|
|
108
|
+
if (userConfig) {
|
|
109
|
+
// `ura init` has run; they just need to add a repo.
|
|
110
|
+
console.error(`Error: no repos configured in ${process.env.URATEAM_HOME ?? "~/.urateam"}/config.json.\n` +
|
|
111
|
+
"Run 'ura repo add <url> [--team <linear-team-id>]' to register a repo.\n" +
|
|
112
|
+
"Example:\n" +
|
|
113
|
+
" ura repo add https://github.com/org/repo.git --team team-uuid\n" +
|
|
114
|
+
`\n(command: ${command})\n`);
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
console.error("Error: no repoConfigs could be built.\n" +
|
|
118
|
+
"Two install paths exist:\n\n" +
|
|
119
|
+
" Project-level (sidecar, env-var-driven):\n" +
|
|
120
|
+
" Set REPO_TEAM_ID and REPO_URL in .urateam/.env and restart.\n" +
|
|
121
|
+
" Example:\n" +
|
|
122
|
+
" REPO_TEAM_ID=<your Linear team UUID — usually the same as LINEAR_TEAM_ID>\n" +
|
|
123
|
+
" REPO_URL=https://github.com/org/repo\n\n" +
|
|
124
|
+
" User-level (~/.urateam config-file-driven):\n" +
|
|
125
|
+
" Run 'ura init' then 'ura repo add <url> --team <id>'.\n" +
|
|
126
|
+
" See deploy/USER_LEVEL_INSTALL.md.\n" +
|
|
127
|
+
`\n(command: ${command})\n`);
|
|
128
|
+
}
|
|
71
129
|
process.exit(1);
|
|
72
130
|
}
|
|
73
131
|
//# sourceMappingURL=build-repo-configs.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build-repo-configs.js","sourceRoot":"","sources":["../../src/lib/build-repo-configs.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"build-repo-configs.js","sourceRoot":"","sources":["../../src/lib/build-repo-configs.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* User-level install — config schema, on-disk locations, read/write helpers.
|
|
3
|
+
*
|
|
4
|
+
* The user-level path stores everything under `~/.urateam/` (or
|
|
5
|
+
* `$URATEAM_HOME` when set). Layout:
|
|
6
|
+
*
|
|
7
|
+
* ~/.urateam/
|
|
8
|
+
* ├── config.json # this module's schema
|
|
9
|
+
* ├── .env # secrets (ANTHROPIC_API_KEY, etc.)
|
|
10
|
+
* ├── data/ # SQLite DB lives here
|
|
11
|
+
* └── repos/ # cloned repos managed by `ura repo add`
|
|
12
|
+
*
|
|
13
|
+
* The schema intentionally mirrors the existing `RepoConfig` shape (`url`,
|
|
14
|
+
* `defaultBranch`, `testCommand`, `buildCommand`, optional `labelPattern`)
|
|
15
|
+
* plus a `path` field that records WHERE the clone lives — that's the
|
|
16
|
+
* field the daemon needs to actually find the worktree.
|
|
17
|
+
*
|
|
18
|
+
* `URATEAM_HOME` env-var override exists for two reasons:
|
|
19
|
+
* 1. Tests (hermetic temp dir per test)
|
|
20
|
+
* 2. Operators who want to run multiple isolated user-level installs on
|
|
21
|
+
* one machine (e.g., one per Linear workspace) without touching
|
|
22
|
+
* `~/.urateam/`.
|
|
23
|
+
*/
|
|
24
|
+
import { z } from "zod";
|
|
25
|
+
export declare const UserLevelRepoSchema: z.ZodObject<{
|
|
26
|
+
url: z.ZodString;
|
|
27
|
+
path: z.ZodString;
|
|
28
|
+
defaultBranch: z.ZodString;
|
|
29
|
+
testCommand: z.ZodDefault<z.ZodString>;
|
|
30
|
+
buildCommand: z.ZodDefault<z.ZodString>;
|
|
31
|
+
teamId: z.ZodOptional<z.ZodString>;
|
|
32
|
+
labelPattern: z.ZodOptional<z.ZodString>;
|
|
33
|
+
}, z.core.$strip>;
|
|
34
|
+
export type UserLevelRepo = z.infer<typeof UserLevelRepoSchema>;
|
|
35
|
+
export declare const UserLevelConfigSchema: z.ZodObject<{
|
|
36
|
+
version: z.ZodLiteral<1>;
|
|
37
|
+
repos: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
38
|
+
url: z.ZodString;
|
|
39
|
+
path: z.ZodString;
|
|
40
|
+
defaultBranch: z.ZodString;
|
|
41
|
+
testCommand: z.ZodDefault<z.ZodString>;
|
|
42
|
+
buildCommand: z.ZodDefault<z.ZodString>;
|
|
43
|
+
teamId: z.ZodOptional<z.ZodString>;
|
|
44
|
+
labelPattern: z.ZodOptional<z.ZodString>;
|
|
45
|
+
}, z.core.$strip>>>;
|
|
46
|
+
}, z.core.$strip>;
|
|
47
|
+
export type UserLevelConfig = z.infer<typeof UserLevelConfigSchema>;
|
|
48
|
+
/**
|
|
49
|
+
* Resolve the user-level state directory. Returns `$URATEAM_HOME` when set,
|
|
50
|
+
* otherwise `~/.urateam`.
|
|
51
|
+
*/
|
|
52
|
+
export declare function resolveUserLevelHome(): string;
|
|
53
|
+
export declare function userLevelConfigPath(): string;
|
|
54
|
+
export declare function userLevelReposDir(): string;
|
|
55
|
+
export declare function userLevelDataDir(): string;
|
|
56
|
+
/**
|
|
57
|
+
* Read and validate the user-level config. Returns `null` when the file
|
|
58
|
+
* doesn't exist (so callers can distinguish "not initialized" from "empty
|
|
59
|
+
* config"). Throws on schema-validation failure — operators should see the
|
|
60
|
+
* Zod error explicitly rather than silently get an unconfigured daemon.
|
|
61
|
+
*/
|
|
62
|
+
export declare function readUserLevelConfig(): UserLevelConfig | null;
|
|
63
|
+
/**
|
|
64
|
+
* Write the user-level config, creating `~/.urateam/` if missing.
|
|
65
|
+
* Idempotent: callers are expected to read-modify-write to preserve any
|
|
66
|
+
* fields the writer doesn't know about (the schema is forward-compatible
|
|
67
|
+
* within version 1).
|
|
68
|
+
*/
|
|
69
|
+
export declare function writeUserLevelConfig(config: UserLevelConfig): void;
|
|
70
|
+
//# sourceMappingURL=user-level-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"user-level-config.d.ts","sourceRoot":"","sources":["../../src/lib/user-level-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,eAAO,MAAM,mBAAmB;;;;;;;;iBAgB9B,CAAC;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,eAAO,MAAM,qBAAqB;;;;;;;;;;;iBAKhC,CAAC;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C;AAED,wBAAgB,mBAAmB,IAAI,MAAM,CAE5C;AAED,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,IAAI,eAAe,GAAG,IAAI,CAK5D;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAIlE"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* User-level install — config schema, on-disk locations, read/write helpers.
|
|
3
|
+
*
|
|
4
|
+
* The user-level path stores everything under `~/.urateam/` (or
|
|
5
|
+
* `$URATEAM_HOME` when set). Layout:
|
|
6
|
+
*
|
|
7
|
+
* ~/.urateam/
|
|
8
|
+
* ├── config.json # this module's schema
|
|
9
|
+
* ├── .env # secrets (ANTHROPIC_API_KEY, etc.)
|
|
10
|
+
* ├── data/ # SQLite DB lives here
|
|
11
|
+
* └── repos/ # cloned repos managed by `ura repo add`
|
|
12
|
+
*
|
|
13
|
+
* The schema intentionally mirrors the existing `RepoConfig` shape (`url`,
|
|
14
|
+
* `defaultBranch`, `testCommand`, `buildCommand`, optional `labelPattern`)
|
|
15
|
+
* plus a `path` field that records WHERE the clone lives — that's the
|
|
16
|
+
* field the daemon needs to actually find the worktree.
|
|
17
|
+
*
|
|
18
|
+
* `URATEAM_HOME` env-var override exists for two reasons:
|
|
19
|
+
* 1. Tests (hermetic temp dir per test)
|
|
20
|
+
* 2. Operators who want to run multiple isolated user-level installs on
|
|
21
|
+
* one machine (e.g., one per Linear workspace) without touching
|
|
22
|
+
* `~/.urateam/`.
|
|
23
|
+
*/
|
|
24
|
+
import { z } from "zod";
|
|
25
|
+
import { homedir } from "node:os";
|
|
26
|
+
import { join } from "node:path";
|
|
27
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "node:fs";
|
|
28
|
+
export const UserLevelRepoSchema = z.object({
|
|
29
|
+
/** Source URL (https / git@ — anything `git clone` accepts). */
|
|
30
|
+
url: z.string().min(1),
|
|
31
|
+
/** Absolute filesystem path where the clone lives. */
|
|
32
|
+
path: z.string().min(1),
|
|
33
|
+
/** Default branch — the daemon uses this for diff/rebase targets. */
|
|
34
|
+
defaultBranch: z.string().min(1),
|
|
35
|
+
/** Test command invoked in the worktree. */
|
|
36
|
+
testCommand: z.string().default("pnpm test"),
|
|
37
|
+
/** Build command invoked in the worktree. */
|
|
38
|
+
buildCommand: z.string().default("pnpm build"),
|
|
39
|
+
/** Linear team ID (optional — required when promote routes by team). */
|
|
40
|
+
teamId: z.string().optional(),
|
|
41
|
+
/** BEC-177: label-based routing. When set, this repo handles tickets
|
|
42
|
+
* whose pipeline label matches the pattern. */
|
|
43
|
+
labelPattern: z.string().optional(),
|
|
44
|
+
});
|
|
45
|
+
export const UserLevelConfigSchema = z.object({
|
|
46
|
+
/** Schema version — bumped if/when the file format changes. */
|
|
47
|
+
version: z.literal(1),
|
|
48
|
+
/** Configured repos. `ura repo add` appends; `ura repo remove` filters. */
|
|
49
|
+
repos: z.array(UserLevelRepoSchema).default([]),
|
|
50
|
+
});
|
|
51
|
+
/**
|
|
52
|
+
* Resolve the user-level state directory. Returns `$URATEAM_HOME` when set,
|
|
53
|
+
* otherwise `~/.urateam`.
|
|
54
|
+
*/
|
|
55
|
+
export function resolveUserLevelHome() {
|
|
56
|
+
return process.env.URATEAM_HOME ?? join(homedir(), ".urateam");
|
|
57
|
+
}
|
|
58
|
+
export function userLevelConfigPath() {
|
|
59
|
+
return join(resolveUserLevelHome(), "config.json");
|
|
60
|
+
}
|
|
61
|
+
export function userLevelReposDir() {
|
|
62
|
+
return join(resolveUserLevelHome(), "repos");
|
|
63
|
+
}
|
|
64
|
+
export function userLevelDataDir() {
|
|
65
|
+
return join(resolveUserLevelHome(), "data");
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Read and validate the user-level config. Returns `null` when the file
|
|
69
|
+
* doesn't exist (so callers can distinguish "not initialized" from "empty
|
|
70
|
+
* config"). Throws on schema-validation failure — operators should see the
|
|
71
|
+
* Zod error explicitly rather than silently get an unconfigured daemon.
|
|
72
|
+
*/
|
|
73
|
+
export function readUserLevelConfig() {
|
|
74
|
+
const path = userLevelConfigPath();
|
|
75
|
+
if (!existsSync(path))
|
|
76
|
+
return null;
|
|
77
|
+
const raw = JSON.parse(readFileSync(path, "utf8"));
|
|
78
|
+
return UserLevelConfigSchema.parse(raw);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Write the user-level config, creating `~/.urateam/` if missing.
|
|
82
|
+
* Idempotent: callers are expected to read-modify-write to preserve any
|
|
83
|
+
* fields the writer doesn't know about (the schema is forward-compatible
|
|
84
|
+
* within version 1).
|
|
85
|
+
*/
|
|
86
|
+
export function writeUserLevelConfig(config) {
|
|
87
|
+
const home = resolveUserLevelHome();
|
|
88
|
+
mkdirSync(home, { recursive: true });
|
|
89
|
+
writeFileSync(userLevelConfigPath(), JSON.stringify(config, null, 2) + "\n");
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=user-level-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"user-level-config.js","sourceRoot":"","sources":["../../src/lib/user-level-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE7E,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1C,gEAAgE;IAChE,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACtB,sDAAsD;IACtD,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACvB,qEAAqE;IACrE,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAChC,4CAA4C;IAC5C,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC;IAC5C,6CAA6C;IAC7C,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,YAAY,CAAC;IAC9C,wEAAwE;IACxE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC7B;oDACgD;IAChD,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACpC,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5C,+DAA+D;IAC/D,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IACrB,2EAA2E;IAC3E,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;CAChD,CAAC,CAAC;AAGH;;;GAGG;AACH,MAAM,UAAU,oBAAoB;IAClC,OAAO,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,UAAU,CAAC,CAAC;AACjE,CAAC;AAED,MAAM,UAAU,mBAAmB;IACjC,OAAO,IAAI,CAAC,oBAAoB,EAAE,EAAE,aAAa,CAAC,CAAC;AACrD,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC/B,OAAO,IAAI,CAAC,oBAAoB,EAAE,EAAE,OAAO,CAAC,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,OAAO,IAAI,CAAC,oBAAoB,EAAE,EAAE,MAAM,CAAC,CAAC;AAC9C,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB;IACjC,MAAM,IAAI,GAAG,mBAAmB,EAAE,CAAC;IACnC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACnC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;IACnD,OAAO,qBAAqB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;AAC1C,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAAC,MAAuB;IAC1D,MAAM,IAAI,GAAG,oBAAoB,EAAE,CAAC;IACpC,SAAS,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACrC,aAAa,CAAC,mBAAmB,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;AAC/E,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@urateam/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.40",
|
|
4
4
|
"license": "BUSL-1.1",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -22,8 +22,9 @@
|
|
|
22
22
|
"better-sqlite3": "^11.8.0",
|
|
23
23
|
"commander": "^13.1.0",
|
|
24
24
|
"postgres": "^3.4.0",
|
|
25
|
-
"
|
|
26
|
-
"@urateam/
|
|
25
|
+
"zod": "^4.3.6",
|
|
26
|
+
"@urateam/core": "0.1.38",
|
|
27
|
+
"@urateam/dashboard": "0.1.38"
|
|
27
28
|
},
|
|
28
29
|
"devDependencies": {
|
|
29
30
|
"@types/better-sqlite3": "^7.6.0",
|