@pleri/olam-cli 0.1.186 → 0.1.195

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 (189) hide show
  1. package/README.md +1 -1
  2. package/dist/ask/knowledge-pack-builder.d.ts.map +1 -1
  3. package/dist/ask/knowledge-pack-builder.js +5 -0
  4. package/dist/ask/knowledge-pack-builder.js.map +1 -1
  5. package/dist/ask/knowledge-pack.generated.d.ts.map +1 -1
  6. package/dist/ask/knowledge-pack.generated.js +442 -33
  7. package/dist/ask/knowledge-pack.generated.js.map +1 -1
  8. package/dist/commands/auth-status.js +2 -2
  9. package/dist/commands/auth-status.js.map +1 -1
  10. package/dist/commands/auth.js +1 -1
  11. package/dist/commands/auth.js.map +1 -1
  12. package/dist/commands/bootstrap.d.ts +4 -0
  13. package/dist/commands/bootstrap.d.ts.map +1 -1
  14. package/dist/commands/bootstrap.js +6 -9
  15. package/dist/commands/bootstrap.js.map +1 -1
  16. package/dist/commands/clean.js +1 -1
  17. package/dist/commands/clean.js.map +1 -1
  18. package/dist/commands/completion.d.ts.map +1 -1
  19. package/dist/commands/completion.js +1 -4
  20. package/dist/commands/completion.js.map +1 -1
  21. package/dist/commands/create.d.ts.map +1 -1
  22. package/dist/commands/create.js +10 -0
  23. package/dist/commands/create.js.map +1 -1
  24. package/dist/commands/crystallize.js +12 -14
  25. package/dist/commands/crystallize.js.map +1 -1
  26. package/dist/commands/destroy.d.ts +13 -1
  27. package/dist/commands/destroy.d.ts.map +1 -1
  28. package/dist/commands/destroy.js +52 -6
  29. package/dist/commands/destroy.js.map +1 -1
  30. package/dist/commands/dispatch.d.ts +9 -0
  31. package/dist/commands/dispatch.d.ts.map +1 -1
  32. package/dist/commands/dispatch.js +21 -2
  33. package/dist/commands/dispatch.js.map +1 -1
  34. package/dist/commands/doctor.d.ts +1 -1
  35. package/dist/commands/doctor.d.ts.map +1 -1
  36. package/dist/commands/doctor.js +29 -22
  37. package/dist/commands/doctor.js.map +1 -1
  38. package/dist/commands/enter.d.ts +3 -3
  39. package/dist/commands/enter.d.ts.map +1 -1
  40. package/dist/commands/enter.js +57 -44
  41. package/dist/commands/enter.js.map +1 -1
  42. package/dist/commands/flywheel/index.d.ts.map +1 -1
  43. package/dist/commands/flywheel/index.js +1 -1
  44. package/dist/commands/flywheel/index.js.map +1 -1
  45. package/dist/commands/host-cp.d.ts.map +1 -1
  46. package/dist/commands/host-cp.js +2 -1
  47. package/dist/commands/host-cp.js.map +1 -1
  48. package/dist/commands/implode.d.ts.map +1 -1
  49. package/dist/commands/implode.js +1 -1
  50. package/dist/commands/implode.js.map +1 -1
  51. package/dist/commands/init.d.ts +20 -0
  52. package/dist/commands/init.d.ts.map +1 -1
  53. package/dist/commands/init.js +102 -9
  54. package/dist/commands/init.js.map +1 -1
  55. package/dist/commands/install.js +2 -2
  56. package/dist/commands/install.js.map +1 -1
  57. package/dist/commands/kg-build.d.ts.map +1 -1
  58. package/dist/commands/kg-build.js +3 -0
  59. package/dist/commands/kg-build.js.map +1 -1
  60. package/dist/commands/kg-classify.d.ts +20 -0
  61. package/dist/commands/kg-classify.d.ts.map +1 -1
  62. package/dist/commands/kg-classify.js +59 -42
  63. package/dist/commands/kg-classify.js.map +1 -1
  64. package/dist/commands/kg-mirror.d.ts +40 -0
  65. package/dist/commands/kg-mirror.d.ts.map +1 -0
  66. package/dist/commands/kg-mirror.js +228 -0
  67. package/dist/commands/kg-mirror.js.map +1 -0
  68. package/dist/commands/mcp/index.js +1 -1
  69. package/dist/commands/mcp/index.js.map +1 -1
  70. package/dist/commands/memory/index.d.ts.map +1 -1
  71. package/dist/commands/memory/index.js +1 -1
  72. package/dist/commands/memory/index.js.map +1 -1
  73. package/dist/commands/resume.d.ts.map +1 -1
  74. package/dist/commands/resume.js +1 -1
  75. package/dist/commands/resume.js.map +1 -1
  76. package/dist/commands/services-tls.d.ts +120 -0
  77. package/dist/commands/services-tls.d.ts.map +1 -0
  78. package/dist/commands/services-tls.js +434 -0
  79. package/dist/commands/services-tls.js.map +1 -0
  80. package/dist/commands/services.d.ts.map +1 -1
  81. package/dist/commands/services.js +40 -1
  82. package/dist/commands/services.js.map +1 -1
  83. package/dist/commands/setup-linux-gate.d.ts.map +1 -1
  84. package/dist/commands/setup-linux-gate.js +1 -3
  85. package/dist/commands/setup-linux-gate.js.map +1 -1
  86. package/dist/commands/setup-metrics.d.ts.map +1 -1
  87. package/dist/commands/setup-metrics.js +1 -2
  88. package/dist/commands/setup-metrics.js.map +1 -1
  89. package/dist/commands/setup-phase-5a-skill-source.d.ts +17 -1
  90. package/dist/commands/setup-phase-5a-skill-source.d.ts.map +1 -1
  91. package/dist/commands/setup-phase-5a-skill-source.js +69 -6
  92. package/dist/commands/setup-phase-5a-skill-source.js.map +1 -1
  93. package/dist/commands/setup.d.ts +26 -1
  94. package/dist/commands/setup.d.ts.map +1 -1
  95. package/dist/commands/setup.js +189 -47
  96. package/dist/commands/setup.js.map +1 -1
  97. package/dist/commands/skills-onboard.d.ts.map +1 -1
  98. package/dist/commands/skills-onboard.js +4 -1
  99. package/dist/commands/skills-onboard.js.map +1 -1
  100. package/dist/commands/skills-source.d.ts.map +1 -1
  101. package/dist/commands/skills-source.js +20 -4
  102. package/dist/commands/skills-source.js.map +1 -1
  103. package/dist/commands/status.d.ts.map +1 -1
  104. package/dist/commands/status.js +5 -1
  105. package/dist/commands/status.js.map +1 -1
  106. package/dist/commands/upgrade.d.ts.map +1 -1
  107. package/dist/commands/upgrade.js +1 -3
  108. package/dist/commands/upgrade.js.map +1 -1
  109. package/dist/commands/yolo.d.ts.map +1 -1
  110. package/dist/commands/yolo.js +1 -1
  111. package/dist/commands/yolo.js.map +1 -1
  112. package/dist/context.d.ts +4 -0
  113. package/dist/context.d.ts.map +1 -1
  114. package/dist/context.js +3 -2
  115. package/dist/context.js.map +1 -1
  116. package/dist/image-digests.json +8 -8
  117. package/dist/index.js +4409 -2375
  118. package/dist/index.js.map +1 -1
  119. package/dist/lib/auth-refresh-kubernetes.d.ts.map +1 -1
  120. package/dist/lib/auth-refresh-kubernetes.js +14 -5
  121. package/dist/lib/auth-refresh-kubernetes.js.map +1 -1
  122. package/dist/lib/bootstrap-kubernetes.d.ts +41 -0
  123. package/dist/lib/bootstrap-kubernetes.d.ts.map +1 -1
  124. package/dist/lib/bootstrap-kubernetes.js +289 -36
  125. package/dist/lib/bootstrap-kubernetes.js.map +1 -1
  126. package/dist/lib/cf-access-token.d.ts.map +1 -1
  127. package/dist/lib/cf-access-token.js +2 -3
  128. package/dist/lib/cf-access-token.js.map +1 -1
  129. package/dist/lib/health-probes.d.ts +14 -0
  130. package/dist/lib/health-probes.d.ts.map +1 -1
  131. package/dist/lib/health-probes.js +41 -3
  132. package/dist/lib/health-probes.js.map +1 -1
  133. package/dist/lib/help-groups.d.ts +36 -0
  134. package/dist/lib/help-groups.d.ts.map +1 -0
  135. package/dist/lib/help-groups.js +124 -0
  136. package/dist/lib/help-groups.js.map +1 -0
  137. package/dist/lib/k8s-bootstrap.d.ts +6 -0
  138. package/dist/lib/k8s-bootstrap.d.ts.map +1 -1
  139. package/dist/lib/k8s-bootstrap.js +15 -2
  140. package/dist/lib/k8s-bootstrap.js.map +1 -1
  141. package/dist/lib/k8s-secret-render.d.ts.map +1 -1
  142. package/dist/lib/k8s-secret-render.js +17 -10
  143. package/dist/lib/k8s-secret-render.js.map +1 -1
  144. package/dist/lib/memory-secret.d.ts +15 -2
  145. package/dist/lib/memory-secret.d.ts.map +1 -1
  146. package/dist/lib/memory-secret.js +25 -8
  147. package/dist/lib/memory-secret.js.map +1 -1
  148. package/dist/lib/upgrade-check.d.ts +60 -0
  149. package/dist/lib/upgrade-check.d.ts.map +1 -0
  150. package/dist/lib/upgrade-check.js +169 -0
  151. package/dist/lib/upgrade-check.js.map +1 -0
  152. package/dist/lib/upgrade-kubernetes.d.ts +17 -0
  153. package/dist/lib/upgrade-kubernetes.d.ts.map +1 -1
  154. package/dist/lib/upgrade-kubernetes.js +125 -1
  155. package/dist/lib/upgrade-kubernetes.js.map +1 -1
  156. package/dist/mcp-server.js +2687 -2818
  157. package/hermes-bundle/version.json +1 -1
  158. package/host-cp/k8s/manifests/30-configmap.yaml +8 -1
  159. package/host-cp/k8s/manifests/50-deployment.yaml +1 -1
  160. package/host-cp/k8s/manifests/60-service.yaml +12 -4
  161. package/host-cp/k8s/manifests/70-ingressroute.yaml +58 -0
  162. package/host-cp/k8s/manifests/auth-service/50-deployment.yaml +1 -1
  163. package/host-cp/k8s/manifests/chunks-electric/10-serviceaccount.yaml +8 -0
  164. package/host-cp/k8s/manifests/chunks-electric/20-rbac.yaml +27 -0
  165. package/host-cp/k8s/manifests/chunks-electric/30-configmap.yaml +23 -0
  166. package/host-cp/k8s/manifests/chunks-electric/45-pvc.yaml +19 -0
  167. package/host-cp/k8s/manifests/chunks-electric/50-deployment.yaml +84 -0
  168. package/host-cp/k8s/manifests/chunks-electric/60-service.yaml +17 -0
  169. package/host-cp/k8s/manifests/chunks-postgres/10-serviceaccount.yaml +8 -0
  170. package/host-cp/k8s/manifests/chunks-postgres/20-rbac.yaml +29 -0
  171. package/host-cp/k8s/manifests/chunks-postgres/30-configmap.yaml +185 -0
  172. package/host-cp/k8s/manifests/chunks-postgres/45-pvc.yaml +24 -0
  173. package/host-cp/k8s/manifests/chunks-postgres/50-deployment.yaml +101 -0
  174. package/host-cp/k8s/manifests/chunks-postgres/60-service.yaml +24 -0
  175. package/host-cp/k8s/manifests/kg-service/50-deployment.yaml +1 -1
  176. package/host-cp/k8s/manifests/mcp-auth-service/50-deployment.yaml +1 -1
  177. package/host-cp/k8s/manifests/memory-service/50-deployment.yaml +1 -1
  178. package/host-cp/k8s/manifests/plan-chat-service/10-serviceaccount.yaml +8 -0
  179. package/host-cp/k8s/manifests/plan-chat-service/20-rbac.yaml +29 -0
  180. package/host-cp/k8s/manifests/plan-chat-service/30-configmap.yaml +36 -0
  181. package/host-cp/k8s/manifests/plan-chat-service/45-pvc.yaml +24 -0
  182. package/host-cp/k8s/manifests/plan-chat-service/50-deployment.yaml +135 -0
  183. package/host-cp/k8s/manifests/plan-chat-service/60-service.yaml +17 -0
  184. package/host-cp/src/plan-chat-secret.mjs +16 -1
  185. package/host-cp/src/plan-chat-service.mjs +709 -11
  186. package/host-cp/src/planning-sessions.mjs +252 -0
  187. package/host-cp/src/pr-cache.mjs +11 -2
  188. package/host-cp/src/server.mjs +128 -22
  189. package/package.json +2 -1
