codify-plugin-lib 1.0.180 → 1.0.182-beta1

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.
Files changed (44) hide show
  1. package/dist/bin/build.d.ts +1 -0
  2. package/dist/bin/build.js +80 -0
  3. package/dist/bin/deploy-plugin.d.ts +2 -0
  4. package/dist/bin/deploy-plugin.js +8 -0
  5. package/dist/index.d.ts +1 -1
  6. package/dist/index.js +1 -1
  7. package/dist/plugin/plugin.js +5 -2
  8. package/dist/pty/background-pty.d.ts +1 -0
  9. package/dist/pty/background-pty.js +17 -3
  10. package/dist/pty/index.d.ts +17 -1
  11. package/dist/pty/seqeuntial-pty.d.ts +16 -0
  12. package/dist/pty/seqeuntial-pty.js +84 -0
  13. package/dist/resource/parsed-resource-settings.d.ts +3 -1
  14. package/dist/resource/parsed-resource-settings.js +4 -6
  15. package/dist/resource/resource-settings.d.ts +5 -1
  16. package/dist/resource/resource-settings.js +4 -3
  17. package/dist/scripts/deploy.d.ts +1 -0
  18. package/dist/scripts/deploy.js +2 -0
  19. package/dist/utils/codify-spawn.d.ts +29 -0
  20. package/dist/utils/codify-spawn.js +136 -0
  21. package/dist/utils/index.d.ts +25 -0
  22. package/dist/utils/index.js +108 -0
  23. package/dist/utils/internal-utils.d.ts +18 -0
  24. package/dist/utils/internal-utils.js +86 -0
  25. package/dist/utils/pty-local-storage.d.ts +0 -1
  26. package/package.json +17 -12
  27. package/src/index.ts +1 -1
  28. package/src/plan/plan.test.ts +6 -1
  29. package/src/plugin/plugin.test.ts +11 -2
  30. package/src/plugin/plugin.ts +5 -2
  31. package/src/pty/background-pty.ts +20 -3
  32. package/src/pty/index.test.ts +7 -4
  33. package/src/pty/index.ts +17 -1
  34. package/src/pty/seqeuntial-pty.ts +105 -0
  35. package/src/pty/sequential-pty.test.ts +61 -0
  36. package/src/resource/parsed-resource-settings.ts +8 -7
  37. package/src/resource/resource-controller-stateful-mode.test.ts +2 -1
  38. package/src/resource/resource-controller.test.ts +22 -4
  39. package/src/resource/resource-settings.test.ts +29 -2
  40. package/src/resource/resource-settings.ts +16 -4
  41. package/src/utils/index.ts +140 -0
  42. package/src/utils/{utils.test.ts → internal-utils.test.ts} +1 -1
  43. package/src/utils/test-utils.test.ts +5 -2
  44. /package/src/utils/{utils.ts → internal-utils.ts} +0 -0
