reffy-cli 1.4.2 → 1.7.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/README.md +100 -58
- package/dist/cli.js +547 -172
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/manifest.d.ts +5 -1
- package/dist/manifest.js +59 -6
- package/dist/remote.d.ts +150 -41
- package/dist/remote.js +356 -99
- package/dist/storage.d.ts +1 -1
- package/dist/storage.js +1 -1
- package/dist/types.d.ts +13 -4
- package/dist/workspace.js +6 -4
- package/package.json +1 -2
package/dist/index.d.ts
CHANGED
|
@@ -4,5 +4,5 @@ export { runDoctor } from "./doctor.js";
|
|
|
4
4
|
export { createPlanScaffold } from "./plan.js";
|
|
5
5
|
export { loadDotEnvIfPresent, parseDotEnv } from "./env.js";
|
|
6
6
|
export { ensureGitignoreEntries } from "./gitignore.js";
|
|
7
|
-
export { collectWorkspaceDocuments,
|
|
7
|
+
export { collectWorkspaceDocuments, ensureManagerInit, ensureWorkspaceTarget, extractWorkspaceSummaryIdentity, PaseoManagerClient, PaseoWorkspaceBackendClient, readRemoteConfig, resolveRemoteConfigPath, resolveRemoteTarget, resolveSelectedWorkspaceId, toCanonicalRemotePath, writeRemoteConfig, } from "./remote.js";
|
|
8
8
|
export { listSpecs, showSpec } from "./spec-runtime.js";
|
package/dist/index.js
CHANGED
|
@@ -4,5 +4,5 @@ export { runDoctor } from "./doctor.js";
|
|
|
4
4
|
export { createPlanScaffold } from "./plan.js";
|
|
5
5
|
export { loadDotEnvIfPresent, parseDotEnv } from "./env.js";
|
|
6
6
|
export { ensureGitignoreEntries } from "./gitignore.js";
|
|
7
|
-
export { collectWorkspaceDocuments,
|
|
7
|
+
export { collectWorkspaceDocuments, ensureManagerInit, ensureWorkspaceTarget, extractWorkspaceSummaryIdentity, PaseoManagerClient, PaseoWorkspaceBackendClient, readRemoteConfig, resolveRemoteConfigPath, resolveRemoteTarget, resolveSelectedWorkspaceId, toCanonicalRemotePath, writeRemoteConfig, } from "./remote.js";
|
|
8
8
|
export { listSpecs, showSpec } from "./spec-runtime.js";
|
package/dist/manifest.d.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import type { Manifest } from "./types.js";
|
|
2
2
|
export declare const MANIFEST_VERSION = 1;
|
|
3
3
|
export declare function allowedKindExtensions(): Record<string, string[]>;
|
|
4
|
-
export
|
|
4
|
+
export interface ManifestIdentityDefaults {
|
|
5
|
+
project_id: string;
|
|
6
|
+
workspace_ids: string[];
|
|
7
|
+
}
|
|
8
|
+
export declare function deriveManifestIdentity(repoRoot: string): ManifestIdentityDefaults;
|
|
5
9
|
export declare function createManifest(repoRoot: string, now?: string): Manifest;
|
|
6
10
|
export declare function normalizeManifest(raw: unknown, repoRoot: string): Manifest;
|
|
7
11
|
export declare function inferArtifactType(filePath: string): {
|
package/dist/manifest.js
CHANGED
|
@@ -13,6 +13,7 @@ const KIND_EXTENSIONS = {
|
|
|
13
13
|
file: [],
|
|
14
14
|
};
|
|
15
15
|
const PROJECT_ID_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
16
|
+
const WORKSPACE_ID_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
16
17
|
const FALLBACK_WORKSPACE_ID = "reffy-workspace";
|
|
17
18
|
function isObject(value) {
|
|
18
19
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -25,11 +26,22 @@ function isIsoDate(value) {
|
|
|
25
26
|
function isProjectId(value) {
|
|
26
27
|
return typeof value === "string" && PROJECT_ID_PATTERN.test(value);
|
|
27
28
|
}
|
|
29
|
+
function isWorkspaceId(value) {
|
|
30
|
+
return typeof value === "string" && WORKSPACE_ID_PATTERN.test(value);
|
|
31
|
+
}
|
|
28
32
|
function isWorkspaceName(value) {
|
|
29
33
|
return (typeof value === "string" &&
|
|
30
34
|
value.trim().length > 0 &&
|
|
31
35
|
!/[\\/\r\n\t]/.test(value));
|
|
32
36
|
}
|
|
37
|
+
function slugifyWorkspaceId(value) {
|
|
38
|
+
const slug = value
|
|
39
|
+
.trim()
|
|
40
|
+
.toLowerCase()
|
|
41
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
42
|
+
.replace(/^-+|-+$/g, "");
|
|
43
|
+
return slug.length > 0 ? slug : null;
|
|
44
|
+
}
|
|
33
45
|
function slugifyIdentity(value) {
|
|
34
46
|
return value
|
|
35
47
|
.trim()
|
|
@@ -51,18 +63,33 @@ export function deriveManifestIdentity(repoRoot) {
|
|
|
51
63
|
const identity = candidate || FALLBACK_WORKSPACE_ID;
|
|
52
64
|
return {
|
|
53
65
|
project_id: identity,
|
|
54
|
-
|
|
66
|
+
workspace_ids: [identity],
|
|
55
67
|
};
|
|
56
68
|
}
|
|
57
69
|
export function createManifest(repoRoot, now = new Date().toISOString()) {
|
|
70
|
+
const defaults = deriveManifestIdentity(repoRoot);
|
|
58
71
|
return {
|
|
59
72
|
version: MANIFEST_VERSION,
|
|
60
73
|
created_at: now,
|
|
61
74
|
updated_at: now,
|
|
62
|
-
|
|
75
|
+
project_id: defaults.project_id,
|
|
76
|
+
workspace_ids: defaults.workspace_ids,
|
|
63
77
|
artifacts: [],
|
|
64
78
|
};
|
|
65
79
|
}
|
|
80
|
+
function normalizeWorkspaceIds(raw, fallback) {
|
|
81
|
+
const explicit = Array.isArray(raw.workspace_ids)
|
|
82
|
+
? raw.workspace_ids.filter((entry) => typeof entry === "string" && entry.trim().length > 0)
|
|
83
|
+
: null;
|
|
84
|
+
if (explicit && explicit.length > 0) {
|
|
85
|
+
return Array.from(new Set(explicit.map((entry) => entry.trim())));
|
|
86
|
+
}
|
|
87
|
+
if (typeof raw.workspace_name === "string" && raw.workspace_name.trim().length > 0) {
|
|
88
|
+
const migrated = slugifyWorkspaceId(raw.workspace_name) ?? raw.workspace_name.trim();
|
|
89
|
+
return [migrated];
|
|
90
|
+
}
|
|
91
|
+
return [...fallback];
|
|
92
|
+
}
|
|
66
93
|
export function normalizeManifest(raw, repoRoot) {
|
|
67
94
|
const now = new Date().toISOString();
|
|
68
95
|
const defaults = deriveManifestIdentity(repoRoot);
|
|
@@ -71,7 +98,8 @@ export function normalizeManifest(raw, repoRoot) {
|
|
|
71
98
|
version: 0,
|
|
72
99
|
created_at: now,
|
|
73
100
|
updated_at: now,
|
|
74
|
-
|
|
101
|
+
project_id: defaults.project_id,
|
|
102
|
+
workspace_ids: defaults.workspace_ids,
|
|
75
103
|
artifacts: raw,
|
|
76
104
|
};
|
|
77
105
|
}
|
|
@@ -79,12 +107,13 @@ export function normalizeManifest(raw, repoRoot) {
|
|
|
79
107
|
return createManifest(repoRoot, now);
|
|
80
108
|
}
|
|
81
109
|
const artifacts = Array.isArray(raw.artifacts) ? raw.artifacts : [];
|
|
110
|
+
const workspaceIds = normalizeWorkspaceIds(raw, defaults.workspace_ids);
|
|
82
111
|
return {
|
|
83
112
|
version: typeof raw.version === "number" ? raw.version : MANIFEST_VERSION,
|
|
84
113
|
created_at: typeof raw.created_at === "string" ? raw.created_at : now,
|
|
85
114
|
updated_at: typeof raw.updated_at === "string" ? raw.updated_at : now,
|
|
86
115
|
project_id: typeof raw.project_id === "string" ? raw.project_id : defaults.project_id,
|
|
87
|
-
|
|
116
|
+
workspace_ids: workspaceIds,
|
|
88
117
|
artifacts,
|
|
89
118
|
};
|
|
90
119
|
}
|
|
@@ -183,8 +212,32 @@ export async function validateManifest(manifestPath, artifactsDir) {
|
|
|
183
212
|
if (raw.project_id !== undefined && !isProjectId(raw.project_id)) {
|
|
184
213
|
errors.push("project_id must be a non-empty kebab-case string");
|
|
185
214
|
}
|
|
186
|
-
if (raw.
|
|
187
|
-
|
|
215
|
+
if (raw.workspace_ids !== undefined) {
|
|
216
|
+
if (!Array.isArray(raw.workspace_ids) || raw.workspace_ids.length === 0) {
|
|
217
|
+
errors.push("workspace_ids must be a non-empty array of kebab-case strings when provided");
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
const seen = new Set();
|
|
221
|
+
raw.workspace_ids.forEach((entry, index) => {
|
|
222
|
+
if (!isWorkspaceId(entry)) {
|
|
223
|
+
errors.push(`workspace_ids[${index}] must be a non-empty kebab-case string`);
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
if (seen.has(entry)) {
|
|
227
|
+
errors.push(`workspace_ids[${index}] duplicates "${entry}"`);
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
seen.add(entry);
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
if (raw.workspace_name !== undefined) {
|
|
235
|
+
if (!isWorkspaceName(raw.workspace_name)) {
|
|
236
|
+
errors.push("workspace_name must be a non-empty string without path separators or control characters");
|
|
237
|
+
}
|
|
238
|
+
else if (raw.workspace_ids === undefined) {
|
|
239
|
+
warnings.push("workspace_name is deprecated; migrate to workspace_ids");
|
|
240
|
+
}
|
|
188
241
|
}
|
|
189
242
|
if (!Array.isArray(raw.artifacts)) {
|
|
190
243
|
errors.push("artifacts must be an array");
|
package/dist/remote.d.ts
CHANGED
|
@@ -1,21 +1,23 @@
|
|
|
1
|
-
import type { RemoteDocument, RemoteImportResult, RemoteLinkConfig, RemoteWorkspaceSummary } from "./types.js";
|
|
2
|
-
export declare const REMOTE_CONFIG_VERSION =
|
|
1
|
+
import type { RemoteActorIdentity, RemoteDocument, RemoteImportResult, RemoteLinkConfig, RemoteTarget, RemoteWorkspaceSummary } from "./types.js";
|
|
2
|
+
export declare const REMOTE_CONFIG_VERSION = 4;
|
|
3
3
|
export declare const REMOTE_PROVIDER = "paseo";
|
|
4
|
+
export declare const REMOTE_BACKEND_ACTOR_TYPE = "reffyRemoteBackend";
|
|
5
|
+
export declare const REMOTE_BACKEND_VERSION = "v2";
|
|
6
|
+
export declare const REMOTE_MANAGER_ACTOR_TYPE = "reffyWorkspaceManager";
|
|
7
|
+
export declare const REMOTE_MANAGER_VERSION = "v1";
|
|
4
8
|
export interface WorkspaceIdentity {
|
|
5
9
|
project_id: string;
|
|
6
|
-
|
|
10
|
+
workspace_id: string;
|
|
7
11
|
}
|
|
8
|
-
export interface
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
actorId?: string;
|
|
12
|
-
provision: boolean;
|
|
13
|
-
identity: WorkspaceIdentity;
|
|
12
|
+
export interface ManifestIdentityLike {
|
|
13
|
+
project_id?: string;
|
|
14
|
+
workspace_ids?: string[];
|
|
14
15
|
}
|
|
15
|
-
export interface
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
export interface ResolvedRemoteTarget {
|
|
17
|
+
endpoint: string;
|
|
18
|
+
manager: RemoteActorIdentity;
|
|
19
|
+
workspace_backend: RemoteActorIdentity;
|
|
20
|
+
last_imported_at?: string;
|
|
19
21
|
}
|
|
20
22
|
export interface ValidatedImportResult {
|
|
21
23
|
imported: number;
|
|
@@ -24,42 +26,149 @@ export interface ValidatedImportResult {
|
|
|
24
26
|
deleted: number;
|
|
25
27
|
}
|
|
26
28
|
export declare function resolveRemoteConfigPath(repoRoot: string): string;
|
|
29
|
+
export declare function resolveSelectedWorkspaceId(identity: ManifestIdentityLike, override: string | undefined): string;
|
|
30
|
+
export declare function requireWorkspaceIdentity(identity: ManifestIdentityLike, selectedWorkspaceId: string): WorkspaceIdentity;
|
|
27
31
|
export declare function readRemoteConfig(repoRoot: string): Promise<RemoteLinkConfig | null>;
|
|
28
32
|
export declare function writeRemoteConfig(repoRoot: string, config: RemoteLinkConfig): Promise<string>;
|
|
29
|
-
export declare function updateRemoteConfigMetadata(repoRoot: string, patch: Partial<Pick<
|
|
30
|
-
export declare function
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
export declare function updateRemoteConfigMetadata(repoRoot: string, workspaceId: string, patch: Partial<Pick<RemoteTarget, "last_imported_at">>): Promise<RemoteLinkConfig | null>;
|
|
34
|
+
export declare function removeWorkspaceTarget(repoRoot: string, existing: RemoteLinkConfig, workspaceId: string): Promise<{
|
|
35
|
+
config: RemoteLinkConfig;
|
|
36
|
+
existed: boolean;
|
|
37
|
+
}>;
|
|
38
|
+
export declare function upsertWorkspaceTarget(repoRoot: string, existing: RemoteLinkConfig, workspaceId: string, workspaceBackend: RemoteActorIdentity): Promise<RemoteLinkConfig>;
|
|
39
|
+
export declare function resolveRemoteTarget(stored: RemoteLinkConfig | null, workspaceId: string, endpoint: string): ResolvedRemoteTarget | null;
|
|
40
|
+
export declare function describeRemoteLinkage(linkage: {
|
|
41
|
+
endpoint: string;
|
|
42
|
+
manager: RemoteActorIdentity;
|
|
43
|
+
workspace_backend: RemoteActorIdentity;
|
|
44
|
+
workspace_id: string;
|
|
45
|
+
}): string;
|
|
46
|
+
export declare class RemoteHttpError extends Error {
|
|
47
|
+
readonly status: number;
|
|
48
|
+
readonly body: string;
|
|
49
|
+
readonly url: string;
|
|
50
|
+
readonly method: string;
|
|
51
|
+
constructor(status: number, statusText: string, body: string, url: string, method: string);
|
|
52
|
+
}
|
|
53
|
+
export interface ManagerWorkspaceResponse {
|
|
54
|
+
workspace?: {
|
|
55
|
+
workspace_id?: string;
|
|
56
|
+
backend?: {
|
|
57
|
+
pod_name?: string;
|
|
58
|
+
actor_id?: string;
|
|
59
|
+
};
|
|
60
|
+
metadata?: Record<string, unknown>;
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
export interface ManagerProjectListResponse {
|
|
64
|
+
projects?: Array<{
|
|
65
|
+
project_id?: string;
|
|
66
|
+
metadata?: Record<string, unknown>;
|
|
67
|
+
}>;
|
|
68
|
+
}
|
|
69
|
+
export interface ManagerProjectResponse {
|
|
70
|
+
project?: {
|
|
71
|
+
project_id?: string;
|
|
72
|
+
metadata?: Record<string, unknown>;
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
export interface CreateManagerActorResult {
|
|
76
|
+
actorId: string;
|
|
77
|
+
managerAuthToken: string;
|
|
78
|
+
}
|
|
79
|
+
export declare class PaseoManagerClient {
|
|
80
|
+
private readonly endpoint;
|
|
81
|
+
private readonly identity;
|
|
82
|
+
private readonly token?;
|
|
83
|
+
constructor(endpoint: string, identity: RemoteActorIdentity, token?: string);
|
|
84
|
+
private base;
|
|
85
|
+
private requireToken;
|
|
35
86
|
createPod(): Promise<string>;
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
path?: string;
|
|
42
|
-
}>;
|
|
87
|
+
createManagerActor(podName: string): Promise<CreateManagerActorResult>;
|
|
88
|
+
createWorkspace(workspaceId: string, metadata?: Record<string, unknown>): Promise<RemoteActorIdentity>;
|
|
89
|
+
getWorkspace(workspaceId: string): Promise<RemoteActorIdentity>;
|
|
90
|
+
registerProject(workspaceId: string, projectId: string): Promise<{
|
|
91
|
+
alreadyRegistered: boolean;
|
|
43
92
|
}>;
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
content_type?: string;
|
|
49
|
-
};
|
|
93
|
+
listProjects(workspaceId: string): Promise<ManagerProjectListResponse>;
|
|
94
|
+
getProject(workspaceId: string, projectId: string): Promise<ManagerProjectResponse>;
|
|
95
|
+
deleteWorkspace(workspaceId: string): Promise<{
|
|
96
|
+
alreadyAbsent: boolean;
|
|
50
97
|
}>;
|
|
51
98
|
}
|
|
52
|
-
export
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
99
|
+
export interface ProjectDocumentListResponse {
|
|
100
|
+
documents?: Array<{
|
|
101
|
+
path?: string;
|
|
102
|
+
content?: string;
|
|
103
|
+
content_type?: string;
|
|
104
|
+
metadata?: Record<string, unknown>;
|
|
105
|
+
}>;
|
|
106
|
+
}
|
|
107
|
+
export interface ProjectDocumentResponse {
|
|
108
|
+
document?: {
|
|
109
|
+
path?: string;
|
|
110
|
+
content?: string;
|
|
111
|
+
content_type?: string;
|
|
112
|
+
metadata?: Record<string, unknown>;
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
export interface ProjectSnapshotResponse {
|
|
116
|
+
snapshot?: Record<string, unknown>;
|
|
117
|
+
documents?: Array<{
|
|
118
|
+
path?: string;
|
|
119
|
+
}>;
|
|
120
|
+
}
|
|
121
|
+
export declare class PaseoWorkspaceBackendClient {
|
|
122
|
+
private readonly endpoint;
|
|
123
|
+
private readonly identity;
|
|
124
|
+
private readonly token;
|
|
125
|
+
constructor(endpoint: string, identity: RemoteActorIdentity, token: string);
|
|
126
|
+
private base;
|
|
127
|
+
getWorkspace(): Promise<RemoteWorkspaceSummary>;
|
|
128
|
+
importProject(projectId: string, documents: RemoteDocument[], replaceMissing?: boolean): Promise<RemoteImportResult>;
|
|
129
|
+
listProjectDocuments(projectId: string, options?: {
|
|
130
|
+
prefix?: string;
|
|
131
|
+
}): Promise<ProjectDocumentListResponse>;
|
|
132
|
+
getProjectDocument(projectId: string, documentPath: string): Promise<ProjectDocumentResponse>;
|
|
133
|
+
getProjectSnapshot(projectId: string): Promise<ProjectSnapshotResponse>;
|
|
134
|
+
}
|
|
135
|
+
export interface EnsureManagerInitOptions {
|
|
136
|
+
endpoint: string;
|
|
137
|
+
managerPodName?: string;
|
|
138
|
+
managerActorId?: string;
|
|
139
|
+
provision: boolean;
|
|
140
|
+
existingConfig: RemoteLinkConfig | null;
|
|
141
|
+
}
|
|
142
|
+
export interface EnsureManagerInitResult {
|
|
143
|
+
config: RemoteLinkConfig;
|
|
144
|
+
created_pod: boolean;
|
|
145
|
+
created_actor: boolean;
|
|
146
|
+
/** Bearer token returned by the backend when a fresh manager actor was created. Only set when `created_actor` is true. */
|
|
147
|
+
manager_auth_token?: string;
|
|
148
|
+
}
|
|
149
|
+
export declare function ensureManagerInit(repoRoot: string, options: EnsureManagerInitOptions): Promise<EnsureManagerInitResult>;
|
|
150
|
+
export type WorkspaceTargetMode = "create" | "resolve" | "auto";
|
|
151
|
+
export interface EnsureWorkspaceTargetOptions {
|
|
152
|
+
workspaceId: string;
|
|
153
|
+
mode: WorkspaceTargetMode;
|
|
154
|
+
endpoint: string;
|
|
155
|
+
token: string;
|
|
156
|
+
metadata?: Record<string, unknown>;
|
|
157
|
+
}
|
|
158
|
+
export interface EnsureWorkspaceTargetResult {
|
|
159
|
+
config: RemoteLinkConfig;
|
|
160
|
+
workspace_backend: RemoteActorIdentity;
|
|
161
|
+
outcome: "created" | "resolved" | "reused";
|
|
162
|
+
}
|
|
163
|
+
export declare function ensureWorkspaceTarget(repoRoot: string, config: RemoteLinkConfig, options: EnsureWorkspaceTargetOptions): Promise<EnsureWorkspaceTargetResult>;
|
|
164
|
+
export declare function extractWorkspaceSummaryIdentity(summary: RemoteWorkspaceSummary): {
|
|
165
|
+
workspace_id?: string | null;
|
|
166
|
+
actor_type?: string | null;
|
|
167
|
+
backend_version?: string | null;
|
|
60
168
|
document_count?: number | null;
|
|
169
|
+
registered_project_count?: number | null;
|
|
61
170
|
};
|
|
62
|
-
export declare function
|
|
171
|
+
export declare function assertWorkspaceSummaryIdentity(summary: RemoteWorkspaceSummary, expectedWorkspaceId: string): void;
|
|
63
172
|
export declare function validateImportResult(result: RemoteImportResult): ValidatedImportResult;
|
|
64
173
|
export declare function toCanonicalRemotePath(refsDir: string, filePath: string): string;
|
|
65
174
|
export declare function collectWorkspaceDocuments(repoRoot: string): Promise<RemoteDocument[]>;
|