@pleri/olam-cli 0.1.186 → 0.1.188

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 (58) hide show
  1. package/dist/ask/knowledge-pack-builder.d.ts.map +1 -1
  2. package/dist/ask/knowledge-pack-builder.js +5 -0
  3. package/dist/ask/knowledge-pack-builder.js.map +1 -1
  4. package/dist/ask/knowledge-pack.generated.d.ts.map +1 -1
  5. package/dist/ask/knowledge-pack.generated.js +406 -22
  6. package/dist/ask/knowledge-pack.generated.js.map +1 -1
  7. package/dist/commands/auth-status.js +2 -2
  8. package/dist/commands/auth-status.js.map +1 -1
  9. package/dist/commands/auth.js +1 -1
  10. package/dist/commands/auth.js.map +1 -1
  11. package/dist/commands/create.d.ts.map +1 -1
  12. package/dist/commands/create.js +4 -0
  13. package/dist/commands/create.js.map +1 -1
  14. package/dist/commands/install.js +2 -2
  15. package/dist/commands/install.js.map +1 -1
  16. package/dist/commands/services.d.ts.map +1 -1
  17. package/dist/commands/services.js +12 -0
  18. package/dist/commands/services.js.map +1 -1
  19. package/dist/commands/setup.js +1 -1
  20. package/dist/commands/setup.js.map +1 -1
  21. package/dist/commands/status.d.ts.map +1 -1
  22. package/dist/commands/status.js +4 -0
  23. package/dist/commands/status.js.map +1 -1
  24. package/dist/image-digests.json +8 -8
  25. package/dist/index.js +788 -368
  26. package/dist/lib/health-probes.d.ts +14 -0
  27. package/dist/lib/health-probes.d.ts.map +1 -1
  28. package/dist/lib/health-probes.js +41 -3
  29. package/dist/lib/health-probes.js.map +1 -1
  30. package/dist/mcp-server.js +95 -27
  31. package/hermes-bundle/version.json +1 -1
  32. package/host-cp/k8s/manifests/50-deployment.yaml +1 -1
  33. package/host-cp/k8s/manifests/auth-service/50-deployment.yaml +1 -1
  34. package/host-cp/k8s/manifests/chunks-electric/10-serviceaccount.yaml +8 -0
  35. package/host-cp/k8s/manifests/chunks-electric/20-rbac.yaml +27 -0
  36. package/host-cp/k8s/manifests/chunks-electric/30-configmap.yaml +23 -0
  37. package/host-cp/k8s/manifests/chunks-electric/45-pvc.yaml +19 -0
  38. package/host-cp/k8s/manifests/chunks-electric/50-deployment.yaml +84 -0
  39. package/host-cp/k8s/manifests/chunks-electric/60-service.yaml +17 -0
  40. package/host-cp/k8s/manifests/chunks-postgres/10-serviceaccount.yaml +8 -0
  41. package/host-cp/k8s/manifests/chunks-postgres/20-rbac.yaml +29 -0
  42. package/host-cp/k8s/manifests/chunks-postgres/30-configmap.yaml +185 -0
  43. package/host-cp/k8s/manifests/chunks-postgres/45-pvc.yaml +24 -0
  44. package/host-cp/k8s/manifests/chunks-postgres/50-deployment.yaml +101 -0
  45. package/host-cp/k8s/manifests/chunks-postgres/60-service.yaml +24 -0
  46. package/host-cp/k8s/manifests/kg-service/50-deployment.yaml +1 -1
  47. package/host-cp/k8s/manifests/mcp-auth-service/50-deployment.yaml +1 -1
  48. package/host-cp/k8s/manifests/memory-service/50-deployment.yaml +1 -1
  49. package/host-cp/k8s/manifests/plan-chat-service/10-serviceaccount.yaml +8 -0
  50. package/host-cp/k8s/manifests/plan-chat-service/20-rbac.yaml +29 -0
  51. package/host-cp/k8s/manifests/plan-chat-service/30-configmap.yaml +36 -0
  52. package/host-cp/k8s/manifests/plan-chat-service/45-pvc.yaml +24 -0
  53. package/host-cp/k8s/manifests/plan-chat-service/50-deployment.yaml +135 -0
  54. package/host-cp/k8s/manifests/plan-chat-service/60-service.yaml +17 -0
  55. package/host-cp/src/plan-chat-service.mjs +216 -0
  56. package/host-cp/src/pr-cache.mjs +11 -2
  57. package/host-cp/src/server.mjs +36 -20
  58. package/package.json +1 -1
