@moda-ai/cli 1.55.27 → 1.55.28
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/{agent-vp9prdma.js → agent-0w9rtdsw.js} +22 -16
- package/dist/cli-3n0gz4d0.js +17971 -0
- package/dist/{cli-q9nsvqqg.js → cli-3retgh64.js} +85 -1165
- package/dist/{cli-ccjfwzqx.js → cli-97jew729.js} +1 -1
- package/dist/{cli-r5pp7qny.js → cli-99p2jh28.js} +42 -456
- package/dist/{cli-0pkc8jhg.js → cli-9bgk5jeh.js} +8 -6
- package/dist/{cli-hmjdgxrn.js → cli-9bgnvth2.js} +5 -3
- package/dist/cli-9kfxkxmk.js +6994 -0
- package/dist/cli-cesds766.js +1516 -0
- package/dist/{cli-v8q7sd7g.js → cli-dr6x0zv7.js} +1 -1
- package/dist/{cli-pg5qfmqc.js → cli-e23g9ywa.js} +1 -1
- package/dist/{cli-vdkwkkp5.js → cli-fwpqghgc.js} +4 -2
- package/dist/cli-k4tqwah4.js +89 -0
- package/dist/{cli-6et4z504.js → cli-mg5zv4s6.js} +15 -13
- package/dist/{cli-wzds257x.js → cli-n2hng3gv.js} +6 -4
- package/dist/cli-ns5fcnkz.js +341 -0
- package/dist/{cli-4h0ave0f.js → cli-ny48a8de.js} +12 -9
- package/dist/{cli-qwgct6x7.js → cli-qpq84eee.js} +5220 -32716
- package/dist/cli-xq45etg1.js +1098 -0
- package/dist/cli-yf39avhh.js +754 -0
- package/dist/cli-yz8xcpyk.js +12 -0
- package/dist/cli.js +77 -153
- package/dist/doctor-k3ta6h2y.js +24 -0
- package/dist/{fix-75s9s0d6.js → fix-w5z02wt4.js} +8 -9
- package/dist/{harness-a7tb9a23.js → harness-7azmzytc.js} +15 -7
- package/dist/{harness-github-actions-6v4wydb8.js → harness-github-actions-bv2qrnqb.js} +11 -5
- package/dist/harness-report-rd9c4e9v.js +54 -0
- package/dist/{index-91bpc8g8.js → index-d1z50dsq.js} +41 -33
- package/dist/{production-intelligence-7nqddd4f.js → production-intelligence-wvsgjxth.js} +9 -6
- package/dist/{profile-commands-49yn02yg.js → profile-commands-h8evz9x0.js} +7 -4
- package/dist/prompt-attribution-1nytc9wj.js +148 -0
- package/dist/prompt-source-mcp.js +14 -7
- package/dist/prompt-sources-07tczyqa.js +19 -0
- package/dist/{prompts-17wyrst6.js → prompts-6y9wfq5z.js} +8 -7
- package/dist/prompts-ab-ezrd63sk.js +70 -0
- package/dist/prompts-propose-2k3enm2q.js +255 -0
- package/dist/{provision-bc3h68e1.js → provision-y5bdbh4y.js} +9 -6
- package/dist/{registry-fpzhjznj.js → registry-96aze5wp.js} +7 -4
- package/dist/{skills-ccdbqghj.js → skills-j8865009.js} +7 -5
- package/dist/{sync-hkxce5zh.js → sync-ew7yvy0e.js} +16 -10
- package/package.json +1 -1
- package/skills/integration/index.json +2 -2
- package/dist/doctor-wmre3mr7.js +0 -22
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
// src/errors.ts
|
|
2
|
+
class CliInputError extends Error {
|
|
3
|
+
usage;
|
|
4
|
+
reason;
|
|
5
|
+
details;
|
|
6
|
+
constructor(message, usage, reason, details) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.usage = usage;
|
|
9
|
+
this.reason = reason;
|
|
10
|
+
this.details = details;
|
|
11
|
+
this.name = "CliInputError";
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
var inputDetails = new WeakMap;
|
|
15
|
+
function attachInputDetails(error, details) {
|
|
16
|
+
inputDetails.set(error, details);
|
|
17
|
+
}
|
|
18
|
+
function inputDetailsOf(error) {
|
|
19
|
+
if (error instanceof CliInputError && error.details)
|
|
20
|
+
return error.details;
|
|
21
|
+
return error !== null && typeof error === "object" ? inputDetails.get(error) : undefined;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
class CliAccessError extends Error {
|
|
25
|
+
guidance;
|
|
26
|
+
constructor(message, options = {}) {
|
|
27
|
+
super(message);
|
|
28
|
+
this.name = "CliAccessError";
|
|
29
|
+
this.guidance = options.guidance;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
class CliInputRequiredError extends Error {
|
|
34
|
+
input_request;
|
|
35
|
+
constructor(message, input_request, usage) {
|
|
36
|
+
super(message);
|
|
37
|
+
this.input_request = input_request;
|
|
38
|
+
this.name = "CliInputRequiredError";
|
|
39
|
+
if (usage)
|
|
40
|
+
this.usage = usage;
|
|
41
|
+
}
|
|
42
|
+
usage;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
class CliAuthError extends Error {
|
|
46
|
+
auth;
|
|
47
|
+
constructor(message, auth, usage) {
|
|
48
|
+
super(message);
|
|
49
|
+
this.auth = auth;
|
|
50
|
+
this.name = "CliAuthError";
|
|
51
|
+
if (usage)
|
|
52
|
+
this.usage = usage;
|
|
53
|
+
}
|
|
54
|
+
usage;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
class CliNotFoundError extends Error {
|
|
58
|
+
entity;
|
|
59
|
+
id;
|
|
60
|
+
usage;
|
|
61
|
+
constructor(entity, id, message, usage) {
|
|
62
|
+
super(message ?? `No ${entity} found for id "${id}" in this tenant.`);
|
|
63
|
+
this.entity = entity;
|
|
64
|
+
this.id = id;
|
|
65
|
+
this.usage = usage;
|
|
66
|
+
this.name = "CliNotFoundError";
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
class CliCancellationError extends Error {
|
|
71
|
+
constructor(message) {
|
|
72
|
+
super(message);
|
|
73
|
+
this.name = "CliCancellationError";
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
function isNetworkLikeError(error) {
|
|
77
|
+
return error instanceof Error && (error.message.startsWith("Network error:") || error.message.startsWith("Request timed out") || error.name === "AbortError" || /(?:ECONNRESET|ECONNREFUSED|ETIMEDOUT|ENOTFOUND|socket hang up)/i.test(error.message));
|
|
78
|
+
}
|
|
79
|
+
function isApiLikeError(error) {
|
|
80
|
+
return error instanceof Error && (error.name === "ApiError" || ("statusCode" in error) && typeof error.statusCode === "number");
|
|
81
|
+
}
|
|
82
|
+
function apiErrorStatus(error) {
|
|
83
|
+
if (!isApiLikeError(error))
|
|
84
|
+
return;
|
|
85
|
+
const status = error.statusCode;
|
|
86
|
+
return typeof status === "number" ? status : undefined;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export { CliInputError, attachInputDetails, inputDetailsOf, CliAccessError, CliInputRequiredError, CliAuthError, CliNotFoundError, CliCancellationError, isNetworkLikeError, isApiLikeError, apiErrorStatus };
|
|
@@ -1,31 +1,33 @@
|
|
|
1
|
+
import {
|
|
2
|
+
SKILL_SOURCE_HARNESS,
|
|
3
|
+
SKILL_SOURCE_INTEGRATION_BUNDLED,
|
|
4
|
+
claudeSkillToCursorRule,
|
|
5
|
+
detectAgents,
|
|
6
|
+
pruneManagedSkillPaths,
|
|
7
|
+
readSkillsManifest,
|
|
8
|
+
writeSkillsManifest
|
|
9
|
+
} from "./cli-8dtnwp9r.js";
|
|
1
10
|
import {
|
|
2
11
|
createCommandContext
|
|
3
|
-
} from "./cli-
|
|
12
|
+
} from "./cli-dr6x0zv7.js";
|
|
4
13
|
import {
|
|
5
14
|
assertFlags,
|
|
6
15
|
assertPositionals,
|
|
7
16
|
writeDryRun
|
|
8
|
-
} from "./cli-
|
|
17
|
+
} from "./cli-n2hng3gv.js";
|
|
9
18
|
import {
|
|
10
19
|
callControlAPI
|
|
11
|
-
} from "./cli-
|
|
20
|
+
} from "./cli-e23g9ywa.js";
|
|
12
21
|
import {
|
|
13
|
-
CliInputError,
|
|
14
22
|
recordApiRequest,
|
|
15
23
|
resolveApiKey,
|
|
16
24
|
resolveIngestUrl,
|
|
17
25
|
resolveTenantId,
|
|
18
26
|
shellArg
|
|
19
|
-
} from "./cli-
|
|
27
|
+
} from "./cli-99p2jh28.js";
|
|
20
28
|
import {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
claudeSkillToCursorRule,
|
|
24
|
-
detectAgents,
|
|
25
|
-
pruneManagedSkillPaths,
|
|
26
|
-
readSkillsManifest,
|
|
27
|
-
writeSkillsManifest
|
|
28
|
-
} from "./cli-8dtnwp9r.js";
|
|
29
|
+
CliInputError
|
|
30
|
+
} from "./cli-k4tqwah4.js";
|
|
29
31
|
import {
|
|
30
32
|
__require
|
|
31
33
|
} from "./cli-0v6na3yp.js";
|
|
@@ -2,10 +2,8 @@ import {
|
|
|
2
2
|
ApiError,
|
|
3
3
|
callControlAPI,
|
|
4
4
|
callDataAPI
|
|
5
|
-
} from "./cli-
|
|
5
|
+
} from "./cli-e23g9ywa.js";
|
|
6
6
|
import {
|
|
7
|
-
CliAccessError,
|
|
8
|
-
CliInputError,
|
|
9
7
|
continuationCommand,
|
|
10
8
|
embeddedTenantIdFromApiKey,
|
|
11
9
|
isPlatformApiKey,
|
|
@@ -13,7 +11,11 @@ import {
|
|
|
13
11
|
resolveApiTenantId,
|
|
14
12
|
setPlatformTenantOverride,
|
|
15
13
|
shellArg
|
|
16
|
-
} from "./cli-
|
|
14
|
+
} from "./cli-99p2jh28.js";
|
|
15
|
+
import {
|
|
16
|
+
CliAccessError,
|
|
17
|
+
CliInputError
|
|
18
|
+
} from "./cli-k4tqwah4.js";
|
|
17
19
|
|
|
18
20
|
// src/schemas.ts
|
|
19
21
|
import { z } from "zod";
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
// ../../packages/harness-snapshot/src/policy.ts
|
|
2
|
+
var MAX_SCANNED_FILE_BYTES = 512 * 1024;
|
|
3
|
+
var DEFAULT_MAX_INVENTORY_FILES = 12000;
|
|
4
|
+
var DEFAULT_MAX_INVENTORY_TEXT_BYTES = 48 * 1024 * 1024;
|
|
5
|
+
var MAX_SNAPSHOT_BODY_BYTES = 4500000;
|
|
6
|
+
var MAX_RECORDED_SKIPS = 1000;
|
|
7
|
+
var SKIPPED_DIRS = new Set([
|
|
8
|
+
".angular",
|
|
9
|
+
".cache",
|
|
10
|
+
".expo",
|
|
11
|
+
".git",
|
|
12
|
+
".hg",
|
|
13
|
+
".idea",
|
|
14
|
+
".svn",
|
|
15
|
+
".next",
|
|
16
|
+
".nuxt",
|
|
17
|
+
".output",
|
|
18
|
+
".parcel-cache",
|
|
19
|
+
".pytest_cache",
|
|
20
|
+
".ruff_cache",
|
|
21
|
+
".serverless",
|
|
22
|
+
".sst",
|
|
23
|
+
".turbo",
|
|
24
|
+
".wrangler",
|
|
25
|
+
".wrangler-shared",
|
|
26
|
+
".moda",
|
|
27
|
+
".moda-test",
|
|
28
|
+
".moda-test-home",
|
|
29
|
+
".moda-cli-workspaces",
|
|
30
|
+
".moda-cli-benchmarks",
|
|
31
|
+
"node_modules",
|
|
32
|
+
"dist",
|
|
33
|
+
"build",
|
|
34
|
+
"coverage",
|
|
35
|
+
"out",
|
|
36
|
+
"target",
|
|
37
|
+
"logs",
|
|
38
|
+
"tmp",
|
|
39
|
+
"temp",
|
|
40
|
+
"__pycache__",
|
|
41
|
+
".venv",
|
|
42
|
+
"venv"
|
|
43
|
+
]);
|
|
44
|
+
var SKIPPED_PATH_PREFIXES = [
|
|
45
|
+
".claude/worktrees",
|
|
46
|
+
".codex/environments"
|
|
47
|
+
];
|
|
48
|
+
function posixNormalize(path) {
|
|
49
|
+
const absolute = path.startsWith("/");
|
|
50
|
+
const parts = path.split("/").filter((part) => part !== "" && part !== ".");
|
|
51
|
+
const normalized = parts.join("/");
|
|
52
|
+
return absolute ? `/${normalized}` : normalized;
|
|
53
|
+
}
|
|
54
|
+
function basename(path) {
|
|
55
|
+
const normalized = posixNormalize(path);
|
|
56
|
+
const index = normalized.lastIndexOf("/");
|
|
57
|
+
return index === -1 ? normalized : normalized.slice(index + 1);
|
|
58
|
+
}
|
|
59
|
+
function extname(path) {
|
|
60
|
+
const name = basename(path);
|
|
61
|
+
const index = name.lastIndexOf(".");
|
|
62
|
+
return index <= 0 ? "" : name.slice(index);
|
|
63
|
+
}
|
|
64
|
+
function isSkippedDir(path) {
|
|
65
|
+
return SKIPPED_DIRS.has(basename(path));
|
|
66
|
+
}
|
|
67
|
+
function isSkippedPathPrefix(path) {
|
|
68
|
+
const normalized = posixNormalize(path);
|
|
69
|
+
return SKIPPED_PATH_PREFIXES.some((prefix) => normalized === prefix || normalized.startsWith(`${prefix}/`));
|
|
70
|
+
}
|
|
71
|
+
function isSourceFile(path) {
|
|
72
|
+
return /\.(ts|tsx|js|jsx|mjs|cjs|py)$/i.test(path);
|
|
73
|
+
}
|
|
74
|
+
function isPackageOrLockfile(path) {
|
|
75
|
+
return path === "package.json" || path === "pyproject.toml" || path === "bun.lock" || path === "bun.lockb" || path === "pnpm-lock.yaml" || path === "yarn.lock";
|
|
76
|
+
}
|
|
77
|
+
function isPromptLikePath(path) {
|
|
78
|
+
return /(^|\/)prompts?\//i.test(path) && /\.(prompt\.)?(md|json|ya?ml)$/i.test(path);
|
|
79
|
+
}
|
|
80
|
+
function isSkillLikePath(path) {
|
|
81
|
+
return /(^|\/)(\.claude\/skills|\.cursor\/rules|skills?)\//i.test(path) && /\.(md|mdc)$/i.test(path);
|
|
82
|
+
}
|
|
83
|
+
function isEvalLikePath(path) {
|
|
84
|
+
return /(^|\/)(evals?|tests?|__tests__)\//i.test(path) && /\.(ts|tsx|js|mjs|py|json|ya?ml)$/i.test(path);
|
|
85
|
+
}
|
|
86
|
+
function isDeploymentLikePath(path) {
|
|
87
|
+
return /(^|\/)(wrangler\.toml|vercel\.json|render\.ya?ml|railway\.json|Dockerfile|docker-compose\.ya?ml)$/i.test(path) || /^\.github\/workflows\/[^/]+\.ya?ml$/i.test(path);
|
|
88
|
+
}
|
|
89
|
+
function isDeveloperAgentConfigPath(path) {
|
|
90
|
+
return path === ".claude/settings.json" || path === ".codex/hooks.json" || path === ".cursor/hooks.json";
|
|
91
|
+
}
|
|
92
|
+
function isReadmeOrAgents(path) {
|
|
93
|
+
const name = basename(path);
|
|
94
|
+
return name === "README.md" || name === "AGENTS.md";
|
|
95
|
+
}
|
|
96
|
+
function shouldInventoryFile(path) {
|
|
97
|
+
const normalized = posixNormalize(path);
|
|
98
|
+
const name = basename(normalized);
|
|
99
|
+
const extension = extname(normalized).toLowerCase();
|
|
100
|
+
if (isSourceFile(normalized))
|
|
101
|
+
return true;
|
|
102
|
+
if (isPackageOrLockfile(normalized))
|
|
103
|
+
return true;
|
|
104
|
+
if (isPromptLikePath(normalized))
|
|
105
|
+
return true;
|
|
106
|
+
if (isSkillLikePath(normalized))
|
|
107
|
+
return true;
|
|
108
|
+
if (isEvalLikePath(normalized))
|
|
109
|
+
return true;
|
|
110
|
+
if (isDeploymentLikePath(normalized))
|
|
111
|
+
return true;
|
|
112
|
+
if (isDeveloperAgentConfigPath(normalized))
|
|
113
|
+
return true;
|
|
114
|
+
if (isReadmeOrAgents(normalized))
|
|
115
|
+
return true;
|
|
116
|
+
return extension === ".toml" && (name === "pyproject.toml" || name === "wrangler.toml");
|
|
117
|
+
}
|
|
118
|
+
function isTextFile(path) {
|
|
119
|
+
const extension = extname(path).toLowerCase();
|
|
120
|
+
return [
|
|
121
|
+
"",
|
|
122
|
+
".cjs",
|
|
123
|
+
".js",
|
|
124
|
+
".json",
|
|
125
|
+
".jsx",
|
|
126
|
+
".md",
|
|
127
|
+
".mdc",
|
|
128
|
+
".mjs",
|
|
129
|
+
".py",
|
|
130
|
+
".toml",
|
|
131
|
+
".ts",
|
|
132
|
+
".tsx",
|
|
133
|
+
".txt",
|
|
134
|
+
".yaml",
|
|
135
|
+
".yml"
|
|
136
|
+
].includes(extension);
|
|
137
|
+
}
|
|
138
|
+
function isSecretishPath(path) {
|
|
139
|
+
const name = basename(path).toLowerCase();
|
|
140
|
+
return name === ".env" || name.startsWith(".env.") || name.includes("secret") || name.includes("private-key") || name.endsWith(".pem");
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// ../../packages/harness-snapshot/src/redact.ts
|
|
144
|
+
var REDACTED = "[REDACTED]";
|
|
145
|
+
var MAX_DEPTH = 256;
|
|
146
|
+
var SECRET_KEYS = new Set([
|
|
147
|
+
"api_key",
|
|
148
|
+
"apikey",
|
|
149
|
+
"token",
|
|
150
|
+
"access_token",
|
|
151
|
+
"authorization",
|
|
152
|
+
"secret",
|
|
153
|
+
"password",
|
|
154
|
+
"cli_token"
|
|
155
|
+
]);
|
|
156
|
+
var SECRET_PATTERNS = [
|
|
157
|
+
{ pattern: /\bmoda_sk_[A-Za-z0-9_-]+\b/g, prefixLength: 8 },
|
|
158
|
+
{ pattern: /\bmoda_pk_[A-Za-z0-9_-]+\b/g, prefixLength: 8 },
|
|
159
|
+
{ pattern: /\bmoda_ct_[A-Za-z0-9_-]+\b/g, prefixLength: 8 },
|
|
160
|
+
{ pattern: /\bBearer\s+([A-Za-z0-9._~+/-]+=*)\b/gi, prefixLength: 8 },
|
|
161
|
+
{ pattern: /\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/g, prefixLength: 8 },
|
|
162
|
+
{ pattern: /\bsk-ant-api\d{2}-[A-Za-z0-9_-]{20,}\b/g, prefixLength: 12 },
|
|
163
|
+
{ pattern: /\bsk-(?:proj-|svcacct-)?[A-Za-z0-9_-]{20,}\b/g, prefixLength: 8 },
|
|
164
|
+
{ pattern: /\bAKIA[A-Z0-9]{16}\b/g, prefixLength: 8 },
|
|
165
|
+
{ pattern: /\bAIza[A-Za-z0-9_-]{35}\b/g, prefixLength: 8 },
|
|
166
|
+
{ pattern: /\bgh[pousr]_[A-Za-z0-9]{36,}\b/g, prefixLength: 8 },
|
|
167
|
+
{ pattern: /\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g, prefixLength: 8 }
|
|
168
|
+
];
|
|
169
|
+
function redactDeep(value) {
|
|
170
|
+
return redactValue(value, 0, new WeakSet);
|
|
171
|
+
}
|
|
172
|
+
function redactValue(value, depth, seen) {
|
|
173
|
+
if (typeof value === "string")
|
|
174
|
+
return redactString(value);
|
|
175
|
+
if (value === null || typeof value !== "object")
|
|
176
|
+
return value;
|
|
177
|
+
if (depth >= MAX_DEPTH)
|
|
178
|
+
return "[MaxDepth]";
|
|
179
|
+
if (seen.has(value))
|
|
180
|
+
return "[Circular]";
|
|
181
|
+
seen.add(value);
|
|
182
|
+
if (Array.isArray(value)) {
|
|
183
|
+
try {
|
|
184
|
+
return value.map((item) => redactValue(item, depth + 1, seen));
|
|
185
|
+
} finally {
|
|
186
|
+
seen.delete(value);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
const out = {};
|
|
190
|
+
try {
|
|
191
|
+
for (const [key, item] of Object.entries(value)) {
|
|
192
|
+
out[key] = shouldRedactKey(key) ? redactSecretValue(item) : redactValue(item, depth + 1, seen);
|
|
193
|
+
}
|
|
194
|
+
} finally {
|
|
195
|
+
seen.delete(value);
|
|
196
|
+
}
|
|
197
|
+
return out;
|
|
198
|
+
}
|
|
199
|
+
function shouldRedactKey(key) {
|
|
200
|
+
return SECRET_KEYS.has(key.replace(/[-\s]/g, "_").toLowerCase());
|
|
201
|
+
}
|
|
202
|
+
function redactSecretValue(value) {
|
|
203
|
+
if (typeof value !== "string")
|
|
204
|
+
return REDACTED;
|
|
205
|
+
const redacted = redactString(value);
|
|
206
|
+
if (redacted !== value)
|
|
207
|
+
return redacted;
|
|
208
|
+
if (/^(configured|missing|not_configured|none|present|absent)$/i.test(value))
|
|
209
|
+
return value;
|
|
210
|
+
return REDACTED;
|
|
211
|
+
}
|
|
212
|
+
function redactStringWithCount(input) {
|
|
213
|
+
let text = input;
|
|
214
|
+
let redactionCount = 0;
|
|
215
|
+
for (const { pattern, prefixLength } of SECRET_PATTERNS) {
|
|
216
|
+
text = text.replace(pattern, (match) => {
|
|
217
|
+
redactionCount += 1;
|
|
218
|
+
if (/^Bearer\s+/i.test(match)) {
|
|
219
|
+
const token = match.replace(/^Bearer\s+/i, "");
|
|
220
|
+
return `Bearer ${token.slice(0, prefixLength)}...[REDACTED]`;
|
|
221
|
+
}
|
|
222
|
+
return `${match.slice(0, prefixLength)}...[REDACTED]`;
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
return { text, redactionCount };
|
|
226
|
+
}
|
|
227
|
+
function redactString(input) {
|
|
228
|
+
return redactStringWithCount(input).text;
|
|
229
|
+
}
|
|
230
|
+
function redactSnapshotText(text) {
|
|
231
|
+
const parts = text.split(/(\r\n|\r|\n)/);
|
|
232
|
+
let redactionCount = 0;
|
|
233
|
+
for (let index = 0;index < parts.length; index += 2) {
|
|
234
|
+
const redacted = redactStringWithCount(parts[index] ?? "");
|
|
235
|
+
parts[index] = redacted.text;
|
|
236
|
+
redactionCount += redacted.redactionCount;
|
|
237
|
+
}
|
|
238
|
+
return { text: parts.join(""), redactionCount };
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// ../../packages/harness-snapshot/src/pack.ts
|
|
242
|
+
function utf8ByteLength(value) {
|
|
243
|
+
let bytes = 0;
|
|
244
|
+
for (let index = 0;index < value.length; index += 1) {
|
|
245
|
+
const code = value.charCodeAt(index);
|
|
246
|
+
if (code <= 127) {
|
|
247
|
+
bytes += 1;
|
|
248
|
+
} else if (code <= 2047) {
|
|
249
|
+
bytes += 2;
|
|
250
|
+
} else if (code >= 55296 && code <= 56319) {
|
|
251
|
+
const next = value.charCodeAt(index + 1);
|
|
252
|
+
if (next >= 56320 && next <= 57343) {
|
|
253
|
+
bytes += 4;
|
|
254
|
+
index += 1;
|
|
255
|
+
} else {
|
|
256
|
+
bytes += 3;
|
|
257
|
+
}
|
|
258
|
+
} else {
|
|
259
|
+
bytes += 3;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
return bytes;
|
|
263
|
+
}
|
|
264
|
+
function isValidRelativePath(path) {
|
|
265
|
+
if (path.length === 0 || path.startsWith("/") || path.includes("\\"))
|
|
266
|
+
return false;
|
|
267
|
+
return !path.split("/").some((part) => part === "..");
|
|
268
|
+
}
|
|
269
|
+
function packSnapshot(inputs, opts) {
|
|
270
|
+
const maxFiles = opts.maxFiles ?? DEFAULT_MAX_INVENTORY_FILES;
|
|
271
|
+
const maxTextBytes = opts.maxTextBytes ?? DEFAULT_MAX_INVENTORY_TEXT_BYTES;
|
|
272
|
+
const maxSnapshotBytes = opts.maxSnapshotBytes ?? MAX_SNAPSHOT_BODY_BYTES;
|
|
273
|
+
const files = [];
|
|
274
|
+
const skips = [];
|
|
275
|
+
let inventoryTextBytes = 0;
|
|
276
|
+
let serializedBytes = 0;
|
|
277
|
+
let byteCount = 0;
|
|
278
|
+
let truncated = false;
|
|
279
|
+
const recordSkip = (path, reason) => {
|
|
280
|
+
if (skips.length < MAX_RECORDED_SKIPS)
|
|
281
|
+
skips.push({ path, reason });
|
|
282
|
+
};
|
|
283
|
+
const sorted = [...inputs].sort((left, right) => left.path < right.path ? -1 : left.path > right.path ? 1 : 0);
|
|
284
|
+
for (const input of sorted) {
|
|
285
|
+
if (!isValidRelativePath(input.path)) {
|
|
286
|
+
recordSkip(input.path, "invalid relative path");
|
|
287
|
+
continue;
|
|
288
|
+
}
|
|
289
|
+
const path = posixNormalize(input.path);
|
|
290
|
+
if (input.isSymlink) {
|
|
291
|
+
recordSkip(path, "symlink skipped for safety");
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
294
|
+
if (isSecretishPath(path)) {
|
|
295
|
+
recordSkip(path, "secret-bearing path");
|
|
296
|
+
continue;
|
|
297
|
+
}
|
|
298
|
+
if (!shouldInventoryFile(path)) {
|
|
299
|
+
recordSkip(path, "not an inventory file");
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
if (!isTextFile(path)) {
|
|
303
|
+
recordSkip(path, "non-text file");
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
if (input.byteSize > MAX_SCANNED_FILE_BYTES) {
|
|
307
|
+
recordSkip(path, "file too large");
|
|
308
|
+
truncated = true;
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
if (files.length >= maxFiles || inventoryTextBytes + input.byteSize > maxTextBytes) {
|
|
312
|
+
recordSkip(path, "inventory budget");
|
|
313
|
+
truncated = true;
|
|
314
|
+
continue;
|
|
315
|
+
}
|
|
316
|
+
const text = opts.redact === false ? input.text : redactSnapshotText(input.text).text;
|
|
317
|
+
const file = { path, text };
|
|
318
|
+
const serializedCost = utf8ByteLength(JSON.stringify(file)) + 1;
|
|
319
|
+
if (serializedBytes + serializedCost > maxSnapshotBytes) {
|
|
320
|
+
recordSkip(path, "snapshot budget");
|
|
321
|
+
truncated = true;
|
|
322
|
+
break;
|
|
323
|
+
}
|
|
324
|
+
files.push(file);
|
|
325
|
+
inventoryTextBytes += input.byteSize;
|
|
326
|
+
serializedBytes += serializedCost;
|
|
327
|
+
byteCount += utf8ByteLength(text);
|
|
328
|
+
}
|
|
329
|
+
return {
|
|
330
|
+
snapshot: {
|
|
331
|
+
repo: { name: opts.repoName, root: "." },
|
|
332
|
+
files,
|
|
333
|
+
truncated,
|
|
334
|
+
fileCount: files.length,
|
|
335
|
+
byteCount,
|
|
336
|
+
...opts.gitCommit ? { gitCommit: opts.gitCommit } : {}
|
|
337
|
+
},
|
|
338
|
+
skips
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
export { MAX_SCANNED_FILE_BYTES, DEFAULT_MAX_INVENTORY_FILES, DEFAULT_MAX_INVENTORY_TEXT_BYTES, MAX_RECORDED_SKIPS, SKIPPED_DIRS, isSkippedDir, isSkippedPathPrefix, isEvalLikePath, shouldInventoryFile, isTextFile, isSecretishPath, SECRET_KEYS, redactDeep, redactString, packSnapshot };
|
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
2
|
isAuthSessionValid,
|
|
3
3
|
loadAuthSession
|
|
4
|
-
} from "./cli-
|
|
4
|
+
} from "./cli-9bgnvth2.js";
|
|
5
5
|
import {
|
|
6
6
|
inspectPromptManifest
|
|
7
|
-
} from "./cli-
|
|
7
|
+
} from "./cli-3retgh64.js";
|
|
8
8
|
import {
|
|
9
9
|
readHarnessSyncState,
|
|
10
10
|
renderDoctorHuman,
|
|
11
|
-
renderStatusHuman
|
|
12
|
-
|
|
13
|
-
} from "./cli-qwgct6x7.js";
|
|
11
|
+
renderStatusHuman
|
|
12
|
+
} from "./cli-xq45etg1.js";
|
|
14
13
|
import {
|
|
15
14
|
callDataAPI
|
|
16
|
-
} from "./cli-
|
|
15
|
+
} from "./cli-e23g9ywa.js";
|
|
17
16
|
import {
|
|
18
17
|
ensureSecretFilePermissions,
|
|
19
18
|
getActiveProfile,
|
|
@@ -27,7 +26,10 @@ import {
|
|
|
27
26
|
resolveSecretReference,
|
|
28
27
|
resolveTenantId,
|
|
29
28
|
secretFilePathFromRef
|
|
30
|
-
} from "./cli-
|
|
29
|
+
} from "./cli-99p2jh28.js";
|
|
30
|
+
import {
|
|
31
|
+
__require
|
|
32
|
+
} from "./cli-0v6na3yp.js";
|
|
31
33
|
|
|
32
34
|
// src/doctor.ts
|
|
33
35
|
import { createHash } from "node:crypto";
|
|
@@ -167,7 +169,7 @@ async function buildDoctorReport(context, options) {
|
|
|
167
169
|
remediation: manifestExists ? undefined : "Run `moda harness scan --summary` to scan the project and write a harness manifest.",
|
|
168
170
|
nextCommand: manifestExists ? undefined : "moda harness scan --summary"
|
|
169
171
|
});
|
|
170
|
-
checks.push(harnessCurrentCheck(context.cwd, manifestPath, manifestExists, tenantId));
|
|
172
|
+
checks.push(await harnessCurrentCheck(context.cwd, manifestPath, manifestExists, tenantId));
|
|
171
173
|
checks.push(harnessSyncStateCheck(context.cwd));
|
|
172
174
|
checks.push(promptsDiscoveredCheck(context.cwd));
|
|
173
175
|
checks.push(discoveryCheck("skills_discovered", "harness", "Skills are discovered", context.cwd, [
|
|
@@ -361,7 +363,7 @@ function localBaseUrlCheck(environment, baseUrl) {
|
|
|
361
363
|
evidence: [{ label: "base_url", value: baseUrl }]
|
|
362
364
|
};
|
|
363
365
|
}
|
|
364
|
-
function harnessCurrentCheck(cwd, manifestPath, manifestExists, tenantId) {
|
|
366
|
+
async function harnessCurrentCheck(cwd, manifestPath, manifestExists, tenantId) {
|
|
365
367
|
if (!manifestExists) {
|
|
366
368
|
return {
|
|
367
369
|
id: "harness_manifest_current",
|
|
@@ -374,6 +376,7 @@ function harnessCurrentCheck(cwd, manifestPath, manifestExists, tenantId) {
|
|
|
374
376
|
};
|
|
375
377
|
}
|
|
376
378
|
try {
|
|
379
|
+
const { scanHarness } = await import("./harness-7azmzytc.js");
|
|
377
380
|
const current = scanHarness({
|
|
378
381
|
rootDir: cwd,
|
|
379
382
|
scannerVersion: "doctor",
|