create-workframe 0.1.1 → 0.1.3

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 (100) hide show
  1. package/README.md +14 -1
  2. package/SECURITY.md +4 -6
  3. package/bin/create-workframe.js +3 -3
  4. package/package.json +1 -1
  5. package/scripts/apply-update-hermes.sh +17 -17
  6. package/scripts/apply-update-workframe.sh +77 -77
  7. package/scripts/bootstrap-workspace-link.sh +8 -8
  8. package/scripts/compose-docker-host.sh +37 -37
  9. package/scripts/fix-zk-encryption-key.sh +35 -35
  10. package/scripts/restart-gateway-hermes.sh +12 -12
  11. package/scripts/setup-stack-secrets.sh +50 -50
  12. package/scripts/sync-canonical-to-package.mjs +19 -2
  13. package/scripts/verify-public-deploy.sh +105 -105
  14. package/workframe-api/README.md +10 -14
  15. package/workframe-api/concierge.py +173 -0
  16. package/workframe-api/llm_error_glossary.py +236 -0
  17. package/workframe-api/llm_proxy.py +3 -0
  18. package/workframe-api/openrouter_catalog.py +114 -0
  19. package/workframe-api/package.json +1 -1
  20. package/workframe-api/server.py +144 -48
  21. package/workframe-ui/public/assets/{arc-COAT3laO.js → arc-CRhulRPr.js} +1 -1
  22. package/workframe-ui/public/assets/architecture-7EHR7CIX-CwxC-UJz.js +1 -0
  23. package/workframe-ui/public/assets/{architectureDiagram-3BPJPVTR-BFjWV24l.js → architectureDiagram-3BPJPVTR-B1Gq5onc.js} +1 -1
  24. package/workframe-ui/public/assets/{blockDiagram-GPEHLZMM-DSQLPfrj.js → blockDiagram-GPEHLZMM-DtXEetq-.js} +1 -1
  25. package/workframe-ui/public/assets/{c4Diagram-AAUBKEIU-DKEHv1t2.js → c4Diagram-AAUBKEIU-Bw7NEN3_.js} +1 -1
  26. package/workframe-ui/public/assets/channel-BaZSQvmW.js +1 -0
  27. package/workframe-ui/public/assets/{chunk-2J33WTMH-DHZg-DUi.js → chunk-2J33WTMH-91lObBre.js} +1 -1
  28. package/workframe-ui/public/assets/{chunk-3OPIFGDE-BB-OYTfp.js → chunk-3OPIFGDE-D5IopWdW.js} +1 -1
  29. package/workframe-ui/public/assets/{chunk-4BX2VUAB-C93q0YIm.js → chunk-4BX2VUAB-DRHbh4Yd.js} +1 -1
  30. package/workframe-ui/public/assets/{chunk-55IACEB6-MAYniqik.js → chunk-55IACEB6-DcfKoh86.js} +1 -1
  31. package/workframe-ui/public/assets/{chunk-5ZQYHXKU-ChgN6YJs.js → chunk-5ZQYHXKU-BMtcWXOU.js} +1 -1
  32. package/workframe-ui/public/assets/{chunk-727SXJPM-B_FYwdAv.js → chunk-727SXJPM-BW7tTfej.js} +1 -1
  33. package/workframe-ui/public/assets/{chunk-AQP2D5EJ-1_Hw_h1A.js → chunk-AQP2D5EJ-CGoSQAgm.js} +1 -1
  34. package/workframe-ui/public/assets/{chunk-BSJP7CBP-CFiDQ1Rv.js → chunk-BSJP7CBP-RW1Jng9K.js} +1 -1
  35. package/workframe-ui/public/assets/{chunk-CSCIHK7Q-DZ9UMTlB.js → chunk-CSCIHK7Q-D8PwFfuF.js} +1 -1
  36. package/workframe-ui/public/assets/{chunk-FMBD7UC4-DlMlyFgw.js → chunk-FMBD7UC4-rUp_DSZ2.js} +1 -1
  37. package/workframe-ui/public/assets/{chunk-KSCS5N6A-DHXtQ_Hf.js → chunk-KSCS5N6A-C3eMeGne.js} +1 -1
  38. package/workframe-ui/public/assets/{chunk-L5ZTLDWV-CuQzg-QG.js → chunk-L5ZTLDWV-DaE5LwXn.js} +1 -1
  39. package/workframe-ui/public/assets/{chunk-LZXEDZCA-BHzjzCGg.js → chunk-LZXEDZCA-Cmn67nL3.js} +2 -2
  40. package/workframe-ui/public/assets/{chunk-ND2GUHAM-DHXx05n2.js → chunk-ND2GUHAM-Bg-FPAN5.js} +1 -1
  41. package/workframe-ui/public/assets/{chunk-NZK2D7GU-CV5pmDM_.js → chunk-NZK2D7GU-orlL5R9g.js} +1 -1
  42. package/workframe-ui/public/assets/{chunk-O5CBEL6O-6tkCHxsV.js → chunk-O5CBEL6O-BaPyh9SK.js} +1 -1
  43. package/workframe-ui/public/assets/chunk-QZHKN3VN-DXcsnu-x.js +1 -0
  44. package/workframe-ui/public/assets/chunk-WU5MYG2G-B2O0DZxu.js +1 -0
  45. package/workframe-ui/public/assets/{chunk-XPW4576I-BClwIiCp.js → chunk-XPW4576I-CXYFE8tT.js} +1 -1
  46. package/workframe-ui/public/assets/classDiagram-4FO5ZUOK-C_TyUBYX.js +1 -0
  47. package/workframe-ui/public/assets/classDiagram-v2-Q7XG4LA2-C_TyUBYX.js +1 -0
  48. package/workframe-ui/public/assets/{cose-bilkent-S5V4N54A-DOrGV6DQ.js → cose-bilkent-S5V4N54A-DDzKMTbp.js} +1 -1
  49. package/workframe-ui/public/assets/{dagre-BM42HDAG-DXTPvJkX.js → dagre-BM42HDAG-DCa6EvS3.js} +1 -1
  50. package/workframe-ui/public/assets/{diagram-2AECGRRQ-xX_v-pbf.js → diagram-2AECGRRQ-C-WIQoE_.js} +1 -1
  51. package/workframe-ui/public/assets/{diagram-5GNKFQAL-Cd2pXbBe.js → diagram-5GNKFQAL-UDk1nRH6.js} +1 -1
  52. package/workframe-ui/public/assets/{diagram-KO2AKTUF-Df3XvUtk.js → diagram-KO2AKTUF-DjLxUTPx.js} +1 -1
  53. package/workframe-ui/public/assets/{diagram-LMA3HP47-CsijIPaD.js → diagram-LMA3HP47-DNA9GSwJ.js} +1 -1
  54. package/workframe-ui/public/assets/{diagram-OG6HWLK6-aq5fmfHd.js → diagram-OG6HWLK6-DO2nQu2f.js} +1 -1
  55. package/workframe-ui/public/assets/{dist-D1c0mkbB.js → dist-DyW8oFIW.js} +1 -1
  56. package/workframe-ui/public/assets/{erDiagram-TEJ5UH35-DnFysVRY.js → erDiagram-TEJ5UH35-DFtJLZx1.js} +1 -1
  57. package/workframe-ui/public/assets/eventmodeling-FCH6USID-BTmiKS74.js +1 -0
  58. package/workframe-ui/public/assets/{flowDiagram-I6XJVG4X-C6Ebi3su.js → flowDiagram-I6XJVG4X-B6K6EnPA.js} +1 -1
  59. package/workframe-ui/public/assets/{ganttDiagram-6RSMTGT7-BQXQtUpa.js → ganttDiagram-6RSMTGT7-CbuWdupl.js} +1 -1
  60. package/workframe-ui/public/assets/{gitGraph-WXDBUCRP-Dt0zIs_M.js → gitGraph-WXDBUCRP-BW_jwUPU.js} +1 -1
  61. package/workframe-ui/public/assets/{gitGraphDiagram-PVQCEYII-BF8gHzRn.js → gitGraphDiagram-PVQCEYII-B4MYuP9j.js} +1 -1
  62. package/workframe-ui/public/assets/index-BYacg3Nj.js +133 -0
  63. package/workframe-ui/public/assets/{info-J43DQDTF-CSmszQJT.js → info-J43DQDTF-Xa61PMDn.js} +1 -1
  64. package/workframe-ui/public/assets/{infoDiagram-5YYISTIA-CVTKGW6p.js → infoDiagram-5YYISTIA-BNbQgdUG.js} +1 -1
  65. package/workframe-ui/public/assets/{ishikawaDiagram-YF4QCWOH-Z8pT09Lv.js → ishikawaDiagram-YF4QCWOH-BDfiCzHo.js} +1 -1
  66. package/workframe-ui/public/assets/{journeyDiagram-JHISSGLW-r3wD68_T.js → journeyDiagram-JHISSGLW-Dn52B8tT.js} +1 -1
  67. package/workframe-ui/public/assets/{kanban-definition-UN3LZRKU-Il8VglqN.js → kanban-definition-UN3LZRKU-rhwkS_g6.js} +1 -1
  68. package/workframe-ui/public/assets/{line-oyjpfz2A.js → line-BQJgrj-x.js} +1 -1
  69. package/workframe-ui/public/assets/{linear-Cf7p5tVp.js → linear-Bq2ZvWSJ.js} +1 -1
  70. package/workframe-ui/public/assets/{mermaid-parser.core-YmbZ-AfY.js → mermaid-parser.core-CwFK_i8p.js} +2 -2
  71. package/workframe-ui/public/assets/{mermaid.core-BFdCAqCo.js → mermaid.core-C9CAm83c.js} +3 -3
  72. package/workframe-ui/public/assets/{mindmap-definition-RKZ34NQL-Cy2iCtEl.js → mindmap-definition-RKZ34NQL-BXwEccNZ.js} +1 -1
  73. package/workframe-ui/public/assets/{packet-YPE3B663-DwOBZL6K.js → packet-YPE3B663-D754iSKT.js} +1 -1
  74. package/workframe-ui/public/assets/{pie-LRSECV5Y-04PPhnKK.js → pie-LRSECV5Y-BQ2V4UWk.js} +1 -1
  75. package/workframe-ui/public/assets/{pieDiagram-4H26LBE5-LxIpgHqi.js → pieDiagram-4H26LBE5-CNHecl4C.js} +1 -1
  76. package/workframe-ui/public/assets/{quadrantDiagram-W4KKPZXB-0nBYfYm4.js → quadrantDiagram-W4KKPZXB-Bu6ciL2O.js} +1 -1
  77. package/workframe-ui/public/assets/{radar-GUYGQ44K-D2-vBqps.js → radar-GUYGQ44K-Dr8b9Qak.js} +1 -1
  78. package/workframe-ui/public/assets/{requirementDiagram-4Y6WPE33-DbuU0nlu.js → requirementDiagram-4Y6WPE33-Beua6Xju.js} +1 -1
  79. package/workframe-ui/public/assets/{sankeyDiagram-5OEKKPKP-B2hQ6B2x.js → sankeyDiagram-5OEKKPKP-CSDFJ0P_.js} +1 -1
  80. package/workframe-ui/public/assets/{sequenceDiagram-3UESZ5HK-BBrU30e1.js → sequenceDiagram-3UESZ5HK-KKziodNI.js} +1 -1
  81. package/workframe-ui/public/assets/{src-BJEDmV70.js → src-PKTIkQR0.js} +1 -1
  82. package/workframe-ui/public/assets/{stateDiagram-AJRCARHV-7FGO4kkH.js → stateDiagram-AJRCARHV-Bu8FNMcj.js} +1 -1
  83. package/workframe-ui/public/assets/stateDiagram-v2-BHNVJYJU-E9A5RCa9.js +1 -0
  84. package/workframe-ui/public/assets/{timeline-definition-PNZ67QCA-ptDm4rCN.js → timeline-definition-PNZ67QCA-DMa-RPqy.js} +1 -1
  85. package/workframe-ui/public/assets/{treeView-BLDUP644-CS6Z-0q8.js → treeView-BLDUP644-CzQeUY7D.js} +1 -1
  86. package/workframe-ui/public/assets/{treemap-LRROVOQU-DqV4Y2VA.js → treemap-LRROVOQU-BT4RYAhY.js} +1 -1
  87. package/workframe-ui/public/assets/{vennDiagram-CIIHVFJN-C0UrZJYt.js → vennDiagram-CIIHVFJN-nKaUH6GG.js} +1 -1
  88. package/workframe-ui/public/assets/{wardley-L42UT6IY-bNDN3_Sa.js → wardley-L42UT6IY-eSpvH7au.js} +1 -1
  89. package/workframe-ui/public/assets/{wardleyDiagram-YWT4CUSO-jWiJsefM.js → wardleyDiagram-YWT4CUSO-B5u4s4a5.js} +1 -1
  90. package/workframe-ui/public/assets/{xychartDiagram-2RQKCTM6-Dsh_fLCy.js → xychartDiagram-2RQKCTM6-DcXo5hDi.js} +1 -1
  91. package/workframe-ui/public/index.html +1 -1
  92. package/workframe-ui/public/assets/architecture-7EHR7CIX-DUyH3hWG.js +0 -1
  93. package/workframe-ui/public/assets/channel-g7r_RGaY.js +0 -1
  94. package/workframe-ui/public/assets/chunk-QZHKN3VN-C5UQehWY.js +0 -1
  95. package/workframe-ui/public/assets/chunk-WU5MYG2G-DhWllrI8.js +0 -1
  96. package/workframe-ui/public/assets/classDiagram-4FO5ZUOK-BBM_8T8E.js +0 -1
  97. package/workframe-ui/public/assets/classDiagram-v2-Q7XG4LA2-BBM_8T8E.js +0 -1
  98. package/workframe-ui/public/assets/eventmodeling-FCH6USID-Ci8mdb44.js +0 -1
  99. package/workframe-ui/public/assets/index-lRpzpNPT.js +0 -133
  100. package/workframe-ui/public/assets/stateDiagram-v2-BHNVJYJU-DLTSizMg.js +0 -1
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  Published on npm as **create-workframe**.
4
4
 
