@popoverai/dotrequirements 0.25.0 → 0.26.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.js +8 -1
- package/dist/codebase-to-spec/present.d.ts +9 -0
- package/dist/codebase-to-spec/present.js +23 -2
- package/dist/codebase-to-spec/skill-install.d.ts +16 -6
- package/dist/codebase-to-spec/skill-install.js +109 -47
- package/dist/codebase-to-spec/version-check.d.ts +31 -0
- package/dist/codebase-to-spec/version-check.js +56 -0
- package/dist/commands/ai-setup.d.ts +12 -1
- package/dist/commands/ai-setup.js +65 -33
- package/dist/commands/codebase-to-spec/pack.d.ts +4 -0
- package/dist/commands/codebase-to-spec/pack.js +17 -0
- package/dist/commands/init.js +6 -1
- package/dist/commands/link-resolution.d.ts +79 -0
- package/dist/commands/link-resolution.js +141 -0
- package/dist/commands/link.d.ts +14 -4
- package/dist/commands/link.js +369 -16
- package/dist/commands/pull.js +19 -2
- package/dist/commands/push.js +36 -2
- package/dist/convex.d.ts +5 -3
- package/dist/convex.js +5 -3
- package/dist/harness/cache.d.ts +0 -14
- package/dist/harness/cache.js +1 -41
- package/dist/harness/finalize.js +2 -2
- package/dist/harness/prepare.js +1 -3
- package/dist/harness/requirementsLoader.d.ts +3 -3
- package/dist/harness/requirementsLoader.js +13 -8
- package/dist/mcp/handlers/authoring.d.ts +5 -5
- package/dist/mcp/handlers/authoring.js +9 -9
- package/dist/mcp/handlers/push.d.ts +2 -2
- package/dist/mcp/handlers/push.js +36 -3
- package/dist/mcp/handlers/review.d.ts +4 -4
- package/dist/mcp/handlers/review.js +4 -4
- package/dist/mcp/handlers/search.d.ts +1 -1
- package/dist/mcp/handlers/search.js +1 -1
- package/dist/mcp/index.js +29 -0
- package/dist/push/core.d.ts +18 -0
- package/dist/push/core.js +70 -3
- package/dist/push/index.d.ts +1 -1
- package/dist/push/index.js +1 -1
- package/dist/schema/parser-core.js +5 -1
- package/dist/schema/parser.js +5 -1
- package/dist/schema/run-marker.d.ts +38 -0
- package/dist/schema/run-marker.js +138 -0
- package/dist/schema/schemas.d.ts +12 -0
- package/dist/schema/schemas.js +1 -0
- package/dist/templates/agents/cts-worker.md +1 -1
- package/dist/templates/skills/codebase-to-spec/SKILL.md +33 -11
- package/dist/templates/workflows/specify-codebase.js +4 -2
- package/dist/utils/own-package.d.ts +10 -0
- package/dist/utils/own-package.js +13 -0
- package/dist/utils/project-selector.d.ts +5 -0
- package/dist/utils/project-selector.js +4 -0
- package/package.json +2 -2
|
@@ -7,8 +7,10 @@
|
|
|
7
7
|
* - CTS-CLI-3: Pipeline refuses to spec a codebase that exceeds the working context budget
|
|
8
8
|
* - CTS-PACK-1: Pack stage produces compressed and uncompressed views of the codebase
|
|
9
9
|
* - CTS-PACK-2: Engineer can extend the ignore list per project
|
|
10
|
+
* - CTS-PACK-4: Pack surfaces when a newer CLI version is available
|
|
10
11
|
* - CTS-OBSERVE-1: CLI emits structured progress as the pipeline runs
|
|
11
12
|
*/
|
|
13
|
+
import { checkForNewerVersion } from "../../codebase-to-spec/version-check.js";
|
|
12
14
|
export interface PackOptions {
|
|
13
15
|
scope?: string;
|
|
14
16
|
/**
|
|
@@ -28,6 +30,8 @@ export interface PackOptions {
|
|
|
28
30
|
progress?: import("../../codebase-to-spec/progress.js").ProgressEmitter;
|
|
29
31
|
/** Override the project root, mainly for tests. */
|
|
30
32
|
projectRoot?: string;
|
|
33
|
+
/** Override the registry version check, mainly for tests. */
|
|
34
|
+
checkVersion?: typeof checkForNewerVersion;
|
|
31
35
|
}
|
|
32
36
|
export declare function packCommand(rawOptions?: PackOptions): Promise<void>;
|
|
33
37
|
//# sourceMappingURL=pack.d.ts.map
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* - CTS-CLI-3: Pipeline refuses to spec a codebase that exceeds the working context budget
|
|
8
8
|
* - CTS-PACK-1: Pack stage produces compressed and uncompressed views of the codebase
|
|
9
9
|
* - CTS-PACK-2: Engineer can extend the ignore list per project
|
|
10
|
+
* - CTS-PACK-4: Pack surfaces when a newer CLI version is available
|
|
10
11
|
* - CTS-OBSERVE-1: CLI emits structured progress as the pipeline runs
|
|
11
12
|
*/
|
|
12
13
|
import { resolve } from "node:path";
|
|
@@ -15,11 +16,16 @@ import { clearCache, ensureCacheDir } from "../../codebase-to-spec/cache.js";
|
|
|
15
16
|
import { ExitCode } from "../../codebase-to-spec/exit-codes.js";
|
|
16
17
|
import { runPack } from "../../codebase-to-spec/pack.js";
|
|
17
18
|
import { StdoutProgress } from "../../codebase-to-spec/progress.js";
|
|
19
|
+
import { checkForNewerVersion } from "../../codebase-to-spec/version-check.js";
|
|
18
20
|
import { findProjectRoot } from "../../utils/project-settings.js";
|
|
19
21
|
export async function packCommand(rawOptions = {}) {
|
|
20
22
|
const progress = rawOptions.progress ?? new StdoutProgress();
|
|
21
23
|
const projectRoot = rawOptions.projectRoot ?? findProjectRoot(process.cwd()) ?? process.cwd();
|
|
22
24
|
const budgetTokens = rawOptions.budgetTokens ?? DEFAULT_BUDGET_TOKENS;
|
|
25
|
+
// Fail-soft staleness check (CTS-PACK-4), started now so the registry
|
|
26
|
+
// round-trip overlaps the pack work and adds no wall-clock on the happy
|
|
27
|
+
// path. Resolves to undefined on any failure or timeout.
|
|
28
|
+
const versionCheck = (rawOptions.checkVersion ?? checkForNewerVersion)();
|
|
23
29
|
if (rawOptions.fresh) {
|
|
24
30
|
progress.emit({
|
|
25
31
|
stage: "pack",
|
|
@@ -54,6 +60,17 @@ export async function packCommand(rawOptions = {}) {
|
|
|
54
60
|
message: `Packed ${packResult.fileCount} files → ${paths.overview} (compressed), ${paths.source} (uncompressed)`,
|
|
55
61
|
data: { fileCount: packResult.fileCount },
|
|
56
62
|
});
|
|
63
|
+
// Surface a stale install (CTS-PACK-4). Informational only: outputs and
|
|
64
|
+
// exit code are unaffected, and a failed check emits nothing.
|
|
65
|
+
const versionInfo = await versionCheck.catch(() => undefined);
|
|
66
|
+
if (versionInfo?.stale) {
|
|
67
|
+
progress.emit({
|
|
68
|
+
stage: "pack",
|
|
69
|
+
step: "stale-version",
|
|
70
|
+
message: `A newer dotrequirements CLI is available: ${versionInfo.latest} (running ${versionInfo.current}). Re-run skill-install to refresh.`,
|
|
71
|
+
data: { current: versionInfo.current, latest: versionInfo.latest },
|
|
72
|
+
});
|
|
73
|
+
}
|
|
57
74
|
// Budget check (CTS-CLI-3)
|
|
58
75
|
const measured = countTokensInFileExact(paths.overview);
|
|
59
76
|
const budget = checkBudget(measured, budgetTokens);
|
package/dist/commands/init.js
CHANGED
|
@@ -353,8 +353,13 @@ async function inviteFlow(cwd, token) {
|
|
|
353
353
|
console.log(`✓ Joined team "${inviteInfo.teamName}"`);
|
|
354
354
|
}
|
|
355
355
|
catch (err) {
|
|
356
|
+
// Production redacts ConvexError messages to "Server Error" but keeps
|
|
357
|
+
// error.data — check both, or this graceful path only works in dev
|
|
358
|
+
const data = err.data;
|
|
359
|
+
const dataMessage = typeof data?.message === "string" ? data.message : "";
|
|
356
360
|
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
357
|
-
if (
|
|
361
|
+
if (dataMessage.includes("already a member") ||
|
|
362
|
+
errorMessage.includes("already a member")) {
|
|
358
363
|
console.log(`Already a member of "${inviteInfo.teamName}"`);
|
|
359
364
|
}
|
|
360
365
|
else {
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure decision logic for `dotrequirements link`'s non-interactive mode
|
|
3
|
+
* (LINK-10/11/12). No I/O: the link command gathers state (teams, projects)
|
|
4
|
+
* and these functions decide what to do — use a project, create one, rename,
|
|
5
|
+
* or stop with a decision-needed result that carries everything an AI
|
|
6
|
+
* assistant needs to ask the user and retry with a deviation flag.
|
|
7
|
+
*/
|
|
8
|
+
export interface TeamOption {
|
|
9
|
+
teamId: string;
|
|
10
|
+
name: string;
|
|
11
|
+
tier: string;
|
|
12
|
+
tierName: string;
|
|
13
|
+
projectCount: number;
|
|
14
|
+
projectLimit: number;
|
|
15
|
+
}
|
|
16
|
+
export interface ProjectOption {
|
|
17
|
+
projectId: string;
|
|
18
|
+
projectName: string;
|
|
19
|
+
projectSlug: string | null;
|
|
20
|
+
isDefault: boolean;
|
|
21
|
+
hasUserContent: boolean;
|
|
22
|
+
}
|
|
23
|
+
export interface LinkFlags {
|
|
24
|
+
yes?: boolean;
|
|
25
|
+
team?: string;
|
|
26
|
+
connect?: string;
|
|
27
|
+
create?: boolean;
|
|
28
|
+
name?: string;
|
|
29
|
+
json?: boolean;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* LINK-12.3: any deviation flag implies non-interactive mode.
|
|
33
|
+
*/
|
|
34
|
+
export declare function isNonInteractive(flags: LinkFlags): boolean;
|
|
35
|
+
export declare function hasCapacity(team: TeamOption): boolean;
|
|
36
|
+
/** A choice the user must make, with everything needed to ask and retry. */
|
|
37
|
+
export interface DecisionNeeded {
|
|
38
|
+
kind: "decision";
|
|
39
|
+
decision: "team" | "project" | "capacity";
|
|
40
|
+
message: string;
|
|
41
|
+
options: Array<{
|
|
42
|
+
label: string;
|
|
43
|
+
/** Exact flag to pass on retry (LINK-11.4), when retryable via link */
|
|
44
|
+
retryFlag?: string;
|
|
45
|
+
}>;
|
|
46
|
+
}
|
|
47
|
+
export interface NoMatch {
|
|
48
|
+
kind: "no-match";
|
|
49
|
+
flag: "team" | "connect";
|
|
50
|
+
provided: string;
|
|
51
|
+
alternatives: string[];
|
|
52
|
+
}
|
|
53
|
+
export type TeamResolution = {
|
|
54
|
+
kind: "use";
|
|
55
|
+
team: TeamOption;
|
|
56
|
+
} | DecisionNeeded | NoMatch;
|
|
57
|
+
/**
|
|
58
|
+
* LINK-10.1, LINK-11.0, LINK-12.0, LINK-12.4
|
|
59
|
+
*/
|
|
60
|
+
export declare function resolveTeam(teams: TeamOption[], flags: LinkFlags): TeamResolution;
|
|
61
|
+
export type ProjectResolution = {
|
|
62
|
+
kind: "connect";
|
|
63
|
+
project: ProjectOption;
|
|
64
|
+
rename: boolean;
|
|
65
|
+
} | {
|
|
66
|
+
kind: "create";
|
|
67
|
+
} | DecisionNeeded | NoMatch;
|
|
68
|
+
/**
|
|
69
|
+
* LINK-10.2/10.3 (default-project rule), LINK-11.1/11.2 (decision menus),
|
|
70
|
+
* LINK-12.1/12.2/12.4 (deviation flags).
|
|
71
|
+
*/
|
|
72
|
+
export declare function resolveProject(projects: ProjectOption[], team: TeamOption, flags: LinkFlags): ProjectResolution;
|
|
73
|
+
/**
|
|
74
|
+
* Prompt-free project naming for non-interactive mode (LINK-9.0): explicit
|
|
75
|
+
* flag, then package metadata, then directory name, then a fixed fallback —
|
|
76
|
+
* never a prompt.
|
|
77
|
+
*/
|
|
78
|
+
export declare function resolveProjectName(flags: LinkFlags, packageName: string | undefined, directoryName: string | undefined): string;
|
|
79
|
+
//# sourceMappingURL=link-resolution.d.ts.map
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure decision logic for `dotrequirements link`'s non-interactive mode
|
|
3
|
+
* (LINK-10/11/12). No I/O: the link command gathers state (teams, projects)
|
|
4
|
+
* and these functions decide what to do — use a project, create one, rename,
|
|
5
|
+
* or stop with a decision-needed result that carries everything an AI
|
|
6
|
+
* assistant needs to ask the user and retry with a deviation flag.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* LINK-12.3: any deviation flag implies non-interactive mode.
|
|
10
|
+
*/
|
|
11
|
+
export function isNonInteractive(flags) {
|
|
12
|
+
return Boolean(flags.yes || flags.team || flags.connect || flags.create);
|
|
13
|
+
}
|
|
14
|
+
export function hasCapacity(team) {
|
|
15
|
+
return team.projectLimit === -1 || team.projectCount < team.projectLimit;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* LINK-10.1, LINK-11.0, LINK-12.0, LINK-12.4
|
|
19
|
+
*/
|
|
20
|
+
export function resolveTeam(teams, flags) {
|
|
21
|
+
if (flags.team) {
|
|
22
|
+
const wanted = flags.team.toLowerCase();
|
|
23
|
+
const match = teams.find((t) => t.teamId === flags.team || t.name.toLowerCase() === wanted);
|
|
24
|
+
if (match)
|
|
25
|
+
return { kind: "use", team: match };
|
|
26
|
+
return {
|
|
27
|
+
kind: "no-match",
|
|
28
|
+
flag: "team",
|
|
29
|
+
provided: flags.team,
|
|
30
|
+
alternatives: teams.map((t) => `${t.name} (${t.teamId})`),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
if (teams.length === 1) {
|
|
34
|
+
return { kind: "use", team: teams[0] };
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
kind: "decision",
|
|
38
|
+
decision: "team",
|
|
39
|
+
message: "You belong to multiple teams — which should this project join?",
|
|
40
|
+
options: teams.map((t) => ({
|
|
41
|
+
label: `${t.name} (${t.tierName}, ${formatCapacity(t)})`,
|
|
42
|
+
retryFlag: `--team ${t.teamId}`,
|
|
43
|
+
})),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* LINK-10.2/10.3 (default-project rule), LINK-11.1/11.2 (decision menus),
|
|
48
|
+
* LINK-12.1/12.2/12.4 (deviation flags).
|
|
49
|
+
*/
|
|
50
|
+
export function resolveProject(projects, team, flags) {
|
|
51
|
+
if (flags.connect) {
|
|
52
|
+
const match = projects.find((p) => p.projectSlug === flags.connect);
|
|
53
|
+
if (match)
|
|
54
|
+
return { kind: "connect", project: match, rename: false };
|
|
55
|
+
return {
|
|
56
|
+
kind: "no-match",
|
|
57
|
+
flag: "connect",
|
|
58
|
+
provided: flags.connect,
|
|
59
|
+
alternatives: projects
|
|
60
|
+
.filter((p) => p.projectSlug)
|
|
61
|
+
.map((p) => `${p.projectName} (${p.projectSlug})`),
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
if (flags.create) {
|
|
65
|
+
if (hasCapacity(team))
|
|
66
|
+
return { kind: "create" };
|
|
67
|
+
return atCapacityDecision(projects, team);
|
|
68
|
+
}
|
|
69
|
+
if (projects.length === 0) {
|
|
70
|
+
// A decision with a single possible answer is not a decision: create.
|
|
71
|
+
if (hasCapacity(team))
|
|
72
|
+
return { kind: "create" };
|
|
73
|
+
return atCapacityDecision(projects, team);
|
|
74
|
+
}
|
|
75
|
+
if (projects.length === 1 && projects[0].isDefault) {
|
|
76
|
+
// LINK-10.2: rename the untouched default project to match this repo;
|
|
77
|
+
// LINK-10.3: if the user has put content in it, connect without renaming
|
|
78
|
+
return {
|
|
79
|
+
kind: "connect",
|
|
80
|
+
project: projects[0],
|
|
81
|
+
rename: !projects[0].hasUserContent,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
// LINK-11.1: existing projects the user chose to create — their call
|
|
85
|
+
return {
|
|
86
|
+
kind: "decision",
|
|
87
|
+
decision: "project",
|
|
88
|
+
message: "This team already has projects — connect to one, or create a new one?",
|
|
89
|
+
options: [
|
|
90
|
+
...projects.map((p) => ({
|
|
91
|
+
label: `${p.projectName}${p.hasUserContent ? "" : " (empty)"}`,
|
|
92
|
+
retryFlag: p.projectSlug ? `--connect ${p.projectSlug}` : undefined,
|
|
93
|
+
})),
|
|
94
|
+
...(hasCapacity(team)
|
|
95
|
+
? [{ label: "Create a new project", retryFlag: "--create" }]
|
|
96
|
+
: []),
|
|
97
|
+
],
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* LINK-11.2: creating is required (or requested) but the team is at its
|
|
102
|
+
* project limit. None of the remedies is a plain link retry flag.
|
|
103
|
+
*/
|
|
104
|
+
function atCapacityDecision(projects, team) {
|
|
105
|
+
return {
|
|
106
|
+
kind: "decision",
|
|
107
|
+
decision: "capacity",
|
|
108
|
+
message: `Team "${team.name}" is at its ${team.tierName} project limit (${formatCapacity(team)}).`,
|
|
109
|
+
options: [
|
|
110
|
+
...projects
|
|
111
|
+
.filter((p) => p.projectSlug)
|
|
112
|
+
.map((p) => ({
|
|
113
|
+
label: `Connect to existing project ${p.projectName}`,
|
|
114
|
+
retryFlag: `--connect ${p.projectSlug}`,
|
|
115
|
+
})),
|
|
116
|
+
{ label: "Delete a project you no longer need (in the web app)" },
|
|
117
|
+
{ label: "Upgrade the team for more projects" },
|
|
118
|
+
],
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
function formatCapacity(team) {
|
|
122
|
+
return team.projectLimit === -1
|
|
123
|
+
? `${team.projectCount}/unlimited projects`
|
|
124
|
+
: `${team.projectCount}/${team.projectLimit} projects`;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Prompt-free project naming for non-interactive mode (LINK-9.0): explicit
|
|
128
|
+
* flag, then package metadata, then directory name, then a fixed fallback —
|
|
129
|
+
* never a prompt.
|
|
130
|
+
*/
|
|
131
|
+
export function resolveProjectName(flags, packageName, directoryName) {
|
|
132
|
+
if (flags.name)
|
|
133
|
+
return flags.name;
|
|
134
|
+
if (packageName)
|
|
135
|
+
return packageName;
|
|
136
|
+
if (directoryName && directoryName !== "/" && directoryName !== ".") {
|
|
137
|
+
return directoryName;
|
|
138
|
+
}
|
|
139
|
+
return "my-project";
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=link-resolution.js.map
|
package/dist/commands/link.d.ts
CHANGED
|
@@ -1,14 +1,24 @@
|
|
|
1
|
+
import { type LinkFlags } from "./link-resolution.js";
|
|
2
|
+
export interface LinkCommandOptions extends LinkFlags {
|
|
3
|
+
}
|
|
1
4
|
/**
|
|
2
|
-
* Link command - connect or reconnect local project to cloud
|
|
5
|
+
* Link command - connect or reconnect local project to cloud, creating the
|
|
6
|
+
* cloud project when needed. Link owns the "upgrade local to cloud"
|
|
7
|
+
* transition.
|
|
3
8
|
*
|
|
4
9
|
* Requirements:
|
|
5
10
|
* - LINK-1: Requires existing .requirements/ folder
|
|
6
11
|
* - LINK-2: Offers refresh when credentials exist
|
|
7
12
|
* - LINK-3: Uses inline OAuth (no persistent tokens)
|
|
8
|
-
* - LINK-4, LINK-5: Team and project selection
|
|
13
|
+
* - LINK-4, LINK-5: Team and project selection (including the create option)
|
|
9
14
|
* - LINK-6: Saves credentials to project-settings.json
|
|
10
|
-
* - LINK-7: Optionally pulls requirements
|
|
15
|
+
* - LINK-7: Optionally pulls requirements (interactive only)
|
|
11
16
|
* - LINK-8: Handles network errors gracefully
|
|
17
|
+
* - LINK-9: Creates the cloud project when chosen
|
|
18
|
+
* - LINK-10/11/12: Non-interactive mode for AI-driven setup
|
|
19
|
+
* - LINK-13: Non-interactive success includes share artifacts (team-invite
|
|
20
|
+
* URL + read-only pull command) so one "yes" puts the spec in front of
|
|
21
|
+
* the team
|
|
12
22
|
*/
|
|
13
|
-
export declare function linkCommand(): Promise<void>;
|
|
23
|
+
export declare function linkCommand(options?: LinkCommandOptions): Promise<void>;
|
|
14
24
|
//# sourceMappingURL=link.d.ts.map
|