@@ -1,4 +1,4 @@
1
1
  {
2
- "bundledAt": "2026-05-27T14:52:44.062Z",
2
+ "bundledAt": "2026-05-28T12:44:06.696Z",
3
3
  "kgFirstSha": "29a9ccce1b115d049e375c4a90eb5cf7c123e610e2d0590270a4db2cdbc64a28"
4
4
  }
@@ -13,7 +13,14 @@ data:
13
13
  # Auth service URL. Default targets host.docker.internal for Colima/Docker
14
14
  # Desktop k3d setups. Override when auth-service runs elsewhere (e.g. via
15
15
  # an ExternalName Service pointing at the host gateway).
16
- OLAM_AUTH_SERVICE_URL: "http://host.docker.internal:8000"
16
+ #
17
+ # Port :9999 matches the published port in AuthContainerController.start()
18
+ # (packages/core/src/auth/container.ts) — the value was historically :8000,
19
+ # which never matched any running auth-service version and surfaced as
20
+ # {"error":"auth_service_unavailable","message":"fetch failed"}
21
+ # on /api/auth/* calls. Verified during the K3d-HTTPS PR live bring-up;
22
+ # see docs/runbooks/k3d-https-setup.md.
23
+ OLAM_AUTH_SERVICE_URL: "http://host.docker.internal:9999"
17
24
  # Docker socket proxy — ClusterIP Service DNS inside the namespace.
