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.
Files changed (45) hide show
  1. package/dist/cli.js +46 -41
  2. package/package.json +1 -1
  3. package/template/.windy-template.json +2 -2
  4. package/template/apps/agent-server/Dockerfile +1 -1
  5. package/template/apps/agent-server/README.md +1 -1
  6. package/template/apps/agent-server/src/southwind_agent_server/asgi.py +8 -0
  7. package/template/apps/agent-server/src/southwind_agent_server/runtime_logging.py +57 -0
  8. package/template/apps/agent-server/src/southwind_agent_server/structured_logging.py +134 -0
  9. package/template/apps/agent-server/src/southwind_agent_server/telemetry.py +4 -0
  10. package/template/apps/agent-server/tests/test_run_operational_logging.py +114 -0
  11. package/template/apps/agent-server/tests/test_structured_logging.py +105 -0
  12. package/template/apps/server/src/agent/isolated-execution-guard.test.ts +194 -0
  13. package/template/apps/server/src/agent/isolated-execution-guard.ts +202 -0
  14. package/template/apps/server/src/agent/run-definition-support.ts +11 -1
  15. package/template/apps/server/src/agent/run-facade.ts +7 -11
  16. package/template/apps/server/src/agent/run-operation-policy.ts +11 -0
  17. package/template/apps/server/src/agent/workflow-durable-runtime-input.ts +8 -5
  18. package/template/apps/server/src/jobs/legacy-service-runtime.ts +4 -0
  19. package/template/apps/server/src/jobs/runtime-logging.test.ts +212 -0
  20. package/template/apps/server/src/jobs/runtime-logging.ts +58 -0
  21. package/template/apps/server/src/jobs/worker.ts +54 -12
  22. package/template/apps/server/src/observability/bootstrap.ts +1 -4
  23. package/template/apps/server/src/observability/http-observability.ts +2 -3
  24. package/template/apps/server/src/observability/structured-logger.test.ts +31 -0
  25. package/template/apps/server/src/observability/structured-logger.ts +27 -0
  26. package/template/apps/server/src/platform-bootstrap.ts +9 -3
  27. package/template/apps/server/src/startup-finalization.ts +3 -3
  28. package/template/apps/server/src/system/built-in-roles.test.ts +23 -0
  29. package/template/apps/server/src/system/built-in-roles.ts +10 -4
  30. package/template/apps/web/src/pages/system/composables/useResourceEditor.ts +16 -5
  31. package/template/apps/web/src/pages/system/composables/useResourceEditor.webtest.ts +4 -0
  32. package/template/docs/architecture/log-governance-implementation.md +79 -0
  33. package/template/docs/architecture/log-governance-plan.md +39 -0
  34. package/template/docs/operations/observability.md +36 -4
  35. package/template/packages/modules/package.json +1 -1
  36. package/template/packages/modules/src/ai-isolated-execution-policy.test.ts +70 -0
  37. package/template/packages/modules/src/ai-isolated-execution-policy.ts +76 -0
  38. package/template/packages/modules/src/ai-operation-composition.ts +2 -0
  39. package/template/packages/modules/src/manifest.ts +23 -0
  40. package/template/packages/modules/src/system-features.ts +11 -10
  41. package/template/packages/server-sdk/package.json +1 -1
  42. package/template/packages/shared/index.ts +1 -0
  43. package/template/packages/shared/package.json +3 -2
  44. package/template/packages/shared/src/structured-log.test.ts +147 -0
  45. 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/.bun/cli-width@4.1.0/node_modules/cli-width/index.js
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/.bun/mute-stream@3.0.0/node_modules/mute-stream/lib/index.js
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) => dlopen2(candidate, nativeSymbols), "\u5F53\u524D\u5E73\u53F0\u65E0\u6CD5\u52A0\u8F7D\u5B89\u5168\u76EE\u5F55\u53E5\u67C4 API");
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 errnoSymbol = process.platform === "darwin" ? libc.symbols.__error : libc.symbols.__errno_location;
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/.bun/@inquirer+core@11.2.1+7cb241fc07b679d9/node_modules/@inquirer/core/dist/lib/key.js
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/.bun/@inquirer+core@11.2.1+7cb241fc07b679d9/node_modules/@inquirer/core/dist/lib/errors.js
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/.bun/@inquirer+core@11.2.1+7cb241fc07b679d9/node_modules/@inquirer/core/dist/lib/use-state.js
4723
+ // ../../node_modules/@inquirer/core/dist/lib/use-state.js
4720
4724
  import { AsyncResource as AsyncResource2 } from "async_hooks";
4721
4725
 
4722
- // ../../node_modules/.bun/@inquirer+core@11.2.1+7cb241fc07b679d9/node_modules/@inquirer/core/dist/lib/hook-engine.js
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/.bun/@inquirer+core@11.2.1+7cb241fc07b679d9/node_modules/@inquirer/core/dist/lib/use-state.js
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/.bun/@inquirer+core@11.2.1+7cb241fc07b679d9/node_modules/@inquirer/core/dist/lib/use-effect.js
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/.bun/@inquirer+core@11.2.1+7cb241fc07b679d9/node_modules/@inquirer/core/dist/lib/theme.js
4864
+ // ../../node_modules/@inquirer/core/dist/lib/theme.js
4861
4865
  import { styleText } from "util";
