agentworkshop 0.5.3 → 0.5.4

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.
@@ -1 +1 @@
1
- {"version":3,"file":"nitro.mjs","sources":["../../../../node_modules/.pnpm/uncrypto@0.1.3/node_modules/uncrypto/dist/crypto.node.mjs","../../../../node_modules/.pnpm/destr@2.0.5/node_modules/destr/dist/index.mjs","../../../../node_modules/.pnpm/ufo@1.6.4/node_modules/ufo/dist/index.mjs","../../../../node_modules/.pnpm/cookie-es@1.2.3/node_modules/cookie-es/dist/index.mjs","../../../../node_modules/.pnpm/radix3@1.1.2/node_modules/radix3/dist/index.mjs","../../../../node_modules/.pnpm/defu@6.1.7/node_modules/defu/dist/defu.mjs","../../../../node_modules/.pnpm/iron-webcrypto@1.2.1/node_modules/iron-webcrypto/dist/index.js","../../../../node_modules/.pnpm/node-mock-http@1.0.5/node_modules/node-mock-http/dist/index.mjs","../../../../node_modules/.pnpm/h3@1.15.11/node_modules/h3/dist/index.mjs","../../../../node_modules/.pnpm/hookable@5.5.3/node_modules/hookable/dist/index.mjs","../../../../node_modules/.pnpm/node-fetch-native@1.6.7/node_modules/node-fetch-native/dist/native.mjs","../../../../node_modules/.pnpm/ofetch@1.5.1/node_modules/ofetch/dist/shared/ofetch.CWycOUEr.mjs","../../../../node_modules/.pnpm/ofetch@1.5.1/node_modules/ofetch/dist/node.mjs","../../../../node_modules/.pnpm/unstorage@1.17.5_db0@0.3.4_ioredis@5.11.1/node_modules/unstorage/dist/shared/unstorage.zVDD2mZo.mjs","../../../../node_modules/.pnpm/unstorage@1.17.5_db0@0.3.4_ioredis@5.11.1/node_modules/unstorage/dist/index.mjs","../../../../node_modules/.pnpm/unstorage@1.17.5_db0@0.3.4_ioredis@5.11.1/node_modules/unstorage/drivers/utils/index.mjs","../../../../node_modules/.pnpm/unstorage@1.17.5_db0@0.3.4_ioredis@5.11.1/node_modules/unstorage/drivers/utils/node-fs.mjs","../../../../node_modules/.pnpm/unstorage@1.17.5_db0@0.3.4_ioredis@5.11.1/node_modules/unstorage/drivers/fs-lite.mjs","../../../../node_modules/.pnpm/nitropack@2.13.4_oxc-parser_b1d7d58181e96cbc69b3295f5f958520/node_modules/nitropack/dist/runtime/internal/storage.mjs","../../../../node_modules/.pnpm/ohash@2.0.11/node_modules/ohash/dist/shared/ohash.D__AXeF1.mjs","../../../../node_modules/.pnpm/ohash@2.0.11/node_modules/ohash/dist/crypto/node/index.mjs","../../../../node_modules/.pnpm/nitropack@2.13.4_oxc-parser_b1d7d58181e96cbc69b3295f5f958520/node_modules/nitropack/dist/runtime/internal/hash.mjs","../../../../node_modules/.pnpm/nitropack@2.13.4_oxc-parser_b1d7d58181e96cbc69b3295f5f958520/node_modules/nitropack/dist/runtime/internal/cache.mjs","../../../../node_modules/.pnpm/klona@2.0.6/node_modules/klona/dist/index.mjs","../../../../node_modules/.pnpm/scule@1.3.0/node_modules/scule/dist/index.mjs","../../../../node_modules/.pnpm/nitropack@2.13.4_oxc-parser_b1d7d58181e96cbc69b3295f5f958520/node_modules/nitropack/dist/runtime/internal/utils.env.mjs","../../../../node_modules/.pnpm/nitropack@2.13.4_oxc-parser_b1d7d58181e96cbc69b3295f5f958520/node_modules/nitropack/dist/runtime/internal/config.mjs","../../../../node_modules/.pnpm/nitropack@2.13.4_oxc-parser_b1d7d58181e96cbc69b3295f5f958520/node_modules/nitropack/dist/runtime/internal/route-rules-utils.mjs","../../../../node_modules/.pnpm/nitropack@2.13.4_oxc-parser_b1d7d58181e96cbc69b3295f5f958520/node_modules/nitropack/dist/runtime/internal/route-rules.mjs","../../../../node_modules/.pnpm/nitropack@2.13.4_oxc-parser_b1d7d58181e96cbc69b3295f5f958520/node_modules/nitropack/dist/runtime/internal/utils.mjs","../../../../node_modules/.pnpm/@nuxt+nitro-server@4.5.2_2b2a73a5ea3a6c1cac65dd2aa61911d0/node_modules/@nuxt/nitro-server/dist/runtime/utils/error.mjs","../../../../node_modules/.pnpm/@nuxt+nitro-server@4.5.2_2b2a73a5ea3a6c1cac65dd2aa61911d0/node_modules/@nuxt/nitro-server/dist/runtime/handlers/error.mjs","../../../../node_modules/.pnpm/nitropack@2.13.4_oxc-parser_b1d7d58181e96cbc69b3295f5f958520/node_modules/nitropack/dist/runtime/internal/error/utils.mjs","../../../../node_modules/.pnpm/nitropack@2.13.4_oxc-parser_b1d7d58181e96cbc69b3295f5f958520/node_modules/nitropack/dist/runtime/internal/error/prod.mjs","../../../../node_modules/.pnpm/nuxt-auth-utils@0.5.30_magi_25cfea03c37d60c613297752f2919dae/node_modules/nuxt-auth-utils/dist/runtime/server/plugins/oauth.js","../../../../node_modules/.pnpm/hookable@6.1.1/node_modules/hookable/dist/index.mjs","../../../../node_modules/.pnpm/nitropack@2.13.4_oxc-parser_b1d7d58181e96cbc69b3295f5f958520/node_modules/nitropack/dist/runtime/internal/plugin.mjs","../../../../node_modules/.pnpm/nitropack@2.13.4_oxc-parser_b1d7d58181e96cbc69b3295f5f958520/node_modules/nitropack/dist/runtime/internal/renderer.mjs","../../../../node_modules/.pnpm/@nuxt+nitro-server@4.5.2_2b2a73a5ea3a6c1cac65dd2aa61911d0/node_modules/@nuxt/nitro-server/dist/runtime/utils/paths.mjs","../../../../server/utils/errors.ts","../../../../sdk/hooks.mjs","../../../../sdk/api.mjs","../../../../sdk/context.mjs","../../../../server/services/workshop/plugins/host.mjs","../../../../server/services/workshop/scene-events.ts","../../../../server/services/workshop/ops/ops.ts","../../../../server/utils/approval-gate.ts","../../../../server/utils/auth.ts","../../../../server/utils/config.ts","../../../../server/utils/response.ts","../../../../server/utils/validate.ts","../../../../node_modules/.pnpm/nuxt-auth-utils@0.5.30_magi_25cfea03c37d60c613297752f2919dae/node_modules/nuxt-auth-utils/dist/runtime/server/utils/session.js","../../../../node_modules/.pnpm/nuxt-auth-utils@0.5.30_magi_25cfea03c37d60c613297752f2919dae/node_modules/nuxt-auth-utils/dist/runtime/server/plugins/ws.js","../../../../server/plugins/aw-plugins.ts","../../../../shared/config/home.mjs","../../../../server/plugins/backup.ts","../../../../server/services/workshop/logger.ts","../../../../server/services/workshop/daq/infra.ts","../../../../server/services/workshop/daq/storage/sqlite.adapter.ts","../../../../server/services/workshop/daq/storage/timescale.adapter.ts","../../../../server/services/workshop/daq/storage/index.ts","../../../../server/services/workshop/daq/bus/inproc.adapter.ts","../../../../server/services/workshop/daq/bus/mqtt.adapter.ts","../../../../server/services/workshop/daq/bus/index.ts","../../../../shared/daq-protocol.ts","../../../../server/services/workshop/daq/drivers.ts","../../../../server/services/workshop/daq/daq-templates.ts","../../../../server/services/workshop/daq/daq-node.ts","../../../../server/services/workshop/daq/daq-runtime.ts","../../../../server/services/workshop/daq/daq-node.repo.ts","../../../../server/services/workshop/daq/host-ports.ts","../../../../server/services/workshop/daq/alarm-notify.ts","../../../../server/services/workshop/daq/daq-controller.ts","../../../../server/plugins/daq.ts","../../../../server/plugins/dev-stability-guard.ts","../../../../server/plugins/security.ts","../../../../shared/config/engine.mjs","../../../../server/services/system-config.ts","../../../../server/plugins/system-config.ts","../../../../server/services/workshop/db/database.ts","../../../../server/services/workshop/db/channel.repo.ts","../../../../server/services/workshop/db/agent.repo.ts","../../../../server/services/workshop/db/channel-agent.repo.ts","../../../../server/services/workshop/db/team.repo.ts","../../../../server/services/workshop/db/team-member.repo.ts","../../../../server/services/workshop/db/channel-template.repo.ts","../../../../server/services/workshop/db/task.repo.ts","../../../../server/services/workshop/db/message.repo.ts","../../../../server/services/workshop/db/subscription.repo.ts","../../../../server/services/workshop/db/memory.repo.ts","../../../../server/services/workshop/db/user.repo.ts","../../../../server/services/workshop/db/channel-event.repo.ts","../../../../server/services/workshop/db/ops.repo.ts","../../../../server/repositories/user.repository.ts","../../../../server/services/user.service.ts","../../../../server/services/workshop/runtime/mailbox.ts","../../../../server/api/workshop/ws.ts","../../../../server/services/workshop/runtime/execution-mode.ts","../../../../server/services/workshop/agents/mock-agent.ts","../../../../server/services/workshop/agents/harness-process.ts","../../../../server/services/workshop/agents/adapters/omp-rpc-client.ts","../../../../shared/terminal-protocol.ts","../../../../server/services/workshop/agents/harness-terminal.ts","../../../../server/services/workshop/prompts/loader.ts","../../../../server/services/workshop/agents/node-bindings.repo.ts","../../../../server/services/workshop/agents/tool-approvals.ts","../../../../shared/dcw-protocol.ts","../../../../server/services/workshop/dcw/drivers.ts","../../../../server/services/workshop/dcw/dcw-templates.ts","../../../../server/services/workshop/assets/device-twin.repo.ts","../../../../server/services/workshop/dcw/dcw-node.ts","../../../../server/services/workshop/dcw/dcw-node.repo.ts","../../../../server/services/workshop/dcw/dcw-runtime.ts","../../../../server/services/workshop/dcw/dcw-product.repo.ts","../../../../server/services/workshop/dcw/dcw-recipe.repo.ts","../../../../server/services/workshop/dcw/dcw-line.repo.ts","../../../../server/services/workshop/dcw/line-run.ts","../../../../server/services/workshop/dcw/recipe-rollback.repo.ts","../../../../server/services/workshop/dcw/recipe-rollback-manager.ts","../../../../server/services/workshop/dcw/dcw-controller.ts","../../../../server/services/workshop/agents/industrial-context.ts","../../../../server/services/workshop/agents/industrial-tools.ts","../../../../server/services/workshop/agents/omp-agent.ts","../../../../server/services/workshop/agents/claude-agent.ts","../../../../server/services/workshop/agents/factory.ts","../../../../server/services/workshop/types/task.ts","../../../../server/services/workshop/runtime/agent-runtime.ts","../../../../server/services/workshop/runtime/channel-runtime.ts","../../../../server/services/workshop/runtime/scheduler-loop.ts","../../../../server/services/workshop/runtime/task-engine.ts","../../../../server/services/workshop/runtime/memory.ts","../../../../server/services/workshop/runtime/embedding-provider.ts","../../../../server/services/workshop/runtime/manager.ts","../../../../server/plugins/workshop.ts","../../../../node_modules/.pnpm/pathe@2.0.3/node_modules/pathe/dist/shared/pathe.M-eThtNZ.mjs","../../../../node_modules/.pnpm/nitropack@2.13.4_oxc-parser_b1d7d58181e96cbc69b3295f5f958520/node_modules/nitropack/dist/runtime/internal/static.mjs","../../../../server/middleware/request-log.ts","../../../../node_modules/.pnpm/nuxt-auth-utils@0.5.30_magi_25cfea03c37d60c613297752f2919dae/node_modules/nuxt-auth-utils/dist/runtime/server/api/session.delete.js","../../../../node_modules/.pnpm/nuxt-auth-utils@0.5.30_magi_25cfea03c37d60c613297752f2919dae/node_modules/nuxt-auth-utils/dist/runtime/server/api/session.get.js","../../../../node_modules/.pnpm/nitropack@2.13.4_oxc-parser_b1d7d58181e96cbc69b3295f5f958520/node_modules/nitropack/dist/runtime/internal/app.mjs","../../../../node_modules/.pnpm/nitropack@2.13.4_oxc-parser_b1d7d58181e96cbc69b3295f5f958520/node_modules/nitropack/dist/runtime/internal/lib/http-graceful-shutdown.mjs","../../../../node_modules/.pnpm/nitropack@2.13.4_oxc-parser_b1d7d58181e96cbc69b3295f5f958520/node_modules/nitropack/dist/runtime/internal/shutdown.mjs"],"names":["decode","getQuery","parse","serialize","createRouter","f","h","c","i","l","g","createError","process","mergeHeaders","crypto","flatHooks","createTask","serialTaskCaller","parallelTaskCaller","callEachWith","createHooks","Hookable","s","callHooks","nodeFetch","fetch","Headers","Headers$1","AbortController","AbortController$1","normalizeKey","defineDriver","DRIVER_NAME","dirname","fsPromises","resolve","fsp","_inlineAppConfig","createRadixRouter","__publicField","log","watch","AEP_VERSION","randomUUID","_a","DB_PATH","rows","_b","_c","_d","reqNative","sleep","REGISTRY","bad","load","normalize","singleton","require","SCHEMA_SQL","COLS","randomPassword","randomBytes","hubGlobal","hub","criteria","worker","registry","frame","save","DATA_DIR","COOLDOWN_MS","_e","fresh","partsToText","pid","seen","modeInfo","rowToTask","TaskEngineImpl","callNodeRequestHandler","fetchNodeRequestHandler","gracefulShutdown"],"mappings":"","x_google_ignoreList":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,51,52,134,135,137,138,139,140,141]}
1
+ {"version":3,"file":"nitro.mjs","sources":["../../../../node_modules/.pnpm/uncrypto@0.1.3/node_modules/uncrypto/dist/crypto.node.mjs","../../../../node_modules/.pnpm/destr@2.0.5/node_modules/destr/dist/index.mjs","../../../../node_modules/.pnpm/ufo@1.6.4/node_modules/ufo/dist/index.mjs","../../../../node_modules/.pnpm/cookie-es@1.2.3/node_modules/cookie-es/dist/index.mjs","../../../../node_modules/.pnpm/radix3@1.1.2/node_modules/radix3/dist/index.mjs","../../../../node_modules/.pnpm/defu@6.1.7/node_modules/defu/dist/defu.mjs","../../../../node_modules/.pnpm/iron-webcrypto@1.2.1/node_modules/iron-webcrypto/dist/index.js","../../../../node_modules/.pnpm/node-mock-http@1.0.5/node_modules/node-mock-http/dist/index.mjs","../../../../node_modules/.pnpm/h3@1.15.11/node_modules/h3/dist/index.mjs","../../../../node_modules/.pnpm/hookable@5.5.3/node_modules/hookable/dist/index.mjs","../../../../node_modules/.pnpm/node-fetch-native@1.6.7/node_modules/node-fetch-native/dist/native.mjs","../../../../node_modules/.pnpm/ofetch@1.5.1/node_modules/ofetch/dist/shared/ofetch.CWycOUEr.mjs","../../../../node_modules/.pnpm/ofetch@1.5.1/node_modules/ofetch/dist/node.mjs","../../../../node_modules/.pnpm/unstorage@1.17.5_db0@0.3.4_ioredis@5.11.1/node_modules/unstorage/dist/shared/unstorage.zVDD2mZo.mjs","../../../../node_modules/.pnpm/unstorage@1.17.5_db0@0.3.4_ioredis@5.11.1/node_modules/unstorage/dist/index.mjs","../../../../node_modules/.pnpm/unstorage@1.17.5_db0@0.3.4_ioredis@5.11.1/node_modules/unstorage/drivers/utils/index.mjs","../../../../node_modules/.pnpm/unstorage@1.17.5_db0@0.3.4_ioredis@5.11.1/node_modules/unstorage/drivers/utils/node-fs.mjs","../../../../node_modules/.pnpm/unstorage@1.17.5_db0@0.3.4_ioredis@5.11.1/node_modules/unstorage/drivers/fs-lite.mjs","../../../../node_modules/.pnpm/nitropack@2.13.4_oxc-parser_b1d7d58181e96cbc69b3295f5f958520/node_modules/nitropack/dist/runtime/internal/storage.mjs","../../../../node_modules/.pnpm/ohash@2.0.11/node_modules/ohash/dist/shared/ohash.D__AXeF1.mjs","../../../../node_modules/.pnpm/ohash@2.0.11/node_modules/ohash/dist/crypto/node/index.mjs","../../../../node_modules/.pnpm/nitropack@2.13.4_oxc-parser_b1d7d58181e96cbc69b3295f5f958520/node_modules/nitropack/dist/runtime/internal/hash.mjs","../../../../node_modules/.pnpm/nitropack@2.13.4_oxc-parser_b1d7d58181e96cbc69b3295f5f958520/node_modules/nitropack/dist/runtime/internal/cache.mjs","../../../../node_modules/.pnpm/klona@2.0.6/node_modules/klona/dist/index.mjs","../../../../node_modules/.pnpm/scule@1.3.0/node_modules/scule/dist/index.mjs","../../../../node_modules/.pnpm/nitropack@2.13.4_oxc-parser_b1d7d58181e96cbc69b3295f5f958520/node_modules/nitropack/dist/runtime/internal/utils.env.mjs","../../../../node_modules/.pnpm/nitropack@2.13.4_oxc-parser_b1d7d58181e96cbc69b3295f5f958520/node_modules/nitropack/dist/runtime/internal/config.mjs","../../../../node_modules/.pnpm/nitropack@2.13.4_oxc-parser_b1d7d58181e96cbc69b3295f5f958520/node_modules/nitropack/dist/runtime/internal/route-rules-utils.mjs","../../../../node_modules/.pnpm/nitropack@2.13.4_oxc-parser_b1d7d58181e96cbc69b3295f5f958520/node_modules/nitropack/dist/runtime/internal/route-rules.mjs","../../../../node_modules/.pnpm/nitropack@2.13.4_oxc-parser_b1d7d58181e96cbc69b3295f5f958520/node_modules/nitropack/dist/runtime/internal/utils.mjs","../../../../node_modules/.pnpm/@nuxt+nitro-server@4.5.2_2b2a73a5ea3a6c1cac65dd2aa61911d0/node_modules/@nuxt/nitro-server/dist/runtime/utils/error.mjs","../../../../node_modules/.pnpm/@nuxt+nitro-server@4.5.2_2b2a73a5ea3a6c1cac65dd2aa61911d0/node_modules/@nuxt/nitro-server/dist/runtime/handlers/error.mjs","../../../../node_modules/.pnpm/nitropack@2.13.4_oxc-parser_b1d7d58181e96cbc69b3295f5f958520/node_modules/nitropack/dist/runtime/internal/error/utils.mjs","../../../../node_modules/.pnpm/nitropack@2.13.4_oxc-parser_b1d7d58181e96cbc69b3295f5f958520/node_modules/nitropack/dist/runtime/internal/error/prod.mjs","../../../../node_modules/.pnpm/nuxt-auth-utils@0.5.30_magi_25cfea03c37d60c613297752f2919dae/node_modules/nuxt-auth-utils/dist/runtime/server/plugins/oauth.js","../../../../node_modules/.pnpm/hookable@6.1.1/node_modules/hookable/dist/index.mjs","../../../../node_modules/.pnpm/nitropack@2.13.4_oxc-parser_b1d7d58181e96cbc69b3295f5f958520/node_modules/nitropack/dist/runtime/internal/plugin.mjs","../../../../node_modules/.pnpm/nitropack@2.13.4_oxc-parser_b1d7d58181e96cbc69b3295f5f958520/node_modules/nitropack/dist/runtime/internal/renderer.mjs","../../../../node_modules/.pnpm/@nuxt+nitro-server@4.5.2_2b2a73a5ea3a6c1cac65dd2aa61911d0/node_modules/@nuxt/nitro-server/dist/runtime/utils/paths.mjs","../../../../server/utils/errors.ts","../../../../sdk/hooks.mjs","../../../../sdk/api.mjs","../../../../sdk/context.mjs","../../../../server/services/workshop/plugins/host.mjs","../../../../server/services/workshop/scene-events.ts","../../../../server/services/workshop/ops/ops.ts","../../../../server/utils/approval-gate.ts","../../../../server/utils/auth.ts","../../../../server/utils/config.ts","../../../../server/utils/response.ts","../../../../server/utils/validate.ts","../../../../node_modules/.pnpm/nuxt-auth-utils@0.5.30_magi_25cfea03c37d60c613297752f2919dae/node_modules/nuxt-auth-utils/dist/runtime/server/utils/session.js","../../../../node_modules/.pnpm/nuxt-auth-utils@0.5.30_magi_25cfea03c37d60c613297752f2919dae/node_modules/nuxt-auth-utils/dist/runtime/server/plugins/ws.js","../../../../server/plugins/aw-plugins.ts","../../../../shared/config/home.mjs","../../../../server/plugins/backup.ts","../../../../server/services/workshop/logger.ts","../../../../server/services/workshop/daq/infra.ts","../../../../server/services/workshop/daq/storage/sqlite.adapter.ts","../../../../server/services/workshop/daq/storage/timescale.adapter.ts","../../../../server/services/workshop/daq/storage/index.ts","../../../../server/services/workshop/daq/bus/inproc.adapter.ts","../../../../server/services/workshop/daq/bus/mqtt.adapter.ts","../../../../server/services/workshop/daq/bus/index.ts","../../../../shared/daq-protocol.ts","../../../../server/services/workshop/daq/drivers.ts","../../../../server/services/workshop/daq/daq-templates.ts","../../../../server/services/workshop/daq/daq-node.ts","../../../../server/services/workshop/daq/daq-runtime.ts","../../../../server/services/workshop/daq/daq-node.repo.ts","../../../../server/services/workshop/daq/host-ports.ts","../../../../server/services/workshop/daq/alarm-notify.ts","../../../../server/services/workshop/daq/daq-controller.ts","../../../../server/plugins/daq.ts","../../../../server/plugins/dev-stability-guard.ts","../../../../server/services/workshop/db/retention.ts","../../../../server/plugins/retention.ts","../../../../server/plugins/security.ts","../../../../shared/config/engine.mjs","../../../../server/services/system-config.ts","../../../../server/plugins/system-config.ts","../../../../server/services/workshop/db/database.ts","../../../../server/services/workshop/db/channel.repo.ts","../../../../server/services/workshop/db/agent.repo.ts","../../../../server/services/workshop/db/channel-agent.repo.ts","../../../../server/services/workshop/db/team.repo.ts","../../../../server/services/workshop/db/team-member.repo.ts","../../../../server/services/workshop/db/channel-template.repo.ts","../../../../server/services/workshop/db/task.repo.ts","../../../../server/services/workshop/db/message.repo.ts","../../../../server/services/workshop/db/subscription.repo.ts","../../../../server/services/workshop/db/memory.repo.ts","../../../../server/services/workshop/db/user.repo.ts","../../../../server/services/workshop/db/channel-event.repo.ts","../../../../server/services/workshop/db/ops.repo.ts","../../../../server/repositories/user.repository.ts","../../../../server/services/user.service.ts","../../../../server/services/workshop/runtime/mailbox.ts","../../../../server/api/workshop/ws.ts","../../../../server/services/workshop/runtime/execution-mode.ts","../../../../server/services/workshop/agents/mock-agent.ts","../../../../server/services/workshop/agents/harness-process.ts","../../../../server/services/workshop/agents/adapters/omp-rpc-client.ts","../../../../shared/terminal-protocol.ts","../../../../server/services/workshop/agents/harness-terminal.ts","../../../../server/services/workshop/prompts/loader.ts","../../../../server/services/workshop/agents/node-bindings.repo.ts","../../../../server/services/workshop/agents/tool-approvals.ts","../../../../shared/dcw-protocol.ts","../../../../server/services/workshop/dcw/drivers.ts","../../../../server/services/workshop/dcw/dcw-templates.ts","../../../../server/services/workshop/assets/device-twin.repo.ts","../../../../server/services/workshop/dcw/dcw-node.ts","../../../../server/services/workshop/dcw/dcw-node.repo.ts","../../../../server/services/workshop/dcw/dcw-runtime.ts","../../../../server/services/workshop/dcw/dcw-product.repo.ts","../../../../server/services/workshop/dcw/dcw-recipe.repo.ts","../../../../server/services/workshop/dcw/dcw-line.repo.ts","../../../../server/services/workshop/dcw/line-run.ts","../../../../server/services/workshop/dcw/recipe-rollback.repo.ts","../../../../server/services/workshop/dcw/recipe-rollback-manager.ts","../../../../server/services/workshop/dcw/dcw-controller.ts","../../../../server/services/workshop/agents/industrial-context.ts","../../../../server/services/workshop/agents/industrial-tools.ts","../../../../server/services/workshop/agents/omp-agent.ts","../../../../server/services/workshop/agents/claude-agent.ts","../../../../server/services/workshop/agents/factory.ts","../../../../server/services/workshop/types/task.ts","../../../../server/services/workshop/runtime/agent-runtime.ts","../../../../server/services/workshop/runtime/channel-runtime.ts","../../../../server/services/workshop/runtime/scheduler-loop.ts","../../../../server/services/workshop/runtime/task-engine.ts","../../../../server/services/workshop/runtime/memory.ts","../../../../server/services/workshop/runtime/embedding-provider.ts","../../../../server/services/workshop/runtime/manager.ts","../../../../server/plugins/workshop.ts","../../../../node_modules/.pnpm/pathe@2.0.3/node_modules/pathe/dist/shared/pathe.M-eThtNZ.mjs","../../../../node_modules/.pnpm/nitropack@2.13.4_oxc-parser_b1d7d58181e96cbc69b3295f5f958520/node_modules/nitropack/dist/runtime/internal/static.mjs","../../../../server/middleware/request-log.ts","../../../../node_modules/.pnpm/nuxt-auth-utils@0.5.30_magi_25cfea03c37d60c613297752f2919dae/node_modules/nuxt-auth-utils/dist/runtime/server/api/session.delete.js","../../../../node_modules/.pnpm/nuxt-auth-utils@0.5.30_magi_25cfea03c37d60c613297752f2919dae/node_modules/nuxt-auth-utils/dist/runtime/server/api/session.get.js","../../../../node_modules/.pnpm/nitropack@2.13.4_oxc-parser_b1d7d58181e96cbc69b3295f5f958520/node_modules/nitropack/dist/runtime/internal/app.mjs","../../../../node_modules/.pnpm/nitropack@2.13.4_oxc-parser_b1d7d58181e96cbc69b3295f5f958520/node_modules/nitropack/dist/runtime/internal/lib/http-graceful-shutdown.mjs","../../../../node_modules/.pnpm/nitropack@2.13.4_oxc-parser_b1d7d58181e96cbc69b3295f5f958520/node_modules/nitropack/dist/runtime/internal/shutdown.mjs"],"names":["decode","getQuery","parse","serialize","createRouter","f","h","c","i","l","g","createError","process","mergeHeaders","crypto","flatHooks","createTask","serialTaskCaller","parallelTaskCaller","callEachWith","createHooks","Hookable","s","callHooks","nodeFetch","fetch","Headers","Headers$1","AbortController","AbortController$1","normalizeKey","defineDriver","DRIVER_NAME","dirname","fsPromises","resolve","fsp","_inlineAppConfig","createRadixRouter","__publicField","log","watch","AEP_VERSION","randomUUID","_a","DB_PATH","rows","_b","_c","_d","reqNative","sleep","REGISTRY","bad","load","normalize","singleton","require","SCHEMA_SQL","COLS","randomPassword","randomBytes","hubGlobal","hub","criteria","worker","registry","frame","save","DATA_DIR","COOLDOWN_MS","_e","fresh","partsToText","pid","seen","modeInfo","rowToTask","TaskEngineImpl","callNodeRequestHandler","fetchNodeRequestHandler","gracefulShutdown"],"mappings":"","x_google_ignoreList":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,51,52,136,137,139,140,141,142,143]}
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentworkshop-prod",
3
- "version": "0.5.3",
3
+ "version": "0.5.4",
4
4
  "type": "module",