5
5
  ```bash
6
- npx create-workframe@0.1.1 MyProject
6
+ npx create-workframe@0.1.3 MyProject
7
7
  ```
8
8
 
9
9
  Scaffolds an isolated Workframe + Hermes project on Windows, macOS, and Linux.
@@ -14,14 +14,27 @@ Scaffolds an isolated Workframe + Hermes project on Windows, macOS, and Linux.
14
14
  MyProject/
15
15
  ├── Agents/
16
16
  ├── Files/
17
+ ├── scripts/ bootstrap, lifecycle, workframe.mjs CLI
17
18
  ├── docker-compose.yml
18
19
  ├── workframe-api/
19
20
  ├── workframe-ui/
21
+ ├── workframe-supervisor/
20
22
  └── workframe-manifest.json
21
23
  ```
22
24
 
25
+ ## Project CLI
26
+
27
+ From the generated project root:
28
+
29
+ ```bash
30
+ node scripts/workframe.mjs doctor
31
+ node scripts/workframe.mjs setup
32
+ ```
33
+
23
34
  ## Source
24
35
 
25
36
  [github.com/npx-workframe/workframe](https://github.com/npx-workframe/workframe)
26
37
 
38
+ Documentation: [docs/README.md](https://github.com/npx-workframe/workframe/blob/main/docs/README.md)
39
+
27
40
  Apache-2.0 — see `LICENSE`, `NOTICE`, `SECURITY.md`.
package/SECURITY.md CHANGED
@@ -16,7 +16,7 @@ direct contact with the repository owner).
16
16
 
17
17
  Include:
18
18
 
19
- - Affected component (BFF, supervisor, installer, UI, compose)
19
+ - Affected component (workframe-api, supervisor, installer, UI, compose)
20
20
  - Steps to reproduce
21
21
  - Impact assessment (data exposure, auth bypass, RCE, etc.)
22
22
  - Suggested fix if you have one
@@ -25,11 +25,9 @@ We aim to acknowledge reports within a few business days.
25
25
 
26
26
  ## Scope notes
27
27
 
28
- - **Host Hermes** (`%LOCALAPPDATA%\hermes` on Windows) is personal runtime state and is
29
- out of scope for Workframe product security reports unless the issue is in shared
30
- Workframe source code that affects all installs.
31
- - Production deployments should run with `WORKFRAME_MODE=team`, invite-only access, and
32
- without `DEV_LOCAL_UNSAFE`.
28
+ - Personal Hermes installs outside a Workframe compose stack are out of scope unless the issue is in shared Workframe source that affects all installs.
29
+ - Production deployments should use `WORKFRAME_DEPLOYMENT_MODE=trusted_team` or
30
+ `public_multi_user`, invite-only access, and without `DEV_LOCAL_UNSAFE`.
33
31
  - BYOK (bring-your-own-key) is the default credential mode; workspace company-pays is an
34
32
  explicit admin opt-in.
35
33
 
@@ -2014,15 +2014,15 @@ function nativeConfigYaml(projectName, agentName, personality) {
2014
2014
  const personalityLine = personality ? `# Personality: ${personality}