@@ -0,0 +1,108 @@
1
+ import os from 'node:os';
2
+ import path from 'node:path';
3
+ export var Shell;
4
+ (function (Shell) {
5
+ Shell["ZSH"] = "zsh";
6
+ Shell["BASH"] = "bash";
7
+ Shell["SH"] = "sh";
8
+ Shell["KSH"] = "ksh";
9
+ Shell["CSH"] = "csh";
10
+ Shell["FISH"] = "fish";
11
+ })(Shell || (Shell = {}));
12
+ export const Utils = {
13
+ getUser() {
14
+ return os.userInfo().username;
15
+ },
16
+ getSystemInfo() {
17
+ return {
18
+ os: os.type(),
19
+ shell: this.getShell(),
20
+ };
21
+ },
22
+ isMacOS() {
23
+ return os.platform() === 'darwin';
24
+ },
25
+ isLinux() {
26
+ return os.platform() === 'linux';
27
+ },
28
+ getShell() {
29
+ const shell = process.env.SHELL || '';
30
+ if (shell.endsWith('bash')) {
31
+ return Shell.BASH;
32
+ }
33
+ if (shell.endsWith('zsh')) {
34
+ return Shell.ZSH;
35
+ }
36
+ if (shell.endsWith('sh')) {
37
+ return Shell.SH;
38
+ }
39
+ if (shell.endsWith('csh')) {
40
+ return Shell.CSH;
41
+ }
42
+ if (shell.endsWith('ksh')) {
43
+ return Shell.KSH;
44
+ }
45
+ if (shell.endsWith('fish')) {
46
+ return Shell.FISH;
47
+ }
48
+ return undefined;
49
+ },
50
+ getPrimaryShellRc() {
51
+ return this.getShellRcFiles()[0];
52
+ },
53
+ getShellRcFiles() {
54
+ const shell = process.env.SHELL || '';
55
+ const homeDir = os.homedir();
56
+ if (shell.endsWith('bash')) {
57
+ // Linux typically uses .bashrc, macOS uses .bash_profile
58
+ if (Utils.isLinux()) {
59
+ return [
60
+ path.join(homeDir, '.bashrc'),
61
+ path.join(homeDir, '.bash_profile'),
62
+ path.join(homeDir, '.profile'),
63
+ ];
64
+ }
65
+ return [
66
+ path.join(homeDir, '.bash_profile'),
67
+ path.join(homeDir, '.bashrc'),
68
+ path.join(homeDir, '.profile'),
69
+ ];
70
+ }
71
+ if (shell.endsWith('zsh')) {
72
+ return [
73
+ path.join(homeDir, '.zshrc'),
74
+ path.join(homeDir, '.zprofile'),
75
+ path.join(homeDir, '.zshenv'),
76
+ ];
77
+ }
78
+ if (shell.endsWith('sh')) {
79
+ return [
80
+ path.join(homeDir, '.profile'),
81
+ ];
82
+ }
83
+ if (shell.endsWith('ksh')) {
84
+ return [
85
+ path.join(homeDir, '.profile'),
86
+ path.join(homeDir, '.kshrc'),
87
+ ];
88
+ }
89
+ if (shell.endsWith('csh')) {
90
+ return [
91
+ path.join(homeDir, '.cshrc'),
92
+ path.join(homeDir, '.login'),
93
+ path.join(homeDir, '.logout'),
94
+ ];
95
+ }
96
+ if (shell.endsWith('fish')) {
97
+ return [
98
+ path.join(homeDir, '.config/fish/config.fish'),
99
+ ];
100
+ }
101
+ // Default to bash-style files
102
+ return [
103
+ path.join(homeDir, '.bashrc'),
104
+ path.join(homeDir, '.bash_profile'),
105
+ path.join(homeDir, '.profile'),
106
+ ];
107
+ },
108
+ };
@@ -0,0 +1,18 @@
1
+ import { ResourceConfig, StringIndexedObject } from 'codify-schemas';
2
+ export declare const VerbosityLevel: {
3
+ level: number;
4
+ get(): number;
5
+ set(level: number): void;
6
+ };
7
+ export declare function isDebug(): boolean;
8
+ export declare function splitUserConfig<T extends StringIndexedObject>(config: ResourceConfig & T): {
9
+ parameters: T;
10
+ coreParameters: ResourceConfig;
11
+ };
12
+ export declare function setsEqual(set1: Set<unknown>, set2: Set<unknown>): boolean;
13
+ export declare function untildify(pathWithTilde: string): string;
14
+ export declare function tildify(pathWithTilde: string): string;
15
+ export declare function resolvePathWithVariables(pathWithVariables: string): string;
16
+ export declare function addVariablesToPath(pathWithoutVariables: string): string;
17
+ export declare function unhome(pathWithHome: string): string;
18
+ export declare function areArraysEqual(isElementEqual: ((desired: unknown, current: unknown) => boolean) | undefined, desired: unknown, current: unknown): boolean;
@@ -0,0 +1,86 @@
1
+ import os from 'node:os';
2
+ import path from 'node:path';
3
+ export const VerbosityLevel = new class {
4
+ level = 0;
5
+ get() {
6
+ return this.level;
7
+ }
8
+ set(level) {
9
+ this.level = level;
10
+ }
11
+ };
12
+ export function isDebug() {
13
+ return process.env.DEBUG != null && process.env.DEBUG.includes('codify'); // TODO: replace with debug library
14
+ }
15
+ export function splitUserConfig(config) {
16
+ const coreParameters = {
17
+ type: config.type,
18
+ ...(config.name ? { name: config.name } : {}),
19
+ ...(config.dependsOn ? { dependsOn: config.dependsOn } : {}),
20
+ };
21
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
22
+ const { type, name, dependsOn, ...parameters } = config;
23
+ return {
24
+ parameters: parameters,
25
+ coreParameters,
26
+ };
27
+ }
28
+ export function setsEqual(set1, set2) {
29
+ return set1.size === set2.size && [...set1].every((v) => set2.has(v));
30
+ }
31
+ const homeDirectory = os.homedir();
32
+ export function untildify(pathWithTilde) {
33
+ return homeDirectory ? pathWithTilde.replace(/^~(?=$|\/|\\)/, homeDirectory) : pathWithTilde;
34
+ }
35
+ export function tildify(pathWithTilde) {
36
+ return homeDirectory ? pathWithTilde.replace(homeDirectory, '~') : pathWithTilde;
37
+ }
38
+ export function resolvePathWithVariables(pathWithVariables) {
39
+ // @ts-expect-error Ignore this for now
40
+ return pathWithVariables.replace(/\$([A-Z_]+[A-Z0-9_]*)|\${([A-Z0-9_]*)}/ig, (_, a, b) => process.env[a || b]);
41
+ }
42
+ export function addVariablesToPath(pathWithoutVariables) {
43
+ let result = pathWithoutVariables;
44
+ for (const [key, value] of Object.entries(process.env)) {
45
+ if (!value || !path.isAbsolute(value) || value === '/' || key === 'HOME' || key === 'PATH' || key === 'SHELL' || key === 'PWD') {
46
+ continue;
47
+ }
48
+ result = result.replaceAll(value, `$${key}`);
49
+ }
50
+ return result;
51
+ }
52
+ export function unhome(pathWithHome) {
53
+ return pathWithHome.includes('$HOME') ? pathWithHome.replaceAll('$HOME', os.homedir()) : pathWithHome;
54
+ }
55
+ export function areArraysEqual(isElementEqual, desired, current) {
56
+ if (!desired || !current) {
57
+ return false;
58
+ }
59
+ if (!Array.isArray(desired) || !Array.isArray(current)) {
60
+ throw new Error(`A non-array value:
61
+
62
+ Desired: ${JSON.stringify(desired, null, 2)}
63
+
64
+ Current: ${JSON.stringify(desired, null, 2)}
65
+
66
+ Was provided even though type array was specified.
67
+ `);
68
+ }
69
+ if (desired.length !== current.length) {
70
+ return false;
71
+ }
72
+ const desiredCopy = [...desired];
73
+ const currentCopy = [...current];
74
+ // Algorithm for to check equality between two un-ordered; un-hashable arrays using
75
+ // an isElementEqual method. Time: O(n^2)
76
+ for (let counter = desiredCopy.length - 1; counter >= 0; counter--) {
77
+ const idx = currentCopy.findIndex((e2) => (isElementEqual
78
+ ?? ((a, b) => a === b))(desiredCopy[counter], e2));
79
+ if (idx === -1) {
80
+ return false;
81
+ }
82
+ desiredCopy.splice(counter, 1);
83
+ currentCopy.splice(idx, 1);
84
+ }
85
+ return currentCopy.length === 0;
86
+ }
@@ -1,3 +1,2 @@
1
- /// <reference types="node" resolution-mode="require"/>
2
1
  import { AsyncLocalStorage } from 'node:async_hooks';