5
5
  "private": true,
6
6
  "dependencies": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentworkshop",
3
- "version": "0.5.3",
3
+ "version": "0.5.4",
4
4
  "type": "module",
5
5
  "description": "AgentWorkShop 软件开发系统 - 基于 Nuxt 4 的配置驱动运行范式",
6
6
  "license": "PolyForm-Noncommercial-1.0.0",
@@ -0,0 +1,25 @@
1
+ /**
2
+ * 保留策略单元验证(hardening GROW-1 / AC-5):临时库种过期行 → sweep → 断言。
3
+ * 用法:npx tsx scripts/_dbg-retention-test.ts
4
+ */
5
+ import { DatabaseSync } from 'node:sqlite'
6
+ import { runRetentionSweep } from '../server/services/workshop/db/retention'
7
+
8
+ const db = new DatabaseSync(':memory:')
9
+ db.exec('CREATE TABLE messages (id TEXT PRIMARY KEY, created_at TEXT NOT NULL)')
10
+ db.exec('CREATE TABLE audit_log (id INTEGER PRIMARY KEY AUTOINCREMENT, at TEXT NOT NULL)')
11
+ db.exec('CREATE TABLE approval_history (id TEXT PRIMARY KEY, created_at TEXT NOT NULL)')
12
+ const old = new Date(Date.now() - 40 * 86_400_000).toISOString()
13
+ const ancient = new Date(Date.now() - 120 * 86_400_000).toISOString()
14
+ const fresh = new Date(Date.now() - 1000).toISOString()
15
+ for (let i = 0; i < 12; i++) {
16
+ db.prepare('INSERT INTO messages VALUES (?,?)').run(`m${i}`, i < 8 ? old : fresh)
17
+ db.prepare('INSERT INTO audit_log (at) VALUES (?)').run(i < 6 ? ancient : fresh)
18
+ db.prepare('INSERT INTO approval_history VALUES (?,?)').run(`a${i}`, fresh)
19
+ }
20
+ console.log('SWEEP =', JSON.stringify(runRetentionSweep(db)))
21
+ const c = (t: string) => String((db.prepare(`SELECT COUNT(*) c FROM ${t}`).get() as { c: number }).c)
22
+ console.log(`剩量 messages=${c('messages')}(期望4) audit=${c('audit_log')}(期望6) approval=${c('approval_history')}(期望12)`)
23
+
24
+ process.env.AW_RETENTION_DISABLED = '1'
25
+ console.log('逃生门 =', JSON.stringify(runRetentionSweep(db)), '(期望 [])')
@@ -73,6 +73,39 @@ const effectivePort = cliPort ?? devPort
73
73
  process.env.PORT = String(effectivePort)
