@uniqbit/mate-core 0.18.5 → 1.0.0-canary.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/claude-plugin/hooks/companion-instructions.mjs +9 -0
- package/claude-plugin/hooks/hooks.json +12 -2
- package/package.json +10 -2
- package/src/brand/art.generated.ts +69 -0
- package/src/brand/index.ts +12 -0
- package/src/brand/palette.ts +19 -0
- package/src/brand/svg.generated.ts +8 -0
- package/src/brand/terminal.ts +83 -0
- package/src/brand/types.ts +33 -0
- package/src/cli/commands/artifact/artifact.ts +8 -0
- package/src/cli/commands/artifact/delivery/archive.ts +117 -0
- package/src/cli/commands/artifact/delivery/branch-flags.ts +55 -0
- package/src/cli/commands/artifact/delivery/environment.ts +104 -0
- package/src/cli/commands/artifact/delivery/link.ts +154 -0
- package/src/cli/commands/artifact/delivery/output.ts +58 -0
- package/src/cli/commands/artifact/finish/command.ts +33 -3
- package/src/cli/commands/artifact/finish/engine.ts +47 -3
- package/src/cli/commands/artifact/finish/finisher.ts +10 -0
- package/src/cli/commands/artifact/finish/openspec.ts +177 -138
- package/src/cli/commands/artifact/finish/secret-scan.ts +43 -0
- package/src/cli/commands/artifact/pending/command.ts +31 -3
- package/src/cli/commands/artifact/pending/discovery.ts +21 -57
- package/src/cli/commands/cap/graphify.ts +52 -3
- package/src/cli/commands/cap/index-cmd.ts +8 -1
- package/src/cli/commands/cap/openspec.ts +13 -25
- package/src/cli/commands/companion/open.ts +56 -39
- package/src/cli/commands/companion/update.ts +75 -42
- package/src/cli/commands/doctor.ts +176 -3
- package/src/cli/commands/plugin/install.ts +9 -4
- package/src/cli/commands/plugin/plugin.ts +3 -2
- package/src/cli/commands/report/adapter.ts +11 -2
- package/src/cli/commands/report/contract.ts +21 -0
- package/src/cli/commands/report/highlight.ts +34 -4
- package/src/cli/commands/report/markdown.ts +110 -0
- package/src/cli/commands/report/palette.ts +118 -0
- package/src/cli/commands/report/renderer.ts +456 -153
- package/src/cli/commands/report/types.ts +16 -0
- package/src/cli/commands/setup.ts +7 -15
- package/src/cli/commands/studio/client-asset.ts +16 -0
- package/src/cli/commands/studio/openspec-cli.ts +10 -58
- package/src/cli/commands/studio/routes.ts +2 -0
- package/src/cli/commands/studio/selection.ts +19 -1
- package/src/cli/commands/studio/server.ts +42 -1
- package/src/cli/commands/studio/views/client.ts +6 -616
- package/src/cli/commands/studio/views/dashboard/changes.tsx +5 -10
- package/src/cli/commands/studio/views/document.tsx +137 -69
- package/src/cli/commands/studio/views/markdown.tsx +250 -0
- package/src/cli/commands/studio/views/palette.ts +134 -0
- package/src/cli/commands/studio/views/reports/index.tsx +2 -7
- package/src/cli/commands/studio/views/skills/index.tsx +43 -62
- package/src/cli/commands/studio/views/specs/index.tsx +7 -15
- package/src/cli/commands/studio/views/studio-client/actions.ts +51 -0
- package/src/cli/commands/studio/views/studio-client/companion.ts +13 -0
- package/src/cli/commands/studio/views/studio-client/index.ts +32 -0
- package/src/cli/commands/studio/views/studio-client/keys.ts +3 -0
- package/src/cli/commands/studio/views/studio-client/main.ts +3 -0
- package/src/cli/commands/studio/views/studio-client/page.ts +146 -0
- package/src/cli/commands/studio/views/studio-client/panels.ts +57 -0
- package/src/cli/commands/studio/views/studio-client/reports.ts +122 -0
- package/src/cli/commands/studio/views/studio-client/theme.ts +63 -0
- package/src/cli/commands/studio/views/studio-client/vault-editor.ts +166 -0
- package/src/cli/commands/studio/views/studio-client/vault-pane.ts +202 -0
- package/src/cli/commands/studio/views/studio-client/vault-tree.ts +258 -0
- package/src/cli/commands/studio/views/studio-client.generated.ts +2 -0
- package/src/cli/commands/studio/views/styles.ts +217 -206
- package/src/cli/commands/studio/views/vault/state.ts +3 -5
- package/src/cli/commands/studio/views/workflow/delivery-path.tsx +370 -0
- package/src/cli/commands/studio/views/workflow/graph.ts +220 -0
- package/src/cli/commands/studio/views/workflow/index.tsx +2 -3
- package/src/cli/commands/studio/views/workflow/steps.ts +228 -287
- package/src/cli/commands/wrap.ts +5 -13
- package/src/cli/main.ts +4 -1
- package/src/cli/parse-flags.ts +25 -7
- package/src/cli/setup-selector.tsx +38 -162
- package/src/cli/usage.ts +4 -0
- package/src/hooks/companion-instructions.ts +190 -0
- package/src/hooks/hook-io.ts +63 -0
- package/src/hooks/session-banner.ts +21 -29
- package/src/hooks/session-guidance.ts +9 -17
- package/src/hooks/session-prepare.ts +115 -28
- package/src/hooks/validate-artifact-path.ts +82 -24
- package/src/index.ts +4 -0
- package/src/lib/change-layout.ts +154 -0
- package/src/lib/components/wizard-header.tsx +3 -1
- package/src/lib/context-mode-package.ts +24 -11
- package/src/lib/delivery/archive-change.ts +154 -0
- package/src/lib/delivery/branches.ts +108 -0
- package/src/lib/delivery/environment.ts +29 -0
- package/src/lib/delivery/forge.ts +279 -0
- package/src/lib/delivery/overlap.ts +202 -0
- package/src/lib/delivery/record-delivery.ts +196 -0
- package/src/lib/delivery/record.ts +343 -0
- package/src/lib/delivery/refresh.ts +174 -0
- package/src/lib/delivery/repository-access.ts +97 -0
- package/src/lib/delivery/stages.ts +111 -0
- package/src/lib/delivery/token.ts +58 -0
- package/src/lib/frontmatter.ts +18 -0
- package/src/lib/opencode-plugin-package.ts +5 -5
- package/src/lib/openspec-cli.ts +116 -0
- package/src/lib/openspec-scopes.ts +86 -0
- package/src/lib/orchestrator/adapters/claude-args.ts +50 -0
- package/src/lib/orchestrator/adapters/claude.ts +48 -40
- package/src/lib/orchestrator/adapters/opencode.ts +2 -0
- package/src/lib/orchestrator/editor.ts +9 -9
- package/src/lib/orchestrator/openspec-store.ts +14 -54
- package/src/lib/orchestrator/projection-claude-commands.ts +36 -0
- package/src/lib/orchestrator/projection-claude-links.ts +159 -0
- package/src/lib/orchestrator/projection-claude-skills.ts +19 -137
- package/src/lib/orchestrator/projection-entries.ts +45 -14
- package/src/lib/orchestrator/projection-runtime-documents.ts +15 -6
- package/src/lib/orchestrator/projection-types.ts +3 -0
- package/src/lib/orchestrator/refresh-working-claude-links.ts +87 -0
- package/src/lib/orchestrator/session-prepare.ts +45 -5
- package/src/lib/orchestrator/setup-compatibilities.ts +18 -75
- package/src/lib/orchestrator/types.ts +2 -2
- package/src/lib/orchestrator/wrap-pass.ts +22 -1
- package/src/lib/package-paths.ts +8 -0
- package/src/opencode/companion-hooks.ts +64 -5
- package/src/opencode/companion-policy.ts +37 -18
- package/src/opencode/projected-guidance.ts +4 -1
- package/src/opencode/session-prepare.ts +2 -1
- package/src/opencode/tui.tsx +4 -2
- package/src/runtime/artifact-refusal.ts +63 -0
- package/src/runtime/claude-delivery-plan.ts +89 -7
- package/src/runtime/commit-attribution-guard.ts +181 -0
- package/src/runtime/companion-guidance.ts +15 -3
- package/src/runtime/companion-instructions.ts +340 -0
- package/src/runtime/error-message.ts +4 -0
- package/src/runtime/index.ts +5 -0
- package/src/runtime/managed-block.ts +117 -0
- package/src/runtime/markdown-scan.ts +266 -0
- package/src/runtime/policy.ts +15 -1
- package/src/runtime/projected-flag.ts +7 -0
- package/src/runtime/projected-guidance.ts +1 -0
- package/src/runtime/runtime-document-manifest.ts +62 -11
- package/src/runtime/secret-guard.ts +148 -0
- package/src/runtime/secret-patterns.ts +164 -0
- package/src/runtime/secret-scan.ts +90 -0
- package/src/runtime/session-kind.ts +13 -0
- package/src/runtime/shell-heredoc.ts +81 -0
- package/src/runtime/wrap-state.ts +36 -2
- package/src/runtime/write-atomic.ts +64 -0
- package/src/templates/capabilities/openspec-cap/mate-minimal/schema.yaml +8 -6
- package/src/templates/capabilities/openspec-cap/mate-minimal/templates/spec.md +3 -5
- package/src/templates/capabilities/openspec-cap/mate-v1/schema.yaml +7 -9
- package/src/templates/capabilities/openspec-cap/mate-v1/templates/spec.md +3 -5
- package/src/templates/capabilities/openspec-cap/openspec-conventions.yaml +10 -12
- package/src/templates/mate-skills/THIRD-PARTY-NOTICES.md +40 -0
- package/src/templates/mate-skills/agents/mate-apply-change/SKILL.md +76 -0
- package/src/templates/mate-skills/agents/mate-apply-change/references/openspec-apply-change.md +198 -0
- package/src/templates/mate-skills/agents/mate-archive-change/SKILL.md +59 -0
- package/src/templates/mate-skills/{claude/mate-openspec-backfill → agents/mate-backfill-spec}/SKILL.md +4 -4
- package/src/templates/mate-skills/agents/mate-clarify-intent/SKILL.md +95 -0
- package/src/templates/mate-skills/agents/mate-explore-change/SKILL.md +50 -0
- package/src/templates/mate-skills/agents/mate-explore-change/references/openspec-explore.md +348 -0
- package/src/templates/mate-skills/agents/mate-grill-me/SKILL.md +3 -3
- package/src/templates/mate-skills/agents/mate-interview-me/SKILL.md +5 -5
- package/src/templates/mate-skills/agents/mate-propose-change/SKILL.md +103 -0
- package/src/templates/mate-skills/agents/mate-propose-change/references/openspec-propose.md +167 -0
- package/src/templates/mate-skills/agents/mate-propose-change/references/openspec-update-change.md +101 -0
- package/src/templates/mate-skills/{claude/mate-artifact-publish → agents/mate-publish-artifact}/SKILL.md +91 -23
- package/src/templates/mate-skills/agents/{mate-artifact-publish → mate-publish-artifact}/references/openspec.md +4 -3
- package/src/templates/mate-skills/agents/mate-show-me/SKILL.md +74 -16
- package/src/templates/mate-skills/agents/mate-simplify-code/SKILL.md +74 -68
- package/src/templates/mate-skills/claude/mate-apply-change/SKILL.md +76 -0
- package/src/templates/mate-skills/claude/mate-apply-change/references/openspec-apply-change.md +198 -0
- package/src/templates/mate-skills/claude/mate-archive-change/SKILL.md +59 -0
- package/src/templates/mate-skills/{agents/mate-openspec-backfill → claude/mate-backfill-spec}/SKILL.md +4 -4
- package/src/templates/mate-skills/claude/mate-clarify-intent/SKILL.md +95 -0
- package/src/templates/mate-skills/claude/mate-explore-change/SKILL.md +50 -0
- package/src/templates/mate-skills/claude/mate-explore-change/references/openspec-explore.md +348 -0
- package/src/templates/mate-skills/claude/mate-grill-me/SKILL.md +3 -3
- package/src/templates/mate-skills/claude/mate-interview-me/SKILL.md +5 -5
- package/src/templates/mate-skills/claude/mate-propose-change/SKILL.md +103 -0
- package/src/templates/mate-skills/claude/mate-propose-change/references/openspec-propose.md +167 -0
- package/src/templates/mate-skills/claude/mate-propose-change/references/openspec-update-change.md +101 -0
- package/src/templates/mate-skills/{agents/mate-artifact-publish → claude/mate-publish-artifact}/SKILL.md +91 -23
- package/src/templates/mate-skills/claude/{mate-artifact-publish → mate-publish-artifact}/references/openspec.md +4 -3
- package/src/templates/mate-skills/claude/mate-show-me/SKILL.md +74 -16
- package/src/templates/mate-skills/claude/mate-simplify-code/SKILL.md +74 -68
- package/src/templates/mate-skills/openspec-references.ts +140 -0
- package/src/templates/root/TEMPLATE_AGENTS.md +2 -2
- package/src/tools/setup/__snapshots__/runtime-surface-golden.test.ts.snap +3727 -320
- package/src/tools/setup/capabilities/context-mode.ts +25 -5
- package/src/tools/setup/capabilities/graphify-gate.ts +31 -0
- package/src/tools/setup/capabilities/graphify-secrets.ts +255 -0
- package/src/tools/setup/capabilities/graphify.ts +12 -0
- package/src/tools/setup/capabilities/openspec.ts +151 -270
- package/src/tools/setup/capabilities/tokensave.ts +36 -3
- package/src/tools/setup/context-services.ts +9 -17
- package/src/tools/setup/dynamic-plugins/install.ts +24 -28
- package/src/tools/setup/engine.ts +97 -21
- package/src/tools/setup/managed-output.ts +51 -0
- package/src/tools/setup/mate.ts +86 -11
- package/src/tools/setup/plugin.ts +35 -0
- package/src/tools/setup/plugins/guidance.ts +7 -4
- package/src/tools/setup/providers/agent-file-sections.ts +4 -2
- package/src/tools/setup/providers/claude-attribution.ts +65 -0
- package/src/tools/setup/providers/claude-plugin-folders.ts +625 -0
- package/src/tools/setup/providers/claude-plugin-hooks.ts +39 -19
- package/src/tools/setup/providers/claude.ts +284 -8
- package/src/tools/setup/providers/opencode.ts +180 -1
- package/src/tools/setup/utils.ts +14 -4
- package/src/tools/setup.ts +126 -10
- package/wrappers/bin/graphify +52 -4
- package/wrappers/bin/openspec +33 -9
- package/wrappers/lib/graphify-gate.mjs +8 -0
- package/src/cli/commands/studio/views/workflow/transcript.tsx +0 -190
- package/src/tools/setup/runtime-documents.ts +0 -291
|
@@ -1,8 +1,18 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_SCHEMA,
|
|
3
|
+
deliveryPath,
|
|
4
|
+
isMateSchema,
|
|
5
|
+
SCHEMA_ARTIFACTS,
|
|
6
|
+
type DeliveryStage,
|
|
7
|
+
type MateSchema,
|
|
8
|
+
type SkillStageId,
|
|
9
|
+
} from "../../../../../lib/delivery/stages";
|
|
1
10
|
import { CHANGE_PLACEHOLDER, IDEA_PLACEHOLDER } from "../../selection";
|
|
11
|
+
import type { WorkflowTopology } from "../../topology";
|
|
2
12
|
|
|
3
|
-
export type
|
|
4
|
-
|
|
5
|
-
export type
|
|
13
|
+
export type WorkflowStepBadge = "optional" | "skill" | "openspec" | "human-review";
|
|
14
|
+
|
|
15
|
+
export type WorkflowPhaseId = "plan" | "review" | "build" | "ship";
|
|
6
16
|
|
|
7
17
|
export interface WorkflowAlternative {
|
|
8
18
|
name: string;
|
|
@@ -11,327 +21,258 @@ export interface WorkflowAlternative {
|
|
|
11
21
|
copyPrompt: string;
|
|
12
22
|
}
|
|
13
23
|
|
|
14
|
-
export
|
|
15
|
-
kind: WorkflowStepKind;
|
|
16
|
-
id: string;
|
|
24
|
+
export type WorkflowStep = DeliveryStage & {
|
|
17
25
|
/** The action the stage performs. */
|
|
18
26
|
what: string;
|
|
19
27
|
/** The reason the stage is in the sequence at this position. */
|
|
20
28
|
why: string;
|
|
21
|
-
title: string;
|
|
22
29
|
badges: WorkflowStepBadge[];
|
|
23
|
-
|
|
24
|
-
prompt: string;
|
|
25
|
-
copyPrompt: string;
|
|
30
|
+
/** Null for a human review: a person performs it, so there is nothing to run. */
|
|
31
|
+
prompt: string | null;
|
|
32
|
+
copyPrompt: string | null;
|
|
26
33
|
alternatives?: WorkflowAlternative[];
|
|
27
|
-
|
|
34
|
+
/** The stage's skill when the companion does not report it. */
|
|
35
|
+
missingSkill?: string;
|
|
36
|
+
sessionBreakBefore?: boolean;
|
|
37
|
+
phase: WorkflowPhaseId;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/** One step of the stage map: a single stage, or a run of review stages or optional peers. */
|
|
41
|
+
export type WorkflowMapNode =
|
|
42
|
+
| { kind: "stage"; step: WorkflowStep }
|
|
43
|
+
| { kind: "group"; group: "human" | "optional"; steps: WorkflowStep[] };
|
|
28
44
|
|
|
29
|
-
export interface
|
|
30
|
-
|
|
45
|
+
export interface WorkflowPath {
|
|
46
|
+
schema: string;
|
|
31
47
|
label: string;
|
|
48
|
+
/** Short tab caption, e.g. `full planning`. */
|
|
49
|
+
tagline: string;
|
|
32
50
|
description: string;
|
|
33
51
|
steps: WorkflowStep[];
|
|
52
|
+
map: WorkflowMapNode[];
|
|
53
|
+
reviewsKnown: boolean;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface WorkflowPlanOptions {
|
|
57
|
+
/** Skills reported for the companion; undefined treats every stage skill as present. */
|
|
58
|
+
skills?: readonly string[];
|
|
59
|
+
topology?: WorkflowTopology | null;
|
|
34
60
|
}
|
|
35
61
|
|
|
36
62
|
export interface WorkflowPlan {
|
|
37
|
-
|
|
38
|
-
branches: WorkflowBranch[];
|
|
39
|
-
shared: WorkflowStep[];
|
|
40
|
-
finish: WorkflowStep;
|
|
63
|
+
paths: WorkflowPath[];
|
|
41
64
|
}
|
|
42
65
|
|
|
43
|
-
const
|
|
66
|
+
const CLARIFY_MODES = ["mate-clarify-intent", "mate-interview-me", "mate-grill-me"] as const;
|
|
44
67
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
68
|
+
const CLARIFY_DESCRIPTIONS: Record<(typeof CLARIFY_MODES)[number], string> = {
|
|
69
|
+
"mate-clarify-intent":
|
|
70
|
+
"Default. Reads what the request already states and routes to an interview, grilling, or skip, then runs that one mode.",
|
|
71
|
+
"mate-interview-me":
|
|
72
|
+
"Explicit mode: guided, one-question-at-a-time clarification when intent, constraints, or scope still need confirmation.",
|
|
73
|
+
"mate-grill-me":
|
|
74
|
+
"Explicit mode: round-based stress test of a mostly known direction to surface hidden assumptions and risks.",
|
|
75
|
+
};
|
|
50
76
|
|
|
51
|
-
|
|
77
|
+
const STAGE_TEXT: Record<SkillStageId, { what: string; why: string }> = {
|
|
78
|
+
"clarify-intent": {
|
|
79
|
+
what: "Settles who the change is for, why it is needed, how success is measured, and what binds it, before any artifact exists.",
|
|
80
|
+
why: "Intent gaps are cheapest to close before exploration turns them into documents.",
|
|
81
|
+
},
|
|
82
|
+
explore: {
|
|
83
|
+
what: "Resolves repository evidence, unknowns, and options, with scope taken from the companion context map, and suggests slicing a large feature.",
|
|
84
|
+
why: "It separates uncertainty from the proposal's committed scope.",
|
|
85
|
+
},
|
|
86
|
+
propose: {
|
|
87
|
+
what: "Chooses the schema from the minimal eligibility test, checks slicing when explore agreed none, and writes the change's planning artifacts in one prompt.",
|
|
88
|
+
why: "One prompt writes every artifact; each one is then reviewed on its own.",
|
|
89
|
+
},
|
|
90
|
+
apply: {
|
|
91
|
+
what: "Records the delivery branch, avoiding protected branches, then implements the reviewed tasks.",
|
|
92
|
+
why: "The recorded branch is what archive and publication later wait on.",
|
|
93
|
+
},
|
|
94
|
+
"inspect-outcome": {
|
|
95
|
+
what: "Shows what the applied change did as a rendered diagram and diff in a Mate report.",
|
|
96
|
+
why: "Seeing the result tells the reviewer whether cleanup is warranted.",
|
|
97
|
+
},
|
|
98
|
+
"refine-code": {
|
|
99
|
+
what: "Looks for smaller, clearer code once tests pass, preserving behavior.",
|
|
100
|
+
why: "Cleanup lands before archive, so shipped code and recorded specs agree.",
|
|
101
|
+
},
|
|
102
|
+
archive: {
|
|
103
|
+
what: "Applies the delta specs to the local canonical specs and records the delivery; allowed before the branch merges.",
|
|
104
|
+
why: "A feature's later changes build on canonical specs that already include this one.",
|
|
105
|
+
},
|
|
106
|
+
publish: {
|
|
107
|
+
what: "Commits, tags, and pushes archived changes whose delivery branches are merged, chosen by the developer.",
|
|
108
|
+
why: "Published canonical specs then describe the default branch; unmerged archives wait.",
|
|
109
|
+
},
|
|
110
|
+
};
|
|
52
111
|
|
|
53
|
-
function
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
)
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
112
|
+
function reviewText(
|
|
113
|
+
artifact: string,
|
|
114
|
+
topology: WorkflowTopology | null | undefined,
|
|
115
|
+
schema: string,
|
|
116
|
+
) {
|
|
117
|
+
const description =
|
|
118
|
+
topology?.schemaName === schema
|
|
119
|
+
? topology.artifacts.find((entry) => entry.id === artifact)?.description
|
|
120
|
+
: undefined;
|
|
121
|
+
return {
|
|
122
|
+
what: description ?? `A person reviews the ${artifact} artifact.`,
|
|
123
|
+
why: "Reviews stay with people: Mate never marks them approved.",
|
|
124
|
+
};
|
|
125
|
+
}
|
|
61
126
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
case "propose":
|
|
69
|
-
return `/openspec-propose${schemaNote}${changeNote}`;
|
|
70
|
-
case "specs":
|
|
71
|
-
case "design":
|
|
72
|
-
case "tasks":
|
|
73
|
-
return `Review ${includeChange ? CHANGE_PLACEHOLDER : ""}/`;
|
|
74
|
-
case "apply":
|
|
75
|
-
return `/openspec-apply-change${schemaNote}${changeNote}`;
|
|
76
|
-
case "show-me":
|
|
77
|
-
return `/mate-show-me${changeNote}`;
|
|
78
|
-
case "simplify":
|
|
79
|
-
return `/mate-simplify-code${changeNote}`;
|
|
80
|
-
case "archive":
|
|
81
|
-
return `/openspec-archive-change${changeNote}`;
|
|
82
|
-
case "finish":
|
|
83
|
-
return `/mate-artifact-publish${changeNote}`;
|
|
84
|
-
default:
|
|
85
|
-
return `Use ${step.title}${schemaNote}${changeNote}`;
|
|
86
|
-
}
|
|
127
|
+
function promptFor(stage: DeliveryStage, schema: string): string | null {
|
|
128
|
+
if (stage.kind === "human") return null;
|
|
129
|
+
if (stage.id === "clarify-intent") return `/${stage.skill} about ${IDEA_PLACEHOLDER}`;
|
|
130
|
+
const schemaNote =
|
|
131
|
+
stage.id === "propose" && schema !== DEFAULT_SCHEMA ? ` (use schema: ${schema})` : "";
|
|
132
|
+
return `/${stage.skill}${schemaNote} for ${CHANGE_PLACEHOLDER}`;
|
|
87
133
|
}
|
|
88
134
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
why: string,
|
|
94
|
-
profile?: WorkflowProfile,
|
|
95
|
-
): WorkflowStep {
|
|
96
|
-
const step = {
|
|
97
|
-
kind: "skill" as const,
|
|
98
|
-
id,
|
|
99
|
-
title,
|
|
100
|
-
what,
|
|
101
|
-
why,
|
|
102
|
-
badges: ["skill", "openspec"] as WorkflowStepBadge[],
|
|
103
|
-
};
|
|
104
|
-
return {
|
|
105
|
-
...step,
|
|
106
|
-
prompt: stepPrompt(step, profile),
|
|
107
|
-
copyPrompt: stepPrompt(step, profile, false),
|
|
108
|
-
};
|
|
135
|
+
/** The prompt without its placeholders, ready to be completed after pasting. */
|
|
136
|
+
function copyPromptFor(prompt: string | null): string | null {
|
|
137
|
+
if (!prompt) return prompt;
|
|
138
|
+
return prompt.replace(` ${CHANGE_PLACEHOLDER}`, "").replace(` ${IDEA_PLACEHOLDER}`, "");
|
|
109
139
|
}
|
|
110
140
|
|
|
111
|
-
function
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
)
|
|
118
|
-
const step = {
|
|
119
|
-
kind: "review" as const,
|
|
120
|
-
id,
|
|
121
|
-
title,
|
|
122
|
-
what,
|
|
123
|
-
why,
|
|
124
|
-
badges: ["human-in-loop", "openspec"] as WorkflowStepBadge[],
|
|
125
|
-
};
|
|
126
|
-
return {
|
|
127
|
-
...step,
|
|
128
|
-
prompt: stepPrompt(step, profile),
|
|
129
|
-
copyPrompt: stepPrompt(step, profile, false),
|
|
130
|
-
};
|
|
141
|
+
function clarifyAlternatives(available: (skill: string) => boolean): WorkflowAlternative[] {
|
|
142
|
+
return CLARIFY_MODES.filter(available).map((name) => ({
|
|
143
|
+
name,
|
|
144
|
+
description: CLARIFY_DESCRIPTIONS[name],
|
|
145
|
+
prompt: `/${name} about ${IDEA_PLACEHOLDER}`,
|
|
146
|
+
copyPrompt: `/${name} about`,
|
|
147
|
+
}));
|
|
131
148
|
}
|
|
132
149
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
)
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
150
|
+
/** Stages whose skills run an OpenSpec workflow. */
|
|
151
|
+
const OPENSPEC_STAGES: ReadonlySet<SkillStageId> = new Set([
|
|
152
|
+
"explore",
|
|
153
|
+
"propose",
|
|
154
|
+
"apply",
|
|
155
|
+
"archive",
|
|
156
|
+
]);
|
|
157
|
+
|
|
158
|
+
function badgesFor(stage: DeliveryStage): WorkflowStepBadge[] {
|
|
159
|
+
if (stage.kind === "human") return ["human-review"];
|
|
160
|
+
const badges: WorkflowStepBadge[] = stage.optional ? ["optional", "skill"] : ["skill"];
|
|
161
|
+
if (OPENSPEC_STAGES.has(stage.id)) badges.push("openspec");
|
|
162
|
+
return badges;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const SHIPPED_PATH_TEXT: Record<MateSchema, { tagline: string; description: string }> = {
|
|
166
|
+
"mate-v1": {
|
|
167
|
+
tagline: "full planning",
|
|
168
|
+
description: "Full planning path: proposal, specs, design, and tasks.",
|
|
169
|
+
},
|
|
170
|
+
"mate-minimal": {
|
|
171
|
+
tagline: "minimal planning",
|
|
172
|
+
description:
|
|
173
|
+
"Short path: specs and tasks only, for one-Area, low-risk changes with clear intent.",
|
|
174
|
+
},
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
function pathText(schema: string): { tagline: string; description: string } {
|
|
178
|
+
if (isMateSchema(schema)) return SHIPPED_PATH_TEXT[schema];
|
|
179
|
+
return { tagline: "custom schema", description: `Planning path of the ${schema} schema.` };
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export const PHASE_LABELS: Record<WorkflowPhaseId, string> = {
|
|
183
|
+
plan: "Plan",
|
|
184
|
+
review: "Review",
|
|
185
|
+
build: "Build",
|
|
186
|
+
ship: "Ship",
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
/** Plan precedes reviews, Review holds them, Build is apply plus its optional peers, Ship follows. */
|
|
190
|
+
function phaseOf(stage: DeliveryStage, previous: WorkflowPhaseId | undefined): WorkflowPhaseId {
|
|
191
|
+
if (stage.kind === "human") return "review";
|
|
192
|
+
if (stage.id === "apply") return "build";
|
|
193
|
+
if (previous === "build" && stage.optional) return "build";
|
|
194
|
+
return previous === undefined || previous === "plan" ? "plan" : "ship";
|
|
154
195
|
}
|
|
155
196
|
|
|
156
|
-
function
|
|
157
|
-
|
|
197
|
+
function groupOf(step: WorkflowStep): "human" | "optional" | null {
|
|
198
|
+
if (step.kind === "human") return "human";
|
|
199
|
+
return step.optional ? "optional" : null;
|
|
158
200
|
}
|
|
159
201
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
for (const name of PRE_EXPLORE_SKILLS) {
|
|
169
|
-
if (!availableSkillSet.has(name)) continue;
|
|
170
|
-
preExploreAlternatives.push({
|
|
171
|
-
name,
|
|
172
|
-
description:
|
|
173
|
-
name === "mate-interview-me"
|
|
174
|
-
? "Difference: guided, one-question-at-a-time clarification. Best when: the request is ambiguous and intent, constraints, or scope still need confirmation."
|
|
175
|
-
: "Difference: adversarial, round-based review of the full design-tree frontier. Best when: the direction is mostly known but hidden assumptions, risks, and downstream impacts need surfacing.",
|
|
176
|
-
prompt: `/${name} about ${IDEA_PLACEHOLDER}`,
|
|
177
|
-
copyPrompt: `/${name} about`,
|
|
178
|
-
});
|
|
202
|
+
/** Review runs are always one group; optional runs group only when they hold peers. */
|
|
203
|
+
function mapOf(steps: readonly WorkflowStep[]): WorkflowMapNode[] {
|
|
204
|
+
const runs: { group: "human" | "optional" | null; steps: WorkflowStep[] }[] = [];
|
|
205
|
+
for (const step of steps) {
|
|
206
|
+
const group = groupOf(step);
|
|
207
|
+
const run = runs.at(-1);
|
|
208
|
+
if (group && run?.group === group) run.steps.push(step);
|
|
209
|
+
else runs.push({ group, steps: [step] });
|
|
179
210
|
}
|
|
180
|
-
|
|
181
|
-
"
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
"One conversational choice settles uncertainty early without invoking documentation or implementation work.",
|
|
185
|
-
preExploreAlternatives,
|
|
211
|
+
return runs.map((run) =>
|
|
212
|
+
run.group === "human" || (run.group === "optional" && run.steps.length > 1)
|
|
213
|
+
? { kind: "group", group: run.group, steps: run.steps }
|
|
214
|
+
: { kind: "stage", step: run.steps[0] },
|
|
186
215
|
);
|
|
216
|
+
}
|
|
187
217
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
"explore",
|
|
197
|
-
"Resolves repository evidence, unknowns, options, and direction.",
|
|
198
|
-
"It separates uncertainty from the proposal's committed motivation and scope.",
|
|
199
|
-
"mate-v1",
|
|
200
|
-
),
|
|
201
|
-
skillStep(
|
|
202
|
-
"proposal",
|
|
203
|
-
"proposal",
|
|
204
|
-
"Commits why the change is needed and what is in scope.",
|
|
205
|
-
"A written scope gives specs, design, and tasks one decision to build from.",
|
|
206
|
-
"mate-v1",
|
|
207
|
-
),
|
|
208
|
-
reviewStep(
|
|
209
|
-
"specs",
|
|
210
|
-
"specs",
|
|
211
|
-
"Defines the observable behavior the system must provide.",
|
|
212
|
-
"The delta is the contract that will later be merged into the canonical spec.",
|
|
213
|
-
"mate-v1",
|
|
214
|
-
),
|
|
215
|
-
reviewStep(
|
|
216
|
-
"design",
|
|
217
|
-
"design",
|
|
218
|
-
"Records the technical decisions for implementing the change.",
|
|
219
|
-
"Separating how from what exposes risks before implementation starts.",
|
|
220
|
-
"mate-v1",
|
|
221
|
-
),
|
|
222
|
-
reviewStep(
|
|
223
|
-
"tasks",
|
|
224
|
-
"tasks",
|
|
225
|
-
"Orders the implementation and verification work.",
|
|
226
|
-
"Small, ordered tasks turn the agreed artifacts into a trackable build path.",
|
|
227
|
-
"mate-v1",
|
|
228
|
-
),
|
|
229
|
-
withSessionBreak(
|
|
230
|
-
skillStep(
|
|
231
|
-
"apply",
|
|
232
|
-
"apply",
|
|
233
|
-
"Implements the change by working through the generated tasks.",
|
|
234
|
-
"Applying only approved tasks keeps code changes inside the agreed scope.",
|
|
235
|
-
"mate-v1",
|
|
236
|
-
),
|
|
237
|
-
),
|
|
238
|
-
],
|
|
239
|
-
},
|
|
240
|
-
{
|
|
241
|
-
profile: "mate-minimal",
|
|
242
|
-
label: "mate-minimal",
|
|
243
|
-
description:
|
|
244
|
-
"Short path that explores first, then creates only specs and tasks for one-Area, low-risk changes; switch to mate-v1 when uncertain.",
|
|
245
|
-
steps: [
|
|
246
|
-
skillStep(
|
|
247
|
-
"explore",
|
|
248
|
-
"explore",
|
|
249
|
-
"Resolves repository evidence, unknowns, options, and direction without adding a planning artifact.",
|
|
250
|
-
"It gives the minimal proposal step an agreed direction while keeping the output to specs and tasks.",
|
|
251
|
-
"mate-minimal",
|
|
252
|
-
),
|
|
253
|
-
skillStep(
|
|
254
|
-
"propose",
|
|
255
|
-
"propose",
|
|
256
|
-
"Creates the concise, parser-compatible specs and tasks from the explored direction.",
|
|
257
|
-
"OpenSpec turns the agreed direction into only the minimal profile's specs and tasks; proposal and design artifacts are intentionally omitted.",
|
|
258
|
-
"mate-minimal",
|
|
259
|
-
),
|
|
260
|
-
reviewStep(
|
|
261
|
-
"specs",
|
|
262
|
-
"specs",
|
|
263
|
-
"Defines the behavior change as a concise, parser-compatible user story.",
|
|
264
|
-
"Reviewing the generated delta confirms the small change before tasks are applied.",
|
|
265
|
-
"mate-minimal",
|
|
266
|
-
),
|
|
267
|
-
reviewStep(
|
|
268
|
-
"tasks",
|
|
269
|
-
"tasks",
|
|
270
|
-
"Orders the implementation and verification work.",
|
|
271
|
-
"The checklist keeps a deliberately small change concrete and reviewable.",
|
|
272
|
-
"mate-minimal",
|
|
273
|
-
),
|
|
274
|
-
withSessionBreak(
|
|
275
|
-
skillStep(
|
|
276
|
-
"apply",
|
|
277
|
-
"apply",
|
|
278
|
-
"Implements the change by working through the generated tasks.",
|
|
279
|
-
"Applying only the short approved checklist keeps the low-risk boundary intact.",
|
|
280
|
-
"mate-minimal",
|
|
281
|
-
),
|
|
282
|
-
),
|
|
283
|
-
],
|
|
284
|
-
},
|
|
285
|
-
];
|
|
218
|
+
export function buildPath(
|
|
219
|
+
schema: string,
|
|
220
|
+
artifacts: readonly string[] | undefined,
|
|
221
|
+
options: WorkflowPlanOptions,
|
|
222
|
+
): WorkflowPath {
|
|
223
|
+
const reported = options.skills ? new Set(options.skills) : null;
|
|
224
|
+
const available = (skill: string): boolean => !reported || reported.has(skill);
|
|
225
|
+
const contract = deliveryPath(artifacts);
|
|
286
226
|
|
|
287
|
-
const
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
227
|
+
const steps: WorkflowStep[] = [];
|
|
228
|
+
for (const stage of contract.stages) {
|
|
229
|
+
const text =
|
|
230
|
+
stage.kind === "human"
|
|
231
|
+
? reviewText(stage.artifact, options.topology, schema)
|
|
232
|
+
: STAGE_TEXT[stage.id];
|
|
233
|
+
const prompt = promptFor(stage, schema);
|
|
234
|
+
const previous = steps.at(-1);
|
|
235
|
+
const step: WorkflowStep = {
|
|
236
|
+
...stage,
|
|
237
|
+
what: text.what,
|
|
238
|
+
why: text.why,
|
|
239
|
+
badges: badgesFor(stage),
|
|
240
|
+
prompt,
|
|
241
|
+
copyPrompt: copyPromptFor(prompt),
|
|
242
|
+
phase: phaseOf(stage, previous?.phase),
|
|
243
|
+
};
|
|
244
|
+
if (stage.id === "clarify-intent") step.alternatives = clarifyAlternatives(available);
|
|
245
|
+
if (stage.kind === "skill" && !available(stage.skill)) step.missingSkill = stage.skill;
|
|
246
|
+
// A new session starts at apply; the optional peers after it reuse its context.
|
|
247
|
+
if (stage.id === "apply") step.sessionBreakBefore = true;
|
|
248
|
+
steps.push(step);
|
|
304
249
|
}
|
|
305
|
-
const archive = skillStep(
|
|
306
|
-
"archive",
|
|
307
|
-
"openspec archive change",
|
|
308
|
-
"Archives the verified change and its approved artifacts, applying its delta specs to the canonical specs.",
|
|
309
|
-
"Archiving validates the change, requires it to be complete, and is the precondition publishing refuses without.",
|
|
310
|
-
);
|
|
311
|
-
const finishStep = {
|
|
312
|
-
kind: "completion" as const,
|
|
313
|
-
id: "finish",
|
|
314
|
-
title: "mate artifact publish",
|
|
315
|
-
what: "Presents the already-archived changes and the drifted canonical specs as two selectable tables, then runs `mate artifact publish` for exactly what the developer picks — announcing that each selection is committed, tagged, and pushed to the companion Git repository before the first one runs.",
|
|
316
|
-
why: "It is the only sanctioned completion; a hand-committed publication leaves the anchor untagged and unrevertable, and a drifted spec shipped under an old archive's tag misfiles today's edit under a change that did not produce it.",
|
|
317
|
-
badges: ["skill"] as WorkflowStepBadge[],
|
|
318
|
-
};
|
|
319
250
|
|
|
320
251
|
return {
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
copyPrompt: stepPrompt(finishStep, undefined, false),
|
|
328
|
-
},
|
|
252
|
+
schema,
|
|
253
|
+
label: schema,
|
|
254
|
+
...pathText(schema),
|
|
255
|
+
steps,
|
|
256
|
+
map: mapOf(steps),
|
|
257
|
+
reviewsKnown: contract.reviewsKnown,
|
|
329
258
|
};
|
|
330
259
|
}
|
|
331
260
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
return
|
|
261
|
+
function schemaArtifacts(
|
|
262
|
+
schema: string,
|
|
263
|
+
topology: WorkflowTopology | null | undefined,
|
|
264
|
+
): readonly string[] | undefined {
|
|
265
|
+
if (topology?.schemaName === schema) return topology.artifacts.map((artifact) => artifact.id);
|
|
266
|
+
return isMateSchema(schema) ? SCHEMA_ARTIFACTS[schema] : undefined;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/** The Delivery Path Studio shows: a path per schema Mate ships, or the served schema's alone. */
|
|
270
|
+
export function workflowPlan(options: WorkflowPlanOptions = {}): WorkflowPlan {
|
|
271
|
+
const served = options.topology?.schemaName;
|
|
272
|
+
const schemas = served && !isMateSchema(served) ? [served] : Object.keys(SCHEMA_ARTIFACTS);
|
|
273
|
+
return {
|
|
274
|
+
paths: schemas.map((schema) =>
|
|
275
|
+
buildPath(schema, schemaArtifacts(schema, options.topology), options),
|
|
276
|
+
),
|
|
277
|
+
};
|
|
337
278
|
}
|
package/src/cli/commands/wrap.ts
CHANGED
|
@@ -4,7 +4,6 @@ import { FRAMEWORK_NAME } from "../../framework";
|
|
|
4
4
|
import { findRepoLocalLinkedRepository } from "../../lib/orchestrator/repository-link";
|
|
5
5
|
import type { ProjectionChangedPaths } from "../../lib/orchestrator/projection-types";
|
|
6
6
|
import { attendedLockOptions } from "../../lib/orchestrator/companion-git-sync";
|
|
7
|
-
import { readCompanionConfig } from "../../lib/orchestrator/config-store";
|
|
8
7
|
import { runWrapPass, type WrapPassResult } from "../../lib/orchestrator/wrap-pass";
|
|
9
8
|
import { withCompanionLock } from "../../runtime/companion-lock";
|
|
10
9
|
import { WRAP_RUNTIMES } from "../../runtime/wrap-state";
|
|
@@ -129,7 +128,8 @@ export async function runWrapCommand(
|
|
|
129
128
|
for (const document of result.documents) {
|
|
130
129
|
console.log(` Runtime: ${document}`);
|
|
131
130
|
}
|
|
132
|
-
|
|
131
|
+
const publication = result.claudePluginFolders?.publication;
|
|
132
|
+
for (const warning of [...result.warnings, ...(publication?.warnings ?? [])]) {
|
|
133
133
|
console.error(`${FRAMEWORK_NAME}: warning: ${warning}`);
|
|
134
134
|
}
|
|
135
135
|
reportChangedPaths(result.changed);
|
|
@@ -141,18 +141,10 @@ export async function runWrapCommand(
|
|
|
141
141
|
console.log(
|
|
142
142
|
`Start sessions yourself (${plain}) or through ${managed}; both work here. \`${FRAMEWORK_NAME} unwrap\` reverses this.`,
|
|
143
143
|
);
|
|
144
|
-
if (runtimes.has("claude")
|
|
144
|
+
if (!runtimes.has("claude")) return;
|
|
145
|
+
for (const unpublished of publication?.unpublished ?? []) {
|
|
145
146
|
console.log(
|
|
146
|
-
`Note:
|
|
147
|
+
`Note: ${unpublished.capability}'s Claude plugin folder ${unpublished.path} ${unpublished.detail}, so it loads only in sessions started with \`${FRAMEWORK_NAME} claude\`.`,
|
|
147
148
|
);
|
|
148
149
|
}
|
|
149
150
|
}
|
|
150
|
-
|
|
151
|
-
async function contextModeEnabled(companionPath: string): Promise<boolean> {
|
|
152
|
-
try {
|
|
153
|
-
const config = await readCompanionConfig(companionPath);
|
|
154
|
-
return (config.capabilities ?? []).some((capability) => capability.name === "context-mode");
|
|
155
|
-
} catch {
|
|
156
|
-
return false;
|
|
157
|
-
}
|
|
158
|
-
}
|
package/src/cli/main.ts
CHANGED
|
@@ -209,8 +209,11 @@ export async function main(argv = process.argv, deps: MainDeps = mainDeps): Prom
|
|
|
209
209
|
case "prepare":
|
|
210
210
|
if (!(await gate({ updateGuard: true }))) return;
|
|
211
211
|
break;
|
|
212
|
-
// open
|
|
212
|
+
// open lists every Linked Companion itself instead of selecting one.
|
|
213
213
|
case "open":
|
|
214
|
+
if (!(await gate({ updateGuard: true, notHubRoot: true }))) return;
|
|
215
|
+
break;
|
|
216
|
+
// tui/sync/update consume a companion context.
|
|
214
217
|
case "tui":
|
|
215
218
|
case "sync":
|
|
216
219
|
case "update":
|