@lark-apaas/miaoda-cli 0.1.4 → 0.1.5-alpha.2f1e0ff
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 +6 -5
- package/dist/api/deploy/index.js +13 -1
- package/dist/api/deploy/modern-types.js +23 -0
- package/dist/api/deploy/modern.js +78 -0
- package/dist/api/deploy/plugin-instances-types.js +6 -0
- package/dist/api/deploy/plugin-instances.js +22 -0
- package/dist/api/observability/api.js +10 -0
- package/dist/api/observability/index.js +2 -1
- package/dist/cli/commands/app/index.js +144 -2
- package/dist/cli/commands/deploy/modern.js +50 -0
- package/dist/cli/commands/index.js +68 -5
- package/dist/cli/commands/observability/index.js +62 -6
- package/dist/cli/commands/shared.js +5 -0
- package/dist/cli/commands/skills/index.js +79 -0
- package/dist/cli/handlers/app/index.js +9 -1
- package/dist/cli/handlers/app/init.js +132 -0
- package/dist/cli/handlers/app/sync.js +215 -0
- package/dist/cli/handlers/deploy/modern.js +33 -0
- package/dist/cli/handlers/observability/helpers.js +4 -0
- package/dist/cli/handlers/observability/index.js +3 -1
- package/dist/cli/handlers/observability/log.js +8 -2
- package/dist/cli/handlers/observability/source-stack.js +389 -0
- package/dist/cli/handlers/observability/trace.js +7 -1
- package/dist/cli/handlers/skills/index.js +7 -0
- package/dist/cli/handlers/skills/status.js +31 -0
- package/dist/cli/handlers/skills/sync.js +49 -0
- package/dist/config/fullstack-cli-pin.js +17 -0
- package/dist/config/sync-configs/design-stack.js +98 -0
- package/dist/config/sync-configs/index.js +62 -0
- package/dist/config/sync-configs/nestjs-react-fullstack.js +177 -0
- package/dist/config/sync.js +14 -0
- package/dist/services/app/init/index.js +12 -0
- package/dist/services/app/init/install.js +123 -0
- package/dist/services/app/init/template.js +108 -0
- package/dist/services/deploy/modern/atoms/build.js +59 -0
- package/dist/services/deploy/modern/atoms/context.js +27 -0
- package/dist/services/deploy/modern/atoms/index.js +17 -0
- package/dist/services/deploy/modern/atoms/local-release.js +27 -0
- package/dist/services/deploy/modern/atoms/pre-release.js +13 -0
- package/dist/services/deploy/modern/atoms/save-plugin-instances.js +72 -0
- package/dist/services/deploy/modern/atoms/upload.js +246 -0
- package/dist/services/deploy/modern/check.js +53 -0
- package/dist/services/deploy/modern/constants.js +13 -0
- package/dist/services/deploy/modern/index.js +16 -0
- package/dist/services/deploy/modern/pipelines/index.js +5 -0
- package/dist/services/deploy/modern/pipelines/local.js +75 -0
- package/dist/services/deploy/modern/protocol.js +122 -0
- package/dist/services/deploy/modern/run-types.js +4 -0
- package/dist/services/deploy/modern/run.js +13 -0
- package/dist/services/deploy/modern/template-key-map.js +22 -0
- package/dist/services/skills/index.js +5 -0
- package/dist/services/skills/status.js +37 -0
- package/dist/utils/coding-steering.js +169 -0
- package/dist/utils/file-ops.js +45 -0
- package/dist/utils/git.js +22 -0
- package/dist/utils/githooks.js +55 -0
- package/dist/utils/http.js +21 -11
- package/dist/utils/merge-json.js +63 -0
- package/dist/utils/npm-pack.js +55 -0
- package/dist/utils/platform-sync.js +160 -0
- package/dist/utils/spark-meta.js +42 -0
- package/dist/utils/sync-rule.js +295 -0
- package/package.json +5 -3
- package/upgrade/templates/README.md +34 -0
- package/upgrade/templates/design-stack/templates/.githooks/pre-commit +4 -0
- package/upgrade/templates/design-stack/templates/scripts/dev-local.sh +53 -0
- package/upgrade/templates/design-stack/templates/scripts/dev.sh +25 -0
- package/upgrade/templates/design-stack/templates/scripts/hooks/run-precommit.js +37 -0
- package/upgrade/templates/nestjs-react-fullstack/templates/.githooks/pre-commit +4 -0
- package/upgrade/templates/nestjs-react-fullstack/templates/.gitignore.append +8 -0
- package/upgrade/templates/nestjs-react-fullstack/templates/.spark_project +16 -0
- package/upgrade/templates/nestjs-react-fullstack/templates/drizzle.config.ts +55 -0
- package/upgrade/templates/nestjs-react-fullstack/templates/helper/gen-openapi.ts +34 -0
- package/upgrade/templates/nestjs-react-fullstack/templates/nest-cli.json +25 -0
- package/upgrade/templates/nestjs-react-fullstack/templates/scripts/build.sh +207 -0
- package/upgrade/templates/nestjs-react-fullstack/templates/scripts/dev-local.sh +61 -0
- package/upgrade/templates/nestjs-react-fullstack/templates/scripts/dev.js +295 -0
- package/upgrade/templates/nestjs-react-fullstack/templates/scripts/dev.sh +25 -0
- package/upgrade/templates/nestjs-react-fullstack/templates/scripts/hooks/run-precommit.js +37 -0
- package/upgrade/templates/nestjs-react-fullstack/templates/scripts/lint.js +150 -0
- package/upgrade/templates/nestjs-react-fullstack/templates/scripts/prune-smart.js +330 -0
- package/upgrade/templates/nestjs-react-fullstack/templates/scripts/run.sh +8 -0
- package/upgrade/templates/nestjs-react-fullstack/templates/server/global.d.ts +19 -0
- package/upgrade/templates/nestjs-react-fullstack/templates/tsconfig.node.json +5 -0
|
@@ -38,6 +38,12 @@ const api = __importStar(require("../../../api/index"));
|
|
|
38
38
|
const output_1 = require("../../../utils/output");
|
|
39
39
|
const index_1 = require("../../../api/observability/index");
|
|
40
40
|
const helpers_1 = require("./helpers");
|
|
41
|
+
function stringIdFilter(value) {
|
|
42
|
+
if (Array.isArray(value)) {
|
|
43
|
+
return value.length > 0 ? (0, helpers_1.inFilter)(value) : undefined;
|
|
44
|
+
}
|
|
45
|
+
return value ? (0, helpers_1.eqFilter)(value) : undefined;
|
|
46
|
+
}
|
|
41
47
|
/** miaoda observability log */
|
|
42
48
|
async function handleObservabilityLog(opts) {
|
|
43
49
|
const appID = opts.appId;
|
|
@@ -50,8 +56,8 @@ async function handleObservabilityLog(opts) {
|
|
|
50
56
|
// - duration_ms 暂未在 BAM 描述里明确列出,留 TODO 等 e2e 验证
|
|
51
57
|
const fieldFilters = (0, helpers_1.buildFieldFilters)([
|
|
52
58
|
{ key: 'severity_text', value: opts.level ? (0, helpers_1.eqFilter)(opts.level) : undefined },
|
|
53
|
-
{ key: 'attributes.ob_data_id', value:
|
|
54
|
-
{ key: 'trace_id', value:
|
|
59
|
+
{ key: 'attributes.ob_data_id', value: stringIdFilter(opts.logId) },
|
|
60
|
+
{ key: 'trace_id', value: stringIdFilter(opts.traceId) },
|
|
55
61
|
{ key: 'module', value: opts.module ? (0, helpers_1.eqFilter)(opts.module) : undefined },
|
|
56
62
|
{ key: 'user_id', value: opts.userId ? (0, helpers_1.eqFilter)(opts.userId, 'i64') : undefined },
|
|
57
63
|
{ key: 'page', value: opts.page ? (0, helpers_1.eqFilter)(opts.page) : undefined },
|
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.handleObservabilitySourceStack = handleObservabilitySourceStack;
|
|
37
|
+
const api = __importStar(require("../../../api/index"));
|
|
38
|
+
const output_1 = require("../../../utils/output");
|
|
39
|
+
const args_1 = require("../../../utils/args");
|
|
40
|
+
const helpers_1 = require("./helpers");
|
|
41
|
+
const SOURCE_MAP_FILE_PREFIX = 'client/assets/';
|
|
42
|
+
/** miaoda observability source-stack */
|
|
43
|
+
async function handleObservabilitySourceStack(opts) {
|
|
44
|
+
const logIds = normalizeValues(opts.logId);
|
|
45
|
+
const traceIds = normalizeValues(opts.traceId);
|
|
46
|
+
if (logIds.length === 0 && traceIds.length === 0) {
|
|
47
|
+
(0, args_1.failArgs)('至少传入线上环境日志 ID 或 trace ID');
|
|
48
|
+
}
|
|
49
|
+
const logs = await collectCandidateLogs(opts, { logIds, traceIds });
|
|
50
|
+
const results = await resolveCandidateLogs(opts.appId, logs);
|
|
51
|
+
(0, output_1.emit)({ data: results, next_cursor: null, has_more: false });
|
|
52
|
+
}
|
|
53
|
+
async function collectCandidateLogs(opts, params) {
|
|
54
|
+
const limit = (0, helpers_1.validateLimit)(opts.limit ?? 50);
|
|
55
|
+
const searches = [];
|
|
56
|
+
if (params.logIds.length > 0) {
|
|
57
|
+
searches.push(searchLogs(opts, {
|
|
58
|
+
limit,
|
|
59
|
+
fieldFilters: (0, helpers_1.buildFieldFilters)([
|
|
60
|
+
{ key: 'attributes.ob_data_id', value: stringIdFilter(params.logIds) },
|
|
61
|
+
]),
|
|
62
|
+
}));
|
|
63
|
+
}
|
|
64
|
+
if (params.traceIds.length > 0) {
|
|
65
|
+
searches.push(searchLogs(opts, {
|
|
66
|
+
limit,
|
|
67
|
+
fieldFilters: (0, helpers_1.buildFieldFilters)([
|
|
68
|
+
{ key: 'trace_id', value: stringIdFilter(params.traceIds) },
|
|
69
|
+
]),
|
|
70
|
+
}));
|
|
71
|
+
}
|
|
72
|
+
const allLogs = (await Promise.all(searches)).flat();
|
|
73
|
+
const deduped = new Map();
|
|
74
|
+
for (const log of allLogs) {
|
|
75
|
+
deduped.set(log.id, log);
|
|
76
|
+
}
|
|
77
|
+
return Array.from(deduped.values());
|
|
78
|
+
}
|
|
79
|
+
async function searchLogs(opts, params) {
|
|
80
|
+
const req = {
|
|
81
|
+
appID: opts.appId,
|
|
82
|
+
appEnv: 'runtime',
|
|
83
|
+
startTimestampNs: (0, helpers_1.parseToNs)(opts.since),
|
|
84
|
+
endTimestampNs: (0, helpers_1.parseToNs)(opts.until),
|
|
85
|
+
limit: params.limit,
|
|
86
|
+
fieldFilters: params.fieldFilters,
|
|
87
|
+
};
|
|
88
|
+
const resp = await api.observability.searchLogs(req);
|
|
89
|
+
return resp.logItems ?? [];
|
|
90
|
+
}
|
|
91
|
+
async function resolveCandidateLogs(appID, logs) {
|
|
92
|
+
const results = [];
|
|
93
|
+
for (const log of logs) {
|
|
94
|
+
const attrs = log.attributes ?? {};
|
|
95
|
+
const rawStack = pickAttr(attrs, ['stack', 'error_stack', 'errorStack']) ??
|
|
96
|
+
pickBodyStack(log.body) ??
|
|
97
|
+
log.body;
|
|
98
|
+
const frames = parseGeneratedFrames(rawStack);
|
|
99
|
+
const commitID = pickAttr(attrs, [
|
|
100
|
+
'release_commit_id',
|
|
101
|
+
'releaseCommitID',
|
|
102
|
+
'commit_id',
|
|
103
|
+
'commitID',
|
|
104
|
+
]);
|
|
105
|
+
const message = pickErrorMessage(log, rawStack);
|
|
106
|
+
const base = {
|
|
107
|
+
log_id: log.id,
|
|
108
|
+
trace_id: log.traceID ?? attrs.trace_id,
|
|
109
|
+
commit_id: commitID,
|
|
110
|
+
source_map_files: sourceMapFilesForFrames(frames),
|
|
111
|
+
};
|
|
112
|
+
const reason = missingReason({ frames, commitID });
|
|
113
|
+
if (reason) {
|
|
114
|
+
results.push({
|
|
115
|
+
...base,
|
|
116
|
+
status: 'unresolved',
|
|
117
|
+
reason,
|
|
118
|
+
error_message_stack: formatStack(message, frames),
|
|
119
|
+
});
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
const resolvedCommitID = commitID;
|
|
123
|
+
if (!resolvedCommitID)
|
|
124
|
+
continue;
|
|
125
|
+
let resolvedFrames;
|
|
126
|
+
try {
|
|
127
|
+
resolvedFrames = await resolveFramesBySourceMap(appID, resolvedCommitID, frames);
|
|
128
|
+
}
|
|
129
|
+
catch (err) {
|
|
130
|
+
results.push({
|
|
131
|
+
...base,
|
|
132
|
+
status: 'unresolved',
|
|
133
|
+
reason: `调用 resolve_stack_trace 失败:${errorMessage(err)}`,
|
|
134
|
+
error_message_stack: formatStack(message, frames),
|
|
135
|
+
});
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
results.push({
|
|
139
|
+
...base,
|
|
140
|
+
status: 'resolved',
|
|
141
|
+
error_message_stack: formatStack(message, resolvedFrames),
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
return results;
|
|
145
|
+
}
|
|
146
|
+
function normalizeValues(value) {
|
|
147
|
+
if (Array.isArray(value)) {
|
|
148
|
+
return value.filter((item) => item.length > 0);
|
|
149
|
+
}
|
|
150
|
+
return value ? [value] : [];
|
|
151
|
+
}
|
|
152
|
+
function stringIdFilter(values) {
|
|
153
|
+
if (values.length === 0)
|
|
154
|
+
return undefined;
|
|
155
|
+
return values.length === 1 ? (0, helpers_1.eqFilter)(values[0]) : (0, helpers_1.inFilter)(values);
|
|
156
|
+
}
|
|
157
|
+
function pickAttr(attrs, keys) {
|
|
158
|
+
for (const key of keys) {
|
|
159
|
+
const value = attrs[key];
|
|
160
|
+
if (value)
|
|
161
|
+
return value;
|
|
162
|
+
}
|
|
163
|
+
return undefined;
|
|
164
|
+
}
|
|
165
|
+
async function resolveFramesBySourceMap(appID, commitID, frames) {
|
|
166
|
+
const resp = await api.observability.resolveStackTrace({
|
|
167
|
+
appID,
|
|
168
|
+
commitID,
|
|
169
|
+
sourceMapFilePrefix: SOURCE_MAP_FILE_PREFIX,
|
|
170
|
+
frames,
|
|
171
|
+
});
|
|
172
|
+
return resp.frames ?? frames;
|
|
173
|
+
}
|
|
174
|
+
function parseGeneratedFrames(stack) {
|
|
175
|
+
if (!stack)
|
|
176
|
+
return [];
|
|
177
|
+
const jsonFrames = parseJsonStackFrames(stack);
|
|
178
|
+
if (jsonFrames.length > 0)
|
|
179
|
+
return jsonFrames;
|
|
180
|
+
const frames = [];
|
|
181
|
+
const parenFramePattern = /\((.+):(\d+):(\d+)\)$/;
|
|
182
|
+
const plainFramePattern = /(?:at\s+)?(.+):(\d+):(\d+)$/;
|
|
183
|
+
for (const line of stack.split('\n')) {
|
|
184
|
+
const trimmed = line.trim();
|
|
185
|
+
const match = parenFramePattern.exec(trimmed) ?? plainFramePattern.exec(trimmed);
|
|
186
|
+
if (!match)
|
|
187
|
+
continue;
|
|
188
|
+
const [, fileName, lineNumber, columnNumber] = match;
|
|
189
|
+
if (!fileName || !lineNumber || !columnNumber)
|
|
190
|
+
continue;
|
|
191
|
+
frames.push({
|
|
192
|
+
fileName: normalizeFrameFileName(fileName),
|
|
193
|
+
line: Number(lineNumber),
|
|
194
|
+
column: Number(columnNumber),
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
return frames.slice(0, 2000);
|
|
198
|
+
}
|
|
199
|
+
function parseJsonStackFrames(stack) {
|
|
200
|
+
const trimmed = stack.trim();
|
|
201
|
+
if (!trimmed.startsWith('['))
|
|
202
|
+
return [];
|
|
203
|
+
let parsed;
|
|
204
|
+
try {
|
|
205
|
+
parsed = JSON.parse(trimmed);
|
|
206
|
+
}
|
|
207
|
+
catch {
|
|
208
|
+
return [];
|
|
209
|
+
}
|
|
210
|
+
if (!Array.isArray(parsed))
|
|
211
|
+
return [];
|
|
212
|
+
return parsed
|
|
213
|
+
.map((item) => normalizeJsonFrame(item))
|
|
214
|
+
.filter((frame) => Boolean(frame))
|
|
215
|
+
.slice(0, 2000);
|
|
216
|
+
}
|
|
217
|
+
function normalizeJsonFrame(item) {
|
|
218
|
+
if (!isRecord(item))
|
|
219
|
+
return undefined;
|
|
220
|
+
const fileName = item.fileName;
|
|
221
|
+
const line = item.line;
|
|
222
|
+
const column = item.column;
|
|
223
|
+
if (typeof fileName !== 'string')
|
|
224
|
+
return undefined;
|
|
225
|
+
const lineNumber = toFiniteNumber(line);
|
|
226
|
+
const columnNumber = toFiniteNumber(column);
|
|
227
|
+
if (lineNumber === undefined || columnNumber === undefined)
|
|
228
|
+
return undefined;
|
|
229
|
+
return {
|
|
230
|
+
fileName: normalizeFrameFileName(fileName),
|
|
231
|
+
line: lineNumber,
|
|
232
|
+
column: columnNumber,
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
function pickErrorMessage(log, rawStack) {
|
|
236
|
+
return (pickBodyErrorMessage(log.body) ??
|
|
237
|
+
firstTextStackLine(rawStack) ??
|
|
238
|
+
pickAttr(log.attributes ?? {}, ['error_message', 'errorMessage', 'message']));
|
|
239
|
+
}
|
|
240
|
+
function pickBodyStack(body) {
|
|
241
|
+
const parsed = parseBodyRecord(body);
|
|
242
|
+
if (!parsed)
|
|
243
|
+
return undefined;
|
|
244
|
+
return (stringProp(parsed, 'stack') ??
|
|
245
|
+
nestedStringProp(parsed, ['error', 'stack']) ??
|
|
246
|
+
nestedStringProp(parsed, ['response', 'error', 'stack']) ??
|
|
247
|
+
pickConsoleArgsStack(parsed));
|
|
248
|
+
}
|
|
249
|
+
function pickBodyErrorMessage(body) {
|
|
250
|
+
const parsed = parseBodyRecord(body);
|
|
251
|
+
if (!parsed)
|
|
252
|
+
return undefined;
|
|
253
|
+
return (stringProp(parsed, 'error_message') ??
|
|
254
|
+
stringProp(parsed, 'message') ??
|
|
255
|
+
nestedStringProp(parsed, ['error', 'message']) ??
|
|
256
|
+
nestedStringProp(parsed, ['response', 'error', 'message']) ??
|
|
257
|
+
pickConsoleArgsMessage(parsed));
|
|
258
|
+
}
|
|
259
|
+
function pickConsoleArgsMessage(record) {
|
|
260
|
+
const parts = Object.entries(record)
|
|
261
|
+
.filter(([key]) => /^\d+$/.test(key))
|
|
262
|
+
.sort(([left], [right]) => Number(left) - Number(right))
|
|
263
|
+
.map(([, value]) => consoleArgMessage(value))
|
|
264
|
+
.filter((message) => Boolean(message));
|
|
265
|
+
if (parts.length === 0)
|
|
266
|
+
return undefined;
|
|
267
|
+
return parts.join(' ').replace(/\s+/g, ' ').trim();
|
|
268
|
+
}
|
|
269
|
+
function pickConsoleArgsStack(record) {
|
|
270
|
+
return Object.entries(record)
|
|
271
|
+
.filter(([key]) => /^\d+$/.test(key))
|
|
272
|
+
.sort(([left], [right]) => Number(left) - Number(right))
|
|
273
|
+
.map(([, value]) => consoleArgStack(value))
|
|
274
|
+
.find((stack) => Boolean(stack));
|
|
275
|
+
}
|
|
276
|
+
function consoleArgStack(value) {
|
|
277
|
+
if (typeof value === 'string') {
|
|
278
|
+
const stack = value.trim();
|
|
279
|
+
return looksLikeTextStack(stack) ? stack : undefined;
|
|
280
|
+
}
|
|
281
|
+
if (!isRecord(value))
|
|
282
|
+
return undefined;
|
|
283
|
+
return (stringProp(value, 'stack') ??
|
|
284
|
+
nestedStringProp(value, ['error', 'stack']) ??
|
|
285
|
+
nestedStringProp(value, ['response', 'error', 'stack']));
|
|
286
|
+
}
|
|
287
|
+
function consoleArgMessage(value) {
|
|
288
|
+
if (typeof value === 'string') {
|
|
289
|
+
const message = value.trim();
|
|
290
|
+
return message.length > 0 ? message : undefined;
|
|
291
|
+
}
|
|
292
|
+
if (!isRecord(value))
|
|
293
|
+
return undefined;
|
|
294
|
+
return errorRecordMessage(value);
|
|
295
|
+
}
|
|
296
|
+
function errorRecordMessage(record) {
|
|
297
|
+
const stackTitle = firstTextStackLine(stringProp(record, 'stack'));
|
|
298
|
+
if (stackTitle)
|
|
299
|
+
return stackTitle;
|
|
300
|
+
const name = stringProp(record, 'name');
|
|
301
|
+
const message = stringProp(record, 'message') ??
|
|
302
|
+
nestedStringProp(record, ['error', 'message']) ??
|
|
303
|
+
nestedStringProp(record, ['response', 'error', 'message']);
|
|
304
|
+
if (name && message && !message.startsWith(`${name}:`)) {
|
|
305
|
+
return `${name}: ${message}`;
|
|
306
|
+
}
|
|
307
|
+
return message ?? name;
|
|
308
|
+
}
|
|
309
|
+
function parseBodyRecord(body) {
|
|
310
|
+
if (!body)
|
|
311
|
+
return undefined;
|
|
312
|
+
let parsed;
|
|
313
|
+
try {
|
|
314
|
+
parsed = JSON.parse(body);
|
|
315
|
+
}
|
|
316
|
+
catch {
|
|
317
|
+
return undefined;
|
|
318
|
+
}
|
|
319
|
+
return isRecord(parsed) ? parsed : undefined;
|
|
320
|
+
}
|
|
321
|
+
function firstTextStackLine(stack) {
|
|
322
|
+
const trimmed = stack?.trim();
|
|
323
|
+
if (!trimmed || trimmed.startsWith('['))
|
|
324
|
+
return undefined;
|
|
325
|
+
return trimmed
|
|
326
|
+
.split('\n')
|
|
327
|
+
.map((line) => line.trim())
|
|
328
|
+
.find((line) => line.length > 0 && !line.startsWith('at '));
|
|
329
|
+
}
|
|
330
|
+
function looksLikeTextStack(value) {
|
|
331
|
+
return value.length > 0 && /:\d+:\d+(?:\)|$)/.test(value);
|
|
332
|
+
}
|
|
333
|
+
function missingReason(params) {
|
|
334
|
+
if (!params.commitID)
|
|
335
|
+
return '日志缺少 release_commit_id / commit_id,无法定位构建产物';
|
|
336
|
+
if (params.frames.length === 0)
|
|
337
|
+
return '日志中没有可解析的 generated stack frame';
|
|
338
|
+
return undefined;
|
|
339
|
+
}
|
|
340
|
+
function normalizeFrameFileName(fileName) {
|
|
341
|
+
return fileName.split(/[/?#]/).filter(Boolean).pop() ?? fileName;
|
|
342
|
+
}
|
|
343
|
+
function formatStack(message, frames) {
|
|
344
|
+
const stack = frames
|
|
345
|
+
.map((frame) => {
|
|
346
|
+
if (frame.sourceFileName) {
|
|
347
|
+
return ` at ${frame.sourceFileName}:${String(frame.sourceLine)}:${String(frame.sourceColumn)}`;
|
|
348
|
+
}
|
|
349
|
+
return ` at ${frame.fileName}:${String(frame.line)}:${String(frame.column)}`;
|
|
350
|
+
})
|
|
351
|
+
.join('\n');
|
|
352
|
+
if (message && stack)
|
|
353
|
+
return `${message}\n${stack}`;
|
|
354
|
+
return message ?? stack;
|
|
355
|
+
}
|
|
356
|
+
function isRecord(value) {
|
|
357
|
+
return typeof value === 'object' && value !== null;
|
|
358
|
+
}
|
|
359
|
+
function toFiniteNumber(value) {
|
|
360
|
+
if (typeof value === 'number' && Number.isFinite(value))
|
|
361
|
+
return value;
|
|
362
|
+
if (typeof value === 'string' && value.trim()) {
|
|
363
|
+
const numberValue = Number(value);
|
|
364
|
+
return Number.isFinite(numberValue) ? numberValue : undefined;
|
|
365
|
+
}
|
|
366
|
+
return undefined;
|
|
367
|
+
}
|
|
368
|
+
function stringProp(record, key) {
|
|
369
|
+
const value = record[key];
|
|
370
|
+
return typeof value === 'string' && value.length > 0 ? value : undefined;
|
|
371
|
+
}
|
|
372
|
+
function nestedStringProp(record, path) {
|
|
373
|
+
let current = record;
|
|
374
|
+
for (const key of path) {
|
|
375
|
+
if (!isRecord(current))
|
|
376
|
+
return undefined;
|
|
377
|
+
current = current[key];
|
|
378
|
+
}
|
|
379
|
+
return typeof current === 'string' && current.length > 0 ? current : undefined;
|
|
380
|
+
}
|
|
381
|
+
function errorMessage(err) {
|
|
382
|
+
return err instanceof Error ? err.message : String(err);
|
|
383
|
+
}
|
|
384
|
+
function sourceMapFileForFrame(fileName) {
|
|
385
|
+
return `${SOURCE_MAP_FILE_PREFIX}${fileName}.map`;
|
|
386
|
+
}
|
|
387
|
+
function sourceMapFilesForFrames(frames) {
|
|
388
|
+
return Array.from(new Set(frames.map((frame) => sourceMapFileForFrame(frame.fileName))));
|
|
389
|
+
}
|
|
@@ -40,6 +40,12 @@ const output_1 = require("../../../utils/output");
|
|
|
40
40
|
const args_1 = require("../../../utils/args");
|
|
41
41
|
const index_1 = require("../../../api/observability/index");
|
|
42
42
|
const helpers_1 = require("./helpers");
|
|
43
|
+
function stringIdFilter(value) {
|
|
44
|
+
if (Array.isArray(value)) {
|
|
45
|
+
return value.length > 0 ? (0, helpers_1.inFilter)(value) : undefined;
|
|
46
|
+
}
|
|
47
|
+
return value ? (0, helpers_1.eqFilter)(value) : undefined;
|
|
48
|
+
}
|
|
43
49
|
/** miaoda observability trace list */
|
|
44
50
|
async function handleObservabilityTraceList(opts) {
|
|
45
51
|
const appID = opts.appId;
|
|
@@ -51,7 +57,7 @@ async function handleObservabilityTraceList(opts) {
|
|
|
51
57
|
// - 入口 span:BAM 没有 entrySpanName fieldFilter,统一走 fuzzyFilter(trace endpoint
|
|
52
58
|
// 默认作用于 span name),所以 --root-span 不进 fieldFilters
|
|
53
59
|
const fieldFilters = (0, helpers_1.buildFieldFilters)([
|
|
54
|
-
{ key: 'trace_id', value:
|
|
60
|
+
{ key: 'trace_id', value: stringIdFilter(opts.traceId) },
|
|
55
61
|
{ key: 'user_id', value: opts.userId ? (0, helpers_1.eqFilter)(opts.userId, 'i64') : undefined },
|
|
56
62
|
]);
|
|
57
63
|
const req = {
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.handleSkillsStatus = exports.handleSkillsSync = void 0;
|
|
4
|
+
var sync_1 = require("./sync");
|
|
5
|
+
Object.defineProperty(exports, "handleSkillsSync", { enumerable: true, get: function () { return sync_1.handleSkillsSync; } });
|
|
6
|
+
var status_1 = require("./status");
|
|
7
|
+
Object.defineProperty(exports, "handleSkillsStatus", { enumerable: true, get: function () { return status_1.handleSkillsStatus; } });
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.handleSkillsStatus = handleSkillsStatus;
|
|
7
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
8
|
+
const index_1 = require("../../../services/skills/index");
|
|
9
|
+
const spark_meta_1 = require("../../../utils/spark-meta");
|
|
10
|
+
const output_1 = require("../../../utils/output");
|
|
11
|
+
/**
|
|
12
|
+
* miaoda skills status [--dir <path>]
|
|
13
|
+
*
|
|
14
|
+
* 从 .spark/meta.json 读 stack,扫描 <dir>/.agent/steering/<stack>/,
|
|
15
|
+
* 给出当前装了哪些 skills、tech.md 是否在。纯本地操作,不联网。
|
|
16
|
+
* meta 缺 stack 时返回 present=false(不抛错,方便和 init 的引导分开)。
|
|
17
|
+
*/
|
|
18
|
+
async function handleSkillsStatus(opts) {
|
|
19
|
+
await Promise.resolve();
|
|
20
|
+
const targetDir = node_path_1.default.resolve(opts.dir ?? process.cwd());
|
|
21
|
+
const meta = (0, spark_meta_1.readSparkMeta)(targetDir);
|
|
22
|
+
const status = (0, index_1.readSkillsStatus)({ targetDir, stack: meta.stack });
|
|
23
|
+
(0, output_1.emit)({
|
|
24
|
+
data: {
|
|
25
|
+
stack: meta.stack ?? null,
|
|
26
|
+
present: status.present,
|
|
27
|
+
skills: status.skills,
|
|
28
|
+
techSynced: status.techSynced,
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.handleSkillsSync = handleSkillsSync;
|
|
7
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
8
|
+
const coding_steering_1 = require("../../../utils/coding-steering");
|
|
9
|
+
const spark_meta_1 = require("../../../utils/spark-meta");
|
|
10
|
+
const error_1 = require("../../../utils/error");
|
|
11
|
+
const output_1 = require("../../../utils/output");
|
|
12
|
+
/**
|
|
13
|
+
* miaoda skills sync [version] [--dir <path>]
|
|
14
|
+
*
|
|
15
|
+
* 从 .spark/meta.json 读 stack(+ 默认 steeringVersion),把 coding-steering 包内对应 stack
|
|
16
|
+
* 的 skills + tech.md 同步到 <dir>/.agent/steering/。需要先跑过 `miaoda app init`。
|
|
17
|
+
*/
|
|
18
|
+
async function handleSkillsSync(opts) {
|
|
19
|
+
await Promise.resolve();
|
|
20
|
+
const targetDir = node_path_1.default.resolve(opts.dir ?? process.cwd());
|
|
21
|
+
const meta = (0, spark_meta_1.readSparkMeta)(targetDir);
|
|
22
|
+
if (meta.stack === undefined || meta.stack === '') {
|
|
23
|
+
throw new error_1.AppError('SKILLS_META_INCOMPLETE', '.spark/meta.json missing stack — run `miaoda app init` first');
|
|
24
|
+
}
|
|
25
|
+
const version = opts.version ?? meta.steeringVersion;
|
|
26
|
+
const versionSource = opts.version
|
|
27
|
+
? 'cli-arg'
|
|
28
|
+
: meta.steeringVersion
|
|
29
|
+
? 'meta.json'
|
|
30
|
+
: 'default-latest';
|
|
31
|
+
const result = (0, coding_steering_1.syncCodingSteering)({
|
|
32
|
+
stack: meta.stack,
|
|
33
|
+
targetDir,
|
|
34
|
+
version,
|
|
35
|
+
outputLayout: opts.local === true ? 'flat' : 'nested',
|
|
36
|
+
});
|
|
37
|
+
(0, output_1.emit)({
|
|
38
|
+
data: {
|
|
39
|
+
stack: meta.stack,
|
|
40
|
+
version: result.version,
|
|
41
|
+
versionSource,
|
|
42
|
+
syncedSkills: result.syncedSkills,
|
|
43
|
+
techSynced: result.techSynced,
|
|
44
|
+
...(result.claudeSkillsLink !== undefined
|
|
45
|
+
? { claudeSkillsLink: result.claudeSkillsLink }
|
|
46
|
+
: {}),
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FULLSTACK_CLI_PIN_SPEC = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* 临时钉死 `@lark-apaas/fullstack-cli` 的 npx 调用版本。
|
|
6
|
+
*
|
|
7
|
+
* 用于 user app `package.json` 里所有 `npx -y @lark-apaas/fullstack-cli ...` 调用 ——
|
|
8
|
+
* sync 规则会按本常量生成 `npx -y <FULLSTACK_CLI_PIN_SPEC> ...`,确保 user app 每次
|
|
9
|
+
* postinstall / gen-db-schema / sync 都拉到验证过能装插件的版本(避免 npx 拉 latest
|
|
10
|
+
* 时碰到外部 prerelease 回归版本)。
|
|
11
|
+
*
|
|
12
|
+
* 维护:
|
|
13
|
+
* - 跟 src/cli/handlers/app/sync.ts 里 PINNED_PLATFORM_VERSIONS['@lark-apaas/fullstack-cli']
|
|
14
|
+
* **保持一致**(前者用于 user app dependencies dep bump,后者用于 npm script 里 npx 调用)
|
|
15
|
+
* - 一旦 latest fullstack-cli 稳定且 token 鉴权回归 OK,可以去掉版本钉,让 npx 走 latest
|
|
16
|
+
*/
|
|
17
|
+
exports.FULLSTACK_CLI_PIN_SPEC = '@lark-apaas/fullstack-cli@1.1.49-alpha.0';
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* design-stack 的 sync 规则。
|
|
4
|
+
*
|
|
5
|
+
* design-stack 是 SSR-only 全栈 stack(design scene,MIAODA_APP_TYPE=4),无 nest 后端、
|
|
6
|
+
* 无数据库、无 nestjs-cli。所以规则集是 nestjs-react-fullstack 的子集:只保留
|
|
7
|
+
* scripts/.githooks/ 派生 + 基础 npm scripts,不动 nest-cli.json / drizzle / tsconfig.node.json。
|
|
8
|
+
*
|
|
9
|
+
* dev-local.sh 跟 nestjs-react-fullstack 不同(单进程 npm run dev,MIAODA_APP_TYPE=4),
|
|
10
|
+
* 单独维护在 upgrade/templates/design-stack/templates/scripts/dev-local.sh。
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.SYNC_CONFIG = void 0;
|
|
14
|
+
const fullstack_cli_pin_1 = require("../../config/fullstack-cli-pin");
|
|
15
|
+
exports.SYNC_CONFIG = {
|
|
16
|
+
sync: [
|
|
17
|
+
// 1. 派生 scripts/(含 design 专属 dev-local.sh + 通用 dev.sh / hooks/run-precommit.js)
|
|
18
|
+
{
|
|
19
|
+
type: 'directory',
|
|
20
|
+
from: 'scripts',
|
|
21
|
+
to: 'scripts',
|
|
22
|
+
overwrite: true,
|
|
23
|
+
},
|
|
24
|
+
// 1a. 同步 .githooks/(hook 入口,可执行 sh)
|
|
25
|
+
{
|
|
26
|
+
type: 'directory',
|
|
27
|
+
from: '.githooks',
|
|
28
|
+
to: '.githooks',
|
|
29
|
+
overwrite: true,
|
|
30
|
+
},
|
|
31
|
+
// 1b. scripts.prepare:npm install 后激活 git hooks
|
|
32
|
+
{
|
|
33
|
+
type: 'add-script',
|
|
34
|
+
name: 'prepare',
|
|
35
|
+
command: 'chmod +x .githooks/pre-commit 2>/dev/null; git config core.hooksPath .githooks 2>/dev/null || true',
|
|
36
|
+
overwrite: false,
|
|
37
|
+
},
|
|
38
|
+
// 1c. scripts.precommit
|
|
39
|
+
{
|
|
40
|
+
type: 'add-script',
|
|
41
|
+
name: 'precommit',
|
|
42
|
+
command: 'node scripts/hooks/run-precommit.js',
|
|
43
|
+
overwrite: false,
|
|
44
|
+
},
|
|
45
|
+
// 2. .gitignore 卫生:移除 package-lock.json + 加 .agent/
|
|
46
|
+
{
|
|
47
|
+
type: 'remove-line',
|
|
48
|
+
to: '.gitignore',
|
|
49
|
+
pattern: 'package-lock.json',
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
type: 'add-line',
|
|
53
|
+
to: '.gitignore',
|
|
54
|
+
line: '.agent/',
|
|
55
|
+
},
|
|
56
|
+
// 3. 老 npm scripts 迁移(裸 fullstack-cli → 钉版 npx)。两条 ifStartsWith 分别覆盖
|
|
57
|
+
// "裸 fullstack-cli"(最老形态)和 "npx 未钉版" 形态,统一升到 FULLSTACK_CLI_PIN_SPEC。
|
|
58
|
+
{
|
|
59
|
+
type: 'patch-script',
|
|
60
|
+
name: 'postinstall',
|
|
61
|
+
to: `npx -y ${fullstack_cli_pin_1.FULLSTACK_CLI_PIN_SPEC} action-plugin init`,
|
|
62
|
+
ifStartsWith: 'fullstack-cli action-plugin init',
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
type: 'patch-script',
|
|
66
|
+
name: 'postinstall',
|
|
67
|
+
to: `npx -y ${fullstack_cli_pin_1.FULLSTACK_CLI_PIN_SPEC} action-plugin init`,
|
|
68
|
+
ifStartsWith: 'npx -y @lark-apaas/fullstack-cli action-plugin init',
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
type: 'patch-script',
|
|
72
|
+
name: 'upgrade',
|
|
73
|
+
to: `npx -y ${fullstack_cli_pin_1.FULLSTACK_CLI_PIN_SPEC} sync --disable-gen-openapi`,
|
|
74
|
+
ifStartsWith: 'fullstack-cli sync',
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
type: 'patch-script',
|
|
78
|
+
name: 'upgrade',
|
|
79
|
+
to: `npx -y ${fullstack_cli_pin_1.FULLSTACK_CLI_PIN_SPEC} sync --disable-gen-openapi`,
|
|
80
|
+
ifStartsWith: 'npx -y @lark-apaas/fullstack-cli sync',
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
type: 'patch-script',
|
|
84
|
+
name: 'dev',
|
|
85
|
+
to: './scripts/dev.sh',
|
|
86
|
+
ifStartsWith: 'npm run upgrade && ',
|
|
87
|
+
},
|
|
88
|
+
// ===== miaoda-cli 本地开发新增规则 =====
|
|
89
|
+
// M1. scripts.dev:local —— 本地用户绕过 SANDBOX_ID 分发直接跑本地链路(npm run dev:local)。
|
|
90
|
+
{
|
|
91
|
+
type: 'add-script',
|
|
92
|
+
name: 'dev:local',
|
|
93
|
+
command: './scripts/dev-local.sh',
|
|
94
|
+
overwrite: false,
|
|
95
|
+
},
|
|
96
|
+
],
|
|
97
|
+
};
|
|
98
|
+
exports.default = exports.SYNC_CONFIG;
|