4862
4866
 
4863
- // ../../node_modules/.bun/@inquirer+figures@2.0.7/node_modules/@inquirer/figures/dist/index.js
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/.bun/@inquirer+core@11.2.1+7cb241fc07b679d9/node_modules/@inquirer/core/dist/lib/theme.js
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/.bun/@inquirer+core@11.2.1+7cb241fc07b679d9/node_modules/@inquirer/core/dist/lib/make-theme.js
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/.bun/@inquirer+core@11.2.1+7cb241fc07b679d9/node_modules/@inquirer/core/dist/lib/use-prefix.js
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/.bun/@inquirer+core@11.2.1+7cb241fc07b679d9/node_modules/@inquirer/core/dist/lib/use-memo.js
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/.bun/@inquirer+core@11.2.1+7cb241fc07b679d9/node_modules/@inquirer/core/dist/lib/use-ref.js
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/.bun/@inquirer+core@11.2.1+7cb241fc07b679d9/node_modules/@inquirer/core/dist/lib/use-keypress.js
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/.bun/@inquirer+core@11.2.1+7cb241fc07b679d9/node_modules/@inquirer/core/dist/lib/utils.js
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/.bun/fast-string-truncated-width@3.0.3/node_modules/fast-string-truncated-width/dist/utils.js
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/.bun/fast-string-truncated-width@3.0.3/node_modules/fast-string-truncated-width/dist/index.js
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/.bun/fast-string-width@3.0.2/node_modules/fast-string-width/dist/index.js
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/.bun/fast-wrap-ansi@0.2.2/node_modules/fast-wrap-ansi/lib/main.js
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/.bun/@inquirer+core@11.2.1+7cb241fc07b679d9/node_modules/@inquirer/core/dist/lib/utils.js
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/.bun/@inquirer+core@11.2.1+7cb241fc07b679d9/node_modules/@inquirer/core/dist/lib/pagination/use-pagination.js
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/.bun/@inquirer+core@11.2.1+7cb241fc07b679d9/node_modules/@inquirer/core/dist/lib/create-prompt.js
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/.bun/signal-exit@4.1.0/node_modules/signal-exit/dist/mjs/signals.js
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/.bun/signal-exit@4.1.0/node_modules/signal-exit/dist/mjs/index.js
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/.bun/@inquirer+core@11.2.1+7cb241fc07b679d9/node_modules/@inquirer/core/dist/lib/screen-manager.js
5911
+ // ../../node_modules/@inquirer/core/dist/lib/screen-manager.js
5908
5912
  import { stripVTControlCharacters } from "util";
5909
5913
 
5910
- // ../../node_modules/.bun/@inquirer+ansi@2.0.7/node_modules/@inquirer/ansi/dist/index.js
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/.bun/@inquirer+core@11.2.1+7cb241fc07b679d9/node_modules/@inquirer/core/dist/lib/screen-manager.js
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/.bun/@inquirer+core@11.2.1+7cb241fc07b679d9/node_modules/@inquirer/core/dist/lib/promise-polyfill.js
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/.bun/@inquirer+core@11.2.1+7cb241fc07b679d9/node_modules/@inquirer/core/dist/lib/create-prompt.js
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/.bun/@inquirer+core@11.2.1+7cb241fc07b679d9/node_modules/@inquirer/core/dist/lib/Separator.js
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/.bun/@inquirer+checkbox@5.2.1+7cb241fc07b679d9/node_modules/@inquirer/checkbox/dist/index.js
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-windy",
3
- "version": "0.8.0",
3
+ "version": "0.8.1",
4
4
  "description": "创建单组织、单租户、私有部署优先的 Windy 企业 Dashboard Starter",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "templateCommit": "20ddeda7267de315fb8fe115d64ad6b8c892ccb8",
4
- "generatorVersion": "0.8.0",
3
+ "templateCommit": "066d8018c0ec0c82fbf01d26013b3b303aaa9c22",
4
+ "generatorVersion": "0.8.1",
5
5
  "modules": [
6
6
  {
7
7
  "name": "system",
@@ -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.app:app", "--host", "0.0.0.0", "--port", "8080"]
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.app:app
46
+ uv run uvicorn southwind_agent_server.asgi:app
47
47
  ```
48
48
 
49
49
  公网 URL 必须使用 HTTPS 且 Host 精确命中 allowlist;本机、容器服务名和内网地址允许
@@ -0,0 +1,8 @@
1
+ """Production ASGI entrypoint with operational logging installed."""
2
+
3
+ from .app import app
4
+ from .structured_logging import configure_agent_logging
5
+
6
+ configure_agent_logging()
7
+
8
+ __all__ = ["app"]
@@ -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)