74
74
  console.log(`[config] worker PORT env -> ${effectivePort}`)
75
75
 
76
+ // --- 单实例互斥 + 端口占用显式报错(hardening ST-1/ST-4):不再静默换端口 ---
77
+ {
78
+ const { acquireLock, checkPort } = await import('../shared/config/single-instance.mjs')
79
+ const lock = acquireLock(resolve(root, '.AgentWorkShop'), { mode: 'dev', port: effectivePort })
80
+ if (!lock.ok) {
81
+ const h = lock.holder
82
+ console.error(`✖ 已有实例在运行(pid=${h.pid}${h.port ? `,端口=${h.port}` : ''},启动于 ${h.startedAt ?? '未知'},模式=${h.mode ?? '未知'})`)
83
+ console.error(` › dev/start 共享同一数据目录,禁止双开;如需并行请用 AW_HOME 隔离配置根`)
84
+ console.error(` › 如确认是残留锁文件,可删除 ${lock.lockPath} 后重试`)
85
+ process.exit(2)
86
+ }
87
+ const probeHost = devHost === '0.0.0.0' || devHost === '::' ? '127.0.0.1' : devHost
88
+ const occupied = await checkPort(probeHost, effectivePort)
89
+ if (occupied) {
90
+ let pidHint = ''
91
+ try {
92
+ const { execSync } = await import('node:child_process')
93
+ const isWin = process.platform === 'win32'
94
+ const out = execSync(
95
+ isWin ? `netstat -ano | findstr :${effectivePort}` : `lsof -ti :${effectivePort} 2>/dev/null | head -1`,
96
+ { encoding: 'utf8', shell: true },
97
+ )
98
+ const m = isWin ? out.split('\n').find(l => l.includes('LISTENING')) : out.trim()
99
+ pidHint = isWin ? (m?.trim().split(/\s+/).pop() ?? '') : m
100
+ if (pidHint) pidHint = `(占用 pid=${pidHint})`
101
+ }
102
+ catch { /* 探测失败不阻断报错 */ }
103
+ console.error(`✖ 开发端口 ${effectivePort} 已被占用${pidHint}`)
104
+ console.error(` › 可显式指定其他端口: aw dev --port ${effectivePort + 1}`)
105
+ process.exit(2)
106
+ }
107
+ }
108
+
76
109
  const inject = [...rest]
