mcoda 0.1.38 → 0.1.41

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.
@@ -0,0 +1,170 @@
1
+ import packageJson from '../../../package.json' with { type: 'json' };
2
+ import { MswarmConfigStore, } from '@mcoda/core';
3
+ import { acceptMswarmConsent, buildMswarmApi, } from './MswarmConsentFlow.js';
4
+ const USAGE = `
5
+ Usage: mcoda consent <show|accept|revoke|request-deletion> [options]
6
+
7
+ Subcommands:
8
+ show Display the persisted mswarm consent state
9
+ accept Register/refresh consent with mswarm and persist the local client identity
10
+ revoke Revoke the currently stored mswarm consent token
11
+ request-deletion Submit a data deletion request to mswarm for this client identity
12
+
13
+ Options:
14
+ --policy-version <VER> Override the consent policy version for \`accept\`
15
+ --reason <TEXT> Attach a reason to \`revoke\` or \`request-deletion\`
16
+ --json Emit JSON output
17
+ --help Show this help
18
+ `.trim();
19
+ export class ConsentCommands {
20
+ static async run(argv) {
21
+ const parsed = parseConsentArgs(argv);
22
+ if (!parsed.subcommand || argv.includes('--help') || argv.includes('-h')) {
23
+ // eslint-disable-next-line no-console
24
+ console.log(USAGE);
25
+ return;
26
+ }
27
+ const store = new MswarmConfigStore();
28
+ const state = await store.readState();
29
+ if (parsed.subcommand === 'show') {
30
+ render(parsed.json, {
31
+ consentAccepted: Boolean(state.consentAccepted),
32
+ consentTokenSet: Boolean(state.consentToken?.trim()),
33
+ clientId: state.clientId,
34
+ clientType: state.clientType,
35
+ policyVersion: state.consentPolicyVersion,
36
+ apiKeySet: Boolean(state.apiKey?.trim()),
37
+ baseUrl: state.baseUrl,
38
+ uploadSigningSecretSet: Boolean(state.uploadSigningSecret?.trim()),
39
+ deletionRequestedAtMs: state.deletionRequestedAtMs,
40
+ });
41
+ return;
42
+ }
43
+ if (parsed.subcommand === 'accept') {
44
+ const nextState = await acceptMswarmConsent({
45
+ state,
46
+ policyVersion: parsed.policyVersion,
47
+ productVersion: String(packageJson.version ?? 'dev'),
48
+ });
49
+ render(parsed.json, {
50
+ consentAccepted: Boolean(nextState.consentAccepted),
51
+ consentTokenSet: Boolean(nextState.consentToken?.trim()),
52
+ clientId: nextState.clientId,
53
+ clientType: nextState.clientType,
54
+ policyVersion: nextState.consentPolicyVersion,
55
+ apiKeySet: Boolean(nextState.apiKey?.trim()),
56
+ baseUrl: nextState.baseUrl,
57
+ uploadSigningSecretSet: Boolean(nextState.uploadSigningSecret?.trim()),
58
+ deletionRequestedAtMs: nextState.deletionRequestedAtMs,
59
+ });
60
+ return;
61
+ }
62
+ if (parsed.subcommand === 'revoke') {
63
+ const consentToken = state.consentToken?.trim();
64
+ if (!consentToken) {
65
+ throw new Error('No persisted mswarm consent token is available. Run `mcoda consent accept` first.');
66
+ }
67
+ const api = await buildMswarmApi(state);
68
+ try {
69
+ const response = await api.revokeConsent(consentToken, parsed.reason);
70
+ await store.clearConsentState();
71
+ render(parsed.json, {
72
+ revoked: response.revoked,
73
+ revokedAtMs: response.revoked_at_ms ?? null,
74
+ });
75
+ }
76
+ finally {
77
+ await api.close();
78
+ }
79
+ return;
80
+ }
81
+ if (parsed.subcommand === 'request-deletion') {
82
+ const consentToken = state.consentToken?.trim();
83
+ if (!consentToken) {
84
+ throw new Error('No persisted mswarm consent token is available. Run `mcoda consent accept` first.');
85
+ }
86
+ const api = await buildMswarmApi(state);
87
+ try {
88
+ const response = await api.requestDataDeletion({
89
+ consentToken,
90
+ product: 'mcoda',
91
+ clientId: state.apiKey?.trim() ? undefined : state.clientId,
92
+ clientType: state.apiKey?.trim() ? undefined : state.clientType,
93
+ reason: parsed.reason,
94
+ });
95
+ const deletionRequestedAtMs = Date.now();
96
+ await store.saveConsentState({
97
+ consentAccepted: Boolean(state.consentAccepted),
98
+ consentPolicyVersion: state.consentPolicyVersion,
99
+ consentToken: state.consentToken,
100
+ clientId: state.clientId,
101
+ clientType: state.clientType,
102
+ registeredAtMs: state.registeredAtMs,
103
+ uploadSigningSecret: state.uploadSigningSecret,
104
+ deletionRequestedAtMs,
105
+ });
106
+ render(parsed.json, {
107
+ accepted: response.accepted,
108
+ requestId: response.request_id,
109
+ product: response.product,
110
+ clientId: response.client_id,
111
+ clientType: response.client_type,
112
+ tenantId: response.tenant_id,
113
+ status: response.status,
114
+ requestedAt: response.requested_at,
115
+ deletionRequestedAtMs,
116
+ });
117
+ }
118
+ finally {
119
+ await api.close();
120
+ }
121
+ return;
122
+ }
123
+ throw new Error(`Unknown consent subcommand: ${parsed.subcommand}`);
124
+ }
125
+ }
126
+ export function parseConsentArgs(argv) {
127
+ const parsed = { json: false };
128
+ const positionals = [];
129
+ for (let index = 0; index < argv.length; index += 1) {
130
+ const value = argv[index];
131
+ if (value === '--json') {
132
+ parsed.json = true;
133
+ continue;
134
+ }
135
+ if (value === '--policy-version') {
136
+ const next = argv[index + 1];
137
+ if (!next?.trim()) {
138
+ throw new Error('--policy-version requires a value');
139
+ }
140
+ parsed.policyVersion = next.trim();
141
+ index += 1;
142
+ continue;
143
+ }
144
+ if (value === '--reason') {
145
+ const next = argv[index + 1];
146
+ if (!next?.trim()) {
147
+ throw new Error('--reason requires a value');
148
+ }
149
+ parsed.reason = next.trim();
150
+ index += 1;
151
+ continue;
152
+ }
153
+ if (value.startsWith('--')) {
154
+ throw new Error(`Unknown consent flag: ${value}`);
155
+ }
156
+ positionals.push(value);
157
+ }
158
+ parsed.subcommand = positionals[0];
159
+ return parsed;
160
+ }
161
+ function render(json, payload) {
162
+ if (json) {
163
+ // eslint-disable-next-line no-console
164
+ console.log(JSON.stringify(payload, null, 2));
165
+ return;
166
+ }
167
+ const fragments = Object.entries(payload).map(([key, value]) => `${key}=${String(value)}`);
168
+ // eslint-disable-next-line no-console
169
+ console.log(fragments.join(' '));
170
+ }
@@ -0,0 +1,10 @@
1
+ import { MswarmApi, MswarmConfigStore } from '@mcoda/core';
2
+ import { type MswarmConfigState } from '@mcoda/core';
3
+ export declare function acceptMswarmConsent(options?: {
4
+ state?: MswarmConfigState;
5
+ policyVersion?: string;
6
+ productVersion?: string;
7
+ store?: MswarmConfigStore;
8
+ }): Promise<MswarmConfigState>;
9
+ export declare function buildMswarmApi(state: MswarmConfigState): Promise<MswarmApi>;
10
+ //# sourceMappingURL=MswarmConsentFlow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MswarmConsentFlow.d.ts","sourceRoot":"","sources":["../../../src/commands/consent/MswarmConsentFlow.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,EAGL,KAAK,iBAAiB,EACvB,MAAM,aAAa,CAAC;AAErB,wBAAsB,mBAAmB,CAAC,OAAO,GAAE;IACjD,KAAK,CAAC,EAAE,iBAAiB,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,KAAK,CAAC,EAAE,iBAAiB,CAAC;CACtB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAiDlC;AAED,wBAAsB,cAAc,CAClC,KAAK,EAAE,iBAAiB,GACvB,OAAO,CAAC,SAAS,CAAC,CAOpB"}
@@ -0,0 +1,57 @@
1
+ import { MswarmApi, MswarmConfigStore } from '@mcoda/core';
2
+ import { MCODA_FREE_CLIENT_TYPE, MSWARM_CONSENT_POLICY_VERSION, } from '@mcoda/core';
3
+ export async function acceptMswarmConsent(options = {}) {
4
+ const store = options.store ?? new MswarmConfigStore();
5
+ const state = options.state ?? (await store.readState());
6
+ const api = await buildMswarmApi(state);
7
+ try {
8
+ const effectivePolicyVersion = options.policyVersion?.trim() ||
9
+ state.consentPolicyVersion ||
10
+ MSWARM_CONSENT_POLICY_VERSION;
11
+ if (state.apiKey?.trim()) {
12
+ const response = await api.issuePaidConsent(effectivePolicyVersion);
13
+ const clientId = response.client_id || response.tenant_id || state.clientId;
14
+ const clientType = response.client_type || 'paid_mcoda_client';
15
+ return store.saveConsentState({
16
+ consentAccepted: true,
17
+ consentPolicyVersion: effectivePolicyVersion,
18
+ consentToken: response.consent_token,
19
+ clientId,
20
+ clientType,
21
+ registeredAtMs: response.issued_at_ms ?? Date.now(),
22
+ uploadSigningSecret: response.upload_signing_secret,
23
+ deletionRequestedAtMs: state.deletionRequestedAtMs,
24
+ });
25
+ }
26
+ const response = await api.registerFreeMcodaClient({
27
+ clientId: state.clientId,
28
+ policyVersion: effectivePolicyVersion,
29
+ productVersion: options.productVersion?.trim() || 'dev',
30
+ });
31
+ const clientId = response.client_id || state.clientId;
32
+ if (!clientId) {
33
+ throw new Error('mswarm free-client registration did not return a client id');
34
+ }
35
+ return store.saveConsentState({
36
+ consentAccepted: true,
37
+ consentPolicyVersion: effectivePolicyVersion,
38
+ consentToken: response.consent_token,
39
+ clientId,
40
+ clientType: response.client_type || MCODA_FREE_CLIENT_TYPE,
41
+ registeredAtMs: response.issued_at_ms ?? Date.now(),
42
+ uploadSigningSecret: response.upload_signing_secret,
43
+ deletionRequestedAtMs: state.deletionRequestedAtMs,
44
+ });
45
+ }
46
+ finally {
47
+ await api.close();
48
+ }
49
+ }
50
+ export async function buildMswarmApi(state) {
51
+ return MswarmApi.create({
52
+ baseUrl: state.baseUrl,
53
+ apiKey: state.apiKey,
54
+ timeoutMs: state.timeoutMs,
55
+ agentSlugPrefix: state.agentSlugPrefix,
56
+ });
57
+ }
@@ -0,0 +1,10 @@
1
+ type ParsedSetupArgs = {
2
+ json: boolean;
3
+ policyVersion?: string;
4
+ };
5
+ export declare class SetupCommand {
6
+ static run(argv: string[]): Promise<void>;
7
+ }
8
+ export declare function parseSetupArgs(argv: string[]): ParsedSetupArgs;
9
+ export {};
10
+ //# sourceMappingURL=SetupCommand.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SetupCommand.d.ts","sourceRoot":"","sources":["../../../src/commands/setup/SetupCommand.ts"],"names":[],"mappings":"AAaA,KAAK,eAAe,GAAG;IACrB,IAAI,EAAE,OAAO,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,qBAAa,YAAY;WACV,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAgChD;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,eAAe,CA0B9D"}
@@ -0,0 +1,78 @@
1
+ import { runMswarmConsentBootstrap } from '../../install/MswarmConsentBootstrap.js';
2
+ const USAGE = `
3
+ Usage: mcoda setup [options]
4
+
5
+ Runs the interactive mcoda setup flow for mandatory mswarm telemetry consent.
6
+
7
+ Options:
8
+ --policy-version <VER> Override the consent policy version
9
+ --json Emit JSON output
10
+ --help Show this help
11
+ `.trim();
12
+ export class SetupCommand {
13
+ static async run(argv) {
14
+ const parsed = parseSetupArgs(argv);
15
+ if (argv.includes('--help') || argv.includes('-h')) {
16
+ // eslint-disable-next-line no-console
17
+ console.log(USAGE);
18
+ return;
19
+ }
20
+ const result = await runMswarmConsentBootstrap({
21
+ mode: 'setup',
22
+ onDeferred: 'error',
23
+ policyVersion: parsed.policyVersion,
24
+ logger: parsed.json ? defaultErrorLogger : defaultLogger,
25
+ });
26
+ if (parsed.json) {
27
+ // eslint-disable-next-line no-console
28
+ console.log(JSON.stringify(result, null, 2));
29
+ return;
30
+ }
31
+ // eslint-disable-next-line no-console
32
+ console.log([
33
+ `status=${result.status}`,
34
+ `consentAccepted=${String(result.consentAccepted)}`,
35
+ `consentTokenSet=${String(result.consentTokenSet)}`,
36
+ result.clientId ? `clientId=${result.clientId}` : undefined,
37
+ result.clientType ? `clientType=${result.clientType}` : undefined,
38
+ result.policyVersion ? `policyVersion=${result.policyVersion}` : undefined,
39
+ ]
40
+ .filter(Boolean)
41
+ .join(' '));
42
+ }
43
+ }
44
+ export function parseSetupArgs(argv) {
45
+ const parsed = { json: false };
46
+ for (let index = 0; index < argv.length; index += 1) {
47
+ const value = argv[index];
48
+ if (value === '--json') {
49
+ parsed.json = true;
50
+ continue;
51
+ }
52
+ if (value === '--policy-version') {
53
+ const next = argv[index + 1];
54
+ if (!next?.trim()) {
55
+ throw new Error('--policy-version requires a value');
56
+ }
57
+ parsed.policyVersion = next.trim();
58
+ index += 1;
59
+ continue;
60
+ }
61
+ if (value === '--help' || value === '-h') {
62
+ continue;
63
+ }
64
+ if (value.startsWith('--')) {
65
+ throw new Error(`Unknown setup flag: ${value}`);
66
+ }
67
+ throw new Error(`Unknown setup argument: ${value}`);
68
+ }
69
+ return parsed;
70
+ }
71
+ function defaultLogger(line) {
72
+ // eslint-disable-next-line no-console
73
+ console.log(line);
74
+ }
75
+ function defaultErrorLogger(line) {
76
+ // eslint-disable-next-line no-console
77
+ console.error(line);
78
+ }
package/dist/index.d.ts CHANGED
@@ -1,25 +1,27 @@
1
- export * from "./commands/agents/AgentsCommands.js";
2
- export * from "./bin/McodaEntrypoint.js";
3
- export * from "./commands/cloud/CloudCommands.js";
4
- export * from "./commands/config/ConfigCommands.js";
5
- export * from "./commands/docs/DocsCommands.js";
6
- export * from "./commands/jobs/JobsCommands.js";
7
- export * from "./commands/openapi/OpenapiCommands.js";
8
- export * from "./commands/planning/CreateTasksCommand.js";
9
- export * from "./commands/backlog/BacklogCommands.js";
10
- export * from "./commands/backlog/TaskShowCommands.js";
11
- export * from "./commands/backlog/OrderTasksCommand.js";
12
- export * from "./commands/estimate/EstimateCommands.js";
13
- export * from "./commands/telemetry/TelemetryCommands.js";
14
- export * from "./commands/planning/RefineTasksCommand.js";
15
- export * from "./commands/planning/TaskSufficiencyAuditCommand.js";
16
- export * from "./commands/planning/SdsPreflightCommand.js";
17
- export * from "./commands/work/WorkOnTasksCommand.js";
18
- export * from "./commands/work/GatewayTrioCommand.js";
19
- export * from "./commands/review/CodeReviewCommand.js";
20
- export * from "./commands/planning/QaTasksCommand.js";
21
- export * from "./commands/update/UpdateCommands.js";
22
- export * from "./commands/routing/RoutingCommands.js";
23
- export * from "./commands/agents/TestAgentCommand.js";
24
- export * from "./commands/workspace/ProjectGuidanceCommand.js";
1
+ export * from './commands/agents/AgentsCommands.js';
2
+ export * from './bin/McodaEntrypoint.js';
3
+ export * from './commands/cloud/CloudCommands.js';
4
+ export * from './commands/config/ConfigCommands.js';
5
+ export * from './commands/consent/ConsentCommands.js';
6
+ export * from './commands/docs/DocsCommands.js';
7
+ export * from './commands/jobs/JobsCommands.js';
8
+ export * from './commands/openapi/OpenapiCommands.js';
9
+ export * from './commands/planning/CreateTasksCommand.js';
10
+ export * from './commands/backlog/BacklogCommands.js';
11
+ export * from './commands/backlog/TaskShowCommands.js';
12
+ export * from './commands/backlog/OrderTasksCommand.js';
13
+ export * from './commands/estimate/EstimateCommands.js';
14
+ export * from './commands/telemetry/TelemetryCommands.js';
15
+ export * from './commands/planning/RefineTasksCommand.js';
16
+ export * from './commands/planning/TaskSufficiencyAuditCommand.js';
17
+ export * from './commands/planning/SdsPreflightCommand.js';
18
+ export * from './commands/work/WorkOnTasksCommand.js';
19
+ export * from './commands/work/GatewayTrioCommand.js';
20
+ export * from './commands/review/CodeReviewCommand.js';
21
+ export * from './commands/planning/QaTasksCommand.js';
22
+ export * from './commands/update/UpdateCommands.js';
23
+ export * from './commands/routing/RoutingCommands.js';
24
+ export * from './commands/setup/SetupCommand.js';
25
+ export * from './commands/agents/TestAgentCommand.js';
26
+ export * from './commands/workspace/ProjectGuidanceCommand.js';
25
27
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,qCAAqC,CAAC;AACpD,cAAc,0BAA0B,CAAC;AACzC,cAAc,mCAAmC,CAAC;AAClD,cAAc,qCAAqC,CAAC;AACpD,cAAc,iCAAiC,CAAC;AAChD,cAAc,iCAAiC,CAAC;AAChD,cAAc,uCAAuC,CAAC;AACtD,cAAc,2CAA2C,CAAC;AAC1D,cAAc,uCAAuC,CAAC;AACtD,cAAc,wCAAwC,CAAC;AACvD,cAAc,yCAAyC,CAAC;AACxD,cAAc,yCAAyC,CAAC;AACxD,cAAc,2CAA2C,CAAC;AAC1D,cAAc,2CAA2C,CAAC;AAC1D,cAAc,oDAAoD,CAAC;AACnE,cAAc,4CAA4C,CAAC;AAC3D,cAAc,uCAAuC,CAAC;AACtD,cAAc,uCAAuC,CAAC;AACtD,cAAc,wCAAwC,CAAC;AACvD,cAAc,uCAAuC,CAAC;AACtD,cAAc,qCAAqC,CAAC;AACpD,cAAc,uCAAuC,CAAC;AACtD,cAAc,uCAAuC,CAAC;AACtD,cAAc,gDAAgD,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,qCAAqC,CAAC;AACpD,cAAc,0BAA0B,CAAC;AACzC,cAAc,mCAAmC,CAAC;AAClD,cAAc,qCAAqC,CAAC;AACpD,cAAc,uCAAuC,CAAC;AACtD,cAAc,iCAAiC,CAAC;AAChD,cAAc,iCAAiC,CAAC;AAChD,cAAc,uCAAuC,CAAC;AACtD,cAAc,2CAA2C,CAAC;AAC1D,cAAc,uCAAuC,CAAC;AACtD,cAAc,wCAAwC,CAAC;AACvD,cAAc,yCAAyC,CAAC;AACxD,cAAc,yCAAyC,CAAC;AACxD,cAAc,2CAA2C,CAAC;AAC1D,cAAc,2CAA2C,CAAC;AAC1D,cAAc,oDAAoD,CAAC;AACnE,cAAc,4CAA4C,CAAC;AAC3D,cAAc,uCAAuC,CAAC;AACtD,cAAc,uCAAuC,CAAC;AACtD,cAAc,wCAAwC,CAAC;AACvD,cAAc,uCAAuC,CAAC;AACtD,cAAc,qCAAqC,CAAC;AACpD,cAAc,uCAAuC,CAAC;AACtD,cAAc,kCAAkC,CAAC;AACjD,cAAc,uCAAuC,CAAC;AACtD,cAAc,gDAAgD,CAAC"}
package/dist/index.js CHANGED
@@ -1,24 +1,26 @@
1
- export * from "./commands/agents/AgentsCommands.js";
2
- export * from "./bin/McodaEntrypoint.js";
3
- export * from "./commands/cloud/CloudCommands.js";
4
- export * from "./commands/config/ConfigCommands.js";
5
- export * from "./commands/docs/DocsCommands.js";
6
- export * from "./commands/jobs/JobsCommands.js";
7
- export * from "./commands/openapi/OpenapiCommands.js";
8
- export * from "./commands/planning/CreateTasksCommand.js";
9
- export * from "./commands/backlog/BacklogCommands.js";
10
- export * from "./commands/backlog/TaskShowCommands.js";
11
- export * from "./commands/backlog/OrderTasksCommand.js";
12
- export * from "./commands/estimate/EstimateCommands.js";
13
- export * from "./commands/telemetry/TelemetryCommands.js";
14
- export * from "./commands/planning/RefineTasksCommand.js";
15
- export * from "./commands/planning/TaskSufficiencyAuditCommand.js";
16
- export * from "./commands/planning/SdsPreflightCommand.js";
17
- export * from "./commands/work/WorkOnTasksCommand.js";
18
- export * from "./commands/work/GatewayTrioCommand.js";
19
- export * from "./commands/review/CodeReviewCommand.js";
20
- export * from "./commands/planning/QaTasksCommand.js";
21
- export * from "./commands/update/UpdateCommands.js";
22
- export * from "./commands/routing/RoutingCommands.js";
23
- export * from "./commands/agents/TestAgentCommand.js";
24
- export * from "./commands/workspace/ProjectGuidanceCommand.js";
1
+ export * from './commands/agents/AgentsCommands.js';
2
+ export * from './bin/McodaEntrypoint.js';
3
+ export * from './commands/cloud/CloudCommands.js';
4
+ export * from './commands/config/ConfigCommands.js';
5
+ export * from './commands/consent/ConsentCommands.js';
6
+ export * from './commands/docs/DocsCommands.js';
7
+ export * from './commands/jobs/JobsCommands.js';
8
+ export * from './commands/openapi/OpenapiCommands.js';
9
+ export * from './commands/planning/CreateTasksCommand.js';
10
+ export * from './commands/backlog/BacklogCommands.js';
11
+ export * from './commands/backlog/TaskShowCommands.js';
12
+ export * from './commands/backlog/OrderTasksCommand.js';
13
+ export * from './commands/estimate/EstimateCommands.js';
14
+ export * from './commands/telemetry/TelemetryCommands.js';
15
+ export * from './commands/planning/RefineTasksCommand.js';
16
+ export * from './commands/planning/TaskSufficiencyAuditCommand.js';
17
+ export * from './commands/planning/SdsPreflightCommand.js';
18
+ export * from './commands/work/WorkOnTasksCommand.js';
19
+ export * from './commands/work/GatewayTrioCommand.js';
20
+ export * from './commands/review/CodeReviewCommand.js';
21
+ export * from './commands/planning/QaTasksCommand.js';
22
+ export * from './commands/update/UpdateCommands.js';
23
+ export * from './commands/routing/RoutingCommands.js';
24
+ export * from './commands/setup/SetupCommand.js';
25
+ export * from './commands/agents/TestAgentCommand.js';
26
+ export * from './commands/workspace/ProjectGuidanceCommand.js';
@@ -0,0 +1,30 @@
1
+ import { MswarmConfigStore } from '@mcoda/core';
2
+ import { acceptMswarmConsent } from '../commands/consent/MswarmConsentFlow.js';
3
+ export type ConsentBootstrapMode = 'setup' | 'postinstall' | 'install_local';
4
+ export type DeferredBehavior = 'log' | 'error';
5
+ export interface ConsentBootstrapPrompter {
6
+ close(): void;
7
+ question(prompt: string): Promise<string>;
8
+ }
9
+ export interface ConsentBootstrapOptions {
10
+ mode?: ConsentBootstrapMode;
11
+ onDeferred?: DeferredBehavior;
12
+ policyVersion?: string;
13
+ interactive?: boolean;
14
+ logger?: (line: string) => void;
15
+ prompter?: ConsentBootstrapPrompter;
16
+ store?: MswarmConfigStore;
17
+ termsText?: string;
18
+ acceptConsent?: typeof acceptMswarmConsent;
19
+ }
20
+ export interface ConsentBootstrapResult {
21
+ status: 'already_configured' | 'accepted' | 'deferred';
22
+ consentAccepted: boolean;
23
+ consentTokenSet: boolean;
24
+ clientId?: string;
25
+ clientType?: string;
26
+ policyVersion?: string;
27
+ message: string;
28
+ }
29
+ export declare function runMswarmConsentBootstrap(options?: ConsentBootstrapOptions): Promise<ConsentBootstrapResult>;
30
+ //# sourceMappingURL=MswarmConsentBootstrap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MswarmConsentBootstrap.d.ts","sourceRoot":"","sources":["../../src/install/MswarmConsentBootstrap.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0CAA0C,CAAC;AAE/E,MAAM,MAAM,oBAAoB,GAAG,OAAO,GAAG,aAAa,GAAG,eAAe,CAAC;AAC7E,MAAM,MAAM,gBAAgB,GAAG,KAAK,GAAG,OAAO,CAAC;AAE/C,MAAM,WAAW,wBAAwB;IACvC,KAAK,IAAI,IAAI,CAAC;IACd,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAC3C;AAED,MAAM,WAAW,uBAAuB;IACtC,IAAI,CAAC,EAAE,oBAAoB,CAAC;IAC5B,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,QAAQ,CAAC,EAAE,wBAAwB,CAAC;IACpC,KAAK,CAAC,EAAE,iBAAiB,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,OAAO,mBAAmB,CAAC;CAC5C;AAED,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,oBAAoB,GAAG,UAAU,GAAG,UAAU,CAAC;IACvD,eAAe,EAAE,OAAO,CAAC;IACzB,eAAe,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;CACjB;AAID,wBAAsB,yBAAyB,CAC7C,OAAO,GAAE,uBAA4B,GACpC,OAAO,CAAC,sBAAsB,CAAC,CA0FjC"}
@@ -0,0 +1,125 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import readline from 'node:readline/promises';
4
+ import { stdin as input, stdout as output } from 'node:process';
5
+ import { fileURLToPath } from 'node:url';
6
+ import packageJson from '../../package.json' with { type: 'json' };
7
+ import { MswarmConfigStore } from '@mcoda/core';
8
+ import { acceptMswarmConsent } from '../commands/consent/MswarmConsentFlow.js';
9
+ const ACCEPTED_RESPONSES = new Set(['accept', 'accepted', 'yes', 'y']);
10
+ export async function runMswarmConsentBootstrap(options = {}) {
11
+ const logger = options.logger ?? defaultLogger;
12
+ const store = options.store ?? new MswarmConfigStore();
13
+ const state = await store.readState();
14
+ const consentAccepted = Boolean(state.consentAccepted);
15
+ const consentTokenSet = Boolean(state.consentToken?.trim());
16
+ if (consentAccepted && consentTokenSet) {
17
+ return {
18
+ status: 'already_configured',
19
+ consentAccepted,
20
+ consentTokenSet,
21
+ clientId: state.clientId,
22
+ clientType: state.clientType,
23
+ policyVersion: state.consentPolicyVersion,
24
+ message: 'Telemetry consent is already configured for this mcoda client.',
25
+ };
26
+ }
27
+ const interactive = resolveInteractive(options.interactive);
28
+ if (!interactive) {
29
+ const message = 'Telemetry consent is required before using mcoda. Run `mcoda setup` or `mcoda consent accept` in an interactive terminal.';
30
+ if ((options.onDeferred ?? 'error') === 'error') {
31
+ throw new Error(message);
32
+ }
33
+ logger(message);
34
+ return {
35
+ status: 'deferred',
36
+ consentAccepted,
37
+ consentTokenSet,
38
+ clientId: state.clientId,
39
+ clientType: state.clientType,
40
+ policyVersion: state.consentPolicyVersion,
41
+ message,
42
+ };
43
+ }
44
+ logger(`mcoda requires acceptance of the bundled mswarm data collection terms before ${describeMode(options.mode ?? 'setup')}.`);
45
+ logger('');
46
+ const termsText = options.termsText ?? (await readBundledTermsText());
47
+ for (const line of termsText.trim().split(/\r?\n/)) {
48
+ logger(line);
49
+ }
50
+ logger('');
51
+ logger('Type "accept" to agree and continue. Any other response aborts setup.');
52
+ const prompter = options.prompter ??
53
+ readline.createInterface({
54
+ input,
55
+ output,
56
+ });
57
+ try {
58
+ const answer = (await prompter.question('Consent> ')).trim().toLowerCase();
59
+ if (!ACCEPTED_RESPONSES.has(answer)) {
60
+ throw new Error('Telemetry consent was not accepted. mcoda cannot continue.');
61
+ }
62
+ }
63
+ finally {
64
+ prompter.close();
65
+ }
66
+ const acceptConsent = options.acceptConsent ?? acceptMswarmConsent;
67
+ const nextState = await acceptConsent({
68
+ state,
69
+ store,
70
+ policyVersion: options.policyVersion,
71
+ productVersion: String(packageJson.version ?? 'dev'),
72
+ });
73
+ const message = `Telemetry consent accepted for ${[
74
+ nextState.clientType,
75
+ nextState.clientId,
76
+ ]
77
+ .filter((value) => typeof value === 'string' && value.trim().length > 0)
78
+ .join(' ')
79
+ .trim()}.`.replace(/\s+\./, '.');
80
+ logger(message);
81
+ return {
82
+ status: 'accepted',
83
+ consentAccepted: Boolean(nextState.consentAccepted),
84
+ consentTokenSet: Boolean(nextState.consentToken?.trim()),
85
+ clientId: nextState.clientId,
86
+ clientType: nextState.clientType,
87
+ policyVersion: nextState.consentPolicyVersion,
88
+ message,
89
+ };
90
+ }
91
+ async function readBundledTermsText() {
92
+ const termsPath = resolveBundledTermsPath();
93
+ try {
94
+ return await fs.readFile(termsPath, 'utf8');
95
+ }
96
+ catch {
97
+ return [
98
+ 'Mswarm Data Collection Terms And Consent',
99
+ '',
100
+ 'Consent is required to use mcoda.',
101
+ 'By accepting, you allow anonymous or account-bound telemetry upload to mswarm, including consent proof, product activity, and agent rating data as described in the bundled terms document.',
102
+ 'You may later revoke consent or request deletion with `mcoda consent revoke` or `mcoda consent request-deletion`.',
103
+ ].join('\n');
104
+ }
105
+ }
106
+ function resolveBundledTermsPath() {
107
+ return path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..', 'MSWARM_DATA_COLLECTION_TERMS.md');
108
+ }
109
+ function resolveInteractive(explicit) {
110
+ if (explicit !== undefined) {
111
+ return explicit;
112
+ }
113
+ return Boolean(process.stdin.isTTY && process.stdout.isTTY && !process.env.CI);
114
+ }
115
+ function describeMode(mode) {
116
+ if (mode === 'postinstall')
117
+ return 'using the installed mcoda CLI';
118
+ if (mode === 'install_local')
119
+ return 'completing the local mcoda install helper';
120
+ return 'continuing mcoda setup';
121
+ }
122
+ function defaultLogger(line) {
123
+ // eslint-disable-next-line no-console
124
+ console.log(line);
125
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcoda",
3
- "version": "0.1.38",
3
+ "version": "0.1.41",
4
4
  "description": "Local-first CLI for planning, documentation, and execution workflows with agent assistance.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -10,8 +10,10 @@
10
10
  },