@@ -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
@@ -0,0 +1,24 @@
1
+ # Headless Service for olam-chunks-postgres StatefulSet.
2
+ #
3
+ # clusterIP: None gives the StatefulSet's pod stable DNS:
4
+ # olam-chunks-postgres-0.olam-chunks-postgres.olam.svc.cluster.local
5
+ # Callers (plan-chat-service, chunks-electric) connect via the shorter
6
+ # olam-chunks-postgres.olam.svc.cluster.local form which Kubernetes resolves
7
+ # round-robin to the single backing pod.
8
+ apiVersion: v1
9
+ kind: Service
10
+ metadata:
11
+ name: olam-chunks-postgres
12
+ namespace: olam
13
+ labels:
14
+ app: olam-chunks-postgres
15
+ olam.io/component: substrate
16
+ spec:
17
+ clusterIP: None
18
+ selector:
19
+ app: olam-chunks-postgres
20
+ ports:
21
+ - name: postgres
22
+ port: 5432
23
+ targetPort: 5432
24
+ protocol: TCP
@@ -61,7 +61,7 @@ spec:
61
61
  mountPath: /data
62
62
  containers:
63
63
  - name: olam-kg-service
64
- image: ghcr.io/pleri/olam-kg-service@sha256:a031eeb1a906b646396d1954e9116b228e5ad9ccedfc9953465f347541e1ecb2
64
+ image: ghcr.io/pleri/olam-kg-service@sha256:c9a0226339907711443657e2ca1eb40d2e2df120562dbb5d7d0ddf628614fb74
65
65
  imagePullPolicy: IfNotPresent
66
66
  securityContext:
67
67
  runAsNonRoot: true
@@ -68,7 +68,7 @@ spec:
68
68
  mountPath: /data
69
69
  containers:
70
70
  - name: olam-mcp-auth-service
71
- image: ghcr.io/pleri/olam-mcp-auth@sha256:be68e388e003ccc4489b3dcf6caecb43bf1e529b6e6384b6cab0d7a6f897438e
71
+ image: ghcr.io/pleri/olam-mcp-auth@sha256:eba57d0c5c89763bc266faba80e98912875f541c9ad8e96ee5f28790f9fb96d8
72
72
  imagePullPolicy: IfNotPresent
73
73
  securityContext:
74
74
  runAsNonRoot: true
@@ -70,7 +70,7 @@ spec:
70
70
  # bootstrap-placeholder comment + run `npm run refresh:manifest-digests`
71
71
  # once ghcr.io/pleri/olam-memory-service has a real published digest.
72
72
  # bootstrap-placeholder: pre-publish; refresh after first release