77
110
  if (!hasPort) inject.push('--port', String(devPort))
78
111
  if (!hasHost) inject.push('--host', devHost)
package/scripts/start.mjs CHANGED
@@ -50,6 +50,17 @@ const host = eff.effective['server.host'] ?? '0.0.0.0'
50
50
  const prodPort = eff.effective['server.prod.port'] ?? 3000
51
51
  const portSource = eff.sources['server.prod.port']
52
52
 
53
+ // ---- 单实例互斥(hardening ST-1):同配置根双开直接退出码 2,防 SQLite 锁崩溃 ----
54
+ const { acquireLock } = await import('../shared/config/single-instance.mjs')
55
+ const lock = acquireLock(rm.configRoot, { mode: `prod:${rm.mode}`, port: argPort ? Number(argPort) : prodPort })
56
+ if (!lock.ok) {
57
+ const h = lock.holder
58
+ console.error(`✖ 已有实例在运行(pid=${h.pid}${h.port ? `,端口=${h.port}` : ''},启动于 ${h.startedAt ?? '未知'},模式=${h.mode ?? '未知'})`)
59
+ console.error(` › 配置根: ${rm.configRoot}`)
60
+ console.error(` › 如确认是残留锁文件,可删除 ${lock.lockPath} 后重试`)
61
+ process.exit(2)
62
+ }
63
+
53
64
  process.env.HOST = process.env.HOST || process.env.NITRO_HOST || String(host)