18
25
  DOCKER_HOST: "tcp://docker-socket-proxy:2375"
19
26
  # Host-cp server port — must match the Service targetPort in 60-service.yaml.
@@ -118,7 +118,7 @@ spec:
118
118
  # k3d), started by `olam upgrade` Step 0.7 — not inside this Pod.
119
119
  containers:
120
120
  - name: olam-host-cp
121
- image: ghcr.io/pleri/olam-host-cp@sha256:c9a2df3d6fc1d4646204968007123d04d817b80aa4ab83a8bf23168fa943822a
121
+ image: ghcr.io/pleri/olam-host-cp@sha256:42fb12f23d51c229288e0c0fa93df8028784136ce75245e582e4fffbc5867798
122
122
  imagePullPolicy: IfNotPresent
123
123
  securityContext:
124
124
  runAsNonRoot: true
@@ -1,8 +1,16 @@
1
1
  # ClusterIP Service for olam-host-cp.
2
- # Operator surfaces the SPA externally via:
3
- # kubectl port-forward -n olam svc/olam-host-cp 19000:19000
4
- # This keeps the "127.0.0.1-only" single-user-per-host invariant
5
- # (NodePort would bind on all interfaces; port-forward keeps it local).
2
+ #
3
+ # Two ways to reach the SPA externally:
4
+ # 1. (preferred) Traefik IngressRoute at https://olam.local:<traefik-https-port>
5
+ # Terminates TLS at the cluster edge, unlocks HTTP/2 multiplexing for
6
+ # Electric SQL long-polls. See 70-ingressroute.yaml + 65-tls-secret-template.yaml.tmpl.
7
+ # The pod itself stays HTTP-only — Traefik handles TLS at the edge.
8
+ # 2. (fallback) kubectl port-forward -n olam svc/olam-host-cp 19000:19000
9
+ # Plain HTTP/1.1; hits browser's 6-conn-per-origin cap under Electric load.
10
+ #
11
+ # ClusterIP (not NodePort) preserves the "127.0.0.1-only" single-user-per-host
12
+ # invariant — exposure is via Traefik's LoadBalancer or port-forward, not by
13
+ # binding pod ports on every node interface.
6
14
  apiVersion: v1
