@polderlabs/bizar-omp 0.2.0 → 0.3.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/README.md +30 -4
- package/agents/bizar-architect.md +1 -1
- package/agents/bizar-docs.md +1 -1
- package/agents/bizar-implementer.md +1 -1
- package/agents/bizar-planner.md +1 -1
- package/agents/bizar-researcher.md +1 -1
- package/agents/bizar-reviewer.md +1 -1
- package/agents/bizar-security-reviewer.md +1 -1
- package/agents/bizar-verifier.md +1 -1
- package/dist/cli/doctor.d.ts +4 -4
- package/dist/cli/install.js +2 -2
- package/dist/extension.d.ts +17 -0
- package/dist/extension.d.ts.map +1 -1
- package/dist/extension.js +60 -12
- package/dist/extension.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/omp/autonomous-settings.d.ts +0 -5
- package/dist/omp/autonomous-settings.d.ts.map +1 -1
- package/dist/omp/autonomous-settings.js +1 -5
- package/dist/omp/autonomous-settings.js.map +1 -1
- package/dist/omp/compatibility.d.ts +4 -4
- package/dist/omp/compatibility.js +1 -1
- package/dist/omp/config.d.ts.map +1 -1
- package/dist/omp/config.js +2 -1
- package/dist/omp/config.js.map +1 -1
- package/dist/omp/model-role-assignment.d.ts +62 -0
- package/dist/omp/model-role-assignment.d.ts.map +1 -0
- package/dist/omp/model-role-assignment.js +92 -0
- package/dist/omp/model-role-assignment.js.map +1 -0
- package/dist/omp/model-roles.d.ts +11 -3
- package/dist/omp/model-roles.d.ts.map +1 -1
- package/dist/omp/model-roles.js +2 -1
- package/dist/omp/model-roles.js.map +1 -1
- package/docs/compatibility/baseline.json +2 -2
- package/docs/compatibility/phase-0-report.md +1 -1
- package/docs/compatibility/supported-surfaces.json +1 -1
- package/docs/releases/0.3.0.md +9 -0
- package/docs/releases/native-stable.md +1 -1
- package/docs/releases/npm-publishing.md +1 -1
- package/docs/releases/support-matrix.md +1 -1
- package/package.json +2 -1
- package/skills/omp-native-development/SKILL.md +111 -0
- package/skills/omp-native-development/agents/openai.yaml +4 -0
- package/skills/omp-native-development/assets/native-role-pack/agent-names.example.json +8 -0
- package/skills/omp-native-development/assets/native-role-pack/agents/bizar-implementer.md +12 -0
- package/skills/omp-native-development/assets/native-role-pack/agents/bizar-planner.md +12 -0
- package/skills/omp-native-development/assets/native-role-pack/agents/bizar-researcher.md +12 -0
- package/skills/omp-native-development/assets/native-role-pack/agents/bizar-reviewer.md +12 -0
- package/skills/omp-native-development/assets/native-role-pack/agents/bizar-security-reviewer.md +12 -0
- package/skills/omp-native-development/assets/native-role-pack/agents/bizar-verifier.md +12 -0
- package/skills/omp-native-development/assets/native-role-pack/bindings.json +8 -0
- package/skills/omp-native-development/assets/native-role-pack/config.fragment.json +10 -0
- package/skills/omp-native-development/assets/native-role-pack/config.fragment.yml +13 -0
- package/skills/omp-native-development/assets/native-role-probe.ts +37 -0
- package/skills/omp-native-development/assets/tests/acceptance-matrix.json +802 -0
- package/skills/omp-native-development/assets/tests/native-role-contract.test.ts +96 -0
- package/skills/omp-native-development/references/accuracy-and-versioning.md +63 -0
- package/skills/omp-native-development/references/agent-and-model-roles.md +158 -0
- package/skills/omp-native-development/references/bizar-integration-contract.md +100 -0
- package/skills/omp-native-development/references/bundle-validation.json +54 -0
- package/skills/omp-native-development/references/developer-handoff.md +126 -0
- package/skills/omp-native-development/references/execution-and-lifecycle.md +74 -0
- package/skills/omp-native-development/references/extensions-and-packaging.md +82 -0
- package/skills/omp-native-development/references/native-validation-matrix.md +96 -0
- package/skills/omp-native-development/references/official-docs-index.md +174 -0
- package/skills/omp-native-development/references/offline-test-results.txt +43 -0
- package/skills/omp-native-development/references/research-and-test-status.md +31 -0
- package/skills/omp-native-development/references/sessions-sdk-rpc.md +59 -0
- package/skills/omp-native-development/references/settings-providers-security.md +69 -0
- package/skills/omp-native-development/references/source-manifest.json +1359 -0
- package/skills/omp-native-development/references/tools-and-capabilities.md +59 -0
- package/skills/omp-native-development/scripts/audit_role_config.py +167 -0
- package/skills/omp-native-development/scripts/omp_docs.py +252 -0
- package/skills/omp-native-development/scripts/test_tools.py +222 -0
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Offline unit tests. These test the skill utilities, not OMP runtime behavior."""
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import contextlib
|
|
6
|
+
import io
|
|
7
|
+
import json
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
import subprocess
|
|
10
|
+
import tempfile
|
|
11
|
+
import unittest
|
|
12
|
+
from unittest.mock import patch
|
|
13
|
+
|
|
14
|
+
import audit_role_config as role
|
|
15
|
+
import omp_docs as docs
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class RoleAuditTests(unittest.TestCase):
|
|
19
|
+
def test_nested_role_profile(self):
|
|
20
|
+
self.assertTrue(role.audit({"modelRoles": {"bizar_build": "@task"}}, ["bizar_build"], [])['static_ok'])
|
|
21
|
+
|
|
22
|
+
def test_actual_config_list_shape(self):
|
|
23
|
+
config = {"modelRoles": {"value": {"bizar_build": "@task"}, "type": "record", "description": "roles"},
|
|
24
|
+
"task.agentModelOverrides": {"value": {"Builder": "@bizar_build"}, "type": "record"}}
|
|
25
|
+
self.assertTrue(role.audit(config, ["bizar_build"], ["Builder"])['static_ok'])
|
|
26
|
+
|
|
27
|
+
def test_dotted_settings(self):
|
|
28
|
+
config = {"modelRoles": {"review": "@slow"}, "task.agentModelOverrides": {"reviewer": "@review"}}
|
|
29
|
+
self.assertTrue(role.audit(config, [], ["reviewer"])['static_ok'])
|
|
30
|
+
|
|
31
|
+
def test_required_role_missing(self):
|
|
32
|
+
self.assertFalse(role.audit({}, ["bizar_build"], [])['static_ok'])
|
|
33
|
+
|
|
34
|
+
def test_builtin_does_not_need_mapping(self):
|
|
35
|
+
self.assertTrue(role.audit({}, ["tiny"], [])['static_ok'])
|
|
36
|
+
|
|
37
|
+
def test_unknown_role_alias(self):
|
|
38
|
+
self.assertFalse(role.audit({"modelRoles": {"build": "@unknown"}}, [], [])['static_ok'])
|
|
39
|
+
|
|
40
|
+
def test_cycle_is_explicitly_bizar_policy(self):
|
|
41
|
+
result = role.audit({"modelRoles": {"a": "@b", "b": "@a"}}, [], [])
|
|
42
|
+
self.assertIn("BIZAR_POLICY_CYCLE", [e['code'] for e in result['errors']])
|
|
43
|
+
|
|
44
|
+
def test_self_cycle(self):
|
|
45
|
+
self.assertFalse(role.audit({"modelRoles": {"a": "@a"}}, [], [])['static_ok'])
|
|
46
|
+
|
|
47
|
+
def test_legacy_alias_warning_not_error(self):
|
|
48
|
+
result = role.audit({"modelRoles": {"a": "pi/slow"}}, [], [])
|
|
49
|
+
self.assertTrue(result['static_ok'])
|
|
50
|
+
self.assertIn("LEGACY_ALIAS", [w['code'] for w in result['warnings']])
|
|
51
|
+
|
|
52
|
+
def test_model_colons_and_routes_not_misparsed_as_roles(self):
|
|
53
|
+
result = role.audit({"modelRoles": {"a": "provider/model:variant@upstream"}}, [], [])
|
|
54
|
+
self.assertTrue(result['static_ok'])
|
|
55
|
+
self.assertFalse(result['native_resolution_tested'])
|
|
56
|
+
|
|
57
|
+
def test_outer_role_effort(self):
|
|
58
|
+
self.assertEqual(role.referenced_roles("@slow:high"), ["slow"])
|
|
59
|
+
self.assertEqual(role.referenced_roles("@team.review:high"), ["team.review"])
|
|
60
|
+
self.assertEqual(role.referenced_roles("@team/review"), ["team/review"])
|
|
61
|
+
|
|
62
|
+
def test_service_tier_not_effort(self):
|
|
63
|
+
self.assertFalse(role.audit({"task": {"agentServiceTierOverrides": {"a": "high"}}}, [], ["a"])['static_ok'])
|
|
64
|
+
|
|
65
|
+
def test_valid_tier_still_not_native_qualified(self):
|
|
66
|
+
report = role.audit({"task": {"agentServiceTierOverrides": {"a": "priority"}}}, [], ["a"])
|
|
67
|
+
self.assertTrue(report['static_ok'])
|
|
68
|
+
self.assertFalse(report['native_resolution_tested'])
|
|
69
|
+
|
|
70
|
+
def test_exact_agent_names(self):
|
|
71
|
+
self.assertFalse(role.audit({"task": {"agentModelOverrides": {"A": "@slow"}}}, [], ["a"])['static_ok'])
|
|
72
|
+
|
|
73
|
+
def test_template_placeholder_rejected(self):
|
|
74
|
+
self.assertFalse(role.audit({"modelRoles": {"a": "YOUR_PROVIDER/YOUR_MODEL"}}, [], [])['static_ok'])
|
|
75
|
+
|
|
76
|
+
def test_credentials_not_echoed(self):
|
|
77
|
+
cfg = {"auth.broker.token": {"type": "string", "value": "secret-test-string"},
|
|
78
|
+
"modelRoles": {"a": "@task"}}
|
|
79
|
+
self.assertNotIn("secret-test-string", json.dumps(role.audit(cfg, [], [])))
|
|
80
|
+
|
|
81
|
+
def test_redacted_metadata(self):
|
|
82
|
+
self.assertEqual(role.get_value({"auth": {"type": "string", "redacted": True}}, "auth", None), None)
|
|
83
|
+
|
|
84
|
+
def test_bad_record_and_bad_storage(self):
|
|
85
|
+
self.assertFalse(role.audit({"modelRoles": []}, [], [])['static_ok'])
|
|
86
|
+
self.assertFalse(role.audit({"modelRoleStorage": {}}, [], [])['static_ok'])
|
|
87
|
+
|
|
88
|
+
def test_prewalk_requires_quoted_string(self):
|
|
89
|
+
self.assertFalse(role.audit({"task": {"agentPrewalk": {"a": True}}}, [], [])['static_ok'])
|
|
90
|
+
|
|
91
|
+
def test_advisor_configured_role(self):
|
|
92
|
+
cfg = {"modelRoles": {"r": "@slow"}, "task": {"agentAdvisor": {"a": "@r"}}}
|
|
93
|
+
self.assertTrue(role.audit(cfg, [], ["a"])['static_ok'])
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class CorpusTests(unittest.TestCase):
|
|
97
|
+
def setUp(self):
|
|
98
|
+
self.tmp = tempfile.TemporaryDirectory()
|
|
99
|
+
self.root = Path(self.tmp.name)
|
|
100
|
+
self.data = b"# Task\nNative modelRoles and agents.\n"
|
|
101
|
+
self.entry = {"path": "docs/task.md", "git_blob_sha1": docs.git_blob_hash(self.data), "url": "https://example.invalid/task.md"}
|
|
102
|
+
self.manifest = {"schema_version": 1, "repository": docs.REPOSITORY, "commit": "a" * 40, "files": [self.entry]}
|
|
103
|
+
self.mp = self.root / "manifest.json"
|
|
104
|
+
self.mp.write_text(json.dumps(self.manifest))
|
|
105
|
+
|
|
106
|
+
def tearDown(self):
|
|
107
|
+
self.tmp.cleanup()
|
|
108
|
+
|
|
109
|
+
def test_git_blob_format(self):
|
|
110
|
+
p = subprocess.run(["git", "hash-object", "--stdin"], input=self.data, capture_output=True, check=True)
|
|
111
|
+
self.assertEqual(docs.git_blob_hash(self.data), p.stdout.decode().strip())
|
|
112
|
+
|
|
113
|
+
def test_manifest_loaded(self):
|
|
114
|
+
self.assertEqual(docs.load_manifest(self.mp)['commit'], 'a' * 40)
|
|
115
|
+
|
|
116
|
+
def test_bad_repository_rejected(self):
|
|
117
|
+
self.manifest['repository'] = 'other/repo'
|
|
118
|
+
self.mp.write_text(json.dumps(self.manifest))
|
|
119
|
+
with self.assertRaises(docs.CorpusError):
|
|
120
|
+
docs.load_manifest(self.mp)
|
|
121
|
+
|
|
122
|
+
def test_moving_branch_pin_rejected(self):
|
|
123
|
+
self.manifest['commit'] = 'main'
|
|
124
|
+
self.mp.write_text(json.dumps(self.manifest))
|
|
125
|
+
with self.assertRaises(docs.CorpusError):
|
|
126
|
+
docs.load_manifest(self.mp)
|
|
127
|
+
|
|
128
|
+
def test_duplicate_manifest_entry_rejected(self):
|
|
129
|
+
self.manifest['files'].append(self.entry)
|
|
130
|
+
self.mp.write_text(json.dumps(self.manifest))
|
|
131
|
+
with self.assertRaises(docs.CorpusError):
|
|
132
|
+
docs.load_manifest(self.mp)
|
|
133
|
+
|
|
134
|
+
def test_path_traversal_rejected(self):
|
|
135
|
+
for name in ('../evil', '/absolute', 'docs/../evil', 'C:\\evil', 'docs//task.md', './docs/a.md'):
|
|
136
|
+
with self.subTest(name=name), self.assertRaises(docs.CorpusError):
|
|
137
|
+
docs.safe_path(self.root, name)
|
|
138
|
+
|
|
139
|
+
def test_symlink_rejected(self):
|
|
140
|
+
(self.root / 'docs').symlink_to(self.root, target_is_directory=True)
|
|
141
|
+
with self.assertRaises(docs.CorpusError):
|
|
142
|
+
docs.safe_path(self.root, 'docs/task.md')
|
|
143
|
+
|
|
144
|
+
def test_html_and_corruption_rejected(self):
|
|
145
|
+
with self.assertRaises(docs.CorpusError):
|
|
146
|
+
docs.checked_bytes(self.entry, b'<html>redirect or error</html>')
|
|
147
|
+
|
|
148
|
+
def test_missing_corpus_not_complete(self):
|
|
149
|
+
self.assertFalse(docs.verify(self.manifest, self.root)['complete'])
|
|
150
|
+
|
|
151
|
+
def test_atomic_no_overwrite(self):
|
|
152
|
+
p = self.root / 'a.md'
|
|
153
|
+
docs.write_new(p, b'one')
|
|
154
|
+
with self.assertRaises(FileExistsError):
|
|
155
|
+
docs.write_new(p, b'two')
|
|
156
|
+
self.assertEqual(p.read_bytes(), b'one')
|
|
157
|
+
|
|
158
|
+
def test_mock_http_happy_path(self):
|
|
159
|
+
with patch.object(docs, 'urlopen', return_value=io.BytesIO(self.data)) as request:
|
|
160
|
+
self.assertEqual(docs.fetch_file(self.manifest, self.entry, None), self.data)
|
|
161
|
+
self.assertIn('/' + 'a'*40 + '/docs/task.md', request.call_args.args[0].full_url)
|
|
162
|
+
|
|
163
|
+
def test_mock_http_wrong_hash(self):
|
|
164
|
+
with patch.object(docs, 'urlopen', return_value=io.BytesIO(b'wrong')):
|
|
165
|
+
with self.assertRaises(docs.CorpusError):
|
|
166
|
+
docs.fetch_file(self.manifest, self.entry, None)
|
|
167
|
+
|
|
168
|
+
def test_mock_http_timeout(self):
|
|
169
|
+
with patch.object(docs, 'urlopen', side_effect=TimeoutError('fixture timeout')):
|
|
170
|
+
with self.assertRaises(TimeoutError):
|
|
171
|
+
docs.fetch_file(self.manifest, self.entry, None)
|
|
172
|
+
|
|
173
|
+
def test_sync_and_verify(self):
|
|
174
|
+
out = self.root / 'corpus'
|
|
175
|
+
with patch.object(docs, 'urlopen', return_value=io.BytesIO(self.data)):
|
|
176
|
+
self.assertEqual(docs.sync(self.manifest, out, None)['fetched'], 1)
|
|
177
|
+
self.assertTrue(docs.verify(self.manifest, out)['complete'])
|
|
178
|
+
self.assertEqual(docs.sync(self.manifest, out, None)['reused'], 1)
|
|
179
|
+
|
|
180
|
+
def test_cli_search_read_and_partial_failure(self):
|
|
181
|
+
out = self.root / 'corpus'
|
|
182
|
+
stdout, stderr = io.StringIO(), io.StringIO()
|
|
183
|
+
with contextlib.redirect_stdout(stdout), contextlib.redirect_stderr(stderr):
|
|
184
|
+
self.assertEqual(docs.main(['--manifest',str(self.mp),'verify','--root',str(out)]),1)
|
|
185
|
+
self.assertEqual(docs.main(['--manifest',str(self.mp),'search','--root',str(out),'modelRoles']),1)
|
|
186
|
+
docs.write_new(out / 'docs/task.md', self.data)
|
|
187
|
+
with contextlib.redirect_stdout(io.StringIO()) as output:
|
|
188
|
+
self.assertEqual(docs.main(['--manifest',str(self.mp),'search','--root',str(out),'modelRoles']),0)
|
|
189
|
+
self.assertEqual(json.loads(output.getvalue())['matches'][0]['line'],2)
|
|
190
|
+
with contextlib.redirect_stdout(io.StringIO()) as output:
|
|
191
|
+
self.assertEqual(docs.main(['--manifest',str(self.mp),'read','--root',str(out),'docs/task.md','--start','2']),0)
|
|
192
|
+
self.assertIn('2: Native modelRoles',output.getvalue())
|
|
193
|
+
|
|
194
|
+
def test_local_git_end_to_end_and_drift(self):
|
|
195
|
+
repo = self.root / 'repo'
|
|
196
|
+
repo.mkdir()
|
|
197
|
+
def run(*args):
|
|
198
|
+
return subprocess.run(['git','-C',str(repo),*args],capture_output=True,check=True).stdout
|
|
199
|
+
run('init','-q')
|
|
200
|
+
run('config','user.email','fixture@example.invalid')
|
|
201
|
+
run('config','user.name','Fixture')
|
|
202
|
+
(repo / 'docs').mkdir()
|
|
203
|
+
(repo / 'docs/task.md').write_bytes(self.data)
|
|
204
|
+
run('add','docs/task.md')
|
|
205
|
+
run('commit','-qm','fixture')
|
|
206
|
+
self.manifest['commit'] = run('rev-parse','HEAD').decode().strip()
|
|
207
|
+
self.mp.write_text(json.dumps(self.manifest))
|
|
208
|
+
out = self.root / 'corpus'
|
|
209
|
+
self.assertEqual(docs.sync(self.manifest,out,repo)['fetched'],1)
|
|
210
|
+
(repo / 'docs/task.md').write_bytes(b'Changed\n')
|
|
211
|
+
run('add','docs/task.md')
|
|
212
|
+
run('commit','-qm','changed')
|
|
213
|
+
with contextlib.redirect_stdout(io.StringIO()) as output:
|
|
214
|
+
self.assertEqual(docs.main(['--manifest',str(self.mp),'drift','--repo',str(repo)]),0)
|
|
215
|
+
report=json.loads(output.getvalue())
|
|
216
|
+
self.assertFalse(report['same_commit'])
|
|
217
|
+
self.assertEqual(len(report['changed_or_missing']),1)
|
|
218
|
+
self.assertTrue(docs.verify(self.manifest,out)['complete'])
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
if __name__ == '__main__':
|
|
222
|
+
unittest.main(verbosity=2)
|