role-os 1.6.0 → 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/CHANGELOG.md +24 -0
- package/README.md +2 -1
- package/bin/roleos.mjs +8 -0
- package/package.json +1 -1
- package/src/artifacts-cmd.mjs +180 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.7.0
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
#### Completion Proof (Phase R)
|
|
8
|
+
- `roleos artifacts` CLI command: list, show, validate, chain subcommands
|
|
9
|
+
- 13 new CLI integration tests for artifact inspection
|
|
10
|
+
- Real task completion missions through the full stack
|
|
11
|
+
|
|
12
|
+
#### Completion Proof Evidence
|
|
13
|
+
- R1-1 Feature mission: `roleos artifacts` command shipped through feature pack
|
|
14
|
+
- Pack: feature (high confidence, correct)
|
|
15
|
+
- Chain: 5 roles, 0 escalations, 1 minor correction
|
|
16
|
+
- Artifact contracts: all 4 used and valid
|
|
17
|
+
- R1-2 Bugfix mission: README.zh.md npm anomaly
|
|
18
|
+
- Diagnosed correctly: npm auto-includes README* regardless of files field
|
|
19
|
+
- Escalated honestly: fix requires structural decision (translation file organization)
|
|
20
|
+
- Not force-closed: deferred to treatment pass
|
|
21
|
+
|
|
22
|
+
### Evidence
|
|
23
|
+
- 398 tests, zero failures
|
|
24
|
+
- 3 missions run through the full stack
|
|
25
|
+
- Completion metrics recorded per mission
|
|
26
|
+
|
|
3
27
|
## 1.6.0
|
|
4
28
|
|
|
5
29
|
### Added
|
package/README.md
CHANGED
|
@@ -192,7 +192,8 @@ Role OS operates **locally only**. It copies markdown templates and writes packe
|
|
|
192
192
|
- v1.3.0: Outcome calibration, mixed-task decomposition, composite execution, adaptive replanning. 317 tests.
|
|
193
193
|
- v1.4.0: Session spine — `roleos init claude`, `roleos doctor`, route cards, /roleos-route + /roleos-review + /roleos-status commands. 335 tests.
|
|
194
194
|
- v1.5.0: Hook spine — 5 lifecycle hooks for runtime enforcement. 358 tests.
|
|
195
|
-
-
|
|
195
|
+
- v1.6.0: Artifact spine — 20 per-role artifact contracts, 7 pack handoff contracts, structural validation. 385 tests.
|
|
196
|
+
- **v1.7.0**: Completion proof — real tasks run through the full stack. `roleos artifacts` CLI. Honest escalation on structural fixes. 398 tests.
|
|
196
197
|
|
|
197
198
|
## License
|
|
198
199
|
|
package/bin/roleos.mjs
CHANGED
|
@@ -10,6 +10,7 @@ import { reviewCommand } from "../src/review.mjs";
|
|
|
10
10
|
import { statusCommand } from "../src/status.mjs";
|
|
11
11
|
import { packsCommand } from "../src/packs-cmd.mjs";
|
|
12
12
|
import { scaffoldClaude, doctor, formatDoctor } from "../src/session.mjs";
|
|
13
|
+
import { artifactsCommand } from "../src/artifacts-cmd.mjs";
|
|
13
14
|
|
|
14
15
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
15
16
|
const VERSION = JSON.parse(readFileSync(join(__dirname, "..", "package.json"), "utf-8")).version;
|
|
@@ -30,6 +31,10 @@ Usage:
|
|
|
30
31
|
roleos packs list List all available team packs
|
|
31
32
|
roleos packs suggest <packet-file> Suggest a pack for a packet
|
|
32
33
|
roleos packs show <pack-key> Show full detail for a named pack
|
|
34
|
+
roleos artifacts List all role artifact contracts
|
|
35
|
+
roleos artifacts show <role> Show artifact contract for a role
|
|
36
|
+
roleos artifacts validate <role> <file> Validate a file against a contract
|
|
37
|
+
roleos artifacts chain <pack> Show pack handoff flow
|
|
33
38
|
roleos doctor Verify repo is wired for Role OS sessions
|
|
34
39
|
roleos help Show this help
|
|
35
40
|
|
|
@@ -103,6 +108,9 @@ try {
|
|
|
103
108
|
case "packs":
|
|
104
109
|
await packsCommand(args);
|
|
105
110
|
break;
|
|
111
|
+
case "artifacts":
|
|
112
|
+
await artifactsCommand(args);
|
|
113
|
+
break;
|
|
106
114
|
case "help":
|
|
107
115
|
case "--help":
|
|
108
116
|
case "-h":
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "role-os",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0",
|
|
4
4
|
"description": "Role OS — a multi-Claude operating system where 31 specialized roles execute work through contracts, conflict detection, escalation, and structured evidence. 7 proven team packs for common task families.",
|
|
5
5
|
"homepage": "https://mcp-tool-shop-org.github.io/role-os/",
|
|
6
6
|
"bugs": {
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI surface for artifact contracts — roleos artifacts
|
|
3
|
+
*
|
|
4
|
+
* Subcommands:
|
|
5
|
+
* - artifacts (bare) — list all roles with contracts
|
|
6
|
+
* - artifacts show <role> — display artifact contract
|
|
7
|
+
* - artifacts validate <role> <file> — validate file against contract
|
|
8
|
+
* - artifacts chain <pack> — show pack handoff flow
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { readFileSync, existsSync } from "node:fs";
|
|
12
|
+
import {
|
|
13
|
+
ROLE_ARTIFACT_CONTRACTS,
|
|
14
|
+
PACK_HANDOFF_CONTRACTS,
|
|
15
|
+
validateArtifact,
|
|
16
|
+
getArtifactContract,
|
|
17
|
+
getHandoffContract,
|
|
18
|
+
formatArtifactValidation,
|
|
19
|
+
formatPackChain,
|
|
20
|
+
validatePackChain,
|
|
21
|
+
} from "./artifacts.mjs";
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Main command handler.
|
|
25
|
+
* @param {string[]} args
|
|
26
|
+
*/
|
|
27
|
+
export async function artifactsCommand(args) {
|
|
28
|
+
const sub = args[0];
|
|
29
|
+
|
|
30
|
+
if (!sub || sub === "list") {
|
|
31
|
+
runList();
|
|
32
|
+
} else if (sub === "show") {
|
|
33
|
+
runShow(args.slice(1));
|
|
34
|
+
} else if (sub === "validate") {
|
|
35
|
+
runValidate(args.slice(1));
|
|
36
|
+
} else if (sub === "chain") {
|
|
37
|
+
runChain(args.slice(1));
|
|
38
|
+
} else {
|
|
39
|
+
const err = new Error(`Unknown artifacts subcommand: "${sub}"`);
|
|
40
|
+
err.exitCode = 1;
|
|
41
|
+
err.hint = "Valid subcommands: list, show <role>, validate <role> <file>, chain <pack>";
|
|
42
|
+
throw err;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function runList() {
|
|
47
|
+
const roles = Object.entries(ROLE_ARTIFACT_CONTRACTS);
|
|
48
|
+
console.log(`\nRole artifact contracts (${roles.length} roles)\n`);
|
|
49
|
+
console.log(`${"Role".padEnd(25)} ${"Artifact Type".padEnd(22)} ${"Required".padEnd(8)} Consumed By`);
|
|
50
|
+
console.log(`${"─".repeat(25)} ${"─".repeat(22)} ${"─".repeat(8)} ${"─".repeat(30)}`);
|
|
51
|
+
|
|
52
|
+
for (const [role, contract] of roles) {
|
|
53
|
+
const consumers = contract.consumedBy.length > 0 ? contract.consumedBy.join(", ") : "terminal";
|
|
54
|
+
console.log(
|
|
55
|
+
`${role.padEnd(25)} ${contract.artifactType.padEnd(22)} ${String(contract.requiredSections.length).padEnd(8)} ${consumers}`
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function runShow(args) {
|
|
61
|
+
if (args.length === 0) {
|
|
62
|
+
const err = new Error("Missing role name.");
|
|
63
|
+
err.exitCode = 1;
|
|
64
|
+
err.hint = "Usage: roleos artifacts show <role-name>";
|
|
65
|
+
throw err;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const input = args.join(" ");
|
|
69
|
+
const roleName = resolveRoleName(input);
|
|
70
|
+
if (!roleName) {
|
|
71
|
+
const err = new Error(`No artifact contract for role "${input}".`);
|
|
72
|
+
err.exitCode = 1;
|
|
73
|
+
err.hint = `Available roles: ${Object.keys(ROLE_ARTIFACT_CONTRACTS).join(", ")}`;
|
|
74
|
+
throw err;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const contract = getArtifactContract(roleName);
|
|
78
|
+
|
|
79
|
+
console.log(`\nArtifact Contract — ${roleName}\n`);
|
|
80
|
+
console.log(`Type: ${contract.artifactType}`);
|
|
81
|
+
console.log(`Required sections: ${contract.requiredSections.join(", ")}`);
|
|
82
|
+
if (contract.optionalSections.length > 0) {
|
|
83
|
+
console.log(`Optional sections: ${contract.optionalSections.join(", ")}`);
|
|
84
|
+
}
|
|
85
|
+
if (contract.requiredEvidence.length > 0) {
|
|
86
|
+
console.log(`Required evidence: ${contract.requiredEvidence.join(", ")}`);
|
|
87
|
+
}
|
|
88
|
+
console.log(`Consumed by: ${contract.consumedBy.length > 0 ? contract.consumedBy.join(", ") : "terminal (no downstream consumer)"}`);
|
|
89
|
+
console.log(`Completion rule: ${contract.completionRule}`);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function runValidate(args) {
|
|
93
|
+
if (args.length < 2) {
|
|
94
|
+
const err = new Error("Missing arguments.");
|
|
95
|
+
err.exitCode = 1;
|
|
96
|
+
err.hint = "Usage: roleos artifacts validate <role-name> <file-path>";
|
|
97
|
+
throw err;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Last arg is the file, everything before is the role name
|
|
101
|
+
const filePath = args[args.length - 1];
|
|
102
|
+
const roleArgs = args.slice(0, -1);
|
|
103
|
+
const roleName = resolveRoleName(roleArgs.join(" "));
|
|
104
|
+
|
|
105
|
+
if (!roleName) {
|
|
106
|
+
const err = new Error(`Unknown role: "${roleArgs.join(" ")}".`);
|
|
107
|
+
err.exitCode = 1;
|
|
108
|
+
err.hint = `Available roles: ${Object.keys(ROLE_ARTIFACT_CONTRACTS).join(", ")}`;
|
|
109
|
+
throw err;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (!existsSync(filePath)) {
|
|
113
|
+
const err = new Error(`File not found: "${filePath}".`);
|
|
114
|
+
err.exitCode = 1;
|
|
115
|
+
err.hint = "Provide a path to the artifact file to validate.";
|
|
116
|
+
throw err;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const content = readFileSync(filePath, "utf-8");
|
|
120
|
+
const validation = validateArtifact(roleName, content);
|
|
121
|
+
console.log(formatArtifactValidation(roleName, validation));
|
|
122
|
+
|
|
123
|
+
if (!validation.valid) {
|
|
124
|
+
process.exitCode = 1;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function runChain(args) {
|
|
129
|
+
const packName = args[0];
|
|
130
|
+
if (!packName) {
|
|
131
|
+
const err = new Error("Missing pack name.");
|
|
132
|
+
err.exitCode = 1;
|
|
133
|
+
err.hint = `Usage: roleos artifacts chain <pack-name>. Available: ${Object.keys(PACK_HANDOFF_CONTRACTS).join(", ")}`;
|
|
134
|
+
throw err;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const contract = getHandoffContract(packName);
|
|
138
|
+
if (!contract) {
|
|
139
|
+
const err = new Error(`No handoff contract for pack "${packName}".`);
|
|
140
|
+
err.exitCode = 1;
|
|
141
|
+
err.hint = `Available packs: ${Object.keys(PACK_HANDOFF_CONTRACTS).join(", ")}`;
|
|
142
|
+
throw err;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
console.log(`\nHandoff Contract — ${packName} pack\n`);
|
|
146
|
+
console.log(`${"Step".padEnd(5)} ${"Role".padEnd(25)} ${"Produces".padEnd(22)} Consumed By`);
|
|
147
|
+
console.log(`${"─".repeat(5)} ${"─".repeat(25)} ${"─".repeat(22)} ${"─".repeat(25)}`);
|
|
148
|
+
|
|
149
|
+
contract.flow.forEach((step, i) => {
|
|
150
|
+
const consumer = step.consumedBy || "terminal";
|
|
151
|
+
console.log(
|
|
152
|
+
`${String(i + 1).padEnd(5)} ${step.role.padEnd(25)} ${step.produces.padEnd(22)} ${consumer}`
|
|
153
|
+
);
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Resolve a role name from user input.
|
|
159
|
+
* Handles both exact names ("Product Strategist") and slug forms ("product-strategist").
|
|
160
|
+
*/
|
|
161
|
+
function resolveRoleName(input) {
|
|
162
|
+
if (!input || !input.trim()) return null;
|
|
163
|
+
const trimmed = input.trim();
|
|
164
|
+
|
|
165
|
+
// Exact match
|
|
166
|
+
if (ROLE_ARTIFACT_CONTRACTS[trimmed]) return trimmed;
|
|
167
|
+
|
|
168
|
+
// Case-insensitive match
|
|
169
|
+
for (const role of Object.keys(ROLE_ARTIFACT_CONTRACTS)) {
|
|
170
|
+
if (role.toLowerCase() === trimmed.toLowerCase()) return role;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Slug match (product-strategist → Product Strategist)
|
|
174
|
+
const slugToName = trimmed.replace(/-/g, " ");
|
|
175
|
+
for (const role of Object.keys(ROLE_ARTIFACT_CONTRACTS)) {
|
|
176
|
+
if (role.toLowerCase() === slugToName.toLowerCase()) return role;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return null;
|
|
180
|
+
}
|