2015
2015
  ` : "";
2016
2016
  return `${personalityLine}model:
2017
- default: openrouter/owl-alpha
2017
+ default: google/gemini-2.5-flash
2018
2018
  provider: openrouter
2019
2019
  base_url: https://openrouter.ai/api/v1
2020
2020
  api_mode: chat_completions
2021
2021
  fallback_providers:
2022
2022
  - provider: openrouter
2023
- model: openrouter/nex-agi
2023
+ model: anthropic/claude-sonnet-4.5
2024
2024
  - provider: openrouter
2025
- model: openrouter/nvidia/nemotron-3-ultra-550b-a55b:free
2025
+ model: meta-llama/llama-3.3-70b-instruct:free
2026
2026
  providers: {}
2027
2027
  credential_pool_strategies: {}
2028
2028
  toolsets:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-workframe",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Scaffold a Workframe + Hermes workspace with guided onboarding",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,17 +1,17 @@
1
- #!/usr/bin/env bash
2
- # Safe Hermes update — pull gateway/dashboard images, recreate containers. Preserves runtime/Agents.
3
- set -euo pipefail
4
- SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
5
- # shellcheck source=compose-docker-host.sh
6
- source "$SCRIPT_DIR/compose-docker-host.sh"
7
-
8
- echo "=== Hermes update (gateway + dashboard only) ==="
9
- workframe_compose_prepare
10
- echo "Compose dir: $compose_cd"
11
- echo "Preserves: Agents/, Files/, workframe-api data volumes"
12
-
13
- SERVICES=(gateway dashboard)
14
- workframe_compose pull "${SERVICES[@]}"
15
- workframe_compose up -d --force-recreate --no-deps "${SERVICES[@]}"
16
-
17
- echo "=== Hermes update complete ==="
1
+ #!/usr/bin/env bash
2
+ # Safe Hermes update — pull gateway/dashboard images, recreate containers. Preserves runtime/Agents.
3
+ set -euo pipefail
4
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
5
+ # shellcheck source=compose-docker-host.sh
6
+ source "$SCRIPT_DIR/compose-docker-host.sh"
7
+
8
+ echo "=== Hermes update (gateway + dashboard only) ==="
9
+ workframe_compose_prepare
10
+ echo "Compose dir: $compose_cd"
11
+ echo "Preserves: Agents/, Files/, workframe-api data volumes"
12
+
13
+ SERVICES=(gateway dashboard)
14
+ workframe_compose pull "${SERVICES[@]}"
15
+ workframe_compose up -d --force-recreate --no-deps "${SERVICES[@]}"
16
+
17
+ echo "=== Hermes update complete ==="
@@ -1,77 +1,77 @@
1
- #!/usr/bin/env bash
2
- # Safe Workframe update — sync npm template (optional), rebuild API/supervisor/UI containers. Never wipes runtime/DB.
3
- set -euo pipefail
4
- SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
5
- # shellcheck source=compose-docker-host.sh
6
- source "$SCRIPT_DIR/compose-docker-host.sh"
7
-
8
- workframe_compose_prepare
9
- PROJECT_ROOT="${WORKFRAME_HOST_PROJECT_ROOT:-${WORKFRAME_PROJECT_ROOT:-$compose_cd}}"
10
-
11
- echo "=== Workframe update (API + supervisor + UI) ==="
12
- echo "Project root: $PROJECT_ROOT"
13
- echo "Preserves: Agents/, Files/, .env, workframe-api/data, gateway/Hermes profiles"
14
-
15
- TARGET_VERSION="${WORKFRAME_UPDATE_VERSION:-}"
16
- NPM_PACKAGE="${WORKFRAME_NPM_PACKAGE:-create-workframe}"
17
-
18
- if [[ "${WORKFRAME_UPDATE_SKIP_NPM:-1}" == "1" ]] && [[ "${WORKFRAME_UPDATE_ALLOW_NPM:-}" != "1" ]]; then
19
- echo "Skipping npm template sync (WORKFRAME_UPDATE_SKIP_NPM=1; set WORKFRAME_UPDATE_ALLOW_NPM=1 to fetch)"
20
- elif command -v npm >/dev/null 2>&1; then
21
- if [[ "${WORKFRAME_UPDATE_ALLOW_NPM:-}" == "1" ]] && [[ -z "$TARGET_VERSION" ]]; then
22
- echo "WORKFRAME_UPDATE_VERSION is required when WORKFRAME_UPDATE_ALLOW_NPM=1" >&2
23
- exit 1
24
- fi
25
- TMP="$(mktemp -d)"
26
- trap 'rm -rf "$TMP"' EXIT
27
- echo "Fetching ${NPM_PACKAGE}@${TARGET_VERSION:-latest} from npm..."
28
- (cd "$TMP" && npm pack "${NPM_PACKAGE}@${TARGET_VERSION:-latest}" --silent)
29
- TARBALL="$(ls -1 "$TMP"/${NPM_PACKAGE}-*.tgz 2>/dev/null | head -n1 || true)"
30
- if [[ -n "$TARBALL" ]]; then
31
- EXPECTED="$(npm view "${NPM_PACKAGE}@${TARGET_VERSION:-latest}" dist.integrity --silent 2>/dev/null || true)"
32
- if [[ -n "$EXPECTED" ]]; then
33
- ACTUAL="sha512-$(sha512sum "$TARBALL" | awk '{print $1}' | xxd -r -p | base64 | tr -d '\n')"
34
- if [[ "$ACTUAL" != "$EXPECTED" ]]; then
35
- echo "integrity mismatch for ${NPM_PACKAGE}@${TARGET_VERSION:-latest}" >&2
36
- exit 1
37
- fi
38
- echo "integrity ok: ${NPM_PACKAGE}@${TARGET_VERSION:-latest}"
39
- fi
40
- tar -xf "$TARBALL" -C "$TMP"
41
- PKG="$TMP/package"
42
- for dir in workframe-api workframe-supervisor; do
43
- if [[ -d "$PKG/$dir" ]]; then
44
- echo "Syncing $dir/"
45
- mkdir -p "$PROJECT_ROOT/$dir"
46
- cp -a "$PKG/$dir/." "$PROJECT_ROOT/$dir/"
47
- fi
48
- done
49
- if [[ -d "$PKG/workframe-ui/public" ]]; then
50
- echo "Syncing workframe-ui/public/"
51
- mkdir -p "$PROJECT_ROOT/workframe-ui/public"
52
- cp -a "$PKG/workframe-ui/public/." "$PROJECT_ROOT/workframe-ui/public/"
53
- fi
54
- for script in apply-update-hermes.sh apply-update-workframe.sh restart-gateway-hermes.sh compose-docker-host.sh update-hermes.sh; do
55
- if [[ -f "$PKG/scripts/$script" ]]; then
56
- cp -a "$PKG/scripts/$script" "$PROJECT_ROOT/scripts/workframe/$script"
57
- chmod +x "$PROJECT_ROOT/scripts/workframe/$script" 2>/dev/null || true
58
- fi
59
- done
60
- else
61
- echo "npm pack produced no tarball — skipping template sync"
62
- fi
63
- else
64
- echo "Skipping npm template sync (npm missing or WORKFRAME_UPDATE_SKIP_NPM=1)"
65
- fi
66
-
67
- echo "Rebuilding workframe-api and workframe-supervisor..."
68
- workframe_compose build workframe-api workframe-supervisor
69
- workframe_compose up -d --build --no-deps workframe-api workframe-supervisor
70
-
71
- if workframe_compose config --services 2>/dev/null | grep -qx workframe-ui; then
72
- workframe_compose up -d --no-deps workframe-ui || workframe_compose restart workframe-ui || true
73
- elif workframe_compose config --services 2>/dev/null | grep -qx workframe; then
74
- workframe_compose up -d --no-deps workframe || workframe_compose restart workframe || true
75
- fi
76
-
77
- echo "=== Workframe update complete ==="
1
+ #!/usr/bin/env bash
2
+ # Safe Workframe update — sync npm template (optional), rebuild API/supervisor/UI containers. Never wipes runtime/DB.
3
+ set -euo pipefail
4
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
5
+ # shellcheck source=compose-docker-host.sh
6
+ source "$SCRIPT_DIR/compose-docker-host.sh"
7
+
8
+ workframe_compose_prepare
9
+ PROJECT_ROOT="${WORKFRAME_HOST_PROJECT_ROOT:-${WORKFRAME_PROJECT_ROOT:-$compose_cd}}"
10
+
11
+ echo "=== Workframe update (API + supervisor + UI) ==="
12
+ echo "Project root: $PROJECT_ROOT"
13
+ echo "Preserves: Agents/, Files/, .env, workframe-api/data, gateway/Hermes profiles"
14
+
15
+ TARGET_VERSION="${WORKFRAME_UPDATE_VERSION:-}"
16
+ NPM_PACKAGE="${WORKFRAME_NPM_PACKAGE:-create-workframe}"
17
+
18
+ if [[ "${WORKFRAME_UPDATE_SKIP_NPM:-1}" == "1" ]] && [[ "${WORKFRAME_UPDATE_ALLOW_NPM:-}" != "1" ]]; then
19
+ echo "Skipping npm template sync (WORKFRAME_UPDATE_SKIP_NPM=1; set WORKFRAME_UPDATE_ALLOW_NPM=1 to fetch)"
20
+ elif command -v npm >/dev/null 2>&1; then
21
+ if [[ "${WORKFRAME_UPDATE_ALLOW_NPM:-}" == "1" ]] && [[ -z "$TARGET_VERSION" ]]; then
22
+ echo "WORKFRAME_UPDATE_VERSION is required when WORKFRAME_UPDATE_ALLOW_NPM=1" >&2
23
+ exit 1
24
+ fi
25
+ TMP="$(mktemp -d)"
26
+ trap 'rm -rf "$TMP"' EXIT
27
+ echo "Fetching ${NPM_PACKAGE}@${TARGET_VERSION:-latest} from npm..."
28
+ (cd "$TMP" && npm pack "${NPM_PACKAGE}@${TARGET_VERSION:-latest}" --silent)
29
+ TARBALL="$(ls -1 "$TMP"/${NPM_PACKAGE}-*.tgz 2>/dev/null | head -n1 || true)"
30
+ if [[ -n "$TARBALL" ]]; then
31
+ EXPECTED="$(npm view "${NPM_PACKAGE}@${TARGET_VERSION:-latest}" dist.integrity --silent 2>/dev/null || true)"
32
+ if [[ -n "$EXPECTED" ]]; then
33
+ ACTUAL="sha512-$(sha512sum "$TARBALL" | awk '{print $1}' | xxd -r -p | base64 | tr -d '\n')"
34
+ if [[ "$ACTUAL" != "$EXPECTED" ]]; then
35
+ echo "integrity mismatch for ${NPM_PACKAGE}@${TARGET_VERSION:-latest}" >&2
36
+ exit 1
37
+ fi
38
+ echo "integrity ok: ${NPM_PACKAGE}@${TARGET_VERSION:-latest}"
39
+ fi
40
+ tar -xf "$TARBALL" -C "$TMP"
41
+ PKG="$TMP/package"
42
+ for dir in workframe-api workframe-supervisor; do
43
+ if [[ -d "$PKG/$dir" ]]; then
44
+ echo "Syncing $dir/"
45
+ mkdir -p "$PROJECT_ROOT/$dir"
46
+ cp -a "$PKG/$dir/." "$PROJECT_ROOT/$dir/"
47
+ fi
48
+ done
49
+ if [[ -d "$PKG/workframe-ui/public" ]]; then
50
+ echo "Syncing workframe-ui/public/"
51
+ mkdir -p "$PROJECT_ROOT/workframe-ui/public"
52
+ cp -a "$PKG/workframe-ui/public/." "$PROJECT_ROOT/workframe-ui/public/"
53
+ fi
54
+ for script in apply-update-hermes.sh apply-update-workframe.sh restart-gateway-hermes.sh compose-docker-host.sh update-hermes.sh; do
55
+ if [[ -f "$PKG/scripts/$script" ]]; then
56
+ cp -a "$PKG/scripts/$script" "$PROJECT_ROOT/scripts/workframe/$script"
57
+ chmod +x "$PROJECT_ROOT/scripts/workframe/$script" 2>/dev/null || true
58
+ fi
59
+ done
60
+ else
61
+ echo "npm pack produced no tarball — skipping template sync"
62
+ fi
63
+ else
64
+ echo "Skipping npm template sync (npm missing or WORKFRAME_UPDATE_SKIP_NPM=1)"
65
+ fi
66
+
67
+ echo "Rebuilding workframe-api and workframe-supervisor..."
68
+ workframe_compose build workframe-api workframe-supervisor
69
+ workframe_compose up -d --build --no-deps workframe-api workframe-supervisor
70
+
71
+ if workframe_compose config --services 2>/dev/null | grep -qx workframe-ui; then
72
+ workframe_compose up -d --no-deps workframe-ui || workframe_compose restart workframe-ui || true
73
+ elif workframe_compose config --services 2>/dev/null | grep -qx workframe; then
74
+ workframe_compose up -d --no-deps workframe || workframe_compose restart workframe || true
75
+ fi
76
+
77
+ echo "=== Workframe update complete ==="
@@ -1,8 +1,8 @@
1
- #!/bin/sh
2
- # Hermes sets HERMES_WRITE_SAFE_ROOT=/opt/data — user artifacts must resolve under it.
3
- # Bind host Files at /opt/data/workspace; keep /workspace as a symlink for agents and API.
4
- mkdir -p /opt/data/workspace
5
- if [ -L /workspace ] || [ ! -e /workspace ]; then
6
- rm -rf /workspace 2>/dev/null || true
7
- ln -sfn /opt/data/workspace /workspace
8
- fi
1
+ #!/bin/sh
2
+ # Hermes sets HERMES_WRITE_SAFE_ROOT=/opt/data — user artifacts must resolve under it.
3
+ # Bind host Files at /opt/data/workspace; keep /workspace as a symlink for agents and API.
4
+ mkdir -p /opt/data/workspace
5
+ if [ -L /workspace ] || [ ! -e /workspace ]; then
6
+ rm -rf /workspace 2>/dev/null || true
7
+ ln -sfn /opt/data/workspace /workspace
8
+ fi
@@ -1,37 +1,37 @@
1
- #!/usr/bin/env bash
2
- # Shared docker compose invocation for in-container apply (docker.sock on host).
3
- set -euo pipefail
4
-
5
- workframe_compose_prepare() {
6
- compose_cd=""
7
- compose_files=()
8
-
9
- # Host-bindings overlay: docker.sock apply from supervisor uses WORKFRAME_HOST_* paths.
10
- if [[ -n "${WORKFRAME_HOST_COMPOSE_DIR:-}" && -n "${WORKFRAME_COMPOSE_DIR:-}" \
11
- && -f "${WORKFRAME_COMPOSE_DIR}/docker-compose.yml" \
12
- && -f "${WORKFRAME_COMPOSE_DIR}/docker-compose.host-bindings.yml" ]]; then
13
- compose_cd="${WORKFRAME_COMPOSE_DIR}"
14
- compose_files=(-f docker-compose.yml -f docker-compose.host-bindings.yml)
15
- return 0
16
- fi
17
-
18
- # ponytail: docker Desktop resolves WORKFRAME_HOST_* via socket even when path is not visible in this container.
19
- if [[ -n "${WORKFRAME_HOST_COMPOSE_DIR:-}" ]]; then
20
- compose_cd="${WORKFRAME_HOST_COMPOSE_DIR}"
21
- compose_files=(-f docker-compose.yml)
22
- return 0
23
- fi
24
-
25
- compose_cd="${WORKFRAME_COMPOSE_DIR:-${WORKFRAME_PROJECT_ROOT:-.}}"
26
- compose_files=(-f docker-compose.yml)
27
- }
28
-
29
- workframe_compose() {
30
- workframe_compose_prepare
31
- cd "$compose_cd"
32
- if [[ ! -f docker-compose.yml ]]; then
33
- echo "docker-compose.yml not found in $compose_cd" >&2
34
- exit 1
35
- fi
36
- docker compose "${compose_files[@]}" "$@"
37
- }
1
+ #!/usr/bin/env bash
2
+ # Shared docker compose invocation for in-container apply (docker.sock on host).
3
+ set -euo pipefail
4
+
5
+ workframe_compose_prepare() {
6
+ compose_cd=""
7
+ compose_files=()
8
+
9
+ # Host-bindings overlay: docker.sock apply from supervisor uses WORKFRAME_HOST_* paths.
10
+ if [[ -n "${WORKFRAME_HOST_COMPOSE_DIR:-}" && -n "${WORKFRAME_COMPOSE_DIR:-}" \
11
+ && -f "${WORKFRAME_COMPOSE_DIR}/docker-compose.yml" \
12
+ && -f "${WORKFRAME_COMPOSE_DIR}/docker-compose.host-bindings.yml" ]]; then
13
+ compose_cd="${WORKFRAME_COMPOSE_DIR}"
14
+ compose_files=(-f docker-compose.yml -f docker-compose.host-bindings.yml)
15
+ return 0
16
+ fi
17
+
18
+ # ponytail: docker Desktop resolves WORKFRAME_HOST_* via socket even when path is not visible in this container.
19
+ if [[ -n "${WORKFRAME_HOST_COMPOSE_DIR:-}" ]]; then
20
+ compose_cd="${WORKFRAME_HOST_COMPOSE_DIR}"
21
+ compose_files=(-f docker-compose.yml)
22
+ return 0
23
+ fi
24
+
25
+ compose_cd="${WORKFRAME_COMPOSE_DIR:-${WORKFRAME_PROJECT_ROOT:-.}}"
26
+ compose_files=(-f docker-compose.yml)
27
+ }
28
+
29
+ workframe_compose() {
30
+ workframe_compose_prepare
31
+ cd "$compose_cd"
32
+ if [[ ! -f docker-compose.yml ]]; then
33
+ echo "docker-compose.yml not found in $compose_cd" >&2
34
+ exit 1
35
+ fi
36
+ docker compose "${compose_files[@]}" "$@"
37
+ }
@@ -1,35 +1,35 @@
1
- #!/usr/bin/env bash
2
- # Fix ZK_AUTH_ENCRYPTION_KEY when it was generated as hex instead of base64.
3
- set -euo pipefail
4
- ENV_FILE="${1:-/opt/workframe/MyBusiness/.env}"
5
- FORCE="${2:-}"
6
- python3 - "$ENV_FILE" "$FORCE" <<'PY'
7
- import base64, os, re, sys
8
- from pathlib import Path
9
- env, force = Path(sys.argv[1]), sys.argv[2] == "--force"
10
- text = env.read_text(encoding="utf-8")
11
- m = re.search(r"^ZK_AUTH_ENCRYPTION_KEY=(.*)$", text, re.M)
12
- if not m:
13
- print("ZK_AUTH_ENCRYPTION_KEY missing"); sys.exit(1)
14
- val = m.group(1).strip()
15
- try:
16
- ok = len(base64.b64decode(val)) == 32
17
- except Exception:
18
- ok = False
19
- if ok:
20
- print("ZK_AUTH_ENCRYPTION_KEY already valid"); sys.exit(0)
21
-
22
- zk_db = Path(os.environ.get("WORKFRAME_API_DATA_DIR", "/app/data")) / "zk_auth.db"
23
- if zk_db.is_file() and not force:
24
- import sqlite3
25
- n = sqlite3.connect(str(zk_db)).execute("SELECT COUNT(*) FROM identities").fetchone()[0]
26
- if n > 0:
27
- print(f"REFUSING: {n} encrypted identities present. Regenerating the KEK will lock "
28
- f"out every existing user. Re-run with --force to proceed.", file=sys.stderr)
29
- sys.exit(1)
30
-
31
- new_key = base64.b64encode(os.urandom(32)).decode()
32
- text = re.sub(r"^ZK_AUTH_ENCRYPTION_KEY=.*$", f"ZK_AUTH_ENCRYPTION_KEY={new_key}", text, flags=re.M)
33
- env.write_text(text, encoding="utf-8")
34
- print("ZK_AUTH_ENCRYPTION_KEY regenerated (was invalid base64)")
35
- PY
1
+ #!/usr/bin/env bash
2
+ # Fix ZK_AUTH_ENCRYPTION_KEY when it was generated as hex instead of base64.
3
+ set -euo pipefail
4
+ ENV_FILE="${1:-/opt/workframe/MyBusiness/.env}"
5
+ FORCE="${2:-}"
6
+ python3 - "$ENV_FILE" "$FORCE" <<'PY'
7
+ import base64, os, re, sys
8
+ from pathlib import Path
9
+ env, force = Path(sys.argv[1]), sys.argv[2] == "--force"
10
+ text = env.read_text(encoding="utf-8")
11
+ m = re.search(r"^ZK_AUTH_ENCRYPTION_KEY=(.*)$", text, re.M)
12
+ if not m:
13
+ print("ZK_AUTH_ENCRYPTION_KEY missing"); sys.exit(1)
14
+ val = m.group(1).strip()
15
+ try:
16
+ ok = len(base64.b64decode(val)) == 32
17
+ except Exception:
18
+ ok = False
19
+ if ok:
20
+ print("ZK_AUTH_ENCRYPTION_KEY already valid"); sys.exit(0)
21
+
22
+ zk_db = Path(os.environ.get("WORKFRAME_API_DATA_DIR", "/app/data")) / "zk_auth.db"
23
+ if zk_db.is_file() and not force:
24
+ import sqlite3
25
+ n = sqlite3.connect(str(zk_db)).execute("SELECT COUNT(*) FROM identities").fetchone()[0]
26
+ if n > 0:
27
+ print(f"REFUSING: {n} encrypted identities present. Regenerating the KEK will lock "
28
+ f"out every existing user. Re-run with --force to proceed.", file=sys.stderr)
29
+ sys.exit(1)
30
+
31
+ new_key = base64.b64encode(os.urandom(32)).decode()
32
+ text = re.sub(r"^ZK_AUTH_ENCRYPTION_KEY=.*$", f"ZK_AUTH_ENCRYPTION_KEY={new_key}", text, flags=re.M)
33
+ env.write_text(text, encoding="utf-8")
34
+ print("ZK_AUTH_ENCRYPTION_KEY regenerated (was invalid base64)")
35
+ PY
@@ -1,12 +1,12 @@
1
- #!/usr/bin/env bash
2
- # Restart Hermes gateway container only — no image pull. Preserves runtime/Agents.
3
- set -euo pipefail
4
- SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
5
- # shellcheck source=compose-docker-host.sh
6
- source "$SCRIPT_DIR/compose-docker-host.sh"
7
-
8
- echo "=== Hermes gateway restart ==="
9
- workframe_compose_prepare
10
- echo "Compose dir: $compose_cd"
11
- workframe_compose up -d --force-recreate --no-deps gateway
12
- echo "=== Gateway restart complete ==="
1
+ #!/usr/bin/env bash
2
+ # Restart Hermes gateway container only — no image pull. Preserves runtime/Agents.
3
+ set -euo pipefail
4
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
5
+ # shellcheck source=compose-docker-host.sh
6
+ source "$SCRIPT_DIR/compose-docker-host.sh"
7
+
8
+ echo "=== Hermes gateway restart ==="
9
+ workframe_compose_prepare
10
+ echo "Compose dir: $compose_cd"
11
+ workframe_compose up -d --force-recreate --no-deps gateway
12
+ echo "=== Gateway restart complete ==="
@@ -1,50 +1,50 @@
1
- #!/usr/bin/env bash
2
- # Append production stack secrets to a Workframe .env (idempotent).
3
- # Usage: bash scripts/workframe/setup-stack-secrets.sh path/to/.env
4
- set -euo pipefail
5
-
6
- ENV_FILE="${1:-/workspace/.env}"
7
-
8
- append_if_missing() {
9
- local key="$1"
10
- local value="$2"
11
- local comment="${3:-}"
12
- if [[ -f "$ENV_FILE" ]] && grep -q "^${key}=" "$ENV_FILE"; then
13
- echo "${key} already exists in ${ENV_FILE}"
14
- return 0
15
- fi
16
- mkdir -p "$(dirname "$ENV_FILE")"
17
- {
18
- [[ -n "$comment" ]] && printf '\n# %s\n' "$comment"
19
- printf '%s=%s\n' "$key" "$value"
20
- } >>"$ENV_FILE"
21
- echo "${key} generated and appended to ${ENV_FILE}"
22
- }
23
-
24
- rand_hex() {
25
- openssl rand -hex 32 2>/dev/null || python3 - <<'PY'
26
- import secrets
27
- print(secrets.token_hex(32))
28
- PY
29
- }
30
-
31
- rand_b64() {
32
- python3 - <<'PY'
33
- import base64, os
34
- print(base64.b64encode(os.urandom(32)).decode())
35
- PY
36
- }
37
-
38
- rand_proxy() {
39
- python3 - <<'PY'
40
- import secrets
41
- print(secrets.token_urlsafe(32))
42
- PY
43
- }
44
-
45
- append_if_missing WORKFRAME_SUPERVISOR_TOKEN "${WORKFRAME_SUPERVISOR_TOKEN:-$(rand_hex)}" \
46
- "Workframe supervisor token. Keep this secret."
47
- append_if_missing WORKFRAME_PROXY_TOKEN "${WORKFRAME_PROXY_TOKEN:-$(rand_proxy)}" \
48
- "Internal LLM/action proxy secret — gateway + API must match."
49
- append_if_missing WORKFRAME_VAULT_KEK "${WORKFRAME_VAULT_KEK:-$(rand_b64)}" \
50
- "Credential vault KEK (32-byte base64). Required for public_multi_user."
1
+ #!/usr/bin/env bash
2
+ # Append production stack secrets to a Workframe .env (idempotent).
3
+ # Usage: bash scripts/workframe/setup-stack-secrets.sh path/to/.env
4
+ set -euo pipefail
5
+
6
+ ENV_FILE="${1:-/workspace/.env}"
7
+
8
+ append_if_missing() {
9
+ local key="$1"
10
+ local value="$2"
11
+ local comment="${3:-}"
12
+ if [[ -f "$ENV_FILE" ]] && grep -q "^${key}=" "$ENV_FILE"; then
13
+ echo "${key} already exists in ${ENV_FILE}"
14
+ return 0
15
+ fi
16
+ mkdir -p "$(dirname "$ENV_FILE")"
17
+ {
18
+ [[ -n "$comment" ]] && printf '\n# %s\n' "$comment"
19
+ printf '%s=%s\n' "$key" "$value"
20
+ } >>"$ENV_FILE"
21
+ echo "${key} generated and appended to ${ENV_FILE}"
22
+ }
23
+
24
+ rand_hex() {
25
+ openssl rand -hex 32 2>/dev/null || python3 - <<'PY'
26
+ import secrets
27
+ print(secrets.token_hex(32))
28
+ PY
29
+ }
30
+
31
+ rand_b64() {
32
+ python3 - <<'PY'
33
+ import base64, os
34
+ print(base64.b64encode(os.urandom(32)).decode())
35
+ PY
36
+ }
37
+
38
+ rand_proxy() {
39
+ python3 - <<'PY'
40
+ import secrets
41
+ print(secrets.token_urlsafe(32))
42
+ PY
43
+ }
44
+
45
+ append_if_missing WORKFRAME_SUPERVISOR_TOKEN "${WORKFRAME_SUPERVISOR_TOKEN:-$(rand_hex)}" \
46
+ "Workframe supervisor token. Keep this secret."
47
+ append_if_missing WORKFRAME_PROXY_TOKEN "${WORKFRAME_PROXY_TOKEN:-$(rand_proxy)}" \
48
+ "Internal LLM/action proxy secret — gateway + API must match."
49
+ append_if_missing WORKFRAME_VAULT_KEK "${WORKFRAME_VAULT_KEK:-$(rand_b64)}" \
50
+ "Credential vault KEK (32-byte base64). Required for public_multi_user."
@@ -57,6 +57,17 @@ function removeIfExists(p) {
57
57
  if (fs.existsSync(p)) fs.rmSync(p, { recursive: true, force: true });
58
58
  }
