oris-skills 2.2.2 → 3.0.1

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 (86) hide show
  1. package/.cursor-plugin/plugin.json +2 -3
  2. package/CHANGELOG.md +24 -6
  3. package/README.md +23 -59
  4. package/docs/architecture.md +15 -11
  5. package/docs/distribution.md +3 -3
  6. package/docs/maintainer-guide.md +4 -4
  7. package/docs/user-guide.md +12 -20
  8. package/package.json +3 -6
  9. package/references/conventions.md +23 -13
  10. package/references/devops.md +58 -0
  11. package/references/devops.schema.json +54 -0
  12. package/references/doc-policy.md +5 -5
  13. package/references/research.md +45 -0
  14. package/references/settings.md +11 -5
  15. package/references/settings.schema.json +10 -0
  16. package/scripts/flow/oris-flow-devops.mjs +77 -0
  17. package/scripts/flow/oris-flow-layout.mjs +0 -16
  18. package/scripts/flow/oris-flow-scan.mjs +32 -317
  19. package/scripts/flow/oris-gitignore.mjs +1 -5
  20. package/scripts/install/install-user-skills.mjs +17 -3
  21. package/scripts/install/oris-mcp.mjs +68 -0
  22. package/scripts/install/uninstall-user-skills.mjs +2 -29
  23. package/scripts/oris-skills.mjs +0 -47
  24. package/scripts/tests/run-all-tests.mjs +3 -9
  25. package/scripts/tests/test-cleanliness.mjs +54 -0
  26. package/scripts/tests/test-install-mcp.mjs +66 -0
  27. package/scripts/tests/test-oris-flow-devops.mjs +64 -0
  28. package/scripts/tests/test-oris-flow-scan.mjs +21 -91
  29. package/scripts/tests/test-routing-lifecycle.mjs +22 -53
  30. package/scripts/tests/test-schemas.mjs +17 -31
  31. package/scripts/tests/test-skill-style.mjs +5 -2
  32. package/skills/oris-flow/SKILL.md +10 -6
  33. package/skills/oris-flow/references/architecture.md +1 -1
  34. package/skills/oris-flow/references/commit.md +46 -0
  35. package/skills/oris-flow/references/criteria.md +2 -2
  36. package/skills/oris-flow/references/discover.md +2 -2
  37. package/skills/oris-flow/references/fix.md +7 -3
  38. package/skills/oris-flow/references/help.md +1 -6
  39. package/skills/oris-flow/references/implement.md +5 -3
  40. package/skills/oris-flow/references/new.md +6 -6
  41. package/skills/oris-flow/references/plan.md +7 -2
  42. package/skills/oris-flow/references/pr.md +44 -0
  43. package/skills/oris-flow/references/setup.md +28 -35
  44. package/skills/oris-flow/references/verify.md +4 -5
  45. package/agents/oris-loop-debriefer.md +0 -30
  46. package/agents/oris-loop-doctor.md +0 -32
  47. package/agents/oris-loop-executor.md +0 -35
  48. package/agents/oris-loop-verifier.md +0 -35
  49. package/references/loop-adapter.schema.json +0 -93
  50. package/references/loop-contract.md +0 -126
  51. package/references/loop.schema.json +0 -156
  52. package/references/repo-map.md +0 -51
  53. package/references/repo-map.schema.json +0 -213
  54. package/scripts/flow/oris-flow-clean-runtime.mjs +0 -182
  55. package/scripts/install/generate-agent-adapters.mjs +0 -81
  56. package/scripts/loop/oris-loop-bootstrap.mjs +0 -383
  57. package/scripts/loop/oris-loop-bundle.mjs +0 -22
  58. package/scripts/loop/oris-loop-chat.mjs +0 -396
  59. package/scripts/loop/oris-loop-demo.mjs +0 -171
  60. package/scripts/loop/oris-loop-document.mjs +0 -196
  61. package/scripts/loop/oris-loop-dry-run.mjs +0 -114
  62. package/scripts/loop/oris-loop-fixtures.mjs +0 -149
  63. package/scripts/loop/oris-loop-list.mjs +0 -81
  64. package/scripts/loop/oris-loop-paths.mjs +0 -232
  65. package/scripts/loop/oris-loop-run.mjs +0 -301
  66. package/scripts/loop/oris-loop-stop.mjs +0 -358
  67. package/scripts/loop/oris-loop-templates.mjs +0 -80
  68. package/scripts/loop/oris-loop-verify.mjs +0 -205
  69. package/scripts/tests/test-agent-adapters.mjs +0 -70
  70. package/scripts/tests/test-oris-1-0-cleanliness.mjs +0 -58
  71. package/scripts/tests/test-oris-flow-clean-runtime.mjs +0 -75
  72. package/scripts/tests/test-oris-loop-bootstrap.mjs +0 -94
  73. package/scripts/tests/test-oris-loop-document.mjs +0 -148
  74. package/scripts/tests/test-oris-loop-list.mjs +0 -74
  75. package/scripts/tests/test-oris-loop-run.mjs +0 -71
  76. package/scripts/tests/test-oris-loop-smoke.mjs +0 -120
  77. package/scripts/tests/test-oris-loop-stop.mjs +0 -432
  78. package/skills/oris-flow/references/loop-craft.md +0 -59
  79. package/skills/oris-flow/references/loop-improve.md +0 -32
  80. package/skills/oris-flow/references/loop-run.md +0 -47
  81. package/skills/oris-flow/references/loop.md +0 -56
  82. package/skills/oris-flow/templates/debriefer.md +0 -19
  83. package/skills/oris-flow/templates/doctor.md +0 -22
  84. package/skills/oris-flow/templates/executor.md +0 -25
  85. package/skills/oris-flow/templates/orchestrator.md +0 -36
  86. package/skills/oris-flow/templates/verifier.md +0 -24