3
2
  export declare const ptyLocalStorage: AsyncLocalStorage<unknown>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codify-plugin-lib",
3
- "version": "1.0.180",
3
+ "version": "1.0.182-beta1",
4
4
  "description": "Library plugin library",
5
5
  "main": "dist/index.js",
6
6
  "typings": "dist/index.d.ts",
@@ -10,42 +10,47 @@
10
10
  "posttest": "tsc",
11
11
  "prepublishOnly": "tsc"
12
12
  },
13
+ "bin": {
14
+ "codify-deploy": "./dist/bin/deploy-plugin.js"
15
+ },
13
16
  "keywords": [],
14
17
  "author": "",
15
18
  "license": "ISC",
16
19
  "dependencies": {
20
+ "@homebridge/node-pty-prebuilt-multiarch": "^0.13.1",
21
+ "@npmcli/promise-spawn": "^7.0.1",
17
22
  "ajv": "^8.12.0",
18
23
  "ajv-formats": "^2.1.1",
19
- "codify-schemas": "1.0.83",
20
- "@npmcli/promise-spawn": "^7.0.1",
21
- "@homebridge/node-pty-prebuilt-multiarch": "^0.12.0-beta.5",
22
- "uuid": "^10.0.0",
24
+ "clean-deep": "^3.4.0",
25
+ "codify-schemas": "1.0.86",
23
26
  "lodash.isequal": "^4.5.0",
24
27
  "nanoid": "^5.0.9",
25
28
  "strip-ansi": "^7.1.0",
26
- "clean-deep": "^3.4.0"
29
+ "uuid": "^10.0.0"
27
30
  },
