@fission-ai/openspec 1.9.0 → 1.11.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/cli/index.d.ts +17 -0
- package/dist/cli/index.js +60 -9
- package/dist/commands/change.d.ts +24 -0
- package/dist/commands/change.js +223 -0
- package/dist/commands/config.js +14 -3
- package/dist/commands/feedback.js +28 -7
- package/dist/commands/schema.d.ts +5 -0
- package/dist/commands/schema.js +201 -35
- package/dist/commands/show.js +1 -1
- package/dist/commands/workflow/index.d.ts +1 -1
- package/dist/commands/workflow/index.js +1 -1
- package/dist/commands/workflow/status.d.ts +2 -0
- package/dist/commands/workflow/status.js +76 -12
- package/dist/core/archive.js +64 -7
- package/dist/core/artifact-graph/instruction-loader.js +2 -7
- package/dist/core/artifact-graph/outputs.d.ts +4 -0
- package/dist/core/artifact-graph/outputs.js +7 -0
- package/dist/core/artifact-graph/resolver.js +15 -9
- package/dist/core/available-tools.js +16 -1
- package/dist/core/command-generation/adapters/antigravity.d.ts +1 -1
- package/dist/core/command-generation/adapters/antigravity.js +2 -2
- package/dist/core/command-generation/adapters/opencode.d.ts +2 -1
- package/dist/core/command-generation/adapters/opencode.js +13 -2
- package/dist/core/completion-tip.d.ts +15 -0
- package/dist/core/completion-tip.js +133 -0
- package/dist/core/completions/command-registry.js +20 -0
- package/dist/core/completions/factory.d.ts +11 -0
- package/dist/core/completions/generators/fish-generator.d.ts +12 -0
- package/dist/core/completions/generators/fish-generator.js +79 -47
- package/dist/core/completions/installers/bash-installer.d.ts +7 -0
- package/dist/core/completions/installers/bash-installer.js +15 -0
- package/dist/core/completions/installers/fish-installer.d.ts +7 -0
- package/dist/core/completions/installers/fish-installer.js +15 -0
- package/dist/core/completions/installers/powershell-installer.d.ts +7 -0
- package/dist/core/completions/installers/powershell-installer.js +15 -0
- package/dist/core/completions/templates/fish-templates.d.ts +1 -1
- package/dist/core/completions/templates/fish-templates.js +107 -10
- package/dist/core/completions/types.d.ts +4 -0
- package/dist/core/config-prompts.js +19 -10
- package/dist/core/config-schema.d.ts +1 -0
- package/dist/core/config-schema.js +2 -0
- package/dist/core/config.js +7 -1
- package/dist/core/global-config.d.ts +2 -0
- package/dist/core/init.d.ts +5 -0
- package/dist/core/init.js +117 -14
- package/dist/core/legacy-cleanup.js +6 -0
- package/dist/core/migration.js +42 -12
- package/dist/core/parsers/requirement-blocks.d.ts +1 -0
- package/dist/core/parsers/requirement-blocks.js +2 -0
- package/dist/core/profiles.d.ts +1 -1
- package/dist/core/profiles.js +11 -2
- package/dist/core/shared/tool-detection.js +9 -3
- package/dist/core/shared-skill-target.d.ts +13 -0
- package/dist/core/shared-skill-target.js +43 -1
- package/dist/core/specs-apply.js +16 -8
- package/dist/core/templates/workflows/explore.js +79 -73
- package/dist/core/templates/workflows/feedback.js +1 -0
- package/dist/core/templates/workflows/onboard.js +4 -4
- package/dist/core/update.js +39 -26
- package/dist/core/validation/constants.d.ts +3 -0
- package/dist/core/validation/constants.js +12 -0
- package/dist/core/validation/purpose-placeholder.d.ts +45 -0
- package/dist/core/validation/purpose-placeholder.js +117 -0
- package/dist/core/validation/validator.js +16 -1
- package/dist/telemetry/index.js +3 -2
- package/dist/utils/change-metadata.js +17 -13
- package/dist/utils/change-utils.js +5 -0
- package/dist/utils/requirement-diff.d.ts +42 -0
- package/dist/utils/requirement-diff.js +61 -0
- package/package.json +4 -6
- package/schemas/spec-driven/schema.yaml +17 -7
- package/scripts/postinstall.js +0 -83
|
@@ -115,12 +115,14 @@ export function parseDeltaSpec(content) {
|
|
|
115
115
|
sink: skippedHeaders,
|
|
116
116
|
});
|
|
117
117
|
const removedNames = parseRemovedNames(removedLookup.body);
|
|
118
|
+
const removedBlocks = parseRequirementBlocksFromSection(removedLookup.body);
|
|
118
119
|
const renamedPairs = parseRenamedPairs(renamedLookup.body);
|
|
119
120
|
skippedHeaders.sort((a, b) => a.line - b.line);
|
|
120
121
|
return {
|
|
121
122
|
added,
|
|
122
123
|
modified,
|
|
123
124
|
removed: removedNames,
|
|
125
|
+
removedBlocks,
|
|
124
126
|
renamed: renamedPairs,
|
|
125
127
|
skippedHeaders,
|
|
126
128
|
sectionPresence: {
|
package/dist/core/profiles.d.ts
CHANGED
|
@@ -20,7 +20,7 @@ export type CoreWorkflowId = (typeof CORE_WORKFLOWS)[number];
|
|
|
20
20
|
* Resolves which workflows should be active for a given profile configuration.
|
|
21
21
|
*
|
|
22
22
|
* - 'core' profile always returns CORE_WORKFLOWS
|
|
23
|
-
* - 'custom' profile returns the provided customWorkflows
|
|
23
|
+
* - 'custom' profile returns the provided customWorkflows and required dependencies
|
|
24
24
|
*/
|
|
25
25
|
export declare function getProfileWorkflows(profile: Profile, customWorkflows?: string[]): readonly string[];
|
|
26
26
|
//# sourceMappingURL=profiles.d.ts.map
|
package/dist/core/profiles.js
CHANGED
|
@@ -30,11 +30,20 @@ export const ALL_WORKFLOWS = [
|
|
|
30
30
|
* Resolves which workflows should be active for a given profile configuration.
|
|
31
31
|
*
|
|
32
32
|
* - 'core' profile always returns CORE_WORKFLOWS
|
|
33
|
-
* - 'custom' profile returns the provided customWorkflows
|
|
33
|
+
* - 'custom' profile returns the provided customWorkflows and required dependencies
|
|
34
34
|
*/
|
|
35
35
|
export function getProfileWorkflows(profile, customWorkflows) {
|
|
36
36
|
if (profile === 'custom') {
|
|
37
|
-
|
|
37
|
+
const workflows = customWorkflows ?? [];
|
|
38
|
+
const syncDependentIndex = workflows.findIndex((workflow) => workflow === 'archive' || workflow === 'bulk-archive');
|
|
39
|
+
if (syncDependentIndex !== -1 && !workflows.includes('sync')) {
|
|
40
|
+
return [
|
|
41
|
+
...workflows.slice(0, syncDependentIndex),
|
|
42
|
+
'sync',
|
|
43
|
+
...workflows.slice(syncDependentIndex),
|
|
44
|
+
];
|
|
45
|
+
}
|
|
46
|
+
return workflows;
|
|
38
47
|
}
|
|
39
48
|
return CORE_WORKFLOWS;
|
|
40
49
|
}
|
|
@@ -10,8 +10,8 @@ import { CommandAdapterRegistry, generateCommands } from '../command-generation/
|
|
|
10
10
|
import { getCommandContents } from './skill-generation.js';
|
|
11
11
|
import { getGlobalConfig } from '../global-config.js';
|
|
12
12
|
import { getProfileWorkflows, ALL_WORKFLOWS } from '../profiles.js';
|
|
13
|
-
import { isSharedSkillTargetActive, readSharedSkillTarget, reconcileSharedSkillTargets, } from '../shared-skill-target.js';
|
|
14
|
-
import { shouldGenerateCommandsForTool, shouldGenerateSkillsForTool, } from '../command-surface.js';
|
|
13
|
+
import { isSharedSkillTargetActive, hasLegacySkills, readSharedSkillTarget, reconcileSharedSkillTargets, } from '../shared-skill-target.js';
|
|
14
|
+
import { shouldGenerateCommandsForTool, shouldGenerateSkillsForTool, resolveCommandSurfaceCapability, } from '../command-surface.js';
|
|
15
15
|
import { getSkillCapableTools, resolveToolSkillsDir, toolSupportsSkills, } from './skill-paths.js';
|
|
16
16
|
/**
|
|
17
17
|
* Names of skill directories created by openspec init.
|
|
@@ -272,12 +272,18 @@ export function getConfiguredTools(projectRoot) {
|
|
|
272
272
|
return false;
|
|
273
273
|
return (getToolSkillStatus(projectRoot, t.value).configured ||
|
|
274
274
|
toolHasAnyConfiguredCommand(projectRoot, t.value) ||
|
|
275
|
+
(resolveCommandSurfaceCapability(t.value) === 'adapter-backed' &&
|
|
276
|
+
hasLegacySkills(projectRoot, t)) ||
|
|
275
277
|
(Boolean(t.skillsDir) &&
|
|
276
278
|
readSharedSkillTarget(projectRoot, t.skillsDir) === t.value));
|
|
277
279
|
});
|
|
278
280
|
const activeProjectTools = new Set(reconcileSharedSkillTargets(projectRoot, configured.filter((tool) => tool.skillsDir)).map((tool) => tool.value));
|
|
279
281
|
return configured
|
|
280
|
-
.filter((tool) => tool.globalSkillsDir ||
|
|
282
|
+
.filter((tool) => tool.globalSkillsDir ||
|
|
283
|
+
toolHasAnyConfiguredCommand(projectRoot, tool.value) ||
|
|
284
|
+
(resolveCommandSurfaceCapability(tool.value) === 'adapter-backed' &&
|
|
285
|
+
hasLegacySkills(projectRoot, tool)) ||
|
|
286
|
+
activeProjectTools.has(tool.value))
|
|
281
287
|
.map((tool) => tool.value);
|
|
282
288
|
}
|
|
283
289
|
/**
|
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
import { type AIToolOption } from './config.js';
|
|
2
2
|
/** Reads a valid-looking marker value without letting linked roots escape. */
|
|
3
3
|
export declare function readSharedSkillTarget(projectPath: string, skillsDir: string): string | undefined;
|
|
4
|
+
/** Whether a tool still has an allowlisted managed skill under an old root. */
|
|
5
|
+
export declare function hasLegacySkills(projectPath: string, tool: AIToolOption): boolean;
|
|
6
|
+
/**
|
|
7
|
+
* Chooses the one selected tool that may render each physical skills root.
|
|
8
|
+
* Command files are not part of this arbitration: tools that share a skills
|
|
9
|
+
* root can still write their own command surface elsewhere under that root.
|
|
10
|
+
*
|
|
11
|
+
* Existing compatible owners win. On a new root, prefer a skills-native
|
|
12
|
+
* renderer over an adapter-backed renderer because its references remain
|
|
13
|
+
* usable by every consumer of the shared tree. Codex is the best fresh owner
|
|
14
|
+
* because its renderer includes both Codex and generic skill invocation forms.
|
|
15
|
+
*/
|
|
16
|
+
export declare function resolveSharedSkillWriters(projectPath: string, tools: AIToolOption[]): Set<string>;
|
|
4
17
|
/**
|
|
5
18
|
* A shared skill root can only hold one rendered variant of each skill.
|
|
6
19
|
* Keep the writer recorded so later updates do not infer every tool that
|
|
@@ -2,6 +2,7 @@ import path from 'path';
|
|
|
2
2
|
import * as fs from 'fs';
|
|
3
3
|
import { AI_TOOLS, OPENSPEC_SKILL_NAMES } from './config.js';
|
|
4
4
|
import { FileSystemUtils } from '../utils/file-system.js';
|
|
5
|
+
import { resolveCommandSurfaceCapability } from './command-surface.js';
|
|
5
6
|
const TARGET_MARKER = '.openspec-target';
|
|
6
7
|
/** Returns the ownership-marker path for one shared skills root. */
|
|
7
8
|
function markerPath(projectPath, skillsDir) {
|
|
@@ -19,7 +20,7 @@ export function readSharedSkillTarget(projectPath, skillsDir) {
|
|
|
19
20
|
}
|
|
20
21
|
}
|
|
21
22
|
/** Whether a tool still has an allowlisted managed skill under an old root. */
|
|
22
|
-
function hasLegacySkills(projectPath, tool) {
|
|
23
|
+
export function hasLegacySkills(projectPath, tool) {
|
|
23
24
|
return (tool.legacySkillsDirs ?? []).some((root) => {
|
|
24
25
|
const skillsDir = path.join(projectPath, root, 'skills');
|
|
25
26
|
return OPENSPEC_SKILL_NAMES.some((skillName) => {
|
|
@@ -69,6 +70,47 @@ function hasCurrentSkills(projectPath, skillsDir) {
|
|
|
69
70
|
}
|
|
70
71
|
});
|
|
71
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* Chooses the one selected tool that may render each physical skills root.
|
|
75
|
+
* Command files are not part of this arbitration: tools that share a skills
|
|
76
|
+
* root can still write their own command surface elsewhere under that root.
|
|
77
|
+
*
|
|
78
|
+
* Existing compatible owners win. On a new root, prefer a skills-native
|
|
79
|
+
* renderer over an adapter-backed renderer because its references remain
|
|
80
|
+
* usable by every consumer of the shared tree. Codex is the best fresh owner
|
|
81
|
+
* because its renderer includes both Codex and generic skill invocation forms.
|
|
82
|
+
*/
|
|
83
|
+
export function resolveSharedSkillWriters(projectPath, tools) {
|
|
84
|
+
const byRoot = new Map();
|
|
85
|
+
const writers = new Set();
|
|
86
|
+
for (const tool of tools) {
|
|
87
|
+
if (!tool.skillsDir)
|
|
88
|
+
continue;
|
|
89
|
+
const group = byRoot.get(tool.skillsDir) ?? [];
|
|
90
|
+
group.push(tool);
|
|
91
|
+
byRoot.set(tool.skillsDir, group);
|
|
92
|
+
}
|
|
93
|
+
for (const [root, unsortedGroup] of byRoot) {
|
|
94
|
+
const group = [...unsortedGroup].sort((left, right) => AI_TOOLS.indexOf(left) - AI_TOOLS.indexOf(right));
|
|
95
|
+
if (group.length === 1) {
|
|
96
|
+
writers.add(group[0].value);
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
const skillsNative = group.filter((tool) => resolveCommandSurfaceCapability(tool.value) !== 'adapter-backed');
|
|
100
|
+
const preferredPool = skillsNative.length > 0 ? skillsNative : group;
|
|
101
|
+
const marked = readSharedSkillTarget(projectPath, root);
|
|
102
|
+
const inferred = inferSharedSkillTarget(projectPath, root);
|
|
103
|
+
const owner = preferredPool.find((tool) => tool.value === marked) ??
|
|
104
|
+
preferredPool.find((tool) => tool.value === inferred) ??
|
|
105
|
+
(hasCurrentSkills(projectPath, root)
|
|
106
|
+
? preferredPool.find((tool) => tool.value === 'agents')
|
|
107
|
+
: undefined) ??
|
|
108
|
+
preferredPool.find((tool) => tool.value === 'codex') ??
|
|
109
|
+
preferredPool[0];
|
|
110
|
+
writers.add(owner.value);
|
|
111
|
+
}
|
|
112
|
+
return writers;
|
|
113
|
+
}
|
|
72
114
|
/**
|
|
73
115
|
* A shared skill root can only hold one rendered variant of each skill.
|
|
74
116
|
* Keep the writer recorded so later updates do not infer every tool that
|
package/dist/core/specs-apply.js
CHANGED
|
@@ -12,7 +12,7 @@ import { extractRequirementsSection, findMissingCurrentScenarios, foldRequiremen
|
|
|
12
12
|
import { findMainSpecStructureIssues } from './parsers/spec-structure.js';
|
|
13
13
|
import { buildCodeFenceMask } from './parsers/code-fence.js';
|
|
14
14
|
import { MarkdownParser } from './parsers/markdown-parser.js';
|
|
15
|
-
import { MIN_PURPOSE_LENGTH } from './validation/constants.js';
|
|
15
|
+
import { MIN_PURPOSE_LENGTH, PURPOSE_PLACEHOLDER_PREFIX, PURPOSE_PLACEHOLDER_SUFFIX, } from './validation/constants.js';
|
|
16
16
|
import { discoverSpecFiles } from '../utils/spec-discovery.js';
|
|
17
17
|
import { FileSystemUtils } from '../utils/file-system.js';
|
|
18
18
|
function isLexicallyWithin(allowedDirectory, targetPath) {
|
|
@@ -254,10 +254,12 @@ export async function buildUpdatedSpec(update, changeName, options = {}) {
|
|
|
254
254
|
for (const block of parts.bodyBlocks) {
|
|
255
255
|
nameToBlock.set(normalizeRequirementName(block.name), block);
|
|
256
256
|
}
|
|
257
|
+
// Keep source blocks immutable for loss attribution. This parallel key list
|
|
258
|
+
// carries only positional identity as renames change lookup keys.
|
|
259
|
+
const orderedKeys = parts.bodyBlocks.map((block) => normalizeRequirementName(block.name));
|
|
257
260
|
// Apply operations in order: RENAMED → REMOVED → MODIFIED → ADDED
|
|
258
261
|
// RENAMED
|
|
259
262
|
let renamedApplied = 0;
|
|
260
|
-
const renamedTargets = new Map();
|
|
261
263
|
for (const r of plan.renamed) {
|
|
262
264
|
const from = normalizeRequirementName(r.from);
|
|
263
265
|
const to = normalizeRequirementName(r.to);
|
|
@@ -291,7 +293,12 @@ export async function buildUpdatedSpec(update, changeName, options = {}) {
|
|
|
291
293
|
};
|
|
292
294
|
nameToBlock.delete(from);
|
|
293
295
|
nameToBlock.set(to, renamedBlock);
|
|
294
|
-
|
|
296
|
+
// A Map delete+set moves the renamed block to insertion-order tail. Carry
|
|
297
|
+
// its new key in the source slot instead; chained renames update it again.
|
|
298
|
+
const orderIndex = orderedKeys.indexOf(from);
|
|
299
|
+
if (orderIndex >= 0) {
|
|
300
|
+
orderedKeys[orderIndex] = to;
|
|
301
|
+
}
|
|
295
302
|
renamedApplied++;
|
|
296
303
|
}
|
|
297
304
|
// REMOVED
|
|
@@ -364,8 +371,9 @@ export async function buildUpdatedSpec(update, changeName, options = {}) {
|
|
|
364
371
|
// Recompose requirements section preserving original ordering where possible
|
|
365
372
|
const keptOrder = [];
|
|
366
373
|
const seen = new Set();
|
|
367
|
-
for (
|
|
368
|
-
const
|
|
374
|
+
for (let index = 0; index < parts.bodyBlocks.length; index++) {
|
|
375
|
+
const block = parts.bodyBlocks[index];
|
|
376
|
+
const key = orderedKeys[index];
|
|
369
377
|
const replacement = nameToBlock.get(key);
|
|
370
378
|
if (replacement) {
|
|
371
379
|
keptOrder.push(replacement);
|
|
@@ -377,8 +385,7 @@ export async function buildUpdatedSpec(update, changeName, options = {}) {
|
|
|
377
385
|
// full absorbed suffix. RENAMED carries the original raw content under a
|
|
378
386
|
// new map key, and MODIFIED may repeat the suffix deliberately; neither is
|
|
379
387
|
// data loss.
|
|
380
|
-
const
|
|
381
|
-
const replacementFromOriginal = replacement ?? (renamedTarget ? nameToBlock.get(renamedTarget) : undefined);
|
|
388
|
+
const replacementFromOriginal = replacement;
|
|
382
389
|
if (replacementFromOriginal !== block) {
|
|
383
390
|
const foreign = firstForeignTail(block.raw);
|
|
384
391
|
const replacementRaw = replacementFromOriginal?.raw;
|
|
@@ -917,7 +924,8 @@ function readableOverview(skeleton, specName) {
|
|
|
917
924
|
*/
|
|
918
925
|
export function buildSpecSkeleton(specFolderName, changeName, purpose) {
|
|
919
926
|
const titleBase = specFolderName;
|
|
920
|
-
const purposeBody = purpose?.trim() ||
|
|
927
|
+
const purposeBody = purpose?.trim() ||
|
|
928
|
+
`${PURPOSE_PLACEHOLDER_PREFIX}${changeName}${PURPOSE_PLACEHOLDER_SUFFIX}`;
|
|
921
929
|
return `# ${titleBase} Specification\n\n## Purpose\n${purposeBody}\n\n## Requirements\n`;
|
|
922
930
|
}
|
|
923
931
|
//# sourceMappingURL=specs-apply.js.map
|
|
@@ -5,7 +5,7 @@ export function getExploreSkillTemplate() {
|
|
|
5
5
|
description: 'Enter explore mode - a thinking partner for exploring ideas, investigating problems, and clarifying requirements. Use when the user wants to think through something before or during a change.',
|
|
6
6
|
instructions: `Enter explore mode. Think deeply. Visualize freely. Follow the conversation wherever it goes.
|
|
7
7
|
|
|
8
|
-
**IMPORTANT: Explore mode is for thinking, not implementing.** You may read files, search code,
|
|
8
|
+
**IMPORTANT: Explore mode is for thinking, not implementing.** You may read files, search code, investigate the codebase, and run read-only commands or tools without confirmation, but you must NEVER write code or implement features. If the user asks you to implement something, remind them to exit explore mode first and create a change proposal. You MAY create or update OpenSpec change artifacts (proposals, designs, specs) within a confirmed scope—that's capturing thinking, not implementing. Answering design or clarifying questions is never consent to write. Before the first write-capable action, name the artifacts or files you would change and what you would do, ask a direct yes/no question, and wait for the user's confirmation in a separate message. Confirmation covers only the scope you described; ask again before expanding it. For a new change, scaffold it first as described below.
|
|
9
9
|
|
|
10
10
|
**This is a stance, not a workflow.** There are no fixed steps, no required sequence, no mandatory outputs. You're a thinking partner helping the user explore.
|
|
11
11
|
|
|
@@ -48,22 +48,25 @@ Depending on what the user brings, you might:
|
|
|
48
48
|
|
|
49
49
|
**Visualize**
|
|
50
50
|
\`\`\`
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
51
|
+
+------------------------------------------+
|
|
52
|
+
| Use ASCII diagrams liberally |
|
|
53
|
+
+------------------------------------------+
|
|
54
|
+
| |
|
|
55
|
+
| [State A] -------> [State B] |
|
|
56
|
+
| | |
|
|
57
|
+
| v |
|
|
58
|
+
| [State C] |
|
|
59
|
+
| |
|
|
60
|
+
| System diagrams, state machines, |
|
|
61
|
+
| data flows, architecture sketches, |
|
|
62
|
+
| dependency graphs, comparison tables |
|
|
63
|
+
| |
|
|
64
|
+
+------------------------------------------+
|
|
65
65
|
\`\`\`
|
|
66
66
|
|
|
67
|
+
**Draw with plain ASCII only** — borders \`+\` \`-\` \`|\`, arrows \`-->\` \`<--\` \`^\` \`v\`, markers \`*\` \`x\`.
|
|
68
|
+
Unicode diagram glyphs can render at different widths across terminals, fonts, and locales, so padded boxes and aligned tables can drift. Keep every diagram character ASCII.
|
|
69
|
+
|
|
67
70
|
**Surface risks and unknowns**
|
|
68
71
|
- Identify what could go wrong
|
|
69
72
|
- Find gaps in understanding
|
|
@@ -164,17 +167,17 @@ User: I'm thinking about adding real-time collaboration
|
|
|
164
167
|
You: Real-time collab is a big space. Let me think about this...
|
|
165
168
|
|
|
166
169
|
COLLABORATION SPECTRUM
|
|
167
|
-
|
|
170
|
+
============================================
|
|
168
171
|
|
|
169
172
|
Awareness Coordination Sync
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
173
|
+
| | |
|
|
174
|
+
v v v
|
|
175
|
+
+--------+ +--------+ +--------+
|
|
176
|
+
|Presence| |Cursors | | CRDT |
|
|
177
|
+
| "3 | | Multi | |Conflict|
|
|
178
|
+
|online" | | select | | free |
|
|
179
|
+
+--------+ +--------+ +--------+
|
|
180
|
+
| | |
|
|
178
181
|
trivial moderate complex
|
|
179
182
|
|
|
180
183
|
Where's your head at?
|
|
@@ -186,27 +189,27 @@ User: The auth system is a mess
|
|
|
186
189
|
|
|
187
190
|
You: [reads codebase]
|
|
188
191
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
192
|
+
+---------------------------------------------+
|
|
193
|
+
| CURRENT AUTH FLOW |
|
|
194
|
+
+---------------------------------------------+
|
|
195
|
+
|
|
|
196
|
+
+-------------+-------------+
|
|
197
|
+
v v v
|
|
198
|
+
+---------+ +---------+ +---------+
|
|
199
|
+
| Google | | GitHub | | Email |
|
|
200
|
+
| OAuth | | OAuth | | Magic |
|
|
201
|
+
+----+----+ +----+----+ +----+----+
|
|
202
|
+
| | |
|
|
203
|
+
+-------------+-------------+
|
|
204
|
+
v
|
|
205
|
+
+-----------+
|
|
206
|
+
| Session |
|
|
207
|
+
+-----+-----+
|
|
208
|
+
|
|
|
209
|
+
v
|
|
210
|
+
+-----------+
|
|
211
|
+
| Perms |
|
|
212
|
+
+-----------+
|
|
210
213
|
|
|
211
214
|
I see three tangles. Which one's burning?
|
|
212
215
|
\`\`\`
|
|
@@ -238,19 +241,19 @@ User: A CLI tool that tracks local dev environments
|
|
|
238
241
|
|
|
239
242
|
You: That changes everything.
|
|
240
243
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
+
+-------------------------------------------------+
|
|
245
|
+
| CLI TOOL DATA STORAGE |
|
|
246
|
+
+-------------------------------------------------+
|
|
244
247
|
|
|
245
248
|
Key constraints:
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
+
- No daemon running
|
|
250
|
+
- Must work offline
|
|
251
|
+
- Single user
|
|
249
252
|
|
|
250
253
|
SQLite Postgres
|
|
251
|
-
Deployment embedded
|
|
252
|
-
Offline yes
|
|
253
|
-
Single file yes
|
|
254
|
+
Deployment embedded needs server
|
|
255
|
+
Offline yes no
|
|
256
|
+
Single file yes no
|
|
254
257
|
|
|
255
258
|
SQLite. Not even close.
|
|
256
259
|
|
|
@@ -290,11 +293,11 @@ But this summary is optional. Sometimes the thinking IS the value.
|
|
|
290
293
|
|
|
291
294
|
## Guardrails
|
|
292
295
|
|
|
293
|
-
- **Don't implement** - Never write code or implement features. Creating OpenSpec artifacts is fine, writing
|
|
296
|
+
- **Don't implement** - Never write code or implement features. Workflow configuration counts too: creating or editing schemas, templates, or \`openspec/config.yaml\` is a change, not thinking. Creating or updating OpenSpec change artifacts within the confirmed scope is fine, writing anything else is not.
|
|
294
297
|
- **Don't fake understanding** - If something is unclear, dig deeper
|
|
295
298
|
- **Don't rush** - Discovery is thinking time, not task time
|
|
296
299
|
- **Don't force structure** - Let patterns emerge naturally
|
|
297
|
-
- **Don't auto-capture** - Offer to save insights, don't just do it
|
|
300
|
+
- **Don't auto-capture** - Offer to save insights, don't just do it. Read-only commands and tools need no confirmation. Before the first write-capable action—including \`openspec new change\` or another command that writes files—name the artifacts or files and proposed changes, ask a direct yes/no question, and wait for explicit confirmation in a separate user message. That confirmation covers only the described scope; ask again before expanding it. Answers to design or clarifying questions are never consent to write.
|
|
298
301
|
- **Don't manually scaffold changes** - Never create a new change directory under \`openspec/changes/\` by hand. Always use \`openspec new change "<name>"\` (with \`--store <id>\` when applicable) so required metadata such as \`.openspec.yaml\` is created before writing artifacts.
|
|
299
302
|
- **Do visualize** - A good diagram is worth many paragraphs
|
|
300
303
|
- **Do explore the codebase** - Ground discussions in reality
|
|
@@ -312,7 +315,7 @@ export function getOpsxExploreCommandTemplate() {
|
|
|
312
315
|
tags: ['workflow', 'explore', 'experimental', 'thinking'],
|
|
313
316
|
content: `Enter explore mode. Think deeply. Visualize freely. Follow the conversation wherever it goes.
|
|
314
317
|
|
|
315
|
-
**IMPORTANT: Explore mode is for thinking, not implementing.** You may read files, search code,
|
|
318
|
+
**IMPORTANT: Explore mode is for thinking, not implementing.** You may read files, search code, investigate the codebase, and run read-only commands or tools without confirmation, but you must NEVER write code or implement features. If the user asks you to implement something, remind them to exit explore mode first and create a change proposal. You MAY create or update OpenSpec change artifacts (proposals, designs, specs) within a confirmed scope—that's capturing thinking, not implementing. Answering design or clarifying questions is never consent to write. Before the first write-capable action, name the artifacts or files you would change and what you would do, ask a direct yes/no question, and wait for the user's confirmation in a separate message. Confirmation covers only the scope you described; ask again before expanding it. For a new change, scaffold it first as described below.
|
|
316
319
|
|
|
317
320
|
**This is a stance, not a workflow.** There are no fixed steps, no required sequence, no mandatory outputs. You're a thinking partner helping the user explore.
|
|
318
321
|
|
|
@@ -362,22 +365,25 @@ Depending on what the user brings, you might:
|
|
|
362
365
|
|
|
363
366
|
**Visualize**
|
|
364
367
|
\`\`\`
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
368
|
+
+------------------------------------------+
|
|
369
|
+
| Use ASCII diagrams liberally |
|
|
370
|
+
+------------------------------------------+
|
|
371
|
+
| |
|
|
372
|
+
| [State A] -------> [State B] |
|
|
373
|
+
| | |
|
|
374
|
+
| v |
|
|
375
|
+
| [State C] |
|
|
376
|
+
| |
|
|
377
|
+
| System diagrams, state machines, |
|
|
378
|
+
| data flows, architecture sketches, |
|
|
379
|
+
| dependency graphs, comparison tables |
|
|
380
|
+
| |
|
|
381
|
+
+------------------------------------------+
|
|
379
382
|
\`\`\`
|
|
380
383
|
|
|
384
|
+
**Draw with plain ASCII only** — borders \`+\` \`-\` \`|\`, arrows \`-->\` \`<--\` \`^\` \`v\`, markers \`*\` \`x\`.
|
|
385
|
+
Unicode diagram glyphs can render at different widths across terminals, fonts, and locales, so padded boxes and aligned tables can drift. Keep every diagram character ASCII.
|
|
386
|
+
|
|
381
387
|
**Surface risks and unknowns**
|
|
382
388
|
- Identify what could go wrong
|
|
383
389
|
- Find gaps in understanding
|
|
@@ -486,11 +492,11 @@ When things crystallize, you might offer a summary - but it's optional. Sometime
|
|
|
486
492
|
|
|
487
493
|
## Guardrails
|
|
488
494
|
|
|
489
|
-
- **Don't implement** - Never write code or implement features. Creating OpenSpec artifacts is fine, writing
|
|
495
|
+
- **Don't implement** - Never write code or implement features. Workflow configuration counts too: creating or editing schemas, templates, or \`openspec/config.yaml\` is a change, not thinking. Creating or updating OpenSpec change artifacts within the confirmed scope is fine, writing anything else is not.
|
|
490
496
|
- **Don't fake understanding** - If something is unclear, dig deeper
|
|
491
497
|
- **Don't rush** - Discovery is thinking time, not task time
|
|
492
498
|
- **Don't force structure** - Let patterns emerge naturally
|
|
493
|
-
- **Don't auto-capture** - Offer to save insights, don't just do it
|
|
499
|
+
- **Don't auto-capture** - Offer to save insights, don't just do it. Read-only commands and tools need no confirmation. Before the first write-capable action—including \`openspec new change\` or another command that writes files—name the artifacts or files and proposed changes, ask a direct yes/no question, and wait for explicit confirmation in a separate user message. That confirmation covers only the described scope; ask again before expanding it. Answers to design or clarifying questions are never consent to write.
|
|
494
500
|
- **Don't manually scaffold changes** - Never create a new change directory under \`openspec/changes/\` by hand. Always use \`openspec new change "<name>"\` (with \`--store <id>\` when applicable) so required metadata such as \`.openspec.yaml\` is created before writing artifacts.
|
|
495
501
|
- **Do visualize** - A good diagram is worth many paragraphs
|
|
496
502
|
- **Do explore the codebase** - Ground discussions in reality
|
|
@@ -39,6 +39,7 @@ export function getFeedbackSkillTemplate() {
|
|
|
39
39
|
5. **Submit on confirmation**
|
|
40
40
|
- Use the \`openspec feedback\` command to submit
|
|
41
41
|
- Format: \`openspec feedback "title" --body "body content"\`
|
|
42
|
+
- The command preserves the title text in the issue body and shortens long GitHub issue titles
|
|
42
43
|
- The command will automatically add metadata (version, platform, timestamp)
|
|
43
44
|
|
|
44
45
|
**Example Draft**
|
|
@@ -374,12 +374,12 @@ Here are the implementation tasks:
|
|
|
374
374
|
|
|
375
375
|
## 1. [Category or file]
|
|
376
376
|
|
|
377
|
-
- [ ] 1.1 [Specific task]
|
|
378
|
-
- [ ] 1.2 [Specific task]
|
|
377
|
+
- [ ] 1.1 [Specific task] — verify: [test, command, observable behavior, or delivered artifact]
|
|
378
|
+
- [ ] 1.2 [Specific task] — verify: [test, command, observable behavior, or delivered artifact]
|
|
379
379
|
|
|
380
|
-
## 2.
|
|
380
|
+
## 2. Integration Verification
|
|
381
381
|
|
|
382
|
-
- [ ] 2.1 [
|
|
382
|
+
- [ ] 2.1 Verify [broader integration or system behavior] with [end-to-end test or observable result]
|
|
383
383
|
|
|
384
384
|
---
|
|
385
385
|
|