@elevasis/sdk 1.5.5 → 1.7.0
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.
- package/dist/cli.cjs +296 -98
- package/dist/index.d.ts +7 -4
- package/package.json +2 -2
- package/reference/_navigation.md +2 -1
- package/reference/_reference-manifest.json +16 -2
- package/reference/claude-config/commands/submit-request.md +11 -0
- package/reference/claude-config/hooks/__tests__/pre-edit-vibe-gate.test.mjs +169 -0
- package/reference/claude-config/hooks/pre-edit-vibe-gate.mjs +128 -0
- package/reference/claude-config/logs/pre-edit-vibe-gate.log +23 -0
- package/reference/claude-config/rules/organization-os.md +55 -8
- package/reference/claude-config/rules/vibe.md +210 -0
- package/reference/claude-config/settings.json +11 -0
- package/reference/claude-config/skills/configure/SKILL.md +100 -0
- package/reference/claude-config/skills/configure/operations/codify-level-a.md +100 -0
- package/reference/claude-config/skills/configure/operations/codify-level-b.md +158 -0
- package/reference/claude-config/skills/configure/operations/customers.md +150 -0
- package/reference/claude-config/skills/configure/operations/features.md +163 -0
- package/reference/claude-config/skills/configure/operations/goals.md +147 -0
- package/reference/claude-config/skills/configure/operations/identity.md +133 -0
- package/reference/claude-config/skills/configure/operations/labels.md +128 -0
- package/reference/claude-config/skills/configure/operations/offerings.md +159 -0
- package/reference/claude-config/skills/configure/operations/roles.md +153 -0
- package/reference/claude-config/skills/configure/operations/techStack.md +139 -0
- package/reference/claude-config/skills/project/SKILL.md +96 -39
- package/reference/claude-config/skills/setup/SKILL.md +81 -32
- package/reference/claude-config/skills/{submit-issue → submit-request}/SKILL.md +41 -26
- package/reference/packages/core/src/organization-model/README.md +16 -12
- package/reference/scaffold/core/organization-graph.mdx +1 -0
- package/reference/scaffold/core/organization-model.mdx +84 -19
- package/reference/scaffold/recipes/add-a-feature.md +1 -1
- package/reference/scaffold/recipes/customize-organization-model.md +5 -5
- package/reference/scaffold/recipes/gate-by-feature-or-admin.md +3 -3
- package/reference/scaffold/reference/contracts.md +115 -7
- package/reference/scaffold/reference/feature-registry.md +1 -1
- package/reference/scaffold/reference/glossary.md +25 -4
- package/reference/claude-config/commands/submit-issue.md +0 -11
package/dist/index.d.ts
CHANGED
|
@@ -3232,7 +3232,7 @@ type Database = {
|
|
|
3232
3232
|
}
|
|
3233
3233
|
];
|
|
3234
3234
|
};
|
|
3235
|
-
|
|
3235
|
+
reported_requests: {
|
|
3236
3236
|
Row: {
|
|
3237
3237
|
affected_page: string | null;
|
|
3238
3238
|
category: string;
|
|
@@ -3251,6 +3251,7 @@ type Database = {
|
|
|
3251
3251
|
status: string;
|
|
3252
3252
|
task_id: string | null;
|
|
3253
3253
|
title: string;
|
|
3254
|
+
type: string;
|
|
3254
3255
|
updated_at: string;
|
|
3255
3256
|
};
|
|
3256
3257
|
Insert: {
|
|
@@ -3271,6 +3272,7 @@ type Database = {
|
|
|
3271
3272
|
status?: string;
|
|
3272
3273
|
task_id?: string | null;
|
|
3273
3274
|
title: string;
|
|
3275
|
+
type: string;
|
|
3274
3276
|
updated_at?: string;
|
|
3275
3277
|
};
|
|
3276
3278
|
Update: {
|
|
@@ -3291,25 +3293,26 @@ type Database = {
|
|
|
3291
3293
|
status?: string;
|
|
3292
3294
|
task_id?: string | null;
|
|
3293
3295
|
title?: string;
|
|
3296
|
+
type?: string;
|
|
3294
3297
|
updated_at?: string;
|
|
3295
3298
|
};
|
|
3296
3299
|
Relationships: [
|
|
3297
3300
|
{
|
|
3298
|
-
foreignKeyName: "
|
|
3301
|
+
foreignKeyName: "reported_requests_organization_id_fkey";
|
|
3299
3302
|
columns: ["organization_id"];
|
|
3300
3303
|
isOneToOne: false;
|
|
3301
3304
|
referencedRelation: "organizations";
|
|
3302
3305
|
referencedColumns: ["id"];
|
|
3303
3306
|
},
|
|
3304
3307
|
{
|
|
3305
|
-
foreignKeyName: "
|
|
3308
|
+
foreignKeyName: "reported_requests_project_id_fkey";
|
|
3306
3309
|
columns: ["project_id"];
|
|
3307
3310
|
isOneToOne: false;
|
|
3308
3311
|
referencedRelation: "prj_projects";
|
|
3309
3312
|
referencedColumns: ["id"];
|
|
3310
3313
|
},
|
|
3311
3314
|
{
|
|
3312
|
-
foreignKeyName: "
|
|
3315
|
+
foreignKeyName: "reported_requests_task_id_fkey";
|
|
3313
3316
|
columns: ["task_id"];
|
|
3314
3317
|
isOneToOne: false;
|
|
3315
3318
|
referencedRelation: "prj_tasks";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elevasis/sdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0",
|
|
4
4
|
"description": "SDK for building Elevasis organization resources",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"tsup": "^8.0.0",
|
|
45
45
|
"typescript": "5.9.2",
|
|
46
46
|
"zod": "^4.1.0",
|
|
47
|
-
"@repo/core": "0.
|
|
47
|
+
"@repo/core": "0.6.0",
|
|
48
48
|
"@repo/typescript-config": "0.0.0"
|
|
49
49
|
},
|
|
50
50
|
"scripts": {
|
package/reference/_navigation.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Auto-generated from the package reference manifests.
|
|
4
4
|
|
|
5
|
-
Package entries indexed:
|
|
5
|
+
Package entries indexed: 42.
|
|
6
6
|
|
|
7
7
|
## @elevasis/core / Core
|
|
8
8
|
|
|
@@ -55,6 +55,7 @@ Package entries indexed: 41.
|
|
|
55
55
|
| Features Lead Gen | `packages/ui/src/features/README.md` | Published lead generation feature surface for downstream shells. | (not specified) |
|
|
56
56
|
| Features Operations | `packages/ui/src/features/README.md` | Published operations feature surface for downstream shells. | (not specified) |
|
|
57
57
|
| Features Monitoring | `packages/ui/src/features/README.md` | Published monitoring feature surface for downstream shells. | (not specified) |
|
|
58
|
+
| Features Monitoring Requests | `packages/ui/src/features/README.md` | Published submitted-requests list, detail, and triage surface for downstream shells. | (not specified) |
|
|
58
59
|
| Features SEO | `packages/ui/src/features/README.md` | Published SEO feature surface for downstream shells. | (not specified) |
|
|
59
60
|
| Features Settings | `packages/ui/src/features/README.md` | Published settings feature surface for downstream shells. | (not specified) |
|
|
60
61
|
|
|
@@ -239,6 +239,20 @@
|
|
|
239
239
|
"referencePath": "packages/ui/src/features/README.md",
|
|
240
240
|
"publishedExportPath": "./dist/features/monitoring/index.js"
|
|
241
241
|
},
|
|
242
|
+
{
|
|
243
|
+
"packageName": "@elevasis/ui",
|
|
244
|
+
"packageDir": "packages/ui",
|
|
245
|
+
"subpath": "./features/monitoring/requests",
|
|
246
|
+
"kind": "subpath",
|
|
247
|
+
"title": "Features Monitoring Requests",
|
|
248
|
+
"description": "Published submitted-requests list, detail, and triage surface for downstream shells.",
|
|
249
|
+
"group": "Features",
|
|
250
|
+
"order": 8,
|
|
251
|
+
"sourcePath": "packages/ui/src/features/monitoring/requests/index.ts",
|
|
252
|
+
"docPath": "packages/ui/src/features/README.md",
|
|
253
|
+
"referencePath": "packages/ui/src/features/README.md",
|
|
254
|
+
"publishedExportPath": "./dist/features/monitoring/requests/index.js"
|
|
255
|
+
},
|
|
242
256
|
{
|
|
243
257
|
"packageName": "@elevasis/ui",
|
|
244
258
|
"packageDir": "packages/ui",
|
|
@@ -247,7 +261,7 @@
|
|
|
247
261
|
"title": "Features SEO",
|
|
248
262
|
"description": "Published SEO feature surface for downstream shells.",
|
|
249
263
|
"group": "Features",
|
|
250
|
-
"order":
|
|
264
|
+
"order": 9,
|
|
251
265
|
"sourcePath": "packages/ui/src/features/seo/index.ts",
|
|
252
266
|
"docPath": "packages/ui/src/features/README.md",
|
|
253
267
|
"referencePath": "packages/ui/src/features/README.md",
|
|
@@ -261,7 +275,7 @@
|
|
|
261
275
|
"title": "Features Settings",
|
|
262
276
|
"description": "Published settings feature surface for downstream shells.",
|
|
263
277
|
"group": "Features",
|
|
264
|
-
"order":
|
|
278
|
+
"order": 10,
|
|
265
279
|
"sourcePath": "packages/ui/src/features/settings/index.ts",
|
|
266
280
|
"docPath": "packages/ui/src/features/README.md",
|
|
267
281
|
"referencePath": "packages/ui/src/features/README.md",
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Submit Request
|
|
2
|
+
|
|
3
|
+
**Usage:** `/submit-request [optional one-line description]`
|
|
4
|
+
|
|
5
|
+
**Goal:** File a structured request report to the Elevasis platform after agent-driven pre-analysis.
|
|
6
|
+
|
|
7
|
+
**EXECUTE:** `.claude/skills/submit-request/SKILL.md`
|
|
8
|
+
|
|
9
|
+
## Env Requirements
|
|
10
|
+
|
|
11
|
+
- `ELEVASIS_PLATFORM_KEY` (same key used by all `elevasis-sdk` commands — no extra setup if deploy already works)
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// pre-edit-vibe-gate.test.mjs
|
|
3
|
+
// Tests for the pre-edit-vibe-gate hook.
|
|
4
|
+
// Run with: node --test .claude/hooks/__tests__/pre-edit-vibe-gate.test.mjs
|
|
5
|
+
//
|
|
6
|
+
// Tests the exported `isProtectedPath` helper directly (pure logic, no stdin/stdout
|
|
7
|
+
// mocking needed). Integration cases simulate the full hook by spawning it as a
|
|
8
|
+
// child process.
|
|
9
|
+
|
|
10
|
+
import { describe, it } from 'node:test'
|
|
11
|
+
import assert from 'node:assert/strict'
|
|
12
|
+
import { spawnSync } from 'node:child_process'
|
|
13
|
+
import { resolve, dirname } from 'node:path'
|
|
14
|
+
import { fileURLToPath, pathToFileURL } from 'node:url'
|
|
15
|
+
|
|
16
|
+
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
17
|
+
const HOOK_PATH = resolve(__dirname, '..', 'pre-edit-vibe-gate.mjs')
|
|
18
|
+
|
|
19
|
+
// Import the exported helper for unit-level tests.
|
|
20
|
+
// Using a dynamic import so the module's top-level await (stdin read) doesn't
|
|
21
|
+
// execute — the hook guards that behind the stdin loop which only runs when
|
|
22
|
+
// there is actual input; unit tests call the exported function directly.
|
|
23
|
+
// On Windows, absolute paths must be converted to file:// URLs for ESM imports.
|
|
24
|
+
const { isProtectedPath } = await import(pathToFileURL(HOOK_PATH).href)
|
|
25
|
+
|
|
26
|
+
// Template root = 3 levels up from __tests__/
|
|
27
|
+
const TEMPLATE_ROOT = resolve(__dirname, '..', '..', '..')
|
|
28
|
+
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
// Helper: run the hook as a subprocess with a synthetic PreToolUse event.
|
|
31
|
+
// filePath may be relative (to template root) or already absolute.
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
function runHook(toolName, filePath, env = {}) {
|
|
34
|
+
// Claude always sends absolute paths to hooks. Resolve relative paths
|
|
35
|
+
// against the template root so toRelative() inside the hook works correctly.
|
|
36
|
+
const absFilePath =
|
|
37
|
+
filePath.startsWith('/') || /^[A-Za-z]:/.test(filePath) ? filePath : resolve(TEMPLATE_ROOT, filePath)
|
|
38
|
+
|
|
39
|
+
const event = JSON.stringify({
|
|
40
|
+
tool_name: toolName,
|
|
41
|
+
tool_input: { file_path: absFilePath }
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
return spawnSync(process.execPath, [HOOK_PATH], {
|
|
45
|
+
input: event,
|
|
46
|
+
encoding: 'utf-8',
|
|
47
|
+
env: {
|
|
48
|
+
...process.env,
|
|
49
|
+
// Override AFTER spreading so this always wins over any ambient value
|
|
50
|
+
CLAUDE_PROJECT_DIR: TEMPLATE_ROOT,
|
|
51
|
+
...env
|
|
52
|
+
},
|
|
53
|
+
timeout: 5000
|
|
54
|
+
})
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// ---------------------------------------------------------------------------
|
|
58
|
+
// Unit tests — isProtectedPath (pure function, no process spawning)
|
|
59
|
+
// ---------------------------------------------------------------------------
|
|
60
|
+
|
|
61
|
+
describe('isProtectedPath — exact protected files', () => {
|
|
62
|
+
it('blocks organization-model.ts', () => {
|
|
63
|
+
assert.equal(isProtectedPath('foundations/config/organization-model.ts'), true)
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
it('blocks organization-model.examples.ts', () => {
|
|
67
|
+
assert.equal(isProtectedPath('foundations/config/organization-model.examples.ts'), true)
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
it('blocks organization-model.override.ts', () => {
|
|
71
|
+
assert.equal(isProtectedPath('foundations/config/organization-model.override.ts'), true)
|
|
72
|
+
})
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
describe('isProtectedPath — extensions glob', () => {
|
|
76
|
+
it('blocks a .ts file directly under extensions/', () => {
|
|
77
|
+
assert.equal(isProtectedPath('foundations/config/extensions/deal-ecom.ts'), true)
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
it('blocks a .ts file in a subdirectory under extensions/', () => {
|
|
81
|
+
assert.equal(isProtectedPath('foundations/config/extensions/crm/deal-ecom.ts'), true)
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
it('blocks the discriminated-union index.ts under extensions/', () => {
|
|
85
|
+
assert.equal(isProtectedPath('foundations/config/extensions/index.ts'), true)
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
it('does NOT block a non-.ts file under extensions/', () => {
|
|
89
|
+
assert.equal(isProtectedPath('foundations/config/extensions/README.md'), false)
|
|
90
|
+
})
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
describe('isProtectedPath — unrelated paths always pass', () => {
|
|
94
|
+
it('allows ui/ files', () => {
|
|
95
|
+
assert.equal(isProtectedPath('ui/src/routes/__root.tsx'), false)
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
it('allows operations/ files', () => {
|
|
99
|
+
assert.equal(isProtectedPath('operations/src/index.ts'), false)
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
it('allows foundations/types (not config)', () => {
|
|
103
|
+
assert.equal(isProtectedPath('foundations/types/entities.ts'), false)
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
it('does NOT block a partial-match path that is not under foundations/config', () => {
|
|
107
|
+
// "organization-model.ts" without the full prefix should not be blocked
|
|
108
|
+
assert.equal(isProtectedPath('src/organization-model.ts'), false)
|
|
109
|
+
})
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
describe('isProtectedPath — partial path / edge cases', () => {
|
|
113
|
+
it('does not block foundations/config/ itself (no .ts suffix)', () => {
|
|
114
|
+
// The directory path should not be blocked
|
|
115
|
+
assert.equal(isProtectedPath('foundations/config/'), false)
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
it('strips leading ./ before matching', () => {
|
|
119
|
+
assert.equal(isProtectedPath('./foundations/config/organization-model.ts'), true)
|
|
120
|
+
})
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
// ---------------------------------------------------------------------------
|
|
124
|
+
// Integration tests — spawn the hook with synthetic events
|
|
125
|
+
// ---------------------------------------------------------------------------
|
|
126
|
+
|
|
127
|
+
describe('hook subprocess — blocked without VIBE_APPROVED', () => {
|
|
128
|
+
it('exits 2 for Write to organization-model.ts', () => {
|
|
129
|
+
const result = runHook('Write', 'foundations/config/organization-model.ts')
|
|
130
|
+
assert.equal(result.status, 2, `expected exit 2, got ${result.status}`)
|
|
131
|
+
assert.ok(result.stderr.includes('BLOCKED'), 'expected BLOCKED in stderr')
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
it('exits 2 for Edit to extensions/deal-ecom.ts', () => {
|
|
135
|
+
const result = runHook('Edit', 'foundations/config/extensions/deal-ecom.ts')
|
|
136
|
+
assert.equal(result.status, 2)
|
|
137
|
+
assert.ok(result.stderr.includes('BLOCKED'))
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
it('exits 2 for MultiEdit to organization-model.override.ts', () => {
|
|
141
|
+
const result = runHook('MultiEdit', 'foundations/config/organization-model.override.ts')
|
|
142
|
+
assert.equal(result.status, 2)
|
|
143
|
+
assert.ok(result.stderr.includes('BLOCKED'))
|
|
144
|
+
})
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
describe('hook subprocess — passes with VIBE_APPROVED=1', () => {
|
|
148
|
+
it('exits 0 for Write to organization-model.ts when VIBE_APPROVED=1', () => {
|
|
149
|
+
const result = runHook('Write', 'foundations/config/organization-model.ts', { VIBE_APPROVED: '1' })
|
|
150
|
+
assert.equal(result.status, 0, `expected exit 0, got ${result.status}`)
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
it('exits 0 for Edit to extensions/deal-ecom.ts when VIBE_APPROVED=1', () => {
|
|
154
|
+
const result = runHook('Edit', 'foundations/config/extensions/deal-ecom.ts', { VIBE_APPROVED: '1' })
|
|
155
|
+
assert.equal(result.status, 0)
|
|
156
|
+
})
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
describe('hook subprocess — unrelated path always passes', () => {
|
|
160
|
+
it('exits 0 for Write to ui/src/routes/__root.tsx without VIBE_APPROVED', () => {
|
|
161
|
+
const result = runHook('Write', 'ui/src/routes/__root.tsx')
|
|
162
|
+
assert.equal(result.status, 0)
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
it('exits 0 for Edit to operations/src/index.ts without VIBE_APPROVED', () => {
|
|
166
|
+
const result = runHook('Edit', 'operations/src/index.ts')
|
|
167
|
+
assert.equal(result.status, 0)
|
|
168
|
+
})
|
|
169
|
+
})
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// pre-edit-vibe-gate.mjs
|
|
3
|
+
// PreToolUse backstop — blocks raw writes to protected foundations/config paths
|
|
4
|
+
// unless the VIBE_APPROVED=1 trust marker is present.
|
|
5
|
+
//
|
|
6
|
+
// Protected paths (relative to project root):
|
|
7
|
+
// foundations/config/organization-model.ts
|
|
8
|
+
// foundations/config/organization-model.examples.ts
|
|
9
|
+
// foundations/config/organization-model.override.ts
|
|
10
|
+
// foundations/config/extensions/**/*.ts
|
|
11
|
+
//
|
|
12
|
+
// To allow a write: set VIBE_APPROVED=1 in the environment before invoking the
|
|
13
|
+
// agent, or run /configure which sets the marker automatically after user
|
|
14
|
+
// confirmation.
|
|
15
|
+
|
|
16
|
+
import { appendFileSync, mkdirSync } from 'node:fs'
|
|
17
|
+
import { normalize, resolve, relative, sep } from 'node:path'
|
|
18
|
+
import { fileURLToPath } from 'node:url'
|
|
19
|
+
|
|
20
|
+
const ROOT = normalize(process.env.CLAUDE_PROJECT_DIR ?? process.cwd())
|
|
21
|
+
const LOG_DIR = ROOT + sep + '.claude' + sep + 'logs'
|
|
22
|
+
const LOG_FILE = LOG_DIR + sep + 'pre-edit-vibe-gate.log'
|
|
23
|
+
|
|
24
|
+
function log(msg) {
|
|
25
|
+
try {
|
|
26
|
+
mkdirSync(LOG_DIR, { recursive: true })
|
|
27
|
+
appendFileSync(LOG_FILE, `[${new Date().toISOString()}] ${msg}\n`)
|
|
28
|
+
} catch {
|
|
29
|
+
// Never crash on log failure
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Normalise an incoming file path (may be absolute or project-relative) to a
|
|
35
|
+
* forward-slash relative path from ROOT for consistent matching.
|
|
36
|
+
*/
|
|
37
|
+
function toRelative(filePath) {
|
|
38
|
+
const abs = normalize(resolve(filePath))
|
|
39
|
+
// relative() returns OS-separator paths — normalise to forward slashes
|
|
40
|
+
return relative(ROOT, abs).replace(/\\/g, '/')
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Returns true if `rel` (forward-slash relative path from root) matches one of
|
|
45
|
+
* the protected path patterns. No external deps — uses simple string checks.
|
|
46
|
+
*
|
|
47
|
+
* Protected patterns:
|
|
48
|
+
* foundations/config/organization-model.ts (exact)
|
|
49
|
+
* foundations/config/organization-model.examples.ts (exact)
|
|
50
|
+
* foundations/config/organization-model.override.ts (exact)
|
|
51
|
+
* foundations/config/extensions/**\/*.ts (glob — any .ts under extensions/)
|
|
52
|
+
*/
|
|
53
|
+
export function isProtectedPath(rel) {
|
|
54
|
+
// Normalise away any leading ./
|
|
55
|
+
const r = rel.replace(/^\.\//, '')
|
|
56
|
+
|
|
57
|
+
// Exact protected files
|
|
58
|
+
const EXACT = [
|
|
59
|
+
'foundations/config/organization-model.ts',
|
|
60
|
+
'foundations/config/organization-model.examples.ts',
|
|
61
|
+
'foundations/config/organization-model.override.ts'
|
|
62
|
+
]
|
|
63
|
+
if (EXACT.includes(r)) return true
|
|
64
|
+
|
|
65
|
+
// Glob: foundations/config/extensions/**/*.ts
|
|
66
|
+
// Must start with the prefix, end with .ts, and have at least one path segment
|
|
67
|
+
// after the extensions/ directory.
|
|
68
|
+
const EXT_PREFIX = 'foundations/config/extensions/'
|
|
69
|
+
if (r.startsWith(EXT_PREFIX) && r.endsWith('.ts')) {
|
|
70
|
+
// Ensure there is at least one filename after the prefix (not just the dir itself)
|
|
71
|
+
const remainder = r.slice(EXT_PREFIX.length)
|
|
72
|
+
if (remainder.length > 3) return true // at least "x.ts"
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return false
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const BLOCK_MESSAGE =
|
|
79
|
+
'BLOCKED: This file is protected by the vibe gate.\n' +
|
|
80
|
+
'WHY: Direct edits to foundations/config/organization-model.ts and\n' +
|
|
81
|
+
' foundations/config/extensions/*.ts bypass the ambient vibe ceremony\n' +
|
|
82
|
+
' (confirm + /configure write + pnpm check-types).\n' +
|
|
83
|
+
'FIX: Run /configure to codify changes with proper ceremony (sets VIBE_APPROVED=1\n' +
|
|
84
|
+
' automatically), or set VIBE_APPROVED=1 explicitly if you are a power user\n' +
|
|
85
|
+
' who has already completed the ceremony manually.'
|
|
86
|
+
|
|
87
|
+
// Only run the stdin-reading main loop when this file is the entry point,
|
|
88
|
+
// not when it is imported as a module (e.g., by tests).
|
|
89
|
+
const isMain =
|
|
90
|
+
process.argv[1] != null && normalize(fileURLToPath(import.meta.url)) === normalize(resolve(process.argv[1]))
|
|
91
|
+
|
|
92
|
+
if (isMain) {
|
|
93
|
+
try {
|
|
94
|
+
const chunks = []
|
|
95
|
+
for await (const chunk of process.stdin) chunks.push(chunk)
|
|
96
|
+
const input = JSON.parse(Buffer.concat(chunks).toString())
|
|
97
|
+
|
|
98
|
+
const toolName = input.tool_name ?? ''
|
|
99
|
+
const filePath = input.tool_input?.file_path ?? ''
|
|
100
|
+
|
|
101
|
+
// Only gate Write, Edit, MultiEdit
|
|
102
|
+
if (!['Write', 'Edit', 'MultiEdit'].includes(toolName)) {
|
|
103
|
+
log(`SKIP tool=${toolName} (not a write tool)`)
|
|
104
|
+
process.exit(0)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (!filePath) {
|
|
108
|
+
log(`SKIP tool=${toolName} no file_path in input`)
|
|
109
|
+
process.exit(0)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const rel = toRelative(filePath)
|
|
113
|
+
const protected_ = isProtectedPath(rel)
|
|
114
|
+
const approved = process.env.VIBE_APPROVED === '1'
|
|
115
|
+
const decision = protected_ && !approved ? 'BLOCK' : 'ALLOW'
|
|
116
|
+
|
|
117
|
+
log(`tool=${toolName} path=${rel} protected=${protected_} VIBE_APPROVED=${approved} decision=${decision}`)
|
|
118
|
+
|
|
119
|
+
if (decision === 'BLOCK') {
|
|
120
|
+
process.stderr.write(BLOCK_MESSAGE)
|
|
121
|
+
process.exit(2)
|
|
122
|
+
}
|
|
123
|
+
} catch (err) {
|
|
124
|
+
log(`ERROR: ${err?.message ?? String(err)}`)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
process.exit(0)
|
|
128
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
[2026-04-20T09:29:53.658Z] tool=Write path=../../foundations/config/organization-model.ts protected=false VIBE_APPROVED=false decision=ALLOW
|
|
2
|
+
[2026-04-20T09:29:53.702Z] tool=Edit path=../../foundations/config/extensions/deal-ecom.ts protected=false VIBE_APPROVED=false decision=ALLOW
|
|
3
|
+
[2026-04-20T09:29:53.747Z] tool=MultiEdit path=../../foundations/config/organization-model.override.ts protected=false VIBE_APPROVED=false decision=ALLOW
|
|
4
|
+
[2026-04-20T09:29:53.793Z] tool=Write path=../../foundations/config/organization-model.ts protected=false VIBE_APPROVED=true decision=ALLOW
|
|
5
|
+
[2026-04-20T09:29:53.837Z] tool=Edit path=../../foundations/config/extensions/deal-ecom.ts protected=false VIBE_APPROVED=true decision=ALLOW
|
|
6
|
+
[2026-04-20T09:29:53.890Z] tool=Write path=../../ui/src/routes/__root.tsx protected=false VIBE_APPROVED=false decision=ALLOW
|
|
7
|
+
[2026-04-20T09:29:53.934Z] tool=Edit path=../../operations/src/index.ts protected=false VIBE_APPROVED=false decision=ALLOW
|
|
8
|
+
[2026-04-20T09:32:06.844Z] tool=Write path=../../foundations/config/organization-model.ts protected=false VIBE_APPROVED=false decision=ALLOW
|
|
9
|
+
[2026-04-20T09:32:06.890Z] tool=Edit path=../../foundations/config/extensions/deal-ecom.ts protected=false VIBE_APPROVED=false decision=ALLOW
|
|
10
|
+
[2026-04-20T09:32:06.934Z] tool=MultiEdit path=../../foundations/config/organization-model.override.ts protected=false VIBE_APPROVED=false decision=ALLOW
|
|
11
|
+
[2026-04-20T09:32:06.978Z] tool=Write path=../../foundations/config/organization-model.ts protected=false VIBE_APPROVED=true decision=ALLOW
|
|
12
|
+
[2026-04-20T09:32:07.021Z] tool=Edit path=../../foundations/config/extensions/deal-ecom.ts protected=false VIBE_APPROVED=true decision=ALLOW
|
|
13
|
+
[2026-04-20T09:32:07.065Z] tool=Write path=../../ui/src/routes/__root.tsx protected=false VIBE_APPROVED=false decision=ALLOW
|
|
14
|
+
[2026-04-20T09:32:07.109Z] tool=Edit path=../../operations/src/index.ts protected=false VIBE_APPROVED=false decision=ALLOW
|
|
15
|
+
[2026-04-20T09:32:30.340Z] tool=Write path=../../foundations/config/organization-model.ts protected=false VIBE_APPROVED=false decision=ALLOW
|
|
16
|
+
[2026-04-20T09:38:14.624Z] tool=Write path=../../foundations/config/organization-model.ts protected=false VIBE_APPROVED=false decision=ALLOW
|
|
17
|
+
[2026-04-20T09:40:20.586Z] tool=Write path=foundations/config/organization-model.ts protected=true VIBE_APPROVED=false decision=BLOCK
|
|
18
|
+
[2026-04-20T09:40:20.631Z] tool=Edit path=foundations/config/extensions/deal-ecom.ts protected=true VIBE_APPROVED=false decision=BLOCK
|
|
19
|
+
[2026-04-20T09:40:20.674Z] tool=MultiEdit path=foundations/config/organization-model.override.ts protected=true VIBE_APPROVED=false decision=BLOCK
|
|
20
|
+
[2026-04-20T09:40:20.718Z] tool=Write path=foundations/config/organization-model.ts protected=true VIBE_APPROVED=true decision=ALLOW
|
|
21
|
+
[2026-04-20T09:40:20.762Z] tool=Edit path=foundations/config/extensions/deal-ecom.ts protected=true VIBE_APPROVED=true decision=ALLOW
|
|
22
|
+
[2026-04-20T09:40:20.807Z] tool=Write path=ui/src/routes/__root.tsx protected=false VIBE_APPROVED=false decision=ALLOW
|
|
23
|
+
[2026-04-20T09:40:20.905Z] tool=Edit path=operations/src/index.ts protected=false VIBE_APPROVED=false decision=ALLOW
|
|
@@ -5,12 +5,34 @@ Organization OS is the semantic contract layer defining how organizations, featu
|
|
|
5
5
|
## Key Files in This Project
|
|
6
6
|
|
|
7
7
|
- `foundations/config/organization-model.ts` -- project-specific org model definition (calls `defineOrganizationModel` + `resolveOrganizationModel`)
|
|
8
|
-
- `foundations/config/organization-model.examples.ts` --
|
|
8
|
+
- `foundations/config/organization-model.examples.ts` -- reference patterns for all 14 domains: branding, identity, customers, offerings, roles, goals, sales stages, prospecting stages, resource mappings with techStack, custom features, statuses, and open-placement navigation groups. Pure reference -- not imported anywhere. Read this when customizing the org model.
|
|
9
9
|
- `foundations/types/entities.ts` -- typed entity contracts (Project, Deal, etc.). Extends `BaseProject`, `BaseDeal` from `@elevasis/core/entities` with project-specific metadata. Read this when authoring workflows that operate on these entities.
|
|
10
10
|
- `ui/src/routes/__root.tsx` -- wires `ElevasisFeaturesProvider` with `canonicalOrganizationModel`
|
|
11
11
|
- `ui/src/app-config.ts` -- references the org model
|
|
12
12
|
- `operations/src/index.ts` -- `DeploymentSpec` registry for workflows and agents
|
|
13
13
|
|
|
14
|
+
## Domain Overview
|
|
15
|
+
|
|
16
|
+
As of the 2026-04-20 expansion, `OrganizationModel` contains 14 top-level domains:
|
|
17
|
+
|
|
18
|
+
**Platform configuration:** `features`, `branding`, `navigation`, `sales` (formerly `crm`), `prospecting` (formerly `leadGen`), `projects` (formerly `delivery`), `resourceMappings`
|
|
19
|
+
|
|
20
|
+
**Organizational reality:** `identity`, `customers`, `offerings`, `roles`, `goals`
|
|
21
|
+
|
|
22
|
+
**Vibe layer:** `statuses`, `operations`
|
|
23
|
+
|
|
24
|
+
The `resourceMappings` entries may carry an optional `techStack` extension (`platform`, `purpose`, `credentialStatus`, `isSystemOfRecord`) without introducing a new top-level domain.
|
|
25
|
+
|
|
26
|
+
### Domain Rename Note
|
|
27
|
+
|
|
28
|
+
Three field names changed in the 2026-04-20 expansion. Feature ID constants and consumer-facing feature IDs are unchanged:
|
|
29
|
+
|
|
30
|
+
| Old field | New field | Feature ID (unchanged) | Constant (unchanged) |
|
|
31
|
+
| ---------- | ------------- | ---------------------- | --------------------- |
|
|
32
|
+
| `crm` | `sales` | `'crm'` | `CRM_FEATURE_ID` |
|
|
33
|
+
| `leadGen` | `prospecting` | `'lead-gen'` | `LEAD_GEN_FEATURE_ID` |
|
|
34
|
+
| `delivery` | `projects` | `'projects'` | `PROJECTS_FEATURE_ID` |
|
|
35
|
+
|
|
14
36
|
## Reference Documentation
|
|
15
37
|
|
|
16
38
|
Full Organization OS documentation ships with the SDK and is available locally after `pnpm install`:
|
|
@@ -20,7 +42,7 @@ Full Organization OS documentation ships with the SDK and is available locally a
|
|
|
20
42
|
All paths under `node_modules/@elevasis/sdk/reference/scaffold/`:
|
|
21
43
|
|
|
22
44
|
- `node_modules/@elevasis/sdk/reference/scaffold/index.mdx` -- scaffold root and navigation
|
|
23
|
-
- `node_modules/@elevasis/sdk/reference/scaffold/core/organization-model.mdx` -- semantic contract,
|
|
45
|
+
- `node_modules/@elevasis/sdk/reference/scaffold/core/organization-model.mdx` -- semantic contract, all 14 domains, adapter authoring, validation gate, `/configure` entry point
|
|
24
46
|
- `node_modules/@elevasis/sdk/reference/scaffold/core/organization-graph.mdx` -- graph derivation, node/edge taxonomy, lenses
|
|
25
47
|
- `node_modules/@elevasis/sdk/reference/scaffold/ui/feature-shell.mdx` -- FeatureModule manifest, provider runtime
|
|
26
48
|
- `node_modules/@elevasis/sdk/reference/scaffold/ui/composition-extensibility.mdx` -- layout primitives, router abstraction
|
|
@@ -48,15 +70,40 @@ All paths under `node_modules/@elevasis/sdk/reference/scaffold/`:
|
|
|
48
70
|
- `@elevasis/core/organization-model` -- the curated organization-model barrel. Exports `defineOrganizationModel`, `resolveOrganizationModel`, `OrganizationModelSchema`, `DEFAULT_ORGANIZATION_MODEL`, organization-model types, and typed feature/surface constants.
|
|
49
71
|
- Feature IDs: `CRM_FEATURE_ID`, `LEAD_GEN_FEATURE_ID`, `PROJECTS_FEATURE_ID`, `OPERATIONS_FEATURE_ID`, `MONITORING_FEATURE_ID`, `SETTINGS_FEATURE_ID`, `SEO_FEATURE_ID`
|
|
50
72
|
- Headline surface IDs: `CRM_PIPELINE_SURFACE_ID`, `LEAD_GEN_LISTS_SURFACE_ID`, `PROJECTS_INDEX_SURFACE_ID`, `OPERATIONS_ORGANIZATION_GRAPH_SURFACE_ID`
|
|
51
|
-
-
|
|
73
|
+
- Reality domain types: `OrganizationModelIdentity`, `OrganizationModelCustomers`, `OrganizationModelCustomerSegment`, `OrganizationModelOfferings`, `OrganizationModelProduct`, `OrganizationModelRoles`, `OrganizationModelRole`, `OrganizationModelGoals`, `OrganizationModelObjective`, `OrganizationModelKeyResult`
|
|
74
|
+
- Vibe domain types: `OrganizationModelStatuses`, `OrganizationModelOperations`
|
|
75
|
+
- TechStack: `TechStackEntrySchema`, `OrganizationModelTechStackEntry`
|
|
76
|
+
- Use constants instead of magic strings when overriding the org model.
|
|
52
77
|
- `@elevasis/core/entities` -- entity contracts barrel. Exports `BaseProject`, `BaseProjectSchema`, `BaseProjectInput` and the equivalents for `Milestone`, `Task`, `Deal`, `Company`, `Contact`. Each base interface is generic over a `\<TMeta>` extension slot. Extend these in `foundations/types/entities.ts` to add project-specific fields.
|
|
53
78
|
|
|
54
79
|
## When Working with Organization OS
|
|
55
80
|
|
|
56
|
-
- **
|
|
57
|
-
- **Adding a
|
|
58
|
-
- **
|
|
81
|
+
- **Changing org model (structural reality):** Use `/configure` as the entry point. Do not edit `foundations/config/organization-model.ts` directly -- the `pre-edit-vibe-gate.mjs` hook blocks raw writes without `VIBE_APPROVED=1`, which `/configure` sets after user confirmation. Run `/configure` for the full layered flow or `/configure \<domain>` for a targeted domain.
|
|
82
|
+
- **Adding a feature:** Follow `node_modules/@elevasis/sdk/reference/scaffold/recipes/add-a-feature.md`. For toggling an existing feature, use `/configure features`.
|
|
83
|
+
- **Adding a resource:** Follow `node_modules/@elevasis/sdk/reference/scaffold/recipes/add-a-resource.md`.
|
|
59
84
|
- **Extending entities:** Start with `foundations/types/entities.ts` for the demo extension pattern. Base shapes come from `@elevasis/core/entities`.
|
|
60
85
|
- **Authoring a workflow that takes a Project/Deal/etc.:** Reference entity types from `foundations/types/entities.ts` in the input schema -- do not redeclare them.
|
|
61
|
-
- **Understanding contracts:** Check `node_modules/@elevasis/sdk/reference/scaffold/reference/contracts.md` for current type shapes
|
|
62
|
-
- **Debugging sync issues:** Check `node_modules/@elevasis/sdk/reference/scaffold/operations/propagation-pipeline.md` for the verification pipeline
|
|
86
|
+
- **Understanding contracts:** Check `node_modules/@elevasis/sdk/reference/scaffold/reference/contracts.md` for current type shapes.
|
|
87
|
+
- **Debugging sync issues:** Check `node_modules/@elevasis/sdk/reference/scaffold/operations/propagation-pipeline.md` for the verification pipeline.
|
|
88
|
+
|
|
89
|
+
## `/configure` -- Org Model QA Entry Point
|
|
90
|
+
|
|
91
|
+
`/configure` is the recurring, safe-to-re-run org model editor for this project. It is a skill (not a command) at `.claude/skills/configure/SKILL.md`.
|
|
92
|
+
|
|
93
|
+
**Usage:**
|
|
94
|
+
|
|
95
|
+
- `/configure` -- layered flow: identity → customers → offerings → roles → goals → techStack
|
|
96
|
+
- `/configure identity` -- legal identity, mission/vision, industry, geography, timezone
|
|
97
|
+
- `/configure customers` -- customer segments with jobs-to-be-done, pains, gains, firmographics
|
|
98
|
+
- `/configure offerings` -- products and services with pricing model and segment references
|
|
99
|
+
- `/configure roles` -- role chart with responsibilities, reporting lines, and holders
|
|
100
|
+
- `/configure goals` -- organizational goals with period and measurable outcomes
|
|
101
|
+
- `/configure techStack` -- external-SaaS integration metadata on resource mappings
|
|
102
|
+
- `/configure features` -- enable, disable, or add features
|
|
103
|
+
- `/configure labels` -- edit display labels on enum entries (statuses, stages)
|
|
104
|
+
|
|
105
|
+
Every write is gated: `resolveOrganizationModel()` must succeed (Zod cross-refs pass) and `pnpm -C operations check-types` must pass. On failure the change is rolled back.
|
|
106
|
+
|
|
107
|
+
**Distinction from `/setup`:** `/setup` is first-time bootstrap only. After bootstrap it delegates here. `/configure` is idempotent and safe to re-run at any time.
|
|
108
|
+
|
|
109
|
+
The ambient vibe layer (`.claude/rules/vibe.md`) automatically detects Codify intent in plain language and delegates to `/configure`. Power users can invoke `/configure` directly to bypass the ambient layer entirely.
|