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 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
- - **v1.6.0**: Artifact spine — 20 per-role artifact contracts, 7 pack handoff contracts, structural validation, chain completeness checks. 385 tests.
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.6.0",
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
+ }