@@ -1,213 +0,0 @@
1
- {
2
- "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "$id": "https://oris.dev/schemas/oris-flow-map-v1.json",
4
- "title": "Oris Flow Repository Map",
5
- "type": "object",
6
- "additionalProperties": false,
7
- "required": [
8
- "$schema",
9
- "schemaVersion",
10
- "repository",
11
- "generatedAt",
12
- "updatedAt",
13
- "setup",
14
- "sections"
15
- ],
16
- "properties": {
17
- "$schema": {
18
- "const": "https://oris.dev/schemas/oris-flow-map-v1.json"
19
- },
20
- "schemaVersion": {
21
- "const": 1
22
- },
23
- "repository": {
24
- "type": "string",
25
- "minLength": 1
26
- },
27
- "generatedAt": {
28
- "type": "string",
29
- "format": "date-time"
30
- },
31
- "updatedAt": {
32
- "type": "string",
33
- "format": "date-time"
34
- },
35
- "headSha": {
36
- "type": ["string", "null"],
37
- "description": "Commit SHA the last scan was anchored to; null outside git. Freshness = headSha vs current HEAD."
38
- },
39
- "mapVersion": {
40
- "type": "string",
41
- "minLength": 1
42
- },
43
- "projectType": {
44
- "$ref": "#/$defs/projectType"
45
- },
46
- "truncated": {
47
- "type": "boolean"
48
- },
49
- "setup": {
50
- "$ref": "#/$defs/setup"
51
- },
52
- "sections": {
53
- "$ref": "#/$defs/sections"
54
- },
55
- "stacks": {
56
- "type": "array",
57
- "items": {
58
- "$ref": "#/$defs/stack"
59
- }
60
- },
61
- "commands": {
62
- "type": "array",
63
- "items": {
64
- "$ref": "#/$defs/detectedCommand"
65
- }
66
- }
67
- },
68
- "$defs": {
69
- "confidence": {
70
- "type": "string",
71
- "enum": ["confirmed", "detected", "inferred", "stale"]
72
- },
73
- "sectionPointer": {
74
- "type": "object",
75
- "additionalProperties": false,
76
- "required": ["path", "confidence"],
77
- "properties": {
78
- "path": {
79
- "type": "string",
80
- "pattern": "^\\.oris-flow/"
81
- },
82
- "confidence": {
83
- "$ref": "#/$defs/confidence"
84
- },
85
- "lastScannedAt": {
86
- "type": "string",
87
- "format": "date-time"
88
- },
89
- "stale": {
90
- "type": "boolean"
91
- },
92
- "summary": {
93
- "type": "string"
94
- }
95
- }
96
- },
97
- "sections": {
98
- "type": "object",
99
- "additionalProperties": {
100
- "$ref": "#/$defs/sectionPointer"
101
- },
102
- "propertyNames": {
103
- "pattern": "^[a-z][a-zA-Z0-9-]*$"
104
- }
105
- },
106
- "setup": {
107
- "type": "object",
108
- "additionalProperties": false,
109
- "required": ["mode", "scanDepth"],
110
- "properties": {
111
- "mode": {
112
- "type": "string",
113
- "enum": ["create", "refresh", "review-stale", "update-area", "summary"]
114
- },
115
- "scanDepth": {
116
- "type": "string",
117
- "enum": ["fast", "balanced", "manual-summary"]
118
- },
119
- "tasksRoot": {
120
- "type": "string",
121
- "minLength": 1
122
- },
123
- "confirmedDecisions": {
124
- "type": "array",
125
- "items": {
126
- "type": "string"
127
- }
128
- },
129
- "tradeOff": {
130
- "type": "string"
131
- },
132
- "versionControl": {
133
- "type": "object",
134
- "additionalProperties": false,
135
- "properties": {
136
- "orisFlowMap": {
137
- "type": "string",
138
- "enum": ["commit", "gitignore"]
139
- }
140
- }
141
- }
142
- }
143
- },
144
- "stack": {
145
- "type": "object",
146
- "additionalProperties": false,
147
- "required": ["id", "label", "evidence"],
148
- "properties": {
149
- "id": {
150
- "type": "string",
151
- "pattern": "^[a-z][a-z0-9-]*$"
152
- },
153
- "label": {
154
- "type": "string",
155
- "minLength": 1
156
- },
157
- "evidence": {
158
- "type": "array",
159
- "items": {
160
- "type": "string"
161
- }
162
- }
163
- }
164
- },
165
- "detectedCommand": {
166
- "type": "object",
167
- "additionalProperties": false,
168
- "required": ["name", "cwd", "command", "evidence"],
169
- "properties": {
170
- "name": {
171
- "type": "string",
172
- "pattern": "^[a-z][a-z0-9-]*$"
173
- },
174
- "cwd": {
175
- "type": "string"
176
- },
177
- "command": {
178
- "type": "string"
179
- },
180
- "evidence": {
181
- "type": "string"
182
- },
183
- "confidence": {
184
- "$ref": "#/$defs/confidence"
185
- }
186
- }
187
- },
188
- "projectType": {
189
- "type": "object",
190
- "additionalProperties": false,
191
- "required": ["id", "label", "confidence"],
192
- "properties": {
193
- "id": {
194
- "type": "string",
195
- "enum": ["empty", "monorepo", "webapp", "api", "library", "cli", "unknown"]
196
- },
197
- "label": {
198
- "type": "string",
199
- "minLength": 1
200
- },
201
- "confidence": {
202
- "$ref": "#/$defs/confidence"
203
- },
204
- "evidence": {
205
- "type": "array",
206
- "items": {
207
- "type": "string"
208
- }
209
- }
210
- }
211
- }
212
- }
213
- }
@@ -1,182 +0,0 @@
1
- import fs from "node:fs";
2
- import path from "node:path";
3
- import { fileURLToPath } from "node:url";
4
- import {
5
- ORIS_FLOW_ADAPTER,
6
- ORIS_FLOW_LOOPS_ROOT,
7
- ORIS_FLOW_MANIFEST,
8
- ORIS_FLOW_MAPS_ROOT,
9
- ORIS_FLOW_RUNTIME,
10
- } from "./oris-flow-layout.mjs";
11
-
12
- const DEFAULT_RUNTIME_RELATIVE = ORIS_FLOW_RUNTIME;
13
-
14
- function readJson(filePath) {
15
- if (!fs.existsSync(filePath)) return null;
16
- return JSON.parse(fs.readFileSync(filePath, "utf8"));
17
- }
18
-
19
- function assertSafeRelativePath(relativePath, label) {
20
- const normalized = String(relativePath ?? "").replace(/\\/g, "/");
21
- if (!normalized || normalized.startsWith("/") || /^[A-Za-z]:\//.test(normalized)) {
22
- throw new Error(`${label} must be a repository-relative path.`);
23
- }
24
- if (normalized.split("/").includes("..")) {
25
- throw new Error(`${label} must not contain '..'.`);
26
- }
27
- return normalized;
28
- }
29
-
30
- function assertUnderRepository(repositoryRoot, targetPath) {
31
- const root = path.resolve(repositoryRoot);
32
- const resolved = path.resolve(targetPath);
33
- const relative = path.relative(root, resolved);
34
- if (relative.startsWith("..") || path.isAbsolute(relative)) {
35
- throw new Error(`Refusing to clean path outside repository: ${targetPath}`);
36
- }
37
- return resolved;
38
- }
39
-
40
- export function resolveCleanTargets(repositoryRoot) {
41
- const root = path.resolve(repositoryRoot);
42
- const adapter = readJson(path.join(root, ORIS_FLOW_ADAPTER));
43
- const runtimeRelative = assertSafeRelativePath(
44
- adapter?.paths?.runtime ?? DEFAULT_RUNTIME_RELATIVE,
45
- "paths.runtime",
46
- );
47
-
48
- if (runtimeRelative.replace(/\\/g, "/") === ORIS_FLOW_RUNTIME) {
49
- return [assertUnderRepository(root, path.join(root, ...ORIS_FLOW_RUNTIME.split("/")))];
50
- }
51
-
52
- return [assertUnderRepository(root, path.join(root, ...runtimeRelative.split("/")))];
53
- }
54
-
55
- function listEntries(directoryPath) {
56
- if (!fs.existsSync(directoryPath)) return [];
57
- const entries = [];
58
- const stack = [directoryPath];
59
- while (stack.length > 0) {
60
- const current = stack.pop();
61
- for (const entry of fs.readdirSync(current, { withFileTypes: true })) {
62
- const fullPath = path.join(current, entry.name);
63
- entries.push(fullPath);
64
- if (entry.isDirectory()) stack.push(fullPath);
65
- }
66
- }
67
- return entries.sort();
68
- }
69
-
70
- function removeEntry(entryPath) {
71
- if (!fs.existsSync(entryPath)) return;
72
- const stat = fs.lstatSync(entryPath);
73
- if (stat.isDirectory()) {
74
- fs.rmSync(entryPath, { recursive: true, force: true });
75
- return;
76
- }
77
- fs.rmSync(entryPath, { force: true });
78
- }
79
-
80
- export function cleanFlowRuntime(repositoryRoot, options = {}) {
81
- const root = path.resolve(repositoryRoot);
82
- const dryRun = Boolean(options.dryRun);
83
- const targets = resolveCleanTargets(root);
84
- const removed = [];
85
- const preserved = [
86
- ORIS_FLOW_MANIFEST,
87
- `${ORIS_FLOW_MAPS_ROOT}/**`,
88
- ORIS_FLOW_ADAPTER,
89
- `${ORIS_FLOW_LOOPS_ROOT}/**`,
90
- ".cursor/hooks.json",
91
- ".cursor/hooks/oris-loop-stop.mjs",
92
- ];
93
-
94
- for (const target of targets) {
95
- if (!fs.existsSync(target)) continue;
96
- const stat = fs.lstatSync(target);
97
- if (stat.isDirectory()) {
98
- for (const entry of listEntries(target)) {
99
- const relative = path.relative(root, entry).split(path.sep).join("/");
100
- if (dryRun) {
101
- removed.push(relative);
102
- } else {
103
- removeEntry(entry);
104
- removed.push(relative);
105
- }
106
- }
107
- if (dryRun) {
108
- removed.push(path.relative(root, target).split(path.sep).join("/"));
109
- } else {
110
- removeEntry(target);
111
- removed.push(path.relative(root, target).split(path.sep).join("/"));
112
- }
113
- continue;
114
- }
115
- const relative = path.relative(root, target).split(path.sep).join("/");
116
- if (dryRun) {
117
- removed.push(relative);
118
- } else {
119
- removeEntry(target);
120
- removed.push(relative);
121
- }
122
- }
123
-
124
- return {
125
- repositoryRoot: root,
126
- dryRun,
127
- targets: targets.map((target) => path.relative(root, target).split(path.sep).join("/")),
128
- removed,
129
- preserved,
130
- cleaned: removed.length > 0,
131
- };
132
- }
133
-
134
- function parseArgs(argv) {
135
- const options = {
136
- repositoryRoot: process.cwd(),
137
- dryRun: false,
138
- json: false,
139
- };
140
- for (let i = 0; i < argv.length; i += 1) {
141
- const raw = argv[i];
142
- if (raw === "--dry-run") options.dryRun = true;
143
- else if (raw === "--json") options.json = true;
144
- else if (raw.startsWith("--repository-root=")) options.repositoryRoot = raw.slice("--repository-root=".length);
145
- else if (raw === "--repository-root" && argv[i + 1]) {
146
- options.repositoryRoot = argv[i + 1];
147
- i += 1;
148
- } else if (!raw.startsWith("-")) {
149
- options.repositoryRoot = raw;
150
- }
151
- }
152
- return options;
153
- }
154
-
155
- export function printCleanReport(result) {
156
- console.log(`Oris Flow runtime clean${result.dryRun ? " (dry run)" : ""}`);
157
- console.log(`Repository: ${result.repositoryRoot}`);
158
- console.log("");
159
- console.log("Targets:");
160
- for (const target of result.targets) console.log(`- ${target}`);
161
- console.log("");
162
- if (result.removed.length === 0) {
163
- console.log("No ephemeral runtime files found.");
164
- return;
165
- }
166
- console.log(`${result.dryRun ? "Would remove" : "Removed"} ${result.removed.length} path(s):`);
167
- for (const entry of result.removed) console.log(`- ${entry}`);
168
- console.log("");
169
- console.log("Preserved by design:");
170
- for (const entry of result.preserved) console.log(`- ${entry}`);
171
- }
172
-
173
- if (process.argv[1] && path.resolve(process.argv[1]) === path.resolve(fileURLToPath(import.meta.url))) {
174
- const options = parseArgs(process.argv.slice(2));
175
- const result = cleanFlowRuntime(options.repositoryRoot, { dryRun: options.dryRun });
176
- if (options.json) {
177
- console.log(JSON.stringify(result, null, 2));
178
- } else {
179
- printCleanReport(result);
180
- }
181
- process.exit(0);
182
- }
@@ -1,81 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import fs from "node:fs";
4
- import path from "node:path";
5
- import process from "node:process";
6
- import { fileURLToPath } from "node:url";
7
-
8
- const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "..");
9
- const sourceRoot = path.join(repoRoot, "agents");
10
-
11
- function readAgent(filePath) {
12
- const text = fs.readFileSync(filePath, "utf8");
13
- const match = text.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);
14
- if (!match) throw new Error(`Agent file is missing front matter: ${filePath}`);
15
- const frontMatter = Object.fromEntries(
16
- match[1]
17
- .split(/\r?\n/)
18
- .map((line) => line.trim())
19
- .filter(Boolean)
20
- .map((line) => {
21
- const index = line.indexOf(":");
22
- if (index < 0) throw new Error(`Unsupported front matter line in ${filePath}: ${line}`);
23
- return [line.slice(0, index).trim(), line.slice(index + 1).trim()];
24
- }),
25
- );
26
- return { frontMatter, body: match[2].trim() };
27
- }
28
-
29
- function writeFile(filePath, content) {
30
- fs.mkdirSync(path.dirname(filePath), { recursive: true });
31
- fs.writeFileSync(filePath, `${content.trimEnd()}\n`, "utf8");
32
- }
33
-
34
- function renderMarkdownAgent(agent) {
35
- return `---
36
- name: ${agent.frontMatter.name}
37
- description: ${agent.frontMatter.description}
38
- readonly: ${agent.frontMatter.readonly ?? "false"}
39
- ---
40
-
41
- ${agent.body}
42
- `;
43
- }
44
-
45
- function renderCodexAgent(agent) {
46
- const name = JSON.stringify(agent.frontMatter.name);
47
- const description = JSON.stringify(agent.frontMatter.description);
48
- const instructions = JSON.stringify(agent.body);
49
- return `name = ${name}
50
- description = ${description}
51
- developer_instructions = ${instructions}
52
- `;
53
- }
54
-
55
- function readAgents() {
56
- return fs.readdirSync(sourceRoot)
57
- .filter((name) => name.endsWith(".md"))
58
- .map((name) => ({ name, ...readAgent(path.join(sourceRoot, name)) }));
59
- }
60
-
61
- /**
62
- * Write adapters into repo-local .cursor/.claude/.codex dirs under root.
63
- * Development-only: the installer never copies these into user agent homes —
64
- * loop roles are internal and reach subagents via per-loop prompts/<role>.md files.
65
- */
66
- export function generateAgentAdapters(root = repoRoot) {
67
- const agents = readAgents();
68
- for (const agent of agents) {
69
- writeFile(path.join(root, ".cursor", "agents", agent.name), renderMarkdownAgent(agent));
70
- writeFile(path.join(root, ".claude", "agents", agent.name), renderMarkdownAgent(agent));
71
- writeFile(path.join(root, ".codex", "agents", agent.name.replace(/\.md$/, ".toml")), renderCodexAgent(agent));
72
- }
73
- return agents.map((agent) => agent.frontMatter.name);
74
- }
75
-
76
- if (process.argv[1] && path.resolve(process.argv[1]) === path.resolve(fileURLToPath(import.meta.url))) {
77
- const rootArg = process.argv.find((arg) => arg.startsWith("--root="));
78
- const root = rootArg ? path.resolve(rootArg.slice("--root=".length)) : repoRoot;
79
- const generated = generateAgentAdapters(root);
80
- console.log(JSON.stringify({ generated }, null, 2));
81
- }