54
65
  process.env.PORT = process.env.PORT || process.env.NITRO_PORT || String(prodPort)
55
66
  process.env.NITRO_HOST = process.env.HOST
@@ -1,13 +1,13 @@
1
1
  /**
2
2
  * 备份定时插件(S6,production-readiness-plan)。
3
3
  *
4
- * 对 data/ 下三库(workshop/users/daq-timeseries)每日 VACUUM INTO 快照到
4
+ * 对 data/ 下三库(workshop/users/daq-timeseries)每日 serialize 镜像快照到
5
5
  * data/backups/,按 BACKUP_KEEP(默认 7)轮转;调度模式复用 ws.ts 保留期清理的
6
6
  * setInterval + globalThis key 防 HMR 重复 + unref()。dev 与生产均生效
7
7
  * (备份无副作用,始终开启;BACKUP_DISABLED=1 可关)。
8
8
  */
9
9
  import { DatabaseSync } from 'node:sqlite'
10
- import { existsSync, mkdirSync, readdirSync, rmSync } from 'node:fs'
10
+ import { existsSync, mkdirSync, readdirSync, rmSync, writeFileSync } from 'node:fs'
11
11
  import { resolve } from 'node:path'
12
12
  import { ensureDataDir } from '@/shared/config/home.mjs'
