@dreamor/atlas-cli 0.7.22 → 0.7.24

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.
Files changed (43) hide show
  1. package/README.github.md +230 -0
  2. package/README.md +1 -55
  3. package/atlas.cjs +226 -0
  4. package/package.json +7 -9
  5. package/atlas.js +0 -5
  6. package/dist/adapters/atlas/auth/browser.js +0 -37
  7. package/dist/adapters/atlas/auth/index.js +0 -3
  8. package/dist/adapters/atlas/auth/login.js +0 -147
  9. package/dist/adapters/atlas/auth/refresh.js +0 -138
  10. package/dist/adapters/atlas/auth/session.js +0 -115
  11. package/dist/adapters/atlas/cli.js +0 -512
  12. package/dist/adapters/atlas/commands/_output_schema.js +0 -379
  13. package/dist/adapters/atlas/commands/actual/_logic.js +0 -116
  14. package/dist/adapters/atlas/commands/actual/index.js +0 -138
  15. package/dist/adapters/atlas/commands/auth.js +0 -1
  16. package/dist/adapters/atlas/commands/baseline/index.js +0 -137
  17. package/dist/adapters/atlas/commands/compare/_logic.js +0 -39
  18. package/dist/adapters/atlas/commands/compare/index.js +0 -89
  19. package/dist/adapters/atlas/commands/exec.js +0 -81
  20. package/dist/adapters/atlas/commands/project/index.js +0 -218
  21. package/dist/adapters/atlas/commands/schema.js +0 -25
  22. package/dist/adapters/atlas/commands/suggest.js +0 -83
  23. package/dist/adapters/atlas/commands/update.js +0 -104
  24. package/dist/adapters/atlas/daemon/index.js +0 -64
  25. package/dist/adapters/atlas/dict/index.js +0 -41
  26. package/dist/adapters/atlas/http/client.js +0 -200
  27. package/dist/adapters/atlas/http/index.js +0 -1
  28. package/dist/adapters/atlas/schema/actual.js +0 -16
  29. package/dist/adapters/atlas/schema/baseline.js +0 -34
  30. package/dist/adapters/atlas/schema/department.js +0 -11
  31. package/dist/adapters/atlas/schema/index.js +0 -4
  32. package/dist/adapters/atlas/schema/project.js +0 -13
  33. package/dist/adapters/atlas/util/constants.js +0 -4
  34. package/dist/adapters/atlas/util/env.js +0 -56
  35. package/dist/adapters/atlas/util/errors.js +0 -49
  36. package/dist/adapters/atlas/util/helpers.js +0 -17
  37. package/dist/adapters/atlas/util/months.js +0 -65
  38. package/dist/adapters/atlas/util/output-limit.js +0 -21
  39. package/dist/adapters/atlas/util/output.js +0 -70
  40. package/dist/adapters/atlas/util/paths.js +0 -40
  41. package/dist/adapters/atlas/util/secure-fs.js +0 -41
  42. package/dist/adapters/atlas/util/time.js +0 -17
  43. package/dist/adapters/atlas/util/version.js +0 -1