7
15
  kind: Service
8
16
  metadata:
@@ -0,0 +1,58 @@
1
+ # Traefik IngressRoute terminating TLS at the cluster edge for olam-host-cp.
2
+ #
3
+ # Topology:
4
+ # Browser --HTTPS/h2--> Traefik :443 (LoadBalancer / k3d NodePort)
5
+ # |
6
+ # | (TLS terminated; cleartext inside cluster)
7
+ # v
8
+ # olam-host-cp:19000 (ClusterIP, HTTP/1.1 internal)
9
+ # |
10
+ # v
11
+ # plan-chat-service:3200 (and other peripherals)
12
+ #
13
+ # Why terminate TLS at Traefik (NOT at host-cp): host-cp is a Node/Hono
14
+ # server tuned for cleartext HTTP. Pushing TLS into the pod would force a
15
+ # second cert-distribution mechanism (Secret → volumeMount → server.mjs
16
+ # reload) and double the operational surface. Traefik already owns cert
17
+ # lifecycle in production (cert-manager + Let's Encrypt), so dev-mode
18
+ # mkcert at the same boundary keeps prod parity tight.
19
+ #
20
+ # Why HTTP/2 matters: TanStack DB / Electric SQL opens N long-poll
21
+ # connections per browser tab (one per shape subscription). Without h2
22
+ # multiplexing they queue against the browser's 6-connection-per-origin
23
+ # cap, leading to the "25-second pending requests" symptom Electric users
24
+ # hit on HTTP/1.1. Traefik 2.x advertises h2 over TLS via ALPN by default;
25
+ # no extra config needed.
26
+ #
27
+ # Why Host(olam.local) instead of a wildcard: the cert is minted for that
28
+ # exact SAN. Traefik routes based on SNI, so the host-rule must match the
29
+ # cert subject or the TLS handshake completes but the route 404s.
30
+ #
31
+ # Operator MUST add `127.0.0.1 olam.local` to /etc/hosts before this works.
32
+ # `olam services tls-install` prints the line + sudo command — it does NOT
33
+ # auto-edit (touching /etc/hosts behind the operator's back is a foot-gun).
34
+ apiVersion: traefik.io/v1alpha1
35
+ kind: IngressRoute
36
+ metadata:
37
+ # Distinct name avoids collision with packages/peripheral-services'
38
+ # `olam-host-cp` IngressRoute (the legacy `web`-entrypoint + path-based
39
+ # router that 50+ SPA fetch sites still depend on). The `-https` variant
40
+ # adds a SECOND ingress that matches Host(olam.local) on `websecure` and
41
+ # terminates TLS via the operator-minted Secret. Both coexist; the legacy
42
+ # one keeps `http://<lb>/api/...` working, this one unlocks HTTP/2.
43
+ name: olam-host-cp-https
44
+ namespace: olam
45
+ labels:
46
+ app: olam-host-cp
47
+ olam.io/component: host-stack
48
+ spec:
49
+ entryPoints:
50
+ - websecure
51
+ routes:
52
+ - match: Host(`olam.local`)
53
+ kind: Rule
54
+ services:
55
+ - name: olam-host-cp
56
+ port: 19000
57
+ tls:
58
+ secretName: olam-host-cp-tls
@@ -70,7 +70,7 @@ spec:
70
70
  mountPath: /data
71
71
  containers:
72
72
  - name: olam-auth-service
73
- image: ghcr.io/pleri/olam-auth@sha256:90bb6b0025b10ac92af4193160bdef881c4f7945346b42803785885b75fe857b
73
+ image: ghcr.io/pleri/olam-auth@sha256:e982aa9812c9c57768987d8fc0a22178c84811bf59a1470eb7a5aa58a73f11a5
74
74
  imagePullPolicy: IfNotPresent
75
75
  securityContext:
76
76
  runAsNonRoot: true
