create-windy 0.8.0 → 0.8.1
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/cli.js +46 -41
- package/package.json +1 -1
- package/template/.windy-template.json +2 -2
- package/template/apps/agent-server/Dockerfile +1 -1
- package/template/apps/agent-server/README.md +1 -1
- package/template/apps/agent-server/src/southwind_agent_server/asgi.py +8 -0
- package/template/apps/agent-server/src/southwind_agent_server/runtime_logging.py +57 -0
- package/template/apps/agent-server/src/southwind_agent_server/structured_logging.py +134 -0
- package/template/apps/agent-server/src/southwind_agent_server/telemetry.py +4 -0
- package/template/apps/agent-server/tests/test_run_operational_logging.py +114 -0
- package/template/apps/agent-server/tests/test_structured_logging.py +105 -0
- package/template/apps/server/src/agent/isolated-execution-guard.test.ts +194 -0
- package/template/apps/server/src/agent/isolated-execution-guard.ts +202 -0
- package/template/apps/server/src/agent/run-definition-support.ts +11 -1
- package/template/apps/server/src/agent/run-facade.ts +7 -11
- package/template/apps/server/src/agent/run-operation-policy.ts +11 -0
- package/template/apps/server/src/agent/workflow-durable-runtime-input.ts +8 -5
- package/template/apps/server/src/jobs/legacy-service-runtime.ts +4 -0
- package/template/apps/server/src/jobs/runtime-logging.test.ts +212 -0
- package/template/apps/server/src/jobs/runtime-logging.ts +58 -0
- package/template/apps/server/src/jobs/worker.ts +54 -12
- package/template/apps/server/src/observability/bootstrap.ts +1 -4
- package/template/apps/server/src/observability/http-observability.ts +2 -3
- package/template/apps/server/src/observability/structured-logger.test.ts +31 -0
- package/template/apps/server/src/observability/structured-logger.ts +27 -0
- package/template/apps/server/src/platform-bootstrap.ts +9 -3
- package/template/apps/server/src/startup-finalization.ts +3 -3
- package/template/apps/server/src/system/built-in-roles.test.ts +23 -0
- package/template/apps/server/src/system/built-in-roles.ts +10 -4
- package/template/apps/web/src/pages/system/composables/useResourceEditor.ts +16 -5
- package/template/apps/web/src/pages/system/composables/useResourceEditor.webtest.ts +4 -0
- package/template/docs/architecture/log-governance-implementation.md +79 -0
- package/template/docs/architecture/log-governance-plan.md +39 -0
- package/template/docs/operations/observability.md +36 -4
- package/template/packages/modules/package.json +1 -1
- package/template/packages/modules/src/ai-isolated-execution-policy.test.ts +70 -0
- package/template/packages/modules/src/ai-isolated-execution-policy.ts +76 -0
- package/template/packages/modules/src/ai-operation-composition.ts +2 -0
- package/template/packages/modules/src/manifest.ts +23 -0
- package/template/packages/modules/src/system-features.ts +11 -10
- package/template/packages/server-sdk/package.json +1 -1
- package/template/packages/shared/index.ts +1 -0
- package/template/packages/shared/package.json +3 -2
- package/template/packages/shared/src/structured-log.test.ts +147 -0
- package/template/packages/shared/src/structured-log.ts +215 -0
package/dist/cli.js
CHANGED
|
@@ -33,7 +33,7 @@ var __toESM = (mod, isNodeMode, target) => {
|
|
|
33
33
|
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
34
34
|
var __require = import.meta.require;
|
|
35
35
|
|
|
36
|
-
// ../../node_modules
|
|
36
|
+
// ../../node_modules/cli-width/index.js
|
|
37
37
|
var require_cli_width = __commonJS((exports, module2) => {
|
|
38
38
|
module2.exports = cliWidth;
|
|
39
39
|
function normalizeOpts(options) {
|
|
@@ -73,7 +73,7 @@ var require_cli_width = __commonJS((exports, module2) => {
|
|
|
73
73
|
}
|
|
74
74
|
});
|
|
75
75
|
|
|
76
|
-
// ../../node_modules
|
|
76
|
+
// ../../node_modules/mute-stream/lib/index.js
|
|
77
77
|
var require_lib = __commonJS((exports, module2) => {
|
|
78
78
|
var Stream = __require("stream");
|
|
79
79
|
|
|
@@ -2022,7 +2022,14 @@ var nativeSymbols = {
|
|
|
2022
2022
|
};
|
|
2023
2023
|
var directoryFlags = constants2.O_RDONLY | constants2.O_DIRECTORY | constants2.O_NOFOLLOW;
|
|
2024
2024
|
var removeDirectoryFlag = process.platform === "darwin" ? 128 : 512;
|
|
2025
|
-
var getLibc = createLazyLibcLoader((candidate) =>
|
|
2025
|
+
var getLibc = createLazyLibcLoader((candidate) => {
|
|
2026
|
+
const libc = dlopen2(candidate, nativeSymbols);
|
|
2027
|
+
const errnoSymbol = process.platform === "darwin" ? libc.symbols.__error : libc.symbols.__errno_location;
|
|
2028
|
+
const errnoPointer = errnoSymbol();
|
|
2029
|
+
if (!errnoPointer)
|
|
2030
|
+
throw new Error("\u65E0\u6CD5\u8BFB\u53D6\u539F\u751F\u9519\u8BEF\u7801\uFF0C\u4E8B\u52A1\u5B89\u5168\u5173\u95ED");
|
|
2031
|
+
return { symbols: libc.symbols, errnoPointer };
|
|
2032
|
+
}, "\u5F53\u524D\u5E73\u53F0\u65E0\u6CD5\u52A0\u8F7D\u5B89\u5168\u76EE\u5F55\u53E5\u67C4 API");
|
|
2026
2033
|
function resolveSafeTarget(root, path) {
|
|
2027
2034
|
if (!path || isAbsolute(path) || path.includes("\x00") || path.split(/[\\/]/).includes("..")) {
|
|
2028
2035
|
throw new Error(`\u66F4\u65B0\u8BA1\u5212\u5305\u542B\u4E0D\u5B89\u5168\u8DEF\u5F84\uFF1A${path}`);
|
|
@@ -2196,12 +2203,7 @@ function nativeUnlinkAt(directoryFd, name, flags) {
|
|
|
2196
2203
|
}
|
|
2197
2204
|
function nativeError(syscall, path) {
|
|
2198
2205
|
const libc = getLibc();
|
|
2199
|
-
const
|
|
2200
|
-
const errnoPointer = errnoSymbol();
|
|
2201
|
-
if (!errnoPointer) {
|
|
2202
|
-
throw new Error(`\u65E0\u6CD5\u8BFB\u53D6 ${syscall} \u7684\u539F\u751F\u9519\u8BEF\u7801\uFF0C\u4E8B\u52A1\u5B89\u5168\u5173\u95ED`);
|
|
2203
|
-
}
|
|
2204
|
-
const errno = read.i32(errnoPointer, 0);
|
|
2206
|
+
const errno = read.i32(libc.errnoPointer, 0);
|
|
2205
2207
|
return Object.assign(new Error(`${syscall} ${path} \u5931\u8D25`), {
|
|
2206
2208
|
code: errnoCode(errno),
|
|
2207
2209
|
errno: -errno,
|
|
@@ -4107,6 +4109,8 @@ var templateDocumentationFiles = [
|
|
|
4107
4109
|
"docs/architecture/mcp-business-capabilities.md",
|
|
4108
4110
|
"docs/architecture/migration-bundle.md",
|
|
4109
4111
|
"docs/architecture/module-host.md",
|
|
4112
|
+
"docs/architecture/log-governance-plan.md",
|
|
4113
|
+
"docs/architecture/log-governance-implementation.md",
|
|
4110
4114
|
"docs/architecture/module-manifest-composition.md",
|
|
4111
4115
|
"docs/architecture/module-secret-resolution.md",
|
|
4112
4116
|
"docs/architecture/object-storage.md",
|
|
@@ -4673,7 +4677,7 @@ function isMissing6(error) {
|
|
|
4673
4677
|
import { createInterface as createInterface2 } from "readline/promises";
|
|
4674
4678
|
import { stdin, stdout } from "process";
|
|
4675
4679
|
|
|
4676
|
-
// ../../node_modules
|
|
4680
|
+
// ../../node_modules/@inquirer/core/dist/lib/key.js
|
|
4677
4681
|
var keybindings = ["emacs", "vim"];
|
|
4678
4682
|
var keybindingLookup = new Set(keybindings);
|
|
4679
4683
|
function isKeybinding(value) {
|
|
@@ -4690,7 +4694,7 @@ var isDownKey = (key, keybindings2 = []) => key.name === "down" || keybindings2.
|
|
|
4690
4694
|
var isSpaceKey = (key) => key.name === "space";
|
|
4691
4695
|
var isNumberKey = (key) => "1234567890".includes(key.name);
|
|
4692
4696
|
var isEnterKey = (key) => key.name === "enter" || key.name === "return";
|
|
4693
|
-
// ../../node_modules
|
|
4697
|
+
// ../../node_modules/@inquirer/core/dist/lib/errors.js
|
|
4694
4698
|
class AbortPromptError extends Error {
|
|
4695
4699
|
name = "AbortPromptError";
|
|
4696
4700
|
message = "Prompt was aborted";
|
|
@@ -4716,10 +4720,10 @@ class HookError extends Error {
|
|
|
4716
4720
|
class ValidationError extends Error {
|
|
4717
4721
|
name = "ValidationError";
|
|
4718
4722
|
}
|
|
4719
|
-
// ../../node_modules
|
|
4723
|
+
// ../../node_modules/@inquirer/core/dist/lib/use-state.js
|
|
4720
4724
|
import { AsyncResource as AsyncResource2 } from "async_hooks";
|
|
4721
4725
|
|
|
4722
|
-
// ../../node_modules
|
|
4726
|
+
// ../../node_modules/@inquirer/core/dist/lib/hook-engine.js
|
|
4723
4727
|
import { AsyncLocalStorage, AsyncResource } from "async_hooks";
|
|
4724
4728
|
var hookStorage = new AsyncLocalStorage;
|
|
4725
4729
|
function createStore(rl) {
|
|
@@ -4824,7 +4828,7 @@ var effectScheduler = {
|
|
|
4824
4828
|
}
|
|
4825
4829
|
};
|
|
4826
4830
|
|
|
4827
|
-
// ../../node_modules
|
|
4831
|
+
// ../../node_modules/@inquirer/core/dist/lib/use-state.js
|
|
4828
4832
|
function isFactory(value) {
|
|
4829
4833
|
return typeof value === "function";
|
|
4830
4834
|
}
|
|
@@ -4845,7 +4849,7 @@ function useState(defaultValue) {
|
|
|
4845
4849
|
});
|
|
4846
4850
|
}
|
|
4847
4851
|
|
|
4848
|
-
// ../../node_modules
|
|
4852
|
+
// ../../node_modules/@inquirer/core/dist/lib/use-effect.js
|
|
4849
4853
|
function useEffect(cb, depArray) {
|
|
4850
4854
|
withPointer((pointer) => {
|
|
4851
4855
|
const oldDeps = pointer.get();
|
|
@@ -4857,10 +4861,10 @@ function useEffect(cb, depArray) {
|
|
|
4857
4861
|
});
|
|
4858
4862
|
}
|
|
4859
4863
|
|
|
4860
|
-
// ../../node_modules
|
|
4864
|
+
// ../../node_modules/@inquirer/core/dist/lib/theme.js
|
|
4861
4865
|
import { styleText } from "util";
|
|
4862
4866
|
|
|
4863
|
-
// ../../node_modules
|
|
4867
|
+
// ../../node_modules/@inquirer/figures/dist/index.js
|
|
4864
4868
|
import process2 from "process";
|
|
4865
4869
|
function isUnicodeSupported() {
|
|
4866
4870
|
if (!process2.platform.startsWith("win")) {
|
|
@@ -5149,7 +5153,7 @@ var figures = shouldUseMain ? mainSymbols : fallbackSymbols;
|
|
|
5149
5153
|
var dist_default = figures;
|
|
5150
5154
|
var replacements = Object.entries(specialMainSymbols);
|
|
5151
5155
|
|
|
5152
|
-
// ../../node_modules
|
|
5156
|
+
// ../../node_modules/@inquirer/core/dist/lib/theme.js
|
|
5153
5157
|
var defaultTheme = {
|
|
5154
5158
|
prefix: {
|
|
5155
5159
|
idle: styleText("blue", "?"),
|
|
@@ -5177,7 +5181,7 @@ function getDefaultTheme() {
|
|
|
5177
5181
|
};
|
|
5178
5182
|
}
|
|
5179
5183
|
|
|
5180
|
-
// ../../node_modules
|
|
5184
|
+
// ../../node_modules/@inquirer/core/dist/lib/make-theme.js
|
|
5181
5185
|
function isPlainObject(value) {
|
|
5182
5186
|
if (typeof value !== "object" || value === null)
|
|
5183
5187
|
return false;
|
|
@@ -5205,7 +5209,7 @@ function makeTheme(...themes) {
|
|
|
5205
5209
|
return deepMerge(...themesToMerge);
|
|
5206
5210
|
}
|
|
5207
5211
|
|
|
5208
|
-
// ../../node_modules
|
|
5212
|
+
// ../../node_modules/@inquirer/core/dist/lib/use-prefix.js
|
|
5209
5213
|
function usePrefix({ status = "idle", theme }) {
|
|
5210
5214
|
const [showLoader, setShowLoader] = useState(false);
|
|
5211
5215
|
const [tick, setTick] = useState(0);
|
|
@@ -5235,7 +5239,7 @@ function usePrefix({ status = "idle", theme }) {
|
|
|
5235
5239
|
const iconName = status === "loading" ? "idle" : status;
|
|
5236
5240
|
return typeof prefix === "string" ? prefix : prefix[iconName] ?? prefix["idle"];
|
|
5237
5241
|
}
|
|
5238
|
-
// ../../node_modules
|
|
5242
|
+
// ../../node_modules/@inquirer/core/dist/lib/use-memo.js
|
|
5239
5243
|
function useMemo(fn, dependencies) {
|
|
5240
5244
|
return withPointer((pointer) => {
|
|
5241
5245
|
const prev = pointer.get();
|
|
@@ -5247,12 +5251,12 @@ function useMemo(fn, dependencies) {
|
|
|
5247
5251
|
return prev.value;
|
|
5248
5252
|
});
|
|
5249
5253
|
}
|
|
5250
|
-
// ../../node_modules
|
|
5254
|
+
// ../../node_modules/@inquirer/core/dist/lib/use-ref.js
|
|
5251
5255
|
function useRef(val) {
|
|
5252
5256
|
return useState({ current: val })[0];
|
|
5253
5257
|
}
|
|
5254
5258
|
|
|
5255
|
-
// ../../node_modules
|
|
5259
|
+
// ../../node_modules/@inquirer/core/dist/lib/use-keypress.js
|
|
5256
5260
|
function useKeypress(userHandler) {
|
|
5257
5261
|
const signal = useRef(userHandler);
|
|
5258
5262
|
signal.current = userHandler;
|
|
@@ -5270,10 +5274,10 @@ function useKeypress(userHandler) {
|
|
|
5270
5274
|
};
|
|
5271
5275
|
}, []);
|
|
5272
5276
|
}
|
|
5273
|
-
// ../../node_modules
|
|
5277
|
+
// ../../node_modules/@inquirer/core/dist/lib/utils.js
|
|
5274
5278
|
var import_cli_width = __toESM(require_cli_width(), 1);
|
|
5275
5279
|
|
|
5276
|
-
// ../../node_modules
|
|
5280
|
+
// ../../node_modules/fast-string-truncated-width/dist/utils.js
|
|
5277
5281
|
var getCodePointsLength = (() => {
|
|
5278
5282
|
const SURROGATE_PAIR_RE = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
|
|
5279
5283
|
return (input) => {
|
|
@@ -5292,7 +5296,7 @@ var isWideNotCJKTNotEmoji = (x) => {
|
|
|
5292
5296
|
return x === 8987 || x === 9001 || x >= 12272 && x <= 12287 || x >= 12289 && x <= 12350 || x >= 12441 && x <= 12543 || x >= 12549 && x <= 12591 || x >= 12593 && x <= 12686 || x >= 12688 && x <= 12771 || x >= 12783 && x <= 12830 || x >= 12832 && x <= 12871 || x >= 12880 && x <= 19903 || x >= 65040 && x <= 65049 || x >= 65072 && x <= 65106 || x >= 65108 && x <= 65126 || x >= 65128 && x <= 65131 || x >= 127488 && x <= 127490 || x >= 127504 && x <= 127547 || x >= 127552 && x <= 127560 || x >= 131072 && x <= 196605 || x >= 196608 && x <= 262141;
|
|
5293
5297
|
};
|
|
5294
5298
|
|
|
5295
|
-
// ../../node_modules
|
|
5299
|
+
// ../../node_modules/fast-string-truncated-width/dist/index.js
|
|
5296
5300
|
var ANSI_RE = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]|\u001b\]8;[^;]*;.*?(?:\u0007|\u001b\u005c)/y;
|
|
5297
5301
|
var CONTROL_RE = /[\x00-\x08\x0A-\x1F\x7F-\x9F]{1,1000}/y;
|
|
5298
5302
|
var CJKT_WIDE_RE = /(?:(?![\uFF61-\uFF9F\uFF00-\uFFEF])[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}\p{Script=Tangut}]){1,1000}/yu;
|
|
@@ -5391,7 +5395,7 @@ var getStringTruncatedWidth = (input, truncationOptions = {}, widthOptions = {})
|
|
|
5391
5395
|
};
|
|
5392
5396
|
var dist_default2 = getStringTruncatedWidth;
|
|
5393
5397
|
|
|
5394
|
-
// ../../node_modules
|
|
5398
|
+
// ../../node_modules/fast-string-width/dist/index.js
|
|
5395
5399
|
var NO_TRUNCATION2 = {
|
|
5396
5400
|
limit: Infinity,
|
|
5397
5401
|
ellipsis: "",
|
|
@@ -5402,7 +5406,7 @@ var fastStringWidth = (input, options = {}) => {
|
|
|
5402
5406
|
};
|
|
5403
5407
|
var dist_default3 = fastStringWidth;
|
|
5404
5408
|
|
|
5405
|
-
// ../../node_modules
|
|
5409
|
+
// ../../node_modules/fast-wrap-ansi/lib/main.js
|
|
5406
5410
|
var ESC = "\x1B";
|
|
5407
5411
|
var CSI = "\x9B";
|
|
5408
5412
|
var END_CODE = 39;
|
|
@@ -5614,7 +5618,7 @@ function wrapAnsi(string, columns, options) {
|
|
|
5614
5618
|
`);
|
|
5615
5619
|
}
|
|
5616
5620
|
|
|
5617
|
-
// ../../node_modules
|
|
5621
|
+
// ../../node_modules/@inquirer/core/dist/lib/utils.js
|
|
5618
5622
|
function breakLines(content, width) {
|
|
5619
5623
|
return content.split(`
|
|
5620
5624
|
`).flatMap((line) => wrapAnsi(line, width, { trim: false, wordWrap: false }).split(`
|
|
@@ -5625,7 +5629,7 @@ function readlineWidth() {
|
|
|
5625
5629
|
return import_cli_width.default({ defaultWidth: 80, output: readline().output });
|
|
5626
5630
|
}
|
|
5627
5631
|
|
|
5628
|
-
// ../../node_modules
|
|
5632
|
+
// ../../node_modules/@inquirer/core/dist/lib/pagination/use-pagination.js
|
|
5629
5633
|
function usePointerPosition({ active, renderedItems, pageSize, loop }) {
|
|
5630
5634
|
const state = useRef({
|
|
5631
5635
|
lastPointer: active,
|
|
@@ -5691,12 +5695,12 @@ function usePagination({ items, active, renderItem, pageSize, loop = true }) {
|
|
|
5691
5695
|
return pageBuffer.filter((line) => typeof line === "string").join(`
|
|
5692
5696
|
`);
|
|
5693
5697
|
}
|
|
5694
|
-
// ../../node_modules
|
|
5698
|
+
// ../../node_modules/@inquirer/core/dist/lib/create-prompt.js
|
|
5695
5699
|
var import_mute_stream = __toESM(require_lib(), 1);
|
|
5696
5700
|
import * as readline2 from "readline";
|
|
5697
5701
|
import { AsyncResource as AsyncResource3 } from "async_hooks";
|
|
5698
5702
|
|
|
5699
|
-
// ../../node_modules
|
|
5703
|
+
// ../../node_modules/signal-exit/dist/mjs/signals.js
|
|
5700
5704
|
var signals = [];
|
|
5701
5705
|
signals.push("SIGHUP", "SIGINT", "SIGTERM");
|
|
5702
5706
|
if (process.platform !== "win32") {
|
|
@@ -5706,7 +5710,7 @@ if (process.platform === "linux") {
|
|
|
5706
5710
|
signals.push("SIGIO", "SIGPOLL", "SIGPWR", "SIGSTKFLT");
|
|
5707
5711
|
}
|
|
5708
5712
|
|
|
5709
|
-
// ../../node_modules
|
|
5713
|
+
// ../../node_modules/signal-exit/dist/mjs/index.js
|
|
5710
5714
|
var processOk = (process3) => !!process3 && typeof process3 === "object" && typeof process3.removeListener === "function" && typeof process3.emit === "function" && typeof process3.reallyExit === "function" && typeof process3.listeners === "function" && typeof process3.kill === "function" && typeof process3.pid === "number" && typeof process3.on === "function";
|
|
5711
5715
|
var kExitEmitter = Symbol.for("signal-exit emitter");
|
|
5712
5716
|
var global = globalThis;
|
|
@@ -5904,10 +5908,10 @@ var {
|
|
|
5904
5908
|
unload
|
|
5905
5909
|
} = signalExitWrap(processOk(process3) ? new SignalExit(process3) : new SignalExitFallback);
|
|
5906
5910
|
|
|
5907
|
-
// ../../node_modules
|
|
5911
|
+
// ../../node_modules/@inquirer/core/dist/lib/screen-manager.js
|
|
5908
5912
|
import { stripVTControlCharacters } from "util";
|
|
5909
5913
|
|
|
5910
|
-
// ../../node_modules
|
|
5914
|
+
// ../../node_modules/@inquirer/ansi/dist/index.js
|
|
5911
5915
|
var ESC2 = "\x1B[";
|
|
5912
5916
|
var cursorLeft = ESC2 + "G";
|
|
5913
5917
|
var cursorHide = ESC2 + "?25l";
|
|
@@ -5923,7 +5927,7 @@ var cursorTo = (x, y) => {
|
|
|
5923
5927
|
var eraseLine = ESC2 + "2K";
|
|
5924
5928
|
var eraseLines = (lines) => lines > 0 ? (eraseLine + cursorUp(1)).repeat(lines - 1) + eraseLine + cursorLeft : "";
|
|
5925
5929
|
|
|
5926
|
-
// ../../node_modules
|
|
5930
|
+
// ../../node_modules/@inquirer/core/dist/lib/screen-manager.js
|
|
5927
5931
|
var height = (content) => content.split(`
|
|
5928
5932
|
`).length;
|
|
5929
5933
|
var lastLine = (content) => content.split(`
|
|
@@ -5989,7 +5993,7 @@ class ScreenManager {
|
|
|
5989
5993
|
}
|
|
5990
5994
|
}
|
|
5991
5995
|
|
|
5992
|
-
// ../../node_modules
|
|
5996
|
+
// ../../node_modules/@inquirer/core/dist/lib/promise-polyfill.js
|
|
5993
5997
|
class PromisePolyfill extends Promise {
|
|
5994
5998
|
static withResolver() {
|
|
5995
5999
|
let resolve6;
|
|
@@ -6002,7 +6006,7 @@ class PromisePolyfill extends Promise {
|
|
|
6002
6006
|
}
|
|
6003
6007
|
}
|
|
6004
6008
|
|
|
6005
|
-
// ../../node_modules
|
|
6009
|
+
// ../../node_modules/@inquirer/core/dist/lib/create-prompt.js
|
|
6006
6010
|
import path from "path";
|
|
6007
6011
|
var nativeSetImmediate = globalThis.setImmediate;
|
|
6008
6012
|
function getCallSites() {
|
|
@@ -6113,7 +6117,7 @@ function createPrompt(view) {
|
|
|
6113
6117
|
};
|
|
6114
6118
|
return prompt;
|
|
6115
6119
|
}
|
|
6116
|
-
// ../../node_modules
|
|
6120
|
+
// ../../node_modules/@inquirer/core/dist/lib/Separator.js
|
|
6117
6121
|
import { styleText as styleText2 } from "util";
|
|
6118
6122
|
class Separator {
|
|
6119
6123
|
separator = styleText2("dim", Array.from({ length: 15 }).join(dist_default.line));
|
|
@@ -6127,7 +6131,7 @@ class Separator {
|
|
|
6127
6131
|
return Boolean(choice && typeof choice === "object" && "type" in choice && choice.type === "separator");
|
|
6128
6132
|
}
|
|
6129
6133
|
}
|
|
6130
|
-
// ../../node_modules
|
|
6134
|
+
// ../../node_modules/@inquirer/checkbox/dist/index.js
|
|
6131
6135
|
import { styleText as styleText3 } from "util";
|
|
6132
6136
|
var checkboxTheme = {
|
|
6133
6137
|
icon: {
|
|
@@ -8524,7 +8528,8 @@ var recipes = [
|
|
|
8524
8528
|
id: "starter-0.7.0-to-0.8.0",
|
|
8525
8529
|
from: "0.7.0",
|
|
8526
8530
|
to: "0.8.0"
|
|
8527
|
-
}
|
|
8531
|
+
},
|
|
8532
|
+
{ id: "starter-0.8.0-to-0.8.1", from: "0.8.0", to: "0.8.1" }
|
|
8528
8533
|
];
|
|
8529
8534
|
function resolveRecipeChain(sourceVersion, targetVersion) {
|
|
8530
8535
|
if (compareVersions2(sourceVersion, minimumSupportedUpdateVersion) < 0) {
|
package/package.json
CHANGED
|
@@ -24,4 +24,4 @@ RUN mkdir -p /app/data/agent \
|
|
|
24
24
|
USER windy
|
|
25
25
|
HEALTHCHECK --interval=15s --timeout=5s --start-period=10s --retries=4 \
|
|
26
26
|
CMD ["python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8080/health/ready', timeout=3)"]
|
|
27
|
-
CMD ["uvicorn", "southwind_agent_server.
|
|
27
|
+
CMD ["uvicorn", "southwind_agent_server.asgi:app", "--host", "0.0.0.0", "--port", "8080"]
|
|
@@ -43,7 +43,7 @@ export AI_PROVIDER_INPUT_MODALITIES='text'
|
|
|
43
43
|
export AGENT_RUN_STORE_PATH='.data/agent-runs.sqlite3'
|
|
44
44
|
export AI_PROVIDER_AUDIT_STORE_PATH='.data/provider-audit.sqlite3'
|
|
45
45
|
export AI_PROVIDER_AUDIT_RETENTION_DAYS='90'
|
|
46
|
-
uv run uvicorn southwind_agent_server.
|
|
46
|
+
uv run uvicorn southwind_agent_server.asgi:app
|
|
47
47
|
```
|
|
48
48
|
|
|
49
49
|
公网 URL 必须使用 HTTPS 且 Host 精确命中 allowlist;本机、容器服务名和内网地址允许
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""Safe attempt diagnostics, separate from the canonical Run store and audit."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
import time
|
|
7
|
+
|
|
8
|
+
from .store import RunRecord
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class AgentOperationalAttempt:
|
|
14
|
+
def __init__(self, record: RunRecord) -> None:
|
|
15
|
+
self._run_id = record.run_id
|
|
16
|
+
self._trace_id = record.trace_id
|
|
17
|
+
self._started_at: float | None = None
|
|
18
|
+
self._finished = False
|
|
19
|
+
|
|
20
|
+
def start(self) -> None:
|
|
21
|
+
if self._started_at is not None:
|
|
22
|
+
return
|
|
23
|
+
self._started_at = time.monotonic()
|
|
24
|
+
self._emit("agent.run.attempt.started")
|
|
25
|
+
|
|
26
|
+
def finish(self, status: str) -> None:
|
|
27
|
+
if self._started_at is None or self._finished:
|
|
28
|
+
return
|
|
29
|
+
self._finished = True
|
|
30
|
+
self._emit(
|
|
31
|
+
"agent.run.attempt.completed",
|
|
32
|
+
operational_status=status,
|
|
33
|
+
operational_duration_ms=round(
|
|
34
|
+
(time.monotonic() - self._started_at) * 1_000, 3
|
|
35
|
+
),
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
def _emit(self, event: str, **fields: str | float) -> None:
|
|
39
|
+
try:
|
|
40
|
+
emit = (
|
|
41
|
+
logger.warning
|
|
42
|
+
if event == "agent.run.attempt.completed"
|
|
43
|
+
and fields.get("operational_status") != "completed"
|
|
44
|
+
else logger.info
|
|
45
|
+
)
|
|
46
|
+
emit(
|
|
47
|
+
"Agent 执行阶段",
|
|
48
|
+
extra={
|
|
49
|
+
"operational_event": event,
|
|
50
|
+
"run_id": self._run_id,
|
|
51
|
+
"trace_id": self._trace_id,
|
|
52
|
+
**fields,
|
|
53
|
+
},
|
|
54
|
+
)
|
|
55
|
+
except Exception:
|
|
56
|
+
# 日志出口失败不能改变 Run 或租约的业务结果。
|
|
57
|
+
return
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"""Agent runtime adapter for the Windy operational log contract."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import logging
|
|
7
|
+
import math
|
|
8
|
+
import re
|
|
9
|
+
import sys
|
|
10
|
+
from datetime import UTC, datetime
|
|
11
|
+
from typing import TextIO
|
|
12
|
+
|
|
13
|
+
MAX_LOG_BYTES = 2048
|
|
14
|
+
_CORRELATION = re.compile(r"^[A-Za-z0-9._-]{1,128}$")
|
|
15
|
+
_STABLE = re.compile(r"^[a-z][a-z0-9]*(?:[._-][a-z0-9]+)*$")
|
|
16
|
+
_EVENTS = {
|
|
17
|
+
"Agent Run 恢复轮询失败,将继续重试": (
|
|
18
|
+
"agent.run.recovery.failed",
|
|
19
|
+
"AGENT_RUN_RECOVERY_FAILED",
|
|
20
|
+
),
|
|
21
|
+
"Agent Runtime 报表写入失败": (
|
|
22
|
+
"agent.report.write.failed",
|
|
23
|
+
"AGENT_REPORT_WRITE_FAILED",
|
|
24
|
+
),
|
|
25
|
+
}
|
|
26
|
+
_ATTEMPT_EVENTS = frozenset(
|
|
27
|
+
{
|
|
28
|
+
"agent.run.attempt.started",
|
|
29
|
+
"agent.run.attempt.completed",
|
|
30
|
+
}
|
|
31
|
+
)
|
|
32
|
+
_ATTEMPT_ERRORS = {
|
|
33
|
+
"failed": "AGENT_RUN_FAILED",
|
|
34
|
+
"cancelled": "AGENT_RUN_CANCELLED",
|
|
35
|
+
"interrupted": "AGENT_RUN_INTERRUPTED",
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def agent_log_record(record: logging.LogRecord) -> dict[str, str | bool | float]:
|
|
40
|
+
"""Map known runtime failures without serializing messages, errors or extras."""
|
|
41
|
+
event, error_code = _EVENTS.get(
|
|
42
|
+
record.msg if isinstance(record.msg, str) else "",
|
|
43
|
+
("agent.runtime.failed", "AGENT_RUNTIME_FAILED"),
|
|
44
|
+
)
|
|
45
|
+
attempt_event = getattr(record, "operational_event", None)
|
|
46
|
+
is_attempt = isinstance(attempt_event, str) and attempt_event in _ATTEMPT_EVENTS
|
|
47
|
+
result: dict[str, str | bool | float] = {
|
|
48
|
+
"timestamp": datetime.now(UTC)
|
|
49
|
+
.isoformat(timespec="milliseconds")
|
|
50
|
+
.replace("+00:00", "Z"),
|
|
51
|
+
"level": "error"
|
|
52
|
+
if record.levelno >= logging.ERROR
|
|
53
|
+
else ("warn" if record.levelno >= logging.WARNING else "info"),
|
|
54
|
+
"component": "agent-server",
|
|
55
|
+
"event": attempt_event
|
|
56
|
+
if isinstance(attempt_event, str) and is_attempt
|
|
57
|
+
else event,
|
|
58
|
+
"retentionClass": "operational",
|
|
59
|
+
}
|
|
60
|
+
if not is_attempt:
|
|
61
|
+
result.update(outcome="failure", errorCode=error_code)
|
|
62
|
+
elif attempt_event == "agent.run.attempt.completed":
|
|
63
|
+
status = getattr(record, "operational_status", "interrupted")
|
|
64
|
+
if status not in {"completed", "failed", "cancelled"}:
|
|
65
|
+
status = "interrupted"
|
|
66
|
+
result["stageKey"] = status
|
|
67
|
+
result["outcome"] = "success" if status == "completed" else "failure"
|
|
68
|
+
if status != "completed":
|
|
69
|
+
result["errorCode"] = _ATTEMPT_ERRORS[status]
|
|
70
|
+
duration = getattr(record, "operational_duration_ms", None)
|
|
71
|
+
if (
|
|
72
|
+
isinstance(duration, (int, float))
|
|
73
|
+
and not isinstance(duration, bool)
|
|
74
|
+
and math.isfinite(duration)
|
|
75
|
+
and 0 <= duration <= 3_600_000
|
|
76
|
+
):
|
|
77
|
+
result["durationMs"] = duration
|
|
78
|
+
for source, target in (
|
|
79
|
+
("request_id", "requestId"),
|
|
80
|
+
("run_id", "runId"),
|
|
81
|
+
("job_id", "jobId"),
|
|
82
|
+
("trace_id", "traceId"),
|
|
83
|
+
):
|
|
84
|
+
value = getattr(record, source, None)
|
|
85
|
+
if isinstance(value, str) and _CORRELATION.fullmatch(value):
|
|
86
|
+
result[target] = value
|
|
87
|
+
stage = getattr(record, "report_stage", None)
|
|
88
|
+
if isinstance(stage, str) and len(stage) <= 64 and _STABLE.fullmatch(stage):
|
|
89
|
+
result["stageKey"] = stage
|
|
90
|
+
for key in ("stageKey", "traceId", "jobId", "runId", "requestId"):
|
|
91
|
+
if len(json.dumps(result, ensure_ascii=False).encode("utf-8")) <= MAX_LOG_BYTES:
|
|
92
|
+
break
|
|
93
|
+
result.pop(key, None)
|
|
94
|
+
result["truncated"] = True
|
|
95
|
+
return result
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
class AgentStructuredLogHandler(logging.Handler):
|
|
99
|
+
def __init__(self, stream: TextIO | None = None) -> None:
|
|
100
|
+
super().__init__(level=logging.INFO)
|
|
101
|
+
self.stream = stream or sys.stdout
|
|
102
|
+
|
|
103
|
+
def emit(self, record: logging.LogRecord) -> None:
|
|
104
|
+
try:
|
|
105
|
+
if (
|
|
106
|
+
record.levelno < logging.WARNING
|
|
107
|
+
and getattr(record, "operational_event", None) not in _ATTEMPT_EVENTS
|
|
108
|
+
):
|
|
109
|
+
return
|
|
110
|
+
line = json.dumps(
|
|
111
|
+
agent_log_record(record), ensure_ascii=False, separators=(",", ":")
|
|
112
|
+
)
|
|
113
|
+
self.stream.write(f"{line}\n")
|
|
114
|
+
self.flush()
|
|
115
|
+
except Exception:
|
|
116
|
+
# 运行日志旁路失败时不能改变 Run 与报表写入的业务结果。
|
|
117
|
+
return
|
|
118
|
+
|
|
119
|
+
def flush(self) -> None:
|
|
120
|
+
try:
|
|
121
|
+
self.stream.flush()
|
|
122
|
+
except Exception:
|
|
123
|
+
return
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def configure_agent_logging() -> None:
|
|
127
|
+
"""Attach once to package loggers; keep Uvicorn's own access logs separate."""
|
|
128
|
+
logger = logging.getLogger("southwind_agent_server")
|
|
129
|
+
if not any(
|
|
130
|
+
isinstance(handler, AgentStructuredLogHandler) for handler in logger.handlers
|
|
131
|
+
):
|
|
132
|
+
logger.addHandler(AgentStructuredLogHandler())
|
|
133
|
+
logger.setLevel(logging.INFO)
|
|
134
|
+
logger.propagate = False
|
|
@@ -17,6 +17,7 @@ from opentelemetry.trace import (
|
|
|
17
17
|
TraceFlags,
|
|
18
18
|
)
|
|
19
19
|
|
|
20
|
+
from .runtime_logging import AgentOperationalAttempt
|
|
20
21
|
from .store import RunRecord
|
|
21
22
|
|
|
22
23
|
_configured = False
|
|
@@ -50,11 +51,14 @@ class AgentRunTrace:
|
|
|
50
51
|
},
|
|
51
52
|
)
|
|
52
53
|
self._token: Token[Context] | None = None
|
|
54
|
+
self._operational = AgentOperationalAttempt(record)
|
|
53
55
|
|
|
54
56
|
def start(self) -> None:
|
|
55
57
|
self._token = context.attach(trace.set_span_in_context(self._span))
|
|
58
|
+
self._operational.start()
|
|
56
59
|
|
|
57
60
|
def finish(self, status: str) -> None:
|
|
61
|
+
self._operational.finish(status)
|
|
58
62
|
self._span.set_attribute("agent.run.status", status)
|
|
59
63
|
if self._token is not None:
|
|
60
64
|
context.detach(self._token)
|