28
31
  "devDependencies": {
32
+ "@apidevtools/json-schema-ref-parser": "^11.7.2",
29
33
  "@oclif/prettier-config": "^0.2.1",
30
34
  "@oclif/test": "^3",
31
- "@types/npmcli__promise-spawn": "^6.0.3",
35
+ "@types/lodash.isequal": "^4.5.8",
32
36
  "@types/node": "^20",
37
+ "@types/npmcli__promise-spawn": "^6.0.3",
33
38
  "@types/semver": "^7.5.4",
34
39
  "@types/sinon": "^17.0.3",
35
40
  "@types/uuid": "^10.0.0",
36
- "@types/lodash.isequal": "^4.5.8",
37
41
  "chai-as-promised": "^7.1.1",
38
- "vitest": "^3.0.5",
39
- "vitest-mock-extended": "^1.3.1",
40
- "sinon": "^17.0.1",
41
42
  "eslint": "^8.51.0",
42
43
  "eslint-config-oclif": "^5",
43
44
  "eslint-config-oclif-typescript": "^3",
45
+ "eslint-config-prettier": "^9.0.0",
46
+ "merge-json-schemas": "^1.0.0",
44
47
  "shx": "^0.3.3",
48
+ "sinon": "^17.0.1",
45
49
  "ts-node": "^10.9.1",
46
50
  "tsc-watch": "^6.0.4",
47
51
  "typescript": "^5",
48
- "eslint-config-prettier": "^9.0.0"
52
+ "vitest": "^3.0.5",
53
+ "vitest-mock-extended": "^1.3.1"
49
54
  },