11
11
  "files": [
12
12
  "dist",
13
+ "scripts",
13
14
  "!dist/**/__tests__/**",
14
15
  "!dist/**/*.test.*",
16
+ "MSWARM_DATA_COLLECTION_TERMS.md",
15
17
  "README.md",
16
18
  "CHANGELOG.md",
17
19
  "LICENSE"
@@ -45,16 +47,17 @@
45
47
  },
46
48
  "dependencies": {
47
49
  "yaml": "^2.4.2",
48
- "@mcoda/core": "0.1.38",
49
- "@mcoda/shared": "0.1.38"
50
+ "@mcoda/core": "0.1.41",
51
+ "@mcoda/shared": "0.1.41"
50
52
  },
51
53
  "devDependencies": {
52
- "@mcoda/db": "0.1.38",
53
- "@mcoda/integrations": "0.1.38"
54
+ "@mcoda/db": "0.1.41",
55
+ "@mcoda/integrations": "0.1.41"
54
56
  },
55
57
  "scripts": {
56
58
  "build": "tsc -p tsconfig.json",
57
59
  "lint": "echo \"lint not configured\"",
60
+ "postinstall": "node ./scripts/postinstall.js",
58
61
  "test": "pnpm run build && node ../../scripts/run-node-tests.js dist",
59
62
  "pack:verify": "node --test test/packaging_guardrails.test.js"
60
63
  }