59
59
 
60
+ /** Alpine sh breaks on CRLF (then\r). Normalize at pack time — Windows checkout is CRLF. */
61
+ function copyIntoPackage(src, dst) {
62
+ fs.mkdirSync(path.dirname(dst), { recursive: true });
63
+ if (dst.endsWith('.sh')) {
64
+ const text = fs.readFileSync(src, 'utf8').replace(/\r\n/g, '\n').replace(/\r/g, '\n');
65
+ fs.writeFileSync(dst, text, 'utf8');
66
+ } else {
67
+ fs.copyFileSync(src, dst);
68
+ }
69
+ }
70
+
60
71
  console.log(`Sync canonical BFF: ${CANONICAL_API} -> ${PKG_API}`);
61
72
  copyTree(CANONICAL_API, PKG_API);
62
73
 
@@ -107,11 +118,17 @@ for (const name of applyScripts) {
107
118
  const src = path.join(REPO_ROOT, 'scripts/workframe', name);
108
119
  const dst = path.join(PKG_ROOT, 'scripts', name);
109
120
  if (!fs.existsSync(src)) throw new Error(`Missing apply script: ${src}`);
110
- fs.mkdirSync(path.dirname(dst), { recursive: true });
111
- fs.copyFileSync(src, dst);
121
+ copyIntoPackage(src, dst);
112
122
  console.log(`Synced ${name} -> package/scripts/`);
113
123
  }
114
124
 
125
+ for (const sh of fs.readdirSync(path.join(PKG_ROOT, 'scripts')).filter((n) => n.endsWith('.sh'))) {
126
+ const p = path.join(PKG_ROOT, 'scripts', sh);
127
+ if (fs.readFileSync(p).includes(0x0d)) {
128
+ throw new Error(`CRLF remains in package script after sync: ${sh}`);
129
+ }
130
+ }
131
+
115
132
  const publicDeploySrc = path.join(REPO_ROOT, 'infra/compose/workframe/PUBLIC_DEPLOY.md');
116
133
  const publicDeployDst = path.join(PKG_ROOT, 'docs/PUBLIC_DEPLOY.md');
117
134
  if (fs.existsSync(publicDeploySrc)) {