@@ -1,49 +0,0 @@
1
- import { ZodError } from 'zod';
2
- export class BanmaApiError extends Error {
3
- errCode;
4
- errorMsg;
5
- requestId;
6
- constructor(errCode, errorMsg, requestId) {
7
- super(`Banma API error [${errCode}] ${errorMsg}`);
8
- this.errCode = errCode;
9
- this.errorMsg = errorMsg;
10
- this.requestId = requestId;
11
- this.name = 'BanmaApiError';
12
- }
13
- }
14
- export class ConfigError extends Error {
15
- constructor(message) {
16
- super(message);
17
- this.name = 'ConfigError';
18
- }
19
- }
20
- export class SessionExpiredError extends Error {
21
- constructor(message = '会话已过期,请重新登录:atlas auth login') {
22
- super(message);
23
- this.name = 'SessionExpiredError';
24
- }
25
- }
26
- export class OutputTooLargeError extends Error {
27
- bytes;
28
- limit;
29
- constructor(bytes, limit) {
30
- super(`输出 ${bytes} 字节超过上限 ${limit} 字节`);
31
- this.bytes = bytes;
32
- this.limit = limit;
33
- this.name = 'OutputTooLargeError';
34
- }
35
- }
36
- export class AtlasError extends Error {
37
- code;
38
- constructor(message, code) {
39
- super(message);
40
- this.code = code;
41
- this.name = 'AtlasError';
42
- }
43
- }
44
- export function isAtlasError(err) {
45
- return err instanceof AtlasError;
46
- }
47
- export function isZodError(err) {
48
- return err instanceof ZodError;
49
- }
@@ -1,17 +0,0 @@
1
- /** 将 人天 ÷ 22 转换为 人月 */
2
- export function manhoursToManMonth(hours) {
3
- const v = typeof hours === 'string' ? parseFloat(hours) : hours;
4
- if (isNaN(v) || v < 0)
5
- return 0;
6
- return Math.round((v / 22) * 100) / 100;
7
- }
8
- /** 格式化人力数字 */
9
- export function fmtManpower(v) {
10
- if (v == null || isNaN(v))
11
- return '-';
12
- return v.toFixed(2);
13
- }
14
- /** 安全的 sum */
15
- export function safeSum(values) {
16
- return values.reduce((acc, v) => acc + (v ?? 0), 0);
17
- }
@@ -1,65 +0,0 @@
1
- /**
2
- * 月份工具:展开月份范围、格式校验、上限保护。
3
- */
4
- import { ConfigError } from './errors.js';
5
- import { currentMonthKey } from './time.js';
6
- /** YYYY-MM 格式正则 */
7
- const MONTH_RE = /^(\d{4})-(0[1-9]|1[0-2])$/;
8
- /** 单次查询最大月份数 */
9
- const MAX_MONTHS = 36;
10
- /**
11
- * 展开月份范围 → YYYY-MM 数组。
12
- * - 同时给 from/to:返回闭区间内的所有月份。
13
- * - 都不给:返回当前月(单元素数组)。
14
- * - 只给一个:按"都给"处理,缺失的那个用当前月补齐的语义由调用方决定(此处不单独支持)。
15
- *
16
- * 格式校验通过 MONTH_RE;无效格式或范围超过 MAX_MONTHS 抛 ConfigError。
17
- */
18
- export function expandMonths(from, to) {
19
- if (!from || !to)
20
- return [currentMonthKey()];
21
- if (!MONTH_RE.test(from))
22
- throw new ConfigError(`月份格式应为 YYYY-MM(如 2026-03),实际: "${from}"`);
23
- if (!MONTH_RE.test(to))
24
- throw new ConfigError(`月份格式应为 YYYY-MM(如 2026-03),实际: "${to}"`);
25
- const [fy, fm] = from.split('-').map(Number);
26
- const [ty, tm] = to.split('-').map(Number);
27
- const months = [];
28
- let y = fy, m = fm;
29
- while (y < ty || (y === ty && m <= tm)) {
30
- months.push(`${y}-${String(m).padStart(2, '0')}`);
31
- m++;
32
- if (m > 12) {
33
- m = 1;
34
- y++;
35
- }
36
- }
37
- if (months.length > MAX_MONTHS) {
38
- throw new ConfigError(`月份范围过大: ${months.length} 个月(上限 ${MAX_MONTHS} 个月),请缩小查询范围`);
39
- }
40
- return months;
41
- }
42
- /**
43
- * 不传月份时的默认范围:当前月及前后各 12 个月(最多 25 个月,低于 MAX_MONTHS)。
44
- * 使 actual month 无参数时与 baseline month 行为一致。
45
- */
46
- export function expandMonthsDefault() {
47
- const now = new Date();
48
- const cy = now.getFullYear();
49
- const cm = now.getMonth() + 1;
50
- // 12 个月前
51
- let fy = cy, fm = cm - 12;
52
- while (fm < 1) {
53
- fm += 12;
54
- fy--;
55
- }
56
- // 12 个月后
57
- let ty = cy, tm = cm + 12;
58
- while (tm > 12) {
59
- tm -= 12;
60
- ty++;
61
- }
62
- const from = `${fy}-${String(fm).padStart(2, '0')}`;
63
- const to = `${ty}-${String(tm).padStart(2, '0')}`;
64
- return expandMonths(from, to);
65
- }
@@ -1,21 +0,0 @@
1
- import { OutputTooLargeError } from './errors.js';
2
- const MAX_OUTPUT_BYTES_ENV = 'ATLAS_MAX_OUTPUT_BYTES';
3
- /**
4
- * 在写出文件前校验输出字节数上限。
5
- *
6
- * 读取 ATLAS_MAX_OUTPUT_BYTES(字节数,需为正数)。未设置或非法值时放行;
7
- * 超限时抛 OutputTooLargeError(退出码 65,error.code: OUTPUT_TOO_LARGE),
8
- * agent 可据此区分"输出过大"和"配置错误"。
9
- */
10
- export function enforceOutputLimit(content) {
11
- const raw = process.env[MAX_OUTPUT_BYTES_ENV];
12
- if (!raw)
13
- return;
14
- const limit = Number(raw);
15
- if (!Number.isFinite(limit) || limit <= 0)
16
- return;
17
- const bytes = Buffer.byteLength(content, 'utf-8');
18
- if (bytes > limit) {
19
- throw new OutputTooLargeError(bytes, limit);
20
- }
21
- }
@@ -1,70 +0,0 @@
1
- import { BanmaApiError, AtlasError, ConfigError, OutputTooLargeError, SessionExpiredError } from './errors.js';
2
- export function isJsonMode() {
3
- return process.env.ATLAS_OUTPUT === 'json';
4
- }
5
- export function isQuietMode() {
6
- return process.env.ATLAS_QUIET === '1';
7
- }
8
- export function jsonOk(data, meta) {
9
- const envelope = { ok: true, data };
10
- if (meta)
11
- envelope.meta = meta;
12
- process.stdout.write(JSON.stringify(envelope) + '\n');
13
- }
14
- export function jsonError(code, message) {
15
- const envelope = { ok: false, error: { code, message } };
16
- process.stdout.write(JSON.stringify(envelope) + '\n');
17
- }
18
- export function printError(err, opts) {
19
- if (opts?.json && isJsonMode()) {
20
- if (err instanceof BanmaApiError) {
21
- jsonError(err.errCode, err.errorMsg);
22
- }
23
- else if (err instanceof AtlasError) {
24
- jsonError(err.code, err.message);
25
- }
26
- else if (err instanceof OutputTooLargeError) {
27
- jsonError('OUTPUT_TOO_LARGE', err.message);
28
- }
29
- else if (err instanceof Error) {
30
- jsonError('ERROR', err.message);
31
- }
32
- else {
33
- jsonError('ERROR', String(err));
34
- }
35
- return;
36
- }
37
- // Non-JSON error printing
38
- if (err instanceof BanmaApiError) {
39
- console.error(`Banma API error [${err.errCode}] ${err.errorMsg}`);
40
- }
41
- else if (err instanceof SessionExpiredError) {
42
- console.error(err.message);
43
- }
44
- else if (err instanceof ConfigError) {
45
- console.error(`Config error: ${err.message}`);
46
- }
47
- else if (err instanceof OutputTooLargeError) {
48
- console.error(err.message);
49
- }
50
- else if (err instanceof AtlasError) {
51
- console.error(`[${err.code}] ${err.message}`);
52
- }
53
- else if (err instanceof Error) {
54
- const debug = process.env.DEBUG === '1';
55
- console.error(debug ? err.stack ?? err.message : err.message);
56
- }
57
- else {
58
- console.error(String(err));
59
- }
60
- }
61
- export function log(msg) {
62
- if (!isQuietMode()) {
63
- console.error(msg);
64
- }
65
- }
66
- export function table(data) {
67
- if (!isJsonMode()) {
68
- console.table(data);
69
- }
70
- }
@@ -1,40 +0,0 @@
1
- /**
2
- * 路径工具:集中管理所有文件路径,统一遵从 ATLAS_HOME 环境变量。
3
- *
4
- * 避免各文件重复拼 ~/.atlas,避免未来改目录结构时遗漏调用点。
5
- */
6
- import { homedir } from 'os';
7
- import { join, resolve } from 'path';
8
- /** ~/.atlas 或 $ATLAS_HOME(经 path.resolve 防止相对路径误导) */
9
- export function getAtlasHome() {
10
- const raw = process.env.ATLAS_HOME || join(homedir(), '.atlas');
11
- return resolve(raw);
12
- }
13
- /** ~/.atlas/cookies.json */
14
- export function getCookieFile() {
15
- return join(getAtlasHome(), 'cookies.json');
16
- }
17
- /** ~/.atlas/link.json */
18
- export function getLinkFile() {
19
- return join(getAtlasHome(), 'link.json');
20
- }
21
- /** ~/.atlas/daemon.token */
22
- export function getDaemonTokenFile() {
23
- return join(getAtlasHome(), 'daemon.token');
24
- }
25
- /** ~/.atlas/bin */
26
- export function getBinDir() {
27
- return join(getAtlasHome(), 'bin');
28
- }
29
- /** ~/.atlas/bin/atlas.cjs */
30
- export function getTargetBinary() {
31
- return join(getBinDir(), 'atlas.cjs');
32
- }
33
- /** ~/.atlas/cache/<key>.json */
34
- export function getCacheFile(key) {
35
- return join(getAtlasHome(), 'cache', `${key}.json`);
36
- }
37
- /** ~/.atlas/cache */
38
- export function getCacheDir() {
39
- return join(getAtlasHome(), 'cache');
40
- }
@@ -1,41 +0,0 @@
1
- /**
2
- * 安全文件系统工具。
3
- *
4
- * 统一按最小权限原则读写敏感文件:
5
- * - 目录:0700(drwx------)
6
- * - 文件:0600(-rw-------)
7
- *
8
- * 覆盖已有文件时额外 chmod 兜底。
9
- */
10
- import { mkdir, writeFile, chmod } from 'fs/promises';
11
- import { resolve } from 'path';
12
- import { ConfigError } from './errors.js';
13
- /** 安全的目录创建:0700 */
14
- export async function secureMkdir(dir, opts) {
15
- await mkdir(dir, { recursive: opts?.recursive ?? true, mode: 0o700 });
16
- }
17
- /** 安全的文件写入:0600,覆盖已有 ✓ */
18
- export async function secureWriteFile(file, data) {
19
- await writeFile(file, data, { mode: 0o600 });
20
- await chmod(file, 0o600);
21
- }
22
- /**
23
- * 校验导出路径,防止 --out 任意写(H2 修复)。
24
- *
25
- * 策略:
26
- * - 相对路径:解析为 `{cwd}/{path}`,允许
27
- * - 绝对路径:必须在 `cwd` 目录树内
28
- *
29
- * @param cwdOverride 仅在测试中用于 mock 工作目录
30
- * 返回解析后的绝对路径(可安全传入 writeFile)。
31
- * 校验不通过时抛 ConfigError。
32
- */
33
- export function resolveSecureExportPath(out, cwdOverride) {
34
- const currentDir = cwdOverride ?? process.cwd();
35
- const resolved = resolve(currentDir, out);
36
- if (!resolved.startsWith(currentDir)) {
37
- throw new ConfigError(`--out 路径 "${resolved}" 不在当前工作目录 "${currentDir}" 内,已拒绝。` +
38
- `请将导出文件放在当前目录或子目录中。`);
39
- }
40
- return resolved;
41
- }
@@ -1,17 +0,0 @@
1
- /**
2
- * 时间工具:处理 CST(UTC+8)时区相关的转换。
3
- *
4
- * API 返回的时间戳是中国标准时间(UTC+8)的午夜,
5
- * 必须加 8h 偏移后取 UTC 年月,否则在非 UTC+8 的机器上月份偏 1。
6
- */
7
- /** API 时间戳 → YYYY-MM 月份键,CST 时区安全 */
8
- export function monthTsToKey(ts) {
9
- const d = new Date(ts + 8 * 3600 * 1000);
10
- return `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}`;
11
- }
12
- /** 当前月的 YYYY-MM 键 */
13
- export function currentMonthKey() {
14
- const d = new Date();
15
- // 使用本地时间,不偏移;当前月即本地年月
16
- return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}`;
17
- }
@@ -1 +0,0 @@
1
- export const ATLAS_VERSION = '0.7.22';