@calibrate-ds/cli 0.1.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/dist/__tests__/component-slug.test.d.ts +2 -0
- package/dist/__tests__/component-slug.test.d.ts.map +1 -0
- package/dist/__tests__/component-slug.test.js +54 -0
- package/dist/__tests__/component-slug.test.js.map +1 -0
- package/dist/__tests__/lock-changes.test.d.ts +2 -0
- package/dist/__tests__/lock-changes.test.d.ts.map +1 -0
- package/dist/__tests__/lock-changes.test.js +81 -0
- package/dist/__tests__/lock-changes.test.js.map +1 -0
- package/dist/__tests__/permissions.test.d.ts +2 -0
- package/dist/__tests__/permissions.test.d.ts.map +1 -0
- package/dist/__tests__/permissions.test.js +67 -0
- package/dist/__tests__/permissions.test.js.map +1 -0
- package/dist/__tests__/stamp-in-lock.test.d.ts +2 -0
- package/dist/__tests__/stamp-in-lock.test.d.ts.map +1 -0
- package/dist/__tests__/stamp-in-lock.test.js +102 -0
- package/dist/__tests__/stamp-in-lock.test.js.map +1 -0
- package/dist/__tests__/status-logic.test.d.ts +2 -0
- package/dist/__tests__/status-logic.test.d.ts.map +1 -0
- package/dist/__tests__/status-logic.test.js +74 -0
- package/dist/__tests__/status-logic.test.js.map +1 -0
- package/dist/__tests__/team-roster.test.d.ts +2 -0
- package/dist/__tests__/team-roster.test.d.ts.map +1 -0
- package/dist/__tests__/team-roster.test.js +97 -0
- package/dist/__tests__/team-roster.test.js.map +1 -0
- package/dist/ai/claude-provider.d.ts +13 -0
- package/dist/ai/claude-provider.d.ts.map +1 -0
- package/dist/ai/claude-provider.js +335 -0
- package/dist/ai/claude-provider.js.map +1 -0
- package/dist/ai/enhance-doc.d.ts +24 -0
- package/dist/ai/enhance-doc.d.ts.map +1 -0
- package/dist/ai/enhance-doc.js +272 -0
- package/dist/ai/enhance-doc.js.map +1 -0
- package/dist/ai/openai-provider.d.ts +13 -0
- package/dist/ai/openai-provider.d.ts.map +1 -0
- package/dist/ai/openai-provider.js +345 -0
- package/dist/ai/openai-provider.js.map +1 -0
- package/dist/ai/prompt-utils.d.ts +23 -0
- package/dist/ai/prompt-utils.d.ts.map +1 -0
- package/dist/ai/prompt-utils.js +67 -0
- package/dist/ai/prompt-utils.js.map +1 -0
- package/dist/commands/ai.d.ts +8 -0
- package/dist/commands/ai.d.ts.map +1 -0
- package/dist/commands/ai.js +576 -0
- package/dist/commands/ai.js.map +1 -0
- package/dist/commands/apply.d.ts +4 -0
- package/dist/commands/apply.d.ts.map +1 -0
- package/dist/commands/apply.js +98 -0
- package/dist/commands/apply.js.map +1 -0
- package/dist/commands/assign.d.ts +5 -0
- package/dist/commands/assign.d.ts.map +1 -0
- package/dist/commands/assign.js +180 -0
- package/dist/commands/assign.js.map +1 -0
- package/dist/commands/ci.d.ts +4 -0
- package/dist/commands/ci.d.ts.map +1 -0
- package/dist/commands/ci.js +84 -0
- package/dist/commands/ci.js.map +1 -0
- package/dist/commands/context.d.ts +19 -0
- package/dist/commands/context.d.ts.map +1 -0
- package/dist/commands/context.js +297 -0
- package/dist/commands/context.js.map +1 -0
- package/dist/commands/diff.d.ts +2 -0
- package/dist/commands/diff.d.ts.map +1 -0
- package/dist/commands/diff.js +119 -0
- package/dist/commands/diff.js.map +1 -0
- package/dist/commands/doctor.d.ts +5 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +348 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/document-system.d.ts +5 -0
- package/dist/commands/document-system.d.ts.map +1 -0
- package/dist/commands/document-system.js +84 -0
- package/dist/commands/document-system.js.map +1 -0
- package/dist/commands/document.d.ts +6 -0
- package/dist/commands/document.d.ts.map +1 -0
- package/dist/commands/document.js +276 -0
- package/dist/commands/document.js.map +1 -0
- package/dist/commands/export.d.ts +11 -0
- package/dist/commands/export.d.ts.map +1 -0
- package/dist/commands/export.js +74 -0
- package/dist/commands/export.js.map +1 -0
- package/dist/commands/generate-components.d.ts +4 -0
- package/dist/commands/generate-components.d.ts.map +1 -0
- package/dist/commands/generate-components.js +62 -0
- package/dist/commands/generate-components.js.map +1 -0
- package/dist/commands/generate-composites.d.ts +2 -0
- package/dist/commands/generate-composites.d.ts.map +1 -0
- package/dist/commands/generate-composites.js +31 -0
- package/dist/commands/generate-composites.js.map +1 -0
- package/dist/commands/generate-tokens.d.ts +2 -0
- package/dist/commands/generate-tokens.d.ts.map +1 -0
- package/dist/commands/generate-tokens.js +48 -0
- package/dist/commands/generate-tokens.js.map +1 -0
- package/dist/commands/help-topics.d.ts +2 -0
- package/dist/commands/help-topics.d.ts.map +1 -0
- package/dist/commands/help-topics.js +324 -0
- package/dist/commands/help-topics.js.map +1 -0
- package/dist/commands/implement.d.ts +5 -0
- package/dist/commands/implement.d.ts.map +1 -0
- package/dist/commands/implement.js +595 -0
- package/dist/commands/implement.js.map +1 -0
- package/dist/commands/import-tokens.d.ts +2 -0
- package/dist/commands/import-tokens.d.ts.map +1 -0
- package/dist/commands/import-tokens.js +42 -0
- package/dist/commands/import-tokens.js.map +1 -0
- package/dist/commands/init.d.ts +6 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +410 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/inspect-component.d.ts +2 -0
- package/dist/commands/inspect-component.d.ts.map +1 -0
- package/dist/commands/inspect-component.js +146 -0
- package/dist/commands/inspect-component.js.map +1 -0
- package/dist/commands/log.d.ts +4 -0
- package/dist/commands/log.d.ts.map +1 -0
- package/dist/commands/log.js +109 -0
- package/dist/commands/log.js.map +1 -0
- package/dist/commands/onboarding.d.ts +9 -0
- package/dist/commands/onboarding.d.ts.map +1 -0
- package/dist/commands/onboarding.js +63 -0
- package/dist/commands/onboarding.js.map +1 -0
- package/dist/commands/plan.d.ts +3 -0
- package/dist/commands/plan.d.ts.map +1 -0
- package/dist/commands/plan.js +108 -0
- package/dist/commands/plan.js.map +1 -0
- package/dist/commands/prompt.d.ts +5 -0
- package/dist/commands/prompt.d.ts.map +1 -0
- package/dist/commands/prompt.js +77 -0
- package/dist/commands/prompt.js.map +1 -0
- package/dist/commands/prune.d.ts +2 -0
- package/dist/commands/prune.d.ts.map +1 -0
- package/dist/commands/prune.js +95 -0
- package/dist/commands/prune.js.map +1 -0
- package/dist/commands/remove.d.ts +2 -0
- package/dist/commands/remove.d.ts.map +1 -0
- package/dist/commands/remove.js +76 -0
- package/dist/commands/remove.js.map +1 -0
- package/dist/commands/scaffold.d.ts +2 -0
- package/dist/commands/scaffold.d.ts.map +1 -0
- package/dist/commands/scaffold.js +47 -0
- package/dist/commands/scaffold.js.map +1 -0
- package/dist/commands/scan.d.ts +2 -0
- package/dist/commands/scan.d.ts.map +1 -0
- package/dist/commands/scan.js +91 -0
- package/dist/commands/scan.js.map +1 -0
- package/dist/commands/stamp.d.ts +11 -0
- package/dist/commands/stamp.d.ts.map +1 -0
- package/dist/commands/stamp.js +147 -0
- package/dist/commands/stamp.js.map +1 -0
- package/dist/commands/status.d.ts +7 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +219 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/team.d.ts +7 -0
- package/dist/commands/team.d.ts.map +1 -0
- package/dist/commands/team.js +173 -0
- package/dist/commands/team.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +303 -0
- package/dist/index.js.map +1 -0
- package/dist/onboarding/content.d.ts +39 -0
- package/dist/onboarding/content.d.ts.map +1 -0
- package/dist/onboarding/content.js +82 -0
- package/dist/onboarding/content.js.map +1 -0
- package/dist/utils/component-slug.d.ts +10 -0
- package/dist/utils/component-slug.d.ts.map +1 -0
- package/dist/utils/component-slug.js +13 -0
- package/dist/utils/component-slug.js.map +1 -0
- package/dist/utils/framework-registry.d.ts +41 -0
- package/dist/utils/framework-registry.d.ts.map +1 -0
- package/dist/utils/framework-registry.js +82 -0
- package/dist/utils/framework-registry.js.map +1 -0
- package/dist/utils/gitignore.d.ts +4 -0
- package/dist/utils/gitignore.d.ts.map +1 -0
- package/dist/utils/gitignore.js +67 -0
- package/dist/utils/gitignore.js.map +1 -0
- package/dist/utils/lock-changes.d.ts +14 -0
- package/dist/utils/lock-changes.d.ts.map +1 -0
- package/dist/utils/lock-changes.js +26 -0
- package/dist/utils/lock-changes.js.map +1 -0
- package/dist/utils/logger.d.ts +9 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +32 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/permissions.d.ts +17 -0
- package/dist/utils/permissions.d.ts.map +1 -0
- package/dist/utils/permissions.js +37 -0
- package/dist/utils/permissions.js.map +1 -0
- package/dist/utils/status-logic.d.ts +16 -0
- package/dist/utils/status-logic.d.ts.map +1 -0
- package/dist/utils/status-logic.js +32 -0
- package/dist/utils/status-logic.js.map +1 -0
- package/dist/utils/storybook-setup.d.ts +5 -0
- package/dist/utils/storybook-setup.d.ts.map +1 -0
- package/dist/utils/storybook-setup.js +104 -0
- package/dist/utils/storybook-setup.js.map +1 -0
- package/dist/utils/team-roster.d.ts +35 -0
- package/dist/utils/team-roster.d.ts.map +1 -0
- package/dist/utils/team-roster.js +99 -0
- package/dist/utils/team-roster.js.map +1 -0
- package/package.json +44 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { loadConfig, loadLatestSnapshot, loadPreviousSnapshot, computeDesignDiff, resolveAffectedFiles, syncManifestWithReport, loadManifest, saveManifest, getGenerator } from "@calibrate-ds/core";
|
|
2
|
+
import { logger } from "../utils/logger.js";
|
|
3
|
+
export async function applyCommand(options = {}) {
|
|
4
|
+
try {
|
|
5
|
+
logger.info("Loading ptb.config.json...");
|
|
6
|
+
const config = await loadConfig();
|
|
7
|
+
logger.info("Loading latest snapshot...");
|
|
8
|
+
const currentModel = await loadLatestSnapshot(config);
|
|
9
|
+
if (!currentModel) {
|
|
10
|
+
logger.warn("No current snapshot found. Please run 'ptb scan' first to establish a baseline.");
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
logger.info("Loading previous snapshot from history...");
|
|
14
|
+
const previousData = await loadPreviousSnapshot(config);
|
|
15
|
+
if (!previousData) {
|
|
16
|
+
logger.warn("No previous snapshot found. Run 'ptb scan' at least twice to compare changes.");
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const summary = computeDesignDiff(previousData.model, currentModel);
|
|
20
|
+
const plan = resolveAffectedFiles(summary, config);
|
|
21
|
+
const generator = getGenerator(config.framework.name || "react");
|
|
22
|
+
if (plan.components.size === 0 && plan.sharedFiles.length === 0) {
|
|
23
|
+
logger.info("No design changes detected. Reconciling manifest...");
|
|
24
|
+
const report = await generator.writeComponents(currentModel, config);
|
|
25
|
+
await syncManifestWithReport(config, report);
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
logger.info("Applying changes...\n");
|
|
29
|
+
const affectedComponentNames = Array.from(plan.components.keys());
|
|
30
|
+
const report = await generator.writeComponents(currentModel, config, {
|
|
31
|
+
forceOverwriteComponents: affectedComponentNames
|
|
32
|
+
});
|
|
33
|
+
await syncManifestWithReport(config, report);
|
|
34
|
+
if (affectedComponentNames.length > 0) {
|
|
35
|
+
console.log(`\x1b[1mRegenerated components:\x1b[0m`);
|
|
36
|
+
for (const name of affectedComponentNames) {
|
|
37
|
+
console.log(`- ${name}`);
|
|
38
|
+
}
|
|
39
|
+
console.log("");
|
|
40
|
+
}
|
|
41
|
+
if (plan.sharedFiles.length > 0) {
|
|
42
|
+
await generator.writeTokens(currentModel, config, { forceOverwriteTokens: true });
|
|
43
|
+
console.log(`\x1b[1mRegenerated shared files:\x1b[0m`);
|
|
44
|
+
for (const file of plan.sharedFiles) {
|
|
45
|
+
console.log(`- ${file}`);
|
|
46
|
+
}
|
|
47
|
+
console.log("");
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// 5. Detect and warn/prune removals based on manifest
|
|
51
|
+
const manifest = await loadManifest(config);
|
|
52
|
+
const staleEntries = [];
|
|
53
|
+
for (const [id, compData] of Object.entries(manifest.components)) {
|
|
54
|
+
const stillExists = currentModel.components.some(c => c.id === id);
|
|
55
|
+
if (!stillExists) {
|
|
56
|
+
staleEntries.push({ id, data: compData });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (staleEntries.length > 0) {
|
|
60
|
+
if (options.prune) {
|
|
61
|
+
logger.info(`Found ${staleEntries.length} stale component${staleEntries.length > 1 ? "s" : ""}. Pruning...`);
|
|
62
|
+
const result = await generator.pruneComponents(config, staleEntries);
|
|
63
|
+
if (result.deleted.length > 0) {
|
|
64
|
+
console.log(`\x1b[1mPruned stale components:\x1b[0m`);
|
|
65
|
+
for (const name of result.deleted) {
|
|
66
|
+
console.log(`- ${name}`);
|
|
67
|
+
const entry = staleEntries.find(e => e.data.name === name);
|
|
68
|
+
if (entry)
|
|
69
|
+
delete manifest.components[entry.id];
|
|
70
|
+
}
|
|
71
|
+
console.log("");
|
|
72
|
+
await saveManifest(config, manifest);
|
|
73
|
+
}
|
|
74
|
+
if (result.skipped.length > 0) {
|
|
75
|
+
console.log(`\x1b[33mSkipped pruning (unexpected files present):\x1b[0m`);
|
|
76
|
+
for (const info of result.skipped) {
|
|
77
|
+
console.log(`- ${info}`);
|
|
78
|
+
}
|
|
79
|
+
console.log("");
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
console.log(`\x1b[33mWarning:\x1b[0m`);
|
|
84
|
+
console.log(`${staleEntries.length} component${staleEntries.length > 1 ? "s" : ""} removed from Figma:`);
|
|
85
|
+
for (const entry of staleEntries) {
|
|
86
|
+
console.log(` - ${entry.data.name}`);
|
|
87
|
+
}
|
|
88
|
+
console.log(`\nRun \x1b[1mptb prune\x1b[0m or \x1b[1mptb apply --prune\x1b[0m to delete stale PTB-managed artifacts.\n`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
logger.success("Apply complete.\n");
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
logger.error(error.message || String(error));
|
|
95
|
+
process.exit(1);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=apply.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apply.js","sourceRoot":"","sources":["../../src/commands/apply.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assign.d.ts","sourceRoot":"","sources":["../../src/commands/assign.ts"],"names":[],"mappings":"AAmDA,wBAAsB,aAAa,CAC/B,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE;IAAE,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,iBAqJjD"}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { loadConfig, resolveDSPaths } from "@calibrate-ds/core";
|
|
2
|
+
import { logger } from "../utils/logger.js";
|
|
3
|
+
import { readRoster, getGitUser, toHandle, findMember, findClosestMember, getCurrentUserRole } from "../utils/team-roster.js";
|
|
4
|
+
import { findComponentSlug } from "../utils/component-slug.js";
|
|
5
|
+
import { canAssignToOther, isSelfAssign, canClearAssignment } from "../utils/permissions.js";
|
|
6
|
+
import * as fs from "node:fs/promises";
|
|
7
|
+
import * as path from "node:path";
|
|
8
|
+
import * as readline from "node:readline";
|
|
9
|
+
function ask(question) {
|
|
10
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
11
|
+
return new Promise(resolve => rl.question(question, ans => { rl.close(); resolve(ans.trim()); }));
|
|
12
|
+
}
|
|
13
|
+
async function resolveAssignee(input, roster) {
|
|
14
|
+
const members = Object.values(roster.members);
|
|
15
|
+
// 1. Exact match
|
|
16
|
+
const exact = findMember(input, roster);
|
|
17
|
+
if (exact)
|
|
18
|
+
return `@${exact.handle}`;
|
|
19
|
+
// 2. No roster yet — use as-is
|
|
20
|
+
if (members.length === 0) {
|
|
21
|
+
return input.startsWith("@") ? input : `@${input}`;
|
|
22
|
+
}
|
|
23
|
+
// 3. Fuzzy match — suggest closest
|
|
24
|
+
const closest = findClosestMember(input, roster);
|
|
25
|
+
if (closest) {
|
|
26
|
+
const answer = await ask(`\x1b[33m '${input}' not found. Did you mean @${closest.member.handle} (${closest.member.name})? (Y/n) \x1b[0m`);
|
|
27
|
+
if (answer === "" || answer.toLowerCase() === "y") {
|
|
28
|
+
return `@${closest.member.handle}`;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
logger.warn(`'${input}' not found in ptb-team.json.`);
|
|
33
|
+
logger.dim(" Registered team members:");
|
|
34
|
+
for (const m of members)
|
|
35
|
+
logger.dim(` @${m.handle.padEnd(20)} ${m.name} <${m.email}>`);
|
|
36
|
+
}
|
|
37
|
+
// 4. Assign as freeform with a warning (pre-registering someone not yet joined)
|
|
38
|
+
logger.dim(` Assigning as '${input.startsWith("@") ? input : "@" + input}' anyway. Ask them to run 'ptb join'.`);
|
|
39
|
+
return input.startsWith("@") ? input : `@${input}`;
|
|
40
|
+
}
|
|
41
|
+
export async function assignCommand(name, options = {}) {
|
|
42
|
+
try {
|
|
43
|
+
const config = await loadConfig();
|
|
44
|
+
const { workspaceRoot } = resolveDSPaths(config);
|
|
45
|
+
const lockPath = path.join(workspaceRoot, "ptb.lock");
|
|
46
|
+
let lock;
|
|
47
|
+
try {
|
|
48
|
+
lock = JSON.parse(await fs.readFile(lockPath, "utf-8"));
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
logger.error("ptb.lock not found. Run 'ptb scan' first.");
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
const roster = await readRoster(workspaceRoot);
|
|
55
|
+
const myRole = getCurrentUserRole(roster);
|
|
56
|
+
const user = getGitUser();
|
|
57
|
+
// Resolve assignee handle
|
|
58
|
+
let assigneeHandle;
|
|
59
|
+
if (!options.clear) {
|
|
60
|
+
if (options.to) {
|
|
61
|
+
// Only leads can assign to others
|
|
62
|
+
if (!canAssignToOther(myRole)) {
|
|
63
|
+
const me = user ? roster.members[user.email] : undefined;
|
|
64
|
+
const myHandle = me ? `@${me.handle}` : undefined;
|
|
65
|
+
if (!isSelfAssign(options.to, myHandle)) {
|
|
66
|
+
logger.error("Only leads can assign components to others.");
|
|
67
|
+
logger.dim(" You can self-assign: ptb assign <component>");
|
|
68
|
+
logger.dim(" Ask a lead to assign to others, or get promoted: ptb team role <handle> lead");
|
|
69
|
+
process.exit(1);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
assigneeHandle = await resolveAssignee(options.to, roster);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
if (!user) {
|
|
76
|
+
logger.error("Could not determine assignee. Pass a name or run 'git config user.name'.");
|
|
77
|
+
process.exit(1);
|
|
78
|
+
}
|
|
79
|
+
const me = roster.members[user.email];
|
|
80
|
+
assigneeHandle = me ? `@${me.handle}` : `@${toHandle(user.name)}`;
|
|
81
|
+
if (!me && Object.keys(roster.members).length > 0) {
|
|
82
|
+
logger.warn("You're not in the team roster. Run 'ptb join' to register.");
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
const all = Object.keys(lock.components);
|
|
87
|
+
const isAll = name === "." || name === "*";
|
|
88
|
+
const targets = [];
|
|
89
|
+
if (isAll) {
|
|
90
|
+
const pending = all.filter(k => {
|
|
91
|
+
const e = lock.components[k];
|
|
92
|
+
return !e.stampedHash || e.stampedHash !== e.designHash;
|
|
93
|
+
});
|
|
94
|
+
if (pending.length === 0) {
|
|
95
|
+
logger.info("No stale or unimplemented components to assign.");
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
targets.push(...pending);
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
const match = findComponentSlug(name, lock.components);
|
|
102
|
+
if (!match) {
|
|
103
|
+
logger.error(`Component '${name}' not found in ptb.lock.`);
|
|
104
|
+
logger.info("Available components:");
|
|
105
|
+
for (const k of all)
|
|
106
|
+
logger.dim(` - ${lock.components[k].displayName} (${k})`);
|
|
107
|
+
process.exit(1);
|
|
108
|
+
}
|
|
109
|
+
targets.push(match);
|
|
110
|
+
}
|
|
111
|
+
let changed = 0;
|
|
112
|
+
let skipped = 0;
|
|
113
|
+
for (const slug of targets) {
|
|
114
|
+
const entry = lock.components[slug];
|
|
115
|
+
if (!options.clear && assigneeHandle) {
|
|
116
|
+
// Already assigned to same person — skip silently
|
|
117
|
+
if (entry.assignedTo === assigneeHandle) {
|
|
118
|
+
skipped++;
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
// Component is already implemented — warn leads before reassigning
|
|
122
|
+
if (myRole === "lead" && entry.stampedHash && entry.stampedHash === entry.designHash && process.stdout.isTTY) {
|
|
123
|
+
const answer = await ask(` ${entry.displayName} is already implemented (stamped by ${entry.stampedBy ?? "unknown"}). Reassign anyway? (Y/n) `);
|
|
124
|
+
if (answer.toLowerCase() === "n") {
|
|
125
|
+
logger.dim(` Skipped: ${entry.displayName}`);
|
|
126
|
+
skipped++;
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
// Already assigned to someone else
|
|
131
|
+
if (entry.assignedTo && entry.assignedTo !== assigneeHandle) {
|
|
132
|
+
if (myRole !== "lead") {
|
|
133
|
+
// Members cannot take a component assigned to someone else
|
|
134
|
+
logger.warn(` ${entry.displayName} is already assigned to ${entry.assignedTo}. Ask a lead to reassign it.`);
|
|
135
|
+
skipped++;
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
// Leads get a confirmation prompt before reassigning
|
|
139
|
+
if (process.stdout.isTTY) {
|
|
140
|
+
const answer = await ask(` ${entry.displayName} is already assigned to ${entry.assignedTo}. Reassign to ${assigneeHandle}? (Y/n) `);
|
|
141
|
+
if (answer.toLowerCase() === "n") {
|
|
142
|
+
logger.dim(` Skipped: ${entry.displayName}`);
|
|
143
|
+
skipped++;
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
lock.components[slug] = { ...entry, assignedTo: assigneeHandle };
|
|
149
|
+
logger.success(` Assigned: ${entry.displayName} → ${assigneeHandle}`);
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
// Members can only clear their own assignments
|
|
153
|
+
if (entry.assignedTo) {
|
|
154
|
+
const me = user ? roster.members[user.email] : undefined;
|
|
155
|
+
const myHandle = me ? `@${me.handle}` : user ? `@${toHandle(user.name)}` : undefined;
|
|
156
|
+
if (!canClearAssignment(myRole, entry.assignedTo, myHandle)) {
|
|
157
|
+
logger.warn(` ${entry.displayName} is assigned to ${entry.assignedTo}. Only leads can clear others' assignments.`);
|
|
158
|
+
skipped++;
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
const { assignedTo: _removed, ...rest } = entry;
|
|
163
|
+
lock.components[slug] = rest;
|
|
164
|
+
logger.dim(` Cleared: ${entry.displayName}`);
|
|
165
|
+
}
|
|
166
|
+
changed++;
|
|
167
|
+
}
|
|
168
|
+
await fs.writeFile(lockPath, JSON.stringify(lock, null, 2) + "\n", "utf-8");
|
|
169
|
+
const parts = [
|
|
170
|
+
changed > 0 ? `${changed} updated` : "",
|
|
171
|
+
skipped > 0 ? `${skipped} skipped` : "",
|
|
172
|
+
].filter(Boolean).join(", ");
|
|
173
|
+
logger.info(`\n${parts}. Commit ptb.lock to share with your team.`);
|
|
174
|
+
}
|
|
175
|
+
catch (error) {
|
|
176
|
+
logger.error(error.message || String(error));
|
|
177
|
+
process.exit(1);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
//# sourceMappingURL=assign.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assign.js","sourceRoot":"","sources":["../../src/commands/assign.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ci.d.ts","sourceRoot":"","sources":["../../src/commands/ci.ts"],"names":[],"mappings":"AAkDA,wBAAsB,cAAc,CAAC,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,iBAsCrE"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import * as fs from "node:fs/promises";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { loadConfig, resolveDSPaths } from "@calibrate-ds/core";
|
|
4
|
+
import { logger } from "../utils/logger.js";
|
|
5
|
+
import { readRoster, getCurrentUserRole } from "../utils/team-roster.js";
|
|
6
|
+
const PTB_WORKFLOW = `name: PTB Design System Check
|
|
7
|
+
|
|
8
|
+
on:
|
|
9
|
+
push:
|
|
10
|
+
branches: [main, master]
|
|
11
|
+
pull_request:
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
test:
|
|
15
|
+
name: Run tests
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
|
|
20
|
+
- name: Setup Node.js
|
|
21
|
+
uses: actions/setup-node@v4
|
|
22
|
+
with:
|
|
23
|
+
node-version: '20'
|
|
24
|
+
|
|
25
|
+
- name: Install dependencies
|
|
26
|
+
run: npm ci
|
|
27
|
+
|
|
28
|
+
- name: Run tests
|
|
29
|
+
run: npm test
|
|
30
|
+
|
|
31
|
+
ptb-status:
|
|
32
|
+
name: Check component freshness
|
|
33
|
+
runs-on: ubuntu-latest
|
|
34
|
+
needs: test
|
|
35
|
+
steps:
|
|
36
|
+
- uses: actions/checkout@v4
|
|
37
|
+
|
|
38
|
+
- name: Setup Node.js
|
|
39
|
+
uses: actions/setup-node@v4
|
|
40
|
+
with:
|
|
41
|
+
node-version: '20'
|
|
42
|
+
|
|
43
|
+
- name: Install dependencies
|
|
44
|
+
run: npm ci
|
|
45
|
+
|
|
46
|
+
- name: PTB status check
|
|
47
|
+
run: npx ptb status --fail-on-stale
|
|
48
|
+
`;
|
|
49
|
+
export async function ciSetupCommand(options = {}) {
|
|
50
|
+
try {
|
|
51
|
+
const cwd = process.cwd();
|
|
52
|
+
// Only leads can set up CI
|
|
53
|
+
const config = await loadConfig().catch(() => null);
|
|
54
|
+
if (config) {
|
|
55
|
+
const { workspaceRoot } = resolveDSPaths(config);
|
|
56
|
+
const roster = await readRoster(workspaceRoot);
|
|
57
|
+
const myRole = getCurrentUserRole(roster);
|
|
58
|
+
if (myRole !== "lead") {
|
|
59
|
+
logger.error("Only leads can set up CI workflows.");
|
|
60
|
+
logger.dim(" Ask a lead to run: ptb ci setup");
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
const workflowsDir = path.join(cwd, ".github", "workflows");
|
|
65
|
+
const workflowPath = path.join(workflowsDir, "ptb.yml");
|
|
66
|
+
const exists = await fs.stat(workflowPath).then(() => true).catch(() => false);
|
|
67
|
+
if (exists && !options.force) {
|
|
68
|
+
logger.warn(`${workflowPath} already exists. Use --force to overwrite.`);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
await fs.mkdir(workflowsDir, { recursive: true });
|
|
72
|
+
await fs.writeFile(workflowPath, PTB_WORKFLOW, "utf-8");
|
|
73
|
+
logger.success(`Created .github/workflows/ptb.yml`);
|
|
74
|
+
console.log("\n This workflow runs \x1b[36mptb status --fail-on-stale\x1b[0m on every push and pull request.");
|
|
75
|
+
console.log(" It will block merges when components are stale.\n");
|
|
76
|
+
console.log(" \x1b[2mCommit it to take effect:\x1b[0m");
|
|
77
|
+
console.log(" \x1b[2mgit add .github/workflows/ptb.yml && git commit -m \"ci: add PTB design freshness check\"\x1b[0m\n");
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
logger.error(error.message || String(error));
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=ci.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ci.js","sourceRoot":"","sources":["../../src/commands/ci.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAEzE,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0CpB,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,UAA+B,EAAE;IAClE,IAAI,CAAC;QACD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;QAE1B,2BAA2B;QAC3B,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QACpD,IAAI,MAAM,EAAE,CAAC;YACT,MAAM,EAAE,aAAa,EAAE,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;YACjD,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,aAAa,CAAC,CAAC;YAC/C,MAAM,MAAM,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;YAC1C,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;gBACpB,MAAM,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAC;gBACpD,MAAM,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;gBAChD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACpB,CAAC;QACL,CAAC;QACD,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC;QAC5D,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;QAExD,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC;QAC/E,IAAI,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YAC3B,MAAM,CAAC,IAAI,CAAC,GAAG,YAAY,4CAA4C,CAAC,CAAC;YACzE,OAAO;QACX,CAAC;QAED,MAAM,EAAE,CAAC,KAAK,CAAC,YAAY,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAClD,MAAM,EAAE,CAAC,SAAS,CAAC,YAAY,EAAE,YAAY,EAAE,OAAO,CAAC,CAAC;QAExD,MAAM,CAAC,OAAO,CAAC,mCAAmC,CAAC,CAAC;QACpD,OAAO,CAAC,GAAG,CAAC,kGAAkG,CAAC,CAAC;QAChH,OAAO,CAAC,GAAG,CAAC,qDAAqD,CAAC,CAAC;QACnE,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAC;QACzD,OAAO,CAAC,GAAG,CAAC,6GAA6G,CAAC,CAAC;IAE/H,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QAClB,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAC7C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare function contextComponentCommand(name: string, options?: {
|
|
2
|
+
json?: boolean;
|
|
3
|
+
}): Promise<void>;
|
|
4
|
+
/**
|
|
5
|
+
* Handler for 'ptb context list'
|
|
6
|
+
* Lists all exported components from the context index.
|
|
7
|
+
*/
|
|
8
|
+
export declare function contextListCommand(): Promise<void>;
|
|
9
|
+
/**
|
|
10
|
+
* Handler for 'ptb context resolve <query>'
|
|
11
|
+
* Resolves a component query to the best matching context file.
|
|
12
|
+
*/
|
|
13
|
+
export declare function contextResolveCommand(query: string): Promise<void>;
|
|
14
|
+
/**
|
|
15
|
+
* Handler for 'ptb context open <query>'
|
|
16
|
+
* Prints ONLY the path to the resolved context file for AI IDE integration.
|
|
17
|
+
*/
|
|
18
|
+
export declare function contextOpenCommand(query: string): Promise<void>;
|
|
19
|
+
//# sourceMappingURL=context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/commands/context.ts"],"names":[],"mappings":"AAKA,wBAAsB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAA;CAAO,iBAuL3F;AAcD;;;GAGG;AACH,wBAAsB,kBAAkB,kBAiCvC;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CAAC,KAAK,EAAE,MAAM,iBAgCxD;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,KAAK,EAAE,MAAM,iBAgCrD"}
|