73
- image: ghcr.io/pleri/olam-memory-service@sha256:a28ad257f7c4d9de3ff6a99fbc016b66356ad09b487840fce106f407096eea3c
73
+ image: ghcr.io/pleri/olam-memory-service@sha256:33390ba1b2b4785ebf9af9732c42c40ae572ec1176e01f1fed8225d0d449ca57
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-plan-chat-service
5
+ namespace: olam
6
+ labels:
7
+ app: olam-plan-chat-service
8
+ olam.io/component: peripheral
@@ -0,0 +1,29 @@
1
+ # plan-chat-service does not need to read or write any Kubernetes API objects.
2
+ # A no-op Role + RoleBinding documents the minimal-privilege stance and
3
+ # keeps the file present so audit:cli-bundle-k8s does not skip this peripheral.
4
+ apiVersion: rbac.authorization.k8s.io/v1
5
+ kind: Role
6
+ metadata:
7
+ name: olam-plan-chat-service
8
+ namespace: olam
9
+ labels:
10
+ app: olam-plan-chat-service
11
+ olam.io/component: peripheral
12
+ rules: []
13
+ ---
14
+ apiVersion: rbac.authorization.k8s.io/v1
15
+ kind: RoleBinding
16
+ metadata:
17
+ name: olam-plan-chat-service
18
+ namespace: olam
19
+ labels:
20
+ app: olam-plan-chat-service
21
+ olam.io/component: peripheral
22
+ roleRef:
23
+ apiGroup: rbac.authorization.k8s.io
24
+ kind: Role
25
+ name: olam-plan-chat-service
26
+ subjects:
27
+ - kind: ServiceAccount
28
+ name: olam-plan-chat-service
29
+ namespace: olam
@@ -0,0 +1,36 @@
1
+ # ConfigMap for olam-plan-chat-service.
2
+ #
3
+ # plan-chat-service.mjs (packages/host-cp/src/plan-chat-service.mjs) reads
4
+ # these env vars at startup. See the file header for the canonical names.
5
+ #
6
+ # DATABASE_URL: points at the in-cluster chunks-postgres StatefulSet's Service.
7
+ # The password is sourced from the chunks-postgres-secret
8
+ # (mounted via envFrom in 50-deployment.yaml) — the literal
9
+ # here uses the env-var substitution syntax
10
+ # `$(VAR)` which kubelet expands when DATABASE_URL is itself
11
+ # read via envFrom or env: subordinate.
12
+ #
13
+ # BUT: kubelet only expands env-refs declared on the container,
14
+ # not values inside a ConfigMap key. So we keep DATABASE_URL
15
+ # OUT of this ConfigMap and assemble it in the Deployment's
16
+ # env: section instead (which CAN reference the Secret-backed
17
+ # POSTGRES_PASSWORD via $(POSTGRES_PASSWORD)). See 50-deployment.yaml.
18
+ #
19
+ # ELECTRIC_URL: chunks-electric ClusterIP. No auth (ELECTRIC_INSECURE=true on
20
+ # that service in local-dev mode).
21
+ #
22
+ # SECRET_PATH: filesystem path where the olam-plan-chat-secret Secret is
23
+ # mounted (see volumeMounts in 50-deployment.yaml). The mount
24
+ # key is "secret" → file `/etc/olam-plan-chat/secret`.
25
+ apiVersion: v1
26
+ kind: ConfigMap
27
+ metadata:
28
+ name: olam-plan-chat-service-env
29
+ namespace: olam
30
+ labels:
31
+ app: olam-plan-chat-service
32
+ olam.io/component: peripheral
33
+ data:
34
+ OLAM_PLAN_CHAT_PORT: "3200"
35
+ OLAM_PLAN_CHAT_ELECTRIC_URL: "http://olam-chunks-electric.olam.svc.cluster.local:3000"
36
+ OLAM_PLAN_CHAT_SECRET_PATH: "/etc/olam-plan-chat/secret"
@@ -0,0 +1,24 @@
1
+ # PersistentVolumeClaim for olam-plan-chat-service /data volume.
2
+ #
3
+ # plan-chat-service is mostly stateless (DB lives in chunks-postgres, secret
4
+ # lives in olam-plan-chat-secret), but ships a /data PVC for parity with
5
+ # the other peripherals. Used for any transient state the service decides
6
+ # to spool (e.g. planning-session resumption buffers).
7
+ #
8
+ # local-path StorageClass ships with k3d by default. On non-k3d clusters,
9
+ # substitute storageClassName with your cluster's provisioner.
10
+ apiVersion: v1
11
+ kind: PersistentVolumeClaim
12
+ metadata:
13
+ name: olam-plan-chat-service-data
14
+ namespace: olam
15
+ labels:
16
+ app: olam-plan-chat-service
17
+ olam.io/component: peripheral
18
+ spec:
19
+ accessModes:
20
+ - ReadWriteOnce
21
+ storageClassName: local-path
22
+ resources:
23
+ requests:
24
+ storage: 1Gi
@@ -0,0 +1,135 @@
1
+ # Deployment for olam-plan-chat-service.
2
+ #
3
+ # Image strategy: REUSES the olam-host-cp image. Per the package layout,
4
+ # plan-chat-service.mjs is a sibling under packages/host-cp/src/, and the
5
+ # host-cp image's WORKDIR=/app already contains it at /app/src/plan-chat-service.mjs.
6
+ # The single shared image avoids version-drift between the two binaries that
7
+ # share plan-chat-secret.mjs (bearer-auth logic), planning-sessions.mjs,
8
+ # crystallize-planning.mjs, and resolver.mjs.
9
+ #
10
+ # The command override replaces the host-cp default
11
+ # ENTRYPOINT (`node src/server.mjs`) with the plan-chat-service entrypoint.
12
+ #
13
+ # Image: pinned to the SAME digest as host-cp's 50-deployment.yaml. Refresh
14
+ # both in lockstep via scripts/refresh-manifest-digests.mjs on every release.
15
+ apiVersion: apps/v1
16
+ kind: Deployment
17
+ metadata:
18
+ name: olam-plan-chat-service
19
+ namespace: olam
20
+ labels:
21
+ app: olam-plan-chat-service
22
+ olam.io/component: peripheral
23
+ spec:
24
+ replicas: 1
25
+ strategy:
26
+ type: RollingUpdate
27
+ rollingUpdate:
28
+ maxSurge: 1
29
+ maxUnavailable: 0
30
+ selector:
31
+ matchLabels:
32
+ app: olam-plan-chat-service
33
+ template:
34
+ metadata:
35
+ labels:
36
+ app: olam-plan-chat-service
37
+ spec:
38
+ enableServiceLinks: false
39
+ imagePullSecrets:
40
+ - name: ghcr-pull
41
+ serviceAccountName: olam-plan-chat-service
42
+ securityContext:
43
+ runAsNonRoot: true
44
+ runAsUser: 1000
45
+ runAsGroup: 1000
46
+ fsGroup: 1000
47
+ initContainers:
48
+ # chown-data: identical to memory-service pattern. Postgres-RWO PVC
49
+ # mounts as root-owned on local-path; this brings it to 1000:1000.
50
+ - name: chown-data
51
+ image: busybox@sha256:73aaf090f3d85aa34ee199857f03fa3a95c8ede2ffd4cc2cdb5b94e566b11662
52
+ imagePullPolicy: IfNotPresent
53
+ securityContext:
54
+ runAsUser: 0
55
+ runAsNonRoot: false
56
+ allowPrivilegeEscalation: false
57
+ command: ["chown", "-R", "1000:1000", "/data"]
58
+ volumeMounts:
59
+ - name: plan-chat-data
60
+ mountPath: /data
61
+ containers:
62
+ - name: olam-plan-chat-service
63
+ # Reuses the host-cp image (same source tree, same node_modules).
64
+ # Digest pinned in lockstep with packages/host-cp/k8s/manifests/50-deployment.yaml.
65
+ image: ghcr.io/pleri/olam-host-cp@sha256:20d84b6d490c633bc5a158b0f7f849152aba3cf1d2d45657360f627d8d41ec3f
66
+ imagePullPolicy: IfNotPresent
67
+ # Override the host-cp ENTRYPOINT. plan-chat-service.mjs exports
68
+ # startService(); we boot it via -e import-and-call.
69
+ command: ["node"]
70
+ args:
71
+ - "-e"
72
+ - "import('/app/src/plan-chat-service.mjs').then(m => m.startService()).catch(e => { console.error('[plan-chat-service]', e); process.exit(1); });"
73
+ workingDir: /app
74
+ securityContext:
75
+ runAsNonRoot: true
76
+ runAsUser: 1000
77
+ allowPrivilegeEscalation: false
78
+ capabilities:
79
+ drop: ["ALL"]
80
+ ports:
81
+ - name: http
82
+ containerPort: 3200
83
+ protocol: TCP
84
+ envFrom:
85
+ - configMapRef:
86
+ name: olam-plan-chat-service-env
87
+ env:
88
+ # DATABASE_URL composition. Same pattern as chunks-electric.
89
+ - name: POSTGRES_PASSWORD
90
+ valueFrom:
91
+ secretKeyRef:
92
+ name: olam-chunks-postgres-secret
93
+ key: POSTGRES_PASSWORD
94
+ - name: OLAM_PLAN_CHAT_DATABASE_URL
95
+ value: "postgres://postgres:$(POSTGRES_PASSWORD)@olam-chunks-postgres.olam.svc.cluster.local:5432/chunks"
96
+ volumeMounts:
97
+ - name: plan-chat-data
98
+ mountPath: /data
99
+ - name: plan-chat-secret
100
+ mountPath: /etc/olam-plan-chat
101
+ readOnly: true
102
+ readinessProbe:
103
+ httpGet:
104
+ path: /livez
105
+ port: 3200
106
+ initialDelaySeconds: 10
107
+ periodSeconds: 5
108
+ timeoutSeconds: 3
109
+ failureThreshold: 12
110
+ livenessProbe:
111
+ httpGet:
112
+ path: /livez
113
+ port: 3200
114
+ initialDelaySeconds: 60
115
+ periodSeconds: 20
116
+ timeoutSeconds: 5
117
+ failureThreshold: 3
118
+ resources:
119
+ requests:
120
+ cpu: "50m"
121
+ memory: "256Mi"
122
+ limits:
123
+ cpu: "500m"
124
+ memory: "1Gi"
125
+ volumes:
126
+ - name: plan-chat-data
127
+ persistentVolumeClaim:
128
+ claimName: olam-plan-chat-service-data
129
+ - name: plan-chat-secret
130
+ secret:
131
+ secretName: olam-plan-chat-secret
132
+ defaultMode: 0400
133
+ items:
134
+ - key: PLAN_CHAT_SECRET
135
+ path: secret
@@ -0,0 +1,17 @@
1
+ apiVersion: v1
2
+ kind: Service
3
+ metadata:
4
+ name: olam-plan-chat-service
5
+ namespace: olam
6
+ labels:
7
+ app: olam-plan-chat-service
8
+ olam.io/component: peripheral
9
+ spec:
10
+ type: ClusterIP
11
+ selector:
12
+ app: olam-plan-chat-service
13
+ ports:
14
+ - name: http
15
+ port: 3200
16
+ targetPort: 3200
17
+ protocol: TCP