@longtable/provider-codex 0.1.38 → 0.1.40

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/skills.d.ts CHANGED
@@ -9,8 +9,9 @@ export interface InstalledCodexSkill {
9
9
  path: string;
10
10
  description: string;
11
11
  }
12
+ export type LongTableSkillSurface = "compact" | "full";
12
13
  export declare function resolveCodexSkillsDir(customDir?: string): string;
13
- export declare function buildCodexSkillSpecs(roles: RoleDefinition[]): CodexSkillSpec[];
14
- export declare function installCodexSkills(roles: RoleDefinition[], customDir?: string): Promise<InstalledCodexSkill[]>;
14
+ export declare function buildCodexSkillSpecs(roles: RoleDefinition[], surface?: LongTableSkillSurface): CodexSkillSpec[];
15
+ export declare function installCodexSkills(roles: RoleDefinition[], customDir?: string, surface?: LongTableSkillSurface): Promise<InstalledCodexSkill[]>;
15
16
  export declare function removeCodexSkills(roles: RoleDefinition[], customDir?: string): Promise<string[]>;
16
- export declare function listInstalledCodexSkills(roles: RoleDefinition[], customDir?: string): Promise<InstalledCodexSkill[]>;
17
+ export declare function listInstalledCodexSkills(roles: RoleDefinition[], customDir?: string, surface?: LongTableSkillSurface): Promise<InstalledCodexSkill[]>;
package/dist/skills.js CHANGED
@@ -2,10 +2,20 @@ import { existsSync } from "node:fs";
2
2
  import { mkdir, readdir, rm, writeFile } from "node:fs/promises";
3
3
  import { homedir } from "node:os";
4
4
  import { join, resolve } from "node:path";
5
+ const COMPACT_ROLE_SKILL_NAMES = {
6
+ methods_critic: "longtable-methods",
7
+ measurement_auditor: "longtable-measure",
8
+ theory_critic: "longtable-theory",
9
+ reviewer: "longtable-reviewer",
10
+ voice_keeper: "longtable-voice"
11
+ };
5
12
  export function resolveCodexSkillsDir(customDir) {
6
13
  return customDir ? resolve(customDir) : join(homedir(), ".codex", "skills");
7
14
  }