50
55
  "engines": {
51
56
  "node": ">=18.0.0"
package/src/index.ts CHANGED
@@ -12,7 +12,7 @@ export * from './resource/parsed-resource-settings.js';
12
12
  export * from './resource/resource.js'
13
13
  export * from './resource/resource-settings.js'
14
14
  export * from './stateful-parameter/stateful-parameter.js'
15
- export * from './utils/utils.js'
15
+ export * from './utils/index.js'
16
16
 
17
17
  export async function runPlugin(plugin: Plugin) {
18
18
  const messageHandler = new MessageHandler(plugin);
@@ -1,6 +1,6 @@
1
1
  import { describe, expect, it } from 'vitest';
2
2
  import { Plan } from './plan.js';
3
- import { ParameterOperation, ResourceOperation } from 'codify-schemas';
3
+ import { OS, ParameterOperation, ResourceOperation } from 'codify-schemas';
4
4
  import { TestConfig, TestResource } from '../utils/test-utils.test.js';
5
5
  import { ResourceController } from '../resource/resource-controller.js';
6
6
  import { ParsedResourceSettings } from '../resource/parsed-resource-settings.js';
@@ -152,6 +152,7 @@ describe('Plan entity tests', () => {
152
152
  getSettings(): ResourceSettings<any> {
153
153
  return {
154
154
  id: 'type',
155
+ operatingSystems: [OS.Darwin],
155
156
  parameterSettings: {
156
157
  propZ: { type: 'array', isElementEqual: (a, b) => b.includes(a) }
157
158
  }
@@ -184,6 +185,7 @@ describe('Plan entity tests', () => {
184
185
  getSettings(): ResourceSettings<any> {
185
186
  return {
186
187
  id: 'type',
188
+ operatingSystems: [OS.Darwin],
187
189
  parameterSettings: {
188
190
  propZ: {
189
191
  type: 'array',
@@ -236,6 +238,7 @@ describe('Plan entity tests', () => {
236
238
  getSettings(): ResourceSettings<TestConfig> {
237
239
  return {
238
240
  id: 'type',
241
+ operatingSystems: [OS.Darwin],
239
242
  parameterSettings: {
240
243
  propA: { type: 'string' },
241
244
  propB: { type: 'string', canModify: true },
@@ -289,6 +292,7 @@ describe('Plan entity tests', () => {
289
292
  getSettings(): ResourceSettings<TestConfig> {
290
293
  return {
291
294
  id: 'type',
295
+ operatingSystems: [OS.Darwin],
292
296
  parameterSettings: {
293
297
  propA: { type: 'string' },
294
298
  propB: { type: 'string', canModify: true },
@@ -351,6 +355,7 @@ function createTestResource() {
351
355
  getSettings(): ResourceSettings<TestConfig> {
352
356
  return {
353
357
  id: 'type',
358
+ operatingSystems: [OS.Darwin],
354
359
  parameterSettings: {
355
360
  propA: {
356
361
  default: 'defaultA'
@@ -1,6 +1,6 @@
1
1
  import { describe, expect, it } from 'vitest';
2
2
  import { Plugin } from './plugin.js';
3
- import { ApplyRequestData, ParameterOperation, ResourceOperation, StringIndexedObject } from 'codify-schemas';
3
+ import { ApplyRequestData, OS, ParameterOperation, ResourceOperation, StringIndexedObject } from 'codify-schemas';
4
4
  import { Resource } from '../resource/resource.js';
5
5
  import { Plan } from '../plan/plan.js';
6
6
  import { spy } from 'sinon';
@@ -17,7 +17,8 @@ interface TestConfig extends StringIndexedObject {
17
17
  class TestResource extends Resource<TestConfig> {
18
18
  getSettings(): ResourceSettings<TestConfig> {
19
19
  return {
20
- id: 'testResource'
20
+ id: 'testResource',
21
+ operatingSystems: [OS.Darwin],
21
22
  };
22
23
  }
23
24
 
@@ -154,6 +155,7 @@ describe('Plugin tests', () => {
154
155
  getSettings(): ResourceSettings<TestConfig> {
155
156
  return {
156
157
  id: 'typeId',
158
+ operatingSystems: [OS.Darwin],
157
159
  schema,
158
160
  }
159
161
  }
@@ -192,6 +194,7 @@ describe('Plugin tests', () => {
192
194
  getSettings(): ResourceSettings<TestConfig> {
193
195
  return {
194
196
  id: 'typeId',
197
+ operatingSystems: [OS.Darwin],
195
198
  schema,
196
199
  importAndDestroy: {
197
200
  requiredParameters: []
@@ -285,6 +288,7 @@ describe('Plugin tests', () => {
285
288
  getSettings(): ResourceSettings<TestConfig> {
286
289
  return {
287
290
  id: 'type',
291
+ operatingSystems: [OS.Darwin],
288
292
  schema: {
289
293
  '$schema': 'http://json-schema.org/draft-07/schema',
290
294
  '$id': 'https://www.codifycli.com/ssh-config.json',
@@ -330,6 +334,7 @@ describe('Plugin tests', () => {
330
334
  getSettings(): ResourceSettings<TestConfig> {
331
335
  return {
332
336
  ...super.getSettings(),
337
+ operatingSystems: [OS.Darwin],
333
338
  allowMultiple: {
334
339
  identifyingParameters: ['path', 'paths']
335
340
  }
@@ -351,6 +356,7 @@ describe('Plugin tests', () => {
351
356
  getSettings(): ResourceSettings<TestConfig> {
352
357
  return {
353
358
  ...super.getSettings(),
359
+ operatingSystems: [OS.Darwin],
354
360
  parameterSettings: {
355
361
  path: { type: 'directory' },
356
362
  paths: { type: 'array', itemType: 'directory' }
@@ -407,6 +413,7 @@ describe('Plugin tests', () => {
407
413
  getSettings(): ResourceSettings<TestConfig> {
408
414
  return {
409
415
  id: 'ssh-config',
416
+ operatingSystems: [OS.Darwin],
410
417
  parameterSettings: {
411
418
  hosts: { type: 'stateful', definition: new TestStatefulParameter() }
412
419
  },
@@ -454,6 +461,7 @@ describe('Plugin tests', () => {
454
461
  getSettings(): ResourceSettings<TestConfig> {
455
462
  return {
456
463
  id: 'ssh-config',
464
+ operatingSystems: [OS.Darwin],
457
465
  allowMultiple: true
458
466
  }
459
467
  }
@@ -476,6 +484,7 @@ describe('Plugin tests', () => {
476
484
  getSettings(): ResourceSettings<TestConfig> {
477
485
  return {
478
486
  id: 'ssh-config',
487
+ operatingSystems: [OS.Darwin],
479
488
  }
480
489
  }
481
490
  })
@@ -21,10 +21,11 @@ import { ApplyValidationError } from '../common/errors.js';
21
21
  import { Plan } from '../plan/plan.js';
22
22
  import { BackgroundPty } from '../pty/background-pty.js';
23
23
  import { getPty } from '../pty/index.js';
24
+ import { SequentialPty } from '../pty/seqeuntial-pty.js';
24
25
  import { Resource } from '../resource/resource.js';
25
26
  import { ResourceController } from '../resource/resource-controller.js';
27
+ import { VerbosityLevel } from '../utils/internal-utils.js';
26
28
  import { ptyLocalStorage } from '../utils/pty-local-storage.js';
27
- import { VerbosityLevel } from '../utils/utils.js';
28
29
 
29
30
  export class Plugin {
30
31
  planStorage: Map<string, Plan<any>>;
@@ -75,6 +76,7 @@ export class Plugin {
75
76
  dependencies: r.dependencies,
76
77
  type: r.typeId,
77
78
  sensitiveParameters,
79
+ operatingSystems: r.settings.operatingSystems,
78
80
  }
79
81
  })
80
82
  }
@@ -121,6 +123,7 @@ export class Plugin {
121
123
  import: {
122
124
  requiredParameters: requiredPropertyNames,
123
125
  },
126
+ operatingSystems: resource.settings.operatingSystems,
124
127
  sensitiveParameters,
125
128
  allowMultiple
126
129
  }
@@ -232,7 +235,7 @@ export class Plugin {
232
235
  throw new Error('Malformed plan with resource that cannot be found');
233
236
  }
234
237
 
235
- await resource.apply(plan);
238
+ await ptyLocalStorage.run(new SequentialPty(), async () => resource.apply(plan))
236
239
 
237
240
  // Validate using desired/desired. If the apply was successful, no changes should be reported back.
238
241
  // Default back desired back to current if it is not defined (for destroys only)
@@ -6,7 +6,8 @@ import * as fs from 'node:fs/promises';
6
6
  import stripAnsi from 'strip-ansi';
7
7
 
8
8
  import { debugLog } from '../utils/debug.js';
9
- import { VerbosityLevel } from '../utils/utils.js';
9
+ import { Shell, Utils } from '../utils/index.js';
10
+ import { VerbosityLevel } from '../utils/internal-utils.js';
10
11
  import { IPty, SpawnError, SpawnOptions, SpawnResult } from './index.js';
11
12
  import { PromiseQueue } from './promise-queue.js';
12
13
 
@@ -19,7 +20,7 @@ EventEmitter.defaultMaxListeners = 1000;
19
20
  * without a tty (or even a stdin) attached so interactive commands will not work.
20
21
  */
21
22
  export class BackgroundPty implements IPty {
22
- private basePty = pty.spawn('zsh', ['-i'], {
23
+ private basePty = pty.spawn(this.getDefaultShell(), ['-i'], {
23
24
  env: process.env, name: nanoid(6),
24
25
  handleFlowControl: true
25
26
  });
@@ -127,7 +128,19 @@ export class BackgroundPty implements IPty {
127
128
  let outputBuffer = '';
128
129
 
129
130
  return new Promise(resolve => {
130
- this.basePty.write('setopt hist_ignore_space;\n');
131
+ // zsh-specific commands
132
+ switch (Utils.getShell()) {
133
+ case Shell.ZSH: {
134
+ this.basePty.write('setopt HIST_NO_STORE;\n');
135
+ break;
136
+ }
137
+
138
+ default: {
139
+ this.basePty.write('export HISTIGNORE=\'history*\';\n');
140
+ break;
141
+ }
142
+ }
143
+
131
144
  this.basePty.write(' unset PS1;\n');
132
145
  this.basePty.write(' unset PS0;\n')
133
146
  this.basePty.write(' echo setup complete\\"\n')
@@ -142,4 +155,8 @@ export class BackgroundPty implements IPty {
142
155
  })
143
156
  })
144
157
  }
158
+
159
+ private getDefaultShell(): string {
160
+ return process.env.SHELL!;
161
+ }
145
162
  }
@@ -3,8 +3,9 @@ import { TestConfig, TestResource } from '../utils/test-utils.test.js';
3
3
  import { getPty, IPty } from './index.js';
4
4
  import { Plugin } from '../plugin/plugin.js'
5
5
  import { CreatePlan } from '../plan/plan-types.js';
6
- import { ResourceOperation } from 'codify-schemas';
6
+ import { OS, ResourceOperation } from 'codify-schemas';
7
7
  import { ResourceSettings } from '../resource/resource-settings.js';
8
+ import { SequentialPty } from './seqeuntial-pty.js';
8
9
 
9
10
  describe('General tests for PTYs', () => {
10
11
  it('Can get pty within refresh', async () => {
@@ -45,7 +46,8 @@ describe('General tests for PTYs', () => {
45
46
  const testResource1 = new class extends TestResource {
46
47
  getSettings(): ResourceSettings<TestConfig> {
47
48
  return {
48
- id: 'type1'
49
+ id: 'type1',
50
+ operatingSystems: [OS.Darwin],
49
51
  }
50
52
  }
51
53
 
@@ -64,6 +66,7 @@ describe('General tests for PTYs', () => {
64
66
  getSettings(): ResourceSettings<TestConfig> {
65
67
  return {
66
68
  id: 'type2',
69
+ operatingSystems: [OS.Darwin],
67
70
  }
68
71
  }
69
72
 
@@ -103,11 +106,11 @@ describe('General tests for PTYs', () => {
103
106
  expect(pty1).to.eq(pty2);
104
107
  })
105
108
 
106
- it('Currently pty not available for apply', async () => {
109
+ it('Sequential pty should be available for applies', async () => {
107
110
  const testResource = new class extends TestResource {
108
111
  create(plan: CreatePlan<TestConfig>): Promise<void> {
109
112
  const $ = getPty();
110
- expect($).to.be.undefined;
113
+ expect($).to.instanceof(SequentialPty)
111
114
  }
112
115
  }
113
116
 
package/src/pty/index.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { ptyLocalStorage } from '../utils/pty-local-storage.js';
2
2
 
3
3
  export interface SpawnResult {
4
- status: 'success' | 'error';
4
+ status: 'error' | 'success';
5
5
  exitCode: number;
6
6
  data: string;
7
7
  }
@@ -11,9 +11,25 @@ export enum SpawnStatus {
11
11
  ERROR = 'error',
12
12
  }
13
13
 
14
+ /**
15
+ * Represents the configuration options for spawning a child process.
16
+ *
17
+ * @interface SpawnOptions
18
+ *
19
+ * @property {string} [cwd] - Specifies the working directory of the child process.
20
+ * If not provided, the current working directory of the parent process is used.
21
+ *
22
+ * @property {Record<string, unknown>} [env] - Defines environment key-value pairs
23
+ * that will be available to the child process. If not specified, the child process
24
+ * will inherit the environment variables of the parent process.
25
+ *
26
+ * @property {boolean} [interactive] - Indicates whether the spawned process needs
27
+ * to be interactive. Only works within apply (not plan). Defaults to true.
28
+ */
14
29
  export interface SpawnOptions {
15
30
  cwd?: string;
16
31
  env?: Record<string, unknown>,
32
+ interactive?: boolean,
17
33
  }
18
34
 
19
35
  export class SpawnError extends Error {