@longtable/cli 0.1.5 → 0.1.6
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/README.md +10 -0
- package/dist/cli.js +9 -4
- package/dist/persona-router.d.ts +9 -0
- package/dist/persona-router.js +69 -4
- package/dist/project-session.js +14 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -72,6 +72,16 @@ codex
|
|
|
72
72
|
|
|
73
73
|
프로젝트 디렉토리 안에서는 보통 그냥 `codex`를 열고 자연어로 연구를 시작하면 됩니다.
|
|
74
74
|
|
|
75
|
+
Codex 안에서 더 명시적으로 부르고 싶다면, 아래처럼 짧은 문법도 사용할 수 있습니다.
|
|
76
|
+
|
|
77
|
+
```text
|
|
78
|
+
lt explore: 연구 질문을 어디서부터 좁혀야 할지 모르겠어.
|
|
79
|
+
lt review: 이 주장 어디가 약한지 봐줘.
|
|
80
|
+
lt panel: 이 방향에 대한 의견 충돌도 같이 보여줘.
|
|
81
|
+
lt editor: BJET 편집자 관점에서 봐줘.
|
|
82
|
+
lt methods: 방법론적으로 어디가 취약한지 말해줘.
|
|
83
|
+
```
|
|
84
|
+
|
|
75
85
|
CLI를 계속 쓰고 싶다면 아래 명령은 보조 경로입니다.
|
|
76
86
|
|
|
77
87
|
## Advanced commands
|
package/dist/cli.js
CHANGED
|
@@ -7,7 +7,7 @@ import { resolve } from "node:path";
|
|
|
7
7
|
import { buildProviderChoices, buildQuickSetupFlow, createPersistedSetupOutput, installRuntimeConfigFromStoredSetup, loadSetupOutput, renderInstallSummary, renderSetupSummary, resolveDefaultRuntimeConfigPath, resolveDefaultSetupPath, saveSetupAndRuntimeConfig, serializeSetupOutput } from "@diverga/setup";
|
|
8
8
|
import { buildCodexThinWrappedPrompt, runCodexThinWrapper } from "@diverga/provider-codex";
|
|
9
9
|
import { installCodexPromptAliases, listInstalledCodexPromptAliases, removeCodexPromptAliases, resolveCodexPromptsDir } from "./prompt-aliases.js";
|
|
10
|
-
import { buildPersonaGuidance } from "./persona-router.js";
|
|
10
|
+
import { buildPersonaGuidance, parseInvocationDirective } from "./persona-router.js";
|
|
11
11
|
import { PERSONA_DEFINITIONS } from "./personas.js";
|
|
12
12
|
import { createOrUpdateProjectWorkspace, loadProjectContextFromDirectory, renderProjectWorkspaceSummary } from "./project-session.js";
|
|
13
13
|
const VALID_MODES = new Set([
|
|
@@ -803,7 +803,9 @@ async function runAsk(args) {
|
|
|
803
803
|
if (!prompt) {
|
|
804
804
|
throw new Error("A prompt is required.");
|
|
805
805
|
}
|
|
806
|
-
const
|
|
806
|
+
const directive = parseInvocationDirective(prompt);
|
|
807
|
+
const effectivePrompt = directive.cleanedPrompt;
|
|
808
|
+
const inferred = directive.mode ?? inferModeFromPrompt(effectivePrompt);
|
|
807
809
|
if (inferred === "status") {
|
|
808
810
|
await runCodexSubcommand("status", args);
|
|
809
811
|
return;
|
|
@@ -811,9 +813,12 @@ async function runAsk(args) {
|
|
|
811
813
|
const mode = inferred === "panel" ? "review" : inferred;
|
|
812
814
|
const delegatedArgs = {
|
|
813
815
|
...args,
|
|
814
|
-
prompt
|
|
816
|
+
prompt: effectivePrompt
|
|
815
817
|
};
|
|
816
|
-
if (
|
|
818
|
+
if (directive.roles.length > 0 && typeof delegatedArgs.role !== "string") {
|
|
819
|
+
delegatedArgs.role = directive.roles.join(",");
|
|
820
|
+
}
|
|
821
|
+
if ((inferred === "panel" || directive.panel) && delegatedArgs.panel !== true) {
|
|
817
822
|
delegatedArgs.panel = true;
|
|
818
823
|
delegatedArgs["show-conflicts"] = true;
|
|
819
824
|
}
|
package/dist/persona-router.d.ts
CHANGED
|
@@ -8,8 +8,17 @@ export interface PersonaRoutingResult {
|
|
|
8
8
|
consultedRoles: CanonicalPersona[];
|
|
9
9
|
ambiguousSignal: string | null;
|
|
10
10
|
}
|
|
11
|
+
export interface LongTableInvocationDirective {
|
|
12
|
+
explicit: boolean;
|
|
13
|
+
cleanedPrompt: string;
|
|
14
|
+
mode?: InteractionMode | "panel" | "status";
|
|
15
|
+
roles: CanonicalPersona[];
|
|
16
|
+
panel: boolean;
|
|
17
|
+
showConflicts: boolean;
|
|
18
|
+
}
|
|
11
19
|
export declare function detectOutputLanguage(input: string): OutputLanguage;
|
|
12
20
|
export declare function parseRoleFlag(value?: string): CanonicalPersona[];
|
|
21
|
+
export declare function parseInvocationDirective(prompt: string): LongTableInvocationDirective;
|
|
13
22
|
export declare function routePersonas(prompt: string, explicitRoleFlag?: string): PersonaRoutingResult;
|
|
14
23
|
export declare function renderDisclosure(roles: CanonicalPersona[], language: OutputLanguage): string | null;
|
|
15
24
|
export declare function buildPersonaGuidance(options: {
|
package/dist/persona-router.js
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
import { getPersonaDefinition, parsePersonaKey, PERSONA_DEFINITIONS } from "./personas.js";
|
|
2
2
|
const AUTO_CALL_LIMIT = 3;
|
|
3
|
+
const INVOCATION_PREFIX = /^(?:lt|longtable|long table|롱테이블)\s+/i;
|
|
4
|
+
const DIRECTIVE_MAP = [
|
|
5
|
+
{ key: "explore", mode: "explore" },
|
|
6
|
+
{ key: "review", mode: "review" },
|
|
7
|
+
{ key: "critique", mode: "critique" },
|
|
8
|
+
{ key: "draft", mode: "draft" },
|
|
9
|
+
{ key: "commit", mode: "commit" },
|
|
10
|
+
{ key: "panel", mode: "panel", panel: true, showConflicts: true },
|
|
11
|
+
{ key: "status", mode: "status" },
|
|
12
|
+
{ key: "editor", mode: "review", roles: ["editor"] },
|
|
13
|
+
{ key: "reviewer", mode: "review", roles: ["reviewer"] },
|
|
14
|
+
{ key: "methods", mode: "review", roles: ["methods_critic"] },
|
|
15
|
+
{ key: "method", mode: "review", roles: ["methods_critic"] },
|
|
16
|
+
{ key: "theory", mode: "review", roles: ["theory_critic"] },
|
|
17
|
+
{ key: "measurement", mode: "review", roles: ["measurement_auditor"] },
|
|
18
|
+
{ key: "ethics", mode: "review", roles: ["ethics_reviewer"] },
|
|
19
|
+
{ key: "voice", mode: "review", roles: ["voice_keeper"] },
|
|
20
|
+
{ key: "venue", mode: "review", roles: ["venue_strategist"] }
|
|
21
|
+
];
|
|
3
22
|
function unique(items) {
|
|
4
23
|
return [...new Set(items)];
|
|
5
24
|
}
|
|
@@ -15,6 +34,49 @@ export function parseRoleFlag(value) {
|
|
|
15
34
|
.map((part) => parsePersonaKey(part))
|
|
16
35
|
.filter((part) => part !== null));
|
|
17
36
|
}
|
|
37
|
+
export function parseInvocationDirective(prompt) {
|
|
38
|
+
const trimmed = prompt.trim();
|
|
39
|
+
if (!INVOCATION_PREFIX.test(trimmed)) {
|
|
40
|
+
return {
|
|
41
|
+
explicit: false,
|
|
42
|
+
cleanedPrompt: prompt,
|
|
43
|
+
roles: [],
|
|
44
|
+
panel: false,
|
|
45
|
+
showConflicts: false
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
const withoutPrefix = trimmed.replace(INVOCATION_PREFIX, "");
|
|
49
|
+
const colonIndex = withoutPrefix.indexOf(":");
|
|
50
|
+
if (colonIndex === -1) {
|
|
51
|
+
return {
|
|
52
|
+
explicit: false,
|
|
53
|
+
cleanedPrompt: prompt,
|
|
54
|
+
roles: [],
|
|
55
|
+
panel: false,
|
|
56
|
+
showConflicts: false
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
const directiveKey = withoutPrefix.slice(0, colonIndex).trim().toLowerCase();
|
|
60
|
+
const body = withoutPrefix.slice(colonIndex + 1).trim();
|
|
61
|
+
const directive = DIRECTIVE_MAP.find((entry) => entry.key === directiveKey);
|
|
62
|
+
if (!directive) {
|
|
63
|
+
return {
|
|
64
|
+
explicit: false,
|
|
65
|
+
cleanedPrompt: body || prompt,
|
|
66
|
+
roles: [],
|
|
67
|
+
panel: false,
|
|
68
|
+
showConflicts: false
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
explicit: true,
|
|
73
|
+
cleanedPrompt: body || prompt,
|
|
74
|
+
mode: directive.mode,
|
|
75
|
+
roles: directive.roles ?? [],
|
|
76
|
+
panel: directive.panel === true,
|
|
77
|
+
showConflicts: directive.showConflicts === true
|
|
78
|
+
};
|
|
79
|
+
}
|
|
18
80
|
export function routePersonas(prompt, explicitRoleFlag) {
|
|
19
81
|
const normalizedPrompt = prompt.toLowerCase();
|
|
20
82
|
const explicitRoles = parseRoleFlag(explicitRoleFlag);
|
|
@@ -60,7 +122,10 @@ export function renderDisclosure(roles, language) {
|
|
|
60
122
|
: `Long Table consulted: ${labels.join(", ")}`;
|
|
61
123
|
}
|
|
62
124
|
export function buildPersonaGuidance(options) {
|
|
63
|
-
const
|
|
125
|
+
const directive = parseInvocationDirective(options.prompt);
|
|
126
|
+
const effectivePrompt = directive.cleanedPrompt;
|
|
127
|
+
const mergedRoleFlag = [options.roleFlag, directive.roles.join(",")].filter(Boolean).join(",");
|
|
128
|
+
const routing = routePersonas(effectivePrompt, mergedRoleFlag || undefined);
|
|
64
129
|
const disclosure = renderDisclosure(routing.consultedRoles, routing.outputLanguage);
|
|
65
130
|
const lines = [];
|
|
66
131
|
lines.push(routing.outputLanguage === "ko"
|
|
@@ -74,12 +139,12 @@ export function buildPersonaGuidance(options) {
|
|
|
74
139
|
? "Ambiguity note: 편집자 관점인지 리뷰어 관점인지 애매합니다. 먼저 둘 중 무엇을 우선할지 짧게 확인하세요."
|
|
75
140
|
: "Ambiguity note: it is unclear whether the user wants an editor view or reviewer view. Ask briefly before closing.");
|
|
76
141
|
}
|
|
77
|
-
if (options.panel) {
|
|
142
|
+
if (options.panel || directive.panel) {
|
|
78
143
|
lines.push(routing.outputLanguage === "ko"
|
|
79
144
|
? "Return format: 1) Long Table synthesis 2) panel opinions by role 3) decision prompt to the researcher."
|
|
80
145
|
: "Return format: 1) Long Table synthesis 2) panel opinions by role 3) decision prompt to the researcher.");
|
|
81
146
|
}
|
|
82
|
-
if (options.showConflicts) {
|
|
147
|
+
if (options.showConflicts || directive.showConflicts) {
|
|
83
148
|
lines.push(routing.outputLanguage === "ko"
|
|
84
149
|
? "If roles disagree, show the conflict explicitly instead of forcing one answer."
|
|
85
150
|
: "If roles disagree, show the conflict explicitly instead of forcing one answer.");
|
|
@@ -92,7 +157,7 @@ export function buildPersonaGuidance(options) {
|
|
|
92
157
|
lines.push(routing.outputLanguage === "ko"
|
|
93
158
|
? "Do not show internal file-search logs, tool traces, or process commentary in the researcher-facing answer."
|
|
94
159
|
: "Do not show internal file-search logs, tool traces, or process commentary in the researcher-facing answer.");
|
|
95
|
-
lines.push(
|
|
160
|
+
lines.push(effectivePrompt.trim());
|
|
96
161
|
return {
|
|
97
162
|
guidedPrompt: lines.join("\n\n"),
|
|
98
163
|
routing
|
package/dist/project-session.js
CHANGED
|
@@ -60,6 +60,15 @@ function buildStartHereGuide(project, session) {
|
|
|
60
60
|
? `"I want to work on ${session.currentGoal}. My current blocker is: ${session.currentBlocker}."`
|
|
61
61
|
: `"I want to work on ${session.currentGoal}."`,
|
|
62
62
|
"",
|
|
63
|
+
"## Explicit Long Table invocation inside Codex",
|
|
64
|
+
"- `lt explore: <question>`",
|
|
65
|
+
"- `lt review: <claim or plan>`",
|
|
66
|
+
"- `lt panel: <claim or plan>`",
|
|
67
|
+
"- `lt editor: <draft or positioning question>`",
|
|
68
|
+
"- `lt reviewer: <claim or section>`",
|
|
69
|
+
"- `lt methods: <design, measure, or analysis plan>`",
|
|
70
|
+
"- `lt commit: <decision that needs commitment>`",
|
|
71
|
+
"",
|
|
63
72
|
"## What Long Table already knows in this directory",
|
|
64
73
|
`- Current goal: ${session.currentGoal}`,
|
|
65
74
|
...(session.currentBlocker ? [`- Current blocker: ${session.currentBlocker}`] : []),
|
|
@@ -88,6 +97,10 @@ function buildProjectAgentsMd(project, session) {
|
|
|
88
97
|
"",
|
|
89
98
|
"## Research-facing behavior",
|
|
90
99
|
"- Treat researcher interaction as the primary task.",
|
|
100
|
+
"- If the user message starts with `lt `, `longtable `, `long table `, or `롱테이블 ` followed by a directive and `:`, treat it as an explicit Long Table invocation.",
|
|
101
|
+
"- Supported explicit directives are: explore, review, critique, draft, commit, panel, status, editor, reviewer, methods, theory, measurement, ethics, voice, venue.",
|
|
102
|
+
"- For explicit Long Table invocations, do not begin by scanning the workspace. Use the current session files first and answer as Long Table immediately.",
|
|
103
|
+
"- For general research requests in this workspace, prefer Long Table behavior before generic coding behavior.",
|
|
91
104
|
"- Begin exploratory work with clarifying or tension questions before recommending a direction.",
|
|
92
105
|
"- If you foreground role perspectives, disclose them with `Long Table consulted: ...`.",
|
|
93
106
|
"- Keep one accountable synthesis, but do not hide meaningful disagreement.",
|
|
@@ -100,6 +113,7 @@ function buildProjectAgentsMd(project, session) {
|
|
|
100
113
|
"- Read `.longtable/current-session.json` before giving substantial guidance.",
|
|
101
114
|
"- Use `.longtable/project.json` as the project-level context.",
|
|
102
115
|
"- Prefer the current goal and blocker over generic assumptions.",
|
|
116
|
+
"- Do not recursively search unrelated files unless the researcher explicitly asks for file analysis or code changes.",
|
|
103
117
|
"",
|
|
104
118
|
"## Scope",
|
|
105
119
|
"- These instructions apply to this directory and its children."
|