8
- function skillNameForRole(role) {
15
+ function skillNameForRole(role, surface) {
16
+ if (surface === "compact" && COMPACT_ROLE_SKILL_NAMES[role.key]) {
17
+ return COMPACT_ROLE_SKILL_NAMES[role.key];
18
+ }
9
19
  return `longtable-${role.key.replaceAll("_", "-")}`;
10
20
  }
11
21
  function yamlString(value) {
@@ -23,8 +33,8 @@ function renderSkillFile(spec) {
23
33
  ...spec.body
24
34
  ].join("\n");
25
35
  }
26
- function baseSkillSpecs() {
27
- return [
36
+ function baseSkillSpecs(surface = "compact") {
37
+ const base = [
28
38
  {
29
39
  name: "longtable",
30
40
  description: "Use for LongTable research conversations, lt explore/review/panel requests, researcher checkpoints, and role routing.",
@@ -44,6 +54,7 @@ function baseSkillSpecs() {
44
54
  "- `use the LongTable methods critic on this design`",
45
55
  "- `$longtable: deploy a research team to review this measurement plan, show the main disagreements, and ask me what decision should be recorded before you revise it.`",
46
56
  "- `$longtable: use editor, reviewer, methods, measurement, and voice perspectives to evaluate this manuscript section. Do not collapse disagreement too early.`",
57
+ "- `$longtable-methods`, `$longtable-measure`, `$longtable-theory`, `$longtable-reviewer`, or `$longtable-voice` when the researcher explicitly wants that shortcut.",
47
58
  "- `$longtable-interview` to create or continue the first research-start interview.",
48
59
  "",
49
60
  "## Routing Rules",
@@ -53,6 +64,7 @@ function baseSkillSpecs() {
53
64
  "- `lt panel` creates a visible multi-role review with synthesis, role opinions, conflict summary, and a decision prompt.",
54
65
  "- `$longtable-interview` runs the provider-native LongTable start interview. It replaces the old CLI start questionnaire as the primary research-start surface.",
55
66
  "- Natural references to methods, measurement, theory, reviewer, editor, ethics, venue, or voice should foreground the matching LongTable role.",
67
+ "- The compact visible shortcut set is methods, measure, theory, reviewer, and voice. Other roles remain available through this router when the request calls for them.",
56
68
  "- When research responsibility is about to shift, surface a Researcher Checkpoint before closure.",
57
69
  "- When changing LongTable product language, README positioning, or checkpoint policy, surface a Meta-Decision Checkpoint first.",
58
70
  "",
@@ -160,7 +172,9 @@ function baseSkillSpecs() {
160
172
  "",
161
173
  "If MCP tools are unavailable, continue the natural-language interview in Codex, but state that durable LongTable state could not be written. Do not pretend a checkpoint or First Research Shape was recorded."
162
174
  ]
163
- },
175
+ }
176
+ ];
177
+ const fullOnly = [
164
178
  {
165
179
  name: "longtable-panel",
166
180
  description: "Use when LongTable should run a panel or team-style review with visible role disagreement.",
@@ -227,6 +241,7 @@ function baseSkillSpecs() {
227
241
  ]
228
242
  }
229
243
  ];
244
+ return surface === "full" ? [...base, ...fullOnly] : base;
230
245
  }
231
246
  function mustAskQuestionsForRole(role) {
232
247
  const common = [
@@ -261,10 +276,10 @@ function mustAskQuestionsForRole(role) {
261
276
  };
262
277
  return [...(byRole[role.key] ?? []), ...common];
263
278
  }
264
- function roleSkillSpec(role) {
279
+ function roleSkillSpec(role, surface = "compact") {
265
280
  const label = role.label;
266
281
  return {
267
- name: skillNameForRole(role),
282
+ name: skillNameForRole(role, surface),
268
283
  description: `Use the LongTable ${label} role: ${role.shortDescription}`,
269
284
  body: [
270
285
  "## Purpose",
@@ -311,14 +326,32 @@ function roleSkillSpec(role) {
311
326
  ]
312
327
  };
313
328
  }
314
- export function buildCodexSkillSpecs(roles) {
315
- return [...baseSkillSpecs(), ...roles.map(roleSkillSpec)];
329
+ function compactRoles(roles) {
330
+ return roles.filter((role) => Object.hasOwn(COMPACT_ROLE_SKILL_NAMES, role.key));
316
331
  }
317
- export async function installCodexSkills(roles, customDir) {
332
+ function allCodexSkillSpecs(roles) {
333
+ const byName = new Map();
334
+ for (const spec of [...buildCodexSkillSpecs(roles, "compact"), ...buildCodexSkillSpecs(roles, "full")]) {
335
+ byName.set(spec.name, spec);
336
+ }
337
+ return [...byName.values()];
338
+ }
339
+ export function buildCodexSkillSpecs(roles, surface = "compact") {
340
+ const roleSpecs = (surface === "compact" ? compactRoles(roles) : roles).map((role) => roleSkillSpec(role, surface));
341
+ return [...baseSkillSpecs(surface), ...roleSpecs];
342
+ }
343
+ export async function installCodexSkills(roles, customDir, surface = "compact") {
318
344
  const skillsDir = resolveCodexSkillsDir(customDir);
319
345
  await mkdir(skillsDir, { recursive: true });
346
+ const specs = buildCodexSkillSpecs(roles, surface);
347
+ const selectedNames = new Set(specs.map((spec) => spec.name));
348
+ for (const spec of allCodexSkillSpecs(roles)) {
349
+ if (!selectedNames.has(spec.name)) {
350
+ await rm(join(skillsDir, spec.name), { recursive: true, force: true });
351
+ }
352
+ }
320
353
  const installed = [];
321
- for (const spec of buildCodexSkillSpecs(roles)) {
354
+ for (const spec of specs) {
322
355
  const skillDir = join(skillsDir, spec.name);
323
356
  await mkdir(skillDir, { recursive: true });
324
357
  const path = join(skillDir, "SKILL.md");
@@ -334,7 +367,7 @@ export async function installCodexSkills(roles, customDir) {
334
367
  export async function removeCodexSkills(roles, customDir) {
335
368
  const skillsDir = resolveCodexSkillsDir(customDir);
336
369
  const removed = [];
337
- for (const spec of buildCodexSkillSpecs(roles)) {
370
+ for (const spec of allCodexSkillSpecs(roles)) {
338
371
  const skillDir = join(skillsDir, spec.name);
339
372
  if (existsSync(skillDir)) {
340
373
  await rm(skillDir, { recursive: true, force: true });
@@ -343,13 +376,13 @@ export async function removeCodexSkills(roles, customDir) {
343
376
  }
344
377
  return removed;
345
378
  }
346
- export async function listInstalledCodexSkills(roles, customDir) {
379
+ export async function listInstalledCodexSkills(roles, customDir, surface = "compact") {
347
380
  const skillsDir = resolveCodexSkillsDir(customDir);
348
381
  if (!existsSync(skillsDir)) {
349
382
  return [];
350
383
  }
351
384
  const entries = new Set(await readdir(skillsDir));
352
- return buildCodexSkillSpecs(roles)
385
+ return buildCodexSkillSpecs(roles, surface)
353
386
  .filter((spec) => entries.has(spec.name) && existsSync(join(skillsDir, spec.name, "SKILL.md")))
354
387
  .map((spec) => ({
355
388
  name: spec.name,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@longtable/provider-codex",
3
- "version": "0.1.38",
3
+ "version": "0.1.40",
4
4
  "private": false,
5
5
  "description": "Codex adapter surface for LongTable",
6
6
  "type": "module",
@@ -15,9 +15,9 @@
15
15
  "typecheck": "tsc -p tsconfig.json --noEmit"
16
16
  },
17
17
  "dependencies": {
18
- "@longtable/checkpoints": "0.1.38",
19
- "@longtable/core": "0.1.38",
20
- "@longtable/setup": "0.1.38"
18
+ "@longtable/checkpoints": "0.1.40",
19
+ "@longtable/core": "0.1.40",
20
+ "@longtable/setup": "0.1.40"
21
21
  },
22
22
  "devDependencies": {
23
23
  "@types/node": "^22.10.1",