@@ -0,0 +1,8 @@
1
+ apiVersion: v1
2
+ kind: ServiceAccount
3
+ metadata:
4
+ name: olam-chunks-electric
5
+ namespace: olam
6
+ labels:
7
+ app: olam-chunks-electric
8
+ olam.io/component: substrate
@@ -0,0 +1,27 @@
1
+ # Electric does not call the Kubernetes API. Empty Role kept for layout parity.
2
+ apiVersion: rbac.authorization.k8s.io/v1
3
+ kind: Role
4
+ metadata:
5
+ name: olam-chunks-electric
6
+ namespace: olam
7
+ labels:
8
+ app: olam-chunks-electric
9
+ olam.io/component: substrate
10
+ rules: []
11
+ ---
12
+ apiVersion: rbac.authorization.k8s.io/v1
13
+ kind: RoleBinding
14
+ metadata:
15
+ name: olam-chunks-electric
16
+ namespace: olam
17
+ labels:
18
+ app: olam-chunks-electric
19
+ olam.io/component: substrate
20
+ roleRef:
21
+ apiGroup: rbac.authorization.k8s.io
22
+ kind: Role
23
+ name: olam-chunks-electric
24
+ subjects:
25
+ - kind: ServiceAccount
26
+ name: olam-chunks-electric
27
+ namespace: olam
@@ -0,0 +1,23 @@
1
+ # ConfigMap for olam-chunks-electric.
2
+ #
3
+ # ELECTRIC_INSECURE=true disables Electric's API-secret-token gate. Acceptable
4
+ # in a single-operator local-dev k3d cluster (the Service is ClusterIP — no
5
+ # external reachability). For multi-tenant deploys, set ELECTRIC_INSECURE=false
6
+ # and provision ELECTRIC_SECRET via a Secret instead.
7
+ #
8
+ # DATABASE_URL is composed at runtime in the Deployment via env: composition
9
+ # referencing the chunks-postgres Secret (POSTGRES_PASSWORD). It is NOT
10
+ # stored here.
11
+ apiVersion: v1
12
+ kind: ConfigMap
13
+ metadata:
14
+ name: olam-chunks-electric-env
15
+ namespace: olam
16
+ labels:
17
+ app: olam-chunks-electric
18
+ olam.io/component: substrate
19
+ data:
20
+ ELECTRIC_INSECURE: "true"
21
+ ELECTRIC_PORT: "3000"
22
+ ELECTRIC_HTTP_API_PORT: "3000"
23
+ ELECTRIC_LOG_LEVEL: "info"
@@ -0,0 +1,19 @@
1
+ # Electric's HTTP server state lives in-memory + the replication slot lives on
2
+ # Postgres. No persistent state required, but a small PVC is kept for parity
3
+ # with other peripherals — Electric writes its persisted-shape index to
4
+ # /app/persistent by default; PVC backs that path.
5
+ apiVersion: v1
6
+ kind: PersistentVolumeClaim
7
+ metadata:
8
+ name: olam-chunks-electric-data
9
+ namespace: olam
10
+ labels:
11
+ app: olam-chunks-electric
12
+ olam.io/component: substrate
13
+ spec:
14
+ accessModes:
15
+ - ReadWriteOnce
16
+ storageClassName: local-path
17
+ resources:
18
+ requests:
19
+ storage: 1Gi
@@ -0,0 +1,84 @@
1
+ # Deployment for olam-chunks-electric.
2
+ #
3
+ # Electric SQL — Postgres logical-replication → HTTP long-poll shape proxy.
4
+ # Single replica (replication slot is single-writer).
5
+ #
6
+ # Image: electricsql/electric:1.6.8 — sha256-pinned per T4 threat model.
7
+ # Resolves to the same digest as :latest at 2026-05-27; refresh when the
8
+ # upstream cuts a new release that closes a security advisory.
9
+ apiVersion: apps/v1
10
+ kind: Deployment
11
+ metadata:
12
+ name: olam-chunks-electric
13
+ namespace: olam
14
+ labels:
15
+ app: olam-chunks-electric
16
+ olam.io/component: substrate
17
+ spec:
18
+ replicas: 1
19
+ strategy:
20
+ # Recreate (NOT RollingUpdate) — Electric holds a postgres replication
21
+ # slot; two pods running at once would fight for the same slot and one
22
+ # would crashloop.
23
+ type: Recreate
24
+ selector:
25
+ matchLabels:
26
+ app: olam-chunks-electric
27
+ template:
28
+ metadata:
29
+ labels:
30
+ app: olam-chunks-electric
31
+ spec:
32
+ enableServiceLinks: false
33
+ serviceAccountName: olam-chunks-electric
34
+ containers:
35
+ - name: electric
36
+ image: electricsql/electric:1.6.8@sha256:a716f2affde44d5b991bdd1492876d9d6bddbcae5c98411327614575cd8f9eec
37
+ imagePullPolicy: IfNotPresent
38
+ ports:
39
+ - name: http
40
+ containerPort: 3000
41
+ protocol: TCP
42
+ envFrom:
43
+ - configMapRef:
44
+ name: olam-chunks-electric-env
45
+ env:
46
+ # DATABASE_URL composition. POSTGRES_PASSWORD is sourced from the
47
+ # chunks-postgres Secret (rendered by k8s-secret-render.ts).
48
+ - name: POSTGRES_PASSWORD
49
+ valueFrom:
50
+ secretKeyRef:
51
+ name: olam-chunks-postgres-secret
52
+ key: POSTGRES_PASSWORD
53
+ - name: DATABASE_URL
54
+ value: "postgres://postgres:$(POSTGRES_PASSWORD)@olam-chunks-postgres.olam.svc.cluster.local:5432/chunks?sslmode=disable"
55
+ volumeMounts:
56
+ - name: persistent
57
+ mountPath: /app/persistent
58
+ readinessProbe:
59
+ httpGet:
60
+ path: /v1/health
61
+ port: 3000
62
+ initialDelaySeconds: 10
63
+ periodSeconds: 5
64
+ timeoutSeconds: 3
65
+ failureThreshold: 12
66
+ livenessProbe:
67
+ httpGet:
68
+ path: /v1/health
69
+ port: 3000
70
+ initialDelaySeconds: 60
71
+ periodSeconds: 20
72
+ timeoutSeconds: 5
73
+ failureThreshold: 3
74
+ resources:
75
+ requests:
76
+ cpu: "100m"
77
+ memory: "256Mi"
78
+ limits:
79
+ cpu: "1000m"
80
+ memory: "1Gi"
81
+ volumes:
82
+ - name: persistent
83
+ persistentVolumeClaim:
84
+ claimName: olam-chunks-electric-data
@@ -0,0 +1,17 @@
1
+ apiVersion: v1
2
+ kind: Service
3
+ metadata:
4
+ name: olam-chunks-electric
5
+ namespace: olam
6
+ labels:
7
+ app: olam-chunks-electric
8
+ olam.io/component: substrate
9
+ spec:
10
+ type: ClusterIP
11
+ selector:
12
+ app: olam-chunks-electric
13
+ ports:
14
+ - name: http
15
+ port: 3000
16
+ targetPort: 3000
17
+ protocol: TCP
@@ -0,0 +1,8 @@
1
+ apiVersion: v1
2
+ kind: ServiceAccount
3
+ metadata:
4
+ name: olam-chunks-postgres
5
+ namespace: olam
6
+ labels:
7
+ app: olam-chunks-postgres
8
+ olam.io/component: substrate
@@ -0,0 +1,29 @@
1
+ # Minimal-privilege RBAC for chunks-postgres. The pod does not call the
2
+ # Kubernetes API; this Role exists to make the per-service apply order
3
+ # (10/20/30/45/50/60) uniform across peripherals + substrate.
4
+ apiVersion: rbac.authorization.k8s.io/v1
5
+ kind: Role
6
+ metadata:
7
+ name: olam-chunks-postgres
8
+ namespace: olam
9
+ labels:
10
+ app: olam-chunks-postgres
11
+ olam.io/component: substrate
12
+ rules: []
13
+ ---
14
+ apiVersion: rbac.authorization.k8s.io/v1
15
+ kind: RoleBinding
16
+ metadata:
17
+ name: olam-chunks-postgres
18
+ namespace: olam
19
+ labels:
20
+ app: olam-chunks-postgres
21
+ olam.io/component: substrate
22
+ roleRef:
23
+ apiGroup: rbac.authorization.k8s.io
24
+ kind: Role
25
+ name: olam-chunks-postgres
26
+ subjects:
27
+ - kind: ServiceAccount
28
+ name: olam-chunks-postgres
29
+ namespace: olam
@@ -0,0 +1,185 @@
1
+ # ConfigMap for olam-chunks-postgres.
2
+ #
3
+ # Two ConfigMaps in one file:
4
+ #
5
+ # 1. olam-chunks-postgres-env — non-secret env vars (POSTGRES_USER, POSTGRES_DB).
6
+ # POSTGRES_PASSWORD lives in the Secret rendered by
7
+ # packages/cli/src/lib/k8s-secret-render.ts.
8
+ #
9
+ # 2. olam-chunks-postgres-initdb-sql — the chunks schema. Mounted at
10
+ # /docker-entrypoint-initdb.d/01-chunks.sql so
11
+ # the postgres image's entrypoint auto-applies it
12
+ # on FIRST init (empty data dir). Subsequent
13
+ # restarts skip the directory by design.
14
+ #
15
+ # Source-of-truth: packages/chunks/src/schema.ts
16
+ # (SCHEMA_SQL export). The CI gate
17
+ # `audit:chunks-schema-parity` (follow-up) will
18
+ # fail when this ConfigMap drifts from
19
+ # SCHEMA_VERSION-tagged schema.ts.
20
+ apiVersion: v1
21
+ kind: ConfigMap
22
+ metadata:
23
+ name: olam-chunks-postgres-env
24
+ namespace: olam
25
+ labels:
26
+ app: olam-chunks-postgres
27
+ olam.io/component: substrate
28
+ data:
29
+ POSTGRES_USER: "postgres"
30
+ POSTGRES_DB: "chunks"
31
+ # PGDATA must point at a subdirectory of the PVC mount, not its root —
32
+ # the PVC root may carry the local-path provisioner's lost+found dir,
33
+ # which postgres's initdb rejects ("data directory not empty").
34
+ PGDATA: "/var/lib/postgresql/data/pgdata"
35
+ ---
36
+ apiVersion: v1
37
+ kind: ConfigMap
38
+ metadata:
39
+ name: olam-chunks-postgres-initdb-sql
40
+ namespace: olam
41
+ labels:
42
+ app: olam-chunks-postgres
43
+ olam.io/component: substrate
44
+ data:
45
+ # MIRRORS packages/chunks/src/schema.ts SCHEMA_VERSION=2.
46
+ # Idempotent: CREATE TABLE IF NOT EXISTS / ADD COLUMN IF NOT EXISTS /
47
+ # DO blocks with EXCEPTION-WHEN-{undefined_object,duplicate_object}.
48
+ 01-chunks.sql: |
49
+ CREATE TABLE IF NOT EXISTS chunks (
50
+ world_id TEXT NOT NULL,
51
+ session_id TEXT NOT NULL,
52
+ message_id TEXT NOT NULL,
53
+ seq INTEGER NOT NULL,
54
+ actor_id TEXT NOT NULL,
55
+ actor_type TEXT NOT NULL CHECK (actor_type IN ('agent', 'operator', 'codex', 'system')),
56
+ role TEXT NOT NULL CHECK (role IN ('user', 'assistant', 'tool', 'system')),
57
+ chunk TEXT NOT NULL,
58
+ chunk_type TEXT NOT NULL DEFAULT 'text' CHECK (chunk_type IN ('text', 'tool_use', 'goal_mode_assumption', 'dispatch_overflow')),
59
+ created_at TIMESTAMPTZ NOT NULL DEFAULT clock_timestamp(),
60
+ PRIMARY KEY (message_id, seq)
61
+ );
62
+
63
+ ALTER TABLE chunks ADD COLUMN IF NOT EXISTS chunk_type TEXT NOT NULL DEFAULT 'text';
64
+
65
+ DO $$ BEGIN
66
+ ALTER TABLE chunks DROP CONSTRAINT IF EXISTS chunks_chunk_type_check;
67
+ EXCEPTION WHEN undefined_object THEN NULL;
68
+ END $$;
69
+
70
+ DO $$ BEGIN
71
+ ALTER TABLE chunks ADD CONSTRAINT chunks_chunk_type_check
72
+ CHECK (chunk_type IN ('text', 'tool_use', 'goal_mode_assumption', 'dispatch_overflow'));
73
+ EXCEPTION WHEN duplicate_object THEN NULL;
74
+ END $$;
75
+
76
+ CREATE INDEX IF NOT EXISTS chunks_world_session_seq
77
+ ON chunks (world_id, session_id, seq);
78
+
79
+ CREATE INDEX IF NOT EXISTS chunks_world_session_created
80
+ ON chunks (world_id, session_id, created_at);
81
+
82
+ CREATE INDEX IF NOT EXISTS idx_chunks_planning
83
+ ON chunks (session_id, seq)
84
+ WHERE world_id = '_planning';
85
+
86
+ CREATE TABLE IF NOT EXISTS planning_sessions (
87
+ session_id TEXT PRIMARY KEY,
88
+ actor_id TEXT NOT NULL,
89
+ summary TEXT,
90
+ crystallize_status TEXT NOT NULL DEFAULT 'open'
91
+ CHECK (crystallize_status IN ('open', 'in_progress', 'crystallized', 'failed', 'abandoned')),
92
+ crystallized_world_id TEXT,
93
+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
94
+ updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
95
+ );
96
+
97
+ CREATE INDEX IF NOT EXISTS idx_planning_sessions_created_at
98
+ ON planning_sessions (created_at DESC);
99
+
100
+ ALTER TABLE planning_sessions ADD COLUMN IF NOT EXISTS session_source TEXT;
101
+
102
+ CREATE OR REPLACE FUNCTION chunks_append_only_trigger()
103
+ RETURNS trigger AS $body$
104
+ BEGIN
105
+ RAISE EXCEPTION 'chunks is append-only; % forbidden', TG_OP;
106
+ END;
107
+ $body$ LANGUAGE plpgsql;
108
+
109
+ DROP TRIGGER IF EXISTS chunks_no_update ON chunks;
110
+ CREATE TRIGGER chunks_no_update
111
+ BEFORE UPDATE ON chunks
112
+ FOR EACH ROW EXECUTE FUNCTION chunks_append_only_trigger();
113
+
114
+ DROP TRIGGER IF EXISTS chunks_no_delete ON chunks;
115
+ CREATE TRIGGER chunks_no_delete
116
+ BEFORE DELETE ON chunks
117
+ FOR EACH ROW EXECUTE FUNCTION chunks_append_only_trigger();
118
+
119
+ CREATE TABLE IF NOT EXISTS message_usage (
120
+ world_id TEXT NOT NULL,
121
+ session_id TEXT NOT NULL,
122
+ message_id TEXT NOT NULL,
123
+ actor_id TEXT NOT NULL,
124
+ model TEXT NOT NULL,
125
+ input_tokens INTEGER NOT NULL DEFAULT 0,
126
+ output_tokens INTEGER NOT NULL DEFAULT 0,
127
+ cache_read_tokens INTEGER NOT NULL DEFAULT 0,
128
+ cache_create_tokens INTEGER NOT NULL DEFAULT 0,
129
+ created_at TIMESTAMPTZ NOT NULL DEFAULT clock_timestamp(),
130
+ PRIMARY KEY (message_id, actor_id)
131
+ );
132
+
133
+ CREATE INDEX IF NOT EXISTS message_usage_session_created
134
+ ON message_usage (session_id, created_at);
135
+
136
+ CREATE OR REPLACE FUNCTION message_usage_append_only_trigger()
137
+ RETURNS trigger AS $body$
138
+ BEGIN
139
+ RAISE EXCEPTION 'message_usage is append-only; % forbidden', TG_OP;
140
+ END;
141
+ $body$ LANGUAGE plpgsql;
142
+
143
+ DROP TRIGGER IF EXISTS message_usage_no_update ON message_usage;
144
+ CREATE TRIGGER message_usage_no_update
145
+ BEFORE UPDATE ON message_usage
146
+ FOR EACH ROW EXECUTE FUNCTION message_usage_append_only_trigger();
147
+
148
+ DROP TRIGGER IF EXISTS message_usage_no_delete ON message_usage;
149
+ CREATE TRIGGER message_usage_no_delete
150
+ BEFORE DELETE ON message_usage
151
+ FOR EACH ROW EXECUTE FUNCTION message_usage_append_only_trigger();
152
+
153
+ CREATE TABLE IF NOT EXISTS planning_artifacts (
154
+ id TEXT PRIMARY KEY,
155
+ world_id TEXT NOT NULL,
156
+ session_id TEXT NOT NULL,
157
+ type TEXT NOT NULL CHECK (type IN ('commit_plan', 'component_scaffold', 'design_jam')),
158
+ title TEXT NOT NULL,
159
+ body JSONB NOT NULL,
160
+ status TEXT NOT NULL DEFAULT 'open'
161
+ CHECK (status IN ('open', 'crystallized', 'failed', 'archived')),
162
+ linear_issue_url TEXT,
163
+ crystallized_world_id TEXT,
164
+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
165
+ updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
166
+ );
167
+
168
+ CREATE INDEX IF NOT EXISTS idx_planning_artifacts_session
169
+ ON planning_artifacts (session_id, created_at);
170
+
171
+ CREATE INDEX IF NOT EXISTS idx_planning_artifacts_world
172
+ ON planning_artifacts (world_id, status);
173
+
174
+ CREATE OR REPLACE FUNCTION planning_artifacts_touch_updated_at()
175
+ RETURNS trigger AS $body$
176
+ BEGIN
177
+ NEW.updated_at = NOW();
178
+ RETURN NEW;
179
+ END;
180
+ $body$ LANGUAGE plpgsql;
181
+
182
+ DROP TRIGGER IF EXISTS planning_artifacts_touch ON planning_artifacts;
183
+ CREATE TRIGGER planning_artifacts_touch
184
+ BEFORE UPDATE ON planning_artifacts
185
+ FOR EACH ROW EXECUTE FUNCTION planning_artifacts_touch_updated_at();
@@ -0,0 +1,24 @@
1
+ # PVC for the chunks-postgres data directory.
2
+ #
3
+ # Sized 10Gi for local-dev. Chunks rows are small (~1KB each) so even a
4
+ # busy single-operator world rarely cracks 1Gi; the headroom is for the
5
+ # message_usage + planning_artifacts sidecar tables.
6
+ #
7
+ # accessModes: ReadWriteOnce — postgres is a StatefulSet with replicas=1.
8
+ # k3d's local-path provisioner only supports RWO; the in-cluster postgres
9
+ # pattern is single-writer by design (no operator-managed HA).
10
+ apiVersion: v1
11
+ kind: PersistentVolumeClaim
12
+ metadata:
13
+ name: olam-chunks-postgres-data
14
+ namespace: olam
15
+ labels:
16
+ app: olam-chunks-postgres
17
+ olam.io/component: substrate
18
+ spec:
19
+ accessModes:
20
+ - ReadWriteOnce
21
+ storageClassName: local-path
22
+ resources:
23
+ requests:
24
+ storage: 10Gi
@@ -0,0 +1,101 @@
1
+ # StatefulSet for olam-chunks-postgres.
2
+ #
3
+ # Why StatefulSet vs Deployment: even with replicas=1 the StatefulSet gives
4
+ # stable network identity (olam-chunks-postgres-0 inside the headless service)
5
+ # and ordered termination semantics — both useful when Electric's replication
6
+ # slot survives pod restarts.
7
+ #
8
+ # command override: postgres requires wal_level=logical for Electric SQL's
9
+ # logical-replication subscription. The image's default postgresql.conf
10
+ # ships wal_level=replica; the -c overrides on the entrypoint args take
11
+ # precedence. max_replication_slots / max_wal_senders need raising too —
12
+ # Electric holds one slot per database.
13
+ #
14
+ # securityContext: postgres image runs as uid 999 by default. fsGroup=999
15
+ # on the pod ensures the PVC mount is chowned to 999 so postgres can write
16
+ # its data dir.
17
+ apiVersion: apps/v1
18
+ kind: StatefulSet
19
+ metadata:
20
+ name: olam-chunks-postgres
21
+ namespace: olam
22
+ labels:
23
+ app: olam-chunks-postgres
24
+ olam.io/component: substrate
25
+ spec:
26
+ replicas: 1
27
+ serviceName: olam-chunks-postgres
28
+ selector:
29
+ matchLabels:
30
+ app: olam-chunks-postgres
31
+ template:
32
+ metadata:
33
+ labels:
34
+ app: olam-chunks-postgres
35
+ spec:
36
+ enableServiceLinks: false
37
+ serviceAccountName: olam-chunks-postgres
38
+ securityContext:
39
+ fsGroup: 999
40
+ containers:
41
+ - name: postgres
42
+ # postgres:16-alpine — sha256-pinned per T4 threat model.
43
+ image: postgres:16-alpine@sha256:16bc17c64a573ef34162af9298258d1aec548232985b33ed7b1eac33ba35c229
44
+ imagePullPolicy: IfNotPresent
45
+ args:
46
+ - postgres
47
+ - -c
48
+ - wal_level=logical
49
+ - -c
50
+ - max_replication_slots=10
51
+ - -c
52
+ - max_wal_senders=10
53
+ ports:
54
+ - name: postgres
55
+ containerPort: 5432
56
+ protocol: TCP
57
+ envFrom:
58
+ - configMapRef:
59
+ name: olam-chunks-postgres-env
60
+ - secretRef:
61
+ name: olam-chunks-postgres-secret
62
+ volumeMounts:
63
+ - name: data
64
+ mountPath: /var/lib/postgresql/data
65
+ - name: initdb
66
+ mountPath: /docker-entrypoint-initdb.d
67
+ readOnly: true
68
+ readinessProbe:
69
+ exec:
70
+ command:
71
+ - sh
72
+ - -c
73
+ - pg_isready -U postgres -d chunks -h 127.0.0.1
74
+ initialDelaySeconds: 5
75
+ periodSeconds: 5
76
+ timeoutSeconds: 3
77
+ failureThreshold: 12
78
+ livenessProbe:
79
+ exec:
80
+ command:
81
+ - sh
82
+ - -c
83
+ - pg_isready -U postgres -h 127.0.0.1
84
+ initialDelaySeconds: 30
85
+ periodSeconds: 20
86
+ timeoutSeconds: 5
87
+ failureThreshold: 3
88
+ resources:
89
+ requests:
90
+ cpu: "100m"
91
+ memory: "256Mi"
92
+ limits:
93
+ cpu: "1000m"
94
+ memory: "1Gi"
95
+ volumes:
96
+ - name: data
97
+ persistentVolumeClaim:
98
+ claimName: olam-chunks-postgres-data
99
+ - name: initdb
100
+ configMap:
101
+ name: olam-chunks-postgres-initdb-sql