13
13
 
@@ -15,7 +15,23 @@ const g = globalThis as typeof globalThis & { __awBackupTimer?: NodeJS.Timeout,
15
15
 
16
16
  const DB_FILES = ['workshop.sqlite', 'users.sqlite', 'daq-timeseries.sqlite'] as const
17
17
 
18
- function backupOnce(dataDir: string): void {
18
+ /**
19
+ * 单库在线快照(hardening ST-2):node:sqlite serialize() 一致性数据库镜像 → 落盘。
20
+ * 纯读操作,不与主写者抢锁(VACUUM INTO 会与写事务竞争 SQLITE_BUSY,已实测);
21
+ * 产物为标准 SQLite 文件,与历史 .bak 结构兼容。失败只记录不抛出。
22
+ */
23
+ async function backupOne(src: string, target: string): Promise<void> {
24
+ const db = new DatabaseSync(src)
25
+ try {
26
+ const image = db.serialize()
27
+ writeFileSync(target, image)
28
+ }
29
+ finally {
30
+ db.close()
31
+ }
32
+ }
33
+
34
+ async function backupOnce(dataDir: string): Promise<void> {
19
35
  const backupDir = resolve(dataDir, 'backups')
20
36
  mkdirSync(backupDir, { recursive: true })
21
37
  const stamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19)
@@ -24,14 +40,8 @@ function backupOnce(dataDir: string): void {
24
40
  if (!existsSync(src)) continue
25
41
  const target = resolve(backupDir, `${file}.${stamp}.bak`)
26
42
  try {
27
- const db = new DatabaseSync(src)
28
- try {
29
- // VACUUM INTO:在线一致性快照(WAL 下安全),不阻塞长事务
30
- db.exec(`VACUUM INTO '${target.replace(/\\/g, '/')}'`)
31
- }
32
- finally {
33
- db.close()
34
- }
43
+ await backupOne(src, target)
44
+ console.log('[backup]', file, '快照完成(serialize)')
35
45
  }
36
46
  catch (err) {
37
47
  console.error(`[backup] ${file} 快照失败:`, err instanceof Error ? err.message : err)
@@ -7,6 +7,9 @@
7
7
  * 依赖异常中止进程,绝不能被护栏吞掉。
8
8
  */
9
9
  const SOCKET_NOISE = /ECONNRESET|EPIPE|ECONNABORTED|ETIMEDOUT|ERR_STREAM_PREMATURE_CLOSE/
10
+ // SQLite 忙/锁(hardening ST-1):多写竞争的瞬态错误,记录并继续;
11
+ // 真正的库损坏/磁盘错误不经此路径,仍走致命语义。
12
+ const SQLITE_BUSY = /SQLITE_BUSY|SQLITE_LOCKED|database is locked/i
10
13
 
11
14
  function isSocketNoise(reason: unknown): boolean {
12
15
  if (reason == null) return false
@@ -22,11 +25,16 @@ function describe(reason: unknown): string {
22
25
  }
23
26
 
24
27
  export default defineNitroPlugin(() => {
28
+ const isTransientDbBusy = (reason: unknown): boolean => SQLITE_BUSY.test(describe(reason))
25
29
  process.on('unhandledRejection', (reason) => {
26
30
  if (isSocketNoise(reason)) {
27
31
  console.warn(`[stability-guard] socket noise suppressed: ${describe(reason).slice(0, 120)}`)
28
32
  return
29
33
  }
34
+ if (isTransientDbBusy(reason)) {
35
+ console.warn(`[stability-guard] sqlite busy(瞬态,不退出): ${describe(reason).slice(0, 120)}`)
36
+ return
37
+ }
30
38
  console.error(`[stability-guard] fatal unhandledRejection, exiting:\n${describe(reason)}`)
31
39
  process.exit(1)
32
40
  })
@@ -35,8 +43,12 @@ export default defineNitroPlugin(() => {
35
43
  console.warn(`[stability-guard] socket noise suppressed: ${describe(err).slice(0, 120)}`)
36
44
  return
37
45
  }
46
+ if (isTransientDbBusy(err)) {
47
+ console.warn(`[stability-guard] sqlite busy(瞬态,不退出): ${describe(err).slice(0, 120)}`)
48
+ return
49
+ }
38
50
  console.error(`[stability-guard] fatal uncaughtException, exiting:\n${describe(err)}`)
39
51
  process.exit(1)
40
52
  })
41
- console.warn('[stability-guard] armed (socket disconnects → log & continue; real errors → exit 1)')
53
+ console.warn('[stability-guard] armed (socket 断连与 sqlite 瞬态忙 → 记录继续;真实错误 → exit 1)')
42
54
  })
@@ -0,0 +1,57 @@
1
+ /**
2
+ * 保留期定时插件(hardening GROW-1)。
3
+ *
4
+ * 每 24h 对 workshop.sqlite 的 messages/audit_log/approval_history 做分批保留
5
+ * 清理(策略见 db/retention.ts;RETENTION_DISABLED=1 可整体关闭)。
6
+ * 调度模式同 backup.ts:setInterval + globalThis key 防 HMR 重复 + unref()。
7
+ * 启动 90s 后首跑(避开启动风暴,且错峰于 backup 的 30s 首备)。
8
+ */
9
+ import { DatabaseSync } from 'node:sqlite'
10
+ import { existsSync } from 'node:fs'
11
+ import { resolve } from 'node:path'
12
+ import { runRetentionSweep } from '@/server/services/workshop/db/retention'
13
+ import { ensureDataDir } from '@/shared/config/home.mjs'
14
+
15
+ const g = globalThis as typeof globalThis & { __awRetentionTimer?: NodeJS.Timeout }
16
+
17
+ function sweepOnce(dataDir: string): void {
18
+ const dbPath = resolve(dataDir, 'workshop.sqlite')
19
+ if (!existsSync(dbPath)) return
20
+ const db = new DatabaseSync(dbPath)
21
+ try {
22
+ const results = runRetentionSweep(db)
23
+ for (const r of results) {
24
+ if (r.removed > 0) console.log(`[retention] ${r.table} 清理 ${r.removed} 行(>${r.days}d)`)
25
+ }
26
+ }
27
+ finally {
28
+ db.close()
29
+ }
30
+ }
31
+
32
+ export default function retentionPlugin() {
33
+ if (process.env.RETENTION_DISABLED === '1' || process.env.AW_RETENTION_DISABLED === '1') return
34
+ if (g.__awRetentionTimer) return
35
+ const dataDir = ensureDataDir()
36
+
37
+ const first = setTimeout(() => {
38
+ try {
39
+ sweepOnce(dataDir)
40
+ }
41
+ catch (err) {
42
+ console.error('[retention] 首轮清理失败:', err instanceof Error ? err.message : err)
43
+ }
44
+ }, 90_000)
45
+ first.unref?.()
46
+
47
+ const timer = setInterval(() => {
48
+ try {
49
+ sweepOnce(dataDir)
50
+ }
51
+ catch (err) {
52
+ console.error('[retention] 定时清理失败:', err instanceof Error ? err.message : err)
53
+ }
54
+ }, 24 * 3_600_000)
55
+ timer.unref?.()
56
+ g.__awRetentionTimer = timer
57
+ }
@@ -476,12 +476,14 @@ class DaqController {
476
476
  controllerState(): AepDaqControllerState & { produced?: number, consumed?: number, dropped?: number, samplesStored?: number, tsdbDropped?: number } {
477
477
  // 丢弃 = 队列层真实丢弃(inproc 拥塞/mqtt 断连)+ 消费侧乱序迟到帧(诚实可见)
478
478
  const queueLost = g_queueLost()
479
+ // 单次遍历(hardening PERF-1):status 高频路径不再对全表多次 all()
480
+ const nodes = this.repo.all()
479
481
  return {
480
482
  running: this.running,
481
483
  defaultIntervalMs: this.defaultIntervalMs,
482
484
  defaultPublishIntervalMs: this.defaultPublishIntervalMs,
483
- nodesTotal: this.repo.all().length,
484
- nodesOnline: this.onlineCount(),
485
+ nodesTotal: nodes.length,
486
+ nodesOnline: this.running ? nodes.filter(n => n.enabled).length : 0,
485
487
  produced: this.producedCount,
486
488
  consumed: this.consumedCount,
487
489
  dropped: Math.max(0, this.producedCount - this.consumedCount) + queueLost + this.lateDropped,
@@ -0,0 +1,50 @@
1
+ /**
2
+ * 增长治理保留策略(hardening GROW-1)。
3
+ *
4
+ * 为无保留机制的只增表做分批清理(每批 ≤5000,循环到 0,避免长事务持锁):
5
+ * messages 默认 30d (AW_MESSAGES_RETENTION_D)
6
+ * audit_log 默认 90d (AW_AUDIT_RETENTION_D;合规观察期,从严保留)
7
+ * approval_history 默认 180d (AW_APPROVAL_RETENTION_D;历史裁决主张不可变,放宽)
8
+ * AW_RETENTION_DISABLED=1 整体逃生门。时间列均为 TEXT ISO,可字典序比较。
9
+ * channel_events 与 daq_samples 已有各自保留机制,此处不重复覆盖。
10
+ */
11
+ type DatabaseSyncLike = {
12
+ prepare: (sql: string) => { run: (...args: unknown[]) => { changes: number | bigint } }
13
+ }
14
+
15
+ const DAY_MS = 86_400_000
16
+ const BATCH = 5000
17
+
18
+ const TARGETS = [
19
+ { table: 'messages', column: 'created_at', days: 30, envKey: 'AW_MESSAGES_RETENTION_D' },
20
+ { table: 'audit_log', column: 'at', days: 90, envKey: 'AW_AUDIT_RETENTION_D' },
21
+ { table: 'approval_history', column: 'created_at', days: 180, envKey: 'AW_APPROVAL_RETENTION_D' },
22
+ ] as const
23
+
24
+ function retentionDays(envKey: string, fallback: number): number {
25
+ const n = Number(process.env[envKey])
26
+ return Number.isFinite(n) && n > 0 ? n : fallback
27
+ }
28
+
29
+ export interface RetentionResult { table: string, removed: number, days: number }
30
+
31
+ /** 对单库执行一轮保留清理;返回各表删除行数(调用方负责 try/catch 与日志)。 */
32
+ export function runRetentionSweep(db: DatabaseSyncLike): RetentionResult[] {
33
+ if (process.env.AW_RETENTION_DISABLED === '1') return []
34
+ const out: RetentionResult[] = []
35
+ for (const t of TARGETS) {
36
+ const days = retentionDays(t.envKey, t.days)
37
+ const before = new Date(Date.now() - days * DAY_MS).toISOString()
38
+ let removed = 0
39
+ for (;;) {
40
+ const res = db.prepare(
41
+ `DELETE FROM ${t.table} WHERE rowid IN (SELECT rowid FROM ${t.table} WHERE ${t.column} < ? LIMIT ${BATCH})`,
42
+ ).run(before)
43
+ const n = Number(res.changes)
44
+ removed += n
45
+ if (n < BATCH) break
46
+ }
47
+ out.push({ table: t.table, removed, days })
48
+ }
49
+ return out
50
+ }
@@ -218,10 +218,12 @@ class DcwController {
218
218
  }
219
219
 
220
220
  controllerState() {
221
+ // 单次遍历(hardening PERF-1):status 高频路径不再对全表多次 all()
222
+ const nodes = this.repo.all()
221
223
  return {
222
224
  running: this.running,
223
- nodesTotal: this.repo.all().length,
224
- nodesOnline: this.running ? this.repo.all().filter(n => n.enabled).length : 0,
225
+ nodesTotal: nodes.length,
226
+ nodesOnline: this.running ? nodes.filter(n => n.enabled).length : 0,
225
227
  writesTotal: this.writesTotal,
226
228
  writesFailed: this.writesFailed,
227
229
  }
@@ -0,0 +1,86 @@
1
+ // ============================================================
2
+ // 单实例互斥(hardening ST-1)—— 零依赖,CLI / 启动脚本通用。
3
+ // 锁文件 <configRoot>/.runtime/aw.lock 原子创建(wx):
4
+ // { pid, startedAt, mode, port }
5
+ // 已存在且 PID 存活 → 视为已有实例(返回冲突信息,调用方以退出码 2 退出);
6
+ // PID 已死(崩溃/强杀残留) → 自动接管重写。进程退出时 releaseLock 兜底清理。
7
+ // ============================================================
8
+ import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
9
+ import { join } from 'node:path'
10
+
11
+ function pidAlive(pid) {
12
+ if (!Number.isInteger(pid) || pid <= 0) return false
13
+ try {
14
+ // signal 0 探活:进程存在但不发信号;ESRCH=不存在,EPERM=存在(他人进程)
15
+ process.kill(pid, 0)
16
+ return true
17
+ }
18
+ catch (err) {
19
+ return err?.code === 'EPERM'
20
+ }
21
+ }
22
+
23
+ /**
24
+ * 尝试获取单实例锁。
25
+ * @returns {{ ok: true, lockPath: string, release: () => void }
26
+ * | { ok: false, lockPath: string, holder: { pid: number, startedAt: string, mode: string, port: number | null } }}
27
+ */
28
+ export function acquireLock(configRoot, { mode = 'prod', port = null } = {}) {
29
+ const runtimeDir = join(configRoot, '.runtime')
30
+ const lockPath = join(runtimeDir, 'aw.lock')
31
+ mkdirSync(runtimeDir, { recursive: true })
32
+ if (existsSync(lockPath)) {
33
+ let holder = null
34
+ try {
35
+ holder = JSON.parse(readFileSync(lockPath, 'utf8'))
36
+ }
37
+ catch { /* 损坏锁文件按残留处理 */ }
38
+ if (holder && pidAlive(holder.pid)) {
39
+ return { ok: false, lockPath, holder: { ...holder, port: holder.port ?? null } }
40
+ }
41
+ try { rmSync(lockPath) } catch { /* 抢不掉则下方 wx 再失败 */ }
42
+ }
43
+ const me = { pid: process.pid, startedAt: new Date().toISOString(), mode, port }
44
+ try {
45
+ writeFileSync(lockPath, JSON.stringify(me, null, 2), { flag: 'wx' })
46
+ }
47
+ catch (err) {
48
+ // 与并发启动者竞态:按冲突处理
49
+ let holder = null
50
+ try { holder = JSON.parse(readFileSync(lockPath, 'utf8')) } catch { /* ignore */ }
51
+ if (holder && pidAlive(holder.pid)) {
52
+ return { ok: false, lockPath, holder: { ...holder, port: holder.port ?? null } }
53
+ }
54
+ throw err
55
+ }
56
+ let released = false
57
+ const release = () => {
58
+ if (released) return
59
+ released = true
60
+ try {
61
+ const cur = JSON.parse(readFileSync(lockPath, 'utf8'))
62
+ if (cur?.pid !== process.pid) return // 锁已被他人接管,不误删
63
+ rmSync(lockPath)
64
+ }
65
+ catch { /* 已不存在/损坏,忽略 */ }
66
+ }
67
+ process.once('exit', release)
68
+ process.once('SIGINT', () => { release(); process.exit(130) })
69
+ process.once('SIGTERM', () => { release(); process.exit(143) })
70
+ return { ok: true, lockPath, release }
71
+ }
72
+
73
+ /** 端口占用探测:返回占用进程 PID(未占用返回 null)。TCP try-listen 后立刻释放。 */
74
+ export async function checkPort(host, port) {
75
+ const net = await import('node:net')
76
+ return new Promise((resolveProbe) => {
77
+ const srv = net.createServer()
78
+ srv.once('error', (err) => {
79
+ resolveProbe(err?.code === 'EADDRINUSE' ? port : null)
80
+ srv.close()
81
+ })
82
+ srv.listen(port, host, () => {
83
+ srv.close(() => resolveProbe(null))
84
+ })
85
+ })
86
+ }
@@ -1 +0,0 @@
1
- {"id":"fb769eda-b1db-437b-adc7-ecf71eb3b30b","timestamp":1788339632657,"prerendered":[]}