@formigio/fazemos-cli 0.10.14 → 0.10.16
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/connectionErrorCopy.d.ts +27 -4
- package/dist/connectionErrorCopy.js +67 -9
- package/dist/connectionErrorCopy.js.map +1 -1
- package/dist/dispatch.d.ts +96 -0
- package/dist/dispatch.js +169 -0
- package/dist/dispatch.js.map +1 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.js +345 -45
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,19 +1,31 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* F16 — Role-aware copy for the
|
|
3
|
-
* structured error (tech spec §5.14
|
|
2
|
+
* F16 / F22 — Role × reason × provider-aware copy for the
|
|
3
|
+
* `PROJECT_CONNECTION_UNAVAILABLE` structured error (tech spec §5.14
|
|
4
|
+
* + F22 spec §8.3 item 7 + UX manifest §3).
|
|
4
5
|
*
|
|
5
6
|
* Mirrors the web's `renderProjectConnectionUnavailableCopy` so admin
|
|
6
7
|
* and member experiences stay consistent across surfaces. CLI variant
|
|
7
8
|
* adds the settings URL as a trailing line for admins; members see
|
|
8
9
|
* "Ask your admin" without a URL.
|
|
9
10
|
*
|
|
11
|
+
* F22 added the `provider` axis: copy now branches on
|
|
12
|
+
* - reason (missing | revoked | suspended | uninstalled)
|
|
13
|
+
* - role (owner|admin vs member)
|
|
14
|
+
* - provider (github | bitbucket | null/unknown)
|
|
15
|
+
*
|
|
16
|
+
* The matrix is the table in Sage UX-manifest §3 ("Role-Aware Pipeline
|
|
17
|
+
* Error Copy"). For unknown provider (defensive fallback) we render a
|
|
18
|
+
* provider-neutral line; the user can always go to settings and see
|
|
19
|
+
* which Connection is bound.
|
|
20
|
+
*
|
|
10
21
|
* The `getEnv()` helper supplies the web origin so we can construct
|
|
11
22
|
* fully-qualified URLs the user can click in the terminal.
|
|
12
23
|
*/
|
|
13
24
|
/**
|
|
14
25
|
* Structured payload returned by pipeline-run endpoints when the
|
|
15
26
|
* Project's Connection is missing/revoked/suspended/uninstalled.
|
|
16
|
-
* Matches the contract in tech spec §5.14.
|
|
27
|
+
* Matches the contract in tech spec §5.14 (F16) + F22 §9.4 (added
|
|
28
|
+
* `provider` for provider-aware copy).
|
|
17
29
|
*/
|
|
18
30
|
export interface ProjectConnectionUnavailableErrorBody {
|
|
19
31
|
error: 'project_connection_unavailable';
|
|
@@ -24,6 +36,14 @@ export interface ProjectConnectionUnavailableErrorBody {
|
|
|
24
36
|
projectId: string;
|
|
25
37
|
projectSlug: string;
|
|
26
38
|
connectionId: string | null;
|
|
39
|
+
/**
|
|
40
|
+
* F22 — Provider for the Project's bound (or expected) Connection.
|
|
41
|
+
* `null`/absent when reason='missing' AND no Connection row exists
|
|
42
|
+
* yet (the server can't know which provider the user wants); the
|
|
43
|
+
* copy falls back to a provider-neutral "Code platform connection"
|
|
44
|
+
* line. Forward-compat: an unknown provider string also falls back.
|
|
45
|
+
*/
|
|
46
|
+
provider?: 'github' | 'bitbucket' | null;
|
|
27
47
|
}
|
|
28
48
|
export interface ConnectionErrorLines {
|
|
29
49
|
/** Lead headline. */
|
|
@@ -42,5 +62,8 @@ export declare function isProjectConnectionUnavailable(body: unknown): body is P
|
|
|
42
62
|
* Produce the role-aware lines for terminal rendering. Caller decides
|
|
43
63
|
* how to color / format. The shape is plain so a JSON test fixture
|
|
44
64
|
* stays readable.
|
|
65
|
+
*
|
|
66
|
+
* F22 — Branches on `error.provider` per UX-manifest §3 table. Falls
|
|
67
|
+
* back to a provider-neutral line when provider is unknown/null.
|
|
45
68
|
*/
|
|
46
|
-
export declare function renderProjectConnectionUnavailableCopy(error: Pick<ProjectConnectionUnavailableErrorBody, 'reason' | 'orgSlug' | 'connectionId'>, role: 'owner' | 'admin' | 'member' | string): ConnectionErrorLines;
|
|
69
|
+
export declare function renderProjectConnectionUnavailableCopy(error: Pick<ProjectConnectionUnavailableErrorBody, 'reason' | 'orgSlug' | 'connectionId' | 'provider'>, role: 'owner' | 'admin' | 'member' | string): ConnectionErrorLines;
|
|
@@ -1,12 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* F16 — Role-aware copy for the
|
|
3
|
-
* structured error (tech spec §5.14
|
|
2
|
+
* F16 / F22 — Role × reason × provider-aware copy for the
|
|
3
|
+
* `PROJECT_CONNECTION_UNAVAILABLE` structured error (tech spec §5.14
|
|
4
|
+
* + F22 spec §8.3 item 7 + UX manifest §3).
|
|
4
5
|
*
|
|
5
6
|
* Mirrors the web's `renderProjectConnectionUnavailableCopy` so admin
|
|
6
7
|
* and member experiences stay consistent across surfaces. CLI variant
|
|
7
8
|
* adds the settings URL as a trailing line for admins; members see
|
|
8
9
|
* "Ask your admin" without a URL.
|
|
9
10
|
*
|
|
11
|
+
* F22 added the `provider` axis: copy now branches on
|
|
12
|
+
* - reason (missing | revoked | suspended | uninstalled)
|
|
13
|
+
* - role (owner|admin vs member)
|
|
14
|
+
* - provider (github | bitbucket | null/unknown)
|
|
15
|
+
*
|
|
16
|
+
* The matrix is the table in Sage UX-manifest §3 ("Role-Aware Pipeline
|
|
17
|
+
* Error Copy"). For unknown provider (defensive fallback) we render a
|
|
18
|
+
* provider-neutral line; the user can always go to settings and see
|
|
19
|
+
* which Connection is bound.
|
|
20
|
+
*
|
|
10
21
|
* The `getEnv()` helper supplies the web origin so we can construct
|
|
11
22
|
* fully-qualified URLs the user can click in the terminal.
|
|
12
23
|
*/
|
|
@@ -56,10 +67,26 @@ function deriveWebOrigin() {
|
|
|
56
67
|
return null;
|
|
57
68
|
}
|
|
58
69
|
}
|
|
70
|
+
/**
|
|
71
|
+
* Human-friendly provider label. Defensive: unknown providers render
|
|
72
|
+
* as a generic "code platform" string so the copy stays useful if a
|
|
73
|
+
* future provider ships before this file is updated (UX manifest §3
|
|
74
|
+
* "Defensive fallback (unknown provider)").
|
|
75
|
+
*/
|
|
76
|
+
function providerLabel(provider) {
|
|
77
|
+
if (provider === 'github')
|
|
78
|
+
return 'GitHub';
|
|
79
|
+
if (provider === 'bitbucket')
|
|
80
|
+
return 'BitBucket';
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
59
83
|
/**
|
|
60
84
|
* Produce the role-aware lines for terminal rendering. Caller decides
|
|
61
85
|
* how to color / format. The shape is plain so a JSON test fixture
|
|
62
86
|
* stays readable.
|
|
87
|
+
*
|
|
88
|
+
* F22 — Branches on `error.provider` per UX-manifest §3 table. Falls
|
|
89
|
+
* back to a provider-neutral line when provider is unknown/null.
|
|
63
90
|
*/
|
|
64
91
|
export function renderProjectConnectionUnavailableCopy(error, role) {
|
|
65
92
|
const isAdmin = role === 'owner' || role === 'admin';
|
|
@@ -68,34 +95,65 @@ export function renderProjectConnectionUnavailableCopy(error, role) {
|
|
|
68
95
|
? `/org/${error.orgSlug}/settings/connections/${error.connectionId}`
|
|
69
96
|
: `/org/${error.orgSlug}/settings/connections`;
|
|
70
97
|
const ctaUrl = origin ? `${origin}${settingsPath}` : settingsPath;
|
|
98
|
+
const label = providerLabel(error.provider);
|
|
99
|
+
// ── Defensive fallback: unknown provider ──────────────────────
|
|
100
|
+
// UX manifest §3 last paragraph: "render the provider name as a raw
|
|
101
|
+
// string if neither github nor bitbucket — 'Code platform connection
|
|
102
|
+
// is unavailable. Check the project's connection in settings.'"
|
|
103
|
+
if (label === null) {
|
|
104
|
+
if (error.reason === 'missing') {
|
|
105
|
+
return isAdmin
|
|
106
|
+
? {
|
|
107
|
+
title: 'Connect a code platform to run this pipeline.',
|
|
108
|
+
body: 'This project needs a code platform connection to clone its repos.',
|
|
109
|
+
ctaUrl,
|
|
110
|
+
}
|
|
111
|
+
: {
|
|
112
|
+
title: 'This project needs a code platform connection.',
|
|
113
|
+
body: 'Ask your admin to add one in Project Settings.',
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
return isAdmin
|
|
117
|
+
? {
|
|
118
|
+
title: `Code platform connection ${error.reason}.`,
|
|
119
|
+
body: "Check the project's connection in settings.",
|
|
120
|
+
ctaUrl,
|
|
121
|
+
}
|
|
122
|
+
: {
|
|
123
|
+
title: 'This project needs a code platform connection.',
|
|
124
|
+
body: 'Ask your admin — the existing connection is not usable.',
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
// ── reason: 'missing' ─────────────────────────────────────────
|
|
71
128
|
if (error.reason === 'missing') {
|
|
72
129
|
return isAdmin
|
|
73
130
|
? {
|
|
74
|
-
title:
|
|
75
|
-
body:
|
|
131
|
+
title: `Connect ${label} to run this pipeline.`,
|
|
132
|
+
body: `This project needs a ${label} connection to clone its repos.`,
|
|
76
133
|
ctaUrl,
|
|
77
134
|
}
|
|
78
135
|
: {
|
|
79
|
-
title:
|
|
136
|
+
title: `This project needs a ${label} connection.`,
|
|
80
137
|
body: 'Ask your admin to add one in Project Settings.',
|
|
81
138
|
};
|
|
82
139
|
}
|
|
140
|
+
// ── reason: 'revoked' | 'uninstalled' | 'suspended' ───────────
|
|
83
141
|
if (error.reason === 'revoked' ||
|
|
84
142
|
error.reason === 'uninstalled' ||
|
|
85
143
|
error.reason === 'suspended') {
|
|
86
144
|
return isAdmin
|
|
87
145
|
? {
|
|
88
|
-
title:
|
|
89
|
-
body:
|
|
146
|
+
title: `${label} connection ${error.reason}.`,
|
|
147
|
+
body: `New pipeline steps that need ${label} will fail until the project is bound to a different connection.`,
|
|
90
148
|
ctaUrl,
|
|
91
149
|
}
|
|
92
150
|
: {
|
|
93
|
-
title:
|
|
151
|
+
title: `This project needs a ${label} connection.`,
|
|
94
152
|
body: 'Ask your admin — the existing connection is not usable.',
|
|
95
153
|
};
|
|
96
154
|
}
|
|
97
155
|
return {
|
|
98
|
-
title:
|
|
156
|
+
title: `${label} connection is unavailable.`,
|
|
99
157
|
body: '',
|
|
100
158
|
};
|
|
101
159
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connectionErrorCopy.js","sourceRoot":"","sources":["../src/connectionErrorCopy.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"connectionErrorCopy.js","sourceRoot":"","sources":["../src/connectionErrorCopy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `fazemos dispatch` — write an inbox file for a role and notify any
|
|
3
|
+
* configured human-filled recipient via the API.
|
|
4
|
+
*
|
|
5
|
+
* Data flow:
|
|
6
|
+
*
|
|
7
|
+
* CLI invocation
|
|
8
|
+
* ↓ resolve recipient via .fazemos/roles.json
|
|
9
|
+
* ↓ generate frontmatter + body markdown
|
|
10
|
+
* ↓ write file at <recipient.inbox>/<timestamp>-<from>-<slug>.md
|
|
11
|
+
* ↓ POST /api/notifications/dispatch (summary + notification config)
|
|
12
|
+
* ↓ API gates on filler.type === 'human' + notification configured
|
|
13
|
+
* ↓ API fans out (Slack today)
|
|
14
|
+
*
|
|
15
|
+
* Workspaces have `.fazemos/roles.json` registries. The CLI walks up from
|
|
16
|
+
* cwd to find the local registry, then can hop to other workspaces via
|
|
17
|
+
* the `cross_workspace_roles` block.
|
|
18
|
+
*/
|
|
19
|
+
export interface RoleNotification {
|
|
20
|
+
channel: 'slack';
|
|
21
|
+
secret_key: string;
|
|
22
|
+
}
|
|
23
|
+
export interface RoleEntry {
|
|
24
|
+
filler: {
|
|
25
|
+
type: 'human' | 'agent';
|
|
26
|
+
identity: string;
|
|
27
|
+
};
|
|
28
|
+
subagent: string | null;
|
|
29
|
+
inbox: string;
|
|
30
|
+
briefs: string;
|
|
31
|
+
persona: string;
|
|
32
|
+
notification?: RoleNotification;
|
|
33
|
+
scope: 'org' | 'project';
|
|
34
|
+
}
|
|
35
|
+
export interface CrossWorkspaceRef {
|
|
36
|
+
workspace_path: string;
|
|
37
|
+
registry_path: string;
|
|
38
|
+
}
|
|
39
|
+
export interface RolesRegistry {
|
|
40
|
+
workspace: string;
|
|
41
|
+
org: string;
|
|
42
|
+
project?: string;
|
|
43
|
+
roles: Record<string, RoleEntry>;
|
|
44
|
+
cross_workspace_roles?: Record<string, CrossWorkspaceRef>;
|
|
45
|
+
_workspaceRoot: string;
|
|
46
|
+
_registryPath: string;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Walk up from `startDir` looking for a `.fazemos/roles.json`. Returns the
|
|
50
|
+
* loaded registry or null if not found within ~10 levels.
|
|
51
|
+
*/
|
|
52
|
+
export declare function findLocalRegistry(startDir: string): RolesRegistry | null;
|
|
53
|
+
/**
|
|
54
|
+
* Load a registry from an explicit workspace path (used when following
|
|
55
|
+
* `cross_workspace_roles` references).
|
|
56
|
+
*/
|
|
57
|
+
export declare function loadRegistryAt(workspacePath: string): RolesRegistry | null;
|
|
58
|
+
/**
|
|
59
|
+
* Find a role by slug. Looks in the local registry first; falls back to
|
|
60
|
+
* the cross-workspace references if not found locally. Returns the role
|
|
61
|
+
* entry together with the registry it was resolved from (so callers know
|
|
62
|
+
* which workspace to write into).
|
|
63
|
+
*/
|
|
64
|
+
export declare function resolveRole(slug: string, localRegistry: RolesRegistry): {
|
|
65
|
+
role: RoleEntry;
|
|
66
|
+
registry: RolesRegistry;
|
|
67
|
+
} | null;
|
|
68
|
+
export interface DispatchInput {
|
|
69
|
+
to: string;
|
|
70
|
+
from: string;
|
|
71
|
+
type: 'question' | 'task' | 'signal' | 'response' | 'flag' | 'decision' | 'direction';
|
|
72
|
+
priority?: 'low' | 'normal' | 'high';
|
|
73
|
+
body: string;
|
|
74
|
+
re?: string;
|
|
75
|
+
thread?: string;
|
|
76
|
+
expiresAt?: string;
|
|
77
|
+
}
|
|
78
|
+
export declare function buildInboxFile(input: DispatchInput): {
|
|
79
|
+
filename: string;
|
|
80
|
+
content: string;
|
|
81
|
+
summary: string;
|
|
82
|
+
};
|
|
83
|
+
export declare function writeInboxFile(workspaceRoot: string, role: RoleEntry, fileName: string, content: string): string;
|
|
84
|
+
export interface NotificationPayload {
|
|
85
|
+
to_role: string;
|
|
86
|
+
to_filler_type: 'human' | 'agent';
|
|
87
|
+
notification?: RoleNotification;
|
|
88
|
+
from_role: string;
|
|
89
|
+
type: string;
|
|
90
|
+
priority: 'low' | 'normal' | 'high';
|
|
91
|
+
summary: string;
|
|
92
|
+
ref?: string;
|
|
93
|
+
source: 'cli';
|
|
94
|
+
}
|
|
95
|
+
export declare function buildNotificationPayload(input: DispatchInput, role: RoleEntry, fileRef: string, summary: string): NotificationPayload;
|
|
96
|
+
export declare function gitCommitInboxFile(workspaceRoot: string, relativePath: string, message: string): void;
|
package/dist/dispatch.js
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `fazemos dispatch` — write an inbox file for a role and notify any
|
|
3
|
+
* configured human-filled recipient via the API.
|
|
4
|
+
*
|
|
5
|
+
* Data flow:
|
|
6
|
+
*
|
|
7
|
+
* CLI invocation
|
|
8
|
+
* ↓ resolve recipient via .fazemos/roles.json
|
|
9
|
+
* ↓ generate frontmatter + body markdown
|
|
10
|
+
* ↓ write file at <recipient.inbox>/<timestamp>-<from>-<slug>.md
|
|
11
|
+
* ↓ POST /api/notifications/dispatch (summary + notification config)
|
|
12
|
+
* ↓ API gates on filler.type === 'human' + notification configured
|
|
13
|
+
* ↓ API fans out (Slack today)
|
|
14
|
+
*
|
|
15
|
+
* Workspaces have `.fazemos/roles.json` registries. The CLI walks up from
|
|
16
|
+
* cwd to find the local registry, then can hop to other workspaces via
|
|
17
|
+
* the `cross_workspace_roles` block.
|
|
18
|
+
*/
|
|
19
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
|
20
|
+
import { dirname, join, resolve as resolvePath } from 'path';
|
|
21
|
+
import { homedir } from 'os';
|
|
22
|
+
import { execSync } from 'child_process';
|
|
23
|
+
// ── Registry loading ────────────────────────────────────────────
|
|
24
|
+
/**
|
|
25
|
+
* Walk up from `startDir` looking for a `.fazemos/roles.json`. Returns the
|
|
26
|
+
* loaded registry or null if not found within ~10 levels.
|
|
27
|
+
*/
|
|
28
|
+
export function findLocalRegistry(startDir) {
|
|
29
|
+
let dir = resolvePath(startDir);
|
|
30
|
+
for (let i = 0; i < 10; i++) {
|
|
31
|
+
const candidate = join(dir, '.fazemos', 'roles.json');
|
|
32
|
+
if (existsSync(candidate)) {
|
|
33
|
+
const raw = JSON.parse(readFileSync(candidate, 'utf-8'));
|
|
34
|
+
return {
|
|
35
|
+
...raw,
|
|
36
|
+
_workspaceRoot: dir,
|
|
37
|
+
_registryPath: candidate,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
const parent = dirname(dir);
|
|
41
|
+
if (parent === dir)
|
|
42
|
+
break;
|
|
43
|
+
dir = parent;
|
|
44
|
+
}
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Load a registry from an explicit workspace path (used when following
|
|
49
|
+
* `cross_workspace_roles` references).
|
|
50
|
+
*/
|
|
51
|
+
export function loadRegistryAt(workspacePath) {
|
|
52
|
+
const expanded = workspacePath.startsWith('~')
|
|
53
|
+
? join(homedir(), workspacePath.slice(1).replace(/^\/+/, ''))
|
|
54
|
+
: workspacePath;
|
|
55
|
+
const candidate = join(expanded, '.fazemos', 'roles.json');
|
|
56
|
+
if (!existsSync(candidate))
|
|
57
|
+
return null;
|
|
58
|
+
const raw = JSON.parse(readFileSync(candidate, 'utf-8'));
|
|
59
|
+
return {
|
|
60
|
+
...raw,
|
|
61
|
+
_workspaceRoot: expanded,
|
|
62
|
+
_registryPath: candidate,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Find a role by slug. Looks in the local registry first; falls back to
|
|
67
|
+
* the cross-workspace references if not found locally. Returns the role
|
|
68
|
+
* entry together with the registry it was resolved from (so callers know
|
|
69
|
+
* which workspace to write into).
|
|
70
|
+
*/
|
|
71
|
+
export function resolveRole(slug, localRegistry) {
|
|
72
|
+
// 1. Local registry
|
|
73
|
+
if (localRegistry.roles[slug]) {
|
|
74
|
+
return { role: localRegistry.roles[slug], registry: localRegistry };
|
|
75
|
+
}
|
|
76
|
+
// 2. Cross-workspace hop
|
|
77
|
+
const xref = localRegistry.cross_workspace_roles?.[slug];
|
|
78
|
+
if (xref) {
|
|
79
|
+
const remote = loadRegistryAt(xref.workspace_path);
|
|
80
|
+
if (remote && remote.roles[slug]) {
|
|
81
|
+
return { role: remote.roles[slug], registry: remote };
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
function slugify(s) {
|
|
87
|
+
return s
|
|
88
|
+
.toLowerCase()
|
|
89
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
90
|
+
.replace(/^-+|-+$/g, '')
|
|
91
|
+
.slice(0, 50);
|
|
92
|
+
}
|
|
93
|
+
function nowParts() {
|
|
94
|
+
// UTC throughout: inbox filenames embed the date+time, and the
|
|
95
|
+
// canonical id includes the filename. Using local time made files
|
|
96
|
+
// inconsistent across timezones — a 2026-05-23T01:52Z dispatch run
|
|
97
|
+
// in MDT would render as 2026-05-22-1952 but the same dispatch from
|
|
98
|
+
// a UTC host would render as 2026-05-23-0152. Pin to UTC so the
|
|
99
|
+
// filename matches the iso timestamp.
|
|
100
|
+
const d = new Date();
|
|
101
|
+
const yyyy = d.getUTCFullYear();
|
|
102
|
+
const mm = String(d.getUTCMonth() + 1).padStart(2, '0');
|
|
103
|
+
const dd = String(d.getUTCDate()).padStart(2, '0');
|
|
104
|
+
const HH = String(d.getUTCHours()).padStart(2, '0');
|
|
105
|
+
const MM = String(d.getUTCMinutes()).padStart(2, '0');
|
|
106
|
+
return {
|
|
107
|
+
iso: d.toISOString(),
|
|
108
|
+
filename: `${yyyy}-${mm}-${dd}-${HH}${MM}`,
|
|
109
|
+
date: `${yyyy}-${mm}-${dd}`,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
export function buildInboxFile(input) {
|
|
113
|
+
const { filename, iso } = nowParts();
|
|
114
|
+
const slug = slugify(input.body.split('\n')[0] || input.type);
|
|
115
|
+
const id = `${filename}-${input.from}-${slug}`;
|
|
116
|
+
const fileName = `${id}.md`;
|
|
117
|
+
const fm = ['---'];
|
|
118
|
+
fm.push(`id: ${id}`);
|
|
119
|
+
fm.push(`type: ${input.type}`);
|
|
120
|
+
fm.push(`from: ${input.from}`);
|
|
121
|
+
fm.push(`to: ${input.to}`);
|
|
122
|
+
fm.push(`priority: ${input.priority ?? 'normal'}`);
|
|
123
|
+
fm.push(`created_at: ${iso}`);
|
|
124
|
+
if (input.re)
|
|
125
|
+
fm.push(`re: ${input.re}`);
|
|
126
|
+
if (input.thread)
|
|
127
|
+
fm.push(`thread: ${input.thread}`);
|
|
128
|
+
if (input.expiresAt)
|
|
129
|
+
fm.push(`expires_at: ${input.expiresAt}`);
|
|
130
|
+
fm.push('source: cli');
|
|
131
|
+
fm.push('---');
|
|
132
|
+
const content = `${fm.join('\n')}\n\n${input.body}\n`;
|
|
133
|
+
const summary = input.body.split('\n')[0].slice(0, 200);
|
|
134
|
+
return { filename: fileName, content, summary };
|
|
135
|
+
}
|
|
136
|
+
export function writeInboxFile(workspaceRoot, role, fileName, content) {
|
|
137
|
+
const inboxDir = join(workspaceRoot, role.inbox);
|
|
138
|
+
if (!existsSync(inboxDir)) {
|
|
139
|
+
mkdirSync(inboxDir, { recursive: true });
|
|
140
|
+
}
|
|
141
|
+
const fullPath = join(inboxDir, fileName);
|
|
142
|
+
writeFileSync(fullPath, content, 'utf-8');
|
|
143
|
+
return fullPath;
|
|
144
|
+
}
|
|
145
|
+
export function buildNotificationPayload(input, role, fileRef, summary) {
|
|
146
|
+
return {
|
|
147
|
+
to_role: input.to,
|
|
148
|
+
to_filler_type: role.filler.type,
|
|
149
|
+
notification: role.notification,
|
|
150
|
+
from_role: input.from,
|
|
151
|
+
type: input.type,
|
|
152
|
+
priority: input.priority ?? 'normal',
|
|
153
|
+
summary,
|
|
154
|
+
ref: fileRef,
|
|
155
|
+
source: 'cli',
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
// ── Optional git add + commit ───────────────────────────────────
|
|
159
|
+
export function gitCommitInboxFile(workspaceRoot, relativePath, message) {
|
|
160
|
+
try {
|
|
161
|
+
execSync(`git add "${relativePath}"`, { cwd: workspaceRoot, stdio: 'pipe' });
|
|
162
|
+
execSync(`git commit -m "${message.replace(/"/g, '\\"')}"`, { cwd: workspaceRoot, stdio: 'pipe' });
|
|
163
|
+
}
|
|
164
|
+
catch (err) {
|
|
165
|
+
// Bubble up so caller can decide whether to surface or ignore
|
|
166
|
+
throw new Error(`git commit failed in ${workspaceRoot}: ${err instanceof Error ? err.message : String(err)}`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
//# sourceMappingURL=dispatch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dispatch.js","sourceRoot":"","sources":["../src/dispatch.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,45 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from 'commander';
|
|
3
3
|
declare const program: Command;
|
|
4
|
+
/**
|
|
5
|
+
* F22 — Normalize a Connection row from the API into a shape the CLI
|
|
6
|
+
* commands can render. The backend serializes the new
|
|
7
|
+
* `serializeVcsConnection` shape with snake_case fields (provider,
|
|
8
|
+
* account_login, supports_contents_api, last_health_check_at, ...) per
|
|
9
|
+
* backend handoff notes. F16 callers historically read camelCase
|
|
10
|
+
* (githubAccountLogin, lastHealthCheckAt, installedAt, ...). During the
|
|
11
|
+
* dual-write rollout BOTH shapes can appear; this helper picks the
|
|
12
|
+
* first defined value.
|
|
13
|
+
*
|
|
14
|
+
* Exported so unit tests can assert the mapping without spinning up
|
|
15
|
+
* the full CLI.
|
|
16
|
+
*/
|
|
17
|
+
export interface NormalizedConnection {
|
|
18
|
+
id: string;
|
|
19
|
+
provider: 'github' | 'bitbucket' | string | null;
|
|
20
|
+
name: string | null;
|
|
21
|
+
accountLogin: string | null;
|
|
22
|
+
accountType: string | null;
|
|
23
|
+
status: string;
|
|
24
|
+
installedAt: string | null;
|
|
25
|
+
lastHealthCheckAt: string | null;
|
|
26
|
+
lastUsedAt: string | null;
|
|
27
|
+
supportsContentsApi: boolean | null;
|
|
28
|
+
projectCount: number | null;
|
|
29
|
+
}
|
|
30
|
+
export declare function normalizeConnection(raw: any): NormalizedConnection;
|
|
31
|
+
/**
|
|
32
|
+
* F22 — Human-friendly provider label used in CLI columns and lines.
|
|
33
|
+
*/
|
|
34
|
+
export declare function formatProviderLabel(provider: string | null | undefined): string;
|
|
35
|
+
/**
|
|
36
|
+
* F22 §8.3 item 3 — interactive provider picker. Used by
|
|
37
|
+
* `fazemos connections install` when no `--provider` flag is supplied
|
|
38
|
+
* so the user explicitly chooses GitHub or BitBucket before the URL
|
|
39
|
+
* mint hits the API. Mirrors the web `ProviderPickerModal` choice
|
|
40
|
+
* without the modal chrome.
|
|
41
|
+
*
|
|
42
|
+
* Returns 'github' or 'bitbucket'. Repeats on invalid input.
|
|
43
|
+
*/
|
|
44
|
+
export declare function promptProviderChoice(): Promise<'github' | 'bitbucket'>;
|
|
4
45
|
export { program };
|