File size: 9,437 Bytes
391c43e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
import type { InterviewTemplate } from './types';

/** Built-in interview templates. The format is data, so user-authored templates can slot in later. */

const UNDERSTAND_COMPANY: InterviewTemplate = {
  id: 'understand-company',
  title: 'Understand a company',
  description: 'Build a profile of a company β€” what it does, who it serves, and its brand β€” to inform later work.',
  artifacts: [{ path: '/.interviews/company-profile.md', description: 'The company profile' }],
  items: [
    {
      id: 'identity',
      elicit: "The company's name and a one-line description of what it does.",
      completion: [{ type: 'judge', criteria: 'The /.interviews/company-profile.md artifact states the company name and a clear description of what it does.', description: 'Name and description recorded' }],
    },
    {
      id: 'audience',
      elicit: 'Who the company serves β€” its target customers or audience.',
      completion: [{ type: 'judge', criteria: 'The company-profile artifact describes the target audience or customers.', description: 'Audience recorded' }],
    },
    {
      id: 'offerings',
      elicit: 'The main products or services the company offers.',
      completion: [{ type: 'judge', criteria: 'The company-profile artifact lists the main products or services.', description: 'Offerings recorded' }],
    },
    {
      id: 'brand',
      elicit: "The brand's tone and any visual identity (colors, fonts). If they have a logo, ask them to add it to the project, then confirm it with ls.",
      completion: [{ type: 'judge', criteria: 'The company-profile artifact describes the brand tone or visual identity, and notes the logo status (present at a path, or none).', description: 'Brand and logo status recorded' }],
    },
    {
      id: 'assets',
      required: false,
      elicit: 'Any existing assets already in the project (logo, images, copy) β€” check with ls and note what is present.',
      completion: [{ type: 'judge', criteria: 'The company-profile artifact notes any existing project assets (or states there are none).', description: 'Existing assets noted' }],
    },
  ],
  handoff: {
    label: 'Build a site from this',
    prompt: 'Build a website for this company using the profile in /.interviews/company-profile.md.',
    mode: 'code',
  },
};

const PLAN_FEATURE: InterviewTemplate = {
  id: 'plan-feature',
  title: 'Plan a feature',
  description: 'Turn a feature idea into a clear, buildable spec through a few focused questions.',
  artifacts: [{ path: '/.interviews/feature-plan.md', description: 'The feature spec' }],
  items: [
    {
      id: 'summary',
      elicit: 'What the feature is and the problem it solves.',
      completion: [{ type: 'judge', criteria: 'The /.interviews/feature-plan.md artifact describes what the feature is and the problem it solves.', description: 'Feature and problem recorded' }],
    },
    {
      id: 'users',
      elicit: 'Who uses the feature and the primary user flow.',
      completion: [{ type: 'judge', criteria: 'The feature-plan artifact describes who uses it and the primary user flow.', description: 'Users and flow recorded' }],
    },
    {
      id: 'scope',
      elicit: "What's in scope for a first version and what is explicitly out of scope.",
      completion: [{ type: 'judge', criteria: 'The feature-plan artifact states both what is in scope for v1 and what is out of scope.', description: 'Scope recorded' }],
    },
    {
      id: 'acceptance',
      elicit: "Acceptance criteria β€” how you'll know the feature is done.",
      completion: [{ type: 'judge', criteria: 'The feature-plan artifact lists concrete acceptance criteria.', description: 'Acceptance criteria recorded' }],
    },
  ],
  handoff: {
    label: 'Implement this plan',
    prompt: 'Implement the feature spec in /.interviews/feature-plan.md.',
    mode: 'code',
  },
};

