opencode-codeops 1.4.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/CHANGELOG.md +179 -0
- package/LICENSE +21 -0
- package/README.md +171 -0
- package/_shared/auto-design.md +129 -0
- package/_shared/layout-convention.md +198 -0
- package/_shared/quality-profile.md +134 -0
- package/_shared/recommendation-hardening.md +166 -0
- package/_shared/scope-expansion-control.md +176 -0
- package/_shared/spec-first-ordering.md +79 -0
- package/_shared/zero-ambiguity-gate.md +311 -0
- package/agent-templates/codebase-scout.md +17 -0
- package/agent-templates/concurrency-auditor.md +5 -0
- package/agent-templates/design-challenger.md +26 -0
- package/agent-templates/financial-integrity-auditor.md +5 -0
- package/agent-templates/perf-auditor.md +23 -0
- package/agent-templates/phase-reviewer.md +54 -0
- package/agent-templates/plan-task-executor-opus.md +46 -0
- package/agent-templates/plan-task-executor.md +43 -0
- package/agent-templates/preflight-auditor.md +45 -0
- package/agent-templates/security-auditor.md +42 -0
- package/agent-templates/semantics-reviewer.md +5 -0
- package/agent-templates/spec-test-author.md +29 -0
- package/agents/concurrency-auditor.md +15 -0
- package/agents/correctness-reviewer.md +66 -0
- package/agents/demanding-executor.md +58 -0
- package/agents/design-challenger.md +38 -0
- package/agents/executor.md +55 -0
- package/agents/explorer.md +29 -0
- package/agents/financial-integrity-auditor.md +15 -0
- package/agents/performance-auditor.md +35 -0
- package/agents/preflight-auditor.md +57 -0
- package/agents/security-auditor.md +54 -0
- package/agents/semantics-reviewer.md +15 -0
- package/agents/spec-test-author.md +41 -0
- package/bin/codeops-worktree +244 -0
- package/bin/index.mjs +106 -0
- package/bin/install-agents.mjs +453 -0
- package/bin/install-skills.mjs +466 -0
- package/bin/lib/opencode-install.mjs +185 -0
- package/install.sh +55 -0
- package/package.json +73 -0
- package/plugin/index.ts +181 -0
- package/references/domains/compiler-and-language.md +28 -0
- package/references/domains/data-and-migration.md +22 -0
- package/references/domains/distributed-and-concurrent.md +26 -0
- package/references/domains/financial-system.md +28 -0
- package/references/domains/selection.md +19 -0
- package/references/domains/web-application.md +23 -0
- package/schemas/codeops-config.schema.json +56 -0
- package/scripts/check-version.mjs +163 -0
- package/scripts/codeops-migrate.sh +355 -0
- package/scripts/codeops-roadmap-compact.sh +232 -0
- package/scripts/codeops-roadmap-sync.sh +275 -0
- package/scripts/codeops_outcomes.py +155 -0
- package/scripts/codeops_plan.py +239 -0
- package/scripts/codeops_plan_migrate.py +318 -0
- package/scripts/codeops_worktree_snapshot.py +99 -0
- package/scripts/install_agents.py +288 -0
- package/scripts/release.mjs +533 -0
- package/skills/analyze-project/SKILL.md +28 -0
- package/skills/clean-comments/SKILL.md +22 -0
- package/skills/exec-plan/SKILL.md +267 -0
- package/skills/exec-plan/commit-modes.md +113 -0
- package/skills/exec-plan/execution-protocol.md +471 -0
- package/skills/git-commit/SKILL.md +35 -0
- package/skills/github-issues/SKILL.md +38 -0
- package/skills/grill-me/SKILL.md +342 -0
- package/skills/make-plan/SKILL.md +282 -0
- package/skills/make-plan/quality-checklist.md +96 -0
- package/skills/make-plan/templates.md +535 -0
- package/skills/make-plan/zero-ambiguity-gate.md +19 -0
- package/skills/make-requirements/SKILL.md +268 -0
- package/skills/make-requirements/discovery-phases.md +255 -0
- package/skills/make-requirements/review-and-add.md +73 -0
- package/skills/make-requirements/templates.md +296 -0
- package/skills/make-requirements/zero-ambiguity-gate.md +18 -0
- package/skills/outcome-review/SKILL.md +34 -0
- package/skills/preflight/SKILL.md +310 -0
- package/skills/preflight/dimensions.md +181 -0
- package/skills/preflight/report-format.md +300 -0
- package/skills/retro-requirements/SKILL.md +218 -0
- package/skills/retro-requirements/confidence-classification.md +45 -0
- package/skills/retro-requirements/phases.md +609 -0
- package/skills/retro-requirements/triage-gate.md +135 -0
- package/skills/roadmap/SKILL.md +381 -0
- package/skills/roadmap/stage-hooks.md +80 -0
- package/skills/roadmap/template.md +200 -0
- package/skills/setup-codeops/SKILL.md +94 -0
- package/skills/setup-codeops/migration.md +106 -0
- package/skills/setup-codeops/scaffold.md +99 -0
- package/skills/setup-routing/SKILL.md +102 -0
- package/skills/setup-routing/routing.md +44 -0
- package/skills/techdocs/SKILL.md +199 -0
- package/skills/techdocs/authoring-and-update.md +178 -0
- package/skills/techdocs/templates.md +655 -0
- package/skills/techdocs/vitepress-setup.md +143 -0
- package/skills/upgrade-plan/SKILL.md +75 -0
- package/skills/upgrade-plan/content-quality-gate.md +35 -0
- package/skills/upgrade-plan/upgrade-checklists.md +107 -0
- package/standards/coding-standards-full.md +124 -0
- package/standards/coding-standards.md +64 -0
- package/standards/output-style.md +17 -0
package/package.json
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "opencode-codeops",
|
|
3
|
+
"version": "1.4.0",
|
|
4
|
+
"description": "Specification-first engineering for complex systems — CodeOps plugin for OpenCode",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=18"
|
|
8
|
+
},
|
|
9
|
+
"main": "./plugin/index.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": "./plugin/index.ts"
|
|
12
|
+
},
|
|
13
|
+
"bin": {
|
|
14
|
+
"opencode-codeops": "bin/index.mjs"
|
|
15
|
+
},
|
|
16
|
+
"scripts": {
|
|
17
|
+
"test": "node --test",
|
|
18
|
+
"typecheck": "tsc --noEmit",
|
|
19
|
+
"check:version": "node scripts/check-version.mjs",
|
|
20
|
+
"verify": "npm run typecheck && npm run test && npm run check:version",
|
|
21
|
+
"prepublishOnly": "npm run verify"
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"plugin/",
|
|
25
|
+
"skills/",
|
|
26
|
+
"_shared/",
|
|
27
|
+
"standards/",
|
|
28
|
+
"agents/",
|
|
29
|
+
"agent-templates/",
|
|
30
|
+
"scripts/",
|
|
31
|
+
"!scripts/*.test.mjs",
|
|
32
|
+
"!scripts/*.spec.test.mjs",
|
|
33
|
+
"bin/",
|
|
34
|
+
"!bin/*.test.mjs",
|
|
35
|
+
"!bin/*.spec.test.mjs",
|
|
36
|
+
"references/",
|
|
37
|
+
"schemas/",
|
|
38
|
+
"install.sh",
|
|
39
|
+
"README.md",
|
|
40
|
+
"CHANGELOG.md",
|
|
41
|
+
"LICENSE"
|
|
42
|
+
],
|
|
43
|
+
"keywords": [
|
|
44
|
+
"opencode",
|
|
45
|
+
"codeops",
|
|
46
|
+
"requirements",
|
|
47
|
+
"planning",
|
|
48
|
+
"verification",
|
|
49
|
+
"specification"
|
|
50
|
+
],
|
|
51
|
+
"license": "MIT",
|
|
52
|
+
"author": "blendsdk",
|
|
53
|
+
"publishConfig": {
|
|
54
|
+
"access": "public",
|
|
55
|
+
"registry": "https://registry.npmjs.org/"
|
|
56
|
+
},
|
|
57
|
+
"repository": {
|
|
58
|
+
"type": "git",
|
|
59
|
+
"url": "git+https://github.com/blendsdk/opencode-codeops.git"
|
|
60
|
+
},
|
|
61
|
+
"homepage": "https://github.com/blendsdk/opencode-codeops#readme",
|
|
62
|
+
"bugs": {
|
|
63
|
+
"url": "https://github.com/blendsdk/opencode-codeops/issues"
|
|
64
|
+
},
|
|
65
|
+
"peerDependencies": {
|
|
66
|
+
"@opencode-ai/plugin": "^1.18.30"
|
|
67
|
+
},
|
|
68
|
+
"devDependencies": {
|
|
69
|
+
"@opencode-ai/plugin": "1.18.30",
|
|
70
|
+
"@types/node": "^22.20.2",
|
|
71
|
+
"typescript": "^5.0.0"
|
|
72
|
+
}
|
|
73
|
+
}
|
package/plugin/index.ts
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import type { Plugin } from "@opencode-ai/plugin"
|
|
2
|
+
import { readFileSync } from "node:fs"
|
|
3
|
+
import { homedir } from "node:os"
|
|
4
|
+
import { join, dirname } from "node:path"
|
|
5
|
+
import { fileURLToPath } from "node:url"
|
|
6
|
+
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
// Package root — resolved at module load time so it is always the plugin's
|
|
9
|
+
// installed directory, regardless of the working directory at event time.
|
|
10
|
+
// PLUGIN_DIR contains this entry point (plugin/); PACKAGE_ROOT is one level
|
|
11
|
+
// above it and holds standards/, skills/, scripts/, and the agent templates.
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
const PLUGIN_DIR = dirname(fileURLToPath(import.meta.url))
|
|
14
|
+
const PACKAGE_ROOT = dirname(PLUGIN_DIR)
|
|
15
|
+
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
// The plugin's own version, read from the package it shipped in. There is no
|
|
18
|
+
// separate hardcoded version: the running plugin always reports the version of
|
|
19
|
+
// the npm package that was installed, so it cannot drift from the package.
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
const packageVersion = readPackageVersion()
|
|
22
|
+
|
|
23
|
+
/** Reads the `version` field of this package's package.json. */
|
|
24
|
+
function readPackageVersion(): string {
|
|
25
|
+
try {
|
|
26
|
+
const manifest = JSON.parse(readFileSync(join(PACKAGE_ROOT, "package.json"), "utf8"))
|
|
27
|
+
return typeof manifest.version === "string" ? manifest.version : "0.0.0"
|
|
28
|
+
} catch {
|
|
29
|
+
return "0.0.0"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
// Load standards at startup (once). Both files are injected into every session.
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
const codingStandards = readFileSync(
|
|
37
|
+
join(PACKAGE_ROOT, "standards", "coding-standards.md"),
|
|
38
|
+
"utf8"
|
|
39
|
+
)
|
|
40
|
+
const outputStyle = readFileSync(
|
|
41
|
+
join(PACKAGE_ROOT, "standards", "output-style.md"),
|
|
42
|
+
"utf8"
|
|
43
|
+
)
|
|
44
|
+
const standardsText = `${codingStandards}\n\n${outputStyle}`
|
|
45
|
+
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
// Helper — inject standards into a session without triggering an AI reply.
|
|
48
|
+
// Uses client.session.prompt with noReply: true (confirmed from OpenCode SDK).
|
|
49
|
+
// ---------------------------------------------------------------------------
|
|
50
|
+
async function injectStandards(
|
|
51
|
+
client: Parameters<Plugin>[0]["client"],
|
|
52
|
+
sessionId: string
|
|
53
|
+
): Promise<void> {
|
|
54
|
+
await client.session.prompt({
|
|
55
|
+
path: { id: sessionId },
|
|
56
|
+
body: {
|
|
57
|
+
noReply: true,
|
|
58
|
+
parts: [{ type: "text", text: standardsText }],
|
|
59
|
+
},
|
|
60
|
+
})
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// ---------------------------------------------------------------------------
|
|
64
|
+
// Helper — read the version recorded in an installed skills marker, if any.
|
|
65
|
+
// The marker (`.opencode-codeops.json`) is written by the skills installer.
|
|
66
|
+
// Its absence means the skills are not managed — for example a development
|
|
67
|
+
// symlink — so there is no version to compare against.
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
function installedSkillsVersion(skillsDir: string): string | undefined {
|
|
70
|
+
try {
|
|
71
|
+
const marker = JSON.parse(
|
|
72
|
+
readFileSync(join(skillsDir, ".opencode-codeops.json"), "utf8")
|
|
73
|
+
)
|
|
74
|
+
return typeof marker.version === "string" ? marker.version : undefined
|
|
75
|
+
} catch {
|
|
76
|
+
return undefined
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// ---------------------------------------------------------------------------
|
|
81
|
+
// Helper — warn (non-blocking) when the installed skills were written by a
|
|
82
|
+
// different CodeOps version than this plugin. The plugin and the skills are
|
|
83
|
+
// installed by separate commands, so their versions can drift; a mismatch
|
|
84
|
+
// usually means the skills need `npx opencode-codeops install-skills` again.
|
|
85
|
+
// ---------------------------------------------------------------------------
|
|
86
|
+
async function warnOnVersionSkew(
|
|
87
|
+
client: Parameters<Plugin>[0]["client"],
|
|
88
|
+
directory: string
|
|
89
|
+
): Promise<void> {
|
|
90
|
+
const skillsDirs = [
|
|
91
|
+
join(homedir(), ".config", "opencode", "skills"),
|
|
92
|
+
join(directory, ".opencode", "skills"),
|
|
93
|
+
]
|
|
94
|
+
|
|
95
|
+
for (const skillsDir of skillsDirs) {
|
|
96
|
+
const installed = installedSkillsVersion(skillsDir)
|
|
97
|
+
if (!installed || installed === packageVersion) continue
|
|
98
|
+
|
|
99
|
+
await client.app.log({
|
|
100
|
+
body: {
|
|
101
|
+
service: "codeops",
|
|
102
|
+
level: "warn",
|
|
103
|
+
message:
|
|
104
|
+
`CodeOps skills at ${skillsDir} are version ${installed}, ` +
|
|
105
|
+
`but the plugin is version ${packageVersion}. ` +
|
|
106
|
+
`Run \`npx opencode-codeops@${packageVersion} install-skills\` to match them.`,
|
|
107
|
+
},
|
|
108
|
+
})
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// ---------------------------------------------------------------------------
|
|
113
|
+
// CodeOps plugin for OpenCode
|
|
114
|
+
// Replaces: hooks/hooks.json + hook_session_context.sh + hook_marker_guard.sh
|
|
115
|
+
// ---------------------------------------------------------------------------
|
|
116
|
+
export const CodeOpsPlugin: Plugin = async ({ client, directory }) => {
|
|
117
|
+
return {
|
|
118
|
+
// -----------------------------------------------------------------------
|
|
119
|
+
// Hook 1 & 2: inject standards on session.created and session.compacted.
|
|
120
|
+
// Both are dispatched via the generic event hook.
|
|
121
|
+
// session.created → new session (Codex: startup)
|
|
122
|
+
// session.compacted → after compact (Codex: resume|compact)
|
|
123
|
+
// -----------------------------------------------------------------------
|
|
124
|
+
event: async ({ event }) => {
|
|
125
|
+
if (event.type === "session.created") {
|
|
126
|
+
const sessionId: string = (event.properties as { info: { id: string } }).info.id
|
|
127
|
+
await injectStandards(client, sessionId)
|
|
128
|
+
await warnOnVersionSkew(client, directory)
|
|
129
|
+
} else if (event.type === "session.compacted") {
|
|
130
|
+
const sessionId: string = (event.properties as { sessionID: string }).sessionID
|
|
131
|
+
await injectStandards(client, sessionId)
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
|
|
135
|
+
// -----------------------------------------------------------------------
|
|
136
|
+
// Hook 3: inject standards into the compaction context itself, so they
|
|
137
|
+
// survive through the compaction summary and are not lost mid-session.
|
|
138
|
+
// -----------------------------------------------------------------------
|
|
139
|
+
"experimental.session.compacting": async (_input, output) => {
|
|
140
|
+
output.context.push(
|
|
141
|
+
"## CodeOps Standards (always active — survive this compaction)\n\n" +
|
|
142
|
+
standardsText
|
|
143
|
+
)
|
|
144
|
+
},
|
|
145
|
+
|
|
146
|
+
// -----------------------------------------------------------------------
|
|
147
|
+
// Hook 4: export CODEOPS_PLUGIN_ROOT into every shell so skills can call
|
|
148
|
+
// scripts as: python3 "${CODEOPS_PLUGIN_ROOT}/scripts/codeops_plan.py"
|
|
149
|
+
// The value is the package root (parent of this plugin/ directory), which
|
|
150
|
+
// is where skills/, scripts/, and the other shipped assets live.
|
|
151
|
+
// -----------------------------------------------------------------------
|
|
152
|
+
"shell.env": async (_input, output) => {
|
|
153
|
+
output.env.CODEOPS_PLUGIN_ROOT = PACKAGE_ROOT
|
|
154
|
+
},
|
|
155
|
+
|
|
156
|
+
// -----------------------------------------------------------------------
|
|
157
|
+
// Hook 5: advisory guard — warn (non-blocking) if any edit tool targets
|
|
158
|
+
// codeops/.codeops.yml, which is owned exclusively by the setup-codeops
|
|
159
|
+
// skill. Equivalent to Codex PreToolUse hook_marker_guard.sh.
|
|
160
|
+
// args are on the output parameter per the OpenCode plugin type signature.
|
|
161
|
+
// -----------------------------------------------------------------------
|
|
162
|
+
"tool.execute.before": async (input, output) => {
|
|
163
|
+
const editTools = ["write", "edit", "apply_patch"]
|
|
164
|
+
if (!editTools.includes(input.tool)) return
|
|
165
|
+
|
|
166
|
+
const args = output.args as Record<string, unknown> | undefined
|
|
167
|
+
const filePath: string =
|
|
168
|
+
(args?.filePath as string | undefined) ??
|
|
169
|
+
(args?.path as string | undefined) ??
|
|
170
|
+
""
|
|
171
|
+
|
|
172
|
+
if (filePath.includes("codeops/.codeops.yml")) {
|
|
173
|
+
process.stderr.write(
|
|
174
|
+
"CodeOps warning: codeops/.codeops.yml is the layout marker and is " +
|
|
175
|
+
"owned by setup-codeops. Edit it only through the setup/migration " +
|
|
176
|
+
"workflow (run the setup-codeops skill).\n"
|
|
177
|
+
)
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
}
|
|
181
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Compiler and language ambiguity lens
|
|
2
|
+
|
|
3
|
+
Use this lens for programming languages, compilers, interpreters, query languages, schemas, protocol decoders, and systems with formal transformation semantics.
|
|
4
|
+
|
|
5
|
+
## Semantic closure checklist
|
|
6
|
+
|
|
7
|
+
- Source encoding, lexical rules, whitespace/comments, reserved words, and error recovery
|
|
8
|
+
- Complete grammar, precedence, associativity, ambiguity resolution, and parse-tree shape
|
|
9
|
+
- Namespaces, scopes, shadowing, imports, visibility, forward references, and cycles
|
|
10
|
+
- Type formation, equivalence, subtyping/coercion, inference, polymorphism, constraints, and error types
|
|
11
|
+
- Compile-time versus runtime behavior and phase ordering
|
|
12
|
+
- Constant evaluation, effects, evaluation order, overflow, undefined behavior, and determinism
|
|
13
|
+
- Ownership/lifetime/resource semantics where applicable
|
|
14
|
+
- IR invariants at every level and preservation between lowering passes
|
|
15
|
+
- Optimization preconditions and semantic-equivalence obligations
|
|
16
|
+
- Linking, modules, ABI, serialization, and version compatibility
|
|
17
|
+
- Diagnostics: location, recovery, cascades, stability, and machine-readable forms
|
|
18
|
+
- Incremental/parallel compilation invalidation and cache correctness
|
|
19
|
+
- Tooling contracts: formatter, language server, debugger, package manager, and build system
|
|
20
|
+
- Conformance, golden, differential, property, fuzz, and invalid-program tests
|
|
21
|
+
|
|
22
|
+
## Required counterexamples
|
|
23
|
+
|
|
24
|
+
For each semantic rule, seek minimal examples at boundaries: empty forms, recursive/cyclic forms, shadowing, ambiguous parses, conflicting constraints, order-sensitive effects, overflow, invalid encodings, partial programs, and cross-module interactions. A prose rule is incomplete until examples distinguish it from plausible alternatives.
|
|
25
|
+
|
|
26
|
+
## Gate
|
|
27
|
+
|
|
28
|
+
The semantics gate fails when two conforming implementations could produce observably different results from the same valid program/input, or when invalid input lacks a defined rejection/recovery class, unless that freedom is explicitly part of the language contract.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Data and migration ambiguity lens
|
|
2
|
+
|
|
3
|
+
Use this lens for persistent schemas, imports/exports, migrations, indexing, backfills, retention, and data-model changes.
|
|
4
|
+
|
|
5
|
+
## Data lifecycle checklist
|
|
6
|
+
|
|
7
|
+
- Entity identity, ownership, cardinality, constraints, nullability, uniqueness, and invariants
|
|
8
|
+
- Canonical representation, normalization/denormalization, units, encoding, and precision
|
|
9
|
+
- Create/update/delete/archive/restore lifecycle and referential behavior
|
|
10
|
+
- Transaction/isolation requirements and concurrent writers/readers
|
|
11
|
+
- Query access patterns, indexes, scale assumptions, and performance bounds
|
|
12
|
+
- Sensitive-data classification, encryption, access, masking, retention, deletion, and audit
|
|
13
|
+
- Schema versioning and compatibility across application versions
|
|
14
|
+
- Migration preconditions, online/offline mode, locks, batching, throttling, and checkpoints
|
|
15
|
+
- Backfill correctness, resumability, idempotency, validation, and repair
|
|
16
|
+
- Rollforward, rollback, irreversible steps, backups, restore proof, and disaster recovery
|
|
17
|
+
- Import validation, duplicate/collision rules, partial files, and provenance
|
|
18
|
+
- Derived data/cache/index rebuild and consistency checks
|
|
19
|
+
|
|
20
|
+
## Gate
|
|
21
|
+
|
|
22
|
+
The gate fails until every migration has measurable pre/postconditions, bounded operational impact, resumable/idempotent behavior, verification, and a recovery path appropriate to irreversibility and data criticality.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Distributed and concurrent system ambiguity lens
|
|
2
|
+
|
|
3
|
+
Use this lens for multiple threads/processes/nodes, queues, actors, workflows, replicated state, caches, background jobs, and asynchronous integrations.
|
|
4
|
+
|
|
5
|
+
## Concurrency and failure checklist
|
|
6
|
+
|
|
7
|
+
- State ownership, mutation authority, synchronization, and atomicity boundaries
|
|
8
|
+
- Ordering guarantees per key, partition, stream, request, and observer
|
|
9
|
+
- Delivery semantics, deduplication, idempotency, replay, and poison-message behavior
|
|
10
|
+
- Consistency model, visibility, stale reads, conflict resolution, and convergence
|
|
11
|
+
- Transactions across resources, outbox/inbox, sagas, compensation, and orphan recovery
|
|
12
|
+
- Timeout, cancellation, deadline propagation, retries, backoff, jitter, and retry budgets
|
|
13
|
+
- Leader election, leases, fencing tokens, split brain, and clock assumptions
|
|
14
|
+
- Backpressure, admission control, queue bounds, overload, fairness, and starvation
|
|
15
|
+
- Deadlock/livelock/race prevention and safe shutdown
|
|
16
|
+
- Partial availability, dependency degradation, circuit breaking, and health semantics
|
|
17
|
+
- Schema/protocol evolution with mixed-version participants
|
|
18
|
+
- Observability and correlation sufficient to reconstruct distributed outcomes
|
|
19
|
+
|
|
20
|
+
## Required interleavings
|
|
21
|
+
|
|
22
|
+
Specify and test at least: concurrent duplicate requests, read during write, fail before/after durable commit, timeout with unknown outcome, retry on a different node, reordered delivery, delayed stale worker, partition and heal, cancellation during side effect, and rolling mixed-version deployment.
|
|
23
|
+
|
|
24
|
+
## Gate
|
|
25
|
+
|
|
26
|
+
The gate fails when correctness relies on unstated timing, a single delivery, synchronized clocks, failure-free dependencies, or process-local state that is not process-local in deployment.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Financial-system ambiguity lens
|
|
2
|
+
|
|
3
|
+
Use this lens whenever the system records, calculates, authorizes, transfers, reconciles, reports, or audits monetary value or financially consequential state.
|
|
4
|
+
|
|
5
|
+
## Integrity closure checklist
|
|
6
|
+
|
|
7
|
+
- Ledger model, account types, posting rules, balancing invariants, and immutable history
|
|
8
|
+
- Currency identity, minor units, decimal precision, rounding mode, allocation, and residual handling
|
|
9
|
+
- Effective, posting, settlement, and event timestamps with timezone and business-day rules
|
|
10
|
+
- Idempotency keys, duplicate detection windows, replay behavior, and exactly-once claims
|
|
11
|
+
- Transaction boundaries, isolation, locking, partial failure, rollback, retry, and compensation
|
|
12
|
+
- Authorization, limits, approvals, segregation of duties, and credential/recovery flows
|
|
13
|
+
- Holds, reservations, pending/posted/failed/reversed state transitions
|
|
14
|
+
- Reversal, refund, chargeback, correction, backdating, and restatement semantics
|
|
15
|
+
- Fees, taxes, rates, rate sources, rate timestamps, and rounding order
|
|
16
|
+
- Reconciliation sources, tolerances, unmatched items, dispute handling, and repair authority
|
|
17
|
+
- Audit event completeness, immutability, provenance, retention, and privacy
|
|
18
|
+
- Overflow, negative values, zero, extreme scale, and malformed/external data
|
|
19
|
+
- Reporting consistency, close periods, snapshots, and historical reproducibility
|
|
20
|
+
- Regulatory, jurisdictional, and data-residency constraints explicitly supplied by qualified owners
|
|
21
|
+
|
|
22
|
+
## Required failure narratives
|
|
23
|
+
|
|
24
|
+
Specify observable state after every boundary failure: request timeout before/after commit, duplicate delivery, dependency outage, partial batch, stale authorization, concurrency conflict, reconciliation mismatch, and crash during recovery. “Retry” is not a complete rule without idempotency and state-observation semantics.
|
|
25
|
+
|
|
26
|
+
## Gate
|
|
27
|
+
|
|
28
|
+
The financial-integrity gate fails until every value-changing operation preserves its accounting invariants under duplication, concurrency, failure, retry, reversal, and audit reconstruction.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Domain-lens selection
|
|
2
|
+
|
|
3
|
+
Before requirements discovery and again before specification preflight, classify the system using repository evidence and user intent. Select every applicable lens; complex systems commonly require several.
|
|
4
|
+
|
|
5
|
+
| Evidence | Lens |
|
|
6
|
+
|---|---|
|
|
7
|
+
| Grammar, parser, IR, optimizer, type checker, evaluator, query planner, protocol codec | compiler and language |
|
|
8
|
+
| Money, balances, invoices, payments, pricing, tax, ledger, reconciliation | financial system |
|
|
9
|
+
| Browser UI, HTTP API, sessions, roles, tenant resources | web application |
|
|
10
|
+
| Threads, workers, queues, events, replicas, workflows, caches, multiple nodes | distributed and concurrent |
|
|
11
|
+
| Persistent schema, migration, backfill, import/export, retention, serialized artifacts, durable caches, file/protocol format evolution, or mixed-version compatibility | data and migration |
|
|
12
|
+
|
|
13
|
+
Treat compatibility language as evidence, not decoration. If an old artifact,
|
|
14
|
+
database, cache entry, message, module, or client must continue to work after a
|
|
15
|
+
change, select **data and migration** and define the version boundary, upgrade or
|
|
16
|
+
invalidation path, rollback behavior, and mixed-version window. An artifact does
|
|
17
|
+
not need to be a database row for evolution semantics to matter.
|
|
18
|
+
|
|
19
|
+
Always apply universal CodeOps ambiguity categories as well. Domain lenses add questions; they never replace scope, actors, failure behavior, security, quality attributes, traceability, or verification.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Web application ambiguity lens
|
|
2
|
+
|
|
3
|
+
Use this lens for browser applications, HTTP APIs, mobile backends, and user-facing network services.
|
|
4
|
+
|
|
5
|
+
## Behavior and boundary checklist
|
|
6
|
+
|
|
7
|
+
- Actors, roles, tenant boundaries, resource ownership, authorization matrix, and administrative exceptions
|
|
8
|
+
- Authentication, session/token lifecycle, revocation, recovery, MFA, and device behavior
|
|
9
|
+
- API request/response schemas, validation, errors, pagination, filtering, ordering, idempotency, and versioning
|
|
10
|
+
- UI states: initial, loading, empty, partial, success, stale, offline, unauthorized, forbidden, validation error, and server failure
|
|
11
|
+
- State transitions, optimistic updates, retries, duplicate submission, and conflict resolution
|
|
12
|
+
- Accessibility: semantics, keyboard, focus, announcements, contrast, motion, and error association
|
|
13
|
+
- Responsive/browser/device support and localization/timezone behavior
|
|
14
|
+
- Caching layers, invalidation, privacy, consistency, and stale-data UX
|
|
15
|
+
- File/upload/download handling and untrusted content
|
|
16
|
+
- CSRF, XSS, injection, SSRF, redirect, cookie, CORS, CSP, and rate-limit boundaries
|
|
17
|
+
- Background jobs, notifications, webhooks, scheduling, and eventual-consistency visibility
|
|
18
|
+
- Observability, privacy-safe logging, support diagnostics, feature flags, rollout, and rollback
|
|
19
|
+
- Deployment compatibility, migrations, zero-downtime constraints, and client skew
|
|
20
|
+
|
|
21
|
+
## Gate
|
|
22
|
+
|
|
23
|
+
The web gate fails when any actor/action/resource combination lacks an authorization result, any user-visible transition lacks a defined state, or any network operation lacks validation, error, retry/idempotency, and stale/concurrent behavior appropriate to its risk.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://github.com/blendsdk/codex-codeops/schemas/codeops-config.schema.json",
|
|
4
|
+
"title": "CodeOps project configuration",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": ["schema", "mode", "artifacts"],
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"properties": {
|
|
9
|
+
"schema": {"const": 1},
|
|
10
|
+
"mode": {"enum": ["strict", "adaptive"]},
|
|
11
|
+
"artifacts": {
|
|
12
|
+
"type": "object",
|
|
13
|
+
"required": ["layout", "root"],
|
|
14
|
+
"additionalProperties": false,
|
|
15
|
+
"properties": {
|
|
16
|
+
"layout": {"enum": ["nested", "flat"]},
|
|
17
|
+
"root": {"type": "string", "minLength": 1}
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"quality": {
|
|
21
|
+
"type": "object",
|
|
22
|
+
"additionalProperties": false,
|
|
23
|
+
"properties": {
|
|
24
|
+
"independentReview": {"type": "boolean"},
|
|
25
|
+
"minimumReviewers": {"type": "integer", "minimum": 1},
|
|
26
|
+
"stopOnMajorFinding": {"type": "boolean"}
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"routing": {
|
|
30
|
+
"type": "object",
|
|
31
|
+
"additionalProperties": false,
|
|
32
|
+
"properties": {
|
|
33
|
+
"maxConcurrentAgents": {"type": "integer", "minimum": 1},
|
|
34
|
+
"roles": {
|
|
35
|
+
"type": "object",
|
|
36
|
+
"additionalProperties": {
|
|
37
|
+
"type": "object",
|
|
38
|
+
"additionalProperties": false,
|
|
39
|
+
"properties": {
|
|
40
|
+
"model": {"type": "string", "minLength": 1},
|
|
41
|
+
"effort": {"type": "string", "minLength": 1},
|
|
42
|
+
"sandbox": {"enum": ["read-only", "workspace-write", "danger-full-access"]}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
"metrics": {
|
|
49
|
+
"type": "object",
|
|
50
|
+
"additionalProperties": false,
|
|
51
|
+
"properties": {
|
|
52
|
+
"enabled": {"type": "boolean"}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Version-parity guard for the `opencode-codeops` package.
|
|
4
|
+
*
|
|
5
|
+
* The product version must exist in exactly one place: the `version` field of
|
|
6
|
+
* `package.json`. This check fails the build when that value drifts from
|
|
7
|
+
* `package-lock.json`, when it is not a plain semantic version, or when a
|
|
8
|
+
* source file hardcodes the current version instead of deriving it.
|
|
9
|
+
*
|
|
10
|
+
* The independent schema versions (the `codeops/` layout version, the artifact
|
|
11
|
+
* schema stamp, and the auto-design policy version) are intentionally unrelated
|
|
12
|
+
* to the product version and are not checked here.
|
|
13
|
+
*
|
|
14
|
+
* @module check-version
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { readFileSync, readdirSync, realpathSync } from "node:fs"
|
|
18
|
+
import { dirname, join, relative } from "node:path"
|
|
19
|
+
import { fileURLToPath } from "node:url"
|
|
20
|
+
|
|
21
|
+
import { isValidVersion } from "./release.mjs"
|
|
22
|
+
|
|
23
|
+
/** Repository root: this file lives in `<root>/scripts/`. */
|
|
24
|
+
const ROOT = dirname(dirname(fileURLToPath(import.meta.url)))
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Directories that ship code or templates and therefore must not hardcode the
|
|
28
|
+
* product version.
|
|
29
|
+
*/
|
|
30
|
+
const SCANNED_DIRS = [
|
|
31
|
+
"bin",
|
|
32
|
+
"plugin",
|
|
33
|
+
"scripts",
|
|
34
|
+
"skills",
|
|
35
|
+
"_shared",
|
|
36
|
+
"standards",
|
|
37
|
+
"agents",
|
|
38
|
+
"agent-templates",
|
|
39
|
+
"schemas",
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
/** Files that legitimately contain the version and are exempt from the scan. */
|
|
43
|
+
const EXEMPT_FILES = new Set(["package.json", "package-lock.json", "CHANGELOG.md"])
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Reads the three version declarations that must agree.
|
|
47
|
+
*
|
|
48
|
+
* @returns The package version, the lockfile root version, and the lockfile
|
|
49
|
+
* `packages[""]` version
|
|
50
|
+
*/
|
|
51
|
+
export function readVersions() {
|
|
52
|
+
const pkg = JSON.parse(readFileSync(join(ROOT, "package.json"), "utf-8"))
|
|
53
|
+
const lock = JSON.parse(readFileSync(join(ROOT, "package-lock.json"), "utf-8"))
|
|
54
|
+
return {
|
|
55
|
+
package: pkg.version,
|
|
56
|
+
lock: lock.version,
|
|
57
|
+
lockRoot: lock.packages?.[""]?.version,
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Recursively lists files under a directory.
|
|
63
|
+
*
|
|
64
|
+
* @param dir - Absolute directory to walk
|
|
65
|
+
* @returns Absolute file paths
|
|
66
|
+
*/
|
|
67
|
+
function listFiles(dir) {
|
|
68
|
+
const files = []
|
|
69
|
+
|
|
70
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
71
|
+
const full = join(dir, entry.name)
|
|
72
|
+
if (entry.isDirectory()) files.push(...listFiles(full))
|
|
73
|
+
else if (entry.isFile()) files.push(full)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return files
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Finds files that contain the version string as a whole word.
|
|
81
|
+
*
|
|
82
|
+
* @param version - Version to search for
|
|
83
|
+
* @returns Paths relative to the repository root
|
|
84
|
+
*/
|
|
85
|
+
export function findVersionLiterals(version) {
|
|
86
|
+
const pattern = new RegExp(`(?<![0-9.])${version.replace(/\./g, "\\.")}(?![0-9.])`)
|
|
87
|
+
const hits = []
|
|
88
|
+
|
|
89
|
+
for (const dir of SCANNED_DIRS) {
|
|
90
|
+
const absolute = join(ROOT, dir)
|
|
91
|
+
let files
|
|
92
|
+
try {
|
|
93
|
+
files = listFiles(absolute)
|
|
94
|
+
} catch {
|
|
95
|
+
continue
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
for (const file of files) {
|
|
99
|
+
const name = relative(ROOT, file)
|
|
100
|
+
if (EXEMPT_FILES.has(name) || name.endsWith(".test.mjs") || name.endsWith(".spec.test.mjs")) {
|
|
101
|
+
continue
|
|
102
|
+
}
|
|
103
|
+
let content
|
|
104
|
+
try {
|
|
105
|
+
content = readFileSync(file, "utf-8")
|
|
106
|
+
} catch {
|
|
107
|
+
continue
|
|
108
|
+
}
|
|
109
|
+
if (pattern.test(content)) hits.push(name)
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return hits
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Runs the parity check.
|
|
118
|
+
*
|
|
119
|
+
* @returns Process exit code; `0` when every declaration agrees
|
|
120
|
+
*/
|
|
121
|
+
export function main() {
|
|
122
|
+
const { package: pkgVersion, lock, lockRoot } = readVersions()
|
|
123
|
+
|
|
124
|
+
if (!isValidVersion(pkgVersion)) {
|
|
125
|
+
console.error(`error: package.json version is not plain semver: ${pkgVersion}`)
|
|
126
|
+
return 1
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const mismatches = []
|
|
130
|
+
if (lock !== pkgVersion) mismatches.push(`package-lock.json version=${lock}`)
|
|
131
|
+
if (lockRoot !== pkgVersion) mismatches.push(`package-lock.json packages[""]=${lockRoot}`)
|
|
132
|
+
|
|
133
|
+
if (mismatches.length > 0) {
|
|
134
|
+
console.error(`error: version drift for ${pkgVersion}: ${mismatches.join(", ")}`)
|
|
135
|
+
console.error("Run `npm install --package-lock-only` to resync the lockfile.")
|
|
136
|
+
return 1
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const literals = findVersionLiterals(pkgVersion)
|
|
140
|
+
if (literals.length > 0) {
|
|
141
|
+
console.error(
|
|
142
|
+
`error: the product version ${pkgVersion} is hardcoded in: ${literals.join(", ")}\n` +
|
|
143
|
+
"Derive it from package.json instead of copying the value."
|
|
144
|
+
)
|
|
145
|
+
return 1
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
console.log(`version ok: ${pkgVersion}`)
|
|
149
|
+
return 0
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function isMainModule() {
|
|
153
|
+
if (!process.argv[1]) return false
|
|
154
|
+
try {
|
|
155
|
+
return fileURLToPath(import.meta.url) === realpathSync(process.argv[1])
|
|
156
|
+
} catch {
|
|
157
|
+
return false
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (isMainModule()) {
|
|
162
|
+
process.exitCode = main()
|
|
163
|
+
}
|