const PLAN_WEBSITE: InterviewTemplate = {
  id: 'plan-website',
  title: 'Plan a website',
  description: 'Turn an idea into a buildable plan for a site β€” its purpose, audience, pages, and the action it should drive.',
  artifacts: [{ path: '/.interviews/site-plan.md', description: 'The site plan' }],
  items: [
    {
      id: 'purpose',
      elicit: "The site's purpose β€” what it's for, and the single most important thing a visitor should do or take away. (Glance at the project first; if something already exists, plan around it.)",
      completion: [{ type: 'judge', criteria: 'The /.interviews/site-plan.md artifact states the purpose of the site and its primary goal.', description: 'Purpose recorded' }],
    },
    {
      id: 'audience',
      elicit: 'Who the site is for β€” its primary visitors.',
      completion: [{ type: 'judge', criteria: 'The site-plan artifact describes the target audience or visitors.', description: 'Audience recorded' }],
    },
    {
      id: 'pages',
      elicit: 'The pages or main sections the site needs (for example: home, about, services, contact).',
      completion: [{ type: 'judge', criteria: 'The site-plan artifact lists the pages or main sections the site needs.', description: 'Pages recorded' }],
    },
    {
      id: 'action',
      elicit: 'The primary action you want visitors to take β€” the main call-to-action or conversion.',
      completion: [{ type: 'judge', criteria: 'The site-plan artifact states the primary call-to-action or conversion goal.', description: 'Primary action recorded' }],
    },
    {
      id: 'content',
      required: false,
      elicit: 'Any content, copy, or assets you already have β€” check the project with ls β€” and what still needs to be created.',
      completion: [{ type: 'judge', criteria: 'The site-plan artifact notes existing content/assets in the project and what still needs creating (or states there is none yet).', description: 'Content/assets noted' }],
    },
  ],
  handoff: {
    label: 'Build this site',
    prompt: 'Build the website described in /.interviews/site-plan.md.',
    mode: 'code',
  },
};

const PREPARE_PUBLISH: InterviewTemplate = {
  id: 'prepare-publish',
  title: 'Get ready to publish',
  description: 'Check a site over before going live β€” domain, SEO basics, and readiness β€” grounded in what is actually in the project.',
  artifacts: [{ path: '/.interviews/publish-checklist.md', description: 'The publish checklist' }],
  items: [
    {
      id: 'destination',
      elicit: 'Where this will live β€” a custom domain, or the default hosting URL. Note it even if undecided.',
      completion: [{ type: 'judge', criteria: 'The /.interviews/publish-checklist.md artifact records the intended domain or hosting URL (or notes it is undecided).', description: 'Destination recorded' }],
    },
    {
      id: 'identity',
      elicit: 'The site title and a one-line description for search engines and link previews.',
      completion: [{ type: 'judge', criteria: 'The publish-checklist artifact records the site title and a meta description.', description: 'Title and description recorded' }],
    },
    {
      id: 'seo-basics',
      elicit: 'Check the SEO basics: read the HTML and verify there is a <title>, a meta description, and a favicon. Note what is present and what is missing.',
      completion: [{ type: 'judge', criteria: 'The publish-checklist artifact reports the state of the page title, meta description, and favicon based on the actual project files.', description: 'SEO basics checked against the project' }],
    },
    {
      id: 'audience-keywords',
      required: false,
      elicit: 'Who the site targets and any keywords or search terms it should rank for.',
      completion: [{ type: 'judge', criteria: 'The publish-checklist artifact notes the target audience and any keywords (or states there are none).', description: 'Audience/keywords noted' }],
    },
    {
      id: 'readiness',
      elicit: 'Look for obvious gaps before publishing β€” read the project for broken internal links, placeholder content, or empty pages β€” and list anything to fix.',
      completion: [{ type: 'judge', criteria: 'The publish-checklist artifact lists publish-readiness gaps found by inspecting the project (broken links, placeholder content, empty pages), or confirms there are none.', description: 'Readiness gaps listed from the project' }],
    },
  ],
  handoff: {
    label: 'Fix and prepare for publish',
    prompt: 'Apply the publish-readiness fixes listed in /.interviews/publish-checklist.md β€” SEO title and meta description, favicon, and any gaps noted.',
    mode: 'code',
  },
};

export const BUILT_IN_INTERVIEWS: InterviewTemplate[] = [UNDERSTAND_COMPANY, PLAN_WEBSITE, PLAN_FEATURE, PREPARE_PUBLISH];

export function isBuiltInInterviewTemplateId(id: string): boolean {
  return BUILT_IN_INTERVIEWS.some(t => t.id === id);
}

export function listInterviewTemplates(): InterviewTemplate[] {
  return BUILT_IN_INTERVIEWS;
}

export function getInterviewTemplate(id: string): InterviewTemplate | undefined {
  return BUILT_IN_INTERVIEWS.find(t => t.id === id);
}

/** Filters templates by a case-insensitive match on title or description. Empty query returns all. */
export function filterInterviewTemplates(templates: InterviewTemplate[], query: string): InterviewTemplate[] {
  const q = query.trim().toLowerCase();
  if (!q) return templates;
  return templates.filter(
    t => t.title.toLowerCase().includes(q) || t.description.toLowerCase().includes(q)
  );
}